From 626c60aa0e6cf832041ff4da0881e331c7ac22c3 Mon Sep 17 00:00:00 2001 From: Artem Dudarev Date: Fri, 13 Dec 2024 18:20:26 +0200 Subject: [PATCH 1/7] fix: request refresh token when impersonating --- client-app/core/composables/useAuth.ts | 13 ++++++++++ client-app/core/composables/useImpersonate.ts | 26 ++++--------------- locales/en.json | 2 +- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/client-app/core/composables/useAuth.ts b/client-app/core/composables/useAuth.ts index 7b12ec063..c4222b623 100644 --- a/client-app/core/composables/useAuth.ts +++ b/client-app/core/composables/useAuth.ts @@ -117,6 +117,18 @@ function _useAuth() { await (getTokenRequest = getToken(true)); } + async function impersonate(userId: string): Promise { + const params = new URLSearchParams({ + grant_type: "impersonate", + scope: "offline_access", + user_id: userId, + }); + + getTokenParams.value = params; + + await (getTokenRequest = getToken(true)); + } + async function refresh(organizationId?: string) { const params = new URLSearchParams({ grant_type: "refresh_token", @@ -178,6 +190,7 @@ function _useAuth() { isAuthorizing, authorize, externalSignInCallback, + impersonate, refresh, unauthorize, diff --git a/client-app/core/composables/useImpersonate.ts b/client-app/core/composables/useImpersonate.ts index 99376dce0..13107a35a 100644 --- a/client-app/core/composables/useImpersonate.ts +++ b/client-app/core/composables/useImpersonate.ts @@ -1,43 +1,27 @@ import { createGlobalState } from "@vueuse/core"; import { ref } from "vue"; import { useI18n } from "vue-i18n"; -import { useFetch } from "@/core/api/common"; import { useAuth } from "@/core/composables/useAuth"; import { Logger } from "@/core/utilities"; import { TabsType, useBroadcast, reloadAndOpenMainPage } from "@/shared/broadcast"; import { useNotifications } from "@/shared/notification"; -import type { ConnectTokenResponseType } from "../types"; export function _useImpersonate() { - const { setTokenType, setAccessToken, setExpiresAt } = useAuth(); + const { impersonate, errors } = useAuth(); const broadcast = useBroadcast(); const status = ref(); const notifications = useNotifications(); const { t } = useI18n(); - async function impersonate(userId: string) { + async function _impersonate(userId: string) { status.value = "loading"; try { - const { error, data } = await useFetch("/connect/token") - .post( - new URLSearchParams({ - grant_type: "impersonate", - user_id: userId, - }), - "application/x-www-form-urlencoded", - ) - .json(); + await impersonate(userId); - if (!data.value || error.value) { + if (errors.value?.length) { status.value = "error"; } else { - const { access_token, token_type, expires_in } = data.value; - - setAccessToken(access_token); - setExpiresAt(expires_in); - setTokenType(token_type); - status.value = "success"; notifications.success({ text: t("pages.account.impersonate.success") }); @@ -53,7 +37,7 @@ export function _useImpersonate() { } return { - impersonate, + impersonate: _impersonate, status, }; } diff --git a/locales/en.json b/locales/en.json index 33fc409bd..06ccf4282 100644 --- a/locales/en.json +++ b/locales/en.json @@ -1102,7 +1102,7 @@ }, "impersonate": { "title": "Impersonation", - "success": "You are impersonated", + "success": "Impersonation succeeded", "error": "Some problems during impersonation. Check your permissions" } }, From 859cca345a802e98e79285b75d7273882a3708ac Mon Sep 17 00:00:00 2001 From: Artem Dudarev Date: Tue, 24 Dec 2024 15:11:30 +0200 Subject: [PATCH 2/7] fix: fix impersonate --- client-app/core/composables/useAuth.ts | 14 +------- client-app/core/composables/useImpersonate.ts | 34 ++++++++++++++++--- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/client-app/core/composables/useAuth.ts b/client-app/core/composables/useAuth.ts index c4222b623..4f53b47f2 100644 --- a/client-app/core/composables/useAuth.ts +++ b/client-app/core/composables/useAuth.ts @@ -117,18 +117,6 @@ function _useAuth() { await (getTokenRequest = getToken(true)); } - async function impersonate(userId: string): Promise { - const params = new URLSearchParams({ - grant_type: "impersonate", - scope: "offline_access", - user_id: userId, - }); - - getTokenParams.value = params; - - await (getTokenRequest = getToken(true)); - } - async function refresh(organizationId?: string) { const params = new URLSearchParams({ grant_type: "refresh_token", @@ -190,13 +178,13 @@ function _useAuth() { isAuthorizing, authorize, externalSignInCallback, - impersonate, refresh, unauthorize, setTokenType, setAccessToken, setExpiresAt, + setRefreshToken, }; } diff --git a/client-app/core/composables/useImpersonate.ts b/client-app/core/composables/useImpersonate.ts index 13107a35a..bdc5a2d10 100644 --- a/client-app/core/composables/useImpersonate.ts +++ b/client-app/core/composables/useImpersonate.ts @@ -1,27 +1,51 @@ import { createGlobalState } from "@vueuse/core"; import { ref } from "vue"; import { useI18n } from "vue-i18n"; +import { useFetch } from "@/core/api/common"; import { useAuth } from "@/core/composables/useAuth"; import { Logger } from "@/core/utilities"; import { TabsType, useBroadcast, reloadAndOpenMainPage } from "@/shared/broadcast"; import { useNotifications } from "@/shared/notification"; +type ConnectTokenResponseType = { + expires_in: number; + access_token: string; + refresh_token: string; + token_type: string; +}; + export function _useImpersonate() { - const { impersonate, errors } = useAuth(); + const { setTokenType, setAccessToken, setExpiresAt, setRefreshToken } = useAuth(); const broadcast = useBroadcast(); const status = ref(); const notifications = useNotifications(); const { t } = useI18n(); - async function _impersonate(userId: string) { + async function impersonate(userId: string) { status.value = "loading"; try { - await impersonate(userId); + const { error, data } = await useFetch("/connect/token") + .post( + new URLSearchParams({ + grant_type: "impersonate", + scope: "offline_access", + user_id: userId, + }), + "application/x-www-form-urlencoded", + ) + .json(); - if (errors.value?.length) { + if (!data.value || error.value) { status.value = "error"; } else { + const { access_token, token_type, expires_in, refresh_token } = data.value; + + setAccessToken(access_token); + setExpiresAt(expires_in); + setTokenType(token_type); + setRefreshToken(refresh_token); + status.value = "success"; notifications.success({ text: t("pages.account.impersonate.success") }); @@ -37,7 +61,7 @@ export function _useImpersonate() { } return { - impersonate: _impersonate, + impersonate: impersonate, status, }; } From 87039a4567c188b0f0f01ac57f006ce4be21cd06 Mon Sep 17 00:00:00 2001 From: Artem Dudarev Date: Tue, 24 Dec 2024 15:15:10 +0200 Subject: [PATCH 3/7] chore: fix export --- client-app/core/composables/useImpersonate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client-app/core/composables/useImpersonate.ts b/client-app/core/composables/useImpersonate.ts index bdc5a2d10..c164913c0 100644 --- a/client-app/core/composables/useImpersonate.ts +++ b/client-app/core/composables/useImpersonate.ts @@ -61,7 +61,7 @@ export function _useImpersonate() { } return { - impersonate: impersonate, + impersonate, status, }; } From 7e2f6b2e9739c786571c6ab1911747bf2dc44c4f Mon Sep 17 00:00:00 2001 From: NaMax66 Date: Thu, 26 Dec 2024 14:50:17 +0100 Subject: [PATCH 4/7] feat: refactor types --- client-app/core/composables/useAuth.ts | 23 +++--------- client-app/core/composables/useImpersonate.ts | 36 +++++++++---------- .../core/types/connect-token-response.ts | 14 +++++--- 3 files changed, 31 insertions(+), 42 deletions(-) diff --git a/client-app/core/composables/useAuth.ts b/client-app/core/composables/useAuth.ts index 4f53b47f2..0a20dea7f 100644 --- a/client-app/core/composables/useAuth.ts +++ b/client-app/core/composables/useAuth.ts @@ -1,24 +1,11 @@ -import { useLocalStorage, createGlobalState } from "@vueuse/core"; +import type { AfterFetchContext } from "@vueuse/core"; +import { createGlobalState, useLocalStorage } from "@vueuse/core"; import { computed, ref } from "vue"; import { useFetch } from "@/core/api/common"; import { errorHandler, toServerError } from "@/core/api/common/utils"; import { globals } from "@/core/globals"; import { TabsType, unauthorizedErrorEvent, useBroadcast, userBeforeUnauthorizeEvent } from "@/shared/broadcast"; -import type { AfterFetchContext } from "@vueuse/core"; - -type IdentityErrorType = { - code?: string; - description?: string; -}; - -type ConnectTokenResponseType = { - expires_in?: number; - access_token?: string; - refresh_token?: string; - errors?: Array; - error: string; - token_type?: string; -}; +import type { ConnectTokenResponseType } from "../types"; function _useAuth() { const broadcast = useBroadcast(); @@ -107,13 +94,11 @@ function _useAuth() { } async function externalSignInCallback(): Promise { - const params = new URLSearchParams({ + getTokenParams.value = new URLSearchParams({ grant_type: "external_sign_in", scope: "offline_access", }); - getTokenParams.value = params; - await (getTokenRequest = getToken(true)); } diff --git a/client-app/core/composables/useImpersonate.ts b/client-app/core/composables/useImpersonate.ts index c164913c0..5d7e4e6c2 100644 --- a/client-app/core/composables/useImpersonate.ts +++ b/client-app/core/composables/useImpersonate.ts @@ -6,13 +6,7 @@ import { useAuth } from "@/core/composables/useAuth"; import { Logger } from "@/core/utilities"; import { TabsType, useBroadcast, reloadAndOpenMainPage } from "@/shared/broadcast"; import { useNotifications } from "@/shared/notification"; - -type ConnectTokenResponseType = { - expires_in: number; - access_token: string; - refresh_token: string; - token_type: string; -}; +import type { ConnectTokenResponseType } from "../types"; export function _useImpersonate() { const { setTokenType, setAccessToken, setExpiresAt, setRefreshToken } = useAuth(); @@ -39,20 +33,24 @@ export function _useImpersonate() { if (!data.value || error.value) { status.value = "error"; } else { - const { access_token, token_type, expires_in, refresh_token } = data.value; - - setAccessToken(access_token); - setExpiresAt(expires_in); - setTokenType(token_type); - setRefreshToken(refresh_token); + const { access_token, token_type, expires_in, refresh_token, errors } = data.value; - status.value = "success"; - notifications.success({ text: t("pages.account.impersonate.success") }); + if (access_token && token_type && expires_in && refresh_token) { + setAccessToken(access_token); + setExpiresAt(expires_in); + setTokenType(token_type); + setRefreshToken(refresh_token); + status.value = "success"; + notifications.success({ text: t("pages.account.impersonate.success") }); - // reload all tabs to renew state - setTimeout(() => { - void broadcast.emit(reloadAndOpenMainPage, null, TabsType.ALL); - }, 1000); + // reload all tabs to renew state + setTimeout(() => { + void broadcast.emit(reloadAndOpenMainPage, null, TabsType.ALL); + }, 1000); + } else { + Logger.error(impersonate.name, errors); + status.value = "error"; + } } } catch (e) { Logger.error(impersonate.name, e); diff --git a/client-app/core/types/connect-token-response.ts b/client-app/core/types/connect-token-response.ts index b0e4a519e..40fccedc5 100644 --- a/client-app/core/types/connect-token-response.ts +++ b/client-app/core/types/connect-token-response.ts @@ -1,6 +1,12 @@ +type IdentityErrorType = { + code?: string; + description?: string; +}; + export type ConnectTokenResponseType = { - expires_in: number; - access_token: string; - token_type: string; - error?: string; + expires_in?: number; + access_token?: string; + refresh_token?: string; + errors?: Array; + token_type?: string; }; From 20aa18c19e532c47e8a68037c981571c85649bb5 Mon Sep 17 00:00:00 2001 From: NaMax66 Date: Thu, 26 Dec 2024 14:54:08 +0100 Subject: [PATCH 5/7] feat: errors to error --- client-app/core/composables/useImpersonate.ts | 4 ++-- client-app/core/types/connect-token-response.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client-app/core/composables/useImpersonate.ts b/client-app/core/composables/useImpersonate.ts index 5d7e4e6c2..ba2f4a899 100644 --- a/client-app/core/composables/useImpersonate.ts +++ b/client-app/core/composables/useImpersonate.ts @@ -33,7 +33,7 @@ export function _useImpersonate() { if (!data.value || error.value) { status.value = "error"; } else { - const { access_token, token_type, expires_in, refresh_token, errors } = data.value; + const { access_token, token_type, expires_in, refresh_token, error: tokenError } = data.value; if (access_token && token_type && expires_in && refresh_token) { setAccessToken(access_token); @@ -48,7 +48,7 @@ export function _useImpersonate() { void broadcast.emit(reloadAndOpenMainPage, null, TabsType.ALL); }, 1000); } else { - Logger.error(impersonate.name, errors); + Logger.error(impersonate.name, tokenError); status.value = "error"; } } diff --git a/client-app/core/types/connect-token-response.ts b/client-app/core/types/connect-token-response.ts index 40fccedc5..26023f5ad 100644 --- a/client-app/core/types/connect-token-response.ts +++ b/client-app/core/types/connect-token-response.ts @@ -8,5 +8,6 @@ export type ConnectTokenResponseType = { access_token?: string; refresh_token?: string; errors?: Array; + error?: string; token_type?: string; }; From b23e6f4026ec59beb9a800817873879fbf0bc4d4 Mon Sep 17 00:00:00 2001 From: NaMax66 Date: Thu, 26 Dec 2024 15:02:36 +0100 Subject: [PATCH 6/7] fix: translations --- locales/de.json | 2 +- locales/es.json | 2 +- locales/fr.json | 2 +- locales/it.json | 2 +- locales/ja.json | 2 +- locales/pl.json | 2 +- locales/pt.json | 2 +- locales/ru.json | 6 +++--- locales/zh.json | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/locales/de.json b/locales/de.json index de5433e43..6a2f141f8 100644 --- a/locales/de.json +++ b/locales/de.json @@ -1105,7 +1105,7 @@ }, "impersonate": { "title": "Nachahmung", - "success": "Sie werden nachgeahmt", + "success": "Impersonation erfolgreich", "error": "Einige Probleme während der Nachahmung. Überprüfen Sie Ihre Berechtigungen" } }, diff --git a/locales/es.json b/locales/es.json index 8e2cf9949..a46fe7391 100644 --- a/locales/es.json +++ b/locales/es.json @@ -1105,7 +1105,7 @@ }, "impersonate": { "title": "Suplantación", - "success": "Estás suplantado", + "success": "Suplantación exitosa", "error": "Algunos problemas durante la suplantación. Verifica tus permisos" } }, diff --git a/locales/fr.json b/locales/fr.json index 5239b2fd2..647d0a04d 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -1105,7 +1105,7 @@ }, "impersonate": { "title": "Impersonation", - "success": "Vous êtes en train d'être imité", + "success": "Impersonation réussie", "error": "Des problèmes sont survenus lors de l'imitation. Vérifiez vos autorisations" } }, diff --git a/locales/it.json b/locales/it.json index 0e23e443a..e2cb93100 100644 --- a/locales/it.json +++ b/locales/it.json @@ -1105,7 +1105,7 @@ }, "impersonate": { "title": "Impersonificazione", - "success": "Sei impersonato", + "success": "Impersonificazione riuscita", "error": "Alcuni problemi durante l'impersonificazione. Controlla i tuoi permessi" } }, diff --git a/locales/ja.json b/locales/ja.json index bb2afbfe6..fc5010e88 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -1105,7 +1105,7 @@ }, "impersonate": { "title": "代理ログイン", - "success": "代理ログインしました", + "success": "代理ログイン成功", "error": "代理ログイン中に問題が発生しました。権限を確認してください" } }, diff --git a/locales/pl.json b/locales/pl.json index 89e676668..3111b8c1f 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -1105,7 +1105,7 @@ }, "impersonate": { "title": "Podrabianie", - "success": "Jesteś podrobiony", + "success": "Podrobienie zakończone", "error": "Wystąpiły problemy podczas podrabiania. Sprawdź swoje uprawnienia" } }, diff --git a/locales/pt.json b/locales/pt.json index bd6ee4755..dee49a9b1 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -1105,7 +1105,7 @@ }, "impersonate": { "title": "Impersonação", - "success": "Você está sendo personificado", + "success": "Impersonificação bem-sucedida", "error": "Alguns problemas durante a personificação. Verifique suas permissões" } }, diff --git a/locales/ru.json b/locales/ru.json index bfc870821..a97c77d42 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -1104,9 +1104,9 @@ "update_error_alert": "Произошла ошибка при обновлении профиля" }, "impersonate": { - "title": "Авторизация", - "success": "Вы авторизовались", - "error": "Возникли проблемы при авторизации. Проверьте ваши права доступа" + "title": "Имперсонализация", + "success": "Имперсонализация прошла успешно", + "error": "Возникли проблемы при имперсонализации. Проверьте ваши права доступа" } }, "company": { diff --git a/locales/zh.json b/locales/zh.json index 0ed3dee0d..8406195ca 100644 --- a/locales/zh.json +++ b/locales/zh.json @@ -1105,7 +1105,7 @@ }, "impersonate": { "title": "冒充", - "success": "您已被冒充", + "success": "冒充成功", "error": "冒充时出现一些问题。检查您的权限" } }, From 1f3b0dce52b9f2cd75098a78d71f21740b60a4ee Mon Sep 17 00:00:00 2001 From: NaMax66 Date: Fri, 27 Dec 2024 11:35:16 +0100 Subject: [PATCH 7/7] feat: add error handler --- client-app/core/composables/useImpersonate.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client-app/core/composables/useImpersonate.ts b/client-app/core/composables/useImpersonate.ts index ba2f4a899..d1db5840b 100644 --- a/client-app/core/composables/useImpersonate.ts +++ b/client-app/core/composables/useImpersonate.ts @@ -33,7 +33,7 @@ export function _useImpersonate() { if (!data.value || error.value) { status.value = "error"; } else { - const { access_token, token_type, expires_in, refresh_token, error: tokenError } = data.value; + const { access_token, token_type, expires_in, refresh_token, error: tokenError, errors } = data.value; if (access_token && token_type && expires_in && refresh_token) { setAccessToken(access_token); @@ -48,11 +48,13 @@ export function _useImpersonate() { void broadcast.emit(reloadAndOpenMainPage, null, TabsType.ALL); }, 1000); } else { - Logger.error(impersonate.name, tokenError); + notifications.error({ text: t("pages.account.impersonate.error") }); + Logger.error(impersonate.name, tokenError, errors); status.value = "error"; } } } catch (e) { + notifications.error({ text: t("pages.account.impersonate.error") }); Logger.error(impersonate.name, e); status.value = "error"; }