@kollors/deep-json-server 1.0.0-alpha.7 → 1.0.0-alpha.9
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 +168 -109
- package/README.ru.md +171 -112
- package/dist/index.d.ts +5 -6
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/src/auth/contract.d.ts +6 -2
- package/dist/src/auth/contract.js +8 -1
- package/dist/src/auth/contract.js.map +1 -1
- package/dist/src/auth/input.d.ts +18 -0
- package/dist/src/auth/input.js +34 -0
- package/dist/src/auth/input.js.map +1 -0
- package/dist/src/auth/password.d.ts +4 -0
- package/dist/src/auth/password.js +5 -1
- package/dist/src/auth/password.js.map +1 -1
- package/dist/src/auth/routes.d.ts +1 -1
- package/dist/src/auth/routes.js +4 -1
- package/dist/src/auth/routes.js.map +1 -1
- package/dist/src/auth/service.d.ts +48 -9
- package/dist/src/auth/service.js +143 -68
- package/dist/src/auth/service.js.map +1 -1
- package/dist/src/auth/store.d.ts +26 -0
- package/dist/src/auth/store.js +82 -0
- package/dist/src/auth/store.js.map +1 -0
- package/dist/src/cli/index.d.ts +2 -2
- package/dist/src/cli/index.js +70 -84
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/core/config-values.d.ts +28 -0
- package/dist/src/core/config-values.js +53 -0
- package/dist/src/core/config-values.js.map +1 -0
- package/dist/src/core/constants.d.ts +1 -1
- package/dist/src/core/constants.js +1 -1
- package/dist/src/core/database.d.ts +10 -12
- package/dist/src/core/database.js +4 -4
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/engine.d.ts +3 -2
- package/dist/src/core/engine.js +53 -44
- package/dist/src/core/engine.js.map +1 -1
- package/dist/src/core/lifecycle/mutation.d.ts +3 -3
- package/dist/src/core/lifecycle/mutation.js +2 -2
- package/dist/src/core/lifecycle/mutation.js.map +1 -1
- package/dist/src/core/lifecycle/options.d.ts +1 -0
- package/dist/src/core/lifecycle/options.js +2 -4
- package/dist/src/core/lifecycle/options.js.map +1 -1
- package/dist/src/core/model.d.ts +18 -3
- package/dist/src/core/model.js +17 -7
- package/dist/src/core/model.js.map +1 -1
- package/dist/src/core/mutations/write.d.ts +1 -2
- package/dist/src/core/mutations/write.js.map +1 -1
- package/dist/src/core/operations.d.ts +33 -0
- package/dist/src/core/operations.js +10 -0
- package/dist/src/core/operations.js.map +1 -0
- package/dist/src/core/pagination.d.ts +2 -2
- package/dist/src/core/pagination.js +3 -5
- package/dist/src/core/pagination.js.map +1 -1
- package/dist/src/core/paths.d.ts +2 -2
- package/dist/src/core/paths.js +15 -5
- package/dist/src/core/paths.js.map +1 -1
- package/dist/src/core/storage.d.ts +2 -0
- package/dist/src/core/storage.js +2 -0
- package/dist/src/core/storage.js.map +1 -0
- package/dist/src/files/contract.d.ts +6 -7
- package/dist/src/files/contract.js.map +1 -1
- package/dist/src/files/disk-store.js +3 -20
- package/dist/src/files/disk-store.js.map +1 -1
- package/dist/src/files/index.d.ts +1 -1
- package/dist/src/files/index.js +5 -2
- package/dist/src/files/index.js.map +1 -1
- package/dist/src/files/memory-store.js +16 -16
- package/dist/src/files/memory-store.js.map +1 -1
- package/dist/src/files/streams.d.ts +5 -0
- package/dist/src/files/streams.js +20 -0
- package/dist/src/files/streams.js.map +1 -0
- package/dist/src/graphql/entry.d.ts +11 -2
- package/dist/src/graphql/entry.js +12 -2
- package/dist/src/graphql/entry.js.map +1 -1
- package/dist/src/graphql/{public.d.ts → generate.d.ts} +3 -2
- package/dist/src/graphql/{public.js → generate.js} +4 -2
- package/dist/src/graphql/generate.js.map +1 -0
- package/dist/src/graphql/resolvers.js +1 -1
- package/dist/src/graphql/resolvers.js.map +1 -1
- package/dist/src/graphql/schema.js +6 -3
- package/dist/src/graphql/schema.js.map +1 -1
- package/dist/src/openapi/auth.d.ts +2 -2
- package/dist/src/openapi/auth.js +82 -15
- package/dist/src/openapi/auth.js.map +1 -1
- package/dist/src/openapi/document.js +16 -13
- package/dist/src/openapi/document.js.map +1 -1
- package/dist/src/openapi/entry.d.ts +12 -1
- package/dist/src/openapi/entry.js +12 -1
- package/dist/src/openapi/entry.js.map +1 -1
- package/dist/src/openapi/{public.d.ts → generate.d.ts} +9 -16
- package/dist/src/openapi/generate.js +41 -0
- package/dist/src/openapi/generate.js.map +1 -0
- package/dist/src/openapi/options.d.ts +18 -0
- package/dist/src/openapi/options.js +13 -0
- package/dist/src/openapi/options.js.map +1 -0
- package/dist/src/openapi/write.d.ts +5 -0
- package/dist/src/openapi/write.js +12 -0
- package/dist/src/openapi/write.js.map +1 -0
- package/dist/src/rest/routes.js +6 -9
- package/dist/src/rest/routes.js.map +1 -1
- package/dist/src/server/config.d.ts +29 -34
- package/dist/src/server/config.js +83 -211
- package/dist/src/server/config.js.map +1 -1
- package/dist/src/server/create.d.ts +3 -5
- package/dist/src/server/create.js +35 -29
- package/dist/src/server/create.js.map +1 -1
- package/dist/src/server/features.d.ts +0 -11
- package/dist/src/server/features.js +0 -20
- package/dist/src/server/features.js.map +1 -1
- package/dist/src/server/model.d.ts +6 -0
- package/dist/src/server/model.js +14 -0
- package/dist/src/server/model.js.map +1 -0
- package/dist/src/server/public.d.ts +1 -2
- package/package.json +1 -1
- package/dist/src/graphql/lazy.d.ts +0 -10
- package/dist/src/graphql/lazy.js +0 -13
- package/dist/src/graphql/lazy.js.map +0 -1
- package/dist/src/graphql/public.js.map +0 -1
- package/dist/src/openapi/index.d.ts +0 -13
- package/dist/src/openapi/index.js +0 -37
- package/dist/src/openapi/index.js.map +0 -1
- package/dist/src/openapi/lazy.d.ts +0 -11
- package/dist/src/openapi/lazy.js +0 -13
- package/dist/src/openapi/lazy.js.map +0 -1
- package/dist/src/openapi/public.js +0 -26
- package/dist/src/openapi/public.js.map +0 -1
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* @example validPasswordHash('plain text') → false.
|
|
3
3
|
*/
|
|
4
4
|
export declare const validPasswordHash: (value: unknown) => value is string;
|
|
5
|
+
/** Проверяет строку пароля по длине без обрезки пробелов.
|
|
6
|
+
* @example validPassword(' secret ') → true; validPassword('') → false.
|
|
7
|
+
*/
|
|
8
|
+
export declare const validPassword: (value: unknown) => value is string;
|
|
5
9
|
/** Создаёт хеш пароля со случайной солью и сохраняет параметры вычисления в строке.
|
|
6
10
|
* @example hashPassword('secret') → Promise<string> вида 'scrypt$16384$8$5$<соль>$<хеш>'; результат случаен.
|
|
7
11
|
*/
|
|
@@ -7,6 +7,10 @@ const HASH_PATTERN = /^scrypt\$16384\$8\$5\$([0-9a-f]{32})\$([0-9a-f]{64})$/;
|
|
|
7
7
|
* @example validPasswordHash('plain text') → false.
|
|
8
8
|
*/
|
|
9
9
|
export const validPasswordHash = (value) => typeof value === 'string' && HASH_PATTERN.test(value);
|
|
10
|
+
/** Проверяет строку пароля по длине без обрезки пробелов.
|
|
11
|
+
* @example validPassword(' secret ') → true; validPassword('') → false.
|
|
12
|
+
*/
|
|
13
|
+
export const validPassword = (value) => typeof value === 'string' && value.length > 0 && value.length <= MAX_PASSWORD_LENGTH;
|
|
10
14
|
/** Вычисляет 32 байта scrypt для пароля и заданной соли.
|
|
11
15
|
* @example derive('secret', Buffer.alloc(16)) → Promise<Buffer> длиной 32 байта; одинаковые входы дают одинаковый результат.
|
|
12
16
|
*/
|
|
@@ -17,7 +21,7 @@ const derive = (password, salt) => new Promise((resolve, reject) => {
|
|
|
17
21
|
* @example hashPassword('secret') → Promise<string> вида 'scrypt$16384$8$5$<соль>$<хеш>'; результат случаен.
|
|
18
22
|
*/
|
|
19
23
|
export async function hashPassword(password) {
|
|
20
|
-
if (
|
|
24
|
+
if (!validPassword(password))
|
|
21
25
|
throw new Error(`Password must contain 1..${MAX_PASSWORD_LENGTH} characters`);
|
|
22
26
|
const salt = randomBytes(16);
|
|
23
27
|
const hash = await derive(password, salt);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password.js","sourceRoot":"","sources":["../../../src/auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,0DAA0D;AAC1D,MAAM,MAAM,GAAG,kBAAkB,CAAC;AAClC,MAAM,YAAY,GAAG,uDAAuD,CAAC;AAC7E;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5H;;GAEG;AACH,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,IAAY,EAAmB,EAAE,CACjE,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/G,CAAC,CAAC,CAAC;AACL;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,IAAI,
|
|
1
|
+
{"version":3,"file":"password.js","sourceRoot":"","sources":["../../../src/auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,0DAA0D;AAC1D,MAAM,MAAM,GAAG,kBAAkB,CAAC;AAClC,MAAM,YAAY,GAAG,uDAAuD,CAAC;AAC7E;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5H;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,mBAAmB,CAAC;AACvJ;;GAEG;AACH,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,IAAY,EAAmB,EAAE,CACjE,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/G,CAAC,CAAC,CAAC;AACL;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,mBAAmB,aAAa,CAAC,CAAC;IAC5G,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC1C,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AACrE,CAAC;AACD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,OAAe;IACpE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACpE,OAAO,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AAC/D,CAAC;AACD,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FastifyInstance } from 'fastify';
|
|
2
2
|
import type { AuthService } from './service.js';
|
|
3
|
-
/** Регистрирует
|
|
3
|
+
/** Регистрирует управление учётными записями и сессиями, запрещая кеширование ответов.
|
|
4
4
|
* @example После регистрации ответы содержат Cache-Control: no-store; функция возвращает undefined.
|
|
5
5
|
*/
|
|
6
6
|
export declare function registerAuthRoutes(server: FastifyInstance, auth: AuthService): void;
|
package/dist/src/auth/routes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AUTH_PATHS } from './contract.js';
|
|
2
|
-
/** Регистрирует
|
|
2
|
+
/** Регистрирует управление учётными записями и сессиями, запрещая кеширование ответов.
|
|
3
3
|
* @example После регистрации ответы содержат Cache-Control: no-store; функция возвращает undefined.
|
|
4
4
|
*/
|
|
5
5
|
export function registerAuthRoutes(server, auth) {
|
|
@@ -8,8 +8,11 @@ export function registerAuthRoutes(server, auth) {
|
|
|
8
8
|
reply.header('Cache-Control', 'no-store');
|
|
9
9
|
});
|
|
10
10
|
app.post(AUTH_PATHS.login, async (request) => auth.login(request.body));
|
|
11
|
+
app.post(AUTH_PATHS.register, async (request, reply) => reply.code(201).send(await auth.register(request.body)));
|
|
11
12
|
app.get(AUTH_PATHS.me, async (request) => auth.me(request.headers.authorization));
|
|
12
13
|
app.post(AUTH_PATHS.logout, async (request) => auth.logout(request.headers.authorization));
|
|
14
|
+
app.patch(AUTH_PATHS.password, async (request) => auth.changePassword(request.headers.authorization, request.params.id, request.body));
|
|
15
|
+
app.patch(AUTH_PATHS.admin, async (request) => auth.changeAdmin(request.headers.authorization, request.params.id, request.body));
|
|
13
16
|
});
|
|
14
17
|
}
|
|
15
18
|
//# sourceMappingURL=routes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/auth/routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAuB,EAAE,IAAiB;IAC3E,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC5B,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;YACjD,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACxE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QAClF,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/auth/routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAuB,EAAE,IAAiB;IAC3E,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC5B,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;YACjD,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACxE,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjH,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QAClF,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;QAC3F,GAAG,CAAC,KAAK,CAA6B,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACnK,GAAG,CAAC,KAAK,CAA6B,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/J,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,17 +1,32 @@
|
|
|
1
|
-
import { type AuthConfig, type AuthSession, type AuthUser
|
|
1
|
+
import { type AuthConfig, type AuthSession, type AuthUser } from './contract.js';
|
|
2
|
+
import { type AuthStore } from './store.js';
|
|
2
3
|
export declare class AuthService {
|
|
3
|
-
private
|
|
4
|
+
private store;
|
|
4
5
|
private expiresIn;
|
|
5
6
|
private sessions;
|
|
6
|
-
private
|
|
7
|
+
private pendingPasswords;
|
|
7
8
|
private closed;
|
|
8
|
-
constructor(
|
|
9
|
-
/** Проверяет
|
|
9
|
+
constructor(store: AuthStore, expiresIn: number);
|
|
10
|
+
/** Проверяет пароль и создаёт сессию с актуальными правами пользователя.
|
|
10
11
|
* @example Корректные username и password → { accessToken, expiresIn, user }; неверный пароль → исключение.
|
|
11
12
|
*/
|
|
12
13
|
login(body: unknown): Promise<AuthSession>;
|
|
13
|
-
/**
|
|
14
|
-
* @example
|
|
14
|
+
/** Создаёт обычного пользователя с новым идентификатором и хешем пароля, не открывая сессию.
|
|
15
|
+
* @example { username: 'anna', password: 'secret' } → { id: '…', username: 'anna', isAdmin: false }.
|
|
16
|
+
*/
|
|
17
|
+
register(body: unknown): Promise<AuthUser>;
|
|
18
|
+
/** Меняет свой пароль после проверки текущего либо пароль обычного пользователя по правам администратора.
|
|
19
|
+
* @example Свой id и два пароля → { success: true } с завершением всех своих сессий; чужой администратор → FORBIDDEN.
|
|
20
|
+
*/
|
|
21
|
+
changePassword(authorization: unknown, id: string, body: unknown): Promise<{
|
|
22
|
+
success: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
/** Меняет статус по правам действующего администратора и сохраняет хотя бы одного при отказе от собственных прав.
|
|
25
|
+
* @example Последний администратор и { isAdmin: false } для себя → CONFLICT; назначение другого → обновлённый пользователь.
|
|
26
|
+
*/
|
|
27
|
+
changeAdmin(authorization: unknown, id: string, body: unknown): Promise<AuthUser>;
|
|
28
|
+
/** Проверяет токен и возвращает копию пользователя с текущими правами.
|
|
29
|
+
* @example После снятия статуса прежний токен возвращает isAdmin: false без повторного входа.
|
|
15
30
|
*/
|
|
16
31
|
me(authorization: unknown): AuthUser;
|
|
17
32
|
/** Проверяет токен и удаляет соответствующую сессию.
|
|
@@ -20,20 +35,44 @@ export declare class AuthService {
|
|
|
20
35
|
logout(authorization: unknown): {
|
|
21
36
|
success: boolean;
|
|
22
37
|
};
|
|
23
|
-
/** Запрещает новые
|
|
38
|
+
/** Запрещает новые обращения и очищает сессии в памяти.
|
|
24
39
|
* @example close() → undefined; последующий login() → отказ.
|
|
25
40
|
*/
|
|
26
41
|
close(): void;
|
|
42
|
+
/** Ограничивает число одновременных вычислений хешей и освобождает место даже при ошибке.
|
|
43
|
+
* @example Четыре незавершённых вычисления → пятое получает TOO_MANY_REQUESTS.
|
|
44
|
+
*/
|
|
45
|
+
private passwordWork;
|
|
46
|
+
/** Отклоняет обращения после закрытия сервиса.
|
|
47
|
+
* @example closed = true → UNAUTHENTICATED; false → undefined.
|
|
48
|
+
*/
|
|
49
|
+
private assertOpen;
|
|
27
50
|
/** Находит сессию по хешу токена и проверяет срок; просроченную сессию удаляет.
|
|
28
51
|
* @example Действительный Bearer-токен → [ключ, сессия]; отсутствующий или истёкший → ошибка.
|
|
29
52
|
*/
|
|
30
53
|
private session;
|
|
54
|
+
/** Получает текущую запись по идентификатору из проверенной сессии.
|
|
55
|
+
* @example Сессия с userId = '1' → актуальная запись с id = '1'; отсутствующая запись → ошибка.
|
|
56
|
+
*/
|
|
57
|
+
private identity;
|
|
58
|
+
/** Проверяет текущие права администратора.
|
|
59
|
+
* @example Действующая сессия обычного пользователя → FORBIDDEN; администратора → его запись.
|
|
60
|
+
*/
|
|
61
|
+
private requireAdmin;
|
|
62
|
+
/** Проверяет владельца пароля и запрет изменения пароля другого администратора.
|
|
63
|
+
* @example Администратор и обычная чужая запись → { actor, target }; два разных администратора → FORBIDDEN.
|
|
64
|
+
*/
|
|
65
|
+
private passwordTarget;
|
|
66
|
+
/** Завершает все сессии одного пользователя после сохранения нового пароля.
|
|
67
|
+
* @example Две сессии id = '1' и одна id = '2' → остаётся сессия id = '2'.
|
|
68
|
+
*/
|
|
69
|
+
private revoke;
|
|
31
70
|
/** Удаляет из памяти сессии, срок которых истёк к текущему моменту.
|
|
32
71
|
* @example Одна истёкшая и одна действующая сессия → остаётся одна действующая; результат undefined.
|
|
33
72
|
*/
|
|
34
73
|
private prune;
|
|
35
74
|
}
|
|
36
|
-
/**
|
|
75
|
+
/** Открывает источник учётных записей и создаёт хранилище сессий в памяти.
|
|
37
76
|
* @example createAuthService({ users: [] }) → Promise<AuthService>; повторяющиеся id → ошибка.
|
|
38
77
|
*/
|
|
39
78
|
export declare function createAuthService(config: AuthConfig): Promise<AuthService>;
|
package/dist/src/auth/service.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
2
|
import { domainError } from '../core/errors.js';
|
|
4
|
-
import {
|
|
5
|
-
import { DEFAULT_SESSION_SECONDS
|
|
6
|
-
import {
|
|
3
|
+
import { createUniqueId } from '../core/utils.js';
|
|
4
|
+
import { DEFAULT_SESSION_SECONDS } from './contract.js';
|
|
5
|
+
import { adminChange, credentials, passwordChange } from './input.js';
|
|
6
|
+
import { DUMMY_HASH, hashPassword, verifyPassword } from './password.js';
|
|
7
|
+
import { createAuthStore } from './store.js';
|
|
7
8
|
/** Создаёт исключение отсутствия действительной сессии без раскрытия причины отказа.
|
|
8
9
|
* @example unauthorized() → Error с code = 'UNAUTHENTICATED'.
|
|
9
10
|
*/
|
|
@@ -12,63 +13,95 @@ const unauthorized = () => domainError('UNAUTHENTICATED', 'Invalid credentials o
|
|
|
12
13
|
* @example tokenKey('abc') → 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'.
|
|
13
14
|
*/
|
|
14
15
|
const tokenKey = (token) => createHash('sha256').update(token).digest('hex');
|
|
15
|
-
/** Возвращает публичные поля пользователя в новом
|
|
16
|
-
* @example
|
|
16
|
+
/** Возвращает публичные поля пользователя в новом объекте.
|
|
17
|
+
* @example { id: '1', username: 'anna', isAdmin: false, passwordHash: '…' } → { id: '1', username: 'anna', isAdmin: false }.
|
|
17
18
|
*/
|
|
18
|
-
const publicUser = (user) => ({ id: user.id, username: user.username, isAdmin: user.isAdmin
|
|
19
|
+
const publicUser = (user) => ({ id: user.id, username: user.username, isAdmin: user.isAdmin });
|
|
19
20
|
export class AuthService {
|
|
20
|
-
|
|
21
|
+
store;
|
|
21
22
|
expiresIn;
|
|
22
23
|
sessions = new Map();
|
|
23
|
-
|
|
24
|
+
pendingPasswords = 0;
|
|
24
25
|
closed = false;
|
|
25
|
-
constructor(
|
|
26
|
-
this.
|
|
26
|
+
constructor(store, expiresIn) {
|
|
27
|
+
this.store = store;
|
|
27
28
|
this.expiresIn = expiresIn;
|
|
28
29
|
}
|
|
29
|
-
/** Проверяет
|
|
30
|
+
/** Проверяет пароль и создаёт сессию с актуальными правами пользователя.
|
|
30
31
|
* @example Корректные username и password → { accessToken, expiresIn, user }; неверный пароль → исключение.
|
|
31
32
|
*/
|
|
32
33
|
async login(body) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
body.password.length > MAX_PASSWORD_LENGTH)
|
|
41
|
-
throw domainError('INVALID_INPUT', 'Supply username and password');
|
|
42
|
-
if (this.closed)
|
|
43
|
-
throw unauthorized();
|
|
44
|
-
if (this.pendingLogins >= 4)
|
|
45
|
-
throw domainError('TOO_MANY_REQUESTS', 'Too many simultaneous login attempts');
|
|
46
|
-
this.pendingLogins++;
|
|
47
|
-
let user;
|
|
48
|
-
let valid;
|
|
49
|
-
try {
|
|
50
|
-
user = this.users.get(body.username);
|
|
51
|
-
valid = await verifyPassword(body.password, user?.passwordHash ?? DUMMY_HASH);
|
|
52
|
-
}
|
|
53
|
-
finally {
|
|
54
|
-
this.pendingLogins--;
|
|
55
|
-
}
|
|
56
|
-
if (!user || !valid || this.closed)
|
|
34
|
+
const { username, password } = credentials(body);
|
|
35
|
+
const user = this.store.read().byUsername.get(username);
|
|
36
|
+
const valid = await this.passwordWork(() => verifyPassword(password, user?.passwordHash ?? DUMMY_HASH));
|
|
37
|
+
this.assertOpen();
|
|
38
|
+
const current = user && this.store.read().byId.get(user.id);
|
|
39
|
+
// Смена пароля во время scrypt не должна выдавать новую сессию по прежнему паролю.
|
|
40
|
+
if (!user || !valid || !current || current.passwordHash !== user.passwordHash)
|
|
57
41
|
throw unauthorized();
|
|
58
42
|
this.prune();
|
|
59
43
|
if (this.sessions.size >= 10000)
|
|
60
44
|
throw domainError('TOO_MANY_REQUESTS', 'Session limit reached');
|
|
61
45
|
const accessToken = randomBytes(32).toString('base64url');
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
46
|
+
this.sessions.set(tokenKey(accessToken), { userId: current.id, expiresAt: Date.now() + this.expiresIn * 1000 });
|
|
47
|
+
return { accessToken, expiresIn: this.expiresIn, user: publicUser(current) };
|
|
48
|
+
}
|
|
49
|
+
/** Создаёт обычного пользователя с новым идентификатором и хешем пароля, не открывая сессию.
|
|
50
|
+
* @example { username: 'anna', password: 'secret' } → { id: '…', username: 'anna', isAdmin: false }.
|
|
51
|
+
*/
|
|
52
|
+
async register(body) {
|
|
53
|
+
const { username, password } = credentials(body);
|
|
54
|
+
const passwordHash = await this.passwordWork(() => hashPassword(password));
|
|
55
|
+
const user = await this.store.update((users) => {
|
|
56
|
+
this.assertOpen();
|
|
57
|
+
return { id: createUniqueId((id) => users.byId.has(id)), username, passwordHash, isAdmin: false };
|
|
58
|
+
});
|
|
59
|
+
return publicUser(user);
|
|
60
|
+
}
|
|
61
|
+
/** Меняет свой пароль после проверки текущего либо пароль обычного пользователя по правам администратора.
|
|
62
|
+
* @example Свой id и два пароля → { success: true } с завершением всех своих сессий; чужой администратор → FORBIDDEN.
|
|
63
|
+
*/
|
|
64
|
+
async changePassword(authorization, id, body) {
|
|
65
|
+
const { actor, target } = this.passwordTarget(this.store.read(), authorization, id);
|
|
66
|
+
const { newPassword, currentPassword } = passwordChange(body);
|
|
67
|
+
const own = actor.id === target.id;
|
|
68
|
+
if (own && currentPassword === undefined)
|
|
69
|
+
throw domainError('INVALID_INPUT', 'Supply currentPassword to change your own password');
|
|
70
|
+
const passwordHash = await this.passwordWork(async () => {
|
|
71
|
+
if (own && !(await verifyPassword(currentPassword, target.passwordHash)))
|
|
72
|
+
throw unauthorized();
|
|
73
|
+
return hashPassword(newPassword);
|
|
74
|
+
});
|
|
75
|
+
await this.store.update((users) => {
|
|
76
|
+
const { target: current } = this.passwordTarget(users, authorization, id);
|
|
77
|
+
if (current.passwordHash !== target.passwordHash)
|
|
78
|
+
throw domainError('CONFLICT', 'Password changed during the request');
|
|
79
|
+
return { ...current, passwordHash };
|
|
80
|
+
}, () => this.revoke(id));
|
|
81
|
+
return { success: true };
|
|
65
82
|
}
|
|
66
|
-
/**
|
|
67
|
-
* @example
|
|
83
|
+
/** Меняет статус по правам действующего администратора и сохраняет хотя бы одного при отказе от собственных прав.
|
|
84
|
+
* @example Последний администратор и { isAdmin: false } для себя → CONFLICT; назначение другого → обновлённый пользователь.
|
|
85
|
+
*/
|
|
86
|
+
async changeAdmin(authorization, id, body) {
|
|
87
|
+
this.requireAdmin(authorization);
|
|
88
|
+
const isAdmin = adminChange(body);
|
|
89
|
+
const user = await this.store.update((users) => {
|
|
90
|
+
const actor = this.requireAdmin(authorization);
|
|
91
|
+
const target = users.byId.get(id);
|
|
92
|
+
if (!target)
|
|
93
|
+
throw domainError('NOT_FOUND', 'Auth user not found');
|
|
94
|
+
if (!isAdmin && actor.id === target.id && ![...users.byId.values()].some((user) => user.id !== id && user.isAdmin))
|
|
95
|
+
throw domainError('CONFLICT', 'The last administrator cannot remove their own admin status');
|
|
96
|
+
return { ...target, isAdmin };
|
|
97
|
+
});
|
|
98
|
+
return publicUser(user);
|
|
99
|
+
}
|
|
100
|
+
/** Проверяет токен и возвращает копию пользователя с текущими правами.
|
|
101
|
+
* @example После снятия статуса прежний токен возвращает isAdmin: false без повторного входа.
|
|
68
102
|
*/
|
|
69
103
|
me(authorization) {
|
|
70
|
-
|
|
71
|
-
return publicUser(session.user);
|
|
104
|
+
return publicUser(this.identity(authorization));
|
|
72
105
|
}
|
|
73
106
|
/** Проверяет токен и удаляет соответствующую сессию.
|
|
74
107
|
* @example Действительный токен → { success: true }; повторный выход с ним → ошибка.
|
|
@@ -78,18 +111,40 @@ export class AuthService {
|
|
|
78
111
|
this.sessions.delete(key);
|
|
79
112
|
return { success: true };
|
|
80
113
|
}
|
|
81
|
-
/** Запрещает новые
|
|
114
|
+
/** Запрещает новые обращения и очищает сессии в памяти.
|
|
82
115
|
* @example close() → undefined; последующий login() → отказ.
|
|
83
116
|
*/
|
|
84
117
|
close() {
|
|
85
118
|
this.closed = true;
|
|
86
119
|
this.sessions.clear();
|
|
87
|
-
|
|
120
|
+
}
|
|
121
|
+
/** Ограничивает число одновременных вычислений хешей и освобождает место даже при ошибке.
|
|
122
|
+
* @example Четыре незавершённых вычисления → пятое получает TOO_MANY_REQUESTS.
|
|
123
|
+
*/
|
|
124
|
+
async passwordWork(operation) {
|
|
125
|
+
this.assertOpen();
|
|
126
|
+
if (this.pendingPasswords >= 4)
|
|
127
|
+
throw domainError('TOO_MANY_REQUESTS', 'Too many simultaneous password operations');
|
|
128
|
+
this.pendingPasswords++;
|
|
129
|
+
try {
|
|
130
|
+
return await operation();
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
this.pendingPasswords--;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** Отклоняет обращения после закрытия сервиса.
|
|
137
|
+
* @example closed = true → UNAUTHENTICATED; false → undefined.
|
|
138
|
+
*/
|
|
139
|
+
assertOpen() {
|
|
140
|
+
if (this.closed)
|
|
141
|
+
throw unauthorized();
|
|
88
142
|
}
|
|
89
143
|
/** Находит сессию по хешу токена и проверяет срок; просроченную сессию удаляет.
|
|
90
144
|
* @example Действительный Bearer-токен → [ключ, сессия]; отсутствующий или истёкший → ошибка.
|
|
91
145
|
*/
|
|
92
146
|
session(authorization) {
|
|
147
|
+
this.assertOpen();
|
|
93
148
|
if (typeof authorization !== 'string')
|
|
94
149
|
throw unauthorized();
|
|
95
150
|
const match = /^Bearer ([A-Za-z0-9_-]{43})$/i.exec(authorization);
|
|
@@ -103,6 +158,47 @@ export class AuthService {
|
|
|
103
158
|
}
|
|
104
159
|
return [key, session];
|
|
105
160
|
}
|
|
161
|
+
/** Получает текущую запись по идентификатору из проверенной сессии.
|
|
162
|
+
* @example Сессия с userId = '1' → актуальная запись с id = '1'; отсутствующая запись → ошибка.
|
|
163
|
+
*/
|
|
164
|
+
identity(authorization) {
|
|
165
|
+
const [, session] = this.session(authorization);
|
|
166
|
+
const user = this.store.read().byId.get(session.userId);
|
|
167
|
+
if (!user)
|
|
168
|
+
throw unauthorized();
|
|
169
|
+
return user;
|
|
170
|
+
}
|
|
171
|
+
/** Проверяет текущие права администратора.
|
|
172
|
+
* @example Действующая сессия обычного пользователя → FORBIDDEN; администратора → его запись.
|
|
173
|
+
*/
|
|
174
|
+
requireAdmin(authorization) {
|
|
175
|
+
const user = this.identity(authorization);
|
|
176
|
+
if (!user.isAdmin)
|
|
177
|
+
throw domainError('FORBIDDEN', 'Administrator access required');
|
|
178
|
+
return user;
|
|
179
|
+
}
|
|
180
|
+
/** Проверяет владельца пароля и запрет изменения пароля другого администратора.
|
|
181
|
+
* @example Администратор и обычная чужая запись → { actor, target }; два разных администратора → FORBIDDEN.
|
|
182
|
+
*/
|
|
183
|
+
passwordTarget(users, authorization, id) {
|
|
184
|
+
const actor = this.identity(authorization);
|
|
185
|
+
if (actor.id !== id && !actor.isAdmin)
|
|
186
|
+
throw domainError('FORBIDDEN', 'You can only change your own password');
|
|
187
|
+
const target = users.byId.get(id);
|
|
188
|
+
if (!target)
|
|
189
|
+
throw domainError('NOT_FOUND', 'Auth user not found');
|
|
190
|
+
if (actor.id !== id && target.isAdmin)
|
|
191
|
+
throw domainError('FORBIDDEN', 'Cannot change another administrator password');
|
|
192
|
+
return { actor, target };
|
|
193
|
+
}
|
|
194
|
+
/** Завершает все сессии одного пользователя после сохранения нового пароля.
|
|
195
|
+
* @example Две сессии id = '1' и одна id = '2' → остаётся сессия id = '2'.
|
|
196
|
+
*/
|
|
197
|
+
revoke(id) {
|
|
198
|
+
for (const [key, session] of this.sessions)
|
|
199
|
+
if (session.userId === id)
|
|
200
|
+
this.sessions.delete(key);
|
|
201
|
+
}
|
|
106
202
|
/** Удаляет из памяти сессии, срок которых истёк к текущему моменту.
|
|
107
203
|
* @example Одна истёкшая и одна действующая сессия → остаётся одна действующая; результат undefined.
|
|
108
204
|
*/
|
|
@@ -113,31 +209,10 @@ export class AuthService {
|
|
|
113
209
|
this.sessions.delete(key);
|
|
114
210
|
}
|
|
115
211
|
}
|
|
116
|
-
/**
|
|
212
|
+
/** Открывает источник учётных записей и создаёт хранилище сессий в памяти.
|
|
117
213
|
* @example createAuthService({ users: [] }) → Promise<AuthService>; повторяющиеся id → ошибка.
|
|
118
214
|
*/
|
|
119
215
|
export async function createAuthService(config) {
|
|
120
|
-
|
|
121
|
-
if (!Array.isArray(records))
|
|
122
|
-
throw new Error('Auth users must be an array');
|
|
123
|
-
const users = new Map();
|
|
124
|
-
const ids = new Set();
|
|
125
|
-
for (const record of records) {
|
|
126
|
-
if (!isObject(record) ||
|
|
127
|
-
!hasOnlyKeys(record, ['id', 'username', 'passwordHash', 'isAdmin']) ||
|
|
128
|
-
typeof record.id !== 'string' ||
|
|
129
|
-
!record.id.trim() ||
|
|
130
|
-
typeof record.username !== 'string' ||
|
|
131
|
-
!record.username.trim() ||
|
|
132
|
-
record.username.length > MAX_USERNAME_LENGTH ||
|
|
133
|
-
!validPasswordHash(record.passwordHash) ||
|
|
134
|
-
(record.isAdmin !== undefined && typeof record.isAdmin !== 'boolean'))
|
|
135
|
-
throw new Error('Auth users require id, username and a valid passwordHash');
|
|
136
|
-
if (ids.has(record.id) || users.has(record.username))
|
|
137
|
-
throw new Error('Auth user ids and usernames must be unique');
|
|
138
|
-
ids.add(record.id);
|
|
139
|
-
users.set(record.username, { id: record.id, username: record.username, passwordHash: record.passwordHash, isAdmin: record.isAdmin ?? false });
|
|
140
|
-
}
|
|
141
|
-
return new AuthService(users, config.expiresIn ?? DEFAULT_SESSION_SECONDS);
|
|
216
|
+
return new AuthService(await createAuthStore(config.source), config.expiresIn ?? DEFAULT_SESSION_SECONDS);
|
|
142
217
|
}
|
|
143
218
|
//# sourceMappingURL=service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/auth/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/auth/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { JSONFile } from 'lowdb/node';
|
|
2
|
+
import { type AuthConfig, type AuthUserRecord } from './contract.js';
|
|
3
|
+
export type StoredUser = Readonly<Required<AuthUserRecord>>;
|
|
4
|
+
export interface UserIndex {
|
|
5
|
+
byId: ReadonlyMap<string, StoredUser>;
|
|
6
|
+
byUsername: ReadonlyMap<string, StoredUser>;
|
|
7
|
+
}
|
|
8
|
+
/** Хранит подтверждённые записи и последовательно сохраняет изменения одного пользователя. */
|
|
9
|
+
export declare class AuthStore {
|
|
10
|
+
private users;
|
|
11
|
+
private file?;
|
|
12
|
+
private schedule;
|
|
13
|
+
constructor(users: UserIndex, file?: JSONFile<StoredUser[]> | undefined);
|
|
14
|
+
/** Возвращает индексы последнего успешно сохранённого состояния.
|
|
15
|
+
* @example Во время записи нового пароля read() ещё возвращает запись с прежним хешем.
|
|
16
|
+
*/
|
|
17
|
+
read(): UserIndex;
|
|
18
|
+
/** Проверяет изменение внутри очереди и публикует его после записи; обработчик подтверждения вызывается синхронно.
|
|
19
|
+
* @example Успешная запись → новый пользователь; ошибка файла → прежние индексы, обработчик не вызван.
|
|
20
|
+
*/
|
|
21
|
+
update(operation: (users: UserIndex) => StoredUser, committed?: () => void): Promise<StoredUser>;
|
|
22
|
+
}
|
|
23
|
+
/** Загружает массив из файла или памяти и подключает запись в тот же источник.
|
|
24
|
+
* @example Массив → хранилище в памяти; 'users.json' → чтение и сохранение JSON-массива через JSONFile.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createAuthStore(source: AuthConfig['source']): Promise<AuthStore>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { JSONFile } from 'lowdb/node';
|
|
2
|
+
import { domainError } from '../core/errors.js';
|
|
3
|
+
import { createSerialQueue, hasOnlyKeys, isObject } from '../core/utils.js';
|
|
4
|
+
import { MAX_USERNAME_LENGTH } from './contract.js';
|
|
5
|
+
import { validPasswordHash } from './password.js';
|
|
6
|
+
/** Проверяет записи и строит индексы по двум уникальным строковым ключам.
|
|
7
|
+
* @example Две записи с разными id и username → два индекса; повторяющийся ключ → ошибка.
|
|
8
|
+
*/
|
|
9
|
+
function indexUsers(records) {
|
|
10
|
+
if (!Array.isArray(records))
|
|
11
|
+
throw new Error('Auth users must be an array');
|
|
12
|
+
const byId = new Map();
|
|
13
|
+
const byUsername = new Map();
|
|
14
|
+
for (const record of records) {
|
|
15
|
+
if (!isObject(record) ||
|
|
16
|
+
!hasOnlyKeys(record, ['id', 'username', 'passwordHash', 'isAdmin']) ||
|
|
17
|
+
typeof record.id !== 'string' ||
|
|
18
|
+
!record.id.trim() ||
|
|
19
|
+
typeof record.username !== 'string' ||
|
|
20
|
+
!record.username.trim() ||
|
|
21
|
+
record.username.length > MAX_USERNAME_LENGTH ||
|
|
22
|
+
!validPasswordHash(record.passwordHash) ||
|
|
23
|
+
(record.isAdmin !== undefined && typeof record.isAdmin !== 'boolean'))
|
|
24
|
+
throw new Error('Auth users require id, username and a valid passwordHash');
|
|
25
|
+
if (byId.has(record.id) || byUsername.has(record.username))
|
|
26
|
+
throw new Error('Auth user ids and usernames must be unique');
|
|
27
|
+
const user = Object.freeze({ id: record.id, username: record.username, passwordHash: record.passwordHash, isAdmin: record.isAdmin ?? false });
|
|
28
|
+
byId.set(user.id, user);
|
|
29
|
+
byUsername.set(user.username, user);
|
|
30
|
+
}
|
|
31
|
+
return { byId, byUsername };
|
|
32
|
+
}
|
|
33
|
+
/** Хранит подтверждённые записи и последовательно сохраняет изменения одного пользователя. */
|
|
34
|
+
export class AuthStore {
|
|
35
|
+
users;
|
|
36
|
+
file;
|
|
37
|
+
schedule = createSerialQueue();
|
|
38
|
+
constructor(users, file) {
|
|
39
|
+
this.users = users;
|
|
40
|
+
this.file = file;
|
|
41
|
+
}
|
|
42
|
+
/** Возвращает индексы последнего успешно сохранённого состояния.
|
|
43
|
+
* @example Во время записи нового пароля read() ещё возвращает запись с прежним хешем.
|
|
44
|
+
*/
|
|
45
|
+
read() {
|
|
46
|
+
return this.users;
|
|
47
|
+
}
|
|
48
|
+
/** Проверяет изменение внутри очереди и публикует его после записи; обработчик подтверждения вызывается синхронно.
|
|
49
|
+
* @example Успешная запись → новый пользователь; ошибка файла → прежние индексы, обработчик не вызван.
|
|
50
|
+
*/
|
|
51
|
+
update(operation, committed) {
|
|
52
|
+
return this.schedule(async () => {
|
|
53
|
+
const user = Object.freeze(operation(this.users));
|
|
54
|
+
const owner = this.users.byUsername.get(user.username);
|
|
55
|
+
if (owner && owner.id !== user.id)
|
|
56
|
+
throw domainError('CONFLICT', 'Username already exists');
|
|
57
|
+
const byId = new Map(this.users.byId);
|
|
58
|
+
const byUsername = new Map(this.users.byUsername);
|
|
59
|
+
const previous = byId.get(user.id);
|
|
60
|
+
if (previous)
|
|
61
|
+
byUsername.delete(previous.username);
|
|
62
|
+
byId.set(user.id, user);
|
|
63
|
+
byUsername.set(user.username, user);
|
|
64
|
+
if (this.file)
|
|
65
|
+
await this.file.write([...byId.values()]);
|
|
66
|
+
this.users = { byId, byUsername };
|
|
67
|
+
committed?.();
|
|
68
|
+
return user;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Загружает массив из файла или памяти и подключает запись в тот же источник.
|
|
73
|
+
* @example Массив → хранилище в памяти; 'users.json' → чтение и сохранение JSON-массива через JSONFile.
|
|
74
|
+
*/
|
|
75
|
+
export async function createAuthStore(source) {
|
|
76
|
+
const file = typeof source === 'string' ? new JSONFile(source) : undefined;
|
|
77
|
+
const records = file ? await file.read() : source;
|
|
78
|
+
if (file && records === null)
|
|
79
|
+
throw new Error(`Auth users file not found: ${source}`);
|
|
80
|
+
return new AuthStore(indexUsers(records), file);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/auth/store.ts"],"names":[],"mappings":"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"}
|
package/dist/src/cli/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createConfiguredServer } from '../server/create.js';
|
|
2
|
-
/** Разбирает
|
|
3
|
-
* @example runCli(['--
|
|
2
|
+
/** Разбирает флаги, выполняет экспорт по секциям конфигурации и при необходимости запускает сервер.
|
|
3
|
+
* @example runCli(['--generate-only', 'config.mjs']) → файлы схем без открытия порта.
|
|
4
4
|
*/
|
|
5
5
|
export declare function runCli(args?: string[], services?: {
|
|
6
6
|
createServer: typeof createConfiguredServer;
|