@kollors/deep-json-server 1.0.0-alpha.7 → 1.0.0-alpha.8
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 +40 -11
- package/README.ru.md +40 -11
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/src/auth/contract.d.ts +3 -0
- 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.js +6 -8
- 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 +4 -1
- package/dist/src/core/database.js +2 -2
- 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 +2 -1
- 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 +6 -2
- package/dist/src/core/paths.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/memory-store.js +13 -13
- 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.js → generate.js} +1 -1
- 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 +39 -0
- package/dist/src/openapi/generate.js.map +1 -0
- package/dist/src/openapi/options.d.ts +20 -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 +5 -8
- package/dist/src/server/config.js +19 -60
- package/dist/src/server/config.js.map +1 -1
- package/dist/src/server/create.js +6 -9
- package/dist/src/server/create.js.map +1 -1
- 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
- /package/dist/src/graphql/{public.d.ts → generate.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A JSON mock server with REST, GraphQL, related records, file uploads and schema exports. Supports user login, owner and administrator permissions, record timestamps and soft deletion. Requires Node.js 22 or newer.
|
|
6
6
|
|
|
7
|
-
**1.0.0-alpha.
|
|
7
|
+
**1.0.0-alpha.8 is a prerelease.** REST queries use `scope=[fields, arguments?]` at every level. When upgrading from an earlier version, update query parameters using the examples below; upgrading from 0.x also requires the new model schema.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ A JSON mock server with REST, GraphQL, related records, file uploads and schema
|
|
|
12
12
|
npm install @kollors/deep-json-server@alpha
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
To install a specific version, use `@1.0.0-alpha.
|
|
15
|
+
To install a specific version, use `@1.0.0-alpha.8`.
|
|
16
16
|
|
|
17
17
|
## Quick start
|
|
18
18
|
|
|
@@ -412,9 +412,9 @@ Each format needs its own output file. The command rejects destinations that wou
|
|
|
412
412
|
|
|
413
413
|
## Authentication
|
|
414
414
|
|
|
415
|
-
The `auth` section enables
|
|
415
|
+
The `auth` section enables registration, login and permission checks for record changes in REST and GraphQL. Reads and all file operations remain public.
|
|
416
416
|
|
|
417
|
-
|
|
417
|
+
Define the first administrator in the initial data. For example, create `auth.json` with `setup-auth.mjs`:
|
|
418
418
|
|
|
419
419
|
```js
|
|
420
420
|
import { writeFile } from 'node:fs/promises';
|
|
@@ -436,17 +436,46 @@ export default {
|
|
|
436
436
|
};
|
|
437
437
|
```
|
|
438
438
|
|
|
439
|
-
Start with `npx deep-json-server server.config.js`.
|
|
439
|
+
Start with `npx deep-json-server server.config.js`. Each initial user needs a unique string `id`, a unique `username` and a `passwordHash` created by the helper. `isAdmin` defaults to `false`. Passwords use salted scrypt hashes.
|
|
440
440
|
|
|
441
|
-
|
|
441
|
+
You can pass an array in `auth.users` instead of a path:
|
|
442
|
+
|
|
443
|
+
```js
|
|
444
|
+
import { hashPassword } from '@kollors/deep-json-server/auth';
|
|
445
|
+
|
|
446
|
+
const password = process.env.DJS_PASSWORD;
|
|
447
|
+
if (!password) throw new Error('Set DJS_PASSWORD');
|
|
448
|
+
|
|
449
|
+
export default {
|
|
450
|
+
database: { data: { items: [] } },
|
|
451
|
+
auth: {
|
|
452
|
+
users: [
|
|
453
|
+
{ id: '1', username: 'admin', passwordHash: await hashPassword(password), isAdmin: true },
|
|
454
|
+
],
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Auth users are stored separately from database collections. With a string in `auth.users`, registration, password changes and admin status changes are saved to that JSON file through the same `lowdb` used by the main database. With an array, changes remain in an internal memory copy and disappear on restart; the original array is unchanged. This choice is independent of `database.path` or `database.data`. A file write failure leaves the user and active sessions unchanged. The file is read at startup; restart the server after editing it manually.
|
|
460
|
+
|
|
461
|
+
| REST request | JSON body | Response |
|
|
442
462
|
|---|---|---|
|
|
443
|
-
| `POST /auth/
|
|
444
|
-
| `
|
|
445
|
-
| `
|
|
463
|
+
| `POST /auth/register` | `{ "username": "anna", "password": "…" }` | `201`: `{ id, username, isAdmin: false }` |
|
|
464
|
+
| `POST /auth/login` | `{ "username": "anna", "password": "…" }` | `{ accessToken, expiresIn, user: { id, username, isAdmin } }` |
|
|
465
|
+
| `GET /auth/me` | — | `{ id, username, isAdmin }` |
|
|
466
|
+
| `POST /auth/logout` | — | `{ success: true }` |
|
|
467
|
+
| `PATCH /auth/users/:id/password` | `{ "currentPassword": "…", "newPassword": "…" }` | `{ success: true }` |
|
|
468
|
+
| `PATCH /auth/users/:id/admin` | `{ "isAdmin": true }` | `{ id, username, isAdmin }` |
|
|
469
|
+
|
|
470
|
+
Registration and login are public. Send `Authorization: Bearer <accessToken>` for the other methods. Registration creates an ordinary user with a generated `id`; requests cannot include `id`, `passwordHash` or `isAdmin`. Usernames are case-sensitive and unique; duplicates return `409`. A username must contain a non-whitespace character and be at most 256 characters long. Passwords must contain 1–1024 characters. Values are not trimmed. Registration does not create a session: log in afterwards.
|
|
471
|
+
|
|
472
|
+
Users can change only their own password by supplying `currentPassword` and `newPassword`. Administrators follow the same rule for their own password. An administrator can change an ordinary user's password with just `newPassword`. Changing another administrator's password returns `403`. A successful password change ends all sessions of the target user, including the current session when changing your own password; log in again. An incorrect current password returns `401` without changing sessions.
|
|
473
|
+
|
|
474
|
+
Only administrators can change `isAdmin`. They can grant or remove another user's admin status. An administrator can remove their own status only if another administrator remains; otherwise the request returns `409`. This check accounts for concurrent requests. Existing tokens use the new permissions as soon as the change is saved, including for GraphQL mutations. An administrator may demote another administrator and then change their password as an ordinary user.
|
|
446
475
|
|
|
447
|
-
|
|
476
|
+
Invalid or expired tokens return `401`, insufficient permissions return `403`, and an absent user for an otherwise permitted operation returns `404`. Invalid request bodies return `400`. Login, registration and password changes may return `429` when too many password computations are running; login also limits active sessions. Sessions are kept in memory and disappear on restart. Logout revokes only the supplied token.
|
|
448
477
|
|
|
449
|
-
OpenAPI describes
|
|
478
|
+
OpenAPI describes all auth routes and their Bearer token requirements. In Swagger UI, paste a token from login into **Authorize**. For schema exports, enable auth in the configuration and run `generate openapi server.config.js`; the users file is not read during generation. Auth methods are exposed through REST. GraphQL checks the same token when changing records. GraphQL and OpenAPI require `database.schema`.
|
|
450
479
|
|
|
451
480
|
## Record dates, deletion and ownership
|
|
452
481
|
|
package/README.ru.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
JSON-сервер для имитации API: REST, GraphQL, связанные записи, загрузка файлов и экспорт схем. Поддерживает вход пользователей, права владельца и администратора, даты записей и мягкое удаление. Требуется Node.js 22 или новее.
|
|
6
6
|
|
|
7
|
-
**1.0.0-alpha.
|
|
7
|
+
**1.0.0-alpha.8 — предварительная версия.** REST-запросы используют `scope=[поля, аргументы?]` на всех уровнях. При обновлении измените параметры запросов по примерам ниже; для перехода с 0.x также нужна новая схема моделей.
|
|
8
8
|
|
|
9
9
|
## Установка
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ JSON-сервер для имитации API: REST, GraphQL, связанные
|
|
|
12
12
|
npm install @kollors/deep-json-server@alpha
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Для установки конкретной версии укажите `@1.0.0-alpha.
|
|
15
|
+
Для установки конкретной версии укажите `@1.0.0-alpha.8`.
|
|
16
16
|
|
|
17
17
|
## Быстрый старт
|
|
18
18
|
|
|
@@ -412,9 +412,9 @@ export default {
|
|
|
412
412
|
|
|
413
413
|
## Аутентификация
|
|
414
414
|
|
|
415
|
-
Секция `auth` включает
|
|
415
|
+
Секция `auth` включает регистрацию, вход и проверку прав на изменение записей в REST и GraphQL. Чтение и все операции с файлами остаются открытыми.
|
|
416
416
|
|
|
417
|
-
|
|
417
|
+
Первого администратора задайте в исходных данных. Например, создайте `auth.json` с помощью `setup-auth.mjs`:
|
|
418
418
|
|
|
419
419
|
```js
|
|
420
420
|
import { writeFile } from 'node:fs/promises';
|
|
@@ -436,17 +436,46 @@ export default {
|
|
|
436
436
|
};
|
|
437
437
|
```
|
|
438
438
|
|
|
439
|
-
Запустите `npx deep-json-server server.config.js`.
|
|
439
|
+
Запустите `npx deep-json-server server.config.js`. Каждой исходной учётной записи нужны уникальный строковый `id`, уникальный `username` и `passwordHash`, созданный функцией выше. `isAdmin` по умолчанию равен `false`. Пароли хешируются через scrypt со случайной солью.
|
|
440
440
|
|
|
441
|
-
|
|
441
|
+
В `auth.users` можно передать массив вместо пути:
|
|
442
|
+
|
|
443
|
+
```js
|
|
444
|
+
import { hashPassword } from '@kollors/deep-json-server/auth';
|
|
445
|
+
|
|
446
|
+
const password = process.env.DJS_PASSWORD;
|
|
447
|
+
if (!password) throw new Error('Set DJS_PASSWORD');
|
|
448
|
+
|
|
449
|
+
export default {
|
|
450
|
+
database: { data: { items: [] } },
|
|
451
|
+
auth: {
|
|
452
|
+
users: [
|
|
453
|
+
{ id: '1', username: 'admin', passwordHash: await hashPassword(password), isAdmin: true },
|
|
454
|
+
],
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Учётные записи auth хранятся отдельно от коллекций базы. При строке в `auth.users` регистрация, смена пароля и статуса сохраняются в указанный JSON-файл через тот же `lowdb`, что и основная база. При массиве изменения остаются во внутренней копии в памяти и исчезают после перезапуска; исходный массив не меняется. Выбор не зависит от `database.path` или `database.data`. Ошибка записи файла отменяет изменение и сохраняет действующие сессии. Файл читается при запуске; после ручного редактирования перезапустите сервер.
|
|
460
|
+
|
|
461
|
+
| REST-запрос | JSON тела | Ответ |
|
|
442
462
|
|---|---|---|
|
|
443
|
-
| `POST /auth/
|
|
444
|
-
| `
|
|
445
|
-
| `
|
|
463
|
+
| `POST /auth/register` | `{ "username": "anna", "password": "…" }` | `201`: `{ id, username, isAdmin: false }` |
|
|
464
|
+
| `POST /auth/login` | `{ "username": "anna", "password": "…" }` | `{ accessToken, expiresIn, user: { id, username, isAdmin } }` |
|
|
465
|
+
| `GET /auth/me` | — | `{ id, username, isAdmin }` |
|
|
466
|
+
| `POST /auth/logout` | — | `{ success: true }` |
|
|
467
|
+
| `PATCH /auth/users/:id/password` | `{ "currentPassword": "…", "newPassword": "…" }` | `{ success: true }` |
|
|
468
|
+
| `PATCH /auth/users/:id/admin` | `{ "isAdmin": true }` | `{ id, username, isAdmin }` |
|
|
469
|
+
|
|
470
|
+
Регистрация и вход доступны без токена. Для остальных методов передавайте `Authorization: Bearer <accessToken>`. Регистрация создаёт обычного пользователя с новым `id`; поля `id`, `passwordHash` и `isAdmin` в запросе запрещены. `username` уникален с учётом регистра, повтор возвращает `409`. Имя должно содержать хотя бы один непробельный символ и не более 256 символов, пароль — от 1 до 1024 символов. Значения не обрезаются. Регистрация не открывает сессию: после неё выполните вход.
|
|
471
|
+
|
|
472
|
+
Пользователь меняет только свой пароль, передавая `currentPassword` и `newPassword`. Для администратора при смене своего пароля действует то же правило. Администратор может сменить пароль обычному пользователю, передав только `newPassword`. Изменение пароля другого администратора возвращает `403`. После успешной смены завершаются все сессии этого пользователя, включая текущую при смене своего пароля; требуется новый вход. Неверный текущий пароль возвращает `401` без изменения сессий.
|
|
473
|
+
|
|
474
|
+
Статус `isAdmin` меняет только администратор. Можно назначать других администраторов и снимать с них статус. Снять статус с себя можно, только если остаётся другой администратор; иначе возвращается `409`. Проверка учитывает параллельные запросы. Новые права действуют с прежними токенами сразу после сохранения, в том числе для мутаций GraphQL. Администратор может снять статус с другого администратора, а затем сменить ему пароль как обычному пользователю.
|
|
446
475
|
|
|
447
|
-
|
|
476
|
+
Недействительный или истёкший токен возвращает `401`, недостаток прав — `403`, отсутствующий пользователь при разрешённой операции — `404`. Ошибки тела запроса возвращают `400`. Вход, регистрация и смена пароля могут вернуть `429` при превышении числа одновременных вычислений паролей; вход также ограничивает число активных сессий. Сессии хранятся в памяти и исчезают после перезапуска. Выход завершает только сессию переданного токена.
|
|
448
477
|
|
|
449
|
-
|
|
478
|
+
OpenAPI описывает все маршруты auth и требования Bearer-токена. В Swagger UI токен из ответа на вход можно вставить в **Authorize**. Для экспорта схем включите auth в конфигурации и выполните `generate openapi server.config.js`; файл учётных записей при генерации не читается. Методы auth доступны через REST. В GraphQL тот же токен проверяется при изменении записей. Для GraphQL и OpenAPI нужна `database.schema`.
|
|
450
479
|
|
|
451
480
|
## Даты записей, удаление и владельцы
|
|
452
481
|
|
package/dist/index.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ export { hashPassword } from './src/auth/public.js';
|
|
|
3
3
|
export type { EntityDefinition, Field, ModelSchema } from './src/core/model.js';
|
|
4
4
|
export type { FileUpdate } from './src/files/contract.js';
|
|
5
5
|
export type { FileMetadata } from './src/files/http.js';
|
|
6
|
-
export {
|
|
7
|
-
export
|
|
8
|
-
export {
|
|
9
|
-
export
|
|
6
|
+
export type { GraphqlOptions } from './src/graphql/entry.js';
|
|
7
|
+
export { generateGraphql, writeGraphql } from './src/graphql/entry.js';
|
|
8
|
+
export type { OpenapiOptions } from './src/openapi/entry.js';
|
|
9
|
+
export { generateOpenapi, writeOpenapi } from './src/openapi/entry.js';
|
|
10
10
|
export type { OpenapiDocument } from './src/openapi/types.js';
|
|
11
11
|
export type { DatabaseConfig, DeepJsonServerConfig, FilesConfig, GraphqlConfig, MemoryFile, OpenapiConfig, ServerConfig } from './src/server/config.js';
|
|
12
12
|
export type { ServerFacade } from './src/server/create.js';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { hashPassword } from './src/auth/public.js';
|
|
2
|
-
export { generateGraphql, writeGraphql } from './src/graphql/
|
|
3
|
-
export { generateOpenapi, writeOpenapi } from './src/openapi/
|
|
2
|
+
export { generateGraphql, writeGraphql } from './src/graphql/entry.js';
|
|
3
|
+
export { generateOpenapi, writeOpenapi } from './src/openapi/entry.js';
|
|
4
4
|
export { createServer } from './src/server/create.js';
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAKpD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAIvE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -19,8 +19,11 @@ export interface AuthSession {
|
|
|
19
19
|
}
|
|
20
20
|
export declare const AUTH_PATHS: {
|
|
21
21
|
readonly login: '/auth/login';
|
|
22
|
+
readonly register: '/auth/register';
|
|
22
23
|
readonly me: '/auth/me';
|
|
23
24
|
readonly logout: '/auth/logout';
|
|
25
|
+
readonly password: '/auth/users/:id/password';
|
|
26
|
+
readonly admin: '/auth/users/:id/admin';
|
|
24
27
|
};
|
|
25
28
|
export declare const DEFAULT_SESSION_SECONDS = 3600;
|
|
26
29
|
export declare const MAX_USERNAME_LENGTH = 256;
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
export const AUTH_PATHS = {
|
|
1
|
+
export const AUTH_PATHS = {
|
|
2
|
+
login: '/auth/login',
|
|
3
|
+
register: '/auth/register',
|
|
4
|
+
me: '/auth/me',
|
|
5
|
+
logout: '/auth/logout',
|
|
6
|
+
password: '/auth/users/:id/password',
|
|
7
|
+
admin: '/auth/users/:id/admin',
|
|
8
|
+
};
|
|
2
9
|
export const DEFAULT_SESSION_SECONDS = 3600;
|
|
3
10
|
export const MAX_USERNAME_LENGTH = 256;
|
|
4
11
|
export const MAX_PASSWORD_LENGTH = 1024;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/auth/contract.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAC,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/auth/contract.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,KAAK,EAAE,aAAa;IACpB,QAAQ,EAAE,gBAAgB;IAC1B,EAAE,EAAE,UAAU;IACd,MAAM,EAAE,cAAc;IACtB,QAAQ,EAAE,0BAA0B;IACpC,KAAK,EAAE,uBAAuB;CACtB,CAAC;AACX,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AACvC,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Принимает только непустое имя и допустимый пароль без дополнительных полей.
|
|
2
|
+
* @example { username: 'anna', password: 'secret' } → та же пара строк; дополнительный isAdmin → ошибка.
|
|
3
|
+
*/
|
|
4
|
+
export declare function credentials(body: unknown): {
|
|
5
|
+
username: string;
|
|
6
|
+
password: string;
|
|
7
|
+
};
|
|
8
|
+
/** Проверяет новый пароль и необязательный текущий пароль; оба значения возвращает без преобразований.
|
|
9
|
+
* @example { newPassword: 'next' } → { newPassword: 'next', currentPassword: undefined }; пустой пароль → ошибка.
|
|
10
|
+
*/
|
|
11
|
+
export declare function passwordChange(body: unknown): {
|
|
12
|
+
newPassword: string;
|
|
13
|
+
currentPassword?: string;
|
|
14
|
+
};
|
|
15
|
+
/** Принимает единственный логический флаг без преобразования строк и чисел.
|
|
16
|
+
* @example { isAdmin: false } → false; { isAdmin: 'false' } → ошибка.
|
|
17
|
+
*/
|
|
18
|
+
export declare function adminChange(body: unknown): boolean;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { domainError } from '../core/errors.js';
|
|
2
|
+
import { hasOnlyKeys, isObject } from '../core/utils.js';
|
|
3
|
+
import { MAX_USERNAME_LENGTH } from './contract.js';
|
|
4
|
+
import { validPassword } from './password.js';
|
|
5
|
+
/** Принимает только непустое имя и допустимый пароль без дополнительных полей.
|
|
6
|
+
* @example { username: 'anna', password: 'secret' } → та же пара строк; дополнительный isAdmin → ошибка.
|
|
7
|
+
*/
|
|
8
|
+
export function credentials(body) {
|
|
9
|
+
if (!isObject(body) ||
|
|
10
|
+
!hasOnlyKeys(body, ['username', 'password']) ||
|
|
11
|
+
typeof body.username !== 'string' ||
|
|
12
|
+
!body.username.trim() ||
|
|
13
|
+
body.username.length > MAX_USERNAME_LENGTH ||
|
|
14
|
+
!validPassword(body.password))
|
|
15
|
+
throw domainError('INVALID_INPUT', 'Supply username and password');
|
|
16
|
+
return { username: body.username, password: body.password };
|
|
17
|
+
}
|
|
18
|
+
/** Проверяет новый пароль и необязательный текущий пароль; оба значения возвращает без преобразований.
|
|
19
|
+
* @example { newPassword: 'next' } → { newPassword: 'next', currentPassword: undefined }; пустой пароль → ошибка.
|
|
20
|
+
*/
|
|
21
|
+
export function passwordChange(body) {
|
|
22
|
+
if (!isObject(body) || !hasOnlyKeys(body, ['currentPassword', 'newPassword']) || !validPassword(body.newPassword) || (body.currentPassword !== undefined && !validPassword(body.currentPassword)))
|
|
23
|
+
throw domainError('INVALID_INPUT', 'Supply newPassword and an optional currentPassword');
|
|
24
|
+
return { newPassword: body.newPassword, currentPassword: body.currentPassword };
|
|
25
|
+
}
|
|
26
|
+
/** Принимает единственный логический флаг без преобразования строк и чисел.
|
|
27
|
+
* @example { isAdmin: false } → false; { isAdmin: 'false' } → ошибка.
|
|
28
|
+
*/
|
|
29
|
+
export function adminChange(body) {
|
|
30
|
+
if (!isObject(body) || !hasOnlyKeys(body, ['isAdmin']) || typeof body.isAdmin !== 'boolean')
|
|
31
|
+
throw domainError('INVALID_INPUT', 'Supply a boolean isAdmin');
|
|
32
|
+
return body.isAdmin;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../../src/auth/input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,IACE,CAAC,QAAQ,CAAC,IAAI,CAAC;QACf,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ;QACjC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;QACrB,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,mBAAmB;QAC1C,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;QAE7B,MAAM,WAAW,CAAC,eAAe,EAAE,8BAA8B,CAAC,CAAC;IACrE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAa;IAC1C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,KAAK,SAAS,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC/L,MAAM,WAAW,CAAC,eAAe,EAAE,oDAAoD,CAAC,CAAC;IAC3F,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,eAAe,EAAE,IAAI,CAAC,eAAqC,EAAE,CAAC;AACxG,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,SAAS;QAAE,MAAM,WAAW,CAAC,eAAe,EAAE,0BAA0B,CAAC,CAAC;IAC5J,OAAO,IAAI,CAAC,OAAO,CAAC;AACtB,CAAC"}
|
|
@@ -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>;
|