preparing for the new token api

This commit is contained in:
Sebastian 2023-09-21 13:54:02 -03:00
parent 0b7bbed99d
commit af623f5096
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
3 changed files with 136 additions and 3 deletions

View File

@ -255,7 +255,7 @@ interface InvalidationResult {
error: unknown;
}
export function useCredentialsChecker() {
export function useCredentialsCheckerOld() {
const { request } = useApiContext();
const baseUrl = getInitialBackendBaseURL();
//check against account details endpoint

View File

@ -0,0 +1,130 @@
import { AbsoluteTime, HttpStatusCode } from "@gnu-taler/taler-util";
import { ErrorType, HttpError, RequestError, useApiContext } from "@gnu-taler/web-util/browser";
import { getInitialBackendBaseURL } from "./backend.js";
export function useCredentialsChecker() {
const { request } = useApiContext();
const baseUrl = getInitialBackendBaseURL();
//check against instance details endpoint
//while merchant backend doesn't have a login endpoint
async function requestNewLoginToken(
username: string,
password: AccessToken,
): Promise<LoginResult> {
const data: LoginTokenRequest = {
scope: "write",
duration: {
d_us: "forever"
},
refreshable: true,
}
try {
const response = await request<LoginTokenSuccessResponse>(baseUrl, `accounts/${username}/token`, {
method: "POST",
token: password,
data
});
return { valid: true, token: response.data.token, expiration: response.data.expiration };
} catch (error) {
if (error instanceof RequestError) {
return { valid: false, cause: error.cause };
}
return {
valid: false, cause: {
type: ErrorType.UNEXPECTED,
loading: false,
info: {
hasToken: true,
status: 0,
options: {},
url: `/private/token`,
payload: {}
},
exception: error,
message: (error instanceof Error ? error.message : "unpexepected error")
}
};
}
};
async function refreshLoginToken(
baseUrl: string,
token: LoginToken
): Promise<LoginResult> {
if (AbsoluteTime.isExpired(AbsoluteTime.fromProtocolTimestamp(token.expiration))) {
return {
valid: false, cause: {
type: ErrorType.CLIENT,
status: HttpStatusCode.Unauthorized,
message: "login token expired, login again.",
info: {
hasToken: true,
status: 401,
options: {},
url: `/private/token`,
payload: {}
},
payload: {}
},
}
}
return requestNewLoginToken(baseUrl, token.token as AccessToken)
}
return { requestNewLoginToken, refreshLoginToken }
}
export interface LoginToken {
token: string,
expiration: Timestamp,
}
// token used to get loginToken
// must forget after used
declare const __ac_token: unique symbol;
export type AccessToken = string & {
[__ac_token]: true;
};
type YesOrNo = "yes" | "no";
export type LoginResult = {
valid: true;
token: string;
expiration: Timestamp;
} | {
valid: false;
cause: HttpError<{}>;
}
// DELETE /private/instances/$INSTANCE
export interface LoginTokenRequest {
// Scope of the token (which kinds of operations it will allow)
scope: "readonly" | "write";
// Server may impose its own upper bound
// on the token validity duration
duration?: RelativeTime;
// Can this token be refreshed?
// Defaults to false.
refreshable?: boolean;
}
export interface LoginTokenSuccessResponse {
// The login token that can be used to access resources
// that are in scope for some time. Must be prefixed
// with "Bearer " when used in the "Authorization" HTTP header.
// Will already begin with the RFC 8959 prefix.
token: string;
// Scope of the token (which kinds of operations it will allow)
scope: "readonly" | "write";
// Server may impose its own upper bound
// on the token validity duration
expiration: Timestamp;
// Can this token be refreshed?
refreshable: boolean;
}

View File

@ -19,11 +19,12 @@ import { ErrorType, notifyError, useTranslationContext } from "@gnu-taler/web-ut
import { Fragment, VNode, h } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
import { useBackendContext } from "../context/backend.js";
import { useCredentialsChecker } from "../hooks/backend.js";
import { bankUiSettings } from "../settings.js";
import { undefinedIfEmpty } from "../utils.js";
import { USERNAME_REGEX } from "./RegistrationPage.js";
import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
import { AccessToken, useCredentialsChecker } from "../hooks/useCredentialsChecker.js";
import { useCredentialsCheckerOld } from "../hooks/backend.js";
/**
* Collect and submit login data.
@ -33,7 +34,9 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
const [username, setUsername] = useState<string | undefined>();
const [password, setPassword] = useState<string | undefined>();
const { i18n } = useTranslationContext();
const testLogin = useCredentialsChecker();
// const { requestNewLoginToken, refreshLoginToken } = useCredentialsChecker();
const testLogin = useCredentialsCheckerOld();
const ref = useRef<HTMLInputElement>(null);
useEffect(function focusInput() {
ref.current?.focus();