diff --git a/package.json b/package.json index 67268fd..f41d2d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@logion/rest-api-core", - "version": "0.2.1-2", + "version": "0.2.1-4", "repository": { "type": "git", "url": "git+https://github.com/logion-network/logion-rest-api-core.git" diff --git a/src/AuthenticationService.ts b/src/AuthenticationService.ts index 499275e..c5be7ba 100644 --- a/src/AuthenticationService.ts +++ b/src/AuthenticationService.ts @@ -23,6 +23,11 @@ export class AuthenticationService { return user; } + async authenticatedUserIsLegalOfficerOnNode(request: Request): Promise { + const user = await this.authenticatedUser(request); + return user.requireLegalOfficerOnNode(); + } + async authenticatedUserIsOneOf(request: Request, ...addresses: (string | undefined | null)[]): Promise { const user = await this.authenticatedUser(request); user.require(user => user.isOneOf(addresses), "User has not access to this resource"); diff --git a/src/TestApp.ts b/src/TestApp.ts index 254366a..3d8e2b7 100644 --- a/src/TestApp.ts +++ b/src/TestApp.ts @@ -1,6 +1,12 @@ import "./inversify.decorate"; import { DateTime } from "luxon"; -import { AuthenticatedUser, AuthenticationSystem, Authenticator, SessionManager } from '@logion/authenticator'; +import { + AuthenticatedUser, + AuthenticationSystem, + Authenticator, + SessionManager, + AuthorityService +} from '@logion/authenticator'; import express, { Express } from 'express'; import { Dino } from 'dinoloop'; import { Container } from 'inversify'; @@ -105,6 +111,13 @@ export function mockAuthenticationForUserOrLegalOfficer(isLegalOfficer: boolean, }); authenticatedUser.setup(instance => instance.isNodeOwner()).returns(isLegalOfficer); authenticatedUser.setup(instance => instance.isLegalOfficer()).returnsAsync(isLegalOfficer); + authenticatedUser.setup(instance => instance.requireLegalOfficerOnNode).returns(() => { + if (isLegalOfficer) { + return Promise.resolve(authenticatedUser.object()) + } else { + throw new UnauthorizedException(); + } + }) return mockAuthenticationWithAuthenticatedUser(authenticatedUser.object()); } @@ -115,6 +128,7 @@ function mockAuthenticationService(mock: AuthenticationServiceMock): Authenticat authenticationService.setup(instance => instance.authenticatedUserIs).returns(mock.authenticatedUserIs); authenticationService.setup(instance => instance.authenticatedUserIsOneOf).returns(mock.authenticatedUserIsOneOf); authenticationService.setup(instance => instance.authenticatedUser).returns(mock.authenticatedUser); + authenticationService.setup(instance => instance.authenticatedUserIsLegalOfficerOnNode).returns(mock.authenticatedUser); authenticationService.setup(instance => instance.nodeOwner).returns(mock.nodeOwner); authenticationService.setup(instance => instance.ensureAuthorizationBearer).returns(mock.ensureAuthorizationBearer); return authenticationService.object(); @@ -134,6 +148,13 @@ 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) { + return Promise.resolve(authenticatedUser.object()); + } else { + throw new UnauthorizedException(); + } + }); return authenticatedUser.object(); } @@ -148,9 +169,21 @@ function mockAuthenticationSystem(mock: AuthenticationServiceMock): Authenticati const authenticator = new Mock(); authenticator.setup(instance => instance.ensureAuthenticatedUserOrThrow).returns(() => mock.authenticatedUser()); + const authorityService: AuthorityService = { + isLegalOfficer(): Promise { + return Promise.resolve(true); + }, + isLegalOfficerNode(): Promise { + return Promise.resolve(true); + }, + isLegalOfficerOnNode(): Promise { + return Promise.resolve(false); + } + } return { sessionManager: sessionManager.object(), authenticator: authenticator.object(), + authorityService, }; } diff --git a/test/AuthenticationController.spec.ts b/test/AuthenticationController.spec.ts index 6dad741..627d6f3 100644 --- a/test/AuthenticationController.spec.ts +++ b/test/AuthenticationController.spec.ts @@ -1,4 +1,12 @@ -import { Authenticator, Session, SessionManager, SessionSignature, SignedSession, Token } from "@logion/authenticator"; +import { + Authenticator, + Session, + SessionManager, + SessionSignature, + SignedSession, + Token, + AuthorityService +} from "@logion/authenticator"; import { UnauthorizedException } from "dinoloop"; import { Container } from "inversify"; import { DateTime } from "luxon"; @@ -160,9 +168,22 @@ function mockDependenciesForAuth(container: Container, verifies: boolean, sessio const sessionManager = new Mock(); const authenticator = new Mock(); + const authorityService: AuthorityService = { + isLegalOfficer(): Promise { + return Promise.resolve(true); + }, + isLegalOfficerNode(): Promise { + return Promise.resolve(true); + }, + isLegalOfficerOnNode(): Promise { + return Promise.resolve(false); + } + } + authenticationService.setup(instance => instance.authenticationSystem()).returnsAsync({ sessionManager: sessionManager.object(), authenticator: authenticator.object(), + authorityService, }); const session = new Mock(); diff --git a/yarn.lock b/yarn.lock index e5f4508..eb417ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -844,8 +844,8 @@ __metadata: linkType: hard "@logion/authenticator@npm:^0.3.3-1": - version: 0.3.3-2 - resolution: "@logion/authenticator@npm:0.3.3-2" + version: 0.3.3-4 + resolution: "@logion/authenticator@npm:0.3.3-4" dependencies: "@ethersproject/transactions": ^5.6.2 "@logion/node-api": ^0.8.0-1 @@ -855,7 +855,7 @@ __metadata: luxon: ^3.0.1 peer-id: ^0.16.0 web3-utils: ^1.7.4 - checksum: 146ae8160b912565ea3aa41c23c81fd315b346c667fd5d2f1e0993fdae86f8a9be93cd2a48354b413c2a23ede37e3880d703d7205fa049bbb6e8f53dc7f3ddc7 + checksum: 1e1e8920cf357f661fa098c7d89bbd00e13a9e440b7f0921ce646d07e587f331d9c225a9d710e78a6e4f66e72a4c0a8f620147bc46bef09c71fbcdc87b28afc6 languageName: node linkType: hard