Merge pull request #216 from dadosfera/feat/generate-token

Feat: generate token
This commit is contained in:
Gabriel Amorim
2023-05-17 10:03:00 -03:00
committed by GitHub
12 changed files with 1897 additions and 2205 deletions
+1 -1
View File
@@ -1 +1 @@
18.3.0
18.10.0
+3 -3
View File
@@ -1,5 +1,5 @@
# install all dependencies
FROM node:18.3.0-alpine3.15 as packages
FROM node:18.10-alpine as packages
WORKDIR /app
COPY package.json package-lock.json ./
RUN apk add --no-cache aws-cli \
@@ -7,12 +7,12 @@ RUN apk add --no-cache aws-cli \
&& npm install
# unit test specific build
FROM node:18.3.0-alpine3.15 as test
FROM node:18.10-alpine as test
WORKDIR /app
COPY --from=packages /app/node_modules ./node_modules
COPY . ./
FROM node:18.3.0-alpine3.15
FROM node:18.10-alpine
WORKDIR /app
COPY . /app/
COPY --from=packages /app/node_modules ./node_modules
+1 -1
View File
@@ -12,7 +12,7 @@ These instructions will allow you to get a working copy of the project on your l
### 📋 Requirements
- [NodeJS v18.3.0 LTS / NPM v8.11](https://nodejs.org/pt-br/download/) (you can opt to use [NVM](https://github.com/nvm-sh/nvm) to easily manage node versions)
- [NodeJS v18.10.0 LTS / NPM v8.11](https://nodejs.org/pt-br/download/) (you can opt to use [NVM](https://github.com/nvm-sh/nvm) to easily manage node versions)
- Request access to AWS Console dev account for **all services** (avoid gradually asking for each needed service. it will slow down your development cycle)
- Create your Access Key on the "Security credentials" menu
- Set the Access Key on your local development machine
+1 -1
View File
@@ -1752,7 +1752,7 @@
}
},
"info": {
"title": "Maestro - feature/customer-links",
"title": "Maestro - feat/generate-token",
"description": "This is the Maestro API",
"version": "1.0.0",
"contact": {}
+39 -4
View File
@@ -4979,9 +4979,6 @@
"Customers"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
@@ -5025,6 +5022,44 @@
]
}
},
"/customers/token": {
"get": {
"operationId": "CustomersController_getCustomerToken",
"parameters": [
{
"name": "exp",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
},
"tags": [
"Customers"
],
"security": [
{
"access-token": []
},
{
"access-token": []
}
]
}
},
"/health": {
"get": {
"operationId": "HealthController_check",
@@ -5041,7 +5076,7 @@
}
},
"info": {
"title": "Maestro - feature/customer-links",
"title": "Maestro - feat/generate-token",
"description": "This is the Maestro API",
"version": "1.0.0",
"contact": {}
+1740 -2179
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -6,7 +6,7 @@
"private": true,
"license": "UNLICENSED",
"engines": {
"node": "18.3.0"
"node": "18.10.0"
},
"scripts": {
"preinstall": "aws codeartifact login --tool npm --namespace @dadosfera --repository dadosfera-npm --domain dadosfera --domain-owner 611330257153 --region us-east-1",
@@ -32,18 +32,20 @@
"@dadosfera/protospack-v2": "3.31.0",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
"@nestjs/config": "^1.2.1",
"@nestjs/core": "^8.4.7",
"@nestjs/mapped-types": "*",
"@nestjs/microservices": "^8.4.7",
"@nestjs/passport": "^8.2.2",
"@nestjs/platform-express": "^8.4.7",
"@nestjs/schedule": "^1.1.0",
"@nestjs/swagger": "^5.2.1",
"@nestjs/cli": "^9.4.2",
"@nestjs/common": "^9.4.0",
"@nestjs/config": "^2.3.1",
"@nestjs/core": "^9.4.0",
"@nestjs/mapped-types": "^1.2.2",
"@nestjs/microservices": "^9.4.0",
"@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.4.0",
"@nestjs/schematics": "^9.1.0",
"@nestjs/swagger": "^6.3.0",
"@nestjs/testing": "^9.4.0",
"axios": "^0.27.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"class-validator": "^0.14.0",
"cron-parser": "^4.4.0",
"dotenv": "^14.3.2",
"elastic-apm-node": "^3.36.0",
@@ -51,6 +53,7 @@
"jsonwebtoken": "^9.0.0",
"jwk-to-pem": "^2.0.5",
"mixpanel": "^0.17.0",
"ms": "^3.0.0-canary.1",
"passport": "^0.6.0",
"passport-facebook": "^3.0.0",
"passport-forcedotcom": "^0.2.0",
@@ -67,9 +70,6 @@
"multer": "1.4.5-lts.1"
},
"devDependencies": {
"@nestjs/cli": "^8.2.8",
"@nestjs/schematics": "^8.0.11",
"@nestjs/testing": "^8.4.7",
"@types/express": "^4.17.13",
"@types/jest": "27.0.2",
"@types/jsonwebtoken": "^8.5.8",
+10
View File
@@ -55,6 +55,16 @@ export const PERMISSIONS_GROUPS = {
'es-es': '',
},
},
GENERATE_TOKEN: {
seqid: 46,
claim: 'customer:generate-token',
usage: PermissionUsages.PUBLIC,
name: {
'pt-br': 'Gerar Token de Acesso',
'en-us': 'Generate Acess Token',
'es-es': 'Gerar Token de Acceso',
},
},
},
},
@@ -7,6 +7,7 @@ import {
Inject,
Param,
Put,
Query,
UseFilters,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
@@ -19,6 +20,8 @@ import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
import { CustomersService } from './customers.service';
import { CustomerDto, CustomerLinksResponse } from './dtos/customers';
import { RequestUser, User } from 'src/decorators/user.decorator';
import type { StringValue } from 'ms';
@ApiInternalOnlyController()
@ApiTags('Customers')
@@ -53,4 +56,19 @@ export class CustomersController {
this.logger.info('setCustomerLinks', { id, links });
return this.customersService.setLinks(id, links);
}
@Get('token')
@RequireAllPermissions(PERMISSIONS_GROUPS.AUTH.permissions.GENERATE_TOKEN)
async getCustomerToken(
@Query('exp') exp: StringValue,
@User() user: RequestUser,
): Promise<string> {
this.logger.info('getCustomerToken', { exp, user });
const data = {
customerId: user.customer_id,
userId: user.user_id,
customerName: user.customer_name,
};
return this.customersService.generateToken(exp, data);
}
}
@@ -4,6 +4,7 @@ import {
Injectable,
HttpException,
HttpStatus,
InternalServerErrorException,
} from '@nestjs/common';
import { firstValueFrom, lastValueFrom } from 'rxjs';
@@ -14,7 +15,15 @@ import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc';
import { CustomerUpdateRequest } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
import { CustomersProtoService } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service';
import ErrorCodes from 'src/utils/errorCodes';
import jwt from 'jsonwebtoken';
import {
GetSecretValueCommand,
SecretsManagerClient,
} from '@aws-sdk/client-secrets-manager';
import getEnv from 'src/utils/getEnv';
import { logger } from 'elastic-apm-node';
// This function will accept any string, which may result in a bug.
@Injectable()
export class CustomersService implements OnModuleInit {
private customerService: CustomersProtoService;
@@ -60,4 +69,55 @@ export class CustomersService implements OnModuleInit {
else throw err;
}
}
async generateToken(
expiresIn = '30m',
data: { customerId: string; userId: string; customerName: string },
) {
const { customerId, userId: generatedById, customerName } = data;
const secretsManagerClient = new SecretsManagerClient({});
const getSecretComand = new GetSecretValueCommand({
SecretId: `${getEnv()}/${customerName}/jwt-signing-key`,
});
let private_key_pem;
await secretsManagerClient
.send(getSecretComand)
.then((res) => {
const secret = JSON.parse(res.SecretString);
private_key_pem = secret.private_key_pem;
})
.catch((err) => {
logger.error(err.stack);
throw new InternalServerErrorException(
'Error finding keys for customer',
);
});
let jwt_token;
try {
jwt_token = jwt.sign(
{
customerId,
generatedById,
},
private_key_pem,
{
algorithm: 'RS256',
expiresIn,
issuer: 'maestro',
},
);
} catch (err) {
logger.error(err.stack);
throw new InternalServerErrorException('Error generating token');
}
// const verify = jwt.verify(jwt_token, public_key_pem, {
// algorithms: ['RS256'],
// issuer: 'maestro',
// });
// const decoded = jwt.decode(jwt_token, { complete: true });
return jwt_token;
}
}
-2
View File
@@ -5,7 +5,6 @@ import {
Inject,
Injectable,
} from '@nestjs/common';
import { Timeout } from '@nestjs/schedule';
import CronParser, { CronExpression } from 'cron-parser';
import { ClientGrpc } from '@nestjs/microservices';
import DadosferaLogger from '@dadosfera/dadosfera-logs/dist';
@@ -222,7 +221,6 @@ export class InputsService {
return lastValueFrom(this.inputWriteService.InputRemove(idRequest));
}
@Timeout(60000 * 10) // Timeout set for 10 minutes
async testConnection(data) {
try {
const testConnectionInputResponse =
+10
View File
@@ -0,0 +1,10 @@
const availableLocalEnvs: Array<typeof process.env.ENV> = ['stg', 'test'];
export default function getEnv(): typeof process.env.ENV {
if (process.env.ENV === 'local') {
if (availableLocalEnvs.includes(process.env.LOCAL_ENV))
return process.env.LOCAL_ENV;
return 'stg';
}
return process.env.ENV;
}