aboutsummaryrefslogtreecommitdiff
path: root/packages/demobank-ui/src/hooks/backend.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/demobank-ui/src/hooks/backend.ts')
-rw-r--r--packages/demobank-ui/src/hooks/backend.ts113
1 files changed, 63 insertions, 50 deletions
diff --git a/packages/demobank-ui/src/hooks/backend.ts b/packages/demobank-ui/src/hooks/backend.ts
index 4b60d1b6c..889618646 100644
--- a/packages/demobank-ui/src/hooks/backend.ts
+++ b/packages/demobank-ui/src/hooks/backend.ts
@@ -40,21 +40,24 @@ import { useCallback, useEffect, useState } from "preact/hooks";
import { useSWRConfig } from "swr";
import { useBackendContext } from "../context/backend.js";
import { bankUiSettings } from "../settings.js";
+import { AccessToken } from "./useCredentialsChecker.js";
/**
* Has the information to reach and
* authenticate at the bank's backend.
*/
-export type BackendState = LoggedIn | LoggedOut;
+export type BackendState = LoggedIn | LoggedOut | Expired;
-export interface BackendCredentials {
+interface LoggedIn {
+ status: "loggedIn";
+ isUserAdministrator: boolean;
username: string;
- password: string;
+ token: AccessToken;
}
-
-interface LoggedIn extends BackendCredentials {
- status: "loggedIn";
+interface Expired {
+ status: "expired";
isUserAdministrator: boolean;
+ username: string;
}
interface LoggedOut {
status: "loggedOut";
@@ -64,10 +67,17 @@ export const codecForBackendStateLoggedIn = (): Codec<LoggedIn> =>
buildCodecForObject<LoggedIn>()
.property("status", codecForConstString("loggedIn"))
.property("username", codecForString())
- .property("password", codecForString())
+ .property("token", codecForString() as Codec<AccessToken>)
.property("isUserAdministrator", codecForBoolean())
.build("BackendState.LoggedIn");
+export const codecForBackendStateExpired = (): Codec<Expired> =>
+ buildCodecForObject<Expired>()
+ .property("status", codecForConstString("expired"))
+ .property("username", codecForString())
+ .property("isUserAdministrator", codecForBoolean())
+ .build("BackendState.Expired");
+
export const codecForBackendStateLoggedOut = (): Codec<LoggedOut> =>
buildCodecForObject<LoggedOut>()
.property("status", codecForConstString("loggedOut"))
@@ -78,6 +88,7 @@ export const codecForBackendState = (): Codec<BackendState> =>
.discriminateOn("status")
.alternative("loggedIn", codecForBackendStateLoggedIn())
.alternative("loggedOut", codecForBackendStateLoggedOut())
+ .alternative("expired", codecForBackendStateExpired())
.build("BackendState");
export function getInitialBackendBaseURL(): string {
@@ -85,18 +96,27 @@ export function getInitialBackendBaseURL(): string {
typeof localStorage !== "undefined"
? localStorage.getItem("bank-base-url")
: undefined;
+ let result: string;
if (!overrideUrl) {
//normal path
if (!bankUiSettings.backendBaseURL) {
console.error(
"ERROR: backendBaseURL was overridden by a setting file and missing. Setting value to 'window.origin'",
);
- return canonicalizeBaseUrl(window.origin);
+ result = window.origin
+ } else {
+ result = bankUiSettings.backendBaseURL;
}
- return canonicalizeBaseUrl(bankUiSettings.backendBaseURL);
+ } else {
+ // testing/development path
+ result = overrideUrl
+ }
+ try {
+ return canonicalizeBaseUrl(result)
+ } catch (e) {
+ //fall back
+ return canonicalizeBaseUrl(window.origin)
}
- // testing/development path
- return canonicalizeBaseUrl(overrideUrl);
}
export const defaultState: BackendState = {
@@ -106,7 +126,8 @@ export const defaultState: BackendState = {
export interface BackendStateHandler {
state: BackendState;
logOut(): void;
- logIn(info: BackendCredentials): void;
+ expired(): void;
+ logIn(info: {username: string, token: AccessToken}): void;
}
const BACKEND_STATE_KEY = buildStorageKey(
@@ -124,12 +145,22 @@ export function useBackendState(): BackendStateHandler {
BACKEND_STATE_KEY,
defaultState,
);
+ const mutateAll = useMatchMutate();
return {
state,
logOut() {
update(defaultState);
},
+ expired() {
+ if (state.status === "loggedOut") return;
+ const nextState: BackendState = {
+ status: "expired",
+ username: state.username,
+ isUserAdministrator: state.username === "admin",
+ };
+ update(nextState);
+ },
logIn(info) {
//admin is defined by the username
const nextState: BackendState = {
@@ -138,6 +169,7 @@ export function useBackendState(): BackendStateHandler {
isUserAdministrator: info.username === "admin",
};
update(nextState);
+ mutateAll(/.*/)
},
};
}
@@ -150,7 +182,7 @@ interface useBackendType {
fetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
multiFetcher: <T>(endpoint: string[][]) => Promise<HttpResponseOk<T>[]>;
paginatedFetcher: <T>(
- args: [string, number, number],
+ args: [string, string | undefined, number],
) => Promise<HttpResponseOk<T>>;
sandboxAccountsFetcher: <T>(
args: [string, number, number, string],
@@ -179,13 +211,15 @@ export function usePublicBackend(): useBackendType {
[baseUrl],
);
const paginatedFetcher = useCallback(
- function fetcherImpl<T>([endpoint, page, size]: [
+ function fetcherImpl<T>([endpoint, start, size]: [
string,
- number,
+ string | undefined,
number,
]): Promise<HttpResponseOk<T>> {
+ const delta = -1 * size //descending order
+ const params = start ? { delta, start } : { delta }
return requestHandler<T>(baseUrl, endpoint, {
- params: { page: page || 1, size },
+ params,
});
},
[baseUrl],
@@ -247,35 +281,12 @@ interface InvalidationResult {
error: unknown;
}
-export function useCredentialsChecker() {
- const { request } = useApiContext();
- const baseUrl = getInitialBackendBaseURL();
- //check against account details endpoint
- //while sandbox backend doesn't have a login endpoint
- return async function testLogin(
- username: string,
- password: string,
- ): Promise<CheckResult> {
- try {
- await request(baseUrl, `access-api/accounts/${username}/`, {
- basicAuth: { username, password },
- preventCache: true,
- });
- return { valid: true };
- } catch (error) {
- if (error instanceof RequestError) {
- return { valid: false, requestError: true, cause: error.cause };
- }
- return { valid: false, requestError: false, error };
- }
- };
-}
-
export function useAuthenticatedBackend(): useBackendType {
const { state } = useBackendContext();
const { request: requestHandler } = useApiContext();
- const creds = state.status === "loggedIn" ? state : undefined;
+ // FIXME: libeufin returns 400 insteand of 401 if there is no auth token
+ const creds = state.status === "loggedIn" ? state.token : "secret-token:a";
const baseUrl = getInitialBackendBaseURL();
const request = useCallback(
@@ -283,26 +294,28 @@ export function useAuthenticatedBackend(): useBackendType {
path: string,
options: RequestOptions = {},
): Promise<HttpResponseOk<T>> {
- return requestHandler<T>(baseUrl, path, { basicAuth: creds, ...options });
+ return requestHandler<T>(baseUrl, path, { token: creds, ...options });
},
[baseUrl, creds],
);
const fetcher = useCallback(
function fetcherImpl<T>(endpoint: string): Promise<HttpResponseOk<T>> {
- return requestHandler<T>(baseUrl, endpoint, { basicAuth: creds });
+ return requestHandler<T>(baseUrl, endpoint, { token: creds });
},
[baseUrl, creds],
);
const paginatedFetcher = useCallback(
- function fetcherImpl<T>([endpoint, page = 1, size]: [
+ function fetcherImpl<T>([endpoint, start, size]: [
string,
- number,
+ string | undefined,
number,
]): Promise<HttpResponseOk<T>> {
+ const delta = -1 * size //descending order
+ const params = start ? { delta, start } : { delta }
return requestHandler<T>(baseUrl, endpoint, {
- basicAuth: creds,
- params: { page, size },
+ token: creds,
+ params,
});
},
[baseUrl, creds],
@@ -313,7 +326,7 @@ export function useAuthenticatedBackend(): useBackendType {
> {
return Promise.all(
endpoints.map((endpoint) =>
- requestHandler<T>(baseUrl, endpoint, { basicAuth: creds }),
+ requestHandler<T>(baseUrl, endpoint, { token: creds }),
),
);
},
@@ -327,7 +340,7 @@ export function useAuthenticatedBackend(): useBackendType {
string,
]): Promise<HttpResponseOk<T>> {
return requestHandler<T>(baseUrl, endpoint, {
- basicAuth: creds,
+ token: creds,
params: { page: page || 1, size },
});
},
@@ -339,7 +352,7 @@ export function useAuthenticatedBackend(): useBackendType {
HttpResponseOk<T>
> {
return requestHandler<T>(baseUrl, endpoint, {
- basicAuth: creds,
+ token: creds,
params: { account },
});
},