Skip to content

Commit

Permalink
Merge pull request #15 from logion-network/feature/use-valid-account
Browse files Browse the repository at this point in the history
Extend use of ValidAccountId
  • Loading branch information
benoitdevos authored Apr 11, 2024
2 parents 06b6c7c + cdfbc22 commit fcf65ac
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 61 deletions.
2 changes: 1 addition & 1 deletion integration/Authentication.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe("Authentication", () => {
const tokenConfig: TokenConfig = {
nodePeerId: PeerId.createFromB58String("12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2"),
nodeKey: Buffer.from("c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a", "hex"),
nodeOwner: alice.address,
nodeOwner: alice,
jwtTimeToLive: Duration.fromObject({ hour: 1 }),
};
const { sessionManager, authenticator } = defaultSetup({ api, tokenConfig });
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@logion/authenticator",
"version": "0.5.6-4",
"version": "0.5.6-5",
"repository": {
"type": "git",
"url": "git+https://github.com/logion-network/logion-authenticator.git"
Expand All @@ -25,7 +25,7 @@
},
"dependencies": {
"@ethersproject/transactions": "^5.7.0",
"@logion/node-api": "^0.29.0-2",
"@logion/node-api": "^0.29.0-4",
"@multiversx/sdk-core": "^12.19.1",
"@multiversx/sdk-wallet": "^4.3.0",
"ethers": "^6.11.1",
Expand All @@ -36,7 +36,7 @@
},
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@logion/client": "^0.42.1-2",
"@logion/client": "^0.43.0-1",
"@tsconfig/node16": "^1.0.3",
"@types/jasmine": "^4.0.3",
"@types/luxon": "^3.4.2",
Expand Down
37 changes: 19 additions & 18 deletions src/AuthenticatedUser.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { AuthorityService, ErrorFactory } from "./Config.js";
import { AccountId, ValidAccountId, AccountType, AnyAccountId } from "@logion/node-api";
import { ValidAccountId, AnyAccountId, AccountId } from "@logion/node-api";
import { AccountType } from "@logion/node-api/dist/types/Types";

export class AuthenticatedUser implements AccountId {

constructor(
address: AccountId,
nodeOwner: string,
accountId: AccountId,
nodeOwner: ValidAccountId,
authorityService: AuthorityService,
errorFactory: ErrorFactory,
) {
this.type = address.type;
this.address = address.address;
this.validAccountId = new AnyAccountId(accountId.address, accountId.type).toValidAccountId();
this.nodeOwner = nodeOwner;
this.authorityService = authorityService;
this.errorFactory = errorFactory;
Expand All @@ -21,17 +21,15 @@ export class AuthenticatedUser implements AccountId {
}

isNodeOwner(): boolean {
return this.isPolkadot() && this.nodeOwner === this.address;
return this.isPolkadot() && this.nodeOwner.equals(this);
}

async isLegalOfficer(): Promise<boolean> {
return this.isPolkadot() && await this.authorityService.isLegalOfficer(this.address);
return this.isPolkadot() && await this.authorityService.isLegalOfficer(this.validAccountId);
}

is(validAccountId: ValidAccountId | undefined | null): boolean {
return validAccountId !== undefined
&& validAccountId !== null
&& validAccountId.equals(this.toValidAccountId())
return this.validAccountId.equals(validAccountId);
}

require(predicate: (check: AuthenticatedUser) => boolean, message?: string): AuthenticatedUser {
Expand All @@ -42,23 +40,26 @@ export class AuthenticatedUser implements AccountId {
}

async requireLegalOfficerOnNode(message?: string): Promise<AuthenticatedUser> {
if (! (this.isPolkadot() && await this.authorityService.isLegalOfficerOnNode(this.address))) {
if (! (this.isPolkadot() && await this.authorityService.isLegalOfficerOnNode(this.validAccountId))) {
throw this.errorFactory.unauthorized(message || "Authenticated User is not Legal Officer on this node.");
}
return this;
}

isOneOf(addresses: (ValidAccountId | undefined | null)[]): boolean {
return addresses.some(address => this.is(address));
isOneOf(accountIds: (ValidAccountId | undefined | null)[]): boolean {
return accountIds.some(accountId => this.is(accountId));
}

toValidAccountId(): ValidAccountId {
return new AnyAccountId(this.address, this.type).toValidAccountId();
get address(): string {
return this.validAccountId.address;
}

readonly address: string;
readonly type: AccountType;
private readonly nodeOwner: string;
get type(): AccountType {
return this.validAccountId.type;
}

readonly validAccountId: ValidAccountId;
private readonly nodeOwner: ValidAccountId;
private readonly authorityService: AuthorityService;
private readonly errorFactory: ErrorFactory;
}
4 changes: 2 additions & 2 deletions src/Authenticator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ export class Authenticator {
}

async ensureAuthenticatedUserOrThrow(jwtToken: string): Promise<AuthenticatedUser> {
const address = await this.validTokenOrThrow(jwtToken);
const account = await this.validTokenOrThrow(jwtToken);
return new AuthenticatedUser(
address,
account,
this.config.nodeOwner,
this.config.authorityService,
this.config.errorFactory
Expand Down
16 changes: 11 additions & 5 deletions src/Authority.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LogionNodeApiClass } from '@logion/node-api';
import { LogionNodeApiClass, ValidAccountId } from '@logion/node-api';
import { OpaquePeerId } from "@logion/node-api/dist/types/interfaces";
import PeerId from 'peer-id';

Expand All @@ -15,13 +15,19 @@ export class PolkadotAuthorityService implements AuthorityService {

private readonly nodeId: PeerId;

async isLegalOfficer(address: string): Promise<boolean> {
const entry = await this.api.polkadot.query.loAuthorityList.legalOfficerSet(address);
async isLegalOfficer(account: ValidAccountId): Promise<boolean> {
if (account.type !== "Polkadot") {
return false
}
const entry = await this.api.polkadot.query.loAuthorityList.legalOfficerSet(account.address);
return entry.isSome;
}

async isLegalOfficerOnNode(address: string): Promise<boolean> {
const entry = await this.api.polkadot.query.loAuthorityList.legalOfficerSet(address);
async isLegalOfficerOnNode(account: ValidAccountId): Promise<boolean> {
if (account.type !== "Polkadot") {
return false
}
const entry = await this.api.polkadot.query.loAuthorityList.legalOfficerSet(account.address);
if(!entry.isSome) {
return false;
} else {
Expand Down
8 changes: 4 additions & 4 deletions src/Config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LogionNodeApiClass } from "@logion/node-api";
import { LogionNodeApiClass, ValidAccountId } from "@logion/node-api";
import { Duration } from "luxon";
import PeerId from "peer-id";
import { Authenticator } from "./Authenticator.js";
Expand All @@ -14,7 +14,7 @@ import {
} from "./Signature.js";

export interface TokenConfig {
readonly nodeOwner: string;
readonly nodeOwner: ValidAccountId;
readonly nodePeerId: PeerId;
readonly nodeKey: Buffer;
readonly jwtTimeToLive: Duration;
Expand All @@ -31,8 +31,8 @@ export interface ErrorFactory {

export interface AuthorityService {
isLegalOfficerNode(peerId: PeerId): Promise<boolean>;
isLegalOfficer(address: string): Promise<boolean>;
isLegalOfficerOnNode(address: string): Promise<boolean>;
isLegalOfficer(account: ValidAccountId): Promise<boolean>;
isLegalOfficerOnNode(account: ValidAccountId): Promise<boolean>;
}

export function defaultErrorFactory(): ErrorFactory {
Expand Down
12 changes: 6 additions & 6 deletions test/AuthenticatedUser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { It, Mock } from "moq.ts";
import { AuthenticatedUser, AuthorityService } from "../src/index.js";
import { AccountType, ValidAccountId, AnyAccountId } from "@logion/node-api";

const ALICE = "vQx5kESPn8dWyX4KxMCKqUyCaWUwtui1isX6PVNcZh2Ghjitr";
const ALICE = ValidAccountId.polkadot("vQx5kESPn8dWyX4KxMCKqUyCaWUwtui1isX6PVNcZh2Ghjitr");
const USER_POLKADOT_ADDRESS = "vQxHAE33LeJYV69GCB4o4YcCgnDu8y99u5hy2751fRdxjX9kz"
const USER_ETHEREUM_ADDRESS = "0x590E9c11b1c2f20210b9b84dc2417B4A7955d4e6"
const SOME_OTHER_USER = "5E4cdkKrh19n75jUrDDrs3RBc1yvt4XqYZux8piEXnsc1Et7";
Expand Down Expand Up @@ -52,7 +52,7 @@ describe('AuthenticatedUser', () => {

it('authenticates legal officer based on token', async () => {
const authenticatedUser = buildAuthenticatedUser({
address: ALICE,
address: ALICE.address,
isWellKnownNode: true,
});
expect(authenticatedUser.isNodeOwner()).toBe(true);
Expand All @@ -76,17 +76,17 @@ describe('AuthenticatedUser', () => {
isWellKnownNode: true,
addressType: "Ethereum"
});
expect(authenticatedUser.toValidAccountId().type).toEqual("Ethereum");
expect(authenticatedUser.toValidAccountId().address).toEqual(USER_ETHEREUM_ADDRESS);
expect(authenticatedUser.validAccountId.type).toEqual("Ethereum");
expect(authenticatedUser.validAccountId.address).toEqual(USER_ETHEREUM_ADDRESS);
})

it("builds valid Account ID for Polkadot address", async () => {
const authenticatedUser = buildAuthenticatedUser({
address: USER_POLKADOT_ADDRESS,
isWellKnownNode: true,
});
expect(authenticatedUser.toValidAccountId().type).toEqual("Polkadot");
expect(authenticatedUser.toValidAccountId().address).toEqual(USER_POLKADOT_ADDRESS);
expect(authenticatedUser.validAccountId.type).toEqual("Polkadot");
expect(authenticatedUser.validAccountId.address).toEqual(USER_POLKADOT_ADDRESS);
})
})

Expand Down
6 changes: 4 additions & 2 deletions test/Authenticator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import { Mock, It } from "moq.ts";
import PeerId from "peer-id";

import { Authenticator, AuthenticatorConfig, AuthorityService, defaultErrorFactory, SignedSession } from "../src/index.js";
import { ValidAccountId } from "@logion/node-api";

const ALICE = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
const ALICE = ValidAccountId.polkadot("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY");
const USER_TOKEN_PAYLOAD = "eyJhbGciOiJFZERTQSJ9.eyJhZGRyZXNzVHlwZSI6IlBvbGthZG90IiwiaWF0IjoxNjMxMjE3NjExLCJleHAiOjQ3ODQ4MTc2MTEsImlzcyI6IjEyRDNLb29XREN1R1U3V1kzVmFXakJTMUU0NHg0RW5tVGdLM0hSeFdGcVlHM2RxWERmUDEiLCJzdWIiOiI1SDRNdkFzb2JmWjZiQkNEeWo1ZHNyV1lMckE4SHJSemFxYTlwNjFVWHR4TWhTQ1kifQ"
const USER_TOKEN = USER_TOKEN_PAYLOAD + ".WT9c_0PkSoJm5y6PbXKOpphP_RxOBWtCJJnun8QRC34MnYB_HXaOIW9Miee19-L0BV72YDpB0whk2WOvR2XyBg";
const USER_TOKEN_WRONG_SIGNATURE = USER_TOKEN_PAYLOAD + ".GTLJB_uMjsdcuWzM3CWL92n1UNI0WYXFUDW7QQ1Vi6k3TQIEvG_WwMuuZ2d9cexY";
const ALICE_TOKEN = "eyJhbGciOiJFZERTQSJ9.eyJhZGRyZXNzVHlwZSI6IlBvbGthZG90IiwiaWF0IjoxNjMxMjE3NjExLCJleHAiOjQ3ODQ4MTc2MTEsImlzcyI6IjEyRDNLb29XREN1R1U3V1kzVmFXakJTMUU0NHg0RW5tVGdLM0hSeFdGcVlHM2RxWERmUDEiLCJzdWIiOiI1R3J3dmFFRjV6WGIyNkZ6OXJjUXBEV1M1N0N0RVJIcE5laFhDUGNOb0hHS3V0UVkifQ.Bp6MrRdlDZqJwPUShc2MLJTsC2vuTFY0XeQtM9sMHthnOq5LwmapMzHz-EUFw225bQsAMHpgA18DrkJMv2AECw"
const USER_ADDRESS = "5H4MvAsobfZ6bBCDyj5dsrWYLrA8HrRzaqa9p61UXtxMhSCY"
const USER = ValidAccountId.polkadot(USER_ADDRESS);
const TTL = 100 * 365 * 24 * 3600; // 100 years

describe('Authenticator', () => {
Expand All @@ -32,7 +34,7 @@ describe('Authenticator', () => {
it('authenticates user based on token', async () => {
const authenticationService = new Authenticator(buildConfig());
const logionUser = await authenticationService.ensureAuthenticatedUserOrThrow(USER_TOKEN);
expect(logionUser.address).toBe(USER_ADDRESS);
expect(logionUser.address).toBe(USER.address);
})

it('authenticates node owner based on token', async () => {
Expand Down
18 changes: 9 additions & 9 deletions test/Authority.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@ import PeerId, { createFromB58String } from "peer-id";
import { AccountId, OpaquePeerId } from "@logion/node-api/dist/types/interfaces";

import { PolkadotAuthorityService } from "../src/index.js";
import { LogionNodeApiClass } from "@logion/node-api";
import { LogionNodeApiClass, ValidAccountId } from "@logion/node-api";

const ALICE = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
const ALICE = ValidAccountId.polkadot("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY");
const NODE1 = "12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2";
const BOB = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty";
const BOB = ValidAccountId.polkadot("5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty");
const NODE2 = "12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust";
const ANY_NODE = "12D3KooWDCuGU7WY3VaWjBS1E44x4EnmTgK3HRxWFqYG3dqXDfP1";
const CHARLIE = "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y";
const CHARLIE = ValidAccountId.polkadot("5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y");

const HOSTS: Record<string, string> = {
[ALICE]: NODE1,
[BOB]: NODE2,
[ALICE.address]: NODE1,
[BOB.address]: NODE2,
};

const GUESTS: Record<string, string> = {
[CHARLIE]: ALICE,
[CHARLIE.address]: ALICE.address,
}

const REGULAR_USER_ADDRESS = "5EBxoSssqNo23FvsDeUxjyQScnfEiGxJaNwuwqBH2Twe35BX";
const REGULAR_USER = ValidAccountId.polkadot("5EBxoSssqNo23FvsDeUxjyQScnfEiGxJaNwuwqBH2Twe35BX");

describe("PolkadotAuthorityService", () => {

Expand All @@ -38,7 +38,7 @@ describe("PolkadotAuthorityService", () => {
it("fails for a non-legal officer", async () => {
const polkadotService = mockPolkadotServiceWithLegalOfficer(HOSTS, {});
const authorityService = new PolkadotAuthorityService(polkadotService, PeerId.createFromB58String(NODE1));
expect(await authorityService.isLegalOfficer(REGULAR_USER_ADDRESS)).toBe(false);
expect(await authorityService.isLegalOfficer(REGULAR_USER)).toBe(false);
})

it("detects a legal officer node", async () => {
Expand Down
22 changes: 11 additions & 11 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,8 @@ __metadata:
dependencies:
"@ethersproject/transactions": ^5.7.0
"@istanbuljs/nyc-config-typescript": ^1.0.2
"@logion/client": ^0.42.1-2
"@logion/node-api": ^0.29.0-2
"@logion/client": ^0.43.0-1
"@logion/node-api": ^0.29.0-4
"@multiversx/sdk-core": ^12.19.1
"@multiversx/sdk-wallet": ^4.3.0
"@tsconfig/node16": ^1.0.3
Expand Down Expand Up @@ -595,29 +595,29 @@ __metadata:
languageName: unknown
linkType: soft

"@logion/client@npm:^0.42.1-2":
version: 0.42.1-2
resolution: "@logion/client@npm:0.42.1-2"
"@logion/client@npm:^0.43.0-1":
version: 0.43.0-1
resolution: "@logion/client@npm:0.43.0-1"
dependencies:
"@logion/node-api": ^0.29.0-2
"@logion/node-api": ^0.29.0-4
axios: ^1.6.7
luxon: ^3.4.4
mime-db: ^1.52.0
checksum: f20b357002073d8e7c87f87a364eb39b995ea63cd0515f43e440ea6c6a42a20dd7ce5f834796ab7f36a9bb0772707f951a912b65d6e9c2370fbe893684bb9d6c
checksum: 096c7e804987694a245179f94645310659ab9bf84785220918642d51bc1a3e0324a5a44566346408a1b62b9b3590853b24b853e2357e55d28dbff6813d2b5093
languageName: node
linkType: hard

"@logion/node-api@npm:^0.29.0-2":
version: 0.29.0-2
resolution: "@logion/node-api@npm:0.29.0-2"
"@logion/node-api@npm:^0.29.0-4":
version: 0.29.0-4
resolution: "@logion/node-api@npm:0.29.0-4"
dependencies:
"@polkadot/api": ^10.12.2
"@polkadot/util": ^12.6.2
"@polkadot/util-crypto": ^12.6.2
"@types/uuid": ^9.0.2
fast-sha256: ^1.3.0
uuid: ^9.0.0
checksum: 0e09ab749c4e46f0e3929fafb10e9da14ced797df929ef2f799ee3a34ad3a7214164a7698c54705ab87b4a76e0b6f79442ba198a1728e4ae5bb7c02fd1118217
checksum: 2ce96fa554c64816b555b090672bcb3ac2472eee6a50c0d1fd19705d6dfc2ae574ca4828f08891bca3529636b0bdb1162e636a3f46ebb4a6d2edc6a442b9e3e9
languageName: node
linkType: hard

Expand Down

0 comments on commit fcf65ac

Please sign in to comment.