1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { expect, it } from "@effect/vitest";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5
6import * as ServerConfig from "../config.ts";
7import * as ServerEnvironment from "../environment/ServerEnvironment.ts";
8import * as EnvironmentAuthPolicy from "./EnvironmentAuthPolicy.ts";
9
10const layerEnvironmentAuthPolicy = (overrides?: Partial<ServerConfig.ServerConfig["Service"]>) =>
11 EnvironmentAuthPolicy.layer.pipe(
12 Layer.provide(ServerEnvironment.layerIdentity),
13 Layer.provide(
14 Layer.effect(
15 ServerConfig.ServerConfig,
16 Effect.gen(function* () {
17 const config = yield* ServerConfig.ServerConfig;
18 return {
19 ...config,
20 ...overrides,
21 } satisfies ServerConfig.ServerConfig["Service"];
22 }),
23 ).pipe(
24 Layer.provide(ServerConfig.layerTest(process.cwd(), { prefix: "t3-auth-policy-test-" })),
25 ),
26 ),
27 );
28
29it.layer(NodeServices.layer)("EnvironmentAuthPolicy.layer", (it) => {
30 it.effect("uses desktop-managed-local policy for desktop mode", () =>
31 Effect.gen(function* () {
32 const policy = yield* EnvironmentAuthPolicy.EnvironmentAuthPolicy;
33 const descriptor = yield* policy.getDescriptor();
34
35 expect(descriptor.policy).toBe("desktop-managed-local");
36 expect(descriptor.bootstrapMethods).toEqual(["desktop-bootstrap"]);
37 expect(descriptor.serverUpdateScope).toBe("environment:maintain");
38 // Packaged desktop has no devUrl, but still needs the port scope: it
39 // scans upward from 3773 for a free port and binds 127.0.0.1, so a second
40 // instance shares this one's hostname on a different port.
41 expect(descriptor.sessionCookieName).toBe("t3_session_3773");
42 }).pipe(
43 Effect.provide(
44 layerEnvironmentAuthPolicy({
45 mode: "desktop",
46 port: 3773,
47 }),
48 ),
49 ),
50 );
51
52 it.effect("keeps desktop cookies port-scoped on the port a second instance lands on", () =>
53 Effect.gen(function* () {
54 const policy = yield* EnvironmentAuthPolicy.EnvironmentAuthPolicy;
55 const descriptor = yield* policy.getDescriptor();
56
57 expect(descriptor.sessionCookieName).toBe("t3_session_3774");
58 }).pipe(
59 Effect.provide(
60 layerEnvironmentAuthPolicy({
61 mode: "desktop",
62 port: 3774,
63 }),
64 ),
65 ),
66 );
67
68 it.effect("uses remote-reachable policy for desktop mode when bound beyond loopback", () =>
69 Effect.gen(function* () {
70 const policy = yield* EnvironmentAuthPolicy.EnvironmentAuthPolicy;
71 const descriptor = yield* policy.getDescriptor();
72
73 expect(descriptor.policy).toBe("remote-reachable");
74 expect(descriptor.bootstrapMethods).toEqual(["desktop-bootstrap", "one-time-token"]);
75 }).pipe(
76 Effect.provide(
77 layerEnvironmentAuthPolicy({
78 mode: "desktop",
79 host: "0.0.0.0",
80 }),
81 ),
82 ),
83 );
84
85 it.effect("uses loopback-browser policy for loopback web hosts", () =>
86 Effect.gen(function* () {
87 const policy = yield* EnvironmentAuthPolicy.EnvironmentAuthPolicy;
88 const descriptor = yield* policy.getDescriptor();
89
90 expect(descriptor.policy).toBe("loopback-browser");
91 expect(descriptor.bootstrapMethods).toEqual(["one-time-token"]);
92 expect(descriptor.serverUpdateScope).toBe("environment:maintain");
93 expect(descriptor.sessionCookieName).toMatch(/^t3_session_3773_[a-f0-9]{12}$/);
94 }).pipe(
95 Effect.provide(
96 layerEnvironmentAuthPolicy({
97 mode: "web",
98 host: "127.0.0.1",
99 port: 3773,
100 }),
101 ),
102 ),
103 );
104
105 it.effect("uses remote-reachable policy for wildcard web hosts", () =>
106 Effect.gen(function* () {
107 const policy = yield* EnvironmentAuthPolicy.EnvironmentAuthPolicy;
108 const descriptor = yield* policy.getDescriptor();
109
110 expect(descriptor.policy).toBe("remote-reachable");
111 expect(descriptor.bootstrapMethods).toEqual(["one-time-token"]);
112 expect(descriptor.sessionCookieName).toMatch(/^t3_session_[a-f0-9]{12}$/);
113 }).pipe(
114 Effect.provide(
115 layerEnvironmentAuthPolicy({
116 mode: "web",
117 host: "0.0.0.0",
118 }),
119 ),
120 ),
121 );
122
123 it.effect("isolates wildcard-bound web development sessions", () =>
124 Effect.gen(function* () {
125 const policy = yield* EnvironmentAuthPolicy.EnvironmentAuthPolicy;
126 const descriptor = yield* policy.getDescriptor();
127
128 expect(descriptor.policy).toBe("remote-reachable");
129 expect(descriptor.sessionCookieName).toMatch(/^t3_session_5775_[a-f0-9]{12}$/);
130 }).pipe(
131 Effect.provide(
132 layerEnvironmentAuthPolicy({
133 mode: "web",
134 host: "0.0.0.0",
135 port: 5775,
136 devUrl: new URL("http://127.0.0.1:5736"),
137 }),
138 ),
139 ),
140 );
141
142 it.effect("uses remote-reachable policy for non-loopback web hosts", () =>
143 Effect.gen(function* () {
144 const policy = yield* EnvironmentAuthPolicy.EnvironmentAuthPolicy;
145 const descriptor = yield* policy.getDescriptor();
146
147 expect(descriptor.policy).toBe("remote-reachable");
148 expect(descriptor.sessionCookieName).toMatch(/^t3_session_[a-f0-9]{12}$/);
149 }).pipe(
150 Effect.provide(
151 layerEnvironmentAuthPolicy({
152 mode: "web",
153 host: "192.168.1.50",
154 }),
155 ),
156 ),
157 );
158});