diff options
5 files changed, 80 insertions, 58 deletions
diff --git a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx b/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx index 8bfbdb076..ebfa2b6d6 100644 --- a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx +++ b/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx @@ -114,7 +114,7 @@ export function ApplicationReadyRoutes(): VNode { <NotificationCard notification={{ message: i18n.str`Access denied`, - description: i18n.str`Check your token is valid 1`, + description: i18n.str`Check your token is valid`, type: "ERROR", }} /> diff --git a/packages/merchant-backoffice-ui/src/hooks/backend.ts b/packages/merchant-backoffice-ui/src/hooks/backend.ts index fe4155788..eaeede103 100644 --- a/packages/merchant-backoffice-ui/src/hooks/backend.ts +++ b/packages/merchant-backoffice-ui/src/hooks/backend.ts @@ -266,7 +266,7 @@ export function useBackendBaseRequest(): useBackendBaseRequestType { endpoint: string, options: RequestOptions = {}, ): Promise<HttpResponseOk<T>> { - return requestHandler<T>(backend, endpoint, { token, ...options }).then(res => { + return requestHandler<T>(backend, endpoint, { ...options, token }).then(res => { return res }).catch(err => { throw err diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts b/packages/merchant-backoffice-ui/src/hooks/instance.ts index 50f9487a3..0677191db 100644 --- a/packages/merchant-backoffice-ui/src/hooks/instance.ts +++ b/packages/merchant-backoffice-ui/src/hooks/instance.ts @@ -36,8 +36,8 @@ interface InstanceAPI { data: MerchantBackend.Instances.InstanceReconfigurationMessage, ) => Promise<void>; deleteInstance: () => Promise<void>; - clearToken: () => Promise<void>; - setNewToken: (token: AccessToken) => Promise<void>; + clearAccessToken: (currentToken: AccessToken | undefined) => Promise<void>; + setNewAccessToken: (currentToken: AccessToken | undefined, token: AccessToken) => Promise<void>; } export function useAdminAPI(): AdminAPI { @@ -111,18 +111,20 @@ export function useManagementAPI(instanceId: string): InstanceAPI { mutateAll(/\/management\/instances/); }; - const clearToken = async (): Promise<void> => { + const clearAccessToken = async (currentToken: AccessToken | undefined): Promise<void> => { await request(`/management/instances/${instanceId}/auth`, { method: "POST", + token: currentToken, data: { method: "external" }, }); mutateAll(/\/management\/instances/); }; - const setNewToken = async (newToken: AccessToken): Promise<void> => { + const setNewAccessToken = async (currentToken: AccessToken | undefined, newToken: AccessToken): Promise<void> => { await request(`/management/instances/${instanceId}/auth`, { method: "POST", + token: currentToken, data: { method: "token", token: newToken }, }); @@ -137,7 +139,7 @@ export function useManagementAPI(instanceId: string): InstanceAPI { mutateAll(/\/management\/instances/); }; - return { updateInstance, deleteInstance, setNewToken, clearToken }; + return { updateInstance, deleteInstance, setNewAccessToken, clearAccessToken }; } export function useInstanceAPI(): InstanceAPI { @@ -172,18 +174,20 @@ export function useInstanceAPI(): InstanceAPI { mutate([`/private/`], null); }; - const clearToken = async (): Promise<void> => { + const clearAccessToken = async (currentToken: AccessToken | undefined): Promise<void> => { await request(`/private/auth`, { method: "POST", + token: currentToken, data: { method: "external" }, }); mutate([`/private/`], null); }; - const setNewToken = async (newToken: AccessToken): Promise<void> => { + const setNewAccessToken = async (currentToken: AccessToken | undefined, newToken: AccessToken): Promise<void> => { await request(`/private/auth`, { method: "POST", + token: currentToken, data: { method: "token", token: newToken }, }); @@ -198,7 +202,7 @@ export function useInstanceAPI(): InstanceAPI { mutate([`/private/`], null); }; - return { updateInstance, deleteInstance, setNewToken, clearToken }; + return { updateInstance, deleteInstance, setNewAccessToken, clearAccessToken }; } export function useInstanceDetails(): HttpResponse< diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx index 4b0db200a..89dba63b2 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx @@ -30,13 +30,13 @@ import { AccessToken } from "../../../declaration.js"; interface Props { instanceId: string; - currentToken: string | undefined; - onClearToken: () => void; - onNewToken: (s: AccessToken) => void; + hasToken: boolean | undefined; + onClearToken: (c: AccessToken | undefined) => void; + onNewToken: (c: AccessToken | undefined, s: AccessToken) => void; onBack?: () => void; } -export function DetailPage({ instanceId, currentToken: oldToken, onBack, onNewToken, onClearToken }: Props): VNode { +export function DetailPage({ instanceId, hasToken, onBack, onNewToken, onClearToken }: Props): VNode { type State = { old_token: string; new_token: string; repeat_token: string }; const [form, setValue] = useState<Partial<State>>({ old_token: "", @@ -45,11 +45,9 @@ export function DetailPage({ instanceId, currentToken: oldToken, onBack, onNewTo }); const { i18n } = useTranslationContext(); - const hasOldtoken = !!oldToken - const hasInputTheCorrectOldToken = hasOldtoken && oldToken !== form.old_token; const errors = { - old_token: hasInputTheCorrectOldToken - ? i18n.str`is not the same as the current access token` + old_token: hasToken && !form.old_token + ? i18n.str`you need your access token to perform the operation` : undefined, new_token: !form.new_token ? i18n.str`cannot be empty` @@ -72,8 +70,9 @@ export function DetailPage({ instanceId, currentToken: oldToken, onBack, onNewTo async function submitForm() { if (hasErrors) return; + const ot = hasToken ? `secret-token:${form.old_token}` as AccessToken : undefined; const nt = `secret-token:${form.new_token}` as AccessToken; - onNewToken(nt) + onNewToken(ot, nt) } return ( @@ -98,32 +97,38 @@ export function DetailPage({ instanceId, currentToken: oldToken, onBack, onNewTo <div class="column" /> <div class="column is-four-fifths"> <FormProvider errors={errors} object={form} valueHandler={setValue}> - {hasOldtoken && ( - <Input<State> - name="old_token" - label={i18n.str`Current access token`} - tooltip={i18n.str`access token currently in use`} - inputType="password" - /> - )} - {!hasInputTheCorrectOldToken && <Fragment> - {hasOldtoken && <Fragment> - <p> - <i18n.Translate> - Clearing the access token will mean public access to the instance. - </i18n.Translate> - </p> - <div class="buttons is-right mt-5"> - <button - disabled={!!hasInputTheCorrectOldToken} - class="button" - onClick={onClearToken} - > - <i18n.Translate>Clear token</i18n.Translate> - </button> - </div> - </Fragment> - } + <Fragment> + {hasToken && ( + <Fragment> + <Input<State> + name="old_token" + label={i18n.str`Current access token`} + tooltip={i18n.str`access token currently in use`} + inputType="password" + /> + <p> + <i18n.Translate> + Clearing the access token will mean public access to the instance. + </i18n.Translate> + </p> + <div class="buttons is-right mt-5"> + <button + class="button" + onClick={() => { + if (hasToken) { + const ot = `secret-token:${form.old_token}` as AccessToken; + onClearToken(ot) + } else { + onClearToken(undefined) + } + }} + > + <i18n.Translate>Clear token</i18n.Translate> + </button> + </div> + </Fragment> + )} + <Input<State> name="new_token" @@ -137,7 +142,7 @@ export function DetailPage({ instanceId, currentToken: oldToken, onBack, onNewTo tooltip={i18n.str`confirm the same access token`} inputType="password" /> - </Fragment>} + </Fragment> </FormProvider> <div class="buttons is-right mt-5"> {onBack && ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx index 0a49448f8..bc2bd9fa3 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx @@ -33,8 +33,6 @@ interface Props { onNotFound: () => VNode; } -const PREFIX = "secret-token:" - export default function Token({ onLoadError, onChange, @@ -44,21 +42,36 @@ export default function Token({ const { i18n } = useTranslationContext(); const [notif, setNotif] = useState<Notification | undefined>(undefined); - const { clearToken, setNewToken } = useInstanceAPI(); - const { token: rootToken } = useBackendContext(); - const { token: instanceToken, id, admin } = useInstanceContext(); + const { clearAccessToken, setNewAccessToken } = useInstanceAPI(); + const { id } = useInstanceContext(); + const result = useInstanceDetails() + + if (result.loading) return <Loading />; + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } + + const hasToken = result.data.auth.method === "token" - const currentToken = !admin ? rootToken : instanceToken - const hasPrefix = currentToken !== undefined && currentToken.token.startsWith(PREFIX) return ( <Fragment> <NotificationCard notification={notif} /> <DetailPage instanceId={id} - currentToken={hasPrefix ? currentToken.token.substring(PREFIX.length) : currentToken?.token} - onClearToken={async (): Promise<void> => { + hasToken={hasToken} + onClearToken={async (currentToken): Promise<void> => { try { - await clearToken(); + await clearAccessToken(currentToken); onChange(); } catch (error) { if (error instanceof Error) { @@ -70,9 +83,9 @@ export default function Token({ } } }} - onNewToken={async (newToken): Promise<void> => { + onNewToken={async (currentToken, newToken): Promise<void> => { try { - await setNewToken(newToken); + await setNewAccessToken(currentToken, newToken); onChange(); } catch (error) { if (error instanceof Error) { |