clay-server 5.1.0 → 5.2.0-beta.1

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 (48) hide show
  1. package/lib/account-auth-policy.js +21 -0
  2. package/lib/account-auth-socket.js +29 -0
  3. package/lib/account-auth-throttle.js +44 -0
  4. package/lib/account-auth-transport.js +48 -0
  5. package/lib/account-login-page.js +28 -0
  6. package/lib/account-passkey-challenges.js +31 -0
  7. package/lib/account-passkey-page.js +89 -0
  8. package/lib/account-passkey-policy.js +39 -0
  9. package/lib/account-password-page.js +69 -0
  10. package/lib/account-passwords.js +36 -0
  11. package/lib/account-remembered.js +77 -0
  12. package/lib/account-session-page.js +51 -0
  13. package/lib/account-session-store.js +82 -0
  14. package/lib/daemon.js +2 -0
  15. package/lib/migrate-single-user.js +3 -23
  16. package/lib/project-server-settings.js +1 -0
  17. package/lib/project-user-knowledge.js +2 -1
  18. package/lib/public/auth/account-login.css +98 -0
  19. package/lib/public/auth/account-login.js +104 -0
  20. package/lib/public/css/mate-conversation.css +2 -2
  21. package/lib/public/css/user-settings-sessions.css +42 -0
  22. package/lib/public/index.html +17 -5
  23. package/lib/public/modules/account-auth-settings.js +71 -0
  24. package/lib/public/modules/account-transport-settings.js +51 -0
  25. package/lib/public/modules/app-messages.js +4 -0
  26. package/lib/public/modules/passkey-browser.js +69 -0
  27. package/lib/public/modules/passkey-server-settings.js +57 -0
  28. package/lib/public/modules/project-logs-render.js +3 -2
  29. package/lib/public/modules/server-settings-controls.js +10 -0
  30. package/lib/public/modules/server-settings.js +7 -2
  31. package/lib/public/modules/user-settings-account.js +14 -1
  32. package/lib/public/modules/user-settings-sessions.js +120 -0
  33. package/lib/public/modules/user-settings.js +3 -0
  34. package/lib/public/modules/you-activity.js +3 -1
  35. package/lib/public/modules/you.js +91 -6
  36. package/lib/public/style.css +1 -0
  37. package/lib/server-account-passkeys.js +186 -0
  38. package/lib/server-account-passwords.js +127 -0
  39. package/lib/server-account-security.js +53 -0
  40. package/lib/server-auth.js +107 -79
  41. package/lib/server-settings.js +2 -1
  42. package/lib/server.js +2 -0
  43. package/lib/user-knowledge-service.js +23 -1
  44. package/lib/users-auth.js +38 -3
  45. package/lib/users-create.js +97 -0
  46. package/lib/users-server-pin.js +37 -0
  47. package/lib/users.js +11 -84
  48. package/package.json +2 -1
package/lib/users.js CHANGED
@@ -71,50 +71,6 @@ function ensureUserBuiltinMates(userId) {
71
71
  }
72
72
  }
73
73
 
74
- function createUser(opts) {
75
- var data = loadUsers();
76
- // Check username uniqueness
77
- for (var i = 0; i < data.users.length; i++) {
78
- if (data.users[i].username.toLowerCase() === opts.username.toLowerCase()) {
79
- return { error: "This username is already taken" };
80
- }
81
- }
82
- // Check email uniqueness (when provided)
83
- if (opts.email) {
84
- for (var i = 0; i < data.users.length; i++) {
85
- if (data.users[i].email && data.users[i].email.toLowerCase() === opts.email.toLowerCase()) {
86
- return { error: "This email is already registered" };
87
- }
88
- }
89
- }
90
- var user = {
91
- id: generateUserId(),
92
- username: opts.username,
93
- email: opts.email || null,
94
- displayName: opts.displayName || opts.username,
95
- pinHash: auth.hashPin(opts.pin),
96
- role: opts.role || "user",
97
- mustChangePin: !!opts.mustChangePin,
98
- createdAt: Date.now(),
99
- linuxUser: opts.linuxUser || null,
100
- profile: opts.profile || {
101
- name: opts.displayName || opts.username,
102
- lang: "en-US",
103
- avatarColor: "#5857fc",
104
- avatarStyle: "imprint",
105
- avatarSeed: crypto.randomBytes(4).toString("hex"),
106
- },
107
- };
108
- data.users.push(user);
109
- saveUsers(data);
110
-
111
- // Seed immediately for ordinary multi-user storage. OS-user provisioning
112
- // calls this again after the Linux mapping exists, targeting its final home.
113
- ensureUserBuiltinMates(user.id);
114
-
115
- return { ok: true, user: user };
116
- }
117
-
118
74
  function createAdmin(opts) {
119
75
  return createUser({
120
76
  username: opts.username,
@@ -188,7 +144,7 @@ function getSoloNoPinUser() {
188
144
  var data = loadUsers();
189
145
  if (!data.users || data.users.length !== 1) return null;
190
146
  var u = data.users[0];
191
- if (u.pinHash) return null;
147
+ if (u.pinHash || u.passwordHash || data.accountAuthMethod === 'password') return null;
192
148
  return u;
193
149
  }
194
150
 
@@ -224,6 +180,11 @@ function updateUserPin(userId, newPin) {
224
180
  for (var i = 0; i < data.users.length; i++) {
225
181
  if (data.users[i].id === userId) {
226
182
  data.users[i].pinHash = auth.hashPin(newPin);
183
+ if (data.accountAuthMethod === 'password') {
184
+ delete data.users[i].passwordHash;
185
+ delete data.users[i].passkeys;
186
+ delete data.users[i].passkeyUserHandle;
187
+ }
227
188
  data.users[i].mustChangePin = false;
228
189
  saveUsers(data);
229
190
  return { ok: true };
@@ -306,44 +267,6 @@ function createInvite(createdByUserId, targetEmail) {
306
267
  return invite;
307
268
  }
308
269
 
309
- function createUserWithoutPin(opts) {
310
- var data = loadUsers();
311
- for (var i = 0; i < data.users.length; i++) {
312
- if (data.users[i].username.toLowerCase() === opts.username.toLowerCase()) {
313
- return { error: "This username is already taken" };
314
- }
315
- }
316
- if (opts.email) {
317
- for (var i = 0; i < data.users.length; i++) {
318
- if (data.users[i].email && data.users[i].email.toLowerCase() === opts.email.toLowerCase()) {
319
- return { error: "This email is already registered" };
320
- }
321
- }
322
- }
323
- var user = {
324
- id: generateUserId(),
325
- username: opts.username,
326
- email: opts.email || null,
327
- displayName: opts.displayName || opts.username,
328
- pinHash: null,
329
- role: opts.role || "user",
330
- createdAt: Date.now(),
331
- profile: opts.profile || {
332
- name: opts.displayName || opts.username,
333
- lang: "en-US",
334
- avatarColor: "#5857fc",
335
- avatarStyle: "imprint",
336
- avatarSeed: crypto.randomBytes(4).toString("hex"),
337
- },
338
- };
339
- data.users.push(user);
340
- saveUsers(data);
341
-
342
- ensureUserBuiltinMates(user.id);
343
-
344
- return { ok: true, user: user };
345
- }
346
-
347
270
  function findInvite(code) {
348
271
  var data = loadUsers();
349
272
  for (var i = 0; i < data.invites.length; i++) {
@@ -400,7 +323,10 @@ function removeExpiredInvites() {
400
323
 
401
324
  // --- Wire extracted modules ---
402
325
 
403
- var auth = attachAuth({ loadUsers: loadUsers, saveUsers: saveUsers, findAdmin: findAdmin });
326
+ var auth = attachAuth({ loadUsers: loadUsers, saveUsers: saveUsers, findAdmin: findAdmin, loadConfig: require('./config').loadConfig });
327
+ var creation = require("./users-create").attachCreation({ loadUsers: loadUsers, saveUsers: saveUsers, generateUserId: generateUserId, ensureUserBuiltinMates: ensureUserBuiltinMates, auth: auth });
328
+ var createUser = creation.createUser;
329
+ var createUserWithoutPin = creation.createUserWithoutPin;
404
330
  var permissions = attachPermissions({ loadUsers: loadUsers, saveUsers: saveUsers, findUserById: findUserById });
405
331
  var preferences = attachPreferences({ loadUsers: loadUsers, saveUsers: saveUsers });
406
332
  var projectMateFilterPreferences = attachProjectMateFilterPreferences({ loadUsers: loadUsers, saveUsers: saveUsers });
@@ -489,6 +415,7 @@ module.exports = {
489
415
  validateSetupCode: validateSetupCode,
490
416
  generateUserId: generateUserId,
491
417
  hashPin: hashPin,
418
+ verifyPin: auth.verifyPin,
492
419
  createUser: createUser,
493
420
  createAdmin: createAdmin,
494
421
  findAdmin: findAdmin,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "5.1.0",
3
+ "version": "5.2.0-beta.1",
4
4
  "description": "Self-hosted team workspace for Claude Code and Codex. Multi-user, browser-based, with persistent AI mates.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js"
@@ -60,6 +60,7 @@
60
60
  "@modelcontextprotocol/sdk": "^1.32.1",
61
61
  "@openai/codex": "^0.162.1",
62
62
  "@seald-io/nedb": "^4.1.2",
63
+ "@simplewebauthn/server": "13.3.3",
63
64
  "codemirror": "^5.65.21",
64
65
  "imapflow": "^1.7.8",
65
66
  "ipaddr.js": "^2.5.0",