mirror of
https://github.com/dadosfera/maestro.git
synced 2026-09-01 12:18:15 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3550255c4 | ||
|
|
54cb3f8e7a |
+244
@@ -5968,6 +5968,167 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api-key": {
|
||||
"post": {
|
||||
"operationId": "ApiKeyController_create",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "dadosfera-lang",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"enum": [
|
||||
"pt-br",
|
||||
"en-us"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateApiKeyDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateApiKeyResponseDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateApiKeyResponseDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"ApiKey"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"get": {
|
||||
"operationId": "ApiKeyController_findAll",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "dadosfera-lang",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"enum": [
|
||||
"pt-br",
|
||||
"en-us"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ApiKeyBaseResponseDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ApiKeyBaseResponseDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"ApiKey"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api-key/{id}": {
|
||||
"delete": {
|
||||
"operationId": "ApiKeyController_remove",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "dadosfera-lang",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"enum": [
|
||||
"pt-br",
|
||||
"en-us"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"ApiKey"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
@@ -8848,6 +9009,89 @@
|
||||
"required": [
|
||||
"policies"
|
||||
]
|
||||
},
|
||||
"CreateApiKeyDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"permissions": {
|
||||
"description": "Array of permission IDs",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"permissions"
|
||||
]
|
||||
},
|
||||
"CreateApiKeyResponseDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"key_mask": {
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PermissionDto"
|
||||
}
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"created_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"key_mask",
|
||||
"permissions",
|
||||
"created_at",
|
||||
"created_by",
|
||||
"key"
|
||||
]
|
||||
},
|
||||
"ApiKeyBaseResponseDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"key_mask": {
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PermissionDto"
|
||||
}
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"created_by": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"key_mask",
|
||||
"permissions",
|
||||
"created_at",
|
||||
"created_by"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
-1
@@ -14,7 +14,6 @@ declare global {
|
||||
AWS_REGION: string;
|
||||
OPEN_GROUP_ID: string;
|
||||
OPEN_CUSTOMER_ID: string;
|
||||
DEDICATED_PROXY: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ charts:
|
||||
values:
|
||||
- ../maestro/values.yaml
|
||||
set:
|
||||
- name: app_name
|
||||
value: maestro
|
||||
- name: maestro.duc_url
|
||||
value: duc.dadosfera.ai
|
||||
- name: hostname
|
||||
@@ -22,32 +20,3 @@ charts:
|
||||
value: c0afdcce-c5be-40d0-9d1d-2d271121f14a
|
||||
- name: replicaCount
|
||||
value: 2
|
||||
|
||||
- name: unimed-maestro
|
||||
chart: ../maestro
|
||||
values:
|
||||
- ../maestro/values.yaml
|
||||
set:
|
||||
- name: app_name
|
||||
value: maestro-unimed
|
||||
- name: maestro.duc_url
|
||||
value: duc.dadosfera.ai
|
||||
- name: hostname
|
||||
value: maestro-unimed.dadosfera.ai
|
||||
- name: maestro.pi_factory_url
|
||||
value: pi-factory.dadosfera.ai
|
||||
- name: maestro.in_factory_url
|
||||
value: in-factory.dadosfera.ai
|
||||
- name: maestro.tr_factory_url
|
||||
value: in-factory.dadosfera.ai
|
||||
- name: maestro.open_customer_id
|
||||
value: b3e3dfe5-b992-4586-a73c-c0b0c00f615d
|
||||
- name: maestro.open_group_id
|
||||
value: c0afdcce-c5be-40d0-9d1d-2d271121f14a
|
||||
# Customer id
|
||||
- name: maestro.dedicated_proxy
|
||||
value: dea2c27f-0973-4588-a2e0-9e31b64c7ffd
|
||||
- name: replicaCount
|
||||
value: 1
|
||||
- name: maestro.restricted_ip
|
||||
value: "177.52.172.0/24,189.84.160.157/32,186.237.171.146/32,57.151.113.140/30"
|
||||
|
||||
+1
-31
@@ -19,34 +19,4 @@ charts:
|
||||
- name: maestro.open_group_id
|
||||
value: e3f98a2f-7748-4981-8505-7695c8ca8218
|
||||
- name: replicaCount
|
||||
value: 1
|
||||
|
||||
# Environment to test Network Policies
|
||||
- name: private-maestro
|
||||
chart: ../maestro
|
||||
values:
|
||||
- ../maestro/values.yaml
|
||||
set:
|
||||
- name: app_name
|
||||
value: maestro-private
|
||||
- name: maestro.duc_url
|
||||
value: duc.stg.dadosfera.ai
|
||||
- name: hostname
|
||||
value: private-maestro.stg.dadosfera.ai
|
||||
- name: maestro.pi_factory_url
|
||||
value: pi-factory.dadosfera.ai
|
||||
- name: maestro.in_factory_url
|
||||
value: in-factory.stg.dadosfera.ai
|
||||
- name: maestro.tr_factory_url
|
||||
value: in-factory.dadosfera.ai
|
||||
- name: maestro.open_customer_id
|
||||
value: b3e3dfe5-b992-4586-a73c-c0b0c00f615d
|
||||
- name: maestro.open_group_id
|
||||
value: e3f98a2f-7748-4981-8505-7695c8ca8218
|
||||
# Customer id
|
||||
- name: maestro.dedicated_proxy
|
||||
value: 14d52fd4-d83d-4cdd-be34-bf11cc28b3bd
|
||||
- name: replicaCount
|
||||
value: 1
|
||||
- name: maestro.restricted_ip
|
||||
value: "57.151.113.140/30"
|
||||
value: 1
|
||||
@@ -1,16 +1,16 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Values.app_name }}
|
||||
name: maestro
|
||||
namespace: applications
|
||||
labels:
|
||||
app: {{ .Values.app_name }}
|
||||
app: maestro
|
||||
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ .Values.app_name }}
|
||||
app: maestro
|
||||
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
@@ -20,7 +20,7 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ .Values.app_name }}
|
||||
app: maestro
|
||||
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
@@ -100,8 +100,6 @@ spec:
|
||||
value: {{ .Values.maestro.open_customer_id }}
|
||||
- name: OPEN_GROUP_ID
|
||||
value: {{ .Values.maestro.open_group_id }}
|
||||
- name: DEDICATED_PROXY
|
||||
value: {{ .Values.maestro.dedicated_proxy }}
|
||||
- name: JWT_PRIVATE_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
@@ -110,15 +108,15 @@ spec:
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: prd-{{ .Values.app_name }}
|
||||
name: prd-maestro
|
||||
key: AWS_ACCESS_KEY_ID
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: prd-{{ .Values.app_name }}
|
||||
name: prd-maestro
|
||||
key: AWS_SECRET_ACCESS_KEY
|
||||
- name: AWS_DEFAULT_REGION
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: prd-{{ .Values.app_name }}
|
||||
name: prd-maestro
|
||||
key: AWS_DEFAULT_REGION
|
||||
|
||||
@@ -10,12 +10,8 @@ metadata:
|
||||
|
||||
generation: 1
|
||||
labels:
|
||||
app: {{ .Values.app_name }}
|
||||
{{- if .Values.maestro.dedicated_proxy}}
|
||||
name: open-data-{{ .Values.app_name }}
|
||||
{{- else }}
|
||||
app: maestro
|
||||
name: open-data
|
||||
{{- end }}
|
||||
namespace: applications
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
@@ -25,7 +21,7 @@ spec:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: {{ .Values.app_name }}
|
||||
name: maestro
|
||||
port:
|
||||
number: {{ .Values.ingress.port }}
|
||||
path: /open-data/sharing-ocean-data
|
||||
|
||||
@@ -3,20 +3,14 @@ kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
|
||||
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
|
||||
nginx.ingress.kubernetes.io/server-snippet: |
|
||||
underscores_in_headers on;
|
||||
ignore_invalid_headers on;
|
||||
{{- if .Values.maestro.restricted_ip}}
|
||||
nginx.ingress.kubernetes.io/whitelist-source-range: {{ .Values.maestro.restricted_ip }}
|
||||
{{- end }}
|
||||
|
||||
generation: 1
|
||||
labels:
|
||||
app: {{ .Values.app_name }}
|
||||
name: {{ .Values.app_name }}
|
||||
app: maestro
|
||||
name: maestro
|
||||
namespace: applications
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
@@ -26,7 +20,7 @@ spec:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: {{ .Values.app_name }}
|
||||
name: maestro
|
||||
port:
|
||||
number: {{ .Values.ingress.port }}
|
||||
path: /
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: prd-{{ .Values.app_name }}
|
||||
name: prd-maestro
|
||||
namespace: applications
|
||||
labels:
|
||||
app: {{ .Values.app_name }}
|
||||
app: maestro
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: secretsmanager-prd
|
||||
kind: SecretStore
|
||||
target:
|
||||
name: prd-{{ .Values.app_name }}
|
||||
name: prd-maestro
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: AWS_ACCESS_KEY_ID
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Values.app_name }}
|
||||
name: maestro
|
||||
namespace: applications
|
||||
labels:
|
||||
app: {{ .Values.app_name }}
|
||||
app: maestro
|
||||
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: {{ .Values.app_name }}
|
||||
- name: maestro
|
||||
protocol: TCP
|
||||
port: {{ .Values.service.port }}
|
||||
targetPort: {{ .Values.service.targetPort }}
|
||||
selector:
|
||||
app: {{ .Values.app_name }}
|
||||
app: maestro
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ image:
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: 1.56.0
|
||||
app_name: maestro
|
||||
containerPort: 3333
|
||||
imagePullSecrets: "applications-secrets-ecr-auth-token-external-secret"
|
||||
service:
|
||||
@@ -43,8 +42,6 @@ maestro:
|
||||
upload_file_agent_connection: cbc2f881-58c4-4d60-8003-0979b0b5b911
|
||||
open_customer_id: f239718a-a271-4ef9-ae7e-02a2f0f3aa6e
|
||||
open_group_id: 401573bb-334f-44b2-b30e-88d4cea31ae9
|
||||
dedicated_proxy: ""
|
||||
restricted_ip: ""
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
|
||||
Generated
+4
-4
@@ -12,7 +12,7 @@
|
||||
"@aws-sdk/client-secrets-manager": "^3.414.0",
|
||||
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
||||
"@dadosfera/protospack": "2.5.3",
|
||||
"@dadosfera/protospack-v2": "3.37.0-beta.23",
|
||||
"@dadosfera/protospack-v2": "3.38.0-beta.1",
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
"@grpc/proto-loader": "^0.7.9",
|
||||
"@nestjs/cli": "^9.5.0",
|
||||
@@ -1400,9 +1400,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@dadosfera/protospack-v2": {
|
||||
"version": "3.37.0-beta.23",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.37.0-beta.23.tgz",
|
||||
"integrity": "sha512-Dv3rODwbiubHB4u8sI5uJOSm1ETOXzlpaxHNEmzTNG2fLTIJxsaF1GlOBST3x9HTkhJC6hUJ8r77/qQu1FKPpQ==",
|
||||
"version": "3.38.0-beta.1",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.38.0-beta.1.tgz",
|
||||
"integrity": "sha512-4+yNZMlhvEkHlxJcaeta+jtJ9owskZcg0yjKdZzBfT8PCclctgertLHmrG0+kDb3Y/na/rpPPHYULRp7AO4zDQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@
|
||||
"@aws-sdk/client-secrets-manager": "^3.414.0",
|
||||
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
||||
"@dadosfera/protospack": "2.5.3",
|
||||
"@dadosfera/protospack-v2": "3.37.0-beta.23",
|
||||
"@dadosfera/protospack-v2": "3.38.0-beta.1",
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
"@grpc/proto-loader": "^0.7.9",
|
||||
"@nestjs/cli": "^9.5.0",
|
||||
|
||||
+3
-1
@@ -29,6 +29,7 @@ import { CustomersModule } from './modules/customers/customers.module';
|
||||
import { OpenDataModule } from './modules/open-data/open-data.module';
|
||||
import { ThemeModule } from './modules/theme/theme.module';
|
||||
import { NetworkPolicyModule } from './modules/network-policy/network-policy.module';
|
||||
import { ApiKeyModule } from './modules/api-key/api-key.module';
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
@@ -64,7 +65,8 @@ import { NetworkPolicyModule } from './modules/network-policy/network-policy.mod
|
||||
ThemeModule,
|
||||
//Always leave HealthModule last, so it is on the bottom of swagger
|
||||
HealthModule,
|
||||
NetworkPolicyModule
|
||||
NetworkPolicyModule,
|
||||
ApiKeyModule
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
OnApplicationBootstrap,
|
||||
ExecutionContext,
|
||||
Inject,
|
||||
ForbiddenException,
|
||||
} from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import assert from 'assert';
|
||||
@@ -18,6 +17,7 @@ import {
|
||||
import { RequestUser } from '../decorators/user.decorator';
|
||||
import ErrorBuilder from '../utils/ErrorBuilder';
|
||||
import ErrorCodes from '../utils/errorCodes';
|
||||
import { ApiKeyService } from 'src/modules/api-key/api-key.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationGuard
|
||||
@@ -32,6 +32,7 @@ export class AuthenticationGuard
|
||||
dadosferaLogger: DadosferaLogger,
|
||||
private reflector: Reflector,
|
||||
private authClient: AuthClientService,
|
||||
private apiKeyService: ApiKeyService
|
||||
) {
|
||||
this.pems = new Map();
|
||||
this.logger = dadosferaLogger.logger;
|
||||
@@ -49,20 +50,40 @@ export class AuthenticationGuard
|
||||
});
|
||||
}
|
||||
|
||||
canActivate(ctx: ExecutionContext): boolean {
|
||||
async canActivate(ctx: ExecutionContext): Promise<boolean> {
|
||||
const authFunctions = this.reflector.getAllAndMerge<
|
||||
AuthenticationFunction[]
|
||||
>(AUTH_FUNCTION_KEY, [ctx.getClass(), ctx.getHandler()]);
|
||||
const mustBeAuthenticated = authFunctions.length > 0;
|
||||
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
const accessToken = this.validateToken(request, mustBeAuthenticated);
|
||||
|
||||
if (!mustBeAuthenticated) {
|
||||
// no need to be authenticated
|
||||
return true;
|
||||
}
|
||||
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
const apiKey = request.get('X-api-key');
|
||||
if (apiKey) {
|
||||
const {
|
||||
api_key
|
||||
} = await this.apiKeyService.get(apiKey);
|
||||
|
||||
request.user = {
|
||||
user_id: api_key.user_id,
|
||||
username: api_key.username,
|
||||
permissions: api_key.permissions,
|
||||
customer_id: api_key.customer_id,
|
||||
customer_name: api_key.customer_name,
|
||||
customer_tier: api_key.customer_tier,
|
||||
customer_modules: api_key.customer_modules,
|
||||
access_token: apiKey,
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const accessToken = this.validateToken(request, mustBeAuthenticated);
|
||||
|
||||
if (!accessToken) {
|
||||
// couldn't load valid token
|
||||
throw new ErrorBuilder(ErrorCodes.AUTH.UNAUTHORIZED);
|
||||
@@ -114,18 +135,6 @@ export class AuthenticationGuard
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bloquear outros customer de usar o maestor dedicado
|
||||
const DEDICATED_PROXY = process.env.DEDICATED_PROXY || '';
|
||||
if (DEDICATED_PROXY !== '' && DEDICATED_PROXY !== accessTokenPayload.customer_id) {
|
||||
throw new ErrorBuilder(ErrorCodes.AUTH.FORBIDDEN);
|
||||
}
|
||||
|
||||
// Bloquear o customer de acesso o maestro publico
|
||||
// const hasNetworkPolicyModule = accessTokenPayload.customer_modules.includes('network-policy');
|
||||
// if (hasNetworkPolicyModule && DEDICATED_PROXY === '') {
|
||||
// throw new ForbiddenException();
|
||||
// }
|
||||
|
||||
request.accessTokenPayload = accessTokenPayload;
|
||||
request.user = {
|
||||
user_id: accessTokenPayload.user_id,
|
||||
|
||||
@@ -603,6 +603,22 @@ export const PERMISSIONS_GROUPS = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const PUBLIC_PERMISSIONS_SEQID = [
|
||||
46, // AUTH.GENERATE_TOKEN
|
||||
23, 13, 29, 5, // PIPELINE
|
||||
37, 38, // CONNECTION
|
||||
35, // NETWORK_CONFIG
|
||||
7, 19, 25, 1, // CATALOG
|
||||
14, // SNOWFLAKE
|
||||
11, // DATAVIZ
|
||||
31, // INTELLIGENCE
|
||||
34, // USERS
|
||||
43, // PROCESS
|
||||
47 // CUSTOMER
|
||||
];
|
||||
|
||||
|
||||
export interface DadosferaModule {
|
||||
name: string;
|
||||
description: string;
|
||||
|
||||
+5
-2
@@ -26,8 +26,11 @@ async function bootstrap() {
|
||||
},
|
||||
});
|
||||
app.use(helmet());
|
||||
app.use('/catalog/register-dataset', json({ limit: '10mb' }));
|
||||
app.use('/catalog/register-dataset', urlencoded({ extended: true, limit: '10mb' }));
|
||||
if (process.env.ENV === 'prd') {
|
||||
app.use('/catalog/register-dataset', json({ limit: '10mb' }));
|
||||
app.use('/catalog/register-dataset', urlencoded({ extended: true, limit: '10mb' }));
|
||||
}
|
||||
|
||||
configureSwagger(app);
|
||||
await app.listen(3333);
|
||||
if (process.env.KILL_AFTER_START) await app.close();
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { Controller, Get, Post, Body, Param, Delete, UseFilters, Inject } from '@nestjs/common';
|
||||
import { ApiKeyService } from './api-key.service';
|
||||
import { CreateApiKeyDto, CreateApiKeyResponseDto, ApiKeyBaseResponseDto } from './dto/api-key.dto';
|
||||
import { Authenticated, RequireAllPermissions } from 'src/decorators/authentication.decorator';
|
||||
import { ApiHeaders, ApiTags, ApiResponse } from '@nestjs/swagger';
|
||||
import { LanguageEnum } from 'src/utils/languages.enum';
|
||||
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
|
||||
import { RequestUser, User } from 'src/decorators/user.decorator';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
|
||||
|
||||
@Controller('api-key')
|
||||
@Authenticated()
|
||||
@ApiTags('ApiKey')
|
||||
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
|
||||
@UseFilters(new GrpcToHttpExceptionFilter())
|
||||
export class ApiKeyController {
|
||||
logger: DadosferaLogger;
|
||||
|
||||
constructor(
|
||||
@Inject(DadosferaLogger)
|
||||
dadosferaLogger: DadosferaLogger,
|
||||
private readonly apiKeyService: ApiKeyService,
|
||||
) {
|
||||
this.logger = dadosferaLogger.logger;
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiResponse({ type: CreateApiKeyResponseDto })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
|
||||
async create(@Body() createApiKeyDto: CreateApiKeyDto, @User() user: RequestUser): Promise<CreateApiKeyResponseDto> {
|
||||
this.logger.info('POST /api-key', {
|
||||
permissions: createApiKeyDto.permissions,
|
||||
method: 'create'
|
||||
});
|
||||
const result = await this.apiKeyService.create(createApiKeyDto, user);
|
||||
this.logger.info('POST /api-key success', {
|
||||
id: result.id,
|
||||
method: 'create'
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiResponse({ type: [ApiKeyBaseResponseDto] })
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
|
||||
async findAll(@User() user: RequestUser): Promise<ApiKeyBaseResponseDto[]> {
|
||||
this.logger.info('GET /api-key', {
|
||||
method: 'findAll'
|
||||
});
|
||||
const result = await this.apiKeyService.findAll(user);
|
||||
this.logger.info('GET /api-key success', {
|
||||
count: result.length,
|
||||
method: 'findAll'
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
|
||||
async remove(@Param('id') id: string, @User() user: RequestUser): Promise<void> {
|
||||
this.logger.info('DELETE /api-key/:id', {
|
||||
id,
|
||||
method: 'remove'
|
||||
});
|
||||
await this.apiKeyService.remove(id, user);
|
||||
this.logger.info('DELETE /api-key/:id success', {
|
||||
id,
|
||||
method: 'remove'
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ApiKeyService } from './api-key.service';
|
||||
import { ApiKeyController } from './api-key.controller';
|
||||
import { ClientsModule } from '@nestjs/microservices';
|
||||
import { DucClient } from '../duc/client.config';
|
||||
import DadosferaLogger from '@dadosfera/dadosfera-logs';
|
||||
|
||||
const ducClient = new DucClient();
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ClientsModule.register([ducClient.providerOptions])
|
||||
],
|
||||
controllers: [ApiKeyController],
|
||||
providers: [ApiKeyService, DadosferaLogger],
|
||||
exports: [ApiKeyService]
|
||||
})
|
||||
export class ApiKeyModule {}
|
||||
@@ -0,0 +1,85 @@
|
||||
import {
|
||||
Injectable,
|
||||
Inject,
|
||||
OnModuleInit,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { ClientGrpc } from '@nestjs/microservices';
|
||||
import {
|
||||
CreateApiKeyDto,
|
||||
CreateApiKeyResponseDto,
|
||||
ApiKeyBaseResponseDto,
|
||||
} from './dto/api-key.dto';
|
||||
import { RequestUser } from 'src/decorators/user.decorator';
|
||||
import { DucClient } from '../duc/client.config';
|
||||
import { PackTheMetadata } from '../../utils/ PackTheMetadata';
|
||||
import { ApiKeyWriteProtoService } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc';
|
||||
import { PUBLIC_PERMISSIONS_SEQID } from 'src/authentication/permissions.enum';
|
||||
|
||||
@Injectable()
|
||||
export class ApiKeyService implements OnModuleInit {
|
||||
private apiKeyService: ApiKeyWriteProtoService;
|
||||
|
||||
constructor(
|
||||
@Inject(DucClient.name) private readonly client: ClientGrpc
|
||||
) {}
|
||||
|
||||
onModuleInit() {
|
||||
this.apiKeyService = this.client.getService<ApiKeyWriteProtoService>(
|
||||
ProtoServices.ApiKeyWriteProtoService,
|
||||
);
|
||||
}
|
||||
|
||||
create(
|
||||
createApiKeyDto: CreateApiKeyDto,
|
||||
user: RequestUser,
|
||||
): Promise<CreateApiKeyResponseDto> {
|
||||
const metadata = PackTheMetadata(user);
|
||||
|
||||
const invalidPermissions = [];
|
||||
for (const permission of createApiKeyDto.permissions) {
|
||||
if (!PUBLIC_PERMISSIONS_SEQID.includes(permission)) {
|
||||
invalidPermissions.push(permission);
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidPermissions.length > 0) {
|
||||
throw new BadRequestException(
|
||||
`Invalid permissions: ${invalidPermissions.join(', ')}`,
|
||||
);
|
||||
}
|
||||
|
||||
return lastValueFrom(
|
||||
this.apiKeyService.CreateApiKey(
|
||||
{
|
||||
permissions: createApiKeyDto.permissions,
|
||||
},
|
||||
metadata,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async findAll(user: RequestUser): Promise<ApiKeyBaseResponseDto[]> {
|
||||
const metadata = PackTheMetadata(user);
|
||||
console.log(metadata);
|
||||
|
||||
const data = await lastValueFrom(
|
||||
this.apiKeyService.ListApiKeys({}, metadata),
|
||||
);
|
||||
return data.api_keys;
|
||||
}
|
||||
|
||||
async remove(id: string, user: RequestUser) {
|
||||
const metadata = PackTheMetadata(user);
|
||||
|
||||
await lastValueFrom(this.apiKeyService.DeleteApiKey({ id }, metadata));
|
||||
}
|
||||
|
||||
async get(key: string) {
|
||||
const metadata = PackTheMetadata({});
|
||||
|
||||
return await lastValueFrom(this.apiKeyService.GetApiKey({ key }, metadata));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsArray, IsNumber } from 'class-validator';
|
||||
|
||||
export class PermissionDto {
|
||||
@ApiProperty({ type: Number })
|
||||
id: number;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class ApiKeyBaseResponseDto {
|
||||
@ApiProperty({ type: String, format: 'uuid' })
|
||||
id: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
key_mask: string;
|
||||
|
||||
@ApiProperty({ type: [PermissionDto] })
|
||||
permissions: PermissionDto[];
|
||||
|
||||
@ApiProperty({ type: String, format: 'date-time' })
|
||||
created_at: string;
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
created_by: string;
|
||||
}
|
||||
|
||||
export class CreateApiKeyResponseDto extends ApiKeyBaseResponseDto {
|
||||
@ApiProperty({ type: String })
|
||||
key: string;
|
||||
}
|
||||
|
||||
export class CreateApiKeyDto {
|
||||
@ApiProperty({ type: [Number], description: 'Array of permission IDs' })
|
||||
@IsArray()
|
||||
@IsNumber({}, { each: true })
|
||||
permissions: number[];
|
||||
}
|
||||
@@ -86,9 +86,11 @@ export class AuthController {
|
||||
async signIn(
|
||||
@Body() { username, password, totp }: AuthSignInReq,
|
||||
@Language() language: LanguageEnum,
|
||||
@Headers('origin') origin = '',
|
||||
): Promise<AuthSignInRes> {
|
||||
this.logger.info('/auth - SignIn');
|
||||
const metadata = PackTheMetadata({ language });
|
||||
const frontHost = origin.replace(/^https?:\/\//, '');
|
||||
const metadata = PackTheMetadata({ language, custom_host: frontHost });
|
||||
this.logger.info('metadata: ' + JSON.stringify(metadata.toJSON()));
|
||||
return this.authClient.signIn({ username, password, totp }, metadata);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OnModuleInit, Inject, Injectable, ForbiddenException } from '@nestjs/common';
|
||||
import { OnModuleInit, Inject, Injectable } from '@nestjs/common';
|
||||
import { ClientGrpc } from '@nestjs/microservices';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
AuthResetPasswordRequest,
|
||||
AuthVerifyResetPasswordCodeRequest,
|
||||
AuthConfirmResetPasswordRequest,
|
||||
AuthSignInResponse,
|
||||
} from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
|
||||
import { DucClient } from '../duc/client.config';
|
||||
import { Metadata } from '@grpc/grpc-js';
|
||||
@@ -54,49 +53,15 @@ export class AuthClientService implements OnModuleInit {
|
||||
return lastValueFrom(this.authService.AuthSnowflakeSignIn(input));
|
||||
}
|
||||
|
||||
checkDedicatedProxy({
|
||||
customer
|
||||
}: AuthSignInResponse) {
|
||||
const DEDICATED_PROXY = process.env.DEDICATED_PROXY || '';
|
||||
this.logger.info('SignIn - Setting customer ID for dedicated proxy: ' + DEDICATED_PROXY);
|
||||
this.logger.info('Customer ID: ' + customer.id);
|
||||
|
||||
if (DEDICATED_PROXY !== '' && DEDICATED_PROXY !== customer.id) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
// Bloquear o customer de acesso o maestro publico
|
||||
this.logger.info('Check if customer have network policy: ' + customer.modules);
|
||||
const hasNetworkPolicyModule = customer.modules.includes('network-policy');
|
||||
if (hasNetworkPolicyModule && DEDICATED_PROXY === '') {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
|
||||
async signIn(
|
||||
{ username, password, totp }: AuthSignInRequest,
|
||||
metadata: Metadata,
|
||||
) {
|
||||
this.logger.info('SignIn');
|
||||
|
||||
let result: AuthSignInResponse;
|
||||
|
||||
try {
|
||||
result = await lastValueFrom(
|
||||
this.authService.AuthSignIn({ username, password, totp }, metadata),
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error('SignIn - Error during sign-in');
|
||||
this.logger.error(error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (result.customer) {
|
||||
this.checkDedicatedProxy(result);
|
||||
}
|
||||
|
||||
return result
|
||||
return lastValueFrom(
|
||||
this.authService.AuthSignIn({ username, password, totp }, metadata),
|
||||
);
|
||||
}
|
||||
|
||||
async refreshAccessToken(
|
||||
|
||||
@@ -45,11 +45,11 @@ export class OpenDataController {
|
||||
) {
|
||||
this.logger.info('createUser for open data' + JSON.stringify(request.headers));
|
||||
|
||||
// const corslist = ["https://devsbm.dadosfera.io", "https://sharingoceandata.com"];
|
||||
// if (!corslist.includes(origin)) {
|
||||
// this.logger.info('block request by cors list: '+ origin);
|
||||
// throw new ForbiddenException();
|
||||
// }
|
||||
const corslist = ["https://devsbm.dadosfera.io", "https://sharingoceandata.com"];
|
||||
if (!corslist.includes(origin)) {
|
||||
this.logger.info('block request by cors list: '+ origin);
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
|
||||
const OPENDATA_CUSTOMER_ID = process.env.OPEN_CUSTOMER_ID;
|
||||
const OPENDATA_GROUP_ID = process.env.OPEN_GROUP_ID;
|
||||
|
||||
@@ -20,6 +20,7 @@ import { PermissionsService } from '../permissions/permissions.service';
|
||||
import { LanguageEnum } from 'src/utils/languages.enum';
|
||||
import { RequestUser } from 'src/decorators/user.decorator';
|
||||
import { DucClient } from '../duc/client.config';
|
||||
import { PUBLIC_PERMISSIONS_SEQID } from 'src/authentication/permissions.enum';
|
||||
|
||||
interface GetRolesPermissionsName {
|
||||
id: string;
|
||||
@@ -103,6 +104,20 @@ export class RolesService {
|
||||
const meta = new Metadata();
|
||||
meta.add('access_token', access_token);
|
||||
const { description, name, permissionIds, userIds } = data;
|
||||
|
||||
const invalidPermissions = [];
|
||||
for (const permission of permissionIds) {
|
||||
if (!PUBLIC_PERMISSIONS_SEQID.includes(permission)) {
|
||||
invalidPermissions.push(permission);
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidPermissions.length > 0) {
|
||||
throw new BadRequestException(
|
||||
`Invalid permissions: ${invalidPermissions.join(', ')}`,
|
||||
);
|
||||
}
|
||||
|
||||
const role = await lastValueFrom(
|
||||
this.rolesClientService.RoleCreate(
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ export class PDFParser<T> implements Parser<T> {
|
||||
const html = await this.htmlParser.parse(data);
|
||||
await page.setContent(html, {
|
||||
waitUntil: 'networkidle0',
|
||||
timeout: 90000,
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
// Configurações adicionais para garantir um PDF válido
|
||||
@@ -43,7 +43,7 @@ export class PDFParser<T> implements Parser<T> {
|
||||
pageRanges: '',
|
||||
tagged: true,
|
||||
outline: false,
|
||||
timeout: 90000,
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
await browser.close();
|
||||
|
||||
Reference in New Issue
Block a user