1068 lines · 36.9 KB · TypeScript
RawDownload
import {  AuthAccessTokenType,  AuthAccessWriteScope,  AuthAdministrativeScopes,  AuthStandardClientScopes,  type AuthAccessTokenResult,  type AuthBrowserSessionResult,  type AuthClientMetadata,  type AuthClientSession,  type AuthCreatePairingCredentialInput,  type AuthEnvironmentScope,  type AuthPairingLink,  type AuthPairingCredentialResult,  type AuthSessionId,  type AuthSessionState,  type ServerAuthDescriptor,  type ServerAuthSessionMethod,  type AuthWebSocketTicketResult,} from "@t3tools/contracts";import { encodeOAuthScope } from "@t3tools/shared/oauthScope";import * as Context from "effect/Context";import * as Crypto from "effect/Crypto";import * as DateTime from "effect/DateTime";import * as Duration from "effect/Duration";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import * as Schema from "effect/Schema";import * as HttpServerRequest from "effect/unstable/http/HttpServerRequest"; import * as EnvironmentAuthPolicy from "./EnvironmentAuthPolicy.ts";import * as PairingGrantStore from "./PairingGrantStore.ts";import * as ServerSecretStore from "./ServerSecretStore.ts";import * as SessionStore from "./SessionStore.ts";import { verifyRequestDpopProof } from "./dpop.ts";import { layerConfig as SqlitePersistenceLayer } from "../persistence/Layers/Sqlite.ts"; export const DEFAULT_SESSION_SUBJECT = "cli-issued-session";export const INTERNAL_ADMINISTRATIVE_BOOTSTRAP_SUBJECT = "administrative-bootstrap"; export interface IssuedPairingLink {  readonly id: string;  readonly credential: string;  readonly scopes: ReadonlyArray<AuthEnvironmentScope>;  readonly subject: string;  readonly label?: string;  readonly createdAt: DateTime.Utc;  readonly expiresAt: DateTime.Utc;} export interface IssuedBearerSession {  readonly sessionId: AuthSessionId;  readonly token: string;  readonly method: "bearer-access-token";  readonly scopes: ReadonlyArray<AuthEnvironmentScope>;  readonly subject: string;  readonly client: AuthClientMetadata;  readonly expiresAt: DateTime.Utc;} export interface AuthenticatedSession {  readonly sessionId: AuthSessionId;  readonly subject: string;  readonly method: ServerAuthSessionMethod;  readonly scopes: ReadonlyArray<AuthEnvironmentScope>;  readonly proofKeyThumbprint?: string;  readonly expiresAt?: DateTime.DateTime;} const serverAuthInternalErrorContext = {  cause: Schema.Defect(),}; export class ServerAuthBootstrapCredentialValidationError extends Schema.TaggedErrorClass<ServerAuthBootstrapCredentialValidationError>()(  "ServerAuthBootstrapCredentialValidationError",  {    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return "Failed to validate bootstrap credential.";  }} export class ServerAuthSessionCredentialValidationError extends Schema.TaggedErrorClass<ServerAuthSessionCredentialValidationError>()(  "ServerAuthSessionCredentialValidationError",  {    credentialKind: Schema.Literals(["session", "websocket-ticket"]),    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to validate ${this.credentialKind} credential.`;  }} export class ServerAuthAuthenticatedSessionIssueError extends Schema.TaggedErrorClass<ServerAuthAuthenticatedSessionIssueError>()(  "ServerAuthAuthenticatedSessionIssueError",  {    subject: Schema.String,    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to issue authenticated session for ${this.subject}.`;  }} export class ServerAuthAuthenticatedAccessTokenIssueError extends Schema.TaggedErrorClass<ServerAuthAuthenticatedAccessTokenIssueError>()(  "ServerAuthAuthenticatedAccessTokenIssueError",  {    subject: Schema.String,    scopes: Schema.Array(Schema.String),    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to issue authenticated access token for ${this.subject} with scopes [${this.scopes.join(", ")}].`;  }} export class ServerAuthPairingLinkCreationError extends Schema.TaggedErrorClass<ServerAuthPairingLinkCreationError>()(  "ServerAuthPairingLinkCreationError",  {    subject: Schema.String,    scopes: Schema.Array(Schema.String),    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to create pairing link for ${this.subject} with scopes [${this.scopes.join(", ")}].`;  }} export class ServerAuthPairingLinksListError extends Schema.TaggedErrorClass<ServerAuthPairingLinksListError>()(  "ServerAuthPairingLinksListError",  {    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return "Failed to list pairing links.";  }} export class ServerAuthPairingLinkRevocationError extends Schema.TaggedErrorClass<ServerAuthPairingLinkRevocationError>()(  "ServerAuthPairingLinkRevocationError",  {    pairingLinkId: Schema.String,    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to revoke pairing link ${this.pairingLinkId}.`;  }} export class ServerAuthSessionTokenIssueError extends Schema.TaggedErrorClass<ServerAuthSessionTokenIssueError>()(  "ServerAuthSessionTokenIssueError",  {    subject: Schema.String,    scopes: Schema.Array(Schema.String),    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to issue session token for ${this.subject} with scopes [${this.scopes.join(", ")}].`;  }} export class ServerAuthSessionsListError extends Schema.TaggedErrorClass<ServerAuthSessionsListError>()(  "ServerAuthSessionsListError",  {    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return "Failed to list sessions.";  }} export class ServerAuthSessionRevocationError extends Schema.TaggedErrorClass<ServerAuthSessionRevocationError>()(  "ServerAuthSessionRevocationError",  {    sessionId: Schema.String,    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to revoke session ${this.sessionId}.`;  }} export class ServerAuthOtherSessionsRevocationError extends Schema.TaggedErrorClass<ServerAuthOtherSessionsRevocationError>()(  "ServerAuthOtherSessionsRevocationError",  {    excludedSessionId: Schema.String,    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to revoke sessions other than ${this.excludedSessionId}.`;  }} export class ServerAuthWebSocketTokenIssueError extends Schema.TaggedErrorClass<ServerAuthWebSocketTokenIssueError>()(  "ServerAuthWebSocketTokenIssueError",  {    sessionId: Schema.String,    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to issue websocket token for session ${this.sessionId}.`;  }} export class ServerAuthDpopReplayStateRecordError extends Schema.TaggedErrorClass<ServerAuthDpopReplayStateRecordError>()(  "ServerAuthDpopReplayStateRecordError",  {    proofKeyThumbprint: Schema.String,    proofId: Schema.String,    replayKey: Schema.String,    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to record replay state for DPoP proof ${this.proofId} (${this.proofKeyThumbprint}).`;  }} export class ServerAuthDpopReplayKeyCalculationError extends Schema.TaggedErrorClass<ServerAuthDpopReplayKeyCalculationError>()(  "ServerAuthDpopReplayKeyCalculationError",  {    proofKeyThumbprint: Schema.String,    proofId: Schema.String,    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return `Failed to calculate replay key for DPoP proof ${this.proofId} (${this.proofKeyThumbprint}).`;  }} export class ServerAuthLinkedCloudAccountVerificationError extends Schema.TaggedErrorClass<ServerAuthLinkedCloudAccountVerificationError>()(  "ServerAuthLinkedCloudAccountVerificationError",  {    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return "Could not verify the linked cloud account.";  }} export class ServerAuthLinkedCloudAccountReadError extends Schema.TaggedErrorClass<ServerAuthLinkedCloudAccountReadError>()(  "ServerAuthLinkedCloudAccountReadError",  {    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return "Could not read the linked cloud account.";  }} export class ServerAuthLinkedCloudAccountMissingError extends Schema.TaggedErrorClass<ServerAuthLinkedCloudAccountMissingError>()(  "ServerAuthLinkedCloudAccountMissingError",  {},) {  override get message(): string {    return "Cloud linked user is not installed for this environment.";  }} export class ServerAuthCloudLinkJwtSigningError extends Schema.TaggedErrorClass<ServerAuthCloudLinkJwtSigningError>()(  "ServerAuthCloudLinkJwtSigningError",  {    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return "Failed to sign cloud link JWT.";  }} export class ServerAuthCloudMintPublicKeyMissingError extends Schema.TaggedErrorClass<ServerAuthCloudMintPublicKeyMissingError>()(  "ServerAuthCloudMintPublicKeyMissingError",  {},) {  override get message(): string {    return "Cloud mint public key is not installed for this environment.";  }} export class ServerAuthCloudRelayIssuerMissingError extends Schema.TaggedErrorClass<ServerAuthCloudRelayIssuerMissingError>()(  "ServerAuthCloudRelayIssuerMissingError",  {},) {  override get message(): string {    return "Cloud relay issuer is not installed for this environment.";  }} export class ServerAuthCloudHealthJwtSigningError extends Schema.TaggedErrorClass<ServerAuthCloudHealthJwtSigningError>()(  "ServerAuthCloudHealthJwtSigningError",  {    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return "Failed to sign cloud health JWT.";  }} export class ServerAuthCloudMintJwtSigningError extends Schema.TaggedErrorClass<ServerAuthCloudMintJwtSigningError>()(  "ServerAuthCloudMintJwtSigningError",  {    ...serverAuthInternalErrorContext,  },) {  override get message(): string {    return "Failed to sign cloud mint JWT.";  }} export const ServerAuthInternalError = Schema.Union([  ServerAuthBootstrapCredentialValidationError,  ServerAuthSessionCredentialValidationError,  ServerAuthAuthenticatedSessionIssueError,  ServerAuthAuthenticatedAccessTokenIssueError,  ServerAuthPairingLinkCreationError,  ServerAuthPairingLinksListError,  ServerAuthPairingLinkRevocationError,  ServerAuthSessionTokenIssueError,  ServerAuthSessionsListError,  ServerAuthSessionRevocationError,  ServerAuthOtherSessionsRevocationError,  ServerAuthWebSocketTokenIssueError,  ServerAuthDpopReplayStateRecordError,  ServerAuthDpopReplayKeyCalculationError,  ServerAuthLinkedCloudAccountVerificationError,  ServerAuthLinkedCloudAccountReadError,  ServerAuthLinkedCloudAccountMissingError,  ServerAuthCloudLinkJwtSigningError,  ServerAuthCloudMintPublicKeyMissingError,  ServerAuthCloudRelayIssuerMissingError,  ServerAuthCloudHealthJwtSigningError,  ServerAuthCloudMintJwtSigningError,]);export type ServerAuthInternalError = typeof ServerAuthInternalError.Type;export const isServerAuthInternalError = Schema.is(ServerAuthInternalError); export class ServerAuthMissingCredentialError extends Schema.TaggedErrorClass<ServerAuthMissingCredentialError>()(  "ServerAuthMissingCredentialError",  {},) {  override get message(): string {    return "Server authentication credential is missing.";  }} export class ServerAuthInvalidCredentialError extends Schema.TaggedErrorClass<ServerAuthInvalidCredentialError>()(  "ServerAuthInvalidCredentialError",  {    diagnostic: Schema.optional(Schema.String),    cause: Schema.optional(Schema.Defect()),  },) {  override get message(): string {    return "Server authentication credential is invalid.";  }} export const ServerAuthCredentialError = Schema.Union([  ServerAuthMissingCredentialError,  ServerAuthInvalidCredentialError,]);export type ServerAuthCredentialError = typeof ServerAuthCredentialError.Type; export class ServerAuthInvalidScopeError extends Schema.TaggedErrorClass<ServerAuthInvalidScopeError>()(  "ServerAuthInvalidScopeError",  {},) {  override get message(): string {    return "The requested authentication scope is invalid.";  }} export class ServerAuthScopeNotGrantedError extends Schema.TaggedErrorClass<ServerAuthScopeNotGrantedError>()(  "ServerAuthScopeNotGrantedError",  {    requestedScopes: Schema.Array(Schema.String),    grantedScopes: Schema.Array(Schema.String),  },) {  override get message(): string {    return `Requested scopes [${this.requestedScopes.join(", ")}] exceed granted scopes [${this.grantedScopes.join(", ")}].`;  }} export const ServerAuthInvalidRequestError = Schema.Union([  ServerAuthInvalidScopeError,  ServerAuthScopeNotGrantedError,]);export type ServerAuthInvalidRequestError = typeof ServerAuthInvalidRequestError.Type; export class ServerAuthForbiddenOperationError extends Schema.TaggedErrorClass<ServerAuthForbiddenOperationError>()(  "ServerAuthForbiddenOperationError",  {    currentSessionId: Schema.String,    targetSessionId: Schema.String,  },) {  override get message(): string {    return `Authentication session ${this.currentSessionId} cannot revoke itself.`;  }} export type ServerAuthAuthenticationInternalError =  | ServerAuthSessionCredentialValidationError  | ServerAuthDpopReplayStateRecordError  | ServerAuthDpopReplayKeyCalculationError; export type ServerAuthAuthenticationError =  | ServerAuthCredentialError  | ServerAuthAuthenticationInternalError; export class EnvironmentAuth extends Context.Service<  EnvironmentAuth,  {    readonly getDescriptor: () => Effect.Effect<ServerAuthDescriptor>;    readonly getSessionState: (      request: HttpServerRequest.HttpServerRequest,    ) => Effect.Effect<AuthSessionState, ServerAuthAuthenticationInternalError>;    readonly createBrowserSession: (      credential: string,      requestMetadata: AuthClientMetadata,    ) => Effect.Effect<      {        readonly response: AuthBrowserSessionResult;        readonly sessionToken: string;      },      | ServerAuthInvalidCredentialError      | ServerAuthBootstrapCredentialValidationError      | ServerAuthAuthenticatedSessionIssueError    >;    readonly exchangeBootstrapCredentialForAccessToken: (      credential: string,      requestedScopes: ReadonlyArray<AuthEnvironmentScope> | undefined,      requestMetadata: AuthClientMetadata,      input?: {        readonly proofKeyThumbprint?: string;      },    ) => Effect.Effect<      AuthAccessTokenResult,      | ServerAuthInvalidCredentialError      | ServerAuthScopeNotGrantedError      | ServerAuthBootstrapCredentialValidationError      | ServerAuthAuthenticatedAccessTokenIssueError    >;    readonly createPairingLink: (input?: {      readonly ttl?: Duration.Duration;      readonly label?: string;      readonly scopes?: ReadonlyArray<AuthEnvironmentScope>;      readonly subject?: string;      readonly proofKeyThumbprint?: string;    }) => Effect.Effect<IssuedPairingLink, ServerAuthPairingLinkCreationError>;    readonly issuePairingCredential: (      input?: AuthCreatePairingCredentialInput,    ) => Effect.Effect<AuthPairingCredentialResult, ServerAuthPairingLinkCreationError>;    readonly issueStartupPairingCredential: () => Effect.Effect<      AuthPairingCredentialResult,      ServerAuthPairingLinkCreationError    >;    readonly listPairingLinks: (input?: {      readonly excludeSubjects?: ReadonlyArray<string>;    }) => Effect.Effect<ReadonlyArray<AuthPairingLink>, ServerAuthPairingLinksListError>;    readonly revokePairingLink: (      id: string,    ) => Effect.Effect<boolean, ServerAuthPairingLinkRevocationError>;    readonly issueSession: (input?: {      readonly ttl?: Duration.Duration;      readonly subject?: string;      readonly scopes?: ReadonlyArray<AuthEnvironmentScope>;      readonly label?: string;    }) => Effect.Effect<IssuedBearerSession, ServerAuthSessionTokenIssueError>;    readonly listSessions: () => Effect.Effect<      ReadonlyArray<AuthClientSession>,      ServerAuthSessionsListError    >;    readonly revokeSession: (      sessionId: AuthSessionId,    ) => Effect.Effect<boolean, ServerAuthSessionRevocationError>;    readonly revokeOtherSessionsExcept: (      sessionId: AuthSessionId,    ) => Effect.Effect<number, ServerAuthOtherSessionsRevocationError>;    readonly listClientSessions: (      currentSessionId: AuthSessionId,    ) => Effect.Effect<ReadonlyArray<AuthClientSession>, ServerAuthSessionsListError>;

Lines 1–500 of 1068.