mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-04-25 09:16:15 -04:00
fix(otp-generator): better computation of token
This commit is contained in:
parent
15cb03347c
commit
5281824b5d
2 changed files with 21 additions and 26 deletions
|
@ -1,15 +1,19 @@
|
||||||
import { computedAsync } from '@vueuse/core';
|
import { computedAsync, watchThrottled } from '@vueuse/core';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
|
|
||||||
export { computedRefreshable, computedRefreshableAsync };
|
export { computedRefreshable, computedRefreshableAsync };
|
||||||
|
|
||||||
function computedRefreshable<T>(getter: () => T) {
|
function computedRefreshable<T>(getter: () => T, { throttle }: { throttle?: number } = {}) {
|
||||||
const dirty = ref(true);
|
const dirty = ref(true);
|
||||||
let value: T;
|
let value: T;
|
||||||
|
|
||||||
const update = () => (dirty.value = true);
|
const update = () => (dirty.value = true);
|
||||||
|
|
||||||
|
if (throttle) {
|
||||||
|
watchThrottled(getter, update, { throttle });
|
||||||
|
} else {
|
||||||
watch(getter, update);
|
watch(getter, update);
|
||||||
|
}
|
||||||
|
|
||||||
const computedValue = computed(() => {
|
const computedValue = computed(() => {
|
||||||
if (dirty.value) {
|
if (dirty.value) {
|
||||||
|
|
|
@ -65,11 +65,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { Refresh } from '@vicons/tabler';
|
import { Refresh } from '@vicons/tabler';
|
||||||
import { useTimestamp, whenever } from '@vueuse/core';
|
import { useTimestamp, useWindowFocus, whenever } from '@vueuse/core';
|
||||||
import { useThemeVars } from 'naive-ui';
|
import { useThemeVars } from 'naive-ui';
|
||||||
import { useStyleStore } from '@/stores/style.store';
|
import { useStyleStore } from '@/stores/style.store';
|
||||||
import InputCopyable from '@/components/InputCopyable.vue';
|
import InputCopyable from '@/components/InputCopyable.vue';
|
||||||
import { useValidation } from '@/composable/validation';
|
import { useValidation } from '@/composable/validation';
|
||||||
|
import { computedRefreshable } from '@/composable/computedRefreshable';
|
||||||
import { generateTOTP, buildKeyUri, generateSecret, base32toHex, getCounterFromTime } from './otp.service';
|
import { generateTOTP, buildKeyUri, generateSecret, base32toHex, getCounterFromTime } from './otp.service';
|
||||||
import { useQRCode } from '../qr-code-generator/useQRCode';
|
import { useQRCode } from '../qr-code-generator/useQRCode';
|
||||||
import TokenDisplay from './token-display.vue';
|
import TokenDisplay from './token-display.vue';
|
||||||
|
@ -78,8 +79,18 @@ const now = useTimestamp();
|
||||||
const interval = computed(() => (now.value / 1000) % 30);
|
const interval = computed(() => (now.value / 1000) % 30);
|
||||||
const theme = useThemeVars();
|
const theme = useThemeVars();
|
||||||
const styleStore = useStyleStore();
|
const styleStore = useStyleStore();
|
||||||
const secret = ref(generateSecret());
|
|
||||||
const tokens = ref(buildTokens());
|
const [secret, refreshSecret] = computedRefreshable(generateSecret);
|
||||||
|
|
||||||
|
const [tokens] = computedRefreshable(
|
||||||
|
() => ({
|
||||||
|
previous: generateTOTP({ key: secret.value, now: now.value - 30000 }),
|
||||||
|
current: generateTOTP({ key: secret.value, now: now.value }),
|
||||||
|
next: generateTOTP({ key: secret.value, now: now.value + 30000 }),
|
||||||
|
}),
|
||||||
|
{ throttle: 500 },
|
||||||
|
);
|
||||||
|
|
||||||
const keyUri = computed(() => buildKeyUri({ secret: secret.value }));
|
const keyUri = computed(() => buildKeyUri({ secret: secret.value }));
|
||||||
|
|
||||||
const { qrcode } = useQRCode({
|
const { qrcode } = useQRCode({
|
||||||
|
@ -104,26 +115,6 @@ const { attrs: secretValidationAttrs } = useValidation({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
// watch + whenever to prevent token to be refresh every raf
|
|
||||||
watch([secret], refreshToken);
|
|
||||||
whenever(() => Math.floor(interval.value) === 0, refreshToken);
|
|
||||||
|
|
||||||
function refreshSecret() {
|
|
||||||
secret.value = generateSecret();
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshToken() {
|
|
||||||
tokens.value = buildTokens();
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildTokens() {
|
|
||||||
return {
|
|
||||||
previous: generateTOTP({ key: secret.value, now: now.value - 30000 }),
|
|
||||||
current: generateTOTP({ key: secret.value, now: now.value }),
|
|
||||||
next: generateTOTP({ key: secret.value, now: now.value + 30000 }),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue