2FAuth/public/build/assets/OtpDisplay-ytUtG8ZN.js.map
2024-11-27 12:03:02 +01:00

1 line
23 KiB
Plaintext

{"version":3,"file":"OtpDisplay-ytUtG8ZN.js","sources":["../../../resources/js/components/TotpLooper.vue","../../../resources/js/components/Dots.vue","../../../resources/js/components/OtpDisplay.vue"],"sourcesContent":["<script setup>\n const props = defineProps({\n step_count: {\n type: Number,\n default: 10\n },\n period : Number,\n generated_at: Number,\n autostart: {\n type: Boolean,\n default: true\n },\n })\n\n const generatedAt = ref(null)\n const remainingTimeout = ref(null)\n const initialStepToNextStepTimeout = ref(null)\n const stepToStepInterval = ref(null)\n const stepIndex = ref(null)\n\n // |<----period p----->|\n // | | |\n // |------- ··· ------------|--------|----------|---------->\n // | | | |\n // unix T0 Tp.start Tgen_at Tp.end\n // | | |\n // elapsedTimeInCurrentPeriod--|<------>| |\n // (in ms) | | |\n // ● ● ● ● ●|● ◌ ◌ ◌ ◌ |\n // | | || |\n // | | |<-------->|--remainingTimeBeforeEndOfPeriod (for remainingTimeout)\n // durationBetweenTwoSteps-->|-|< || \n // (for stepToStepInterval) | | >||<---durationFromInitialToNextStep (for initialStepToNextStepTimeout)\n // |\n // |\n // stepIndex\n\n const elapsedTimeInCurrentPeriod = computed(() => {\n return generatedAt.value % props.period\n })\n\n const remainingTimeBeforeEndOfPeriod = computed(() => {\n return props.period - elapsedTimeInCurrentPeriod.value\n })\n\n const durationBetweenTwoSteps = computed(() => {\n return props.period / props.step_count\n })\n\n const initialStepIndex = computed(() => {\n let relativePosition = (elapsedTimeInCurrentPeriod.value * props.step_count) / props.period\n\n return (Math.floor(relativePosition) + 0)\n })\n\n const emit = defineEmits(['loop-started', 'loop-ended', 'stepped-up'])\n\n /**\n * Starts looping\n */\n const startLoop = (generated_at = null) => {\n clearLooper()\n generatedAt.value = generated_at != null ? generated_at : props.generated_at\n\n emit('loop-started', initialStepIndex.value)\n\n stepIndex.value = initialStepIndex.value\n\n // Main timeout that runs until the end of the period\n remainingTimeout.value = setTimeout(function() {\n clearLooper()\n emit('loop-ended')\n }, remainingTimeBeforeEndOfPeriod.value * 1000);\n\n // During the remainingTimeout countdown we emit an event every durationBetweenTwoSteps seconds,\n // except for the first next dot\n let durationFromInitialToNextStep = (Math.ceil(elapsedTimeInCurrentPeriod.value / durationBetweenTwoSteps.value) * durationBetweenTwoSteps.value) - elapsedTimeInCurrentPeriod.value\n\n initialStepToNextStepTimeout.value = setTimeout(function() {\n if( durationFromInitialToNextStep > 0 ) {\n stepIndex.value += 1\n emit('stepped-up', stepIndex.value)\n }\n stepToStepInterval.value = setInterval(function() {\n stepIndex.value += 1\n emit('stepped-up', stepIndex.value)\n }, durationBetweenTwoSteps.value * 1000)\n }, durationFromInitialToNextStep * 1000)\n }\n\n /**\n * Resets all timers and internal vars\n */\n const clearLooper = () => {\n clearTimeout(remainingTimeout.value)\n clearTimeout(initialStepToNextStepTimeout.value)\n clearInterval(stepToStepInterval.value)\n stepIndex.value = generatedAt.value = null\n }\n\n onMounted(() => {\n if (props.autostart == true) {\n startLoop()\n }\n })\n\n onUnmounted(() => {\n clearLooper()\n })\n\n defineExpose({\n startLoop,\n clearLooper,\n props\n })\n\n</script>\n\n<template>\n <div>\n </div>\n</template>","<script setup>\n const props = defineProps({\n stepCount: {\n type: Number,\n default: 10\n },\n initialIndex: {\n type: Number,\n default: null\n },\n period: { // Used only to identify the dots component in Accounts.vue\n type: Number,\n default: null\n },\n })\n\n const activeDot = ref(0)\n const isOff = computed(() => {\n return activeDot.value == -1\n })\n\n /**\n * Turns On dots\n */\n function turnOn(index) {\n activeDot.value = index < props.stepCount ? index + 1 : 1\n }\n\n /**\n * Turns Off all dots\n */\n function turnOff() {\n activeDot.value = -1\n }\n\n onMounted(() => {\n if (! isNaN(props.initialIndex)) {\n turnOn(props.initialIndex)\n }\n })\n\n defineExpose({\n turnOn,\n turnOff,\n props\n })\n\n</script>\n\n<template>\n <ul class=\"dots\" :class=\"{'off' : isOff}\">\n <li v-for=\"n in stepCount\" :key=\"n\" :data-is-active=\"n == activeDot ? true : null\"></li>\n </ul>\n</template>","<script setup>\n import Spinner from '@/components/Spinner.vue'\n import TotpLooper from '@/components/TotpLooper.vue'\n import Dots from '@/components/Dots.vue'\n import twofaccountService from '@/services/twofaccountService'\n import { useUserStore } from '@/stores/user'\n import { useNotifyStore } from '@/stores/notify'\n import { UseColorMode } from '@vueuse/components'\n import { useDisplayablePassword } from '@/composables/helpers'\n\n const user = useUserStore()\n const notify = useNotifyStore()\n const $2fauth = inject('2fauth')\n const { copy, copied } = useClipboard({ legacy: true })\n const route = useRoute()\n \n const emit = defineEmits(['please-close-me', 'increment-hotp', 'validation-error'])\n const props = defineProps({\n otp_type : String,\n account : String,\n service : String,\n icon : String,\n secret : String,\n digits : Number,\n algorithm : String,\n period : null,\n counter : null,\n image : String,\n qrcode : null,\n uri : String\n })\n\n const id = ref(null)\n const uri = ref(null)\n const otpauthParams = ref({\n otp_type : '',\n account : '',\n service : '',\n icon : '',\n secret : '',\n digits : null,\n algorithm : '',\n period : null,\n counter : null,\n image : ''\n })\n const password = ref('')\n const generated_at = ref(null)\n const hasTOTP = ref(false)\n const showInlineSpinner = ref(false)\n const revealPassword = ref(false)\n\n const dots = ref()\n const totpLooper = ref()\n const otpSpanTag = ref()\n const autoCloseTimeout = ref(null)\n\n watch(\n () => props.icon,\n (val) => {\n if (val != undefined) {\n otpauthParams.value.icon = val\n }\n }\n )\n\n /***\n * \n */\n const show = async (accountId) => {\n revealPassword.value = false\n\n // 3 possible cases :\n //\n // Case 1 : When user asks for an otp of an existing account: the ID is provided so we fetch the account data\n // from db but without the uri. This prevent the uri (a sensitive data) to transit via http request unnecessarily.\n // In this case this.otp_type is sent by the backend.\n //\n // Case 2 : When user uses the Quick Uploader and preview the account: No ID but we have an URI.\n //\n // Case 3 : When user uses the Advanced form and preview the account: We should have all OTP parameter\n // to obtain an otp, including Secret and otp_type which are required\n\n otpauthParams.value.otp_type = props.otp_type\n otpauthParams.value.account = props.account\n otpauthParams.value.service = props.service\n otpauthParams.value.icon = props.icon\n otpauthParams.value.secret = props.secret\n otpauthParams.value.digits = props.digits\n otpauthParams.value.algorithm = props.algorithm\n otpauthParams.value.period = props.period\n otpauthParams.value.counter = props.counter\n setLoadingState()\n\n // Case 1\n if (accountId) {\n id.value = accountId\n const { data } = await twofaccountService.get(id.value)\n\n otpauthParams.value.service = data.service\n otpauthParams.value.account = data.account\n otpauthParams.value.icon = data.icon\n otpauthParams.value.otp_type = data.otp_type\n\n if( isHMacBased(data.otp_type) && data.counter ) {\n otpauthParams.value.counter = data.counter\n }\n }\n // Case 2\n else if(props.uri) {\n uri.value = props.uri\n otpauthParams.value.otp_type = props.uri.slice(0, 15 ).toLowerCase() === \"otpauth://totp/\" ? 'totp' : 'hotp'\n }\n // Case 3\n else if (! props.secret) {\n notify.error(new Error(trans('errors.cannot_create_otp_without_secret')))\n }\n else if (! isTimeBased(otpauthParams.value.otp_type) && ! isHMacBased(otpauthParams.value.otp_type)) {\n notify.error(new Error(trans('errors.not_a_supported_otp_type')))\n }\n\n try {\n await getOtp()\n focusOnOTP()\n\n if (user.preferences.getOtpOnRequest && parseInt(user.preferences.autoCloseTimeout) > 0) {\n startAutoCloseTimer()\n }\n }\n catch(error) {\n clearOTP()\n }\n }\n\n /**\n * Requests and handles a fresh OTP\n */\n async function getOtp() {\n setLoadingState()\n\n await getOtpPromise().then(response => {\n let otp = response.data\n password.value = otp.password\n\n if(user.preferences.copyOtpOnDisplay) {\n copyOTP(otp.password)\n }\n\n if (isTimeBased(otp.otp_type)) {\n generated_at.value = otp.generated_at\n otpauthParams.value.period = otp.period\n hasTOTP.value = true\n\n nextTick().then(() => {\n totpLooper.value.startLoop()\n })\n }\n else if (isHMacBased(otp.otp_type)) {\n otpauthParams.value.counter = otp.counter\n\n // returned counter & uri are incremented\n emit('increment-hotp', { nextHotpCounter: otp.counter, nextUri: otp.uri })\n }\n })\n .catch(error => {\n if (error.response.status === 422) {\n emit('validation-error', error.response)\n }\n //throw error\n })\n .finally(() => {\n showInlineSpinner.value = false\n })\n }\n\n /**\n * Shows blacked dots and a loading spinner\n */\n function setLoadingState() {\n showInlineSpinner.value = true\n dots.value.turnOff()\n }\n\n /**\n * Returns the appropriate promise to get a fresh OTP from backend\n */\n function getOtpPromise() {\n if(id.value) {\n return twofaccountService.getOtpById(id.value)\n }\n else if(uri.value) {\n return twofaccountService.getOtpByUri(uri.value)\n }\n else {\n return twofaccountService.getOtpByParams(otpauthParams.value)\n }\n }\n\n /**\n * Triggers the component closing\n */\n function closeMe() {\n emit(\"please-close-me\");\n revealPassword.value = false\n clearOTP()\n }\n\n /**\n * Reset component's refs\n */\n function clearOTP() {\n id.value = otpauthParams.value.counter = generated_at.value = null\n otpauthParams.value.service = otpauthParams.value.account = otpauthParams.value.icon = otpauthParams.value.otp_type = otpauthParams.value.secret = ''\n password.value = '... ...'\n hasTOTP.value = false\n clearTimeout(autoCloseTimeout.value)\n\n totpLooper.value?.clearLooper();\n }\n\n /**\n * Put focus on the OTP html tag\n */\n function focusOnOTP() {\n nextTick().then(() => {\n otpSpanTag.value?.focus()\n })\n }\n\n /**\n * Copies to clipboard and notify\n * \n * @param {string} otp The password to copy\n * @param {*} permit_closing Toggle moddle closing On-Off\n */\n function copyOTP(otp, permit_closing) {\n copy(otp.replace(/ /g, ''))\n\n if (copied) {\n if(user.preferences.kickUserAfter == -1 && (permit_closing || false) === true && route.name != 'importAccounts') {\n user.logout({ kicked: true})\n }\n else if(user.preferences.closeOtpOnCopy && (permit_closing || false) === true) {\n closeMe()\n }\n\n if(user.preferences.clearSearchOnCopy) {\n emit(\"please-clear-search\");\n }\n if (user.preferences.viewDefaultGroupOnCopy) {\n user.preferences.activeGroup = user.preferences.defaultGroup == -1 ?\n user.preferences.activeGroup\n : user.preferences.defaultGroup\n }\n\n notify.success({ text: trans('commons.copied_to_clipboard') })\n }\n }\n\n /**\n * Checks OTP type is Time based (TOTP)\n * \n * @param {string} otp_type \n */\n function isTimeBased(otp_type) {\n return (otp_type === 'totp' || otp_type === 'steamtotp')\n }\n\n /**\n * Checks OTP type is HMAC based (HOTP)\n * \n * @param {string} otp_type \n */\n function isHMacBased(otp_type) {\n return otp_type === 'hotp'\n }\n \n /**\n * Turns dots On from the first one to the provided one\n */\n function turnDotOn(dotIndex) {\n dots.value.turnOn(dotIndex)\n }\n\n defineExpose({\n show,\n clearOTP\n })\n \n /**\n * Starts an auto close timer\n */\n function startAutoCloseTimer() {\n let duration = parseInt(user.preferences.autoCloseTimeout) // in minutes\n \n autoCloseTimeout.value = setTimeout(function() {\n closeMe()\n }, duration * 60 * 1000);\n }\n\n</script>\n\n<template>\n <div>\n <figure class=\"image is-64x64\" :class=\"{ 'no-icon': !otpauthParams.icon }\" style=\"display: inline-block\">\n <img :src=\"$2fauth.config.subdirectory + '/storage/icons/' + otpauthParams.icon\" v-if=\"otpauthParams.icon\" :alt=\"$t('twofaccounts.icon_to_illustrate_the_account')\">\n </figure>\n <UseColorMode v-slot=\"{ mode }\">\n <p class=\"is-size-4 has-ellipsis\" :class=\"mode == 'dark' ? 'has-text-grey-light' : 'has-text-grey'\">{{ otpauthParams.service }}</p>\n <p class=\"is-size-6 has-ellipsis\" :class=\"mode == 'dark' ? 'has-text-grey' : 'has-text-grey-light'\">{{ otpauthParams.account }}</p>\n <p>\n <span\n v-if=\"!showInlineSpinner\"\n id=\"otp\"\n role=\"log\"\n ref=\"otpSpanTag\"\n tabindex=\"0\"\n class=\"otp is-size-1 is-clickable px-3\"\n :class=\"mode == 'dark' ? 'has-text-white' : 'has-text-grey-dark'\"\n @click=\"copyOTP(password, true)\"\n @keyup.enter=\"copyOTP(password, true)\"\n :title=\"$t('commons.copy_to_clipboard')\"\n >\n {{ useDisplayablePassword(password, user.preferences.showOtpAsDot && user.preferences.revealDottedOTP && revealPassword) }}\n </span>\n <span v-else tabindex=\"0\" class=\"otp is-size-1\">\n <Spinner :isVisible=\"showInlineSpinner\" :type=\"'raw'\" />\n </span>\n </p>\n </UseColorMode>\n <Dots v-show=\"isTimeBased(otpauthParams.otp_type)\" ref=\"dots\"></Dots>\n <p v-show=\"isHMacBased(otpauthParams.otp_type)\">\n {{ $t('twofaccounts.forms.counter.label') }}: {{ otpauthParams.counter }}\n </p>\n <p v-if=\"user.preferences.showOtpAsDot && user.preferences.revealDottedOTP\" class=\"mt-3\">\n <button type=\"button\" class=\"button is-ghost has-text-grey-dark\" @click.stop=\"revealPassword = !revealPassword\">\n <font-awesome-icon v-if=\"revealPassword\" :icon=\"['fas', 'eye']\" />\n <font-awesome-icon v-else :icon=\"['fas', 'eye-slash']\" />\n </button>\n </p>\n <TotpLooper \n v-if=\"hasTOTP\"\n :period=\"otpauthParams.period\" \n :generated_at=\"generated_at\" \n :autostart=\"false\" \n v-on:loop-ended=\"getOtp()\"\n v-on:loop-started=\"turnDotOn($event)\"\n v-on:stepped-up=\"turnDotOn($event)\"\n ref=\"totpLooper\"\n ></TotpLooper>\n </div>\n</template>\n"],"names":["props","__props","generatedAt","ref","remainingTimeout","initialStepToNextStepTimeout","stepToStepInterval","stepIndex","elapsedTimeInCurrentPeriod","computed","remainingTimeBeforeEndOfPeriod","durationBetweenTwoSteps","initialStepIndex","relativePosition","emit","__emit","startLoop","generated_at","clearLooper","durationFromInitialToNextStep","onMounted","onUnmounted","__expose","activeDot","isOff","turnOn","index","turnOff","user","useUserStore","notify","useNotifyStore","$2fauth","inject","copy","copied","useClipboard","route","useRoute","id","uri","otpauthParams","password","hasTOTP","showInlineSpinner","revealPassword","dots","totpLooper","otpSpanTag","autoCloseTimeout","watch","val","show","accountId","setLoadingState","data","twofaccountService","isHMacBased","isTimeBased","trans","getOtp","focusOnOTP","startAutoCloseTimer","clearOTP","getOtpPromise","response","otp","copyOTP","nextTick","error","closeMe","_a","permit_closing","otp_type","turnDotOn","dotIndex","duration"],"mappings":"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"}