@kurdel/auth-db 0.1.0-beta.4 → 0.1.0-beta.6
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/README.md +192 -96
- package/lib/api-key-hasher.d.ts +15 -0
- package/lib/api-key-hasher.js +6 -0
- package/lib/api-key-hasher.js.map +1 -1
- package/lib/auth-database-module.d.ts +28 -0
- package/lib/auth-database-module.js +23 -0
- package/lib/auth-database-module.js.map +1 -1
- package/lib/auth-database-tables.d.ts +26 -0
- package/lib/auth-database-tables.js +28 -1
- package/lib/auth-database-tables.js.map +1 -1
- package/lib/database-api-key-repository.d.ts +29 -0
- package/lib/database-api-key-repository.js +29 -0
- package/lib/database-api-key-repository.js.map +1 -1
- package/lib/database-api-key-service.d.ts +33 -0
- package/lib/database-api-key-service.js +33 -0
- package/lib/database-api-key-service.js.map +1 -1
- package/lib/database-api-key-usage-recorder.d.ts +25 -1
- package/lib/database-api-key-usage-recorder.js +25 -1
- package/lib/database-api-key-usage-recorder.js.map +1 -1
- package/lib/database-auth-event-sink-provider.d.ts +8 -0
- package/lib/database-auth-event-sink-provider.js +15 -0
- package/lib/database-auth-event-sink-provider.js.map +1 -0
- package/lib/database-auth-event-store.d.ts +28 -1
- package/lib/database-auth-event-store.js +37 -1
- package/lib/database-auth-event-store.js.map +1 -1
- package/lib/database-auth-user-repository.d.ts +28 -0
- package/lib/database-auth-user-repository.js +28 -0
- package/lib/database-auth-user-repository.js.map +1 -1
- package/lib/database-jwt-session-repository.d.ts +27 -1
- package/lib/database-jwt-session-repository.js +27 -1
- package/lib/database-jwt-session-repository.js.map +1 -1
- package/lib/database-jwt-session-service.d.ts +55 -1
- package/lib/database-jwt-session-service.js +182 -1
- package/lib/database-jwt-session-service.js.map +1 -1
- package/lib/database-password-credential-repository.d.ts +27 -0
- package/lib/database-password-credential-repository.js +27 -0
- package/lib/database-password-credential-repository.js.map +1 -1
- package/lib/database-password-service.d.ts +31 -0
- package/lib/database-password-service.js +31 -0
- package/lib/database-password-service.js.map +1 -1
- package/lib/database-user-service.d.ts +47 -13
- package/lib/database-user-service.js +273 -190
- package/lib/database-user-service.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/tokens.d.ts +8 -0
- package/lib/tokens.js +8 -0
- package/lib/tokens.js.map +1 -1
- package/package.json +5 -5
|
@@ -13,14 +13,55 @@ export class ActiveJwtSessionUserNotFoundError extends Error {
|
|
|
13
13
|
this.userId = userId;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
export class InvalidRefreshTokenError extends Error {
|
|
17
|
+
constructor() {
|
|
18
|
+
super('Refresh token is invalid or expired');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* ## DatabaseJwtSessionService
|
|
23
|
+
*
|
|
24
|
+
* Application service responsible for managing persistent JWT sessions
|
|
25
|
+
* backed by a relational database through the `Database` abstraction.
|
|
26
|
+
*
|
|
27
|
+
* Responsibilities:
|
|
28
|
+
* - create server-side JWT sessions
|
|
29
|
+
* - issue and rotate refresh tokens
|
|
30
|
+
* - list active and historical sessions
|
|
31
|
+
* - revoke individual or all user sessions
|
|
32
|
+
* - emit JWT session audit events
|
|
33
|
+
*
|
|
34
|
+
* Guarantees:
|
|
35
|
+
* - validates that sessions belong to active users
|
|
36
|
+
* - stores refresh tokens as SHA-256 hashes only
|
|
37
|
+
* - rotates refresh tokens atomically
|
|
38
|
+
* - performs all state changes inside database transactions
|
|
39
|
+
* - remains database-agnostic (SQLite/PostgreSQL)
|
|
40
|
+
*
|
|
41
|
+
* Non-responsibilities:
|
|
42
|
+
* - JWT signing or verification
|
|
43
|
+
* - access token generation
|
|
44
|
+
* - authorization policy evaluation
|
|
45
|
+
* - HTTP request handling
|
|
46
|
+
*/
|
|
17
47
|
export class DatabaseJwtSessionService {
|
|
48
|
+
/**
|
|
49
|
+
* Creates a new database-backed JWT session service.
|
|
50
|
+
*
|
|
51
|
+
* @param db Database abstraction used for persistence.
|
|
52
|
+
* @param tables Optional table name overrides.
|
|
53
|
+
* @param events Optional transactional audit event sink.
|
|
54
|
+
* @param now Time provider used for expiration checks and timestamps.
|
|
55
|
+
*/
|
|
18
56
|
constructor(db, tables = {}, events, now = () => new Date()) {
|
|
19
57
|
this.db = db;
|
|
20
58
|
this.events = events;
|
|
21
59
|
this.now = now;
|
|
22
60
|
this.tables = resolveAuthDatabaseTables(tables);
|
|
23
61
|
}
|
|
62
|
+
// ---------------------------------------------------------------------
|
|
63
|
+
// JWT session lyfecycle
|
|
64
|
+
// ---------------------------------------------------------------------
|
|
24
65
|
async create(userId, expiresAt) {
|
|
25
66
|
const expirationTime = expiresAt.getTime();
|
|
26
67
|
if (!Number.isFinite(expirationTime) || expirationTime <= this.now().getTime()) {
|
|
@@ -50,6 +91,137 @@ export class DatabaseJwtSessionService {
|
|
|
50
91
|
});
|
|
51
92
|
return { id, userId, expiresAt: expiresAt.toISOString() };
|
|
52
93
|
}
|
|
94
|
+
async createRefreshable(userId, refreshExpiresAt) {
|
|
95
|
+
const expirationTime = refreshExpiresAt.getTime();
|
|
96
|
+
if (!Number.isFinite(expirationTime) || expirationTime <= this.now().getTime()) {
|
|
97
|
+
throw new RangeError('JWT refresh session expiration must be in the future');
|
|
98
|
+
}
|
|
99
|
+
const id = crypto.randomUUID();
|
|
100
|
+
const refreshToken = this.generateRefreshToken();
|
|
101
|
+
await this.db.transaction(async (transaction) => {
|
|
102
|
+
const user = await transaction.get({
|
|
103
|
+
sql: `SELECT id FROM ${this.tables.users} WHERE id = ? AND status = 'active';`,
|
|
104
|
+
params: [userId],
|
|
105
|
+
});
|
|
106
|
+
if (!user)
|
|
107
|
+
throw new ActiveJwtSessionUserNotFoundError(userId);
|
|
108
|
+
await transaction.run({
|
|
109
|
+
sql: [
|
|
110
|
+
`INSERT INTO ${this.tables.jwtSessions}`,
|
|
111
|
+
'(id, user_id, status, expires_at) VALUES (?, ?, ?, ?);',
|
|
112
|
+
].join(' '),
|
|
113
|
+
params: [id, userId, 'active', refreshExpiresAt.toISOString()],
|
|
114
|
+
});
|
|
115
|
+
await transaction.run({
|
|
116
|
+
sql: [
|
|
117
|
+
`INSERT INTO ${this.tables.jwtRefreshTokens}`,
|
|
118
|
+
'(session_id, token_hash, expires_at) VALUES (?, ?, ?);',
|
|
119
|
+
].join(' '),
|
|
120
|
+
params: [id, this.hashRefreshToken(refreshToken), refreshExpiresAt.toISOString()],
|
|
121
|
+
});
|
|
122
|
+
await this.events?.report({
|
|
123
|
+
type: 'jwt-session.created',
|
|
124
|
+
occurredAt: this.now(),
|
|
125
|
+
userId,
|
|
126
|
+
credential: { type: 'jwt', id },
|
|
127
|
+
}, transaction);
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
id,
|
|
131
|
+
userId,
|
|
132
|
+
expiresAt: refreshExpiresAt.toISOString(),
|
|
133
|
+
refreshToken,
|
|
134
|
+
refreshExpiresAt: refreshExpiresAt.toISOString(),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
async refresh(refreshToken) {
|
|
138
|
+
const nextRefreshToken = this.generateRefreshToken();
|
|
139
|
+
const now = this.now();
|
|
140
|
+
return this.db.transaction(async (transaction) => {
|
|
141
|
+
const record = await transaction.get({
|
|
142
|
+
sql: [
|
|
143
|
+
'SELECT sessions.id, sessions.user_id, sessions.status,',
|
|
144
|
+
'refresh_tokens.expires_at AS refresh_expires_at',
|
|
145
|
+
`FROM ${this.tables.jwtRefreshTokens} AS refresh_tokens`,
|
|
146
|
+
`INNER JOIN ${this.tables.jwtSessions} AS sessions ON sessions.id = refresh_tokens.session_id`,
|
|
147
|
+
`INNER JOIN ${this.tables.users} AS users ON users.id = sessions.user_id`,
|
|
148
|
+
"WHERE refresh_tokens.token_hash = ? AND users.status = 'active';",
|
|
149
|
+
].join(' '),
|
|
150
|
+
params: [this.hashRefreshToken(refreshToken)],
|
|
151
|
+
});
|
|
152
|
+
const expiresAt = record ? new Date(record.refresh_expires_at) : undefined;
|
|
153
|
+
if (!record ||
|
|
154
|
+
record.status !== 'active' ||
|
|
155
|
+
!expiresAt ||
|
|
156
|
+
!Number.isFinite(expiresAt.getTime()) ||
|
|
157
|
+
expiresAt.getTime() <= now.getTime()) {
|
|
158
|
+
throw new InvalidRefreshTokenError();
|
|
159
|
+
}
|
|
160
|
+
await transaction.run({
|
|
161
|
+
sql: [
|
|
162
|
+
`UPDATE ${this.tables.jwtRefreshTokens}`,
|
|
163
|
+
'SET token_hash = ?, last_used_at = ? WHERE session_id = ?;',
|
|
164
|
+
].join(' '),
|
|
165
|
+
params: [this.hashRefreshToken(nextRefreshToken), now.toISOString(), record.id],
|
|
166
|
+
});
|
|
167
|
+
await this.events?.report({
|
|
168
|
+
type: 'jwt-session.refreshed',
|
|
169
|
+
occurredAt: now,
|
|
170
|
+
userId: Number(record.user_id),
|
|
171
|
+
credential: { type: 'jwt', id: record.id },
|
|
172
|
+
}, transaction);
|
|
173
|
+
return {
|
|
174
|
+
id: record.id,
|
|
175
|
+
userId: Number(record.user_id),
|
|
176
|
+
expiresAt: expiresAt.toISOString(),
|
|
177
|
+
refreshToken: nextRefreshToken,
|
|
178
|
+
refreshExpiresAt: expiresAt.toISOString(),
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// ---------------------------------------------------------------------
|
|
183
|
+
// Session management
|
|
184
|
+
// ---------------------------------------------------------------------
|
|
185
|
+
async list(userId) {
|
|
186
|
+
const now = this.now().getTime();
|
|
187
|
+
const records = await this.db.all({
|
|
188
|
+
sql: [
|
|
189
|
+
'SELECT id, user_id, status, expires_at, created_at',
|
|
190
|
+
`FROM ${this.tables.jwtSessions} WHERE user_id = ?`,
|
|
191
|
+
'ORDER BY created_at DESC, id DESC;',
|
|
192
|
+
].join(' '),
|
|
193
|
+
params: [userId],
|
|
194
|
+
});
|
|
195
|
+
return records.map(record => ({
|
|
196
|
+
id: record.id,
|
|
197
|
+
userId: Number(record.user_id),
|
|
198
|
+
status: record.status !== 'active'
|
|
199
|
+
? 'revoked'
|
|
200
|
+
: new Date(record.expires_at).getTime() <= now ? 'expired' : 'active',
|
|
201
|
+
expiresAt: new Date(record.expires_at).toISOString(),
|
|
202
|
+
createdAt: new Date(record.created_at).toISOString(),
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
async revokeAll(userId) {
|
|
206
|
+
await this.db.transaction(async (transaction) => {
|
|
207
|
+
const sessions = await transaction.all({
|
|
208
|
+
sql: `SELECT id FROM ${this.tables.jwtSessions} WHERE user_id = ? AND status = 'active';`,
|
|
209
|
+
params: [userId],
|
|
210
|
+
});
|
|
211
|
+
await transaction.run({
|
|
212
|
+
sql: `UPDATE ${this.tables.jwtSessions} SET status = 'revoked' WHERE user_id = ? AND status = 'active';`,
|
|
213
|
+
params: [userId],
|
|
214
|
+
});
|
|
215
|
+
for (const session of sessions) {
|
|
216
|
+
await this.events?.report({
|
|
217
|
+
type: 'jwt-session.revoked',
|
|
218
|
+
occurredAt: this.now(),
|
|
219
|
+
userId,
|
|
220
|
+
credential: { type: 'jwt', id: session.id },
|
|
221
|
+
}, transaction);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
53
225
|
async revoke(userId, sessionId) {
|
|
54
226
|
await this.db.transaction(async (transaction) => {
|
|
55
227
|
const session = await transaction.get({
|
|
@@ -70,5 +242,14 @@ export class DatabaseJwtSessionService {
|
|
|
70
242
|
}, transaction);
|
|
71
243
|
});
|
|
72
244
|
}
|
|
245
|
+
// ---------------------------------------------------------------------
|
|
246
|
+
// Security helpers
|
|
247
|
+
// ---------------------------------------------------------------------
|
|
248
|
+
generateRefreshToken() {
|
|
249
|
+
return `kdl_rt_${crypto.randomBytes(32).toString('base64url')}`;
|
|
250
|
+
}
|
|
251
|
+
hashRefreshToken(token) {
|
|
252
|
+
return crypto.createHash('sha256').update(token).digest('hex');
|
|
253
|
+
}
|
|
73
254
|
}
|
|
74
255
|
//# sourceMappingURL=database-jwt-session-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database-jwt-session-service.js","sourceRoot":"","sources":["../src/database-jwt-session-service.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAKjC,OAAO,EAAE,yBAAyB,EAA2B,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"database-jwt-session-service.js","sourceRoot":"","sources":["../src/database-jwt-session-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,36 @@
|
|
|
1
1
|
import type { PasswordCredential, PasswordCredentialRepository } from '@kurdel/auth';
|
|
2
2
|
import type { Database } from '@kurdel/db';
|
|
3
3
|
import { type AuthDatabaseTables } from './auth-database-tables.js';
|
|
4
|
+
/**
|
|
5
|
+
* ## DatabasePasswordCredentialRepository
|
|
6
|
+
*
|
|
7
|
+
* Database-backed repository for password authentication credentials.
|
|
8
|
+
*
|
|
9
|
+
* Responsibilities:
|
|
10
|
+
* - locate password credentials by login identifier
|
|
11
|
+
* - map database records to `PasswordCredential`
|
|
12
|
+
* - isolate authentication from the underlying database schema
|
|
13
|
+
*
|
|
14
|
+
* Guarantees:
|
|
15
|
+
* - returns `null` when no matching credentials exist
|
|
16
|
+
* - performs case-insensitive login lookup
|
|
17
|
+
* - remains database-agnostic (SQLite/PostgreSQL)
|
|
18
|
+
*
|
|
19
|
+
* Non-responsibilities:
|
|
20
|
+
* - password verification
|
|
21
|
+
* - password hashing
|
|
22
|
+
* - user management
|
|
23
|
+
* - authentication workflows
|
|
24
|
+
*/
|
|
4
25
|
export declare class DatabasePasswordCredentialRepository implements PasswordCredentialRepository {
|
|
5
26
|
private readonly db;
|
|
6
27
|
private readonly tables;
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new database-backed password credential repository.
|
|
30
|
+
*
|
|
31
|
+
* @param db Database abstraction used for persistence.
|
|
32
|
+
* @param tables Optional table name overrides.
|
|
33
|
+
*/
|
|
7
34
|
constructor(db: Database, tables?: Partial<AuthDatabaseTables>);
|
|
8
35
|
findByLogin(login: string): Promise<PasswordCredential | null>;
|
|
9
36
|
}
|
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
import { resolveAuthDatabaseTables } from './auth-database-tables.js';
|
|
2
|
+
/**
|
|
3
|
+
* ## DatabasePasswordCredentialRepository
|
|
4
|
+
*
|
|
5
|
+
* Database-backed repository for password authentication credentials.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - locate password credentials by login identifier
|
|
9
|
+
* - map database records to `PasswordCredential`
|
|
10
|
+
* - isolate authentication from the underlying database schema
|
|
11
|
+
*
|
|
12
|
+
* Guarantees:
|
|
13
|
+
* - returns `null` when no matching credentials exist
|
|
14
|
+
* - performs case-insensitive login lookup
|
|
15
|
+
* - remains database-agnostic (SQLite/PostgreSQL)
|
|
16
|
+
*
|
|
17
|
+
* Non-responsibilities:
|
|
18
|
+
* - password verification
|
|
19
|
+
* - password hashing
|
|
20
|
+
* - user management
|
|
21
|
+
* - authentication workflows
|
|
22
|
+
*/
|
|
2
23
|
export class DatabasePasswordCredentialRepository {
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new database-backed password credential repository.
|
|
26
|
+
*
|
|
27
|
+
* @param db Database abstraction used for persistence.
|
|
28
|
+
* @param tables Optional table name overrides.
|
|
29
|
+
*/
|
|
3
30
|
constructor(db, tables = {}) {
|
|
4
31
|
this.db = db;
|
|
5
32
|
this.tables = resolveAuthDatabaseTables(tables);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database-password-credential-repository.js","sourceRoot":"","sources":["../src/database-password-credential-repository.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAA2B,MAAM,2BAA2B,CAAC;AAI/F,MAAM,OAAO,oCAAoC;IAG/C,YACmB,EAAY,EAC7B,SAAsC,EAAE;QADvB,OAAE,GAAF,EAAE,CAAU;QAG7B,IAAI,CAAC,MAAM,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;YAChC,GAAG,EAAE;gBACH,8DAA8D,IAAI,CAAC,MAAM,CAAC,mBAAmB,cAAc;gBAC3G,cAAc,IAAI,CAAC,MAAM,CAAC,KAAK,0CAA0C;gBACzE,sCAAsC;aACvC,CAAC,IAAI,CAAC,GAAG,CAAC;YACX,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SACvB,CAAC,CAAiC,CAAC;QACpC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACxF,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"database-password-credential-repository.js","sourceRoot":"","sources":["../src/database-password-credential-repository.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAA2B,MAAM,2BAA2B,CAAC;AAI/F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,oCAAoC;IAG/C;;;;;OAKG;IACH,YACmB,EAAY,EAC7B,SAAsC,EAAE;QADvB,OAAE,GAAF,EAAE,CAAU;QAG7B,IAAI,CAAC,MAAM,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC;YAChC,GAAG,EAAE;gBACH,8DAA8D,IAAI,CAAC,MAAM,CAAC,mBAAmB,cAAc;gBAC3G,cAAc,IAAI,CAAC,MAAM,CAAC,KAAK,0CAA0C;gBACzE,sCAAsC;aACvC,CAAC,IAAI,CAAC,GAAG,CAAC;YACX,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SACvB,CAAC,CAAiC,CAAC;QACpC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACxF,CAAC;CACF"}
|
|
@@ -5,10 +5,41 @@ export declare class PasswordUserNotFoundError extends Error {
|
|
|
5
5
|
readonly userId: number;
|
|
6
6
|
constructor(userId: number);
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* ## DatabasePasswordService
|
|
10
|
+
*
|
|
11
|
+
* Application service responsible for managing user password credentials
|
|
12
|
+
* backed by a relational database through the `Database` abstraction.
|
|
13
|
+
*
|
|
14
|
+
* Responsibilities:
|
|
15
|
+
* - set or replace user password credentials
|
|
16
|
+
* - hash passwords before persisting them
|
|
17
|
+
* - ensure the target user exists
|
|
18
|
+
*
|
|
19
|
+
* Guarantees:
|
|
20
|
+
* - never stores plaintext passwords
|
|
21
|
+
* - delegates password hashing to the configured `PasswordHasher`
|
|
22
|
+
* - performs updates atomically using a database transaction
|
|
23
|
+
* - remains database-agnostic (SQLite/PostgreSQL)
|
|
24
|
+
*
|
|
25
|
+
* Non-responsibilities:
|
|
26
|
+
* - password verification
|
|
27
|
+
* - password policy enforcement
|
|
28
|
+
* - password reset workflows
|
|
29
|
+
* - authentication
|
|
30
|
+
* - HTTP request handling
|
|
31
|
+
*/
|
|
8
32
|
export declare class DatabasePasswordService {
|
|
9
33
|
private readonly db;
|
|
10
34
|
private readonly hasher;
|
|
11
35
|
private readonly tables;
|
|
36
|
+
/**
|
|
37
|
+
* Creates a new database-backed password management service.
|
|
38
|
+
*
|
|
39
|
+
* @param db Database abstraction used for persistence.
|
|
40
|
+
* @param hasher Password hasher used to derive secure password hashes.
|
|
41
|
+
* @param tables Optional table name overrides.
|
|
42
|
+
*/
|
|
12
43
|
constructor(db: Database, hasher: PasswordHasher, tables?: Partial<AuthDatabaseTables>);
|
|
13
44
|
set(userId: number, password: string): Promise<void>;
|
|
14
45
|
}
|
|
@@ -5,7 +5,38 @@ export class PasswordUserNotFoundError extends Error {
|
|
|
5
5
|
this.userId = userId;
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* ## DatabasePasswordService
|
|
10
|
+
*
|
|
11
|
+
* Application service responsible for managing user password credentials
|
|
12
|
+
* backed by a relational database through the `Database` abstraction.
|
|
13
|
+
*
|
|
14
|
+
* Responsibilities:
|
|
15
|
+
* - set or replace user password credentials
|
|
16
|
+
* - hash passwords before persisting them
|
|
17
|
+
* - ensure the target user exists
|
|
18
|
+
*
|
|
19
|
+
* Guarantees:
|
|
20
|
+
* - never stores plaintext passwords
|
|
21
|
+
* - delegates password hashing to the configured `PasswordHasher`
|
|
22
|
+
* - performs updates atomically using a database transaction
|
|
23
|
+
* - remains database-agnostic (SQLite/PostgreSQL)
|
|
24
|
+
*
|
|
25
|
+
* Non-responsibilities:
|
|
26
|
+
* - password verification
|
|
27
|
+
* - password policy enforcement
|
|
28
|
+
* - password reset workflows
|
|
29
|
+
* - authentication
|
|
30
|
+
* - HTTP request handling
|
|
31
|
+
*/
|
|
8
32
|
export class DatabasePasswordService {
|
|
33
|
+
/**
|
|
34
|
+
* Creates a new database-backed password management service.
|
|
35
|
+
*
|
|
36
|
+
* @param db Database abstraction used for persistence.
|
|
37
|
+
* @param hasher Password hasher used to derive secure password hashes.
|
|
38
|
+
* @param tables Optional table name overrides.
|
|
39
|
+
*/
|
|
9
40
|
constructor(db, hasher, tables = {}) {
|
|
10
41
|
this.db = db;
|
|
11
42
|
this.hasher = hasher;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database-password-service.js","sourceRoot":"","sources":["../src/database-password-service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAA2B,MAAM,2BAA2B,CAAC;AAE/F,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,YAAqB,MAAc;QACjC,KAAK,CAAC,SAAS,MAAM,iBAAiB,CAAC,CAAC;QADrB,WAAM,GAAN,MAAM,CAAQ;IAEnC,CAAC;CACF;AAED,MAAM,OAAO,uBAAuB;IAGlC,YACmB,EAAY,EACZ,MAAsB,EACvC,SAAsC,EAAE;QAFvB,OAAE,GAAF,EAAE,CAAU;QACZ,WAAM,GAAN,MAAM,CAAgB;QAGvC,IAAI,CAAC,MAAM,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAc,EAAE,QAAgB;QACxC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAC,WAAW,EAAC,EAAE;YAC5C,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC;gBACjC,GAAG,EAAE,kBAAkB,IAAI,CAAC,MAAM,CAAC,KAAK,gBAAgB;gBACxD,MAAM,EAAE,CAAC,MAAM,CAAC;aACjB,CAAC,CAAC;YACH,IAAI,CAAC,IAAI;gBAAE,MAAM,IAAI,yBAAyB,CAAC,MAAM,CAAC,CAAC;YACvD,MAAM,WAAW,CAAC,GAAG,CAAC;gBACpB,GAAG,EAAE;oBACH,eAAe,IAAI,CAAC,MAAM,CAAC,mBAAmB,uCAAuC;oBACrF,kCAAkC;oBAClC,4GAA4G;iBAC7G,CAAC,IAAI,CAAC,GAAG,CAAC;gBACX,MAAM,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC;aAC/B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"database-password-service.js","sourceRoot":"","sources":["../src/database-password-service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAA2B,MAAM,2BAA2B,CAAC;AAE/F,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,YAAqB,MAAc;QACjC,KAAK,CAAC,SAAS,MAAM,iBAAiB,CAAC,CAAC;QADrB,WAAM,GAAN,MAAM,CAAQ;IAEnC,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,OAAO,uBAAuB;IAGlC;;;;;;OAMG;IACH,YACmB,EAAY,EACZ,MAAsB,EACvC,SAAsC,EAAE;QAFvB,OAAE,GAAF,EAAE,CAAU;QACZ,WAAM,GAAN,MAAM,CAAgB;QAGvC,IAAI,CAAC,MAAM,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAc,EAAE,QAAgB;QACxC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAC,WAAW,EAAC,EAAE;YAC5C,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC;gBACjC,GAAG,EAAE,kBAAkB,IAAI,CAAC,MAAM,CAAC,KAAK,gBAAgB;gBACxD,MAAM,EAAE,CAAC,MAAM,CAAC;aACjB,CAAC,CAAC;YACH,IAAI,CAAC,IAAI;gBAAE,MAAM,IAAI,yBAAyB,CAAC,MAAM,CAAC,CAAC;YACvD,MAAM,WAAW,CAAC,GAAG,CAAC;gBACpB,GAAG,EAAE;oBACH,eAAe,IAAI,CAAC,MAAM,CAAC,mBAAmB,uCAAuC;oBACrF,kCAAkC;oBAClC,4GAA4G;iBAC7G,CAAC,IAAI,CAAC,GAAG,CAAC;gBACX,MAAM,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC;aAC/B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -89,36 +89,70 @@ export declare class RoleInUseError extends Error {
|
|
|
89
89
|
readonly userCount: number;
|
|
90
90
|
constructor(roleId: number, userCount: number);
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* ## DatabaseUserService
|
|
94
|
+
*
|
|
95
|
+
* Application service responsible for user, role and permission management
|
|
96
|
+
* backed by a relational database through the `Database` abstraction.
|
|
97
|
+
*
|
|
98
|
+
* Responsibilities:
|
|
99
|
+
* - manage users and their lifecycle
|
|
100
|
+
* - assign and revoke user roles
|
|
101
|
+
* - manage roles and role permissions
|
|
102
|
+
* - provide paginated user listings
|
|
103
|
+
* - execute bulk user operations
|
|
104
|
+
* - expose dashboard statistics
|
|
105
|
+
*
|
|
106
|
+
* Guarantees:
|
|
107
|
+
* - validates referenced roles and permissions before persisting changes
|
|
108
|
+
* - keeps user-role relationships consistent using database transactions
|
|
109
|
+
* - translates database constraint violations into domain-specific errors
|
|
110
|
+
* - remains database-agnostic (SQLite/PostgreSQL)
|
|
111
|
+
*
|
|
112
|
+
* Non-responsibilities:
|
|
113
|
+
* - authentication
|
|
114
|
+
* - authorization policy evaluation
|
|
115
|
+
* - password management
|
|
116
|
+
* - JWT or API key validation
|
|
117
|
+
* - HTTP request handling
|
|
118
|
+
*/
|
|
92
119
|
export declare class DatabaseUserService {
|
|
93
120
|
private readonly db;
|
|
94
121
|
private readonly tables;
|
|
122
|
+
/**
|
|
123
|
+
* Creates a new database-backed user management service.
|
|
124
|
+
*
|
|
125
|
+
* @param db Database abstraction used for all persistence operations.
|
|
126
|
+
* @param tables Optional table name overrides.
|
|
127
|
+
*/
|
|
95
128
|
constructor(db: Database, tables?: Partial<AuthDatabaseTables>);
|
|
96
|
-
listRoles(): Promise<string[]>;
|
|
97
|
-
listRoleSummaries(): Promise<RoleSummary[]>;
|
|
98
|
-
listPermissions(): Promise<string[]>;
|
|
99
|
-
setRolePermissions(roleId: number, names: string[]): Promise<RoleSummary>;
|
|
100
|
-
createRole(name: string): Promise<RoleSummary>;
|
|
101
|
-
renameRole(roleId: number, name: string): Promise<RoleSummary>;
|
|
102
|
-
deleteRole(roleId: number): Promise<void>;
|
|
103
129
|
create(input: CreateUserInput): Promise<ManagedUser>;
|
|
104
|
-
list(input: ListUsersInput): Promise<UserList>;
|
|
105
|
-
bulkUpdate(input: BulkUpdateUsersInput): Promise<ManagedUser[]>;
|
|
106
|
-
bulkDelete(userIds: number[]): Promise<void>;
|
|
107
|
-
dashboardStats(): Promise<AdminDashboardStats>;
|
|
108
|
-
findById(userId: number): Promise<ManagedUser>;
|
|
109
130
|
update(userId: number, input: UpdateUserInput): Promise<ManagedUser>;
|
|
110
131
|
delete(userId: number): Promise<void>;
|
|
132
|
+
findById(userId: number): Promise<ManagedUser>;
|
|
111
133
|
private findRecord;
|
|
134
|
+
list(input: ListUsersInput): Promise<UserList>;
|
|
135
|
+
bulkUpdate(input: BulkUpdateUsersInput): Promise<ManagedUser[]>;
|
|
136
|
+
bulkDelete(userIds: number[]): Promise<void>;
|
|
137
|
+
createRole(name: string): Promise<RoleSummary>;
|
|
138
|
+
renameRole(roleId: number, name: string): Promise<RoleSummary>;
|
|
139
|
+
deleteRole(roleId: number): Promise<void>;
|
|
140
|
+
listRoles(): Promise<string[]>;
|
|
141
|
+
listRoleSummaries(): Promise<RoleSummary[]>;
|
|
112
142
|
private findRole;
|
|
143
|
+
listPermissions(): Promise<string[]>;
|
|
144
|
+
setRolePermissions(roleId: number, names: string[]): Promise<RoleSummary>;
|
|
145
|
+
dashboardStats(): Promise<AdminDashboardStats>;
|
|
113
146
|
private ensureUsersExist;
|
|
114
147
|
private resolveRoles;
|
|
115
148
|
private resolvePermissions;
|
|
116
149
|
private loadRolePermissions;
|
|
117
|
-
private replaceRoles;
|
|
118
150
|
private loadRoles;
|
|
151
|
+
private replaceRoles;
|
|
119
152
|
private mapUser;
|
|
120
153
|
private normalizeEmail;
|
|
121
154
|
private rethrowEmailConflict;
|
|
122
155
|
private rethrowRoleConflict;
|
|
123
156
|
private isUniqueConstraintError;
|
|
157
|
+
private toCount;
|
|
124
158
|
}
|