diff --git a/.gitignore b/.gitignore index d3d969e..4b56acf 100755 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ /dist /node_modules /build -/keys # Logs logs diff --git a/keys/private.pem b/keys/private.pem new file mode 100644 index 0000000..2a5052a --- /dev/null +++ b/keys/private.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCb+gKyoUDyEX1M +y/hRfkQh4O/UpfMj4oUhp9n6BTUhaASZY/Xp57xXDX6PsjGX0N3tTFz0OFxZEHpk +PCoJhvdLfPnNps4iRrvA00GlMSZEquZX8TOKEDD4T3oqxy3Q8d43ZgXJ0+KYyd0E +PpWhFaJZKFAPgWSUhAqoFiu5rQ2S4iQWyFgvMLesBtxPwaQuRxscqsoiXJ65wIvD +Kbad3lRygj58qoMHX/clgQolFpmAWq2GiR4UE3hJX20xovN4kOTds2hMDFG09u24 +nyZVMv0/SmHOOisbFPFXtJsA22YHdOubqghd4KpjjQC7L5lNQRWv6EPhfGzxMy+O +5Py+sx5VAgMBAAECggEAC06piWeVPLc13S5gNxAvQkF7QXAyWySdwB3Z+H0OJ/jR +dIlBl45cIfdxeFtTqwzSOdSyXGYFk9NU/BU8eupU3R0XQuhXwzZbgBQQizgv7QRy +pGdw9A5OboHcemNsF9yg3mVAACyjHa5snlUnJcFavpnki+s2bmnQF/VbgB9if4ZW +S07UsJCB6kyzuhDnBJYkB8Ibuxk5951hpegHy4KzfVwajBHe4iRT5IyfqtxxU1lZ +by3PISFqosjlvV2TrZlb3J4qllHkm3JRTD1XlGekb3f4o2geoIv4bimhz3tRJ3mS +tpPiNpJnOIQacNhn1Vjk03s0DfQGuqY75NyXkd8sVQKBgQDV5QtLfRf/d0RdAgfj +7AZYagd9izkpBky6OwJZwxabqSFQ4vMgOaMdVKchc0P/d5pdSWSSjkywDUp0RcDL +foNCt/yEfUeBWxGOqCvsBhEvflSEUFzSkvgIWLHI5HYdWJ1geEXAVFx00b/3bLpj +Zioug2w2bZLa0mjPsXBcqmIW+wKBgQC6rkGaVXXbq/hu4bWY85MdcWCsRrFilLhY +ECw6cqaVYchjpk10J0fQcl2kZfLr8rr9m2zymtDDX9TuPQPG7F1o7KZ/jvHrDxwh +cg1l3EtpCiqA5k2+qKBVPZ7Cv35px1HZQtPUz1fSDR9fXGwDiPhJtM7XqzFAuE5p +1A29GPbe7wKBgD9LHLGE3dIRt+AR1sXiNOp6zaafyRVTsOa2yXZIXWtIe/xUe/9A +Lv1h7GbglfGFsd8C9cjMZPL/q9WGQou07yCSEx4deEhV63ccWoroLLOyHU5d/Wmu +ZckKfelleXIro75FONa13/oNi1GrEeiR9c93wlDE0d0AwFUdO5OgM5B7AoGAa+is +nUTHMuruWVH5QeeSY5OVGSBoCx8CjE0U89gwOOtkBU4tOXY3SePCA3S2/fK6ajx8 +tqQNBtKPaAM2+rbIrA0XlWaQqpp6XU7rNbUolhg9R3NY/1vECmHrMpG0xfpkcpzx +i/MqxY22U8491bFILHrqkbowZ0Pid8QPCP60PVsCgYAB83iEuuisaLoIC3fePm/1 +7wuEisVAdLBnPf8ZhRpD6qdZkOlFHQFq4nnpEOkrW0GY0KLvPsVcE0zuak3kLaiy +9dS1qbfCD8T0wp/oqUXQ7p5GuoLAb2l7MMCQSwBKfAGrQm9gMyXjB05nhAQ0U+dE +qEe/CUjVZ2MsMb/Z9z8EfQ== +-----END PRIVATE KEY----- diff --git a/keys/public.pem b/keys/public.pem new file mode 100644 index 0000000..6120574 --- /dev/null +++ b/keys/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm/oCsqFA8hF9TMv4UX5E +IeDv1KXzI+KFIafZ+gU1IWgEmWP16ee8Vw1+j7Ixl9Dd7Uxc9DhcWRB6ZDwqCYb3 +S3z5zabOIka7wNNBpTEmRKrmV/EzihAw+E96Ksct0PHeN2YFydPimMndBD6VoRWi +WShQD4FklIQKqBYrua0NkuIkFshYLzC3rAbcT8GkLkcbHKrKIlyeucCLwym2nd5U +coI+fKqDB1/3JYEKJRaZgFqthokeFBN4SV9tMaLzeJDk3bNoTAxRtPbtuJ8mVTL9 +P0phzjorGxTxV7SbANtmB3Trm6oIXeCqY40Auy+ZTUEVr+hD4Xxs8TMvjuT8vrMe +VQIDAQAB +-----END PUBLIC KEY----- diff --git a/package.json b/package.json index f4b22e1..219b74d 100755 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "dotenv": "^16.4.7", "fastify": "^5.2.1", "handlebars": "^4.7.8", + "node-jose": "^2.2.0", "nodemailer": "^6.9.16", "passport-jwt": "^4.0.1", "pg": "^8.13.1", @@ -77,6 +78,7 @@ "@types/bcrypt": "^5.0.2", "@types/jest": "^29.5.14", "@types/node": "^20.17.14", + "@types/node-jose": "^1.1.13", "@types/nodemailer": "^6.4.17", "@types/passport-jwt": "^4.0.1", "@types/supertest": "^6.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ecc4cdc..d88823f 100755 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -101,6 +101,9 @@ importers: handlebars: specifier: ^4.7.8 version: 4.7.8 + node-jose: + specifier: ^2.2.0 + version: 2.2.0 nodemailer: specifier: ^6.9.16 version: 6.9.16 @@ -144,6 +147,9 @@ importers: '@types/node': specifier: ^20.17.14 version: 20.17.15 + '@types/node-jose': + specifier: ^1.1.13 + version: 1.1.13 '@types/nodemailer': specifier: ^6.4.17 version: 6.4.17 @@ -1505,6 +1511,9 @@ packages: '@types/mjml@4.7.4': resolution: {integrity: sha512-vyi1vzWgMzFMwZY7GSZYX0GU0dmtC8vLHwpgk+NWmwbwRSrlieVyJ9sn5elodwUfklJM7yGl0zQeet1brKTWaQ==} + '@types/node-jose@1.1.13': + resolution: {integrity: sha512-QjMd4yhwy1EvSToQn0YI3cD29YhyfxFwj7NecuymjLys2/P0FwxWnkgBlFxCai6Y3aBCe7rbwmqwJJawxlgcXw==} + '@types/node@20.17.15': resolution: {integrity: sha512-ymrDMpEhuYz7PXTItXhY0ZDBDZT/RgsmFM9rBiRLOSVX1HKJhhrLXuLY00fHsFsugYT1wZU3IC4dleUUC22UDQ==} @@ -1891,6 +1900,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + base64url@3.0.1: + resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} + engines: {node: '>=6.0.0'} + bcrypt@5.1.1: resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} engines: {node: '>= 10.0.0'} @@ -2510,6 +2523,9 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -3736,6 +3752,9 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} + long@5.3.1: + resolution: {integrity: sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==} + lower-case@1.1.4: resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} @@ -4033,6 +4052,10 @@ packages: encoding: optional: true + node-forge@1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + node-gyp-build-optional-packages@5.2.2: resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} hasBin: true @@ -4040,6 +4063,9 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-jose@2.2.0: + resolution: {integrity: sha512-XPCvJRr94SjLrSIm4pbYHKLEaOsDvJCpyFw/6V/KK/IXmyZ6SFBzAUDO9HQf4DB/nTEFcRGH87mNciOP23kFjw==} + node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} @@ -4201,6 +4227,9 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + param-case@2.1.1: resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} @@ -4407,6 +4436,10 @@ packages: process-warning@4.0.1: resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + promise@7.3.1: resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} @@ -7372,6 +7405,10 @@ snapshots: '@types/mjml-core': 4.15.1 optional: true + '@types/node-jose@1.1.13': + dependencies: + '@types/node': 20.17.15 + '@types/node@20.17.15': dependencies: undici-types: 6.19.8 @@ -7881,6 +7918,8 @@ snapshots: base64-js@1.5.1: {} + base64url@3.0.1: {} + bcrypt@5.1.1: dependencies: '@mapbox/node-pre-gyp': 1.0.11 @@ -8593,6 +8632,8 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + es6-promise@4.2.8: {} + escalade@3.2.0: {} escape-goat@3.0.0: @@ -10205,6 +10246,8 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 9.0.0 + long@5.3.1: {} + lower-case@1.1.4: optional: true @@ -10716,6 +10759,8 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-forge@1.3.1: {} + node-gyp-build-optional-packages@5.2.2: dependencies: detect-libc: 2.0.3 @@ -10723,6 +10768,18 @@ snapshots: node-int64@0.4.0: {} + node-jose@2.2.0: + dependencies: + base64url: 3.0.1 + buffer: 6.0.3 + es6-promise: 4.2.8 + lodash: 4.17.21 + long: 5.3.1 + node-forge: 1.3.1 + pako: 2.1.0 + process: 0.11.10 + uuid: 9.0.1 + node-releases@2.0.19: {} nodemailer@6.9.16: {} @@ -10903,6 +10960,8 @@ snapshots: package-json-from-dist@1.0.1: {} + pako@2.1.0: {} + param-case@2.1.1: dependencies: no-case: 2.3.2 @@ -11104,6 +11163,8 @@ snapshots: process-warning@4.0.1: {} + process@0.11.10: {} + promise@7.3.1: dependencies: asap: 2.0.6 diff --git a/src/common/transformers/decimal.transformer.ts b/src/common/transformers/decimal.transformer.ts index 6120a90..88bf8e2 100755 --- a/src/common/transformers/decimal.transformer.ts +++ b/src/common/transformers/decimal.transformer.ts @@ -3,18 +3,8 @@ import Decimal from "decimal.js"; import { ValueTransformer } from "typeorm"; export class DecimalTransformer implements ValueTransformer { - // to(value: Decimal | string | number): string { - // return new Decimal(value).toString(); - // } - - // from(value: string): number { - // return new Decimal(value).toNumber(); - // } - - to(value: Decimal | number | null): string | null { - if (value === null) return "0"; - - return value instanceof Decimal ? value.toString() : new Decimal(value).toString(); + to(value: Decimal | null): string | null { + return value ? value.toString() : "0"; } from(value: string | null): number { diff --git a/src/configs/jwt.config.ts b/src/configs/jwt.config.ts index 882203b..d07ef35 100755 --- a/src/configs/jwt.config.ts +++ b/src/configs/jwt.config.ts @@ -1,11 +1,24 @@ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + import { ConfigService } from "@nestjs/config"; import { JwtModuleAsyncOptions } from "@nestjs/jwt"; export function jwtConfig(): JwtModuleAsyncOptions { return { inject: [ConfigService], - useFactory: (configService: ConfigService) => ({ - secret: configService.getOrThrow("JWT_SECRET_KEY"), - }), + useFactory: (configService: ConfigService) => { + const privateKeyPath = join(process.cwd(), "keys", "private.pem"); + const publicKeyPath = join(process.cwd(), "keys", "public.pem"); + + return { + privateKey: readFileSync(privateKeyPath, "utf8"), + publicKey: readFileSync(publicKeyPath, "utf8"), + signOptions: { + algorithm: "RS256", + issuer: configService.getOrThrow("JWT_ISSUER"), + }, + }; + }, }; } diff --git a/src/modules/auth/strategies/jwt.strategy.ts b/src/modules/auth/strategies/jwt.strategy.ts index 4d80890..b089942 100755 --- a/src/modules/auth/strategies/jwt.strategy.ts +++ b/src/modules/auth/strategies/jwt.strategy.ts @@ -1,3 +1,5 @@ +import { readFileSync } from "fs"; + import { Injectable } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { PassportStrategy } from "@nestjs/passport"; @@ -12,7 +14,9 @@ export class JwtStrategy extends PassportStrategy(Strategy, JWT_STRATEGY_NAME) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, - secretOrKey: configService.getOrThrow("JWT_SECRET_KEY"), + secretOrKey: readFileSync(`${process.cwd()}/keys/public.pem`, "utf8"), + algorithms: ["RS256"], + issuer: configService.getOrThrow("JWT_ISSUER"), }); }