commit 1223268bdd21e947a327fc81056f17a504a55466
parent 1516e6ea13de77263243e21c65a0c92b9211708e
Author: Florian Dold <florian@dold.me>
Date: Tue, 25 Feb 2025 14:42:37 +0100
util: get rid of separate auth client
Auth is part of each service client
Diffstat:
14 files changed, 74 insertions(+), 249 deletions(-)
diff --git a/packages/bank-ui/src/Routing.tsx b/packages/bank-ui/src/Routing.tsx
@@ -38,7 +38,7 @@ import { useEffect } from "preact/hooks";
import { useSessionState } from "./hooks/session.js";
import { AccountPage } from "./pages/AccountPage/index.js";
import { BankFrame } from "./pages/BankFrame.js";
-import { SESSION_DURATION, LoginForm } from "./pages/LoginForm.js";
+import { LoginForm, SESSION_DURATION } from "./pages/LoginForm.js";
import { PublicHistoriesPage } from "./pages/PublicHistoriesPage.js";
import { RegistrationPage } from "./pages/RegistrationPage.js";
import { ShowNotifications } from "./pages/ShowNotifications.js";
@@ -73,7 +73,7 @@ export function Routing(): VNode {
};
const {
- lib: { auth: authenticator },
+ lib: { bank },
} = useBankCoreApiContext();
useEffect(() => {
@@ -97,13 +97,15 @@ export function Routing(): VNode {
0,
);
const timeoutId = setTimeout(async () => {
- const result = await authenticator(
+ const result = await bank.createAccessTokenBasic(
refreshSession.user,
- ).createAccessTokenBearer_BANK(refreshSession.auth, {
- scope: "readwrite",
- duration: SESSION_DURATION,
- refreshable: true,
- });
+ refreshSession.auth,
+ {
+ scope: "readwrite",
+ duration: SESSION_DURATION,
+ refreshable: true,
+ },
+ );
if (result.type === "fail") {
console.log(`could not refresh session ${result.case}`);
return;
@@ -175,13 +177,11 @@ function PublicRounting({
async function doAutomaticLogin(username: string, password: string) {
await handleError(async () => {
- const resp = await lib
- .auth(username)
- .createAccessTokenBasic(username, password, {
- scope: "readwrite",
- duration: SESSION_DURATION,
- refreshable: true,
- });
+ const resp = await lib.bank.createAccessTokenBasic(username, password, {
+ scope: "readwrite",
+ duration: SESSION_DURATION,
+ refreshable: true,
+ });
if (resp.type === "ok") {
onLoggedUser(
username,
diff --git a/packages/bank-ui/src/pages/BankFrame.tsx b/packages/bank-ui/src/pages/BankFrame.tsx
@@ -69,7 +69,7 @@ export function BankFrame({
const [, , resetBankState] = useBankState();
const d = useBankCoreApiContext();
const config = d === undefined ? undefined : d.config;
- const authenticator = d === undefined ? undefined : d.lib.auth;
+ const authenticator = d === undefined ? undefined : d.lib.bank;
const [error, resetError] = useErrorBoundary();
useEffect(() => {
@@ -108,7 +108,8 @@ export function BankFrame({
? undefined
: () => {
if (session.state.status === "loggedIn" && authenticator) {
- authenticator(session.state.username).deleteAccessToken(
+ // FIXME: This returns a promise, should await on it!
+ authenticator.deleteAccessToken(session.state.username,
session.state.token,
);
}
diff --git a/packages/bank-ui/src/pages/LoginForm.tsx b/packages/bank-ui/src/pages/LoginForm.tsx
@@ -30,7 +30,7 @@ import {
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
-import { useEffect, useRef, useState } from "preact/hooks";
+import { useState } from "preact/hooks";
import { useSessionState } from "../hooks/session.js";
import { undefinedIfEmpty } from "../utils.js";
import { doAutoFocus } from "./PaytoWireTransferForm.js";
@@ -69,7 +69,7 @@ export function LoginForm({
const [password, setPassword] = useState<string | undefined>();
const { i18n } = useTranslationContext();
const {
- lib: { auth: authenticator },
+ lib: { bank: authenticator },
} = useBankCoreApiContext();
const [notification, withErrorHandler] = useLocalNotificationHandler();
const { config } = useBankCoreApiContext();
@@ -85,7 +85,8 @@ export function LoginForm({
async function doLogout() {
if (sessionState) {
- authenticator(sessionState.username).deleteAccessToken(
+ authenticator.deleteAccessToken(
+ sessionState.username,
sessionState.token,
);
}
@@ -97,7 +98,7 @@ export function LoginForm({
? undefined
: withErrorHandler(
async () =>
- authenticator(username).createAccessTokenBasic(username, password, {
+ authenticator.createAccessTokenBasic(username, password, {
scope: "readwrite",
duration: SESSION_DURATION,
refreshable: true,
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
@@ -59,16 +59,13 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode {
}
if (d.auth.token) {
//if auth has been updated, request a new access token
- const result = await lib.authenticate.createAccessTokenBearer(
- d.auth.token,
- {
- scope: "write",
- duration: {
- d_us: "forever",
- },
- refreshable: true,
+ const result = await lib.instance.createAuthTokenFromToken(d.auth.token, {
+ scope: "write",
+ duration: {
+ d_us: "forever",
},
- );
+ refreshable: true,
+ });
if (result.type === "ok") {
const { token } = result.body;
logIn(token);
@@ -79,7 +76,8 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode {
setNotif({
message: i18n.str`Failed to create instance`,
type: "ERROR",
- description: error instanceof Error ? error.message : String(error),
+ description:
+ error instanceof Error ? error.message : String(error),
});
}
}}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
@@ -114,16 +114,13 @@ export default function Token({ onChange, onCancel }: Props): VNode {
});
}
}
- const resp = await lib.authenticate.createAccessTokenBearer(
- newToken,
- {
- scope: "write",
- duration: {
- d_us: "forever",
- },
- refreshable: true,
+ const resp = await lib.instance.createAuthTokenFromToken(newToken, {
+ scope: "write",
+ duration: {
+ d_us: "forever",
},
- );
+ refreshable: true,
+ });
if (resp.type === "ok") {
logIn(resp.body.token);
return onChange();
diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
@@ -48,7 +48,7 @@ export function LoginPage(_p: Props): VNode {
const { i18n } = useTranslationContext();
async function doLoginImpl() {
- const result = await lib.authenticate.createAccessTokenBearer(
+ const result = await lib.instance.createAuthTokenFromToken(
createRFC8959AccessTokenEncoded(token),
tokenRequest,
);
diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts
@@ -29,7 +29,6 @@ import {
Logger,
MerchantAuthMethod,
PaytoString,
- TalerAuthenticationHttpClient,
TalerBankConversionHttpClient,
TalerCoreBankHttpClient,
TalerKycAml,
@@ -201,7 +200,7 @@ testingCli
const merchantBaseUrl = "https://backend.test.taler.net/instances/sandbox/";
const merchantApi = new TalerMerchantInstanceHttpClient(merchantBaseUrl);
const tokResp = succeedOrThrow(
- await merchantApi.createLoginToken("secret-token:sandbox", {
+ await merchantApi.createAuthTokenFromToken("secret-token:sandbox", {
scope: "write",
}),
);
@@ -852,10 +851,6 @@ deploymentCli
bank.getConversionInfoAPI().href,
httpLib,
);
- const bankAuth = new TalerAuthenticationHttpClient(
- bank.getAuthenticationAPI(id).href,
- httpLib,
- );
const bc = await bank.getConfig();
if (bc.type === "fail") {
@@ -882,12 +877,7 @@ deploymentCli
let bankAdminToken: AccessToken | undefined;
if (bankAdminPassword) {
- const adminAuth = new TalerAuthenticationHttpClient(
- bank.getAuthenticationAPI("admin").href,
- httpLib,
- );
-
- const resp = await adminAuth.createAccessTokenBasic(
+ const resp = await bank.createAccessTokenBasic(
"admin",
bankAdminPassword,
{
@@ -1059,7 +1049,7 @@ deploymentCli
logger.info("random password: ", randomPassword);
let token: AccessToken;
{
- const resp = await bankAuth.createAccessTokenBasic(id, prevPassword, {
+ const resp = await bank.createAccessTokenBasic(id, prevPassword, {
scope: "readwrite",
duration: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }),
diff --git a/packages/taler-util/src/http-client/authentication.ts b/packages/taler-util/src/http-client/authentication.ts
@@ -1,165 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Imports.
- */
-import { HttpStatusCode } from "../http-status-codes.js";
-import {
- HttpRequestLibrary,
- createPlatformHttpLib,
- makeBasicAuthHeader,
- readTalerErrorResponse,
-} from "../http.js";
-import { LibtoolVersion } from "../libtool-version.js";
-import {
- opEmptySuccess,
- opKnownHttpFailure,
- opSuccessFromHttp,
- opUnknownFailure,
-} from "../operation.js";
-import {
- AccessToken,
- TokenRequest,
- codecForTokenSuccessResponse,
- codecForTokenSuccessResponseMerchant,
-} from "../types-taler-common.js";
-import { makeBearerTokenAuthHeader } from "./utils.js";
-
-export class TalerAuthenticationHttpClient {
- public readonly PROTOCOL_VERSION = "0:0:0";
-
- httpLib: HttpRequestLibrary;
-
- constructor(
- readonly baseUrl: string,
- httpClient?: HttpRequestLibrary,
- ) {
- this.httpLib = httpClient ?? createPlatformHttpLib();
- }
-
- isCompatible(version: string): boolean {
- const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
- return compare?.compatible ?? false;
- }
-
- /**
- * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
- *
- * @returns
- */
- async createAccessTokenBasic(
- username: string,
- password: string,
- body: TokenRequest,
- ) {
- const url = new URL(`token`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- headers: {
- Authorization: makeBasicAuthHeader(username, password),
- },
- body,
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForTokenSuccessResponse());
- //FIXME: missing in docs
- case HttpStatusCode.Unauthorized:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await readTalerErrorResponse(resp));
- }
- }
-
- /**
- * FIXME: merge this with createAccessTokenBearer the protocol of both
- * services need to reply the same
- *
- * @returns
- */
- async createAccessTokenBearer_BANK(token: AccessToken, body: TokenRequest) {
- const url = new URL(`token`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- headers: {
- Authorization: makeBearerTokenAuthHeader(token),
- },
- body,
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForTokenSuccessResponse());
- //FIXME: missing in docs
- case HttpStatusCode.Unauthorized:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await readTalerErrorResponse(resp));
- }
- }
-
- /**
- *
- * @returns
- */
- async createAccessTokenBearer(token: AccessToken, body: TokenRequest) {
- const url = new URL(`token`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- headers: {
- Authorization: makeBearerTokenAuthHeader(token),
- },
- body,
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForTokenSuccessResponseMerchant());
- //FIXME: missing in docs
- case HttpStatusCode.Unauthorized:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await readTalerErrorResponse(resp));
- }
- }
-
- async deleteAccessToken(token: AccessToken) {
- const url = new URL(`token`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "DELETE",
- headers: {
- Authorization: makeBearerTokenAuthHeader(token),
- },
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opEmptySuccess(resp);
- //FIXME: missing in docs
- case HttpStatusCode.NoContent:
- return opEmptySuccess(resp);
- //FIXME: missing in docs
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownFailure(resp, await readTalerErrorResponse(resp));
- }
- }
-}
diff --git a/packages/taler-util/src/http-client/bank-core.ts b/packages/taler-util/src/http-client/bank-core.ts
@@ -152,6 +152,28 @@ export class TalerCoreBankHttpClient {
}
}
+ async deleteAccessToken(user: string, token: AccessToken) {
+ const url = new URL(`accounts/${user}/token`, this.baseUrl);
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "DELETE",
+ headers: {
+ Authorization: makeBearerTokenAuthHeader(token),
+ },
+ });
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opEmptySuccess(resp);
+ // FIXME: missing in docs
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess(resp);
+ // FIXME: missing in docs
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
/**
* https://docs.taler.net/core/api-corebank.html#config
*
@@ -1143,14 +1165,6 @@ export class TalerCoreBankHttpClient {
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
*
*/
- getAuthenticationAPI(username: string): URL {
- return new URL(`accounts/${username}/`, this.baseUrl);
- }
-
- /**
- * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
- *
- */
getConversionInfoAPI(): URL {
return new URL(`conversion-info/`, this.baseUrl);
}
diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts
@@ -219,7 +219,16 @@ export class TalerMerchantInstanceHttpClient {
// Auth
//
- async createLoginToken(
+ /**
+ * Create an auth token from a login token.
+ *
+ * See https://bugs.gnunet.org/view.php?id=9556 to explain
+ * this weirdness.
+ *
+ * In the future, we'll only create auth tokens from login
+ * credentials.
+ */
+ async createAuthTokenFromToken(
token: string,
body: TokenRequest,
): Promise<
diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts
@@ -1,7 +1,4 @@
-import { TalerErrorCode } from "./taler-error-codes.js";
-
-export { TalerErrorCode };
-
+export { TalerErrorCode } from "./taler-error-codes.js";
export * from "./amounts.js";
export * from "./bank-api-client.js";
export * from "./base64.js";
@@ -12,7 +9,6 @@ export * from "./contract-terms.js";
export * from "./errors.js";
export { fnutil } from "./fnutils.js";
export * from "./helpers.js";
-export * from "./http-client/authentication.js";
export * from "./http-client/bank-conversion.js";
export * from "./http-client/bank-core.js";
export * from "./http-client/bank-integration.js";
diff --git a/packages/web-util/src/context/activity.ts b/packages/web-util/src/context/activity.ts
@@ -17,7 +17,6 @@
import {
ChallengerHttpClient,
ObservabilityEvent,
- TalerAuthenticationHttpClient,
TalerBankConversionHttpClient,
TalerCoreBankHttpClient,
TalerExchangeHttpClient,
@@ -64,7 +63,6 @@ export interface APIClient<T, C> {
export interface MerchantLib {
instance: TalerMerchantManagementHttpClient;
- authenticate: TalerAuthenticationHttpClient;
subInstanceApi: (instanceId: string) => MerchantLib;
}
@@ -75,7 +73,6 @@ export interface ExchangeLib {
export interface BankLib {
bank: TalerCoreBankHttpClient;
conversion: TalerBankConversionHttpClient;
- auth: (user: string) => TalerAuthenticationHttpClient;
}
export interface ChallengerLib {
diff --git a/packages/web-util/src/context/bank-api.ts b/packages/web-util/src/context/bank-api.ts
@@ -19,7 +19,6 @@ import {
LibtoolVersion,
ObservabilityEvent,
ObservableHttpClientLibrary,
- TalerAuthenticationHttpClient,
TalerBankConversionCacheEviction,
TalerBankConversionHttpClient,
TalerCoreBankCacheEviction,
@@ -183,11 +182,6 @@ function buildBankApiClient(
httpLib,
evictors.conversion,
);
- const auth = (user: string) =>
- new TalerAuthenticationHttpClient(
- bank.getAuthenticationAPI(user).href,
- httpLib,
- );
async function getRemoteConfig(): Promise<TalerCorebankApi.TalerCorebankConfigResponse> {
const resp = await bank.getConfig();
@@ -209,7 +203,6 @@ function buildBankApiClient(
lib: {
bank,
conversion,
- auth,
},
onActivity: tracker.subscribe,
cancelRequest: httpLib.cancelRequest,
diff --git a/packages/web-util/src/context/merchant-api.ts b/packages/web-util/src/context/merchant-api.ts
@@ -19,7 +19,6 @@ import {
LibtoolVersion,
ObservabilityEvent,
ObservableHttpClientLibrary,
- TalerAuthenticationHttpClient,
TalerError,
TalerMerchantApi,
TalerMerchantInstanceCacheEviction,
@@ -182,10 +181,6 @@ function buildMerchantApiClient(
httpLib,
evictors.management,
);
- const authenticate = new TalerAuthenticationHttpClient(
- instance.getAuthenticationAPI().href,
- httpLib,
- );
function getSubInstanceAPI(instanceId: string): MerchantLib {
const api = buildMerchantApiClient(
@@ -212,7 +207,6 @@ function buildMerchantApiClient(
VERSION: instance.PROTOCOL_VERSION,
lib: {
instance,
- authenticate,
subInstanceApi: getSubInstanceAPI,
},
onActivity: tracker.subscribe,