commit be1e21e699bb6bb31fa979e47d34286fc26697bb Author: Дмитрий Date: Fri Mar 27 10:38:23 2026 +0300 first commit diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..9b346b7 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,32 @@ +name: Publish + +on: + push: + branches: + - main + +jobs: + publish: + name: Publish Job + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: 'https://git.lendry.ru/api/packages/lendry-erp/npm/' + scope: '@lendry-erp' + + - name: Install deps + run: npm ci + + - name: Build + run: npm run build + + - name: Publish package + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa52e45 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +node_modules/ +dist/ +build/ +pnpm-lock.yaml +.env +.DS_Store +.vscode/ +.log \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..1b38f0f --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +@lendry-erp:registry=https://git.lendry.ru/api/packages/lendry-erp/npm/ \ No newline at end of file diff --git a/lib/constants/index.ts b/lib/constants/index.ts new file mode 100644 index 0000000..380998f --- /dev/null +++ b/lib/constants/index.ts @@ -0,0 +1 @@ +export * from './passport.constants' diff --git a/lib/constants/passport.constants.ts b/lib/constants/passport.constants.ts new file mode 100644 index 0000000..7aa03f1 --- /dev/null +++ b/lib/constants/passport.constants.ts @@ -0,0 +1 @@ +export const PASSPORT_OPTIONS = Symbol('PassportOptions') diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 0000000..2472f1f --- /dev/null +++ b/lib/index.ts @@ -0,0 +1,3 @@ +export * from './interfaces' +export * from './passport.module' +export * from './passport.service' diff --git a/lib/interfaces/index.ts b/lib/interfaces/index.ts new file mode 100644 index 0000000..df4a36b --- /dev/null +++ b/lib/interfaces/index.ts @@ -0,0 +1,3 @@ +export * from './passport-async-options.interface' +export * from './passport-options.interface' +export * from './token.interface' diff --git a/lib/interfaces/passport-async-options.interface.ts b/lib/interfaces/passport-async-options.interface.ts new file mode 100644 index 0000000..3f100bc --- /dev/null +++ b/lib/interfaces/passport-async-options.interface.ts @@ -0,0 +1,8 @@ +import type { FactoryProvider, ModuleMetadata } from '@nestjs/common' + +import { PassportOptions } from './passport-options.interface' + +export interface PassportAsyncOptions extends Pick { + useFactory: (...args: any[]) => Promise | PassportOptions + inject?: FactoryProvider['inject'] +} diff --git a/lib/interfaces/passport-options.interface.ts b/lib/interfaces/passport-options.interface.ts new file mode 100644 index 0000000..d1a590d --- /dev/null +++ b/lib/interfaces/passport-options.interface.ts @@ -0,0 +1,3 @@ +export interface PassportOptions { + secretKey: string +} diff --git a/lib/interfaces/token.interface.ts b/lib/interfaces/token.interface.ts new file mode 100644 index 0000000..8dac8f5 --- /dev/null +++ b/lib/interfaces/token.interface.ts @@ -0,0 +1,13 @@ +export interface TokenPayload { + sub: string +} + +// роли храним в токене +export interface TokenRolePayload { + id: string | number + name: string +} + +export type VerifyResult = + | { valid: true; userId: string; jti: string; role: TokenRolePayload } + | { valid: false; reason: string } diff --git a/lib/passport.module.ts b/lib/passport.module.ts new file mode 100644 index 0000000..32cb5ab --- /dev/null +++ b/lib/passport.module.ts @@ -0,0 +1,34 @@ +import { type DynamicModule, Global, Module } from '@nestjs/common' + +import { PASSPORT_OPTIONS } from './constants' +import type { PassportAsyncOptions, PassportOptions } from './interfaces' +import { + createPassportAsyncOptionsProvider, + createPassportOptionsProvider +} from './passport.provider' +import { PassportService } from './passport.service' + +@Global() +@Module({}) +export class PassportModule { + public static register(options: PassportOptions): DynamicModule { + const optionsProvider = createPassportOptionsProvider(options) + + return { + module: PassportModule, + providers: [optionsProvider, PassportService], + exports: [PassportService, PASSPORT_OPTIONS] + } + } + + public static registerAsync(options: PassportAsyncOptions): DynamicModule { + const optionsProvider = createPassportAsyncOptionsProvider(options) + + return { + module: PassportModule, + imports: options.imports ?? [], + providers: [optionsProvider, PassportService], + exports: [PassportService, PASSPORT_OPTIONS] + } + } +} diff --git a/lib/passport.provider.ts b/lib/passport.provider.ts new file mode 100644 index 0000000..1f8aa89 --- /dev/null +++ b/lib/passport.provider.ts @@ -0,0 +1,33 @@ +import type { Provider } from '@nestjs/common' + +import { PASSPORT_OPTIONS } from './constants' +import type { PassportAsyncOptions, PassportOptions } from './interfaces' + +export function createPassportOptionsProvider( + options: PassportOptions +): Provider { + return { + provide: PASSPORT_OPTIONS, + useValue: Object.freeze({ ...options }) + } +} + +export function createPassportAsyncOptionsProvider( + options: PassportAsyncOptions +): Provider { + return { + provide: PASSPORT_OPTIONS, + useFactory: async (...args: any[]) => { + const resolved = await options.useFactory!(...args) + + if (!resolved || typeof resolved.secretKey !== 'string') { + throw new Error( + '[Passport Module] "secretKey" обязателен для заполнения и должен быть строкой.' + ) + } + + return Object.freeze({ ...resolved }) + }, + inject: options.inject ?? [] + } +} diff --git a/lib/passport.service.ts b/lib/passport.service.ts new file mode 100644 index 0000000..90af7b6 --- /dev/null +++ b/lib/passport.service.ts @@ -0,0 +1,124 @@ +import { Inject, Injectable } from '@nestjs/common' +import { createHmac, randomUUID } from 'crypto' + +import { PASSPORT_OPTIONS } from './constants' +import { PassportOptions, TokenRolePayload } from './interfaces' +import { base64UrlDecode, base64UrlEncode, constantTimeEqual } from './utils' + +const TOKEN_TYPES = { + AUTH: 'PassportToken/v1', + TEMP_2FA: 'PassportToken/v1/2fa' +} as const + +type TokenType = (typeof TOKEN_TYPES)[keyof typeof TOKEN_TYPES] + +@Injectable() +export class PassportService { + private readonly SECRET_KEY: string + + private static readonly INTERNAL_SEPARATOR = '|' + + public constructor( + @Inject(PASSPORT_OPTIONS) private readonly options: PassportOptions + ) { + this.SECRET_KEY = options.secretKey + } + + public generate( + userId: string, + role: TokenRolePayload, + ttl: number, + tokenType: TokenType = TOKEN_TYPES.AUTH + ) { + const issuedAt = this.now() + const expiresAt = issuedAt + ttl + + const jti = randomUUID() + + const userPart = base64UrlEncode(userId) + const rolePart = base64UrlEncode(JSON.stringify(role)) + const iatPart = base64UrlEncode(String(issuedAt)) + const expPart = base64UrlEncode(String(expiresAt)) + const jtiPart = base64UrlEncode(jti) + + const serialized = this.serialize( + tokenType, + userPart, + rolePart, + iatPart, + expPart, + jtiPart + ) + const mac = this.computeHmac(this.SECRET_KEY, serialized) + + return `${userPart}.${rolePart}.${iatPart}.${expPart}.${jtiPart}.${mac}` + } + + public verify(token: string, expectedType: TokenType = TOKEN_TYPES.AUTH) { + try { + const parts = token.split('.') + + if (parts.length !== 6) + return { valid: false, reason: 'Не верный формат токена.' } + + const [userPart, rolePart, iatPart, expPart, jtiPart, mac] = parts + + const serialized = this.serialize( + expectedType, + userPart, + rolePart, + iatPart, + expPart, + jtiPart + ) + + const expectedMac = this.computeHmac(this.SECRET_KEY, serialized) + + if (!constantTimeEqual(expectedMac, mac)) + return { + valid: false, + reason: 'Невалидная подпись токена или неверный формат.' + } + + const expNumber = Number(base64UrlDecode(expPart)) + + if (!Number.isFinite(expNumber)) + return { valid: false, reason: 'Ошибка формата даты.' } + if (this.now() > expNumber) + return { valid: false, reason: 'Срок действия токена истёк.' } + + const decodedRole = JSON.parse( + base64UrlDecode(rolePart) + ) as TokenRolePayload + return { + valid: true, + userId: base64UrlDecode(userPart), + role: decodedRole, + jti: base64UrlDecode(jtiPart) + } + } catch (error) { + return { valid: false, reason: 'Поврежденный токен.' } + } + } + + private now() { + return Math.floor(Date.now() / 1000) + } + + private serialize( + domain: string, + user: string, + role: string, + iat: string, + exp: string, + jti: string + ) { + return [domain, user, role, iat, exp, jti].join( + PassportService.INTERNAL_SEPARATOR + ) + } + + private computeHmac(secretKey: string, data: string) { + return createHmac('sha256', secretKey).update(data).digest('hex') + } +} diff --git a/lib/utils/base64.ts b/lib/utils/base64.ts new file mode 100644 index 0000000..dc688a0 --- /dev/null +++ b/lib/utils/base64.ts @@ -0,0 +1,17 @@ +export function base64UrlEncode(buf: Buffer | string) { + const s = typeof buf === 'string' ? Buffer.from(buf) : buf + + return s + .toString('base64') + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, '') +} + +export function base64UrlDecode(str: string) { + str = str.replace(/-/g, '+').replace(/_/g, '/') + + while (str.length % 4) str += '=' + + return Buffer.from(str, 'base64').toString() +} diff --git a/lib/utils/crypto.ts b/lib/utils/crypto.ts new file mode 100644 index 0000000..1f95b49 --- /dev/null +++ b/lib/utils/crypto.ts @@ -0,0 +1,10 @@ +import { timingSafeEqual } from 'crypto' + +export function constantTimeEqual(a: string, b: string) { + const bufA = Buffer.from(a) + const bufB = Buffer.from(b) + + if (bufA.length !== bufB.length) return false + + return timingSafeEqual(bufA, bufB) +} diff --git a/lib/utils/index.ts b/lib/utils/index.ts new file mode 100644 index 0000000..889470c --- /dev/null +++ b/lib/utils/index.ts @@ -0,0 +1,2 @@ +export * from './base64' +export * from './crypto' diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1913599 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,649 @@ +{ + "name": "passport", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "passport", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@nestjs/common": "^11.1.17", + "@nestjs/core": "^11.1.17", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.2" + }, + "devDependencies": { + "@lendry-erp/prettier-config": "^1.0.0", + "@types/node": "^25.5.0", + "prettier": "^3.8.1", + "typescript": "^6.0.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@borewit/text-codec": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lendry-erp/prettier-config": { + "version": "1.0.0", + "resolved": "https://git.lendry.ru/api/packages/lendry-erp/npm/%40lendry-erp%2Fprettier-config/-/1.0.0/prettier-config-1.0.0.tgz", + "integrity": "sha512-HpeOX5fJvU9O1rFhRUwiTgLssXyh+xNf97Ygl5p3drm2v2hwvxMR1GYK0pA50c/gUF2SKwkosdOpLJX9sq25vQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@trivago/prettier-plugin-sort-imports": "^5.2.2" + }, + "peerDependencies": { + "prettier": "^3.8.1" + } + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@nestjs/common": { + "version": "11.1.17", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.17.tgz", + "integrity": "sha512-hLODw5Abp8OQgA+mUO4tHou4krKgDtUcM9j5Ihxncst9XeyxYBTt2bwZm4e4EQr5E352S4Fyy6V3iFx9ggxKAg==", + "license": "MIT", + "dependencies": { + "file-type": "21.3.2", + "iterare": "1.2.1", + "load-esm": "1.0.3", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": ">=0.4.1", + "class-validator": ">=0.13.2", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/core": { + "version": "11.1.17", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.17.tgz", + "integrity": "sha512-lD5mAYekTTurF3vDaa8C2OKPnjiz4tsfxIc5XlcSUzOhkwWf6Ay3HKvt6FmvuWQam6uIIHX52Clg+e6tAvf/cg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@nuxt/opencollective": "0.4.1", + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "8.3.0", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "engines": { + "node": ">= 20" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^11.0.0", + "@nestjs/microservices": "^11.0.0", + "@nestjs/platform-express": "^11.0.0", + "@nestjs/websockets": "^11.0.0", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true + } + } + }, + "node_modules/@nuxt/opencollective": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.4.1.tgz", + "integrity": "sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + }, + "bin": { + "opencollective": "bin/opencollective.js" + }, + "engines": { + "node": "^14.18.0 || >=16.10.0", + "npm": ">=5.10.0" + } + }, + "node_modules/@tokenizer/inflate": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "token-types": "^6.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, + "node_modules/@trivago/prettier-plugin-sort-imports": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-5.2.2.tgz", + "integrity": "sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.7", + "@babel/traverse": "^7.26.7", + "@babel/types": "^7.26.7", + "javascript-natural-sort": "^0.7.1", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">18.12" + }, + "peerDependencies": { + "@vue/compiler-sfc": "3.x", + "prettier": "2.x - 3.x", + "prettier-plugin-svelte": "3.x", + "svelte": "4.x || 5.x" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + }, + "svelte": { + "optional": true + } + } + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, + "node_modules/file-type": { + "version": "21.3.2", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.2.tgz", + "integrity": "sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==", + "license": "MIT", + "dependencies": { + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "license": "ISC", + "engines": { + "node": ">=6" + } + }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/load-esm": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/load-esm/-/load-esm-1.0.3.tgz", + "integrity": "sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + }, + { + "type": "buymeacoffee", + "url": "https://buymeacoffee.com/borewit" + } + ], + "license": "MIT", + "engines": { + "node": ">=13.2.0" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/strtok3": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "license": "MIT", + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fa11877 --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "@lendry-erp/passport", + "version": "1.0.0", + "description": "Библиотека для аутентификации.", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsc -p tsconfig.build.json", + "format": "prettier --write \"lib/**/*.ts\"" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "devDependencies": { + "@lendry-erp/prettier-config": "^1.0.0", + "@types/node": "^25.5.0", + "prettier": "^3.8.1", + "typescript": "^6.0.2" + }, + "dependencies": { + "@nestjs/common": "^11.1.17", + "@nestjs/core": "^11.1.17", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.2" + } +} diff --git a/prettier.config.mjs b/prettier.config.mjs new file mode 100644 index 0000000..0227e7c --- /dev/null +++ b/prettier.config.mjs @@ -0,0 +1,3 @@ +import config from '@lendry-erp/prettier-config/prettier' + +export default config diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..b8df181 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "outDir": "./dist", + "rootDir": "./lib" + }, + "include": ["lib/**/*"], + "exclude": ["node_module", "dist", "test"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..53456e9 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2024", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "forceConsistentCasingInFileNames": true, + "strictNullChecks": false, + "types": ["node"] + } +}