From 60842c049082fcc5a9dc7efc86cd59db5697425f Mon Sep 17 00:00:00 2001 From: Jared Snider Date: Wed, 28 May 2025 18:30:20 -0400 Subject: [PATCH] PM-20532 - WIP on send token stuff --- .../abstractions/send-token.service.ts | 15 +++++- .../services/send-token-api.service.ts | 3 ++ .../services/send-token.service.ts | 48 ++++++++++++++----- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/libs/common/src/auth/send-access/abstractions/send-token.service.ts b/libs/common/src/auth/send-access/abstractions/send-token.service.ts index ba6078534fe..d74a39b7a22 100644 --- a/libs/common/src/auth/send-access/abstractions/send-token.service.ts +++ b/libs/common/src/auth/send-access/abstractions/send-token.service.ts @@ -1,6 +1,6 @@ import { SendHashedPassword } from "../../../key-management/sends/send-password.service"; import { SendAccessToken } from "../models/send-access-token"; -import { SendTokenRetrievalError } from "../services/send-token.service"; +import { TryGetSendAccessTokenError } from "../services/send-token.service"; export type SendAccessCredentialsType = "password" | "email-otp"; @@ -31,9 +31,20 @@ export abstract class SendTokenService { // TODO: define return types. // TODO: consider converting to observable. + /** + * Attempts to retrieve a SendAccessToken for the given sendId. + * If the access token is found in session storage and is not expired, then it returns the token. + * If the access token is expired, then it returns a SendTokenRetrievalError expired error. + * If an access token is not found in storage, then it attempts to retrieve it from the server (will succeed for sends that don't require any credentials to view). + * If the access token is successfully retrieved from the server, then it stores the token in session storage and returns it. + * If an access token cannot be granted b/c the send requires credentials, then it returns a SendTokenRetrievalError indicating which credentials are required. + * Any submissions of credentials will be handled by the getSendAccessTokenWithCredentials method. + * @param sendId The ID of the send to retrieve the access token for. + * @returns A promise that resolves to a SendAccessToken if found and valid, or a SendTokenRetrievalError if not. + */ abstract tryGetSendAccessToken: ( sendId: string, - ) => Promise; + ) => Promise; abstract getSendAccessTokenWithCredentials: ( sendId: string, diff --git a/libs/common/src/auth/send-access/services/send-token-api.service.ts b/libs/common/src/auth/send-access/services/send-token-api.service.ts index 57276ef90a2..89d31d0a50a 100644 --- a/libs/common/src/auth/send-access/services/send-token-api.service.ts +++ b/libs/common/src/auth/send-access/services/send-token-api.service.ts @@ -8,6 +8,9 @@ import { SendAccessToken } from "../models/send-access-token"; export type SendTokenApiRetrievalError = "password-required" | "otp-required" | "unknown-error"; +// Consider adding types for submission with credentials: +// | "invalid-password" + export class SendTokenApiService implements SendTokenApiServiceAbstraction { constructor( private environmentService: EnvironmentService, diff --git a/libs/common/src/auth/send-access/services/send-token.service.ts b/libs/common/src/auth/send-access/services/send-token.service.ts index 297fc1bb0c6..c4d594ccf81 100644 --- a/libs/common/src/auth/send-access/services/send-token.service.ts +++ b/libs/common/src/auth/send-access/services/send-token.service.ts @@ -33,7 +33,9 @@ export const SEND_ACCESS_TOKEN_DICT = KeyDefinition.record; export class SendTokenService implements SendTokenServiceAbstraction { private sendAccessTokenDictGlobalState: GlobalState> | undefined; @@ -50,9 +52,13 @@ export class SendTokenService implements SendTokenServiceAbstraction { this.sendAccessTokenDictGlobalState = this.globalStateProvider.get(SEND_ACCESS_TOKEN_DICT); } - async tryGetSendAccessToken(sendId: string): Promise { - // TODO: check in storage for the access token and if it is expired. + async tryGetSendAccessToken( + sendId: string, + ): Promise { + // Validate the sendId is a non-empty string. + this.validateSendId(sendId); + // Check in storage for the access token for the given sendId. const sendAccessTokenFromStorage = await this.getSendAccessTokenFromStorage(sendId); if (sendAccessTokenFromStorage != null) { @@ -60,7 +66,7 @@ export class SendTokenService implements SendTokenServiceAbstraction { if (sendAccessTokenFromStorage.isExpired()) { return "expired"; } else { - // If it is not expired, we return + // If it is not expired, we return it return sendAccessTokenFromStorage; } } @@ -68,7 +74,6 @@ export class SendTokenService implements SendTokenServiceAbstraction { // If we don't have a token in storage, we can try to request a new token from the server. const request = new SendAccessTokenRequest(sendId); - // try { const result = await this.sendTokenApiService.requestSendAccessToken(request); if (result instanceof SendAccessToken) { @@ -82,13 +87,28 @@ export class SendTokenService implements SendTokenServiceAbstraction { async getSendAccessTokenWithCredentials( sendId: string, - sendCredentials: SendAccessCredentials | undefined, + sendCredentials: SendAccessCredentials, ): Promise { - // TODO: check in storage for the access token and if it is expired. - // If it is expired, we will need to request a new token from the server. - // If it is not expired, we will return the token from storage. - // const request = new SendAccessTokenRequest(sendId, sendCredentials); - // const result = await this.sendTokenApiService.requestSendAccessToken(request); + // Validate the sendId + this.validateSendId(sendId); + + // Validate the credentials + if (sendCredentials == null) { + throw new Error("sendCredentials must be provided."); + } + + // Request the access token from the server using the provided credentials. + const request = new SendAccessTokenRequest(sendId, sendCredentials); + const result = await this.sendTokenApiService.requestSendAccessToken(request); + + if (result instanceof SendAccessToken) { + // If we get a token back, we need to store it in the global state. + await this.setSendAccessTokenInStorage(sendId, result); + return; + } + + // Handle errors from the API service. + // return result; } async hashPassword(password: string, keyMaterialUrlB64: string): Promise { @@ -118,4 +138,10 @@ export class SendTokenService implements SendTokenServiceAbstraction { }); } } + + private validateSendId(sendId: string): void { + if (sendId == null || sendId.trim() === "") { + throw new Error("sendId must be provided."); + } + } }