Compare commits

...
17 Commits
Author SHA1 Message Date
Gabriel Rosa d6b3e02890 FIX: automattically skip ssl when microservices connection are local 2023-02-13 10:30:50 -03:00
Gabriel Amorim d06910515b FIX: force deploy 2023-02-10 15:53:10 -03:00
Gabriel Amorim d1b328d481 Merge pull request #204 from dadosfera/feat/oauth-login
Feat/oauth login
2023-02-10 14:58:20 -03:00
Gabriel Rosa 945955a71c Merge branch 'main' into feat/oauth-login 2023-02-09 15:21:05 -03:00
Gabriel Amorim cdba41dffa Merge pull request #203 from dadosfera/force-deploy
FIX: force deploy
2023-02-03 17:24:13 -03:00
Gabriel Rosa 5020e8913e FIX: force deploy 2023-02-03 17:21:53 -03:00
Gabriel Amorim 89369270b9 Merge pull request #202 from dadosfera/feat/embed-private
Feat/embed private
2023-02-03 17:14:14 -03:00
Gabriel Rosa 52f17725af new protospack version 2023-02-03 15:03:51 -03:00
Gabriel Rosa 6da213aebc starting module strategy 2023-02-03 11:14:15 -03:00
Gabriel Rosa a353a1b45c FIX: new permission 2023-02-02 14:00:24 -03:00
Gabriel Rosa b36ff624b5 FIX: add logic for fetching shared data_assets 2023-02-01 18:00:36 -03:00
Gabriel Rosa 03c09a525b DOCS: documenting oauth flow 2023-02-01 10:07:45 -03:00
Gabriel Rosa 52bf2bdef3 teste new docsfera cloud function url 2023-01-31 09:34:34 -03:00
Gabriel Rosa 161d1fa05d Added some logs 2023-01-30 16:35:05 -03:00
Gabriel Rosa 642bf462ad FIX: add fallback language to pt-br 2023-01-26 17:00:27 -03:00
Gabriel Rosa 6d61d74d0c FIX: set google callback 2023-01-25 09:51:22 -03:00
Gabriel Rosa 2bc060b13d FEAT: oauth sign in 2023-01-24 19:19:00 -03:00
25 changed files with 452 additions and 80 deletions
+84 -2
View File
@@ -288,6 +288,71 @@
]
}
},
"/auth/session/{session}": {
"get": {
"operationId": "AuthController_getSession",
"parameters": [
{
"name": "session",
"required": true,
"in": "path",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"tags": [
"Auth"
]
}
},
"/auth/oauth/google": {
"get": {
"operationId": "AuthController_googleOauth",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "boolean"
}
}
}
}
},
"tags": [
"Auth"
]
}
},
"/auth/oauth/google/callback": {
"get": {
"operationId": "AuthController_googleOauthCallback",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"tags": [
"Auth"
]
}
},
"/connectors": {
"post": {
"operationId": "ConnectorController_uploadConnector",
@@ -2854,7 +2919,16 @@
"/catalog/data-asset/{id}": {
"get": {
"operationId": "CatalogController_getDataAsset",
"parameters": [],
"parameters": [
{
"name": "shared",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": ""
@@ -3405,7 +3479,7 @@
}
},
"info": {
"title": "Maestro - feature/upload-to-s3-presigned",
"title": "Maestro - main",
"description": "Documentation for Maestro gateway",
"version": "1.0.0",
"contact": {}
@@ -5911,6 +5985,14 @@
},
"embed": {
"$ref": "#/components/schemas/EmbedObject"
},
"share_type": {
"type": "string",
"enum": [
"none",
"public",
"private"
]
}
},
"required": [
+7 -7
View File
@@ -12,7 +12,7 @@
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.112.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "3.28.0",
"@dadosfera/protospack-v2": "3.29.0",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
@@ -1727,9 +1727,9 @@
}
},
"node_modules/@dadosfera/protospack-v2": {
"version": "3.28.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.28.0.tgz",
"integrity": "sha512-JZYYhoaXFUpb5W/fBVt4XYe1Hlef2x9aLlM2Yv0erYn9QAu+/Pb99YnXbkgawQVlmJojSRrAvSwq1o9yOgKCrg==",
"version": "3.29.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.29.0.tgz",
"integrity": "sha512-G66u9V+/+5rQb+fpJdDXydTaji2Mlr0Ro5TTYcQleITKU9DjF1WZs/jP/Qu0Y224nCb8HhePvaVl/Rr0wtLt4w==",
"dependencies": {
"@grpc/grpc-js": "^1.6.7",
"rxjs": "^7.5.5",
@@ -12284,9 +12284,9 @@
}
},
"@dadosfera/protospack-v2": {
"version": "3.28.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.28.0.tgz",
"integrity": "sha512-JZYYhoaXFUpb5W/fBVt4XYe1Hlef2x9aLlM2Yv0erYn9QAu+/Pb99YnXbkgawQVlmJojSRrAvSwq1o9yOgKCrg==",
"version": "3.29.0",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.29.0.tgz",
"integrity": "sha512-G66u9V+/+5rQb+fpJdDXydTaji2Mlr0Ro5TTYcQleITKU9DjF1WZs/jP/Qu0Y224nCb8HhePvaVl/Rr0wtLt4w==",
"requires": {
"@grpc/grpc-js": "^1.6.7",
"rxjs": "^7.5.5",
+1 -1
View File
@@ -28,7 +28,7 @@
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.112.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack-v2": "3.28.0",
"@dadosfera/protospack-v2": "3.29.0",
"@grpc/grpc-js": "^1.6.7",
"@grpc/proto-loader": "^0.6.13",
"@nestjs/common": "^8.4.7",
+43 -1
View File
@@ -336,6 +336,16 @@ export const PERMISSIONS_GROUPS = {
'es-es': 'Gestor de catálogos. Puede ver y editar todos los activos.',
},
},
EMBED_ANALYTICS: {
seqid: 44,
claim: 'catalog:embed',
usage: PermissionUsages.INTERNAL,
name: {
'pt-br': 'Acessar Módulo de Incorporação de Ativos',
'en-us': 'Access Embedding analytics Module',
'es-es': 'Acceder al Módulo de Incorporación de Activos',
},
},
},
},
@@ -556,7 +566,34 @@ export const PERMISSIONS_GROUPS = {
},
},
};
export interface DadosferaModule {
name: string;
description: string;
key: string;
permissionSeqId: number;
}
export const DADOSFERA_MODULES: Array<DadosferaModule> = [
{
name: 'Intelligence Module',
description: 'Orchest Module',
key: 'intelligence',
permissionSeqId: PERMISSIONS_GROUPS.ANALYZE.permissions.INTELLIGENCE.seqid,
},
{
name: 'Proccessing Module',
description: 'Proccessing Module',
key: 'process',
permissionSeqId:
PERMISSIONS_GROUPS.PROCESS.permissions.TRANSFORMATION.seqid,
},
{
name: 'Embedded Analytics',
description: 'Embedded Analytics Module',
key: 'embedded-analytics',
permissionSeqId:
PERMISSIONS_GROUPS.PROCESS.permissions.TRANSFORMATION.seqid,
},
];
// traverses the object searching for duplicate seqids or claims (executes at runtime)
let nextAvailableSeqid = 0;
const seqids = Object.values(PERMISSIONS_GROUPS).flatMap((namespace) =>
@@ -576,4 +613,9 @@ Object.values(PERMISSIONS_GROUPS).map((namespace) =>
}),
);
DADOSFERA_MODULES.map((m) => m.key).forEach((m, i, arr) => {
if (arr.indexOf(m) !== i)
throw new Error(`DADOSFERA_MODULES[${i}] does not have a unique key`);
});
logger.log(`next available seqid ${nextAvailableSeqid + 1}`);
+38
View File
@@ -0,0 +1,38 @@
# Auth
## SSO/oAuth
### Strategy
We are using [PassportJs](https://www.passportjs.org/) to handle oAuth authentications.
When the client (front end) makes a `GET /auth/oauth/{strategy}` Passport automatically redirects the user to the `strategy` login page. To do that we must configure and use a **Passport Strategy**. We must also have a callback route, conventionally `GET /auth/oauth/{strategy}/callback`, so the oAuth app can report the status of the user's login.
- If the oAuth is successfull we call DUC's `AuthOauthSignIn` request that gets the tokens from Cognito and saves them on cache temporarily under a key we call `session`. Duc returns that `session` to maestro which then redirects the user to our app login page with that `session` as a query param.
- If the oAuth login is not successfull for some reason or the user **does not** exist on DUC's database we redirect the user to our login page with an `error` and `error_description` as query params.
### Routes
So in order to have an SSO login, besides configuring the Strategy, we must have two routes for each Strategy, like in the example below:
```ts
@Get('oauth/google')
@UseGuards(AuthGuard('google-login'))
googleOauth() {
this.logger.info('/oauth/google');
return true;
}
@Get('oauth/google/callback')
@UseGuards(AuthGuard('google-login'))
@Redirect()
async googleOauthCallback(@Req() req) {
const { url, email, token, language = 'pt-br' } = await this.callback(req);
if (url.searchParams.get('error')) {
this.logger.error('/oauth/google - ERROR');
return { url: url.href };
}
// ... Rest of the logic
return { url: url.href };
}
```
+112 -1
View File
@@ -8,6 +8,10 @@ import {
Inject,
UseFilters,
Get,
UseGuards,
Redirect,
Req,
Param,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
@@ -35,12 +39,17 @@ import {
AuthSignInRes,
} from './dtos/login';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
import { AuthGuard } from '@nestjs/passport';
import { Request } from 'express';
import ErrorCodes, { OauthErrors } from 'src/utils/errorCodes';
import jwt from 'jsonwebtoken';
@ApiTags('Auth')
@UseFilters(new GrpcToHttpExceptionFilter())
@Controller('auth')
export class AuthController {
logger: DadosferaLogger;
redirectUrl: string;
constructor(
@Inject(DadosferaLogger)
@@ -48,6 +57,17 @@ export class AuthController {
private authClient: AuthClientService,
) {
this.logger = dadosferaLogger.logger;
switch (process.env.ENV) {
case 'stg':
this.redirectUrl = `https://app.${process.env.ENV}.dadosfera.ai/auth/login`;
break;
case 'prd':
this.redirectUrl = `https://app.dadosfera.ai/auth/login`;
break;
default:
this.redirectUrl = `http://localhost:4200/auth/login`;
}
}
@Post('sign-in')
@@ -204,8 +224,99 @@ export class AuthController {
@Authenticated()
@Get('verify-access-token')
@HttpCode(HttpStatus.OK)
verifyAccessToken() {
return { access_token_status: 'valid' };
}
@Get('session/:session')
getSession(@Param('session') session: string) {
return this.authClient.getSession(session);
}
@Get('oauth/google')
@UseGuards(AuthGuard('google-login'))
googleOauth() {
this.logger.info('/oauth/google');
return true;
}
@Get('oauth/google/callback')
@UseGuards(AuthGuard('google-login'))
@Redirect()
async googleOauthCallback(@Req() req) {
const { url, email, token, language = 'pt-br' } = await this.callback(req);
if (url.searchParams.get('error')) {
this.logger.error('/oauth/google - ERROR');
return { url: url.href };
}
await this.authClient
.oauthSignIn({
username: email,
token,
})
.then(({ session }) => {
this.logger.info('/oauth/google - SUCESS');
url.searchParams.set('session', session);
})
.catch((err) => {
this.logger.error('/oauth/google - ERROR');
let error = OauthErrors.INVALID_CREDENTIALS[language].error;
let error_description =
OauthErrors.INVALID_CREDENTIALS[language].error_description;
switch (err.details) {
case ErrorCodes.USER.NOT_FOUND:
error = OauthErrors.USER_NOT_FOUND[language].error;
error_description =
OauthErrors.USER_NOT_FOUND[language].error_description(email);
break;
case ErrorCodes.AUTH.UNAUTHORIZED:
error = OauthErrors.INVALID_SESSION[language].error;
error_description =
OauthErrors.INVALID_SESSION[language].error_description;
break;
}
url.searchParams.set('error', error);
url.searchParams.set('error_description', error_description);
return null;
});
return { url: url.href };
}
async callback(req: Request) {
const { error, state } = req.query;
const { authInfo } = req;
const url = new URL(this.redirectUrl);
let email, token, error_title, error_description;
let language: 'pt-br' | 'en-us' = 'pt-br';
const stateObject = jwt.verify(
state as string,
process.env.JWT_PRIVATE_KEY,
);
if (typeof stateObject != 'string') language = stateObject.language;
if (error || !authInfo) {
this.logger.error(error);
if (!authInfo) this.logger.error('No authInfo', { request: req });
error_title = OauthErrors.INVALID_CREDENTIALS[language].error;
error_description =
OauthErrors.INVALID_CREDENTIALS[language].error_description;
if (error) error_description += ` - [${error}]`;
} else {
const { accessToken } = authInfo as any;
const { _json: userInfo } = req.user as any;
email = userInfo.email;
token = accessToken;
}
if (error_title) {
url.searchParams.set('error', error_title);
url.searchParams.set('error_description', error_description);
}
return { token, email, url, language };
}
}
+8 -1
View File
@@ -6,12 +6,19 @@ import { AuthController } from './auth.controller';
import { AuthClientService } from './auth.service';
import { DucClient } from '../duc/client.config';
import { GoogleLoginStrategy } from './passport-strategies/google-strategy';
import { getOauthSecrets } from 'src/utils/OauthSecrets';
const client = new DucClient();
@Module({
imports: [ClientsModule.register([client.providerOptions])],
controllers: [AuthController],
providers: [AuthClientService, DadosferaLogger],
providers: [
AuthClientService,
DadosferaLogger,
GoogleLoginStrategy,
{ provide: 'OAUTH_SECRETS', useValue: getOauthSecrets() },
],
exports: [AuthClientService],
})
export class AuthModule {}
+9
View File
@@ -157,4 +157,13 @@ export class AuthClientService implements OnModuleInit {
this.authService.AuthVerifyTotpMfa({ accessToken, totp }),
);
}
async getSession(session: string) {
return lastValueFrom(this.authService.AuthGetSession({ session }));
}
async oauthSignIn(data: { username: string; token: string }) {
const { username, token } = data;
return lastValueFrom(this.authService.AuthOauthSignIn({ token, username }));
}
}
@@ -0,0 +1,46 @@
import {
AuthenticateOptionsGoogle,
Profile,
Strategy,
StrategyOptions,
} from 'passport-google-oauth20';
import { PassportStrategy } from '@nestjs/passport';
import { Inject, Injectable } from '@nestjs/common';
import { OauthSecrets } from 'src/utils/OauthSecrets';
import { Request } from 'express';
import jwt from 'jsonwebtoken';
@Injectable()
export class GoogleLoginStrategy extends PassportStrategy(
Strategy,
'google-login',
) {
redirect_uri: string;
constructor(
@Inject('OAUTH_SECRETS')
private readonly oauthSecrets: OauthSecrets,
) {
const options: StrategyOptions = {
clientID: oauthSecrets['google-login'].client_id,
clientSecret: oauthSecrets['google-login'].client_secret,
callbackURL: oauthSecrets['google-login'].redirect_uri,
scope: ['email', 'profile', 'openid'],
};
const verify = (
accessToken: string,
refreshToken: string,
profile: Profile,
done,
) => {
return done(null, profile, { accessToken, refreshToken });
};
super(options, verify);
}
authenticate(req: Request, options: AuthenticateOptionsGoogle) {
const language = req.headers['dadosfera-lang'] || req.query.language;
options.state = jwt.sign({ language }, process.env.JWT_PRIVATE_KEY);
super.authenticate(req, options);
}
}
+3 -4
View File
@@ -6,6 +6,8 @@ import {
import { credentials } from '@grpc/grpc-js';
import { Catalog } from '@dadosfera/protospack-v2';
const isLocalConnection = !!process.env.PIFACTORY_URL?.includes('0.0.0.0');
export class CatalogClientConfiguration {
public name = 'CatalogClientConfiguration';
private config: GrpcOptions = {
@@ -16,10 +18,7 @@ export class CatalogClientConfiguration {
Catalog.ProtoPackages.ReadPackage,
Catalog.ProtoPackages.WritePackage,
],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: [
Catalog.ProtoPaths.ReadFilePath,
Catalog.ProtoPaths.WriteFilePath,
+27 -27
View File
@@ -1,11 +1,14 @@
import {
BadRequestException,
Body,
Controller,
Delete,
ForbiddenException,
Get,
Headers,
HttpException,
Inject,
NotFoundException,
Param,
Post,
Put,
@@ -98,7 +101,7 @@ export class CatalogController {
});
if (!pipeline || !object) {
throw new HttpException('Query params not provided', 400);
throw new BadRequestException('Query params not provided');
}
const is_data_manager = permissions.includes(
@@ -136,9 +139,8 @@ export class CatalogController {
return { data_asset };
}
throw new HttpException(
throw new ForbiddenException(
'You do not have permission to access this data asset.',
403,
);
}
@@ -172,12 +174,12 @@ export class CatalogController {
)
async getDataAsset(
@User() user: RequestUser,
@Headers() headers,
@Param('id') id,
@Query('shared') shared?: 'true',
) {
const { username, user_id, customer_id, customer_name, permissions } = user;
this.logger.info(`/catalog - ON GET ONE DASHBOARD METABASE ROUTE`, {
this.logger.info(`GET /data-asset/${id}`, {
username,
customer_name,
});
@@ -200,25 +202,24 @@ export class CatalogController {
id,
metadata,
});
has_permission =
is_data_manager ||
data_asset?.owner === username ||
(user_roles as Array<any>).some((r) => data_asset.p_roles.includes(r)) ||
data_asset.p_users.includes(user_id);
if (
shared === 'true' &&
(data_asset.share_type === undefined || data_asset.share_type === 'none')
)
throw new NotFoundException();
if (!has_permission)
throw new ForbiddenException(
'You do not have permission to access this data asset.',
);
delete data_asset.p_roles;
delete data_asset.p_users;
if (data_asset?.owner === username) has_permission = true;
for (const role of user_roles) {
if (data_asset.p_roles.includes(role)) has_permission = true;
}
if (data_asset.p_users.includes(user_id)) has_permission = true;
if (is_data_manager || has_permission) {
delete data_asset.p_roles;
delete data_asset.p_users;
return { data_asset };
}
throw new HttpException(
'You do not have permission to access this data asset.',
403,
);
return { data_asset };
}
@Get('data-asset/rls/:id')
@@ -271,9 +272,8 @@ export class CatalogController {
return { data_asset };
}
throw new HttpException(
throw new ForbiddenException(
'You do not have permission to access this data asset.',
403,
);
}
@@ -376,7 +376,7 @@ export class CatalogController {
async updateDataAsset(
@User() user: RequestUser,
@Headers('Dadosfera-Lang') language,
@Param('id') id,
@Param('id') data_asset_id,
@Body() body: IUpdateDataRequest,
): Promise<IOneDataAsset> {
const { customer_id, customer_name, user_id, username } = user;
@@ -390,7 +390,7 @@ export class CatalogController {
const result = await this.catalogService.updateOneDataAsset({
body,
data_asset_id: id,
data_asset_id,
customer_id,
metadata,
});
+7
View File
@@ -1,6 +1,11 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { CreateDataAssetRequest } from '@dadosfera/protospack-v2/dist/lib/Catalog/interfaces/messages';
export enum DataAssetShareType {
none = 'none',
public = 'public',
private = 'private',
}
export class EmbedObject {
@ApiProperty()
url: string;
@@ -135,6 +140,8 @@ export class IUpdateDataRequest {
tags: string[];
@ApiPropertyOptional()
embed: EmbedObject;
@ApiPropertyOptional({ enum: DataAssetShareType })
share_type: DataAssetShareType;
}
export class ICreateDataAsset implements CreateDataAssetRequest {
@ApiProperty()
@@ -6,14 +6,15 @@ import {
} from '@nestjs/microservices';
import { ConnectionTest } from '@dadosfera/protospack-v2';
const isLocalConnection = !!process.env.INFACTORY_URL?.includes('0.0.0.0');
export class ConnectionTestClientConfiguration {
private config: GrpcOptions = {
transport: Transport.GRPC,
options: {
url: process.env.INFACTORY_URL,
package: [ConnectionTest.ProtoPackages.ReadPackage],
credentials:
process.env.ENV === 'local' ? undefined : credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: [ConnectionTest.ProtoPaths.ReadFilePath],
loader: {
keepCase: true,
+3 -4
View File
@@ -6,6 +6,8 @@ import {
} from '@nestjs/microservices';
import { ConnectionManager } from '@dadosfera/protospack-v2';
const isLocalConnection = !!process.env.INFACTORY_URL?.includes('0.0.0.0');
export class ConnectionClientConfiguration {
public name = 'ConnectionClientConfiguration';
private config: GrpcOptions = {
@@ -16,10 +18,7 @@ export class ConnectionClientConfiguration {
ConnectionManager.ProtoPackages.WritePackage,
ConnectionManager.ProtoPackages.ReadPackage,
],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: [
ConnectionManager.ProtoPaths.WriteFilePath,
ConnectionManager.ProtoPaths.ReadFilePath,
+3 -4
View File
@@ -6,6 +6,8 @@ import {
} from '@nestjs/microservices';
import { ConnectorManager } from '@dadosfera/protospack-v2';
const isLocalConnection = !!process.env.INFACTORY_URL?.includes('0.0.0.0');
export class ConnectorClientConfiguration {
public name = 'ConnectorClientConfiguration';
private config: GrpcOptions = {
@@ -16,10 +18,7 @@ export class ConnectorClientConfiguration {
ConnectorManager.ProtoPackages.WritePackage,
ConnectorManager.ProtoPackages.ReadPackage,
],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: [
ConnectorManager.ProtoPaths.WriteFilePath,
ConnectorManager.ProtoPaths.ReadFilePath,
+3 -4
View File
@@ -9,6 +9,8 @@ import {
ProtoPaths,
} from '@dadosfera/protospack-v2/dist/lib/Duc';
const isLocalConnection = !!process.env.DUC_URL?.includes('0.0.0.0');
export class DucClient {
public name = 'DucClient';
@@ -17,10 +19,7 @@ export class DucClient {
options: {
url: process.env.DUC_URL,
package: [ProtoPackages.WritePackage, ProtoPackages.ReadPackage],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: [ProtoPaths.WriteFilePath, ProtoPaths.ReadFilePath],
loader: {
keepCase: true,
+3 -5
View File
@@ -2,10 +2,11 @@ import { Input } from '@dadosfera/protospack-v2';
import { credentials } from '@grpc/grpc-js';
import {
ClientProviderOptions,
GrpcOptions,
Transport,
type GrpcOptions,
} from '@nestjs/microservices';
const isLocalConnection = !!process.env.INFACTORY_URL?.includes('0.0.0.0');
export class InputsGrpcClient {
public readonly name = 'InputsGrpcClient';
private config: GrpcOptions = {
@@ -16,10 +17,7 @@ export class InputsGrpcClient {
Input.ProtoPackages.WritePackage,
Input.ProtoPackages.ReadPackage,
],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: [
Input.ProtoPaths.WriteFilePath,
Input.ProtoPaths.ReadFilePath,
+2 -2
View File
@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common';
import { getSecreteFromSecreteManager } from 'src/utils/SecretManager';
import { getSecretFromSecretsManager } from 'src/utils/SecretManager';
import { MixpanelController } from './mixpanel.controller';
@Module({
@@ -7,7 +7,7 @@ import { MixpanelController } from './mixpanel.controller';
providers: [
{
provide: 'MIXPANEL_TOKEN',
useValue: getSecreteFromSecreteManager(
useValue: getSecretFromSecretsManager(
`${process.env.ENV}/root/mixpanel_token`,
),
},
+3 -4
View File
@@ -6,6 +6,8 @@ import {
import { PipelinePackages, PipelineProtoFilePath } from 'protospack';
import { credentials } from '@grpc/grpc-js';
const isLocalConnection = !!process.env.PIFACTORY_URL?.includes('0.0.0.0');
export class PipelinesClientConfiguration {
public name = 'PipelinesClientConfiguration';
private config: GrpcOptions = {
@@ -13,10 +15,7 @@ export class PipelinesClientConfiguration {
options: {
url: process.env.PIFACTORY_URL,
package: PipelinePackages,
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: PipelineProtoFilePath,
loader: {
keepCase: true,
+3 -4
View File
@@ -9,6 +9,8 @@ import {
} from '@dadosfera/protospack-v2/dist/lib/PipelineV2';
import { credentials } from '@grpc/grpc-js';
const isLocalConnection = !!process.env.PIFACTORY_URL?.includes('0.0.0.0');
export class PipelinesClientConfiguration {
public name = 'PipelinesClientConfiguration';
private config: GrpcOptions = {
@@ -16,10 +18,7 @@ export class PipelinesClientConfiguration {
options: {
url: process.env.PIFACTORY_URL,
package: [ProtoPackages.ReadPackage, ProtoPackages.WritePackage],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: [ProtoPaths.ReadFilePath, ProtoPaths.WriteFilePath],
loader: {
keepCase: true,
@@ -2,7 +2,7 @@ import { Body, Controller, HttpException, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import axios from 'axios';
import { User, RequestUser } from 'src/authentication/user.decorator';
import { getSecreteFromSecreteManager } from 'src/utils/SecretManager';
import { getSecretFromSecretsManager } from 'src/utils/SecretManager';
import { INote } from './dtos';
@ApiTags('Productboard')
@@ -18,7 +18,7 @@ export class ProductboardController {
: username + `@${customer_name}.default`;
const path = process.env.PB_TOKEN_PATH;
const token = await getSecreteFromSecreteManager(path);
const token = await getSecretFromSecretsManager(path);
const response = await axios
.post(
@@ -6,6 +6,8 @@ import {
import { credentials } from '@grpc/grpc-js';
import { Transformation } from '@dadosfera/protospack-v2';
const isLocalConnection = !!process.env.INFACTORY_URL?.includes('0.0.0.0');
export class TransformationsClientConfiguration {
public name = 'TransformationsClientConfiguration';
private config: GrpcOptions = {
@@ -13,10 +15,7 @@ export class TransformationsClientConfiguration {
options: {
url: process.env.INFACTORY_URL,
package: [Transformation.ProtoPackages.WritePackage],
credentials:
process.env.LOCAL_ENV || process.env.ENV === 'local'
? undefined
: credentials.createSsl(),
credentials: isLocalConnection ? undefined : credentials.createSsl(),
protoPath: [Transformation.ProtoPaths.WriteFilePath],
loader: {
enums: String,
+4
View File
@@ -2,6 +2,7 @@ import {
SecretsManagerClient,
GetSecretValueCommand,
} from '@aws-sdk/client-secrets-manager';
let cachedSecrets: OauthSecrets;
class OauthSecretsObject {
client_id = '';
@@ -15,8 +16,10 @@ export class OauthSecrets {
mailchimp = new OauthSecretsObject();
facebook = new OauthSecretsObject();
salesforce = new OauthSecretsObject();
'google-login' = new OauthSecretsObject();
}
export async function getOauthSecrets() {
if (cachedSecrets) return cachedSecrets;
const secrets = new OauthSecrets();
const path = process.env.SM_OAUTH_PATH;
const secretsManagerClient = new SecretsManagerClient({});
@@ -37,5 +40,6 @@ export async function getOauthSecrets() {
};
}
}
cachedSecrets = secrets;
return secrets;
}
+1 -1
View File
@@ -3,7 +3,7 @@ import {
GetSecretValueCommand,
} from '@aws-sdk/client-secrets-manager';
export async function getSecreteFromSecreteManager(path: string) {
export async function getSecretFromSecretsManager(path: string) {
const secretsManagerClient = new SecretsManagerClient({});
const getSecretComand = new GetSecretValueCommand({
+34
View File
@@ -89,3 +89,37 @@ const ErrorCodes = {
};
export default ErrorCodes;
export const OauthErrors = {
INVALID_CREDENTIALS: {
'pt-br': {
error: 'Erro ao autorizar',
error_description: 'Credenciais inválidas. Tente novamente',
},
'en-us': {
error: 'Authorization Error',
error_description: 'Invalid credentials. Please try again',
},
},
USER_NOT_FOUND: {
'pt-br': {
error: 'Erro ao autorizar',
error_description: (email) => `Usuário não existe na Dadosfera: ${email}`,
},
'en-us': {
error: 'Authorization Error',
error_description: (email) =>
`User does not exist on Dadosfera: ${email}`,
},
},
INVALID_SESSION: {
'pt-br': {
error: 'Erro ao autorizar',
error_description: 'Sessão inválida!',
},
'en-us': {
error: 'Authorization Error',
error_description: 'Invalid session!',
},
},
};