@adminforth/two-factors-auth 2.6.2 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build.log CHANGED
@@ -15,5 +15,5 @@ custom/package.json
15
15
  custom/tsconfig.json
16
16
  custom/utils.js
17
17
 
18
- sent 272,490 bytes received 210 bytes 545,400.00 bytes/sec
19
- total size is 271,663 speedup is 1.00
18
+ sent 272,788 bytes received 210 bytes 545,996.00 bytes/sec
19
+ total size is 271,961 speedup is 1.00
@@ -5,7 +5,7 @@
5
5
  @click="handleLoginWithPasskey"
6
6
  >
7
7
  <IconShieldOutline class="w-7 h-8" />
8
- <span class="ml-2">Continue with Passkey</span>
8
+ <span class="ml-2">{{ $t('Continue with Passkey') }}</span>
9
9
  </Button>
10
10
 
11
11
  </template>
@@ -20,7 +20,9 @@
20
20
  import { Button } from '@/afcl';
21
21
  import adminforth from '@/adminforth';
22
22
  import { useRouter, useRoute } from 'vue-router';
23
+ import { useI18n } from 'vue-i18n';
23
24
 
25
+ const { t } = useI18n();
24
26
  const userStore = useUserStore();
25
27
  const router = useRouter();
26
28
 
@@ -36,7 +38,7 @@
36
38
  });
37
39
  if ( resp.error ) {
38
40
  console.error("Login failed:", resp.error);
39
- adminforth.alert({message: 'Error: ' + resp.error, variant: 'warning'});
41
+ adminforth.alert({message: t('Error: ') + resp.error, variant: 'warning'});
40
42
  return;
41
43
  }
42
44
 
@@ -46,7 +48,7 @@
46
48
  router.push(resp.redirectTo);
47
49
  } else {
48
50
  console.error("Login not allowed:", resp.error);
49
- adminforth.alert({message: 'Error: ' + (resp.error || 'Login not allowed'), variant: 'warning'});
51
+ adminforth.alert({message: t('Error: ') + (resp.error || t('Login not allowed')), variant: 'warning'});
50
52
  }
51
53
  } catch (error) {
52
54
  console.error("Error during passkey login:", error);
@@ -23,7 +23,7 @@
23
23
  </div>
24
24
 
25
25
  <div class="mt-6 flex justify-center items-center gap-32 w-full">
26
- <p v-if="doesUserHavePasskeys===true" class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'passkey'" >use passkey</p>
26
+ <p v-if="doesUserHavePasskeys===true" class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'passkey'" >{{$t('use passkey')}}</p>
27
27
  <Button
28
28
  class="px-4 py-2 rounded border"
29
29
  @click="onCancel"
@@ -43,21 +43,21 @@
43
43
  <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
44
44
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
45
45
  </svg>
46
- <span class="sr-only">Close modal</span>
46
+ <span class="sr-only">{{$t('Close modal')}}</span>
47
47
  </button>
48
48
  <IconShieldOutline class="w-16 h-16 text-lightPrimary dark:text-darkPrimary"/>
49
- <p class="text-4xl font-semibold mb-4 text:gray-900 dark:text-gray-200 ">Passkey</p>
49
+ <p class="text-4xl font-semibold mb-4 text:gray-900 dark:text-gray-200 ">{{$t('Passkey')}}</p>
50
50
  <div class="mb-2 max-w-[300px] text:gray-900 dark:text-gray-200">
51
51
  <p class="mb-2">{{customDialogTitle}} </p>
52
- <p>Authenticate yourself using the button below</p>
52
+ <p>{{$t('Authenticate yourself using the button below')}}</p>
53
53
  </div>
54
54
  <Button @click="usePasskeyButtonClick" :disabled="isFetchingPasskey" :loader="isFetchingPasskey" class="w-full mx-16">
55
- Use passkey
55
+ {{$t('Use passkey')}}
56
56
  </Button>
57
57
  <div v-if="modalMode === 'passkey'" class="max-w-sm px-6 pt-3 w-full bg-white border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700">
58
58
  <div class="mb-3 font-normal text-gray-700 dark:text-gray-400">
59
- <p> Have issues with passkey? </p>
60
- <p class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'totp'" >use TOTP</p>
59
+ <p>{{$t('Have issues with passkey?')}}</p>
60
+ <p class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'totp'" >{{$t('use TOTP')}}</p>
61
61
  </div>
62
62
  </div>
63
63
 
@@ -168,11 +168,11 @@
168
168
  onCancel();
169
169
  return null;
170
170
  } else if (name === 'NotAllowedError') {
171
- adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'warning' });
171
+ adminforth.alert({ message: t('The operation either timed out or was not allowed'), variant: 'warning' });
172
172
  onCancel();
173
173
  return null;
174
174
  } else {
175
- adminforth.alert({message: `Error during authentication: ${error}`, variant: 'warning'});
175
+ adminforth.alert({message: t(`Error during authentication: ${error}`), variant: 'warning'});
176
176
  onCancel();
177
177
  return null;
178
178
  }
@@ -29,7 +29,7 @@
29
29
  @on-complete="handleOnComplete"
30
30
  />
31
31
  <div class="flex items-center justify-between w-full">
32
- <Link v-if="confirmationMode === 'code' && doesUserHavePasskeys" :to="{ hash: '#passkey' }" class="w-max underline hover:no-underline hover:cursor-pointer text-lightPrimary whitespace-nowrap">Use passkey</Link>
32
+ <Link v-if="confirmationMode === 'code' && doesUserHavePasskeys" :to="{ hash: '#passkey' }" class="w-max underline hover:no-underline hover:cursor-pointer text-lightPrimary whitespace-nowrap">{{$t('Use passkey')}}</Link>
33
33
  <Link
34
34
  v-if="confirmationMode === 'code'"
35
35
  to="/login"
@@ -42,17 +42,17 @@
42
42
  </div>
43
43
  <div v-else class="af-passkey-confirmation flex flex-col items-center justify-center py-4 gap-6">
44
44
  <IconShieldOutline class="w-16 h-16 text-lightPrimary dark:text-darkPrimary"/>
45
- <p class="text-4xl font-semibold mb-4">Passkey</p>
46
- <p class="mb-2 max-w-[300px]">When you are ready, authenticate using the button below</p>
45
+ <p class="text-4xl font-semibold mb-4">{{$t('Passkey')}}</p>
46
+ <p class="mb-2 max-w-[300px]">{{$t('When you are ready, authenticate using the button below')}}</p>
47
47
  <Button @click="usePasskeyButton" :disabled="isFetchingPasskey" :loader="isFetchingPasskey" class="w-full mx-16">
48
- Use passkey
48
+ {{$t('Use passkey')}}
49
49
  </Button>
50
50
  <div v-if="confirmationMode === 'passkey'" class="max-w-sm px-6 pt-3 w-full bg-white border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700">
51
51
  <p class="mb-3 font-normal text-gray-700 dark:text-gray-400">
52
- Have issues with passkey?
52
+ {{$t('Have issues with passkey?')}}
53
53
  <div v-if="doesUserHavePasskeys" class="flex justify-start cursor-pointer gap-2" >
54
- <Link v-if="confirmationMode === 'passkey'" :to="{ hash: '#code' }" class="underline hover:no-underline text-lightPrimary whitespace-nowrap">use TOTP</Link>
55
- <p> or </p>
54
+ <Link v-if="confirmationMode === 'passkey'" :to="{ hash: '#code' }" class="underline hover:no-underline text-lightPrimary whitespace-nowrap">{{$t('use TOTP')}}</Link>
55
+ <p> {{$t('or')}}</p>
56
56
  <Link
57
57
  to="/login"
58
58
  class="w-full"
@@ -318,7 +318,7 @@
318
318
  options = PublicKeyCredential.parseRequestOptionsFromJSON(_options);
319
319
  } catch (e) {
320
320
  console.error('Error parsing request options:', e);
321
- adminforth.alert({message: 'Error initiating passkey authentication.', variant: 'warning'});
321
+ adminforth.alert({message: t('Error initiating passkey authentication.'), variant: 'warning'});
322
322
  return;
323
323
  }
324
324
  const credential = await authenticate(options);
@@ -350,7 +350,7 @@
350
350
  if (response.ok === true) {
351
351
  return { _options: response.data, challengeId: response.challengeId };
352
352
  } else {
353
- adminforth.alert({message: 'Error creating sign-in request.', variant: 'warning'});
353
+ adminforth.alert({message: t('Error creating sign-in request.'), variant: 'warning'});
354
354
  codeError.value = 'Error creating sign-in request.';
355
355
  }
356
356
  }
@@ -389,12 +389,12 @@
389
389
  codeError.value = t('A previous passkey attempt was still pending. Please try again.');
390
390
  return null;
391
391
  } else if (name === 'NotAllowedError') {
392
- adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'warning' });
393
- codeError.value = 'The operation either timed out or was not allowed.';
392
+ adminforth.alert({ message: t('The operation either timed out or was not allowed'), variant: 'warning' });
393
+ codeError.value = t('The operation either timed out or was not allowed.');
394
394
  return null;
395
395
  } else {
396
- adminforth.alert({message: `Error during authentication: ${error}`, variant: 'warning'});
397
- codeError.value = 'Error during authentication.';
396
+ adminforth.alert({message: t(`Error during authentication: ${error}`), variant: 'warning'});
397
+ codeError.value = t('Error during authentication.');
398
398
  return null;
399
399
  }
400
400
  }
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="text-3xl text-lightBreadcrumbsText dark:text-darkBreadcrumbsText font-semibold max-w-2xl mr-6 flex-col justify-center items-center">
3
- <p class="flex items-start justify-start leading-none">Passkeys</p>
3
+ <p class="flex items-start justify-start leading-none">{{$t('Passkeys')}}</p>
4
4
  <div class="flex flex-col items-end">
5
5
  <Table
6
6
  class="mt-4 w-full"
@@ -37,12 +37,12 @@
37
37
  </div>
38
38
 
39
39
  <template #tooltip>
40
- Rename passkey
40
+ {{$t('Rename passkey')}}
41
41
  </template>
42
42
  </Tooltip>
43
43
  </template>
44
44
  <div>
45
- <p>Enter new passkey name:</p>
45
+ <p>{{$t('Enter new passkey name:')}}</p>
46
46
  <input
47
47
  v-model="passkeysNewName"
48
48
  type="text"
@@ -67,19 +67,19 @@
67
67
  />
68
68
  </div>
69
69
  <template #tooltip>
70
- Delete passkey
70
+ {{$t('Delete passkey')}}
71
71
  </template>
72
72
  </Tooltip>
73
73
  </template>
74
74
  <div>
75
- <p>Are you sure you want to delete this passkey?</p>
75
+ <p>{{$t('Are you sure you want to delete this passkey?')}}</p>
76
76
  </div>
77
77
  </Dialog>
78
78
  </div>
79
79
  </template>
80
80
  <template #cell:last_used_at="{item}">
81
81
  <span v-if="item.last_used_at">{{ formatDateTime(item.last_used_at) }}</span>
82
- <span v-else class="text-gray-400">Never</span>
82
+ <span v-else class="text-gray-400">{{$t('Never')}}</span>
83
83
  </template>
84
84
  </Table>
85
85
  <div class="flex space-x-4 mt-4" v-if="isInitialFinished">
@@ -96,7 +96,7 @@
96
96
  </div>
97
97
  </template>
98
98
  </ButtonGroup>
99
- <p v-else class="flex items-center justify-center gap-2 text-base">Processing <Spinner class="w-4 h-4 inline-block" /></p>
99
+ <p v-else class="flex items-center justify-center gap-2 text-base">{{$t('Processing')}} <Spinner class="w-4 h-4 inline-block" /></p>
100
100
  </div>
101
101
  <div v-if="isCardsVisible" id="cards-container" class="w-80 mt-2 border-gray-400 p-2 bg-white dark:bg-gray-800 rounded-lg shadow-md flex flex-col space-y-2">
102
102
  <div v-if="isPasskeySupported" class="flex justify-between gap-4" :class="!isPasskeySupported ? 'opacity-50 pointer-events-none' : ''">
@@ -126,8 +126,8 @@
126
126
  </div>
127
127
 
128
128
  <template #tooltip>
129
- <p class="max-w-64">This browser or device is reporting partial passkey support.</p>
130
- <p class="max-w-64"> To fix it try to install extention or change browser.</p>
129
+ <p class="max-w-64">{{$t('This browser or device is reporting partial passkey support.')}}</p>
130
+ <p class="max-w-64">{{$t('To fix it try to install extention or change browser.')}}</p>
131
131
  </template>
132
132
  </Tooltip>
133
133
  <div class="border-t border-gray-300"></div>
@@ -161,12 +161,12 @@
161
161
  <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
162
162
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
163
163
  </svg>
164
- <span class="sr-only">Close dialog</span>
164
+ <span class="sr-only">{{$t('Close dialog')}}</span>
165
165
  </button>
166
166
  <div class="flex items-center justify-center space-y-4">
167
- Now you can add a passkey.
167
+ {{$t('Now you can add a passkey.')}}
168
168
  </div>
169
- <Button class="mt-4" @click="addPasskeyFinishAction(fetchedOptions); closeDialog();">Add Passkey</Button>
169
+ <Button class="mt-4" @click="addPasskeyFinishAction(fetchedOptions); closeDialog();">{{$t('Add Passkey')}}</Button>
170
170
  </div>
171
171
  </Dialog>
172
172
  </div>
@@ -377,7 +377,6 @@
377
377
  async function callWebAuthn(options: any) {
378
378
  let credential;
379
379
  try {
380
- console.log('Creating credential with options:', options);
381
380
  credential = await navigator.credentials.create({
382
381
  publicKey: options
383
382
  });
@@ -5,7 +5,7 @@
5
5
  @click="handleLoginWithPasskey"
6
6
  >
7
7
  <IconShieldOutline class="w-7 h-8" />
8
- <span class="ml-2">Continue with Passkey</span>
8
+ <span class="ml-2">{{ $t('Continue with Passkey') }}</span>
9
9
  </Button>
10
10
 
11
11
  </template>
@@ -20,7 +20,9 @@
20
20
  import { Button } from '@/afcl';
21
21
  import adminforth from '@/adminforth';
22
22
  import { useRouter, useRoute } from 'vue-router';
23
+ import { useI18n } from 'vue-i18n';
23
24
 
25
+ const { t } = useI18n();
24
26
  const userStore = useUserStore();
25
27
  const router = useRouter();
26
28
 
@@ -36,7 +38,7 @@
36
38
  });
37
39
  if ( resp.error ) {
38
40
  console.error("Login failed:", resp.error);
39
- adminforth.alert({message: 'Error: ' + resp.error, variant: 'warning'});
41
+ adminforth.alert({message: t('Error: ') + resp.error, variant: 'warning'});
40
42
  return;
41
43
  }
42
44
 
@@ -46,7 +48,7 @@
46
48
  router.push(resp.redirectTo);
47
49
  } else {
48
50
  console.error("Login not allowed:", resp.error);
49
- adminforth.alert({message: 'Error: ' + (resp.error || 'Login not allowed'), variant: 'warning'});
51
+ adminforth.alert({message: t('Error: ') + (resp.error || t('Login not allowed')), variant: 'warning'});
50
52
  }
51
53
  } catch (error) {
52
54
  console.error("Error during passkey login:", error);
@@ -23,7 +23,7 @@
23
23
  </div>
24
24
 
25
25
  <div class="mt-6 flex justify-center items-center gap-32 w-full">
26
- <p v-if="doesUserHavePasskeys===true" class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'passkey'" >use passkey</p>
26
+ <p v-if="doesUserHavePasskeys===true" class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'passkey'" >{{$t('use passkey')}}</p>
27
27
  <Button
28
28
  class="px-4 py-2 rounded border"
29
29
  @click="onCancel"
@@ -43,21 +43,21 @@
43
43
  <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
44
44
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
45
45
  </svg>
46
- <span class="sr-only">Close modal</span>
46
+ <span class="sr-only">{{$t('Close modal')}}</span>
47
47
  </button>
48
48
  <IconShieldOutline class="w-16 h-16 text-lightPrimary dark:text-darkPrimary"/>
49
- <p class="text-4xl font-semibold mb-4 text:gray-900 dark:text-gray-200 ">Passkey</p>
49
+ <p class="text-4xl font-semibold mb-4 text:gray-900 dark:text-gray-200 ">{{$t('Passkey')}}</p>
50
50
  <div class="mb-2 max-w-[300px] text:gray-900 dark:text-gray-200">
51
51
  <p class="mb-2">{{customDialogTitle}} </p>
52
- <p>Authenticate yourself using the button below</p>
52
+ <p>{{$t('Authenticate yourself using the button below')}}</p>
53
53
  </div>
54
54
  <Button @click="usePasskeyButtonClick" :disabled="isFetchingPasskey" :loader="isFetchingPasskey" class="w-full mx-16">
55
- Use passkey
55
+ {{$t('Use passkey')}}
56
56
  </Button>
57
57
  <div v-if="modalMode === 'passkey'" class="max-w-sm px-6 pt-3 w-full bg-white border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700">
58
58
  <div class="mb-3 font-normal text-gray-700 dark:text-gray-400">
59
- <p> Have issues with passkey? </p>
60
- <p class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'totp'" >use TOTP</p>
59
+ <p>{{$t('Have issues with passkey?')}}</p>
60
+ <p class="underline hover:no-underline text-lightPrimary whitespace-nowrap hover:cursor-pointer" @click="modalMode = 'totp'" >{{$t('use TOTP')}}</p>
61
61
  </div>
62
62
  </div>
63
63
 
@@ -168,11 +168,11 @@
168
168
  onCancel();
169
169
  return null;
170
170
  } else if (name === 'NotAllowedError') {
171
- adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'warning' });
171
+ adminforth.alert({ message: t('The operation either timed out or was not allowed'), variant: 'warning' });
172
172
  onCancel();
173
173
  return null;
174
174
  } else {
175
- adminforth.alert({message: `Error during authentication: ${error}`, variant: 'warning'});
175
+ adminforth.alert({message: t(`Error during authentication: ${error}`), variant: 'warning'});
176
176
  onCancel();
177
177
  return null;
178
178
  }
@@ -29,7 +29,7 @@
29
29
  @on-complete="handleOnComplete"
30
30
  />
31
31
  <div class="flex items-center justify-between w-full">
32
- <Link v-if="confirmationMode === 'code' && doesUserHavePasskeys" :to="{ hash: '#passkey' }" class="w-max underline hover:no-underline hover:cursor-pointer text-lightPrimary whitespace-nowrap">Use passkey</Link>
32
+ <Link v-if="confirmationMode === 'code' && doesUserHavePasskeys" :to="{ hash: '#passkey' }" class="w-max underline hover:no-underline hover:cursor-pointer text-lightPrimary whitespace-nowrap">{{$t('Use passkey')}}</Link>
33
33
  <Link
34
34
  v-if="confirmationMode === 'code'"
35
35
  to="/login"
@@ -42,17 +42,17 @@
42
42
  </div>
43
43
  <div v-else class="af-passkey-confirmation flex flex-col items-center justify-center py-4 gap-6">
44
44
  <IconShieldOutline class="w-16 h-16 text-lightPrimary dark:text-darkPrimary"/>
45
- <p class="text-4xl font-semibold mb-4">Passkey</p>
46
- <p class="mb-2 max-w-[300px]">When you are ready, authenticate using the button below</p>
45
+ <p class="text-4xl font-semibold mb-4">{{$t('Passkey')}}</p>
46
+ <p class="mb-2 max-w-[300px]">{{$t('When you are ready, authenticate using the button below')}}</p>
47
47
  <Button @click="usePasskeyButton" :disabled="isFetchingPasskey" :loader="isFetchingPasskey" class="w-full mx-16">
48
- Use passkey
48
+ {{$t('Use passkey')}}
49
49
  </Button>
50
50
  <div v-if="confirmationMode === 'passkey'" class="max-w-sm px-6 pt-3 w-full bg-white border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700">
51
51
  <p class="mb-3 font-normal text-gray-700 dark:text-gray-400">
52
- Have issues with passkey?
52
+ {{$t('Have issues with passkey?')}}
53
53
  <div v-if="doesUserHavePasskeys" class="flex justify-start cursor-pointer gap-2" >
54
- <Link v-if="confirmationMode === 'passkey'" :to="{ hash: '#code' }" class="underline hover:no-underline text-lightPrimary whitespace-nowrap">use TOTP</Link>
55
- <p> or </p>
54
+ <Link v-if="confirmationMode === 'passkey'" :to="{ hash: '#code' }" class="underline hover:no-underline text-lightPrimary whitespace-nowrap">{{$t('use TOTP')}}</Link>
55
+ <p> {{$t('or')}}</p>
56
56
  <Link
57
57
  to="/login"
58
58
  class="w-full"
@@ -318,7 +318,7 @@
318
318
  options = PublicKeyCredential.parseRequestOptionsFromJSON(_options);
319
319
  } catch (e) {
320
320
  console.error('Error parsing request options:', e);
321
- adminforth.alert({message: 'Error initiating passkey authentication.', variant: 'warning'});
321
+ adminforth.alert({message: t('Error initiating passkey authentication.'), variant: 'warning'});
322
322
  return;
323
323
  }
324
324
  const credential = await authenticate(options);
@@ -350,7 +350,7 @@
350
350
  if (response.ok === true) {
351
351
  return { _options: response.data, challengeId: response.challengeId };
352
352
  } else {
353
- adminforth.alert({message: 'Error creating sign-in request.', variant: 'warning'});
353
+ adminforth.alert({message: t('Error creating sign-in request.'), variant: 'warning'});
354
354
  codeError.value = 'Error creating sign-in request.';
355
355
  }
356
356
  }
@@ -389,12 +389,12 @@
389
389
  codeError.value = t('A previous passkey attempt was still pending. Please try again.');
390
390
  return null;
391
391
  } else if (name === 'NotAllowedError') {
392
- adminforth.alert({ message: `The operation either timed out or was not allowed`, variant: 'warning' });
393
- codeError.value = 'The operation either timed out or was not allowed.';
392
+ adminforth.alert({ message: t('The operation either timed out or was not allowed'), variant: 'warning' });
393
+ codeError.value = t('The operation either timed out or was not allowed.');
394
394
  return null;
395
395
  } else {
396
- adminforth.alert({message: `Error during authentication: ${error}`, variant: 'warning'});
397
- codeError.value = 'Error during authentication.';
396
+ adminforth.alert({message: t(`Error during authentication: ${error}`), variant: 'warning'});
397
+ codeError.value = t('Error during authentication.');
398
398
  return null;
399
399
  }
400
400
  }
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="text-3xl text-lightBreadcrumbsText dark:text-darkBreadcrumbsText font-semibold max-w-2xl mr-6 flex-col justify-center items-center">
3
- <p class="flex items-start justify-start leading-none">Passkeys</p>
3
+ <p class="flex items-start justify-start leading-none">{{$t('Passkeys')}}</p>
4
4
  <div class="flex flex-col items-end">
5
5
  <Table
6
6
  class="mt-4 w-full"
@@ -37,12 +37,12 @@
37
37
  </div>
38
38
 
39
39
  <template #tooltip>
40
- Rename passkey
40
+ {{$t('Rename passkey')}}
41
41
  </template>
42
42
  </Tooltip>
43
43
  </template>
44
44
  <div>
45
- <p>Enter new passkey name:</p>
45
+ <p>{{$t('Enter new passkey name:')}}</p>
46
46
  <input
47
47
  v-model="passkeysNewName"
48
48
  type="text"
@@ -67,19 +67,19 @@
67
67
  />
68
68
  </div>
69
69
  <template #tooltip>
70
- Delete passkey
70
+ {{$t('Delete passkey')}}
71
71
  </template>
72
72
  </Tooltip>
73
73
  </template>
74
74
  <div>
75
- <p>Are you sure you want to delete this passkey?</p>
75
+ <p>{{$t('Are you sure you want to delete this passkey?')}}</p>
76
76
  </div>
77
77
  </Dialog>
78
78
  </div>
79
79
  </template>
80
80
  <template #cell:last_used_at="{item}">
81
81
  <span v-if="item.last_used_at">{{ formatDateTime(item.last_used_at) }}</span>
82
- <span v-else class="text-gray-400">Never</span>
82
+ <span v-else class="text-gray-400">{{$t('Never')}}</span>
83
83
  </template>
84
84
  </Table>
85
85
  <div class="flex space-x-4 mt-4" v-if="isInitialFinished">
@@ -96,7 +96,7 @@
96
96
  </div>
97
97
  </template>
98
98
  </ButtonGroup>
99
- <p v-else class="flex items-center justify-center gap-2 text-base">Processing <Spinner class="w-4 h-4 inline-block" /></p>
99
+ <p v-else class="flex items-center justify-center gap-2 text-base">{{$t('Processing')}} <Spinner class="w-4 h-4 inline-block" /></p>
100
100
  </div>
101
101
  <div v-if="isCardsVisible" id="cards-container" class="w-80 mt-2 border-gray-400 p-2 bg-white dark:bg-gray-800 rounded-lg shadow-md flex flex-col space-y-2">
102
102
  <div v-if="isPasskeySupported" class="flex justify-between gap-4" :class="!isPasskeySupported ? 'opacity-50 pointer-events-none' : ''">
@@ -126,8 +126,8 @@
126
126
  </div>
127
127
 
128
128
  <template #tooltip>
129
- <p class="max-w-64">This browser or device is reporting partial passkey support.</p>
130
- <p class="max-w-64"> To fix it try to install extention or change browser.</p>
129
+ <p class="max-w-64">{{$t('This browser or device is reporting partial passkey support.')}}</p>
130
+ <p class="max-w-64">{{$t('To fix it try to install extention or change browser.')}}</p>
131
131
  </template>
132
132
  </Tooltip>
133
133
  <div class="border-t border-gray-300"></div>
@@ -161,12 +161,12 @@
161
161
  <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
162
162
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
163
163
  </svg>
164
- <span class="sr-only">Close dialog</span>
164
+ <span class="sr-only">{{$t('Close dialog')}}</span>
165
165
  </button>
166
166
  <div class="flex items-center justify-center space-y-4">
167
- Now you can add a passkey.
167
+ {{$t('Now you can add a passkey.')}}
168
168
  </div>
169
- <Button class="mt-4" @click="addPasskeyFinishAction(fetchedOptions); closeDialog();">Add Passkey</Button>
169
+ <Button class="mt-4" @click="addPasskeyFinishAction(fetchedOptions); closeDialog();">{{$t('Add Passkey')}}</Button>
170
170
  </div>
171
171
  </Dialog>
172
172
  </div>
@@ -377,7 +377,6 @@
377
377
  async function callWebAuthn(options: any) {
378
378
  let credential;
379
379
  try {
380
- console.log('Creating credential with options:', options);
381
380
  credential = await navigator.credentials.create({
382
381
  publicKey: options
383
382
  });
package/dist/index.js CHANGED
@@ -255,7 +255,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
255
255
  const beforeLoginConfirmation = this.adminforth.config.auth.beforeLoginConfirmation;
256
256
  const beforeLoginConfirmationArray = Array.isArray(beforeLoginConfirmation) ? beforeLoginConfirmation : [beforeLoginConfirmation];
257
257
  beforeLoginConfirmationArray.push((_a) => __awaiter(this, [_a], void 0, function* ({ adminUser, response, extra }) {
258
- var _b, _c;
258
+ var _b, _c, _d, _e;
259
259
  if (((_b = extra === null || extra === void 0 ? void 0 : extra.body) === null || _b === void 0 ? void 0 : _b.loginAllowedByPasskeyDirectSignIn) === true) {
260
260
  return { body: { loginAllowed: true }, ok: true };
261
261
  }
@@ -280,7 +280,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
280
280
  if (!secret) {
281
281
  const tempSecret = twofactor.generateSecret({ name: issuerName, account: userName });
282
282
  newSecret = tempSecret.secret;
283
- const totpTemporaryJWT = this.adminforth.auth.issueJWT({ userName, newSecret, issuer: issuerName, pk: userPk, userCanSkipSetup, rememberMeDays }, 'temp2FA', '10m');
283
+ const totpTemporaryJWT = this.adminforth.auth.issueJWT({ userName, newSecret, issuer: issuerName, pk: userPk, userCanSkipSetup, rememberMeDays }, 'temp2FA', ((_d = this.options.passkeys) === null || _d === void 0 ? void 0 : _d.challengeValidityPeriod) || '1m');
284
284
  this.adminforth.auth.setCustomCookie({ response, payload: { name: "2FaTemporaryJWT", value: totpTemporaryJWT, expiry: undefined, expirySeconds: 10 * 60, httpOnly: true } });
285
285
  return {
286
286
  body: {
@@ -291,7 +291,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
291
291
  };
292
292
  }
293
293
  else {
294
- const value = this.adminforth.auth.issueJWT({ userName, issuer: issuerName, pk: userPk, userCanSkipSetup, rememberMeDays }, 'temp2FA', '10m');
294
+ const value = this.adminforth.auth.issueJWT({ userName, issuer: issuerName, pk: userPk, userCanSkipSetup, rememberMeDays }, 'temp2FA', ((_e = this.options.passkeys) === null || _e === void 0 ? void 0 : _e.challengeValidityPeriod) || '1m');
295
295
  this.adminforth.auth.setCustomCookie({ response, payload: { name: "2FaTemporaryJWT", value: value, expiry: undefined, expirySeconds: 10 * 60, httpOnly: true } });
296
296
  return {
297
297
  body: {
@@ -511,7 +511,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
511
511
  path: `/plugin/passkeys/registerPasskeyRequest`,
512
512
  noAuth: false,
513
513
  handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, cookies }) {
514
- var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
514
+ var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
515
515
  const mode = body === null || body === void 0 ? void 0 : body.mode;
516
516
  const confirmationResult = body === null || body === void 0 ? void 0 : body.confirmationResult;
517
517
  const verificationResult = yield this.verify(confirmationResult, {
@@ -562,7 +562,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
562
562
  userVerification: ((_m = this.options.passkeys) === null || _m === void 0 ? void 0 : _m.settings.authenticatorSelection.userVerification) || "required"
563
563
  },
564
564
  });
565
- const value = this.adminforth.auth.issueJWT({ "challenge": options.challenge, "user_id": adminUser.pk }, 'registerTempPasskeyChallenge', '10m');
565
+ const value = this.adminforth.auth.issueJWT({ "challenge": options.challenge, "user_id": adminUser.pk }, 'registerTempPasskeyChallenge', ((_o = this.options.passkeys) === null || _o === void 0 ? void 0 : _o.challengeValidityPeriod) || '1m');
566
566
  this.adminforth.auth.setCustomCookie({ response, payload: { name: "registerPasskeyTemporaryJWT", value: value, expiry: undefined, expirySeconds: 10 * 60, httpOnly: true } });
567
567
  return { ok: true, data: options };
568
568
  })
@@ -644,13 +644,13 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
644
644
  path: `/plugin/passkeys/signInRequest`,
645
645
  noAuth: true,
646
646
  handler: (_a) => __awaiter(this, [_a], void 0, function* ({ response }) {
647
- var _b, _c;
647
+ var _b, _c, _d;
648
648
  try {
649
649
  const options = yield generateAuthenticationOptions({
650
650
  rpID: (_b = this.options.passkeys) === null || _b === void 0 ? void 0 : _b.settings.rp.id,
651
651
  userVerification: ((_c = this.options.passkeys) === null || _c === void 0 ? void 0 : _c.settings.authenticatorSelection.userVerification) || "required"
652
652
  });
653
- const value = this.adminforth.auth.issueJWT({ "challenge": options.challenge }, 'tempLoginPasskeyChallenge', '10m');
653
+ const value = this.adminforth.auth.issueJWT({ "challenge": options.challenge }, 'tempLoginPasskeyChallenge', ((_d = this.options.passkeys) === null || _d === void 0 ? void 0 : _d.challengeValidityPeriod) || '1m');
654
654
  this.adminforth.auth.setCustomCookie({ response, payload: { name: `passkeyLoginTemporaryJWT`, value: value, expiry: undefined, expirySeconds: 10 * 60, httpOnly: true } });
655
655
  return { ok: true, data: options };
656
656
  }
package/index.ts CHANGED
@@ -316,7 +316,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
316
316
  const tempSecret = twofactor.generateSecret({name: issuerName,account: userName})
317
317
  newSecret = tempSecret.secret;
318
318
 
319
- const totpTemporaryJWT = this.adminforth.auth.issueJWT({userName, newSecret, issuer:issuerName, pk:userPk, userCanSkipSetup, rememberMeDays }, 'temp2FA', '10m');
319
+ const totpTemporaryJWT = this.adminforth.auth.issueJWT({userName, newSecret, issuer:issuerName, pk:userPk, userCanSkipSetup, rememberMeDays }, 'temp2FA', this.options.passkeys?.challengeValidityPeriod || '1m');
320
320
  this.adminforth.auth.setCustomCookie({response, payload: {name: "2FaTemporaryJWT", value: totpTemporaryJWT, expiry: undefined, expirySeconds: 10 * 60, httpOnly: true}});
321
321
 
322
322
  return {
@@ -328,7 +328,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
328
328
  }
329
329
 
330
330
  } else {
331
- const value = this.adminforth.auth.issueJWT({userName, issuer:issuerName, pk:userPk, userCanSkipSetup, rememberMeDays }, 'temp2FA', '10m');
331
+ const value = this.adminforth.auth.issueJWT({userName, issuer:issuerName, pk:userPk, userCanSkipSetup, rememberMeDays }, 'temp2FA', this.options.passkeys?.challengeValidityPeriod || '1m');
332
332
  this.adminforth.auth.setCustomCookie({response, payload: {name: "2FaTemporaryJWT", value: value, expiry: undefined, expirySeconds: 10 * 60, httpOnly: true}});
333
333
 
334
334
  return {
@@ -615,7 +615,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
615
615
  userVerification: this.options.passkeys?.settings.authenticatorSelection.userVerification || "required"
616
616
  },
617
617
  });
618
- const value = this.adminforth.auth.issueJWT({ "challenge": options.challenge, "user_id": adminUser.pk }, 'registerTempPasskeyChallenge', '10m');
618
+ const value = this.adminforth.auth.issueJWT({ "challenge": options.challenge, "user_id": adminUser.pk }, 'registerTempPasskeyChallenge', this.options.passkeys?.challengeValidityPeriod || '1m');
619
619
  this.adminforth.auth.setCustomCookie({response, payload: {name: "registerPasskeyTemporaryJWT", value: value, expiry: undefined, expirySeconds: 10 * 60, httpOnly: true}});
620
620
  return { ok: true, data: options };
621
621
  }
@@ -707,7 +707,7 @@ export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
707
707
  rpID: this.options.passkeys?.settings.rp.id,
708
708
  userVerification: this.options.passkeys?.settings.authenticatorSelection.userVerification || "required"
709
709
  });
710
- const value = this.adminforth.auth.issueJWT({ "challenge": options.challenge }, 'tempLoginPasskeyChallenge', '10m');
710
+ const value = this.adminforth.auth.issueJWT({ "challenge": options.challenge }, 'tempLoginPasskeyChallenge', this.options.passkeys?.challengeValidityPeriod || '1m');
711
711
  this.adminforth.auth.setCustomCookie({response, payload: {name: `passkeyLoginTemporaryJWT`, value: value, expiry: undefined, expirySeconds: 10 * 60, httpOnly: true}});
712
712
  return { ok: true, data: options };
713
713
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/two-factors-auth",
3
- "version": "2.6.2",
3
+ "version": "2.7.1",
4
4
  "description": "AdminForth plugin for two factors authentication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/types.ts CHANGED
@@ -45,6 +45,10 @@ export type PluginOptions = {
45
45
  * Period between showing alert suggesting to set up Passkeys if not set up yet.
46
46
  */
47
47
  suggestionPeriod?: string; // e.g. '30d', '12h', '15m'. Default is '5d'
48
+ /**
49
+ * Challenge period for Passkeys authentication.
50
+ */
51
+ challengeValidityPeriod?: string; // e.g. '5m', '10m', '15m'. Default is '1m'
48
52
  /**
49
53
  * Passkeys settings for WebAuthn API.
50
54
  */