178 lines · 6.6 KB · TypeScript
RawDownload
import type { AuthClientSession, AuthPairingLink } from "@t3tools/contracts";import { DateTime, Effect, Layer } from "effect"; import { BootstrapCredentialServiceLive } from "./BootstrapCredentialService.ts";import { ServerSecretStoreLive } from "./ServerSecretStore.ts";import { SessionCredentialServiceLive } from "./SessionCredentialService.ts";import { BootstrapCredentialService } from "../Services/BootstrapCredentialService.ts";import { SessionCredentialService } from "../Services/SessionCredentialService.ts";import { layerConfig as SqlitePersistenceLayerLive } from "../../persistence/Layers/Sqlite.ts";import {  AuthControlPlane,  AuthControlPlaneError,  DEFAULT_SESSION_SUBJECT,} from "../Services/AuthControlPlane.ts";import type {  AuthControlPlaneShape,  IssuedBearerSession,  IssuedPairingLink,} from "../Services/AuthControlPlane.ts"; const bySessionPriority = (left: AuthClientSession, right: AuthClientSession) => {  if (left.role !== right.role) {    return left.role === "owner" ? -1 : 1;  }  if (left.connected !== right.connected) {    return left.connected ? -1 : 1;  }  return right.issuedAt.epochMilliseconds - left.issuedAt.epochMilliseconds;}; const toAuthControlPlaneError =  (message: string) =>  (cause: unknown): AuthControlPlaneError =>    new AuthControlPlaneError({      message,      cause,    }); export const makeAuthControlPlane = Effect.gen(function* () {  const bootstrapCredentials = yield* BootstrapCredentialService;  const sessions = yield* SessionCredentialService;   const createPairingLink: AuthControlPlaneShape["createPairingLink"] = (input) =>    Effect.gen(function* () {      const createdAt = yield* DateTime.now;      const issued = yield* bootstrapCredentials.issueOneTimeToken({        role: input?.role ?? "client",        subject: input?.subject ?? "one-time-token",        ...(input?.ttl ? { ttl: input.ttl } : {}),        ...(input?.label ? { label: input.label } : {}),      });      return {        id: issued.id,        credential: issued.credential,        role: input?.role ?? "client",        subject: input?.subject ?? "one-time-token",        ...(issued.label ? { label: issued.label } : {}),        createdAt: DateTime.toUtc(createdAt),        expiresAt: DateTime.toUtc(issued.expiresAt),      } satisfies IssuedPairingLink;    }).pipe(Effect.mapError(toAuthControlPlaneError("Failed to create pairing link.")));   const listPairingLinks: AuthControlPlaneShape["listPairingLinks"] = (input) =>    bootstrapCredentials.listActive().pipe(      Effect.map((pairingLinks) =>        pairingLinks          .filter((pairingLink) => (input?.role ? pairingLink.role === input.role : true))          .filter((pairingLink) => !input?.excludeSubjects?.includes(pairingLink.subject))          .map((pairingLink) =>            pairingLink.label              ? ({                  id: pairingLink.id,                  credential: pairingLink.credential,                  role: pairingLink.role,                  subject: pairingLink.subject,                  label: pairingLink.label,                  createdAt: pairingLink.createdAt,                  expiresAt: pairingLink.expiresAt,                } satisfies AuthPairingLink)              : ({                  id: pairingLink.id,                  credential: pairingLink.credential,                  role: pairingLink.role,                  subject: pairingLink.subject,                  createdAt: pairingLink.createdAt,                  expiresAt: pairingLink.expiresAt,                } satisfies AuthPairingLink),          )          .toSorted(            (left, right) => right.createdAt.epochMilliseconds - left.createdAt.epochMilliseconds,          ),      ),      Effect.mapError(toAuthControlPlaneError("Failed to list pairing links.")),    );   const revokePairingLink: AuthControlPlaneShape["revokePairingLink"] = (id) =>    bootstrapCredentials      .revoke(id)      .pipe(Effect.mapError(toAuthControlPlaneError("Failed to revoke pairing link.")));   const issueSession: AuthControlPlaneShape["issueSession"] = (input) =>    sessions      .issue({        subject: input?.subject ?? DEFAULT_SESSION_SUBJECT,        method: "bearer-session-token",        role: input?.role ?? "owner",        client: {          ...(input?.label ? { label: input.label } : {}),          deviceType: "bot",        },        ...(input?.ttl ? { ttl: input.ttl } : {}),      })      .pipe(        Effect.flatMap((issued) => {          if (issued.method !== "bearer-session-token") {            return Effect.fail(              new AuthControlPlaneError({                message: "CLI session issuance produced an unexpected session method.",              }),            );          }           return Effect.succeed({            sessionId: issued.sessionId,            token: issued.token,            method: "bearer-session-token" as const,            role: issued.role,            subject: input?.subject ?? DEFAULT_SESSION_SUBJECT,            client: issued.client,            expiresAt: DateTime.toUtc(issued.expiresAt),          } satisfies IssuedBearerSession);        }),        Effect.mapError(toAuthControlPlaneError("Failed to issue session token.")),      );   const listSessions: AuthControlPlaneShape["listSessions"] = () =>    sessions.listActive().pipe(      Effect.map((activeSessions) => activeSessions.toSorted(bySessionPriority)),      Effect.mapError(toAuthControlPlaneError("Failed to list sessions.")),    );   const revokeSession: AuthControlPlaneShape["revokeSession"] = (sessionId) =>    sessions      .revoke(sessionId)      .pipe(Effect.mapError(toAuthControlPlaneError("Failed to revoke session.")));   const revokeOtherSessionsExcept: AuthControlPlaneShape["revokeOtherSessionsExcept"] = (    sessionId,  ) =>    sessions      .revokeAllExcept(sessionId)      .pipe(Effect.mapError(toAuthControlPlaneError("Failed to revoke other sessions.")));   return {    createPairingLink,    listPairingLinks,    revokePairingLink,    issueSession,    listSessions,    revokeSession,    revokeOtherSessionsExcept,  } satisfies AuthControlPlaneShape;}); export const AuthCoreLive = Layer.mergeAll(  BootstrapCredentialServiceLive,  SessionCredentialServiceLive,); export const AuthStorageLive = Layer.mergeAll(ServerSecretStoreLive, SqlitePersistenceLayerLive); export const AuthRuntimeLive = AuthCoreLive.pipe(Layer.provideMerge(AuthStorageLive)); export const AuthControlPlaneLive = Layer.effect(AuthControlPlane, makeAuthControlPlane); export const AuthControlPlaneRuntimeLive = AuthControlPlaneLive.pipe(  Layer.provideMerge(AuthRuntimeLive),);