update how access token management is handled
This commit is contained in:
parent
dd25740c91
commit
1653130de8
@ -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",
|
||||
}}
|
||||
/>
|
||||
|
@ -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
|
||||
|
@ -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<
|
||||
|
@ -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 && (
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user