aboutsummaryrefslogtreecommitdiff
path: root/front-end/src/views
diff options
context:
space:
mode:
Diffstat (limited to 'front-end/src/views')
-rw-r--r--front-end/src/views/Account/components/settings/Fido.vue8
-rw-r--r--front-end/src/views/Account/components/settings/PasswordReset.vue4
-rw-r--r--front-end/src/views/Account/components/settings/Pki.vue124
-rw-r--r--front-end/src/views/Account/components/settings/Security.vue22
-rw-r--r--front-end/src/views/Account/components/settings/TotpSettings.vue12
5 files changed, 120 insertions, 50 deletions
diff --git a/front-end/src/views/Account/components/settings/Fido.vue b/front-end/src/views/Account/components/settings/Fido.vue
index 340d6d9..f319cd3 100644
--- a/front-end/src/views/Account/components/settings/Fido.vue
+++ b/front-end/src/views/Account/components/settings/Fido.vue
@@ -12,15 +12,15 @@
<h6>FIDO/WebAuthN Authentication</h6>
<div class="">
<div v-if="fidoEnabled" class="">
- <button class="ml-1 btn red sm" @click.prevent="Disable">
+ <button class="ml-1 btn red xs" @click.prevent="Disable">
<fa-icon icon="minus-circle" />
- <span class="pl-3">Disable</span>
+ <span class="pl-2">Disable</span>
</button>
</div>
<div v-else>
- <button class="btn primary sm" @click.prevent="Setup">
+ <button class="btn primary xs" @click.prevent="Setup">
<fa-icon icon="plus" />
- <span class="pl-3">Setup</span>
+ <span class="pl-2">Setup</span>
</button>
</div>
</div>
diff --git a/front-end/src/views/Account/components/settings/PasswordReset.vue b/front-end/src/views/Account/components/settings/PasswordReset.vue
index b1389ac..f90bce8 100644
--- a/front-end/src/views/Account/components/settings/PasswordReset.vue
+++ b/front-end/src/views/Account/components/settings/PasswordReset.vue
@@ -12,9 +12,9 @@
</div>
<div class="flex justify-end">
- <button class="btn red sm" @click="showForm">
+ <button class="btn red xs" @click="showForm">
<fa-icon icon="sync" />
- <span class="pl-3">Reset Password</span>
+ <span class="pl-2">Reset Password</span>
</button>
</div>
</div>
diff --git a/front-end/src/views/Account/components/settings/Pki.vue b/front-end/src/views/Account/components/settings/Pki.vue
index a937cc7..1b169e2 100644
--- a/front-end/src/views/Account/components/settings/Pki.vue
+++ b/front-end/src/views/Account/components/settings/Pki.vue
@@ -1,29 +1,68 @@
<template>
<div id="pki-settings" v-show="pkiEnabled" class="container">
<div class="panel-content">
- <h5>PKI Authentication</h5>
+
<div class="flex flex-row flex-wrap justify-between">
- <h6>Authentication keys</h6>
-
- <div v-if="enabled" class="button-group">
- <button class="btn yellow sm" @click.prevent="setIsOpen(true)">
- <fa-icon icon="sync" />
- <span class="pl-3">Update Key</span>
- </button>
- <button class="btn red sm" @click.prevent="onDisable">
- <fa-icon icon="minus-circle" />
- <span class="pl-3">Disable</span>
- </button>
+ <h5>PKI Authentication</h5>
+ <div class="">
+ <div v-if="enabled" class="button-group">
+ <button class="btn yellow xs" @click.prevent="setIsOpen(true)">
+ <fa-icon icon="plus" />
+ <span class="pl-2">Add Key</span>
+ </button>
+ <button class="btn red xs" @click.prevent="onDisable">
+ <fa-icon icon="minus-circle" />
+ <span class="pl-2">Disable</span>
+ </button>
+ </div>
+ <div v-else class="">
+ <button class="btn primary xs" @click.prevent="setIsOpen(true)">
+ <fa-icon icon="plus" />
+ <span class="pl-2">Add Key</span>
+ </button>
+ </div>
</div>
-
- <div v-else class="">
- <button class="btn primary sm" @click.prevent="setIsOpen(true)">
- <fa-icon icon="plus" />
- <span class="pl-3">Add Key</span>
- </button>
+
+ <div v-if="pubKeys && pubKeys.length > 0" class="w-full mt-4">
+ <table class="min-w-full text-sm divide-y-2 divide-gray-200 dark:divide-dark-500">
+ <thead class="text-left">
+ <tr>
+ <th class="p-2 font-medium whitespace-nowrap dark:text-white" >
+ KeyID
+ </th>
+ <th class="p-2 font-medium whitespace-nowrap dark:text-white">
+ Algorithm
+ </th>
+ <th class="p-2 font-medium whitespace-nowrap dark:text-white">
+ Curve
+ </th>
+ <th class="p-2"></th>
+ </tr>
+ </thead>
+
+ <tbody class="divide-y divide-gray-200 dark:divide-dark-500">
+ <tr v-for="key in pubKeys">
+ <td class="p-2 t font-medium truncate max-w-[8rem] whitespace-nowrap dark:text-white">
+ {{ key.kid }}
+ </td>
+ <td class="p-2 text-gray-700 whitespace-nowrap dark:text-gray-200">
+ {{ key.alg }}
+ </td>
+ <td class="p-2 text-gray-700 whitespace-nowrap dark:text-gray-200">
+ {{ key.crv }}
+ </td>
+ <td class="p-2 text-right whitespace-nowrap">
+ <button class="rounded btn red xs borderless" @click="onRemoveKey(key)">
+ <span class="hidden sm:inline">Remove</span>
+ <fa-icon icon="trash-can" class="inline sm:hidden" />
+ </button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
</div>
- <p class="p-1 pt-3 text-sm text-gray-600">
+ <p v-else class="p-1 pt-3 text-sm text-gray-600">
PKI authentication is a method of authenticating your user account with signed messages and a shared public key. This method implementation
uses client signed Json Web Tokens to authenticate user generated outside this website as a One Time Password (OTP). This allows for you to
use your favorite hardware or software tools, to generate said OTPs to authenticate your user.
@@ -55,8 +94,9 @@
<script setup lang="ts">
import { isEmpty, isNil } from 'lodash-es'
-import { apiCall, useConfirm, useSession, debugLog, useFormToaster, PkiApi } from '@vnuge/vnlib.browser'
+import { apiCall, useConfirm, useSession, debugLog, useFormToaster, PkiApi, PkiPublicKey } from '@vnuge/vnlib.browser'
import { computed, ref, watch } from 'vue'
+import { asyncComputed } from '@vueuse/core'
import { Dialog, DialogPanel } from '@headlessui/vue'
const props = defineProps<{
@@ -70,6 +110,8 @@ const { error } = useFormToaster()
const pkiEnabled = computed(() => isLocalAccount.value && !isNil(import.meta.env.VITE_PKI_ENDPOINT) && window.crypto.subtle)
const { enabled, refresh } = props.pkaiApi
+const pubKeys = asyncComputed(() => pkiEnabled.value ? apiCall(props.pkaiApi.getAllKeys) : [], [])
+
const isOpen = ref(false)
const keyData = ref('')
const pemFormat = ref(false)
@@ -85,6 +127,39 @@ watch(isOpen, () =>{
const setIsOpen = (value : boolean) => isOpen.value = value
+const onRemoveKey = async (single: PkiPublicKey) =>{
+ const { isCanceled } = await reveal({
+ title: 'Are you sure?',
+ text: `This will remove key ${single.kid} from your account.`
+ })
+ if (isCanceled) {
+ return;
+ }
+
+ //Delete pki
+ await apiCall(async ({ toaster }) => {
+
+ //TODO: require password or some upgrade to disable
+ const { success } = await props.pkaiApi.removeKey(single.kid);
+
+ if (success) {
+ toaster.general.success({
+ title: 'Success',
+ text: 'Key was removed successfully.'
+ })
+ }
+ else {
+ toaster.general.error({
+ title: 'Error',
+ text: 'Your single PKI key could not be removed.'
+ })
+ }
+
+ //Refresh the status
+ props.pkaiApi.refresh();
+ });
+}
+
const onDisable = async () => {
const { isCanceled } = await reveal({
title: 'Are you sure?',
@@ -119,11 +194,6 @@ const onDisable = async () => {
});
}
-//Server requires the JWK to set a keyid (kid) field
-interface IdJsonWebKey extends JsonWebKey {
- readonly kid?: string
-}
-
const onSubmitKeys = async () =>{
if(window.crypto.subtle == null){
@@ -137,7 +207,7 @@ const onSubmitKeys = async () =>{
return;
}
- let jwk : IdJsonWebKey;
+ let jwk : PkiPublicKey & JsonWebKey;
try {
//Try to parse as jwk
jwk = JSON.parse(keyData.value)
@@ -162,7 +232,7 @@ const onSubmitKeys = async () =>{
//init/update the key
//TODO: require password or some upgrade to disable
- const { getResultOrThrow } = await props.pkaiApi.initOrUpdate(jwk);
+ const { getResultOrThrow } = await props.pkaiApi.addOrUpdate(jwk);
const result = getResultOrThrow();
diff --git a/front-end/src/views/Account/components/settings/Security.vue b/front-end/src/views/Account/components/settings/Security.vue
index 39df512..42b7389 100644
--- a/front-end/src/views/Account/components/settings/Security.vue
+++ b/front-end/src/views/Account/components/settings/Security.vue
@@ -27,16 +27,16 @@
<h5>Keep me logged in</h5>
<div class="pl-1">
<Switch
- v-model="enabled"
- :class="enabled ? 'bg-primary-500 dark:bg-primary-600' : 'bg-gray-200 dark:bg-dark-400'"
- class="relative inline-flex items-center h-6 rounded-full w-11"
- >
- <span class="sr-only">Enable auto heartbeat</span>
- <span
- :class="enabled ? 'translate-x-6' : 'translate-x-1'"
- class="inline-block w-4 h-4 transition transform bg-white rounded-full"
- />
- </Switch>
+ v-model="enabled"
+ :class="enabled ? 'bg-primary-500 dark:bg-primary-600' : 'bg-gray-200 dark:bg-dark-400'"
+ class="relative inline-flex items-center h-6 rounded-full w-11"
+ >
+ <span class="sr-only">Enable auto heartbeat</span>
+ <span
+ :class="enabled ? 'translate-x-6' : 'translate-x-1'"
+ class="inline-block w-4 h-4 transition transform bg-white rounded-full"
+ />
+ </Switch>
</div>
</div>
@@ -52,7 +52,7 @@
</template>
<script setup lang="ts">
-import { useAutoHeartbeat, useMfaConfig, MfaMethod, usePkiConfig } from '@vnuge/vnlib.browser'
+import { useAutoHeartbeat, useMfaConfig, MfaMethod, usePkiConfig } from '@vnuge/vnlib.browser'
import { computed } from 'vue'
import { Switch } from '@headlessui/vue'
import { includes } from 'lodash-es'
diff --git a/front-end/src/views/Account/components/settings/TotpSettings.vue b/front-end/src/views/Account/components/settings/TotpSettings.vue
index 4dc686a..9760806 100644
--- a/front-end/src/views/Account/components/settings/TotpSettings.vue
+++ b/front-end/src/views/Account/components/settings/TotpSettings.vue
@@ -58,20 +58,20 @@
<h6>TOTP Authenticator App</h6>
<div v-if="totpEnabled" class="button-group">
- <button class="btn yellow sm" @click.prevent="regenTotp">
+ <button class="btn yellow xs" @click.prevent="regenTotp">
<fa-icon icon="sync" />
- <span class="pl-3">Regenerate</span>
+ <span class="pl-2">Regenerate</span>
</button>
- <button class="btn red sm" @click.prevent="disable">
+ <button class="btn red xs" @click.prevent="disable">
<fa-icon icon="minus-circle" />
- <span class="pl-3">Disable</span>
+ <span class="pl-2">Disable</span>
</button>
</div>
<div v-else>
- <button class="btn primary sm" @click.prevent="configTotp">
+ <button class="btn primary xs" @click.prevent="configTotp">
<fa-icon icon="plus" />
- <span class="pl-3">Setup</span>
+ <span class="pl-2">Setup</span>
</button>
</div>
<p class="p-1 pt-3 text-sm text-gray-600">