From b00cf3e6c0dcdd47dd04b071efc0c49d663dbfc0 Mon Sep 17 00:00:00 2001 From: Benoit Devos Date: Tue, 9 Apr 2024 10:00:03 +0200 Subject: [PATCH] chore: update authenticator, mock with AccountId. logion-network/logion-internal#1216 --- package.json | 4 +-- src/AuthenticationService.ts | 5 ++-- src/TestApp.ts | 50 ++++++++++++++++++++++-------------- yarn.lock | 10 ++++---- 4 files changed, 41 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index fbb0636..b4b2ecd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@logion/rest-api-core", - "version": "0.4.8-4", + "version": "0.4.8-5", "repository": { "type": "git", "url": "git+https://github.com/logion-network/logion-rest-api-core.git" @@ -26,7 +26,7 @@ "coverage": "nyc yarn run test" }, "dependencies": { - "@logion/authenticator": "^0.5.6-3", + "@logion/authenticator": "^0.5.6-4", "dinoloop": "^2.4.0", "express": "^4.18.2", "express-fileupload": "^1.4.0", diff --git a/src/AuthenticationService.ts b/src/AuthenticationService.ts index 952497e..4de088e 100644 --- a/src/AuthenticationService.ts +++ b/src/AuthenticationService.ts @@ -3,6 +3,7 @@ import { injectable } from "inversify"; import { Request } from "express"; import { UnauthorizedException } from "dinoloop/modules/builtin/exceptions/exceptions.js"; import { AuthenticationSystemFactory, unauthorized } from "./AuthenticationSystemFactory.js"; +import { ValidAccountId } from "@logion/node-api"; @injectable() export class AuthenticationService { @@ -17,7 +18,7 @@ export class AuthenticationService { return authenticator.ensureAuthenticatedUserOrThrow(jwtToken); } - async authenticatedUserIs(request: Request, address: string | undefined | null): Promise { + async authenticatedUserIs(request: Request, address: ValidAccountId | undefined | null): Promise { const user = await this.authenticatedUser(request); user.require(user => user.is(address), "User has not access to this resource"); return user; @@ -28,7 +29,7 @@ export class AuthenticationService { return user.requireLegalOfficerOnNode(); } - async authenticatedUserIsOneOf(request: Request, ...addresses: (string | undefined | null)[]): Promise { + async authenticatedUserIsOneOf(request: Request, ...addresses: (ValidAccountId | undefined | null)[]): Promise { const user = await this.authenticatedUser(request); user.require(user => user.isOneOf(addresses), "User has not access to this resource"); return user; diff --git a/src/TestApp.ts b/src/TestApp.ts index a29e13d..a380a9f 100644 --- a/src/TestApp.ts +++ b/src/TestApp.ts @@ -16,9 +16,11 @@ import { Mock } from "moq.ts"; import { AuthenticationService } from "./AuthenticationService.js"; import { UnauthorizedException } from "dinoloop/modules/builtin/exceptions/exceptions.js"; import { buildBaseExpress } from "./Express.js"; +import { AccountId, AnyAccountId } from "@logion/node-api"; export const ALICE = "vQx5kESPn8dWyX4KxMCKqUyCaWUwtui1isX6PVNcZh2Ghjitr"; export const BOB = "vQvWaxNDdzuX5N3qSvGMtjdHcQdw1TAcPNgx4S1Utd3MTxYeN"; +const ALICE_ACCOUNT = new AnyAccountId(ALICE, "Polkadot").toValidAccountId(); export * from "./TestUtil.js"; @@ -68,8 +70,8 @@ export interface AuthenticationServiceMock { ensureAuthorizationBearer: () => void; } -export function mockAuthenticationWithCondition(conditionFulfilled: boolean, address?: string): AuthenticationServiceMock { - const authenticatedUser = mockAuthenticatedUser(conditionFulfilled, address); +export function mockAuthenticationWithCondition(conditionFulfilled: boolean, account?: AccountId): AuthenticationServiceMock { + const authenticatedUser = mockAuthenticatedUser(conditionFulfilled, account); const ensureAuthorizationBearerMock = () => { if (!conditionFulfilled) { throw new UnauthorizedException(); @@ -112,13 +114,16 @@ export function mockAuthenticationFailureWithInvalidSignature(): AuthenticationS } } -export function mockAuthenticationForUserOrLegalOfficer(isLegalOfficer: boolean, address?: string) { +export function mockAuthenticationForUserOrLegalOfficer(isLegalOfficer: boolean, account?: AccountId) { const authenticatedUser = new Mock(); - authenticatedUser.setup(instance => instance.address).returns(address || ALICE); - authenticatedUser.setup(instance => instance.type).returns("Polkadot"); - authenticatedUser.setup(instance => instance.isPolkadot()).returns(true); - authenticatedUser.setup(instance => instance.is).returns(() => true); - authenticatedUser.setup(instance => instance.isOneOf).returns(() => true); + const validAccount = account ? + new AnyAccountId(account.address, account.type).toValidAccountId() : + ALICE_ACCOUNT; + authenticatedUser.setup(instance => instance.address).returns(validAccount.address); + authenticatedUser.setup(instance => instance.type).returns(validAccount.type); + authenticatedUser.setup(instance => instance.isPolkadot()).returns(validAccount.type === "Polkadot"); + authenticatedUser.setup(instance => instance.is).returns(account => account !== undefined && account !== null && account.equals(validAccount)); + authenticatedUser.setup(instance => instance.isOneOf).returns(accounts => accounts.some(account => account !== undefined && account !== null && account.equals(validAccount))); authenticatedUser.setup(instance => instance.require).returns((predicate) => { if(!predicate(authenticatedUser.object())) { throw new UnauthorizedException(); @@ -135,6 +140,7 @@ export function mockAuthenticationForUserOrLegalOfficer(isLegalOfficer: boolean, throw new UnauthorizedException(); } }) + authenticatedUser.setup(instance => instance.toValidAccountId()).returns(validAccount) return mockAuthenticationWithAuthenticatedUser(authenticatedUser.object()); } @@ -151,11 +157,14 @@ function mockAuthenticationService(mock: AuthenticationServiceMock): Authenticat return authenticationService.object(); } -export function mockAuthenticatedUser(conditionFulfilled: boolean, address?: string): AuthenticatedUser { +export function mockAuthenticatedUser(conditionFulfilled: boolean, account?: AccountId): AuthenticatedUser { const authenticatedUser = new Mock(); - authenticatedUser.setup(instance => instance.address).returns(address || ALICE); - authenticatedUser.setup(instance => instance.type).returns("Polkadot"); - authenticatedUser.setup(instance => instance.isPolkadot()).returns(true); + const validAccount = account ? + new AnyAccountId(account.address, account.type).toValidAccountId() : + ALICE_ACCOUNT; + authenticatedUser.setup(instance => instance.address).returns(validAccount.address); + authenticatedUser.setup(instance => instance.type).returns(validAccount.type); + authenticatedUser.setup(instance => instance.isPolkadot()).returns(validAccount.type === "Polkadot"); authenticatedUser.setup(instance => instance.is).returns(() => conditionFulfilled); authenticatedUser.setup(instance => instance.isOneOf).returns(() => conditionFulfilled); authenticatedUser.setup(instance => instance.require).returns((predicate) => { @@ -168,22 +177,24 @@ export function mockAuthenticatedUser(conditionFulfilled: boolean, address?: str authenticatedUser.setup(instance => instance.isNodeOwner).returns(() => conditionFulfilled); authenticatedUser.setup(instance => instance.isLegalOfficer()).returnsAsync(conditionFulfilled); authenticatedUser.setup(instance => instance.requireLegalOfficerOnNode).returns(() => { - if (address === ALICE) { + if (account?.address === ALICE) { return Promise.resolve(authenticatedUser.object()); } else { throw new UnauthorizedException(); } }); + authenticatedUser.setup(instance => instance.toValidAccountId()).returns(validAccount) return authenticatedUser.object(); } -export function mockLegalOfficerOnNode(address: string): AuthenticatedUser { +export function mockLegalOfficerOnNode(account: AccountId): AuthenticatedUser { const authenticatedUser = new Mock(); - authenticatedUser.setup(instance => instance.address).returns(address); - authenticatedUser.setup(instance => instance.type).returns("Polkadot"); - authenticatedUser.setup(instance => instance.isPolkadot()).returns(true); - authenticatedUser.setup(instance => instance.is).returns((param) => param === address); - authenticatedUser.setup(instance => instance.isOneOf).returns(addresses => addresses.indexOf(address) >= 0); + const validAccount = new AnyAccountId(account.address, account.type).toValidAccountId(); + authenticatedUser.setup(instance => instance.address).returns(validAccount.address); + authenticatedUser.setup(instance => instance.type).returns(validAccount.type); + authenticatedUser.setup(instance => instance.isPolkadot()).returns(validAccount.type === "Polkadot"); + authenticatedUser.setup(instance => instance.is).returns(account => account !== undefined && account !== null && account.equals(validAccount)); + authenticatedUser.setup(instance => instance.isOneOf).returns(accounts => accounts.some(account => account !== undefined && account !== null && account.equals(validAccount))); authenticatedUser.setup(instance => instance.require).returns((predicate) => { if (!predicate(authenticatedUser.object())) { throw new UnauthorizedException(); @@ -194,6 +205,7 @@ export function mockLegalOfficerOnNode(address: string): AuthenticatedUser { authenticatedUser.setup(instance => instance.isNodeOwner()).returns(true); authenticatedUser.setup(instance => instance.isLegalOfficer()).returnsAsync(true); authenticatedUser.setup(instance => instance.requireLegalOfficerOnNode()).returns(Promise.resolve(authenticatedUser.object())); + authenticatedUser.setup(instance => instance.toValidAccountId()).returns(validAccount) return authenticatedUser.object(); } diff --git a/yarn.lock b/yarn.lock index 1ad4a50..b855cdf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -564,9 +564,9 @@ __metadata: languageName: node linkType: hard -"@logion/authenticator@npm:^0.5.6-3": - version: 0.5.6-3 - resolution: "@logion/authenticator@npm:0.5.6-3" +"@logion/authenticator@npm:^0.5.6-4": + version: 0.5.6-4 + resolution: "@logion/authenticator@npm:0.5.6-4" dependencies: "@ethersproject/transactions": ^5.7.0 "@logion/node-api": ^0.29.0-2 @@ -579,7 +579,7 @@ __metadata: web3-utils: ^4.2.1 peerDependencies: "@logion/node-api": 0.x - checksum: 3b0e5892303c5910c081b1c3afdbe7f642282ec8ac598dbe909d6eb42739fdcbabd9d7c104efcf5c0b9b8066d8403860fa706a7e3824af2a766456644e31e83c + checksum: 43568b5446ccdfe7b9d0eedc526caa7e2dda64702f83ebe7a326d3c9480d17214b6c06cf3e964dcec98c9c472f7efbb35de6715fb888303c310ff98938217580 languageName: node linkType: hard @@ -602,7 +602,7 @@ __metadata: resolution: "@logion/rest-api-core@workspace:." dependencies: "@istanbuljs/nyc-config-typescript": ^1.0.2 - "@logion/authenticator": ^0.5.6-3 + "@logion/authenticator": ^0.5.6-4 "@logion/node-api": ^0.29.0-2 "@tsconfig/node16": ^16.1.1 "@types/express": ^4.17.14