import * as NodeServices from "@effect/platform-node/NodeServices";import { expect, it } from "@effect/vitest";import { Duration, Effect, Layer } from "effect";import { TestClock } from "effect/testing"; import type { ServerConfigShape } from "../../config.ts";import { ServerConfig } from "../../config.ts";import { SqlitePersistenceMemory } from "../../persistence/Layers/Sqlite.ts";import { BootstrapCredentialService } from "../Services/BootstrapCredentialService.ts";import { BootstrapCredentialServiceLive } from "./BootstrapCredentialService.ts"; const makeServerConfigLayer = ( overrides?: Partial<Pick<ServerConfigShape, "desktopBootstrapToken">>,) => Layer.effect( ServerConfig, Effect.gen(function* () { const config = yield* ServerConfig; return { ...config, ...overrides, } satisfies ServerConfigShape; }), ).pipe( Layer.provide(ServerConfig.layerTest(process.cwd(), { prefix: "t3-auth-bootstrap-test-" })), ); const makeBootstrapCredentialLayer = ( overrides?: Partial<Pick<ServerConfigShape, "desktopBootstrapToken">>,) => BootstrapCredentialServiceLive.pipe( Layer.provide(SqlitePersistenceMemory), Layer.provide(makeServerConfigLayer(overrides)), ); it.layer(NodeServices.layer)("BootstrapCredentialServiceLive", (it) => { it.effect("issues pairing tokens in a short manual-entry format", () => Effect.gen(function* () { const bootstrapCredentials = yield* BootstrapCredentialService; const issued = yield* bootstrapCredentials.issueOneTimeToken(); expect(issued.credential).toMatch(/^[23456789ABCDEFGHJKLMNPQRSTUVWXYZ]{12}$/); }).pipe(Effect.provide(makeBootstrapCredentialLayer())), ); it.effect("issues one-time bootstrap tokens that can only be consumed once", () => Effect.gen(function* () { const bootstrapCredentials = yield* BootstrapCredentialService; const issued = yield* bootstrapCredentials.issueOneTimeToken({ label: "Julius iPhone" }); const first = yield* bootstrapCredentials.consume(issued.credential); const second = yield* Effect.flip(bootstrapCredentials.consume(issued.credential)); expect(first.method).toBe("one-time-token"); expect(first.role).toBe("client"); expect(first.subject).toBe("one-time-token"); expect(first.label).toBe("Julius iPhone"); expect(issued.label).toBe("Julius iPhone"); expect(second._tag).toBe("BootstrapCredentialError"); expect(second.message).toContain("Unknown bootstrap credential"); }).pipe(Effect.provide(makeBootstrapCredentialLayer())), ); it.effect("atomically consumes a one-time token when multiple requests race", () => Effect.gen(function* () { const bootstrapCredentials = yield* BootstrapCredentialService; const token = yield* bootstrapCredentials.issueOneTimeToken(); const results = yield* Effect.all( Array.from({ length: 8 }, () => Effect.result(bootstrapCredentials.consume(token.credential)), ), { concurrency: "unbounded", }, ); const successes = results.filter((result) => result._tag === "Success"); const failures = results.filter((result) => result._tag === "Failure"); expect(successes).toHaveLength(1); expect(failures).toHaveLength(7); for (const failure of failures) { expect(failure.failure._tag).toBe("BootstrapCredentialError"); expect(failure.failure.message).toContain("Unknown bootstrap credential"); } }).pipe(Effect.provide(makeBootstrapCredentialLayer())), ); it.effect("seeds the desktop bootstrap credential as a one-time grant", () => Effect.gen(function* () { const bootstrapCredentials = yield* BootstrapCredentialService; const first = yield* bootstrapCredentials.consume("desktop-bootstrap-token"); const second = yield* Effect.flip(bootstrapCredentials.consume("desktop-bootstrap-token")); expect(first.method).toBe("desktop-bootstrap"); expect(first.role).toBe("owner"); expect(first.subject).toBe("desktop-bootstrap"); expect(second._tag).toBe("BootstrapCredentialError"); expect(second.status).toBe(401); }).pipe( Effect.provide( makeBootstrapCredentialLayer({ desktopBootstrapToken: "desktop-bootstrap-token", }), ), ), ); it.effect("reports seeded desktop bootstrap credentials as expired after their ttl", () => Effect.gen(function* () { const bootstrapCredentials = yield* BootstrapCredentialService; yield* TestClock.adjust(Duration.minutes(6)); const expired = yield* Effect.flip(bootstrapCredentials.consume("desktop-bootstrap-token")); expect(expired._tag).toBe("BootstrapCredentialError"); expect(expired.status).toBe(401); expect(expired.message).toContain("Bootstrap credential expired"); }).pipe( Effect.provide( Layer.merge( makeBootstrapCredentialLayer({ desktopBootstrapToken: "desktop-bootstrap-token", }), TestClock.layer(), ), ), ), ); it.effect("lists and revokes active pairing links", () => Effect.gen(function* () { const bootstrapCredentials = yield* BootstrapCredentialService; const first = yield* bootstrapCredentials.issueOneTimeToken(); const second = yield* bootstrapCredentials.issueOneTimeToken({ role: "owner" }); const activeBeforeRevoke = yield* bootstrapCredentials.listActive(); expect(activeBeforeRevoke.map((entry) => entry.id)).toContain(first.id); expect(activeBeforeRevoke.map((entry) => entry.id)).toContain(second.id); const revoked = yield* bootstrapCredentials.revoke(first.id); const activeAfterRevoke = yield* bootstrapCredentials.listActive(); const revokedConsume = yield* Effect.flip(bootstrapCredentials.consume(first.credential)); expect(revoked).toBe(true); expect(activeAfterRevoke.map((entry) => entry.id)).not.toContain(first.id); expect(activeAfterRevoke.map((entry) => entry.id)).toContain(second.id); expect(revokedConsume.message).toContain("no longer available"); expect(revokedConsume.status).toBe(401); }).pipe(Effect.provide(makeBootstrapCredentialLayer())), );});
import * as NodeServices from "@effect/platform-node/NodeServices";
import { expect, it } from "@effect/vitest";
import { Duration, Effect, Layer } from "effect";
import { TestClock } from "effect/testing";
import type { ServerConfigShape } from "../../config.ts";
import { ServerConfig } from "../../config.ts";
import { SqlitePersistenceMemory } from "../../persistence/Layers/Sqlite.ts";
import { BootstrapCredentialService } from "../Services/BootstrapCredentialService.ts";
import { BootstrapCredentialServiceLive } from "./BootstrapCredentialService.ts";
const makeServerConfigLayer = (
overrides?: Partial<Pick<ServerConfigShape, "desktopBootstrapToken">>,
) =>
Layer.effect(
ServerConfig,
Effect.gen(function* () {
const config = yield* ServerConfig;
return {
...config,
...overrides,
} satisfies ServerConfigShape;
}),
).pipe(
Layer.provide(ServerConfig.layerTest(process.cwd(), { prefix: "t3-auth-bootstrap-test-" })),
);
const makeBootstrapCredentialLayer = (
overrides?: Partial<Pick<ServerConfigShape, "desktopBootstrapToken">>,
) =>
BootstrapCredentialServiceLive.pipe(
Layer.provide(SqlitePersistenceMemory),
Layer.provide(makeServerConfigLayer(overrides)),
);
it.layer(NodeServices.layer)("BootstrapCredentialServiceLive", (it) => {
it.effect("issues pairing tokens in a short manual-entry format", () =>
Effect.gen(function* () {
const bootstrapCredentials = yield* BootstrapCredentialService;
const issued = yield* bootstrapCredentials.issueOneTimeToken();
expect(issued.credential).toMatch(/^[23456789ABCDEFGHJKLMNPQRSTUVWXYZ]{12}$/);
}).pipe(Effect.provide(makeBootstrapCredentialLayer())),
);
it.effect("issues one-time bootstrap tokens that can only be consumed once", () =>
Effect.gen(function* () {
const bootstrapCredentials = yield* BootstrapCredentialService;
const issued = yield* bootstrapCredentials.issueOneTimeToken({ label: "Julius iPhone" });
const first = yield* bootstrapCredentials.consume(issued.credential);
const second = yield* Effect.flip(bootstrapCredentials.consume(issued.credential));
expect(first.method).toBe("one-time-token");
expect(first.role).toBe("client");
expect(first.subject).toBe("one-time-token");
expect(first.label).toBe("Julius iPhone");
expect(issued.label).toBe("Julius iPhone");
expect(second._tag).toBe("BootstrapCredentialError");
expect(second.message).toContain("Unknown bootstrap credential");
}).pipe(Effect.provide(makeBootstrapCredentialLayer())),
);
it.effect("atomically consumes a one-time token when multiple requests race", () =>
Effect.gen(function* () {
const bootstrapCredentials = yield* BootstrapCredentialService;
const token = yield* bootstrapCredentials.issueOneTimeToken();
const results = yield* Effect.all(
Array.from({ length: 8 }, () =>
Effect.result(bootstrapCredentials.consume(token.credential)),
),
{
concurrency: "unbounded",
},
);
const successes = results.filter((result) => result._tag === "Success");
const failures = results.filter((result) => result._tag === "Failure");
expect(successes).toHaveLength(1);
expect(failures).toHaveLength(7);
for (const failure of failures) {
expect(failure.failure._tag).toBe("BootstrapCredentialError");
expect(failure.failure.message).toContain("Unknown bootstrap credential");
}
}).pipe(Effect.provide(makeBootstrapCredentialLayer())),
);
it.effect("seeds the desktop bootstrap credential as a one-time grant", () =>
Effect.gen(function* () {
const bootstrapCredentials = yield* BootstrapCredentialService;
const first = yield* bootstrapCredentials.consume("desktop-bootstrap-token");
const second = yield* Effect.flip(bootstrapCredentials.consume("desktop-bootstrap-token"));
expect(first.method).toBe("desktop-bootstrap");
expect(first.role).toBe("owner");
expect(first.subject).toBe("desktop-bootstrap");
expect(second._tag).toBe("BootstrapCredentialError");
expect(second.status).toBe(401);
}).pipe(
Effect.provide(
makeBootstrapCredentialLayer({
desktopBootstrapToken: "desktop-bootstrap-token",
}),
),
),
);
it.effect("reports seeded desktop bootstrap credentials as expired after their ttl", () =>
Effect.gen(function* () {
const bootstrapCredentials = yield* BootstrapCredentialService;
yield* TestClock.adjust(Duration.minutes(6));
const expired = yield* Effect.flip(bootstrapCredentials.consume("desktop-bootstrap-token"));
expect(expired._tag).toBe("BootstrapCredentialError");
expect(expired.status).toBe(401);
expect(expired.message).toContain("Bootstrap credential expired");
}).pipe(
Effect.provide(
Layer.merge(
makeBootstrapCredentialLayer({
desktopBootstrapToken: "desktop-bootstrap-token",
}),
TestClock.layer(),
),
),
),
);
it.effect("lists and revokes active pairing links", () =>
Effect.gen(function* () {
const bootstrapCredentials = yield* BootstrapCredentialService;
const first = yield* bootstrapCredentials.issueOneTimeToken();
const second = yield* bootstrapCredentials.issueOneTimeToken({ role: "owner" });
const activeBeforeRevoke = yield* bootstrapCredentials.listActive();
expect(activeBeforeRevoke.map((entry) => entry.id)).toContain(first.id);
expect(activeBeforeRevoke.map((entry) => entry.id)).toContain(second.id);
const revoked = yield* bootstrapCredentials.revoke(first.id);
const activeAfterRevoke = yield* bootstrapCredentials.listActive();
const revokedConsume = yield* Effect.flip(bootstrapCredentials.consume(first.credential));
expect(revoked).toBe(true);
expect(activeAfterRevoke.map((entry) => entry.id)).not.toContain(first.id);
expect(activeAfterRevoke.map((entry) => entry.id)).toContain(second.id);
expect(revokedConsume.message).toContain("no longer available");
expect(revokedConsume.status).toBe(401);
}).pipe(Effect.provide(makeBootstrapCredentialLayer())),
);
});