Open History to see the last commit
1// @effect-diagnostics nodeBuiltinImport:off -- These tests assert real POSIX modes on a temporary directory.
2import * as NodeFS from "node:fs";
3import * as NodeOS from "node:os";
4import * as NodePath from "node:path";
5import { assert, describe, it } from "@effect/vitest";
6
7import { openClerkTokenStorage, type ClerkTokenStorage } from "./ClerkTokenStore.ts";
8
9// oxlint-disable-next-line t3code/no-global-process-runtime -- Unix mode bits are the assertion; Windows reports them through ACLs.
10const describePosix = describe.skipIf(process.platform === "win32");
11
12const modeOf = (path: string): number => NodeFS.statSync(path).mode & 0o777;
13
14function writeLoose(path: string, contents: string): void {
15 NodeFS.writeFileSync(path, contents, { mode: 0o666 });
16 NodeFS.chmodSync(path, 0o666);
17}
18
19async function withStateDir(run: (stateDir: string) => Promise<void> | void): Promise<void> {
20 const stateDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-clerk-tokens-"));
21 try {
22 await run(stateDir);
23 } finally {
24 NodeFS.rmSync(stateDir, { recursive: true, force: true });
25 }
26}
27
28const idleStorage = (): ClerkTokenStorage => ({
29 getItem: async () => null,
30 setItem: async () => undefined,
31 removeItem: () => undefined,
32});
33
34describePosix("ClerkTokenStore", () => {
35 it("keeps clerk tokens at 0600 inside a 0700 directory", async () => {
36 await withStateDir(async (stateDir) => {
37 NodeFS.chmodSync(stateDir, 0o755);
38 const directory = NodePath.join(stateDir, "clerk");
39 const legacyPath = NodePath.join(stateDir, "clerk-tokens.json");
40 const tokenPath = NodePath.join(directory, "clerk-tokens.json");
41 NodeFS.mkdirSync(directory, { mode: 0o755 });
42 NodeFS.chmodSync(directory, 0o755);
43 writeLoose(legacyPath, '{"__clerk_client_jwt":"enc:existing"}\n');
44
45 const opened: string[] = [];
46 const storage = openClerkTokenStorage(stateDir, (cwd) => {
47 opened.push(cwd);
48 return {
49 getItem: async () => {
50 writeLoose(tokenPath, "from-get");
51 return "from-get";
52 },
53 setItem: (_key, value) => {
54 writeLoose(tokenPath, value);
55 },
56 removeItem: () => {
57 NodeFS.rmSync(tokenPath, { force: true });
58 },
59 };
60 });
61
62 assert.deepEqual(opened, [directory]);
63 assert.equal(modeOf(stateDir), 0o755);
64 assert.equal(modeOf(directory), 0o700);
65 assert.equal(modeOf(tokenPath), 0o600);
66 assert.equal(NodeFS.existsSync(legacyPath), false);
67 assert.equal(
68 NodeFS.readFileSync(tokenPath, "utf8"),
69 '{"__clerk_client_jwt":"enc:existing"}\n',
70 );
71
72 assert.equal(await storage.getItem("client"), "from-get");
73 assert.equal(modeOf(tokenPath), 0o600);
74 await storage.setItem("client", "from-set");
75 assert.equal(modeOf(tokenPath), 0o600);
76 assert.equal(NodeFS.readFileSync(tokenPath, "utf8"), "from-set");
77 storage.removeItem("client");
78 assert.equal(NodeFS.existsSync(tokenPath), false);
79
80 writeLoose(tokenPath, "kept");
81 writeLoose(legacyPath, "stale");
82 NodeFS.chmodSync(directory, 0o755);
83 openClerkTokenStorage(stateDir, () => idleStorage());
84 assert.equal(modeOf(directory), 0o700);
85 assert.equal(modeOf(tokenPath), 0o600);
86 assert.equal(NodeFS.existsSync(legacyPath), false);
87 assert.equal(NodeFS.readFileSync(tokenPath, "utf8"), "kept");
88 });
89 });
90
91 it("resolves a relative state directory before opening storage", async () => {
92 await withStateDir(async (stateDir) => {
93 const relativeStateDir = NodePath.relative(process.cwd(), stateDir);
94 const opened: string[] = [];
95 openClerkTokenStorage(relativeStateDir, (directory) => {
96 opened.push(directory);
97 return idleStorage();
98 });
99
100 const directory = NodePath.join(stateDir, "clerk");
101 assert.equal(NodePath.isAbsolute(relativeStateDir), false);
102 assert.deepEqual(opened, [directory]);
103 assert.equal(modeOf(directory), 0o700);
104 });
105 });
106
107 it("migrates relative state paths from Electron userData, not the working directory", async () => {
108 await withStateDir((stateDir) => {
109 const relativeStateDir = NodePath.relative(process.cwd(), stateDir);
110 const userData = NodePath.join(
111 stateDir,
112 "electron",
113 ...relativeStateDir.split(NodePath.sep).map(() => "profile"),
114 );
115 const legacyStateDir = NodePath.join(userData, relativeStateDir);
116 const legacyPath = NodePath.join(legacyStateDir, "clerk-tokens.json");
117 NodeFS.mkdirSync(legacyStateDir, { recursive: true });
118 writeLoose(legacyPath, "existing-session");
119 const unrelatedPath = NodePath.join(stateDir, "clerk-tokens.json");
120 writeLoose(unrelatedPath, "not-the-electron-session");
121
122 openClerkTokenStorage(relativeStateDir, idleStorage, userData);
123
124 const tokenPath = NodePath.join(stateDir, "clerk", "clerk-tokens.json");
125 assert.equal(NodeFS.readFileSync(tokenPath, "utf8"), "existing-session");
126 assert.equal(modeOf(tokenPath), 0o600);
127 assert.equal(NodeFS.existsSync(legacyPath), false);
128 assert.equal(NodeFS.readFileSync(unrelatedPath, "utf8"), "not-the-electron-session");
129 });
130 });
131
132 it("does not follow a symlinked clerk directory or token file", async () => {
133 await withStateDir(async (stateDir) => {
134 const outsideDirectory = NodePath.join(stateDir, "outside-dir");
135 NodeFS.mkdirSync(outsideDirectory, { mode: 0o755 });
136 NodeFS.chmodSync(outsideDirectory, 0o755);
137 NodeFS.symlinkSync(outsideDirectory, NodePath.join(stateDir, "clerk"));
138
139 assert.throws(() => openClerkTokenStorage(stateDir, idleStorage), /must be a real directory/);
140 assert.equal(modeOf(outsideDirectory), 0o755);
141 NodeFS.unlinkSync(NodePath.join(stateDir, "clerk"));
142
143 const outsideFile = NodePath.join(stateDir, "outside.json");
144 NodeFS.writeFileSync(outsideFile, "secret", { mode: 0o644 });
145 NodeFS.chmodSync(outsideFile, 0o644);
146 NodeFS.symlinkSync(outsideFile, NodePath.join(stateDir, "clerk-tokens.json"));
147 assert.throws(() => openClerkTokenStorage(stateDir, idleStorage), /must be a regular file/);
148 assert.equal(modeOf(outsideFile), 0o644);
149 });
150 });
151});