aicodeman 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/README.md +20 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +168 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/config/multiuser.d.ts +38 -0
  6. package/dist/config/multiuser.d.ts.map +1 -0
  7. package/dist/config/multiuser.js +58 -0
  8. package/dist/config/multiuser.js.map +1 -0
  9. package/dist/cron/cron-service.d.ts +1 -1
  10. package/dist/cron/cron-service.d.ts.map +1 -1
  11. package/dist/cron/cron-service.js +31 -4
  12. package/dist/cron/cron-service.js.map +1 -1
  13. package/dist/mux-interface.d.ts +6 -0
  14. package/dist/mux-interface.d.ts.map +1 -1
  15. package/dist/plan-orchestrator.d.ts +8 -1
  16. package/dist/plan-orchestrator.d.ts.map +1 -1
  17. package/dist/plan-orchestrator.js +20 -1
  18. package/dist/plan-orchestrator.js.map +1 -1
  19. package/dist/push-store.d.ts +17 -5
  20. package/dist/push-store.d.ts.map +1 -1
  21. package/dist/push-store.js +3 -1
  22. package/dist/push-store.js.map +1 -1
  23. package/dist/session-cli-builder.d.ts +1 -1
  24. package/dist/session-cli-builder.d.ts.map +1 -1
  25. package/dist/session-cli-builder.js +7 -2
  26. package/dist/session-cli-builder.js.map +1 -1
  27. package/dist/session.d.ts +9 -0
  28. package/dist/session.d.ts.map +1 -1
  29. package/dist/session.js +19 -2
  30. package/dist/session.js.map +1 -1
  31. package/dist/tmux-manager.d.ts +15 -1
  32. package/dist/tmux-manager.d.ts.map +1 -1
  33. package/dist/tmux-manager.js +21 -6
  34. package/dist/tmux-manager.js.map +1 -1
  35. package/dist/tunnel-manager.d.ts +17 -0
  36. package/dist/tunnel-manager.d.ts.map +1 -1
  37. package/dist/tunnel-manager.js +48 -8
  38. package/dist/tunnel-manager.js.map +1 -1
  39. package/dist/types/api.d.ts +10 -0
  40. package/dist/types/api.d.ts.map +1 -1
  41. package/dist/types/api.js +20 -0
  42. package/dist/types/api.js.map +1 -1
  43. package/dist/types/cron.d.ts +2 -0
  44. package/dist/types/cron.d.ts.map +1 -1
  45. package/dist/types/index.d.ts +1 -0
  46. package/dist/types/index.d.ts.map +1 -1
  47. package/dist/types/index.js +1 -0
  48. package/dist/types/index.js.map +1 -1
  49. package/dist/types/session.d.ts +8 -1
  50. package/dist/types/session.d.ts.map +1 -1
  51. package/dist/types/session.js.map +1 -1
  52. package/dist/types/user.d.ts +59 -0
  53. package/dist/types/user.d.ts.map +1 -0
  54. package/dist/types/user.js +12 -0
  55. package/dist/types/user.js.map +1 -0
  56. package/dist/user-store.d.ts +139 -0
  57. package/dist/user-store.d.ts.map +1 -0
  58. package/dist/user-store.js +433 -0
  59. package/dist/user-store.js.map +1 -0
  60. package/dist/web/admin-audit.d.ts +17 -0
  61. package/dist/web/admin-audit.d.ts.map +1 -0
  62. package/dist/web/admin-audit.js +19 -0
  63. package/dist/web/admin-audit.js.map +1 -0
  64. package/dist/web/middleware/auth.d.ts +8 -0
  65. package/dist/web/middleware/auth.d.ts.map +1 -1
  66. package/dist/web/middleware/auth.js +250 -51
  67. package/dist/web/middleware/auth.js.map +1 -1
  68. package/dist/web/ports/auth-port.d.ts +13 -0
  69. package/dist/web/ports/auth-port.d.ts.map +1 -1
  70. package/dist/web/ports/config-port.d.ts +4 -1
  71. package/dist/web/ports/config-port.d.ts.map +1 -1
  72. package/dist/web/ports/infra-port.d.ts +4 -1
  73. package/dist/web/ports/infra-port.d.ts.map +1 -1
  74. package/dist/web/public/admin-ui.js +260 -0
  75. package/dist/web/public/admin-ui.js.br +0 -0
  76. package/dist/web/public/admin-ui.js.gz +0 -0
  77. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  78. package/dist/web/public/app.6c4b9893.js.gz +0 -0
  79. package/dist/web/public/{constants.48da7f03.js → constants.5ce97313.js} +3 -0
  80. package/dist/web/public/constants.5ce97313.js.br +0 -0
  81. package/dist/web/public/{constants.48da7f03.js.gz → constants.5ce97313.js.gz} +0 -0
  82. package/dist/web/public/cron-ui.js.gz +0 -0
  83. package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
  84. package/dist/web/public/index.html +5 -3
  85. package/dist/web/public/index.html.br +0 -0
  86. package/dist/web/public/index.html.gz +0 -0
  87. package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
  88. package/dist/web/public/keyboard-accessory.3f91acef.js.gz +0 -0
  89. package/dist/web/public/mobile-handlers.b5a667ef.js.gz +0 -0
  90. package/dist/web/public/mobile.0644e3ac.css.gz +0 -0
  91. package/dist/web/public/notification-manager.ca9dc40d.js.gz +0 -0
  92. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  93. package/dist/web/public/panels-ui.3c9b0465.js.gz +0 -0
  94. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  95. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  96. package/dist/web/public/respawn-ui.2d249da9.js.gz +0 -0
  97. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  98. package/dist/web/public/session-ui.4851c61a.js.gz +0 -0
  99. package/dist/web/public/settings-ui.29214cf1.js.gz +0 -0
  100. package/dist/web/public/styles.9e6cdb9d.css +1 -0
  101. package/dist/web/public/styles.9e6cdb9d.css.br +0 -0
  102. package/dist/web/public/styles.9e6cdb9d.css.gz +0 -0
  103. package/dist/web/public/subagent-windows.69b60c35.js.gz +0 -0
  104. package/dist/web/public/sw.js.gz +0 -0
  105. package/dist/web/public/terminal-ui.efda6083.js.gz +0 -0
  106. package/dist/web/public/ultracode-panel.js.gz +0 -0
  107. package/dist/web/public/ultracode-windows.js.gz +0 -0
  108. package/dist/web/public/upload.html.gz +0 -0
  109. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  110. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  111. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  112. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  113. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  114. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  115. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  116. package/dist/web/public/vendor/xterm.css.gz +0 -0
  117. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  118. package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
  119. package/dist/web/route-helpers.d.ts +78 -1
  120. package/dist/web/route-helpers.d.ts.map +1 -1
  121. package/dist/web/route-helpers.js +172 -3
  122. package/dist/web/route-helpers.js.map +1 -1
  123. package/dist/web/routes/admin-routes.d.ts +20 -0
  124. package/dist/web/routes/admin-routes.d.ts.map +1 -0
  125. package/dist/web/routes/admin-routes.js +193 -0
  126. package/dist/web/routes/admin-routes.js.map +1 -0
  127. package/dist/web/routes/case-routes.d.ts.map +1 -1
  128. package/dist/web/routes/case-routes.js +137 -59
  129. package/dist/web/routes/case-routes.js.map +1 -1
  130. package/dist/web/routes/clipboard-routes.d.ts +2 -2
  131. package/dist/web/routes/clipboard-routes.d.ts.map +1 -1
  132. package/dist/web/routes/clipboard-routes.js +10 -0
  133. package/dist/web/routes/clipboard-routes.js.map +1 -1
  134. package/dist/web/routes/cron-routes.d.ts.map +1 -1
  135. package/dist/web/routes/cron-routes.js +57 -9
  136. package/dist/web/routes/cron-routes.js.map +1 -1
  137. package/dist/web/routes/file-routes.d.ts.map +1 -1
  138. package/dist/web/routes/file-routes.js +26 -20
  139. package/dist/web/routes/file-routes.js.map +1 -1
  140. package/dist/web/routes/index.d.ts +2 -0
  141. package/dist/web/routes/index.d.ts.map +1 -1
  142. package/dist/web/routes/index.js +2 -0
  143. package/dist/web/routes/index.js.map +1 -1
  144. package/dist/web/routes/me-routes.d.ts +16 -0
  145. package/dist/web/routes/me-routes.d.ts.map +1 -0
  146. package/dist/web/routes/me-routes.js +73 -0
  147. package/dist/web/routes/me-routes.js.map +1 -0
  148. package/dist/web/routes/mux-routes.d.ts.map +1 -1
  149. package/dist/web/routes/mux-routes.js +23 -5
  150. package/dist/web/routes/mux-routes.js.map +1 -1
  151. package/dist/web/routes/orchestrator-routes.d.ts.map +1 -1
  152. package/dist/web/routes/orchestrator-routes.js +43 -11
  153. package/dist/web/routes/orchestrator-routes.js.map +1 -1
  154. package/dist/web/routes/plan-routes.d.ts.map +1 -1
  155. package/dist/web/routes/plan-routes.js +28 -9
  156. package/dist/web/routes/plan-routes.js.map +1 -1
  157. package/dist/web/routes/push-routes.d.ts.map +1 -1
  158. package/dist/web/routes/push-routes.js +4 -0
  159. package/dist/web/routes/push-routes.js.map +1 -1
  160. package/dist/web/routes/ralph-routes.d.ts.map +1 -1
  161. package/dist/web/routes/ralph-routes.js +21 -17
  162. package/dist/web/routes/ralph-routes.js.map +1 -1
  163. package/dist/web/routes/respawn-routes.d.ts.map +1 -1
  164. package/dist/web/routes/respawn-routes.js +23 -14
  165. package/dist/web/routes/respawn-routes.js.map +1 -1
  166. package/dist/web/routes/scheduled-routes.d.ts.map +1 -1
  167. package/dist/web/routes/scheduled-routes.js +22 -6
  168. package/dist/web/routes/scheduled-routes.js.map +1 -1
  169. package/dist/web/routes/search-routes.d.ts.map +1 -1
  170. package/dist/web/routes/search-routes.js +9 -3
  171. package/dist/web/routes/search-routes.js.map +1 -1
  172. package/dist/web/routes/session-routes.d.ts.map +1 -1
  173. package/dist/web/routes/session-routes.js +188 -61
  174. package/dist/web/routes/session-routes.js.map +1 -1
  175. package/dist/web/routes/system-routes.d.ts.map +1 -1
  176. package/dist/web/routes/system-routes.js +108 -23
  177. package/dist/web/routes/system-routes.js.map +1 -1
  178. package/dist/web/routes/ws-routes.d.ts.map +1 -1
  179. package/dist/web/routes/ws-routes.js +11 -0
  180. package/dist/web/routes/ws-routes.js.map +1 -1
  181. package/dist/web/server.d.ts +12 -0
  182. package/dist/web/server.d.ts.map +1 -1
  183. package/dist/web/server.js +187 -11
  184. package/dist/web/server.js.map +1 -1
  185. package/dist/web/sse-events.d.ts +6 -0
  186. package/dist/web/sse-events.d.ts.map +1 -1
  187. package/dist/web/sse-events.js +7 -0
  188. package/dist/web/sse-events.js.map +1 -1
  189. package/dist/web/sse-stream-manager.d.ts +32 -2
  190. package/dist/web/sse-stream-manager.d.ts.map +1 -1
  191. package/dist/web/sse-stream-manager.js +51 -4
  192. package/dist/web/sse-stream-manager.js.map +1 -1
  193. package/package.json +1 -1
  194. package/dist/web/public/constants.48da7f03.js.br +0 -0
  195. package/dist/web/public/styles.ff43f80f.css +0 -1
  196. package/dist/web/public/styles.ff43f80f.css.br +0 -0
  197. package/dist/web/public/styles.ff43f80f.css.gz +0 -0
@@ -5,13 +5,16 @@
5
5
  * that replaces ~43 inline not-found checks across route handlers.
6
6
  */
7
7
  import { join, resolve, relative, isAbsolute } from 'node:path';
8
- import { realpathSync } from 'node:fs';
8
+ import { realpathSync, existsSync, mkdirSync } from 'node:fs';
9
9
  import fs from 'node:fs/promises';
10
10
  import { homedir } from 'node:os';
11
11
  import { ApiErrorCode, createErrorResponse } from '../types.js';
12
+ import { MAX_CONCURRENT_SESSIONS } from '../config/map-limits.js';
12
13
  import { parseRalphLoopConfig, extractCompletionPhrase } from '../ralph-config.js';
13
14
  import { SseEvent } from './sse-events.js';
14
15
  import { dataPath } from '../config/instance.js';
16
+ import { isMultiUserMode, maxSessionsPerUser, userCasesDir } from '../config/multiuser.js';
17
+ import { SYNTHETIC_ADMIN, findUser } from '../user-store.js';
15
18
  // Shared path constants used across route modules. CASES_DIR (project folders)
16
19
  // stays shared across instances; SETTINGS_PATH is per-instance runtime state.
17
20
  export const CASES_DIR = join(homedir(), 'codeman-cases');
@@ -67,13 +70,179 @@ export function validateSessionFilePath(sessionWorkingDir, filePath) {
67
70
  }
68
71
  // Maximum hook data size (prevents oversized SSE broadcasts)
69
72
  const MAX_HOOK_DATA_SIZE = 8 * 1024;
73
+ /**
74
+ * Effective identity for a request. In multi-user mode this is the auth-decorated
75
+ * user; in single-user mode (or when unset) it defaults to a synthetic admin so
76
+ * downstream ownership checks are no-ops and there is ONE code path.
77
+ */
78
+ export function getAuthUser(req) {
79
+ return req.authUser ?? SYNTHETIC_ADMIN;
80
+ }
81
+ /**
82
+ * Whether an identity may see/act on a resource with the given owner. Always true
83
+ * in single-user mode; in multi-user, admins see everything and regular users only
84
+ * their own (an absent owner is legacy/unassigned = admin-only).
85
+ */
86
+ export function canAccessOwned(user, owner) {
87
+ if (!isMultiUserMode())
88
+ return true;
89
+ if (user.role === 'admin')
90
+ return true;
91
+ return !!owner && owner === user.username;
92
+ }
93
+ /**
94
+ * The owner to stamp on a resource created by this request: the requesting user in
95
+ * multi-user mode, or undefined in single-user (so state stays owner-free and the
96
+ * flag can be removed later without leaving stray owners).
97
+ */
98
+ export function ownerFor(req) {
99
+ return isMultiUserMode() ? getAuthUser(req).username : undefined;
100
+ }
101
+ /**
102
+ * The cases directory for a request/user: the shared ~/codeman-cases in single-user
103
+ * mode, or the per-user ~/codeman-users/<username>/cases in multi-user (created
104
+ * lazily). Admins are NOT auto-scoped here — an admin acting on a specific user's
105
+ * case resolves through the owner-aware case resolver instead.
106
+ */
107
+ export function resolveCasesDir(user) {
108
+ if (!isMultiUserMode() || !user)
109
+ return CASES_DIR;
110
+ const dir = userCasesDir(user.username);
111
+ if (!existsSync(dir))
112
+ mkdirSync(dir, { recursive: true });
113
+ return dir;
114
+ }
115
+ /**
116
+ * Realpath-confine a non-admin's requested working directory to their own case
117
+ * space in multi-user mode. Returns true if allowed. Admins and single-user mode
118
+ * are unrestricted. The path need not exist yet (checked against its nearest
119
+ * existing ancestor) so newly-created case dirs pass. This is the load-bearing
120
+ * rule (plan 6.2/14.7): every file-serving surface downstream trusts workingDir.
121
+ */
122
+ export function isWorkingDirAllowed(user, workingDir) {
123
+ if (!isMultiUserMode() || user.role === 'admin')
124
+ return true;
125
+ const base = userCasesDir(user.username);
126
+ // Resolve the deepest existing ancestor to defeat symlink escapes without
127
+ // requiring the leaf to exist yet.
128
+ const resolveExisting = (p) => {
129
+ let cur = resolve(p);
130
+ // walk up until an existing path is found
131
+ for (;;) {
132
+ try {
133
+ return realpathSync(cur);
134
+ }
135
+ catch {
136
+ const parent = resolve(cur, '..');
137
+ if (parent === cur)
138
+ return cur;
139
+ cur = parent;
140
+ }
141
+ }
142
+ };
143
+ let realBase;
144
+ try {
145
+ realBase = realpathSync(base);
146
+ }
147
+ catch {
148
+ // base does not exist yet — create it so confinement has a stable anchor
149
+ mkdirSync(base, { recursive: true });
150
+ realBase = realpathSync(base);
151
+ }
152
+ const realTarget = resolveExisting(workingDir);
153
+ if (realTarget === realBase)
154
+ return true;
155
+ const rel = relative(realBase, realTarget);
156
+ return rel !== '' && !rel.startsWith('..') && !isAbsolute(rel);
157
+ }
158
+ /**
159
+ * Username-keyed variant of `isWorkingDirAllowed` for spawn sites that only carry
160
+ * an owner username (cron fire-time, scheduled-run loop) rather than a live request.
161
+ * Resolves the owner's role from the store; a missing/deleted user is treated as a
162
+ * non-privileged regular user (fails closed to their deterministic case space).
163
+ * No-op (true) in single-user mode or for an unset owner.
164
+ */
165
+ export async function isWorkingDirAllowedForUsername(username, workingDir) {
166
+ if (!isMultiUserMode() || !username)
167
+ return true;
168
+ const user = await findUser(username);
169
+ return isWorkingDirAllowed({ username, role: user?.role ?? 'user' }, workingDir);
170
+ }
171
+ /** Whether the caller is an admin (or single-user mode, where the sole user is admin). */
172
+ export function isAdmin(req) {
173
+ return !isMultiUserMode() || getAuthUser(req).role === 'admin';
174
+ }
175
+ /**
176
+ * First line of admin-only handlers: 403 FORBIDDEN + returns false when the caller
177
+ * is not an admin. Always true in single-user mode (the sole user is the admin).
178
+ */
179
+ export function requireAdmin(req, reply) {
180
+ if (isAdmin(req))
181
+ return true;
182
+ reply.code(403).send(createErrorResponse(ApiErrorCode.FORBIDDEN));
183
+ return false;
184
+ }
185
+ /**
186
+ * Session-capacity check, centralized so the global cap AND the per-user cap are
187
+ * enforced everywhere a session is created (the check was copy-pasted at 6 sites).
188
+ * Pure: takes the sessions Map so it composes with ctx.sessions / this.sessions /
189
+ * this.deps.sessions callers. Per-user cap only applies in multi-user mode.
190
+ */
191
+ export function sessionCapacityState(sessions, owner) {
192
+ const atGlobalCap = sessions.size >= MAX_CONCURRENT_SESSIONS;
193
+ let atUserCap = false;
194
+ if (isMultiUserMode() && owner) {
195
+ let count = 0;
196
+ for (const s of sessions.values())
197
+ if (s.owner === owner)
198
+ count++;
199
+ atUserCap = count >= maxSessionsPerUser();
200
+ }
201
+ return { atGlobalCap, atUserCap };
202
+ }
203
+ /**
204
+ * Route sugar: the human-readable error message when at capacity, else null. The
205
+ * caller wraps it in createErrorResponse with its own error code (OPERATION_FAILED
206
+ * vs SESSION_BUSY, matching the pre-existing per-route codes).
207
+ */
208
+ export function sessionCapacityMessage(sessions, owner) {
209
+ const { atGlobalCap, atUserCap } = sessionCapacityState(sessions, owner);
210
+ if (atGlobalCap) {
211
+ return `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached. Delete some sessions first.`;
212
+ }
213
+ if (atUserCap) {
214
+ return `Your session limit (${maxSessionsPerUser()}) reached. Delete some of your sessions first.`;
215
+ }
216
+ return null;
217
+ }
218
+ /**
219
+ * Revoke every cookie session belonging to a user (optionally keeping one token,
220
+ * e.g. the caller's own during a self-service password change). Returns the count.
221
+ */
222
+ export function revokeUserSessions(authSessions, username, exceptToken) {
223
+ if (!authSessions)
224
+ return 0;
225
+ const norm = username.trim().toLowerCase();
226
+ let removed = 0;
227
+ for (const [token, record] of authSessions) {
228
+ if (record.username === norm && token !== exceptToken) {
229
+ authSessions.delete(token);
230
+ removed++;
231
+ }
232
+ }
233
+ return removed;
234
+ }
70
235
  /**
71
236
  * Look up a session by ID or throw a structured error.
72
237
  * Replaces the pattern: `const session = sessions.get(id); if (!session) return createErrorResponse(...)`.
238
+ *
239
+ * When `req` is passed in multi-user mode, a session the caller does not own is
240
+ * reported as NOT_FOUND (never 403), so existence of other users' sessions is not
241
+ * leaked. Single-user / admin callers are unaffected.
73
242
  */
74
- export function findSessionOrFail(ctx, sessionId) {
243
+ export function findSessionOrFail(ctx, sessionId, req) {
75
244
  const session = ctx.sessions.get(sessionId);
76
- if (!session) {
245
+ if (!session || (req && !canAccessOwned(getAuthUser(req), session.owner))) {
77
246
  throw Object.assign(new Error(`Session ${sessionId} not found`), {
78
247
  statusCode: 404,
79
248
  body: createErrorResponse(ApiErrorCode.NOT_FOUND, `Session ${sessionId} not found`),
@@ -1 +1 @@
1
- {"version":3,"file":"route-helpers.js","sourceRoot":"","sources":["../../src/web/route-helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"route-helpers.js","sourceRoot":"","sources":["../../src/web/route-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @fileoverview Admin user-management routes (multi-user mode only).
3
+ *
4
+ * All handlers: 404 unless multi-user mode is active, requireAdmin, and audit-logged
5
+ * to ~/.codeman/admin-audit.jsonl. Endpoints (docs/multi-user-plan.md section 8):
6
+ * GET /api/admin/users
7
+ * POST /api/admin/users
8
+ * PATCH /api/admin/users/:username
9
+ * POST /api/admin/users/:username/reset-password
10
+ * POST /api/admin/users/:username/logout
11
+ * DELETE /api/admin/users/:username
12
+ *
13
+ * Self-service GET /api/me + POST /api/me/password live in me-routes.ts.
14
+ */
15
+ import type { FastifyInstance } from 'fastify';
16
+ import type { AuthPort } from '../ports/auth-port.js';
17
+ import type { SessionPort } from '../ports/session-port.js';
18
+ import type { EventPort } from '../ports/event-port.js';
19
+ export declare function registerAdminRoutes(app: FastifyInstance, ctx: SessionPort & AuthPort & EventPort): void;
20
+ //# sourceMappingURL=admin-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-routes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/admin-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAoB7E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AA4BxD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,IAAI,CA0IvG"}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * @fileoverview Admin user-management routes (multi-user mode only).
3
+ *
4
+ * All handlers: 404 unless multi-user mode is active, requireAdmin, and audit-logged
5
+ * to ~/.codeman/admin-audit.jsonl. Endpoints (docs/multi-user-plan.md section 8):
6
+ * GET /api/admin/users
7
+ * POST /api/admin/users
8
+ * PATCH /api/admin/users/:username
9
+ * POST /api/admin/users/:username/reset-password
10
+ * POST /api/admin/users/:username/logout
11
+ * DELETE /api/admin/users/:username
12
+ *
13
+ * Self-service GET /api/me + POST /api/me/password live in me-routes.ts.
14
+ */
15
+ import { z } from 'zod';
16
+ import { readdirSync } from 'node:fs';
17
+ import { ApiErrorCode, createErrorResponse } from '../../types.js';
18
+ import { isMultiUserMode, userCasesDir } from '../../config/multiuser.js';
19
+ import { createUser, deleteUser, deleteUserSpace, findUser, generateOneTimePassword, readUsers, setPassword, toPublicUser, updateUser, UserStoreError, } from '../../user-store.js';
20
+ import { getAuthUser, requireAdmin, revokeUserSessions } from '../route-helpers.js';
21
+ import { appendAdminAudit } from '../admin-audit.js';
22
+ import { SseEvent } from '../sse-events.js';
23
+ const CreateUserSchema = z.object({
24
+ username: z.string().min(1).max(64),
25
+ role: z.enum(['admin', 'user']).default('user'),
26
+ password: z.string().min(8).max(1024).optional(),
27
+ canBypassPermissions: z.boolean().optional(),
28
+ });
29
+ const UpdateUserSchema = z.object({
30
+ role: z.enum(['admin', 'user']).optional(),
31
+ disabled: z.boolean().optional(),
32
+ canBypassPermissions: z.boolean().optional(),
33
+ });
34
+ const DeleteUserSchema = z.object({ deleteSpace: z.boolean().optional() });
35
+ /** Map a UserStoreError's code onto the API error code + status. */
36
+ function storeError(reply, err) {
37
+ if (err instanceof UserStoreError) {
38
+ const code = ApiErrorCode[err.code] ?? ApiErrorCode.INVALID_INPUT;
39
+ reply.code(err.code === 'USER_EXISTS' || err.code === 'LAST_ADMIN' ? 409 : err.code === 'USER_NOT_FOUND' ? 404 : 400);
40
+ return createErrorResponse(code, err.message);
41
+ }
42
+ reply.code(500);
43
+ return createErrorResponse(ApiErrorCode.INTERNAL_ERROR, err instanceof Error ? err.message : 'error');
44
+ }
45
+ export function registerAdminRoutes(app, ctx) {
46
+ // Gate: admin routes exist only in multi-user mode, and only for admins.
47
+ const gate = (req, reply) => {
48
+ if (!isMultiUserMode()) {
49
+ reply.code(404).send(createErrorResponse(ApiErrorCode.NOT_FOUND, 'Not found'));
50
+ return false;
51
+ }
52
+ return requireAdmin(req, reply);
53
+ };
54
+ const audit = (req, action, target, detail) => void appendAdminAudit({ admin: getAuthUser(req).username, action, target, ip: req.ip, detail });
55
+ // Count a user's live sessions + active cookie sessions + case folders.
56
+ const statsFor = (username) => {
57
+ let liveSessions = 0;
58
+ for (const s of ctx.sessions.values())
59
+ if (s.owner === username)
60
+ liveSessions++;
61
+ let activeSessions = 0;
62
+ if (ctx.authSessions)
63
+ for (const [, rec] of ctx.authSessions)
64
+ if (rec.username === username)
65
+ activeSessions++;
66
+ let caseCount = 0;
67
+ try {
68
+ caseCount = readdirSync(userCasesDir(username), { withFileTypes: true }).filter((e) => e.isDirectory()).length;
69
+ }
70
+ catch {
71
+ /* no cases dir yet */
72
+ }
73
+ return { liveSessions, activeSessions, caseCount };
74
+ };
75
+ app.get('/api/admin/users', async (req, reply) => {
76
+ if (!gate(req, reply))
77
+ return;
78
+ const users = await readUsers(true);
79
+ return {
80
+ success: true,
81
+ data: users.map((u) => ({ ...toPublicUser(u), stats: statsFor(u.username) })),
82
+ };
83
+ });
84
+ app.post('/api/admin/users', async (req, reply) => {
85
+ if (!gate(req, reply))
86
+ return;
87
+ const parsed = CreateUserSchema.safeParse(req.body);
88
+ if (!parsed.success) {
89
+ reply.code(400);
90
+ return createErrorResponse(ApiErrorCode.INVALID_INPUT, parsed.error.issues[0]?.message ?? 'Invalid input');
91
+ }
92
+ // No password given: generate a one-time password, returned ONCE, force change.
93
+ const oneTime = parsed.data.password ? undefined : generateOneTimePassword();
94
+ try {
95
+ const user = await createUser({
96
+ username: parsed.data.username,
97
+ role: parsed.data.role,
98
+ password: parsed.data.password ?? oneTime,
99
+ canBypassPermissions: parsed.data.canBypassPermissions,
100
+ mustChangePassword: !parsed.data.password,
101
+ });
102
+ audit(req, 'user.create', user.username, { role: user.role });
103
+ ctx.broadcast(SseEvent.AdminUsersChanged, {});
104
+ return { success: true, data: { user: toPublicUser(user), oneTimePassword: oneTime } };
105
+ }
106
+ catch (err) {
107
+ return storeError(reply, err);
108
+ }
109
+ });
110
+ app.patch('/api/admin/users/:username', async (req, reply) => {
111
+ if (!gate(req, reply))
112
+ return;
113
+ const { username } = req.params;
114
+ const parsed = UpdateUserSchema.safeParse(req.body);
115
+ if (!parsed.success) {
116
+ reply.code(400);
117
+ return createErrorResponse(ApiErrorCode.INVALID_INPUT, parsed.error.issues[0]?.message ?? 'Invalid input');
118
+ }
119
+ try {
120
+ const user = await updateUser(username, parsed.data);
121
+ // Security: revoke the target's cookie sessions on ANY successful update. role,
122
+ // disabled, and canBypassPermissions are all authorization-relevant, and the
123
+ // cookie snapshots role, so a stale cookie could otherwise retain old privileges
124
+ // (a demoted admin staying admin). Idempotent, affects only the target, and
125
+ // forces a re-auth that re-snapshots the new record.
126
+ revokeUserSessions(ctx.authSessions, user.username);
127
+ audit(req, 'user.update', user.username, parsed.data);
128
+ ctx.broadcast(SseEvent.AdminUsersChanged, {});
129
+ return { success: true, data: { user: toPublicUser(user) } };
130
+ }
131
+ catch (err) {
132
+ return storeError(reply, err);
133
+ }
134
+ });
135
+ app.post('/api/admin/users/:username/reset-password', async (req, reply) => {
136
+ if (!gate(req, reply))
137
+ return;
138
+ const { username } = req.params;
139
+ if (!(await findUser(username))) {
140
+ reply.code(404);
141
+ return createErrorResponse(ApiErrorCode.USER_NOT_FOUND, 'No such user');
142
+ }
143
+ const oneTime = generateOneTimePassword();
144
+ try {
145
+ await setPassword(username, oneTime, { mustChangePassword: true });
146
+ revokeUserSessions(ctx.authSessions, username);
147
+ audit(req, 'user.reset-password', username);
148
+ ctx.broadcast(SseEvent.AdminUsersChanged, {});
149
+ return { success: true, data: { oneTimePassword: oneTime } };
150
+ }
151
+ catch (err) {
152
+ return storeError(reply, err);
153
+ }
154
+ });
155
+ app.post('/api/admin/users/:username/logout', async (req, reply) => {
156
+ if (!gate(req, reply))
157
+ return;
158
+ const { username } = req.params;
159
+ const revoked = revokeUserSessions(ctx.authSessions, username);
160
+ audit(req, 'user.logout', username, { revoked });
161
+ return { success: true, data: { revoked } };
162
+ });
163
+ app.delete('/api/admin/users/:username', async (req, reply) => {
164
+ if (!gate(req, reply))
165
+ return;
166
+ const { username } = req.params;
167
+ const parsed = DeleteUserSchema.safeParse(req.body ?? {});
168
+ const deleteSpace = parsed.success ? parsed.data.deleteSpace : false;
169
+ try {
170
+ // Security: validate BEFORE any teardown. deleteUser runs the authoritative
171
+ // existence + last-admin guard under lock with no side effects, so a refusal
172
+ // (409 LAST_ADMIN / 404 USER_NOT_FOUND) leaves the user's live sessions and
173
+ // cookies untouched. Only after it succeeds do we irreversibly kill sessions and
174
+ // revoke cookies. (owned is captured from the in-memory map, independent of the
175
+ // record, so it is safe to read before the delete.)
176
+ const owned = [...ctx.sessions.values()].filter((s) => s.owner === username).map((s) => s.id);
177
+ await deleteUser(username); // throws LAST_ADMIN / USER_NOT_FOUND (no side effects)
178
+ for (const id of owned) {
179
+ await ctx.cleanupSession(id, true, 'admin_delete_user').catch(() => { });
180
+ }
181
+ revokeUserSessions(ctx.authSessions, username);
182
+ if (deleteSpace)
183
+ await deleteUserSpace(username);
184
+ audit(req, 'user.delete', username, { deleteSpace, killedSessions: owned.length });
185
+ ctx.broadcast(SseEvent.AdminUsersChanged, {});
186
+ return { success: true, data: { username, deletedSpace: !!deleteSpace } };
187
+ }
188
+ catch (err) {
189
+ return storeError(reply, err);
190
+ }
191
+ });
192
+ }
193
+ //# sourceMappingURL=admin-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-routes.js","sourceRoot":"","sources":["../../../src/web/routes/admin-routes.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"case-routes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/case-routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA0B1C,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAiG/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,SAAS,GAAG,UAAU,GAAG,IAAI,CA89B1F"}
1
+ {"version":3,"file":"case-routes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/case-routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAuC1C,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAuG/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,SAAS,GAAG,UAAU,GAAG,IAAI,CAuiC1F"}