new libeufin api
This commit is contained in:
parent
fd9ed97fdc
commit
0b2c03dc5e
9
packages/demobank-ui/src/declaration.d.ts
vendored
9
packages/demobank-ui/src/declaration.d.ts
vendored
@ -319,11 +319,10 @@ namespace SandboxBackend {
|
||||
interface ListBankAccountsResponse {
|
||||
accounts: AccountMinimalData[];
|
||||
}
|
||||
// interface Balance {
|
||||
// amount: Amount;
|
||||
// credit_debit_indicator: "credit" | "debit";
|
||||
// }
|
||||
type Balance = Amount
|
||||
interface Balance {
|
||||
amount: Amount;
|
||||
credit_debit_indicator: "credit" | "debit";
|
||||
}
|
||||
interface AccountMinimalData {
|
||||
// Username
|
||||
username: string;
|
||||
|
@ -40,6 +40,7 @@ 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
|
||||
@ -49,7 +50,7 @@ export type BackendState = LoggedIn | LoggedOut;
|
||||
|
||||
export interface BackendCredentials {
|
||||
username: string;
|
||||
password: string;
|
||||
token: AccessToken;
|
||||
}
|
||||
|
||||
interface LoggedIn extends BackendCredentials {
|
||||
@ -64,7 +65,7 @@ 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");
|
||||
|
||||
@ -255,35 +256,11 @@ interface InvalidationResult {
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
export function useCredentialsCheckerOld() {
|
||||
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;
|
||||
const creds = state.status === "loggedIn" ? state.token : undefined;
|
||||
const baseUrl = getInitialBackendBaseURL();
|
||||
|
||||
const request = useCallback(
|
||||
@ -291,14 +268,14 @@ 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],
|
||||
);
|
||||
@ -309,7 +286,7 @@ export function useAuthenticatedBackend(): useBackendType {
|
||||
number,
|
||||
]): Promise<HttpResponseOk<T>> {
|
||||
return requestHandler<T>(baseUrl, endpoint, {
|
||||
basicAuth: creds,
|
||||
token: creds,
|
||||
params: { delta: size, start: size * page },
|
||||
});
|
||||
},
|
||||
@ -321,7 +298,7 @@ export function useAuthenticatedBackend(): useBackendType {
|
||||
> {
|
||||
return Promise.all(
|
||||
endpoints.map((endpoint) =>
|
||||
requestHandler<T>(baseUrl, endpoint, { basicAuth: creds }),
|
||||
requestHandler<T>(baseUrl, endpoint, { token: creds }),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -335,7 +312,7 @@ export function useAuthenticatedBackend(): useBackendType {
|
||||
string,
|
||||
]): Promise<HttpResponseOk<T>> {
|
||||
return requestHandler<T>(baseUrl, endpoint, {
|
||||
basicAuth: creds,
|
||||
token: creds,
|
||||
params: { page: page || 1, size },
|
||||
});
|
||||
},
|
||||
@ -347,7 +324,7 @@ export function useAuthenticatedBackend(): useBackendType {
|
||||
HttpResponseOk<T>
|
||||
> {
|
||||
return requestHandler<T>(baseUrl, endpoint, {
|
||||
basicAuth: creds,
|
||||
token: creds,
|
||||
params: { account },
|
||||
});
|
||||
},
|
||||
|
@ -33,6 +33,7 @@ import {
|
||||
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
|
||||
import _useSWR, { SWRHook } from "swr";
|
||||
import { AmountJson, Amounts } from "@gnu-taler/taler-util";
|
||||
import { AccessToken } from "./useCredentialsChecker.js";
|
||||
const useSWR = _useSWR as unknown as SWRHook;
|
||||
|
||||
export function useAdminAccountAPI(): AdminAccountAPI {
|
||||
@ -90,7 +91,8 @@ export function useAdminAccountAPI(): AdminAccountAPI {
|
||||
await mutateAll(/.*/);
|
||||
logIn({
|
||||
username: account,
|
||||
password: data.new_password,
|
||||
//FIXME: change password api
|
||||
token: data.new_password as AccessToken,
|
||||
});
|
||||
}
|
||||
return res;
|
||||
@ -215,14 +217,15 @@ export interface CircuitAccountAPI {
|
||||
|
||||
async function getBusinessStatus(
|
||||
request: ReturnType<typeof useApiContext>["request"],
|
||||
basicAuth: { username: string; password: string },
|
||||
username: string,
|
||||
token: AccessToken,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const url = getInitialBackendBaseURL();
|
||||
const result = await request<SandboxBackend.Circuit.CircuitAccountData>(
|
||||
url,
|
||||
`circuit-api/accounts/${basicAuth.username}`,
|
||||
{ basicAuth },
|
||||
`circuit-api/accounts/${username}`,
|
||||
{ token },
|
||||
);
|
||||
return result.ok;
|
||||
} catch (error) {
|
||||
@ -264,10 +267,10 @@ type CashoutEstimators = {
|
||||
export function useEstimator(): CashoutEstimators {
|
||||
const { state } = useBackendContext();
|
||||
const { request } = useApiContext();
|
||||
const basicAuth =
|
||||
const creds =
|
||||
state.status === "loggedOut"
|
||||
? undefined
|
||||
: { username: state.username, password: state.password };
|
||||
: state.token;
|
||||
return {
|
||||
estimateByCredit: async (amount, fee, rate) => {
|
||||
const zeroBalance = Amounts.zeroOfCurrency(fee.currency);
|
||||
@ -282,7 +285,7 @@ export function useEstimator(): CashoutEstimators {
|
||||
url,
|
||||
`circuit-api/cashouts/estimates`,
|
||||
{
|
||||
basicAuth,
|
||||
token: creds,
|
||||
params: {
|
||||
amount_credit: Amounts.stringify(amount),
|
||||
},
|
||||
@ -313,7 +316,7 @@ export function useEstimator(): CashoutEstimators {
|
||||
url,
|
||||
`circuit-api/cashouts/estimates`,
|
||||
{
|
||||
basicAuth,
|
||||
token: creds,
|
||||
params: {
|
||||
amount_debit: Amounts.stringify(amount),
|
||||
},
|
||||
@ -339,11 +342,11 @@ export function useBusinessAccountFlag(): boolean | undefined {
|
||||
const creds =
|
||||
state.status === "loggedOut"
|
||||
? undefined
|
||||
: { username: state.username, password: state.password };
|
||||
: {user: state.username, token: state.token};
|
||||
|
||||
useEffect(() => {
|
||||
if (!creds) return;
|
||||
getBusinessStatus(request, creds)
|
||||
getBusinessStatus(request, creds.user, creds.token)
|
||||
.then((result) => {
|
||||
setIsBusiness(result);
|
||||
})
|
||||
|
@ -23,13 +23,13 @@ export function useCredentialsChecker() {
|
||||
const response = await request<LoginTokenSuccessResponse>(baseUrl, `accounts/${username}/token`, {
|
||||
method: "POST",
|
||||
basicAuth: {
|
||||
username: username,
|
||||
username,
|
||||
password,
|
||||
},
|
||||
data,
|
||||
contentType: "json"
|
||||
});
|
||||
return { valid: true, token: response.data.token, expiration: response.data.expiration };
|
||||
return { valid: true, token: `secret-token:${response.data.access_token}` as AccessToken, expiration: response.data.expiration };
|
||||
} catch (error) {
|
||||
if (error instanceof RequestError) {
|
||||
return { valid: false, cause: error.cause };
|
||||
@ -76,13 +76,13 @@ export function useCredentialsChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
return requestNewLoginToken(baseUrl, token.token as AccessToken)
|
||||
return requestNewLoginToken(baseUrl, token.token)
|
||||
}
|
||||
return { requestNewLoginToken, refreshLoginToken }
|
||||
}
|
||||
|
||||
export interface LoginToken {
|
||||
token: string,
|
||||
token: AccessToken,
|
||||
expiration: Timestamp,
|
||||
}
|
||||
// token used to get loginToken
|
||||
@ -95,7 +95,7 @@ export type AccessToken = string & {
|
||||
type YesOrNo = "yes" | "no";
|
||||
export type LoginResult = {
|
||||
valid: true;
|
||||
token: string;
|
||||
token: AccessToken;
|
||||
expiration: Timestamp;
|
||||
} | {
|
||||
valid: false;
|
||||
@ -121,7 +121,7 @@ export interface LoginTokenSuccessResponse {
|
||||
// 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;
|
||||
access_token: AccessToken;
|
||||
|
||||
// Scope of the token (which kinds of operations it will allow)
|
||||
scope: "readonly" | "write";
|
||||
|
@ -63,9 +63,7 @@ export function useComponentState({ account, goToBusinessAccount, goToConfirmOpe
|
||||
|
||||
const { data } = result;
|
||||
|
||||
// FIXME: balance
|
||||
// const balance = Amounts.parseOrThrow(data.balance.amount);
|
||||
const balance = Amounts.parseOrThrow(data.balance);
|
||||
const balance = Amounts.parseOrThrow(data.balance.amount);
|
||||
|
||||
const debitThreshold = Amounts.parseOrThrow(data.debit_threshold);
|
||||
const payto = parsePaytoUri(data.payto_uri);
|
||||
|
@ -14,16 +14,14 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { Amounts, stringifyPaytoUri } from "@gnu-taler/taler-util";
|
||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { Fragment, VNode, h } from "preact";
|
||||
import { Transactions } from "../../components/Transactions/index.js";
|
||||
import { PaymentOptions } from "../PaymentOptions.js";
|
||||
import { State } from "./index.js";
|
||||
import { CopyButton } from "../../components/CopyButton.js";
|
||||
import { bankUiSettings } from "../../settings.js";
|
||||
import { useBusinessAccountDetails } from "../../hooks/circuit.js";
|
||||
import { useSettings } from "../../hooks/settings.js";
|
||||
import { bankUiSettings } from "../../settings.js";
|
||||
import { PaymentOptions } from "../PaymentOptions.js";
|
||||
import { State } from "./index.js";
|
||||
|
||||
export function InvalidIbanView({ error }: State.InvalidIban) {
|
||||
return (
|
||||
|
@ -474,11 +474,9 @@ function AccountBalance({ account }: { account: string }): VNode {
|
||||
const result = useAccountDetails(account);
|
||||
if (!result.ok) return <div />
|
||||
|
||||
// FIXME: balance
|
||||
return <div>
|
||||
{Amounts.currencyOf(result.data.balance)} {Amounts.stringifyValue(result.data.balance)}
|
||||
{/* {Amounts.currencyOf(result.data.balance.amount)}
|
||||
{Amounts.currencyOf(result.data.balance.amount)}
|
||||
{result.data.balance.credit_debit_indicator === "debit" ? "-" : ""}
|
||||
{Amounts.stringifyValue(result.data.balance.amount)} */}
|
||||
{Amounts.stringifyValue(result.data.balance.amount)}
|
||||
</div>
|
||||
}
|
||||
|
@ -18,13 +18,11 @@ import { HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util";
|
||||
import { ErrorType, notifyError, useTranslationContext } from "@gnu-taler/web-util/browser";
|
||||
import { Fragment, VNode, h } from "preact";
|
||||
import { useEffect, useRef, useState } from "preact/hooks";
|
||||
import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
|
||||
import { useBackendContext } from "../context/backend.js";
|
||||
import { useCredentialsChecker } from "../hooks/useCredentialsChecker.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.
|
||||
@ -62,7 +60,7 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
|
||||
setBusy({})
|
||||
const result = await requestNewLoginToken(username, password);
|
||||
if (result.valid) {
|
||||
backend.logIn({ username, password });
|
||||
backend.logIn({ username, token: result.token });
|
||||
} else {
|
||||
const { cause } = result;
|
||||
switch (cause.type) {
|
||||
|
@ -28,6 +28,7 @@ import { bankUiSettings } from "../settings.js";
|
||||
import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js";
|
||||
import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
|
||||
import { getRandomPassword, getRandomUsername } from "./rnd.js";
|
||||
import { useCredentialsChecker } from "../hooks/useCredentialsChecker.js";
|
||||
|
||||
const logger = new Logger("RegistrationPage");
|
||||
|
||||
@ -58,6 +59,7 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on
|
||||
const [name, setName] = useState<string | undefined>();
|
||||
const [password, setPassword] = useState<string | undefined>();
|
||||
const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
|
||||
const {requestNewLoginToken} = useCredentialsChecker()
|
||||
|
||||
const { register } = useTestingAPI();
|
||||
const { i18n } = useTranslationContext();
|
||||
@ -83,8 +85,11 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on
|
||||
if (!username || !password || !name) return;
|
||||
try {
|
||||
await register({ name, username, password });
|
||||
const resp = await requestNewLoginToken(username, password)
|
||||
setUsername(undefined);
|
||||
backend.logIn({ username, password });
|
||||
if (resp.valid) {
|
||||
backend.logIn({ username, token: resp.token });
|
||||
}
|
||||
onComplete();
|
||||
} catch (error) {
|
||||
if (error instanceof RequestError) {
|
||||
@ -125,7 +130,10 @@ function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, on
|
||||
setRepeatPassword(undefined);
|
||||
const username = `_${user.first}-${user.second}_`
|
||||
await register({ username, name: `${user.first} ${user.second}`, password: pass });
|
||||
backend.logIn({ username, password: pass });
|
||||
const resp = await requestNewLoginToken(username, pass)
|
||||
if (resp.valid) {
|
||||
backend.logIn({ username, token: resp.token });
|
||||
}
|
||||
onComplete();
|
||||
} catch (error) {
|
||||
if (error instanceof RequestError) {
|
||||
|
@ -17,11 +17,8 @@ export function AdminAccount({ onRegister }: { onRegister: () => void }): VNode
|
||||
}
|
||||
const { data } = result;
|
||||
|
||||
//FIXME: libeufin does not follow the spec
|
||||
const balance = Amounts.parseOrThrow(data.balance);
|
||||
const balanceIsDebit = true;
|
||||
// const balance = Amounts.parseOrThrow(data.balance.amount);
|
||||
// const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
|
||||
const balance = Amounts.parseOrThrow(data.balance.amount);
|
||||
const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
|
||||
|
||||
const debitThreshold = Amounts.parseOrThrow(result.data.debit_threshold);
|
||||
const limit = balanceIsDebit
|
||||
|
@ -41,9 +41,7 @@ export function RemoveAccount({
|
||||
if (focus) ref.current?.focus();
|
||||
}, [focus]);
|
||||
|
||||
//FIXME: libeufin does not follow the spec
|
||||
const balance = Amounts.parse(result.data.balance);
|
||||
// const balance = Amounts.parse(result.data.balance.amount);
|
||||
const balance = Amounts.parse(result.data.balance.amount);
|
||||
if (!balance) {
|
||||
return <div>there was an error reading the balance</div>;
|
||||
}
|
||||
|
@ -236,11 +236,8 @@ function CreateCashout({
|
||||
if (!ratiosResult.ok) return onLoadNotOk(ratiosResult);
|
||||
const config = ratiosResult.data;
|
||||
|
||||
//FIXME: libeufin does not follow the spec
|
||||
const balance = Amounts.parseOrThrow(result.data.balance);
|
||||
const balanceIsDebit = true;
|
||||
// const balance = Amounts.parseOrThrow(result.data.balance.amount);
|
||||
// const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
|
||||
const balance = Amounts.parseOrThrow(result.data.balance.amount);
|
||||
const balanceIsDebit = result.data.balance.credit_debit_indicator == "debit";
|
||||
|
||||
const debitThreshold = Amounts.parseOrThrow(result.data.debit_threshold);
|
||||
const zero = Amounts.zeroOfCurrency(balance.currency);
|
||||
|
@ -26,6 +26,7 @@ import * as pages from "./pages/index.stories.js";
|
||||
|
||||
import { ComponentChildren, VNode, h as create } from "preact";
|
||||
import { BackendStateProviderTesting } from "./context/backend.js";
|
||||
import { AccessToken } from "./hooks/useCredentialsChecker.js";
|
||||
|
||||
setupI18n("en", { en: {} });
|
||||
|
||||
@ -56,7 +57,7 @@ function DefaultTestingContext({
|
||||
state: {
|
||||
status: "loggedIn",
|
||||
username: "test",
|
||||
password: "pwd",
|
||||
token: "pwd" as AccessToken,
|
||||
isUserAdministrator: false,
|
||||
},
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user