- added backup codes for 2 factor authentication
Some checks failed
CI Pipeline / japa-tests (push) Failing after 58s
Some checks failed
CI Pipeline / japa-tests (push) Failing after 58s
- npm updates - coverage validation: elevation ust be positive, depth must be negative - vinejs-provider.js: get enabled extensions from database, not via validOptions.extnames - vue components for backup codes: e.g.: PersonalSettings.vue - validate spaital coverage in leaflet map: draw.component.vue, map.component.vue - add backup code authentication into Login.vue - preset to use no preferred reviewer: Release.vue - 2 new vinejs validation rules: file_scan.ts and file-length.ts
This commit is contained in:
parent
ac473b1e72
commit
005df2e454
32 changed files with 1416 additions and 526 deletions
152
resources/js/Components/PersonalSettings.vue
Normal file
152
resources/js/Components/PersonalSettings.vue
Normal file
|
@ -0,0 +1,152 @@
|
|||
<template>
|
||||
<div>
|
||||
<BaseButton v-if="!enabled" id="generate-backup-codes" class="mx-2" :icon="mdiContentSaveCheck" type="button"
|
||||
color="info" :class="{ 'icon-loading-small': generatingCodes }" :disabled="generatingCodes"
|
||||
label=" Generate backup codes" @click="generateBackupCodes" />
|
||||
|
||||
<template v-else>
|
||||
|
||||
<template v-if="!haveCodes">
|
||||
{{ `Backup codes have been generated. ${used} of ${total} codes have been used.` }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<div>
|
||||
These are your backup codes. Please save and/or print them as you will not be able to read the codes
|
||||
again later
|
||||
<ul>
|
||||
<li v-for="code in codes" :key="code" class="backup-code">
|
||||
{{ code }}
|
||||
</li>
|
||||
</ul>
|
||||
<BaseButton :href="downloadUrl" class="mt-2 mb-2" :download="downloadFilename" rounded-full small
|
||||
:icon="mdiContentSave" :label="'Save backup codes'">
|
||||
</BaseButton>
|
||||
<BaseButton @click="printCodes" rounded-full small :icon="mdiContentSave"
|
||||
:label="'Print backup codes'">
|
||||
</BaseButton>
|
||||
<!-- <button class="button" @click="printCodes">
|
||||
{{ t('twofactor_backupcodes', 'Print backup codes') }}
|
||||
</button> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<div class="mt-4 max-w-xl text-sm text-gray-600">
|
||||
<BaseButton class="mt-2 mb-2" :icon="mdiContentSaveCheck" type="button" color="info"
|
||||
:disabled="generatingCodes" label="Regenerate backup codes" @click="generateBackupCodes" />
|
||||
</div>
|
||||
<p>
|
||||
<em> 'twofactor_backupcodes', `If you regenerate backup codes, you automatically invalidate old codes.`
|
||||
</em>
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, Ref } from 'vue';
|
||||
import { ComputedRef } from 'vue';
|
||||
import { MainService } from '@/Stores/main';
|
||||
import Notification from '@/utils/toast';
|
||||
import { mdiContentSaveCheck, mdiContentSave } from '@mdi/js';
|
||||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
// import { useI18n } from 'vue-i18n';
|
||||
// import { confirmPassword } from '@nextcloud/password-confirmation'
|
||||
// import '@nextcloud/password-confirmation/dist/style.css'
|
||||
// import { print } from '../service/PrintService.js'
|
||||
// const { t } = useI18n();
|
||||
|
||||
const generatingCodes: Ref<boolean> = ref(false);
|
||||
const mainService = MainService();
|
||||
|
||||
const props = defineProps({
|
||||
backupState: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
if (props.backupState.enabled) {
|
||||
mainService.backupcodesEnabled = true;
|
||||
mainService.total = props.backupState.total;
|
||||
mainService.used = props.backupState.used;
|
||||
}
|
||||
|
||||
const enabled = computed(() => mainService.backupcodesEnabled);
|
||||
const total = computed(() => mainService.total);
|
||||
const used = computed(() => mainService.used);
|
||||
const codes: ComputedRef<string[]> = computed(() => mainService.codes);
|
||||
const haveCodes = computed(() => {
|
||||
return codes && codes.value.length > 0;
|
||||
});
|
||||
const downloadFilename = computed(() => {
|
||||
return 'tethys-backup-codes.txt';
|
||||
});
|
||||
const downloadUrl = computed(() => {
|
||||
if (!codes) {
|
||||
return '';
|
||||
}
|
||||
return (
|
||||
'data:text/plain,' +
|
||||
encodeURIComponent(
|
||||
codes.value.reduce((prev, code) => {
|
||||
return prev + code + '\r\n';
|
||||
}, ''),
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
const print = (data: any) => {
|
||||
const name = 'Tethys';
|
||||
// const newTab = window.open('', `${name} backup codes`)
|
||||
const newTab = window.open('about:blank', `${name} backup codes`);
|
||||
if (newTab) {
|
||||
newTab.document.write('<h1>' + `${name} backup codes` + '</h1>');
|
||||
newTab.document.write('<pre>' + data + '</pre>');
|
||||
newTab.print();
|
||||
newTab.close();
|
||||
}
|
||||
};
|
||||
const getPrintData = (codes: string[]) => {
|
||||
if (!codes) {
|
||||
return '';
|
||||
}
|
||||
return codes.reduce((prev, code) => {
|
||||
return prev + code + '<br>';
|
||||
}, '');
|
||||
};
|
||||
|
||||
const printCodes = () => {
|
||||
const data = getPrintData(codes.value);
|
||||
print(data);
|
||||
};
|
||||
|
||||
const generateBackupCodes = async () => {
|
||||
// Hide old codes
|
||||
generatingCodes.value = true;
|
||||
|
||||
try {
|
||||
await mainService.generate();
|
||||
generatingCodes.value = false;
|
||||
} catch (err) {
|
||||
Notification.showTemporary('An error occurred while generating your backup codes');
|
||||
generatingCodes.value = false;
|
||||
throw err;
|
||||
}
|
||||
|
||||
// this.$store.dispatch('generate').then(data => {
|
||||
// this.generatingCodes = false
|
||||
// }).catch(err => {
|
||||
// OC.Notification.showTemporary(t('twofactor_backupcodes', 'An error occurred while generating your backup codes'))
|
||||
// this.generatingCodes = false
|
||||
// throw err
|
||||
// })
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.backup-code {
|
||||
font-family: monospace;
|
||||
letter-spacing: 0.02em;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
</style>
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue