Skip to content

Commit

Permalink
solution: create/delete permanent auth tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
kanazirsky committed Jan 15, 2025
1 parent a710fd8 commit 89ea893
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 22 deletions.
2 changes: 1 addition & 1 deletion api-definitions
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export {
CredentialsClient,
RefreshRequest,
ConvertAuth,
DeleteTokenRequest, DeleteTokenResponse,
ListTokensRequest, ListTokensResponse, TokenDetails,
WhoIAmResponse, IAmAuthenticated, IAMUnauthenticated,
IssueTokenRequest, IssuedTokenResponse,
Expand Down
53 changes: 51 additions & 2 deletions packages/core/src/typesAuth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {MessageFactory} from "./typesConvert";
import * as auth_pb from "./generated/auth_pb";
import {UUID} from "./typesCommon";
import {MessageFactory} from "./typesConvert";

export type AuthCapability = 'JWT_RS256';

Expand Down Expand Up @@ -87,8 +87,9 @@ export type IssueTokenRequest = {
/**
* Type of the token to issue
* - "temp" - one-time token
* - "permanent" - long-live token that can be used multiple times
*/
type: "temp",
type: "temp" | "permanent",

/**
* The scopes to be used for the token. Cannot be larger that the current authenticated scopes.
Expand All @@ -106,6 +107,22 @@ export type IssueTokenRequest = {
* For a temp one-time token, by default, it's 1 Day and cannot be more than 30 days.
*/
expireAt?: Date,

/**
* (for a permanent token) organization id for the token
*/
organizationId?: OrganizationId,

/**
* (for a permanent token) project id for the token
*/
projectId?: ProjectId,

/**
* (for a permanent token) description of the token
*/
description?: string,

}

export type IssuedTokenResponse = {
Expand All @@ -120,6 +137,14 @@ export type IssuedTokenResponse = {
expiresAt: Date,
}

export type DeleteTokenRequest = {
organizationId: OrganizationId,
projectId: ProjectId,
tokenId: TokenId,
}

export type DeleteTokenResponse = Record<string, never>;

export class ConvertAuth {
private readonly factory: MessageFactory;

Expand Down Expand Up @@ -201,13 +226,24 @@ export class ConvertAuth {
const result: auth_pb.IssueTokenRequest = this.factory('auth_pb.IssueTokenRequest');
if (req.type == "temp") {
result.setType(auth_pb.IssueTokenRequest.TokenType.TEMP);
} else if (req.type == "permanent") {
result.setType(auth_pb.IssueTokenRequest.TokenType.PERMANENT);
}
if (req.scopes) {
result.setScopesList(req.scopes);
}
if (req.userId) {
result.setUserId(req.userId);
}
if (req.organizationId) {
result.setOrganizationId(req.organizationId);
}
if (req.projectId) {
result.setProjectId(req.projectId);
}
if (req.description) {
result.setDescription(req.description);
}
if (req.expireAt) {
result.setExpireAt(req.expireAt.getTime());
}
Expand All @@ -223,6 +259,19 @@ export class ConvertAuth {
expiresAt: res.getExpiresAt() > 0 ? new Date(res.getExpiresAt()) : new Date(Date.now() + 10 * 365 * 24 * 60 * 60 * 1000),
}
}

public deleteTokenRequest(req: DeleteTokenRequest): auth_pb.DeleteTokenRequest {
const result: auth_pb.DeleteTokenRequest = this.factory('auth_pb.DeleteTokenRequest');
result.setOrganizationId(req.organizationId);
result.setProjectId(req.projectId);
result.setTokenId(req.tokenId);
return result;
}

// eslint-disable-next-line unused-imports/no-unused-vars
public deleteTokenResponse(res: auth_pb.DeleteTokenResponse): DeleteTokenResponse {
return {};
}
}

/**
Expand Down
4 changes: 3 additions & 1 deletion packages/node/src/EmeraldApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export class EmeraldApi {

static devApi(token?: SecretToken | undefined, credentials?: ChannelCredentials): EmeraldApi {
// a dev token with access only from the internal network
const devToken = token ?? 'emrld_8ntrHbZN67DF8TWKgCMO1I9nSaMG0cpoMhj3GP';
// Token ID: 893b95a0-d28c-49b9-b1b1-6c63e2081d7e
// User ID: bada55a1-0000-4000-a000-000000000000
const devToken = token ?? 'emrld_pbhT80xj0hsnFf73uOVJ6LEmenaVcbsXO7pGwH';
return new EmeraldApi('api.emeraldpay.dev:443', devToken, credentials);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ describe("SierraProjectClient", () => {
let api: EmeraldApi;

beforeAll(() => {
// a dev token with user id: bada55a1-0000-4000-a000-000000000000
api = EmeraldApi.devApi("emrld_fU88aIafXsCClerhyWtflBp1hH6h112ckzpSfP");
api = EmeraldApi.devApi();
});

test('createProject permission denied for the user', async () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/EmeraldApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class EmeraldApi {

static devApi(token?: SecretToken | undefined, credentials?: CredentialsContext): EmeraldApi {
// a dev token with access only from the internal network
const devToken = token ?? 'emrld_8ntrHbZN67DF8TWKgCMO1I9nSaMG0cpoMhj3GP';
const devToken = token ?? 'emrld_pbhT80xj0hsnFf73uOVJ6LEmenaVcbsXO7pGwH';
return new EmeraldApi('https://api.emeraldpay.dev', devToken, credentials);
}

Expand Down
3 changes: 1 addition & 2 deletions packages/web/src/__integration-tests__/sierraOrg.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ describe("SierraOrgClient", () => {
let api: EmeraldApi;

beforeAll(() => {
// a dev token with user id: bada55a1-0000-4000-a000-000000000000
api = EmeraldApi.devApi("emrld_fU88aIafXsCClerhyWtflBp1hH6h112ckzpSfP");
api = EmeraldApi.devApi();
});

test('getOrg', async () => {
Expand Down
3 changes: 1 addition & 2 deletions packages/web/src/__integration-tests__/sierraProject.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ describe("SierraProjectClient", () => {
let api: EmeraldApi;

beforeAll(() => {
// a dev token with user id: bada55a1-0000-4000-a000-000000000000
api = EmeraldApi.devApi("emrld_fU88aIafXsCClerhyWtflBp1hH6h112ckzpSfP");
api = EmeraldApi.devApi();
});

test('createProject permission denied for the user', async () => {
Expand Down
3 changes: 1 addition & 2 deletions packages/web/src/__integration-tests__/sierraStat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ describe("SierraStatClient", () => {
let api: EmeraldApi;

beforeAll(() => {
// a dev token with user id: bada55a1-0000-4000-a000-000000000000
api = EmeraldApi.devApi("emrld_fU88aIafXsCClerhyWtflBp1hH6h112ckzpSfP");
api = EmeraldApi.devApi();
});

test('getRequestCount', (done) => {
Expand Down
23 changes: 14 additions & 9 deletions packages/web/src/wrapped/AuthClient.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import {
AuthRequest, AuthResponse,
CredentialsClient,
ConvertAuth,
DeleteTokenRequest,
DeleteTokenResponse,
IssueTokenRequest,
IssuedTokenResponse,
ListTokensRequest,
ListTokensResponse,
RefreshRequest,
WhoIAmResponse,
publishToPromise,
readOnce, IssueTokenRequest, IssuedTokenResponse
WhoIAmResponse, publishToPromise, readOnce
} from "@emeraldpay/api";
import {callPromise, WebChannel} from "../channel";
import * as auth_rpc from '../generated/AuthServiceClientPb';
import {WebChannel, callPromise} from "../channel";
import {CredentialsContext} from "../credentials";
import * as auth_pb from "../generated/auth_pb";
import * as auth_rpc from '../generated/AuthServiceClientPb';
import {classFactory} from "./Factory";
import {CredentialsContext} from "../credentials";

export class AuthClient {
readonly client: auth_rpc.AuthClient;
Expand Down Expand Up @@ -46,6 +45,12 @@ export class AuthClient {
issueToken(req: IssueTokenRequest): Promise<IssuedTokenResponse> {
const request = this.convert.issueTokenRequest(req);
const call = callPromise(this.client.issueToken.bind(this.client), this.convert.issuedTokenResponse);
return publishToPromise(readOnce(this.channel, call, request, 1));
}

deleteToken(req: DeleteTokenRequest): Promise<DeleteTokenResponse> {
const request = this.convert.deleteTokenRequest(req)
const call = callPromise(this.client.deleteToken.bind(this.client), this.convert.deleteTokenResponse);
return publishToPromise(readOnce(this.channel, call, request, this.retries));
}

Expand Down
3 changes: 3 additions & 0 deletions packages/web/src/wrapped/Factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export const classFactory: MessageFactory = (id: string) => {
if (id == 'auth_pb.IssueTokenRequest') {
return new auth_pb.IssueTokenRequest();
}
if (id == 'auth_pb.DeleteTokenRequest') {
return new auth_pb.DeleteTokenRequest();
}
// Blockchain
if (id == "blockchain_pb.NativeCallRequest") {
return new blockchain_pb.NativeCallRequest();
Expand Down

0 comments on commit 89ea893

Please sign in to comment.