@naisys/supervisor-database 3.0.0-beta.4 → 3.0.0-beta.5
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/dist/dbConfig.js +2 -2
- package/dist/generated/prisma/browser.js +4 -4
- package/dist/generated/prisma/client.js +5 -5
- package/dist/generated/prisma/commonInputTypes.js +1 -1
- package/dist/generated/prisma/enums.js +12 -12
- package/dist/generated/prisma/internal/class.js +36 -28
- package/dist/generated/prisma/internal/prismaNamespace.js +42 -39
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +34 -34
- package/dist/index.js +17 -2
- package/dist/migrationHelper.js +5 -5
- package/dist/prismaClient.js +12 -12
- package/dist/sessionService.js +135 -139
- package/package.json +6 -4
- package/dist/dbConfig.d.ts +0 -5
- package/dist/generated/prisma/browser.d.ts +0 -25
- package/dist/generated/prisma/client.d.ts +0 -44
- package/dist/generated/prisma/commonInputTypes.d.ts +0 -341
- package/dist/generated/prisma/enums.d.ts +0 -11
- package/dist/generated/prisma/internal/class.d.ts +0 -164
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +0 -775
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +0 -82
- package/dist/generated/prisma/models/SchemaVersion.d.ts +0 -984
- package/dist/generated/prisma/models/Session.d.ts +0 -1212
- package/dist/generated/prisma/models/User.d.ts +0 -1546
- package/dist/generated/prisma/models/UserPermission.d.ts +0 -1354
- package/dist/generated/prisma/models.d.ts +0 -6
- package/dist/index.d.ts +0 -8
- package/dist/migrationHelper.d.ts +0 -2
- package/dist/prismaClient.d.ts +0 -7
- package/dist/sessionService.d.ts +0 -88
package/dist/sessionService.js
CHANGED
|
@@ -14,195 +14,191 @@ let supervisorDb = null;
|
|
|
14
14
|
* No-ops gracefully if NAISYS_FOLDER is unset or the database doesn't exist.
|
|
15
15
|
*/
|
|
16
16
|
export async function createSupervisorDatabaseClient() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
supervisorDb = await createPrismaClient(dbPath);
|
|
23
|
-
return true;
|
|
17
|
+
if (supervisorDb) return true;
|
|
18
|
+
const dbPath = supervisorDbPath();
|
|
19
|
+
if (!existsSync(dbPath)) return false;
|
|
20
|
+
supervisorDb = await createPrismaClient(dbPath);
|
|
21
|
+
return true;
|
|
24
22
|
}
|
|
25
23
|
/**
|
|
26
24
|
* Find a session user by session token hash. Returns null if not found or expired.
|
|
27
25
|
*/
|
|
28
26
|
export async function findSession(tokenHash) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
uuid: session.user.uuid,
|
|
45
|
-
};
|
|
27
|
+
if (!supervisorDb) return null;
|
|
28
|
+
const session = await supervisorDb.session.findUnique({
|
|
29
|
+
where: {
|
|
30
|
+
tokenHash,
|
|
31
|
+
expiresAt: { gt: new Date() },
|
|
32
|
+
},
|
|
33
|
+
include: { user: true },
|
|
34
|
+
});
|
|
35
|
+
if (!session) return null;
|
|
36
|
+
return {
|
|
37
|
+
userId: session.user.id,
|
|
38
|
+
username: session.user.username,
|
|
39
|
+
passwordHash: session.user.passwordHash,
|
|
40
|
+
uuid: session.user.uuid,
|
|
41
|
+
};
|
|
46
42
|
}
|
|
47
43
|
/**
|
|
48
44
|
* Look up a session user by username.
|
|
49
45
|
*/
|
|
50
46
|
export async function lookupUsername(username) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
uuid: user.uuid,
|
|
63
|
-
};
|
|
47
|
+
if (!supervisorDb) return null;
|
|
48
|
+
const user = await supervisorDb.user.findUnique({
|
|
49
|
+
where: { username },
|
|
50
|
+
});
|
|
51
|
+
if (!user) return null;
|
|
52
|
+
return {
|
|
53
|
+
userId: user.id,
|
|
54
|
+
username: user.username,
|
|
55
|
+
passwordHash: user.passwordHash,
|
|
56
|
+
uuid: user.uuid,
|
|
57
|
+
};
|
|
64
58
|
}
|
|
65
59
|
/**
|
|
66
60
|
* Find a supervisor user by API key. Returns null if not found or DB not initialized.
|
|
67
61
|
*/
|
|
68
62
|
export async function findUserByApiKey(apiKey) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return user;
|
|
63
|
+
if (!supervisorDb) return null;
|
|
64
|
+
const user = await supervisorDb.user.findUnique({
|
|
65
|
+
where: { apiKey },
|
|
66
|
+
select: { uuid: true, username: true },
|
|
67
|
+
});
|
|
68
|
+
return user;
|
|
76
69
|
}
|
|
77
70
|
/**
|
|
78
71
|
* Authenticate a user by username/password and create a session.
|
|
79
72
|
* Returns null if credentials are invalid or DB is not initialized.
|
|
80
73
|
*/
|
|
81
74
|
export async function authenticateAndCreateSession(username, password) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
});
|
|
101
|
-
return { token, user, expiresAt };
|
|
75
|
+
const user = await lookupUsername(username);
|
|
76
|
+
if (!user) return null;
|
|
77
|
+
const valid = await bcrypt.compare(password, user.passwordHash);
|
|
78
|
+
if (!valid) return null;
|
|
79
|
+
const token = randomUUID();
|
|
80
|
+
const tokenHash = hashToken(token);
|
|
81
|
+
const expiresAt = new Date(Date.now() + SESSION_DURATION_MS);
|
|
82
|
+
const dbUser = await supervisorDb.user.findUnique({
|
|
83
|
+
where: { username },
|
|
84
|
+
});
|
|
85
|
+
await supervisorDb.session.create({
|
|
86
|
+
data: {
|
|
87
|
+
userId: dbUser.id,
|
|
88
|
+
tokenHash,
|
|
89
|
+
expiresAt,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
return { token, user, expiresAt };
|
|
102
93
|
}
|
|
103
94
|
/**
|
|
104
95
|
* Update a user's password hash. No-op if not initialized.
|
|
105
96
|
*/
|
|
106
97
|
export async function updateUserPassword(username, passwordHash) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
});
|
|
98
|
+
if (!supervisorDb) return;
|
|
99
|
+
await supervisorDb.user.update({
|
|
100
|
+
where: { username },
|
|
101
|
+
data: { passwordHash },
|
|
102
|
+
});
|
|
113
103
|
}
|
|
114
104
|
/**
|
|
115
105
|
* Delete a session by token hash.
|
|
116
106
|
*/
|
|
117
107
|
export async function deleteSession(tokenHash) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
});
|
|
108
|
+
if (!supervisorDb) return;
|
|
109
|
+
await supervisorDb.session.deleteMany({
|
|
110
|
+
where: { tokenHash },
|
|
111
|
+
});
|
|
123
112
|
}
|
|
124
113
|
/**
|
|
125
114
|
* Ensure a "superadmin" user exists in the supervisor database.
|
|
126
115
|
* If already exists, returns it as-is. Otherwise creates with generated credentials.
|
|
127
116
|
*/
|
|
128
117
|
export async function ensureSuperAdmin() {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (existing) {
|
|
135
|
-
return {
|
|
136
|
-
created: false,
|
|
137
|
-
user: {
|
|
138
|
-
uuid: existing.uuid,
|
|
139
|
-
username: existing.username,
|
|
140
|
-
passwordHash: existing.passwordHash,
|
|
141
|
-
apiKey: existing.apiKey,
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
const uuid = randomUUID();
|
|
146
|
-
const password = randomUUID().slice(0, 8);
|
|
147
|
-
const passwordHash = await bcrypt.hash(password, 10);
|
|
148
|
-
const apiKey = randomBytes(32).toString("hex");
|
|
149
|
-
const user = await supervisorDb.user.create({
|
|
150
|
-
data: { uuid, username: SUPER_ADMIN_USERNAME, passwordHash, apiKey },
|
|
151
|
-
});
|
|
152
|
-
await supervisorDb.userPermission.create({
|
|
153
|
-
data: { userId: user.id, permission: "supervisor_admin" },
|
|
154
|
-
});
|
|
118
|
+
if (!supervisorDb) throw new Error("Supervisor DB not initialized");
|
|
119
|
+
const existing = await supervisorDb.user.findUnique({
|
|
120
|
+
where: { username: SUPER_ADMIN_USERNAME },
|
|
121
|
+
});
|
|
122
|
+
if (existing) {
|
|
155
123
|
return {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
124
|
+
created: false,
|
|
125
|
+
user: {
|
|
126
|
+
uuid: existing.uuid,
|
|
127
|
+
username: existing.username,
|
|
128
|
+
passwordHash: existing.passwordHash,
|
|
129
|
+
apiKey: existing.apiKey,
|
|
130
|
+
},
|
|
159
131
|
};
|
|
132
|
+
}
|
|
133
|
+
const uuid = randomUUID();
|
|
134
|
+
const password = randomUUID().slice(0, 8);
|
|
135
|
+
const passwordHash = await bcrypt.hash(password, 10);
|
|
136
|
+
const apiKey = randomBytes(32).toString("hex");
|
|
137
|
+
const user = await supervisorDb.user.create({
|
|
138
|
+
data: { uuid, username: SUPER_ADMIN_USERNAME, passwordHash, apiKey },
|
|
139
|
+
});
|
|
140
|
+
await supervisorDb.userPermission.create({
|
|
141
|
+
data: { userId: user.id, permission: "supervisor_admin" },
|
|
142
|
+
});
|
|
143
|
+
return {
|
|
144
|
+
created: true,
|
|
145
|
+
generatedPassword: password,
|
|
146
|
+
user: { uuid, username: SUPER_ADMIN_USERNAME, passwordHash, apiKey },
|
|
147
|
+
};
|
|
160
148
|
}
|
|
161
149
|
/**
|
|
162
150
|
* CLI entry point for --reset-password. Initializes supervisor sessions,
|
|
163
151
|
* then runs the interactive password reset.
|
|
164
152
|
*/
|
|
165
153
|
export async function handleResetPassword(options) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
154
|
+
console.log(`NAISYS_FOLDER: ${process.env.NAISYS_FOLDER}`);
|
|
155
|
+
await createSupervisorDatabaseClient();
|
|
156
|
+
await resetPassword(
|
|
157
|
+
options.findLocalUser,
|
|
158
|
+
options.updateLocalPassword,
|
|
159
|
+
options.username,
|
|
160
|
+
options.password,
|
|
161
|
+
);
|
|
169
162
|
}
|
|
170
163
|
/**
|
|
171
164
|
* CLI to reset a user's password. Updates both local DB (via callbacks) and
|
|
172
165
|
* the supervisor DB. If username/password are provided, skips interactive
|
|
173
166
|
* prompts.
|
|
174
167
|
*/
|
|
175
|
-
export async function resetPassword(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (!user) {
|
|
197
|
-
console.error(`User '${username}' not found.`);
|
|
198
|
-
process.exit(1);
|
|
199
|
-
}
|
|
200
|
-
if (password.length < 6) {
|
|
201
|
-
console.error("Password must be at least 6 characters.");
|
|
202
|
-
process.exit(1);
|
|
168
|
+
export async function resetPassword(
|
|
169
|
+
findLocalUser,
|
|
170
|
+
updateLocalPassword,
|
|
171
|
+
usernameArg,
|
|
172
|
+
passwordArg,
|
|
173
|
+
) {
|
|
174
|
+
let username;
|
|
175
|
+
let password;
|
|
176
|
+
if (usernameArg && passwordArg) {
|
|
177
|
+
username = usernameArg;
|
|
178
|
+
password = passwordArg;
|
|
179
|
+
} else {
|
|
180
|
+
const rl = readline.createInterface({
|
|
181
|
+
input: process.stdin,
|
|
182
|
+
output: process.stdout,
|
|
183
|
+
});
|
|
184
|
+
try {
|
|
185
|
+
username = usernameArg || (await rl.question("Username: "));
|
|
186
|
+
password = passwordArg || (await rl.question("New password: "));
|
|
187
|
+
} finally {
|
|
188
|
+
rl.close();
|
|
203
189
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
console.
|
|
190
|
+
}
|
|
191
|
+
const user = await findLocalUser(username);
|
|
192
|
+
if (!user) {
|
|
193
|
+
console.error(`User '${username}' not found.`);
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
if (password.length < 6) {
|
|
197
|
+
console.error("Password must be at least 6 characters.");
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
const hash = await bcrypt.hash(password, 10);
|
|
201
|
+
await updateLocalPassword(user.id, hash);
|
|
202
|
+
await updateUserPassword(username, hash);
|
|
203
|
+
console.log(`Password reset for '${username}'.`);
|
|
208
204
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naisys/supervisor-database",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "[internal] Supervisor database schema and Prisma client for NAISYS",
|
|
6
6
|
"files": [
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
"prisma.config.ts",
|
|
9
9
|
"prisma/schema.prisma",
|
|
10
10
|
"prisma/migrations",
|
|
11
|
-
"!dist/**/*.map"
|
|
11
|
+
"!dist/**/*.map",
|
|
12
|
+
"!dist/**/*.d.ts",
|
|
13
|
+
"!dist/**/*.d.ts.map"
|
|
12
14
|
],
|
|
13
15
|
"scripts": {
|
|
14
16
|
"clean": "rimraf dist",
|
|
@@ -24,8 +26,8 @@
|
|
|
24
26
|
"typescript": "^5.9.3"
|
|
25
27
|
},
|
|
26
28
|
"dependencies": {
|
|
27
|
-
"@naisys/common": "3.0.0-beta.
|
|
28
|
-
"@naisys/common-node": "3.0.0-beta.
|
|
29
|
+
"@naisys/common": "3.0.0-beta.5",
|
|
30
|
+
"@naisys/common-node": "3.0.0-beta.5",
|
|
29
31
|
"bcryptjs": "^3.0.2",
|
|
30
32
|
"@prisma/adapter-better-sqlite3": "^7.5.0",
|
|
31
33
|
"@prisma/client": "^7.5.0",
|
package/dist/dbConfig.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export declare function supervisorDbPath(): string;
|
|
2
|
-
export declare function supervisorDbUrl(): string;
|
|
3
|
-
/** We run migration scripts if this is greater than what's in the schema_version table */
|
|
4
|
-
export declare const SUPERVISOR_DB_VERSION = 8;
|
|
5
|
-
//# sourceMappingURL=dbConfig.d.ts.map
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import * as Prisma from './internal/prismaNamespaceBrowser.js';
|
|
2
|
-
export { Prisma };
|
|
3
|
-
export * as $Enums from './enums.js';
|
|
4
|
-
export * from './enums.js';
|
|
5
|
-
/**
|
|
6
|
-
* Model User
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
export type User = Prisma.UserModel;
|
|
10
|
-
/**
|
|
11
|
-
* Model Session
|
|
12
|
-
*
|
|
13
|
-
*/
|
|
14
|
-
export type Session = Prisma.SessionModel;
|
|
15
|
-
/**
|
|
16
|
-
* Model UserPermission
|
|
17
|
-
*
|
|
18
|
-
*/
|
|
19
|
-
export type UserPermission = Prisma.UserPermissionModel;
|
|
20
|
-
/**
|
|
21
|
-
* Model SchemaVersion
|
|
22
|
-
*
|
|
23
|
-
*/
|
|
24
|
-
export type SchemaVersion = Prisma.SchemaVersionModel;
|
|
25
|
-
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import * as runtime from "@prisma/client/runtime/client";
|
|
2
|
-
import * as $Class from "./internal/class.js";
|
|
3
|
-
import * as Prisma from "./internal/prismaNamespace.js";
|
|
4
|
-
export * as $Enums from './enums.js';
|
|
5
|
-
export * from "./enums.js";
|
|
6
|
-
/**
|
|
7
|
-
* ## Prisma Client
|
|
8
|
-
*
|
|
9
|
-
* Type-safe database client for TypeScript
|
|
10
|
-
* @example
|
|
11
|
-
* ```
|
|
12
|
-
* const prisma = new PrismaClient({
|
|
13
|
-
* adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL })
|
|
14
|
-
* })
|
|
15
|
-
* // Fetch zero or more Users
|
|
16
|
-
* const users = await prisma.user.findMany()
|
|
17
|
-
* ```
|
|
18
|
-
*
|
|
19
|
-
* Read more in our [docs](https://pris.ly/d/client).
|
|
20
|
-
*/
|
|
21
|
-
export declare const PrismaClient: $Class.PrismaClientConstructor;
|
|
22
|
-
export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>;
|
|
23
|
-
export { Prisma };
|
|
24
|
-
/**
|
|
25
|
-
* Model User
|
|
26
|
-
*
|
|
27
|
-
*/
|
|
28
|
-
export type User = Prisma.UserModel;
|
|
29
|
-
/**
|
|
30
|
-
* Model Session
|
|
31
|
-
*
|
|
32
|
-
*/
|
|
33
|
-
export type Session = Prisma.SessionModel;
|
|
34
|
-
/**
|
|
35
|
-
* Model UserPermission
|
|
36
|
-
*
|
|
37
|
-
*/
|
|
38
|
-
export type UserPermission = Prisma.UserPermissionModel;
|
|
39
|
-
/**
|
|
40
|
-
* Model SchemaVersion
|
|
41
|
-
*
|
|
42
|
-
*/
|
|
43
|
-
export type SchemaVersion = Prisma.SchemaVersionModel;
|
|
44
|
-
//# sourceMappingURL=client.d.ts.map
|