clay-server 5.1.1-beta.1 → 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.
- package/lib/account-auth-policy.js +21 -0
- package/lib/account-auth-socket.js +29 -0
- package/lib/account-auth-throttle.js +44 -0
- package/lib/account-auth-transport.js +48 -0
- package/lib/account-login-page.js +28 -0
- package/lib/account-passkey-challenges.js +31 -0
- package/lib/account-passkey-page.js +89 -0
- package/lib/account-passkey-policy.js +39 -0
- package/lib/account-password-page.js +69 -0
- package/lib/account-passwords.js +36 -0
- package/lib/account-remembered.js +77 -0
- package/lib/account-session-page.js +51 -0
- package/lib/account-session-store.js +82 -0
- package/lib/daemon.js +2 -0
- package/lib/migrate-single-user.js +3 -23
- package/lib/project-server-settings.js +1 -0
- package/lib/project-user-knowledge.js +2 -1
- package/lib/public/auth/account-login.css +98 -0
- package/lib/public/auth/account-login.js +104 -0
- package/lib/public/css/user-settings-sessions.css +42 -0
- package/lib/public/index.html +17 -5
- package/lib/public/modules/account-auth-settings.js +71 -0
- package/lib/public/modules/account-transport-settings.js +51 -0
- package/lib/public/modules/app-messages.js +4 -0
- package/lib/public/modules/passkey-browser.js +69 -0
- package/lib/public/modules/passkey-server-settings.js +57 -0
- package/lib/public/modules/project-logs-render.js +3 -2
- package/lib/public/modules/server-settings-controls.js +10 -0
- package/lib/public/modules/server-settings.js +7 -2
- package/lib/public/modules/user-settings-account.js +14 -1
- package/lib/public/modules/user-settings-sessions.js +120 -0
- package/lib/public/modules/user-settings.js +3 -0
- package/lib/public/modules/you-activity.js +3 -1
- package/lib/public/modules/you.js +91 -6
- package/lib/public/style.css +1 -0
- package/lib/server-account-passkeys.js +186 -0
- package/lib/server-account-passwords.js +127 -0
- package/lib/server-account-security.js +53 -0
- package/lib/server-auth.js +107 -79
- package/lib/server-settings.js +2 -1
- package/lib/server.js +2 -0
- package/lib/user-knowledge-service.js +23 -1
- package/lib/users-auth.js +38 -3
- package/lib/users-create.js +97 -0
- package/lib/users-server-pin.js +37 -0
- package/lib/users.js +11 -84
- 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.
|
|
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",
|