1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-08 04:33:38 +00:00

PM-20532 - WIP on Send Token services.

This commit is contained in:
Jared Snider
2025-05-20 17:11:00 -04:00
parent 10f166269f
commit e4299dac26
5 changed files with 65 additions and 6 deletions

View File

@@ -6,5 +6,12 @@ import { SendAccessTokenRequest } from "../../models/request/identity-token/send
*/
export abstract class SendTokenApiService {
// TODO: add return type for requestSendAccessToken and error scenarios
// Returns a valid send access token or several error types (use discriminated union):
// RequiresPassword
// RequiresEmailOtp
// InvalidCredentials
// ExpiredRequiredPassword // these will live at higher level in SendTokenService
// ExpiredRequiredEmailOtp
abstract requestSendAccessToken: (request: SendAccessTokenRequest) => Promise<unknown>;
}

View File

@@ -1,3 +1,12 @@
export interface SendPasswordCredentials {
password: string;
}
export interface SendEmailOtpCredentials {
email: string;
otp: string;
}
export type SendAccessCredentials = SendPasswordCredentials | SendEmailOtpCredentials;
export abstract class SendTokenService {
// TODO: talk with Tools about what expected behavior is for expired access tokens.
// Do we implement any local TTL or do we just rely on the server to return a 401 and then we handle that in the api service?
@@ -6,9 +15,22 @@ export abstract class SendTokenService {
// All SendAccessTokens are scoped to a specific send id so all getting and setting should accept a send id.
// TODO: should this abstraction have separate methods for requesting an access token from the server
// and for getting the access token from storage? Or should it just be one method that does both?
// and for getting the access token from storage?
// One method that does both is ideal.
// We will need to extend inputs to include the send id and the credentials.
// We will also need to store the send access token with it's expires_in value so we know if it's expired
// so that we don't hand out an expired token to make a request.
// Get the access token for a specific send id.
abstract getSendAccessToken: (sendId: string) => Promise<string | null>;
abstract setSendAccessToken: (sendId: string, token: string) => Promise<void>;
// Returned error types should be discriminated union with a type that can be conditioned off for logic.
// Attempts to get a send access token for a specific send id.
// If the token is not found or is expired, it will request a new token from the server.
// As send access tokens can be protected by different credentials, the credentials must be passed in for those sends.
abstract getSendAccessToken: (
sendId: string,
sendCredentials?: SendAccessCredentials,
) => Promise<void>;
// Private internal logic for getting the access token.
// abstract setSendAccessToken: (sendId: string, token: string) => Promise<void>;
}

View File

@@ -11,7 +11,6 @@ export class SendTokenApiService implements SendTokenApiServiceAbstraction {
private apiService: ApiService,
) {}
// TODO: talk with Justin about needing to use httpOperations or not.
async requestSendAccessToken(request: SendAccessTokenRequest): Promise<void> {
const payload = request.toIdentityTokenPayload();
@@ -34,6 +33,6 @@ export class SendTokenApiService implements SendTokenApiServiceAbstraction {
await this.apiService.fetch(req);
// TODO: add processing.
// TODO: add result processing
}
}

View File

@@ -0,0 +1,29 @@
import { GlobalStateProvider, KeyDefinition, SEND_AUTH_DISK } from "../../../platform/state";
import {
SendAccessCredentials,
SendTokenService as SendTokenServiceAbstraction,
} from "../abstractions/send-token.service";
import { SendTokenApiService } from "./send-token-api.service";
// Will need to map sendId to access token
// TODO: will need to build a better type for access token where it contains
// the expires in and the token itself.
export const SEND_ACCESS_TOKEN_DICT = KeyDefinition.record<string, string>(
SEND_AUTH_DISK,
"accessTokenDict",
{
deserializer: (accessTokenDict) => accessTokenDict,
},
);
export class SendTokenService implements SendTokenServiceAbstraction {
constructor(
private globalStateProvider: GlobalStateProvider,
private sendTokenApiService: SendTokenApiService,
) {}
async getSendAccessToken(sendId: string, sendCredentials?: SendAccessCredentials): Promise<void> {
// TODO: first
}
}

View File

@@ -76,6 +76,8 @@ export const TOKEN_DISK = new StateDefinition("token", "disk");
export const TOKEN_DISK_LOCAL = new StateDefinition("tokenDiskLocal", "disk", {
web: "disk-local",
});
export const SEND_AUTH_DISK = new StateDefinition("sendAuth", "disk");
export const TOKEN_MEMORY = new StateDefinition("token", "memory");
export const TWO_FACTOR_MEMORY = new StateDefinition("twoFactor", "memory");
export const USER_DECRYPTION_OPTIONS_DISK = new StateDefinition("userDecryptionOptions", "disk");