mirror of
https://github.com/bitwarden/browser
synced 2026-02-09 21:20:27 +00:00
design tweaks
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -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),
|
||||
},
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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$);
|
||||
};
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user