Skip to content

Commit

Permalink
feature: add 2fa[WTEL-3405]
Browse files Browse the repository at this point in the history
  • Loading branch information
Lera24 committed May 15, 2024
1 parent 100f17a commit 7218c45
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 12 deletions.
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"jszip-utils": "^0.1.0",
"monaco-editor": "^0.44.0",
"path": "^0.12.7",
"qrcode.vue": "^3.4.1",
"query-string": "^7.1.1",
"sortablejs": "^1.10.2",
"vue": "^3.2.47",
Expand Down
3 changes: 3 additions & 0 deletions src/app/locale/en/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ export default {
tokenPopupSave: 'Save as TXT',
userIp: 'User IP',
userId: 'User ID',
download: 'Download',
regenerate: 'Regenerate',
askingAlert: 'Are you sure you want to regenerate the code? The user won’t be able to log in',
},
license: {
customers: 'Customers',
Expand Down
3 changes: 3 additions & 0 deletions src/app/locale/ru/ru.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ export default {
tokenPopupSave: 'Сохранить в формате TXT',
userIp: 'IP пользователя',
userId: 'ID пользователя',
download: 'Скачать',
regenerate: 'Перегенерировать',
askingAlert: 'Вы уверены, что хотите перегенерировать QR-код? Пользователь потеряет возможность войти в систему',
},
license: {
customers: 'Пользователи',
Expand Down
3 changes: 3 additions & 0 deletions src/app/locale/ua/ua.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ export default {
tokenPopupSave: 'Зберегти у форматі TXT',
userIp: 'IP користувача',
userId: 'ID користувача',
download: 'Завантажити',
regenerate: 'Перегенерувати',
askingAlert: 'Ви впевнені, що хочете перегенерувати QR-код? Користувач втратить можливість зайти в систему',
},
license: {
customers: 'Користувачі',
Expand Down
21 changes: 21 additions & 0 deletions src/modules/directory/modules/users/api/users-2fa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import applyTransform, { notify } from '@webitel/ui-sdk/src/api/transformers/index.js';
import instance from '../../../../../app/api/instance';

const generateUrl = async ({ id }) => {
const url = `users/${id}/2fa`;

try {
const response = await instance.post(url,{});
return applyTransform(response.data, []);
} catch (err) {
throw applyTransform(err, [
notify,
]);
}
};

const Users2faAPI = {
generate: generateUrl,
};

export default Users2faAPI;
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<template>
<div class="user-qrcode">

<wt-popup
v-if="isConfirmationPopup"
overflow
@close="closeConfirmationPopup"
>

<template v-slot:title>
{{ $t('reusable.warning') }}
</template>

<template v-slot:main>
{{ $t('objects.directory.users.askingAlert') }}
</template>

<template v-slot:actions>
<wt-button
color="secondary"
@click="closeConfirmationPopup"
>
{{ $t('vocabulary.no') }}
</wt-button>

<wt-button
color="error"
@click="regenerateUrl"
>
{{ $t('vocabulary.yes') }}
</wt-button>
</template>
</wt-popup>

<div
ref="qrcodeContainer"
class="user-qrcode__canvas"
>
<qrcode-vue
ref="qrcode"
:value="props.url"
level="H"
/>
</div>

<div class="user-qrcode__wrapper">
<wt-button
color="secondary"
@click="download"
>
{{ $t('objects.directory.users.download') }}
</wt-button>

<wt-button
color="error"
@click="openConfirmationPopup"
>
{{ $t('objects.directory.users.regenerate') }}
</wt-button>
</div>

</div>
</template>

<script setup>
import { ref } from 'vue';
import { useStore } from 'vuex';
import QrcodeVue from 'qrcode.vue';
const props = defineProps({
namespace: {
type: String,
},
url: {
type: String,
required: true,
},
});
const store = useStore();
const qrcodeContainer = ref();
const isConfirmationPopup = ref(false);
function download() {
const canvas = qrcodeContainer.value.querySelector('canvas');
const link = document.createElement('a');
link.download = 'qr-code.png';
link.href = canvas.toDataURL('image/png');
link.click();
}
async function regenerateUrl() {
await store.dispatch(`${props.namespace}/REGENERATE_2FA_URL`);
closeConfirmationPopup();
}
function openConfirmationPopup() {
isConfirmationPopup.value = true;
}
function closeConfirmationPopup() {
isConfirmationPopup.value = false;
}
</script>

<style lang="scss" scoped>
.user-qrcode {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
&__wrapper {
display: flex;
gap: var(--spacing-sm);
}
&__canvas {
box-shadow: var(--elevation-5);
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@

<wt-input
:disabled="disableUserInput"
:label="$t('objects.directory.users.login')"
:v="v.itemInstance.username"
:value="itemInstance.username"
required
@input="setItemProp({ prop: 'username', value: $event })"
:label="$t('objects.email')"
:value="itemInstance.email"
@input="setItemProp({ prop: 'email', value: $event })"
/>

<password-input
Expand All @@ -32,17 +30,26 @@

<wt-input
:disabled="disableUserInput"
:label="$t('objects.directory.users.extensions')"
:value="itemInstance.extension"
@input="setItemProp({ prop: 'extension', value: $event })"
:label="$t('objects.directory.users.login')"
:v="v.itemInstance.username"
:value="itemInstance.username"
required
@input="setItemProp({ prop: 'username', value: $event })"
/>

<user-qrcode
v-if="itemInstance.totpUrl"
:namespace="namespace"
:url="itemInstance.totpUrl"
/>

<wt-input
:disabled="disableUserInput"
:label="$t('objects.email')"
:value="itemInstance.email"
@input="setItemProp({ prop: 'email', value: $event })"
:label="$t('objects.directory.users.extensions')"
:value="itemInstance.extension"
@input="setItemProp({ prop: 'extension', value: $event })"
/>

</div>
</section>
</template>
Expand All @@ -51,10 +58,11 @@
import PasswordInput from '../../../../../app/components/utils/generate-password-input.vue';
import openedTabComponentMixin
from '../../../../../app/mixins/objectPagesMixins/openedObjectTabMixin/openedTabComponentMixin';
import UserQrcode from './_internals/user-qrcode.vue';
export default {
name: 'OpenedUserGeneral',
components: { PasswordInput },
components: { PasswordInput, UserQrcode },
mixins: [openedTabComponentMixin],
};
</script>
Expand Down
10 changes: 10 additions & 0 deletions src/modules/directory/modules/users/store/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ObjectStoreModule
import PermissionsStoreModule
from '../../../../../app/store/BaseStoreModules/StoreModules/PermissionsStoreModule/PermissionsStoreModule';
import UsersAPI from '../api/users';
import Users2faAPI from '../api/users-2fa.js';
import logs from '../modules/logs/store/logs';
import tokens from '../modules/tokens/store/usersTokens';
import headers from './_internals/headers';
Expand All @@ -23,6 +24,7 @@ const resettableState = {
note: '',
},
variables: [],
totpUrl: '',
},
};

Expand Down Expand Up @@ -55,6 +57,14 @@ const actions = {
context.commit('RESET_ITEM_STATE');
context.dispatch('directory/users/tokens/RESET_STATE', {}, { root: true });
},
REGENERATE_2FA_URL: async (context) => {
try {
await Users2faAPI.generate({id: context.state.itemId});
await context.dispatch('LOAD_ITEM');
} catch (err) {
throw err;
}
}
};

const mutations = {
Expand Down

0 comments on commit 7218c45

Please sign in to comment.