1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-09 21:20:27 +00:00

design tweaks

This commit is contained in:
✨ Audrey ✨
2025-07-09 17:52:00 -04:00
parent c75a13d925
commit 9186d9a4ed
8 changed files with 108 additions and 20 deletions

View File

@@ -9,7 +9,7 @@ Anyone can access a public send. The token endpoint automatically issues a token
```mermaid
sequenceDiagram
participant Visitor
participant TryAccess as try-access.component
participant TryAccess as try-send-access.guard
participant SendToken as send-token API
participant ViewContent as view-content.component
participant SendAccess as send-access API
@@ -34,7 +34,7 @@ Password protected sends redirect to a password challenge prompt.
```mermaid
sequenceDiagram
participant Visitor
participant TryAccess as try-access.component
participant TryAccess as try-send-access.guard
participant PasswordAuth as password-authentication.component
participant SendToken as send-token API
participant ViewContent as view-content.component
@@ -68,7 +68,7 @@ Visiting the view page without a token redirects to a try-access flow, above.
sequenceDiagram
participant Visitor
participant ViewContent as view-content.component
participant TryAccess as try-access.component
participant TryAccess as try-send-access.guard
Visitor->>ViewContent: Navigate to send URL (with id and key)
ViewContent->>TryAccess: Redirect to try-access (with id and key)

View File

@@ -0,0 +1,34 @@
# Documentation prompts
The following prompts were used with Claude 4 - Sonnet to write send documentation.
## Authentication Flow Diagrams
Turn a list of steps into a sequence diagram.
```
Create a mermaid sequence diagram for the Bitwarden Send protocol authentication flow. Use these components:
**Components:**
- `try-access.component` - Entry point that attempts to access a send
- `password-authentication.component` - Handles password-based authentication
- `view-content.component` - Displays the send content
- `send-token API` - Server endpoint that issues security tokens
**Flow Steps:**
1. [Visitor navigates to try-access.]
2. [try-access requests anonymous access from the send-token API]
3. [send-token service replies with 200 and a token.]
4. [try-access redirects to view-content with the token.]
5. [view-content requests the send content from the send-access API with the token.]
6. [the send-access API returns the send content]
[ADD MORE STEPS AS NEEDED]
**Requirements:**
- Use clear, descriptive labels for each interaction
- Include HTTP status codes where relevant
- Show conditional logic with alt/opt blocks for decision points
- Use proper mermaid sequence diagram syntax
- Generate ONLY the mermaid code block, no additional explanation
- Follow the exact component names provided above
```

View File

@@ -0,0 +1,32 @@
import { KeyDefinition, SEND_ACCESS_AUTH_MEMORY } from "@bitwarden/common/platform/state";
import { SendAccessResponse } from "@bitwarden/common/tools/send/models/response/send-access.response";
export type SendContext = {
id: string;
key: string;
};
export function isSendContext(value: unknown): value is SendContext {
return !!value && typeof value === "object" && "id" in value && "key" in value;
}
export const SEND_CONTEXT_KEY = new KeyDefinition<SendContext | null>(
SEND_ACCESS_AUTH_MEMORY,
"sendContext",
{
deserializer: (data) => data,
},
);
/** When send authentication succeeds, this stores the result so that
* multiple access attempts don't accrue due to the send workflow.
*/
// FIXME: replace this with the send authentication token once it's
// available
export const SEND_RESPONSE_KEY = new KeyDefinition<SendAccessResponse | null>(
SEND_ACCESS_AUTH_MEMORY,
"sendResponse",
{
deserializer: (data) => (data ? new SendAccessResponse(data) : null),
},
);

View File

@@ -9,13 +9,13 @@ import { SystemServiceProvider } from "@bitwarden/common/tools/providers.js";
import { SendAccessRequest } from "@bitwarden/common/tools/send/models/request/send-access.request";
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
import { TOKEN_KEY, SEND_KEY_KEY } from "./send-access-memory";
import { SEND_RESPONSE_KEY, SEND_CONTEXT_KEY } from "./send-access-memory";
import { isErrorResponse } from "./util";
const TEN_SECONDS = 10_000;
@Injectable({ providedIn: "root" })
export class SendAccessAuthenticationService {
export class SendAccessService {
private readonly logger: SemanticLogger;
constructor(
@@ -31,6 +31,8 @@ export class SendAccessAuthenticationService {
}
redirect$(sendId: string) {
// FIXME: when the send authentication APIs become available, this method
// should delegate to the API
const response$ = from(this.api.postSendAccess(sendId, new SendAccessRequest()));
const redirect$ = response$.pipe(
@@ -84,16 +86,12 @@ export class SendAccessAuthenticationService {
return url;
}
async setToken(token: string) {
return this.state.getGlobal(TOKEN_KEY).update(() => token);
}
async setKey(key: string) {
return this.state.getGlobal(SEND_KEY_KEY).update(() => key);
async setContext(sendId: string, key: string) {
return this.state.getGlobal(SEND_CONTEXT_KEY).update(() => ({ id: sendId, key }));
}
async clear(): Promise<void> {
await this.state.getGlobal(TOKEN_KEY).update(() => null);
await this.state.getGlobal(SEND_KEY_KEY).update(() => null);
await this.state.getGlobal(SEND_RESPONSE_KEY).update(() => null);
await this.state.getGlobal(SEND_CONTEXT_KEY).update(() => null);
}
}

View File

@@ -2,18 +2,37 @@ import { inject } from "@angular/core";
import { ActivatedRouteSnapshot, CanActivateFn, RouterStateSnapshot } from "@angular/router";
import { from, ignoreElements, concat } from "rxjs";
import { SendAccessAuthenticationService } from "./send-access-authentication.service";
import { SystemServiceProvider } from "@bitwarden/common/tools/providers";
import { SYSTEM_SERVICE_PROVIDER } from "@bitwarden/generator-components";
import { SendAccessService } from "./send-access.service";
export const trySendAccess: CanActivateFn = (
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
_state: RouterStateSnapshot,
) => {
const sendAccess = inject(SendAccessAuthenticationService);
const sendAccess = inject(SendAccessService);
const system = inject<SystemServiceProvider>(SYSTEM_SERVICE_PROVIDER);
const logger = system.log({ function: "trySendAccess" });
const { sendId, key } = route.params;
if (!sendId) {
logger.warn("sendId missing from the route parameters; redirecting to 404");
}
if (typeof sendId !== "string") {
logger.panic({ expected: "string", actual: typeof sendId }, "sendId has invalid type");
}
const setKey$ = from(sendAccess.setKey(key)).pipe(ignoreElements());
if (!key) {
logger.panic("key missing from the route parameters");
}
if (typeof key !== "string") {
logger.panic({ expected: "string", actual: typeof key }, "key has invalid type");
}
const contextUpdated$ = from(sendAccess.setContext(sendId, key)).pipe(ignoreElements());
const redirect$ = sendAccess.redirect$(sendId);
return concat(setKey$, redirect$);
// ensure the key has loaded before redirecting
return concat(contextUpdated$, redirect$);
};

View File

@@ -40,7 +40,12 @@ export const RANDOMIZER = new SafeInjectionToken<Randomizer>("Randomizer");
const GENERATOR_SERVICE_PROVIDER = new SafeInjectionToken<providers.CredentialGeneratorProviders>(
"CredentialGeneratorProviders",
);
const SYSTEM_SERVICE_PROVIDER = new SafeInjectionToken<SystemServiceProvider>("SystemServices");
// FIXME: relocate the system service provider to a more general module once
// NX migration is complete.
export const SYSTEM_SERVICE_PROVIDER = new SafeInjectionToken<SystemServiceProvider>(
"SystemServices",
);
/** Shared module containing generator component dependencies */
@NgModule({

View File

@@ -2,4 +2,4 @@ export { CredentialGeneratorHistoryComponent } from "./credential-generator-hist
export { CredentialGeneratorHistoryDialogComponent } from "./credential-generator-history-dialog.component";
export { EmptyCredentialHistoryComponent } from "./empty-credential-history.component";
export { GeneratorModule } from "./generator.module";
export { GeneratorServicesModule } from "./generator-services.module";
export { GeneratorServicesModule, SYSTEM_SERVICE_PROVIDER } from "./generator-services.module";