Compare commits

...
Author SHA1 Message Date
marcos-silva-rodrigues df8520afd3 FIX: send origin header 2025-04-15 14:24:41 -03:00
marcos-silva-rodrigues f4b8addda4 FIX: send origin removing http prefix 2025-04-14 08:45:59 -03:00
marcos-silva-rodrigues 0a5f138829 FIX: remove host and send custom host 2025-04-14 08:30:38 -03:00
marcos-silva-rodrigues bacbf42a04 UPDATE: send host 2025-04-11 18:00:51 -03:00
marcos-silva-rodrigues 2c964253ec UPDATE: send header in metadata 2025-04-11 17:33:34 -03:00
marcos-silva-rodrigues e886bea05c UPDATE: send origin header 2025-04-11 17:18:45 -03:00
marcos-silva-rodrigues 16cb00f46f UPDATE: send host 2025-04-11 15:06:02 -03:00
marcos-silva-rodrigues 3e0dbc7401 FIX: remove host metadata 2025-04-10 11:53:53 -03:00
marcos-silva-rodrigues deb32b5c0f FIX: send host metadata 2025-04-10 11:44:52 -03:00
Marcos Rodrigues Silva 01ea0e9561 Merge branch 'beta' into fix/network-policy 2025-04-10 11:33:43 -03:00
marcos-silva-rodrigues 9676b51f01 FIX: comment host metadata 2025-04-10 11:27:07 -03:00
Marcos Rodrigues Silva b0d2f86eaf Merge pull request #280 from dadosfera/feat/network-policy
FEAT: networks get endpoint
2025-04-09 15:34:18 -03:00
marcos-silva-rodrigues f356efb42e Merge branch 'beta' into feat/network-policy 2025-04-09 15:32:10 -03:00
marcos-silva-rodrigues 559d98e884 FIX: merge with beta 2025-04-09 15:28:23 -03:00
Marcos Rodrigues Silva d8623b88df Merge pull request #277 from dadosfera/feat/network-policy
Feat/network policy
2025-04-09 11:36:32 -03:00
Marcos Rodrigues Silva 92aab57d37 Merge pull request #279 from dadosfera/fix/reset-block-users
FIX: send all metadata
2025-04-08 14:35:10 -03:00
marcos-silva-rodrigues 301ad369c0 FEAT: networks get endpoint 2025-04-04 18:25:48 -03:00
marcos-silva-rodrigues e5d9ac2fbf FEAT: network policy endpoint 2025-04-02 16:48:10 -03:00
marcos-silva-rodrigues 9cc538cdcd FEAT: add host in metadata 2025-04-01 17:57:05 -03:00
11 changed files with 364 additions and 47 deletions
+128
View File
@@ -20,6 +20,14 @@
], ],
"type": "string" "type": "string"
} }
},
{
"name": "origin",
"required": true,
"in": "header",
"schema": {
"type": "string"
}
} }
], ],
"requestBody": { "requestBody": {
@@ -64,6 +72,14 @@
], ],
"type": "string" "type": "string"
} }
},
{
"name": "origin",
"required": true,
"in": "header",
"schema": {
"type": "string"
}
} }
], ],
"requestBody": { "requestBody": {
@@ -249,6 +265,14 @@
], ],
"type": "string" "type": "string"
} }
},
{
"name": "origin",
"required": true,
"in": "header",
"schema": {
"type": "string"
}
} }
], ],
"responses": { "responses": {
@@ -5715,6 +5739,96 @@
"Health" "Health"
] ]
} }
},
"/network-policy": {
"get": {
"operationId": "NetworkPolicyController_getNetworks",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NetworkPoliciesDTO"
}
}
}
}
},
"security": [
{
"access-token": []
},
{
"access-token": []
}
]
},
"post": {
"operationId": "NetworkPolicyController_applyNetworkPolicies",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NetworkPoliciesDTO"
}
}
}
},
"responses": {
"200": {
"description": ""
},
"201": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
},
"security": [
{
"access-token": []
},
{
"access-token": []
}
]
},
"delete": {
"operationId": "NetworkPolicyController_removeNetworkPolicies",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NetworkPoliciesDTO"
}
}
}
},
"responses": {
"200": {
"description": ""
}
},
"security": [
{
"access-token": []
},
{
"access-token": []
}
]
}
} }
}, },
"info": { "info": {
@@ -8566,6 +8680,20 @@
"required": [ "required": [
"theme" "theme"
] ]
},
"NetworkPoliciesDTO": {
"type": "object",
"properties": {
"policies": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"policies"
]
} }
} }
} }
+4 -4
View File
@@ -12,7 +12,7 @@
"@aws-sdk/client-secrets-manager": "^3.414.0", "@aws-sdk/client-secrets-manager": "^3.414.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4", "@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack": "2.5.3", "@dadosfera/protospack": "2.5.3",
"@dadosfera/protospack-v2": "3.37.0-alpha.19", "@dadosfera/protospack-v2": "3.37.0-alpha.20",
"@grpc/grpc-js": "^1.9.3", "@grpc/grpc-js": "^1.9.3",
"@grpc/proto-loader": "^0.7.9", "@grpc/proto-loader": "^0.7.9",
"@nestjs/cli": "^9.5.0", "@nestjs/cli": "^9.5.0",
@@ -1397,9 +1397,9 @@
} }
}, },
"node_modules/@dadosfera/protospack-v2": { "node_modules/@dadosfera/protospack-v2": {
"version": "3.37.0-alpha.19", "version": "3.37.0-alpha.20",
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.37.0-alpha.19.tgz", "resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.37.0-alpha.20.tgz",
"integrity": "sha512-+F2sMJszfXRqWuN5ae+v7MqHhJyg7TgVvnuFBKUOwHvBoWCfAUnIm9XGEA/YjPpRUa1gM0nnKL8SpBFf43Q1aA==", "integrity": "sha512-rs8YUgnwA8dTohzSEAeilU7WAscodf26/yrsqC/lq0Dz2s3Hi09TXItnLJ5ktv5xWaBQ/eZjyc5zPjpcWL3myQ==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@grpc/grpc-js": "^1.9.3", "@grpc/grpc-js": "^1.9.3",
+1 -1
View File
@@ -30,7 +30,7 @@
"@aws-sdk/client-secrets-manager": "^3.414.0", "@aws-sdk/client-secrets-manager": "^3.414.0",
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4", "@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
"@dadosfera/protospack": "2.5.3", "@dadosfera/protospack": "2.5.3",
"@dadosfera/protospack-v2": "3.37.0-alpha.19", "@dadosfera/protospack-v2": "3.37.0-alpha.20",
"@grpc/grpc-js": "^1.9.3", "@grpc/grpc-js": "^1.9.3",
"@grpc/proto-loader": "^0.7.9", "@grpc/proto-loader": "^0.7.9",
"@nestjs/cli": "^9.5.0", "@nestjs/cli": "^9.5.0",
+3 -1
View File
@@ -28,6 +28,7 @@ import { MixpanelModule } from './modules/mixpanel/mixpanel.module';
import { CustomersModule } from './modules/customers/customers.module'; import { CustomersModule } from './modules/customers/customers.module';
import { OpenDataModule } from './modules/open-data/open-data.module'; import { OpenDataModule } from './modules/open-data/open-data.module';
import { ThemeModule } from './modules/theme/theme.module'; import { ThemeModule } from './modules/theme/theme.module';
import { NetworkPolicyModule } from './modules/network-policy/network-policy.module';
@Module({ @Module({
providers: [ providers: [
@@ -62,7 +63,8 @@ import { ThemeModule } from './modules/theme/theme.module';
OpenDataModule, OpenDataModule,
ThemeModule, ThemeModule,
//Always leave HealthModule last, so it is on the bottom of swagger //Always leave HealthModule last, so it is on the bottom of swagger
HealthModule HealthModule,
NetworkPolicyModule
], ],
}) })
export class AppModule {} export class AppModule {}
+30 -20
View File
@@ -54,7 +54,6 @@ import { LanguageEnum } from 'src/utils/languages.enum';
import { Language } from 'src/decorators/language.decorator'; import { Language } from 'src/decorators/language.decorator';
import { ApiInternalOnlyEndpoint } from 'src/decorators/swagger.decorator'; import { ApiInternalOnlyEndpoint } from 'src/decorators/swagger.decorator';
@ApiTags('Auth') @ApiTags('Auth')
@ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }]) @ApiHeaders([{ name: 'dadosfera-lang', enum: LanguageEnum, required: false }])
@UseFilters(new GrpcToHttpExceptionFilter()) @UseFilters(new GrpcToHttpExceptionFilter())
@@ -63,7 +62,6 @@ export class AuthController {
logger: DadosferaLogger; logger: DadosferaLogger;
redirectUrl: string; redirectUrl: string;
constructor( constructor(
@Inject(DadosferaLogger) @Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger, dadosferaLogger: DadosferaLogger,
@@ -88,9 +86,12 @@ export class AuthController {
async signIn( async signIn(
@Body() { username, password, totp }: AuthSignInReq, @Body() { username, password, totp }: AuthSignInReq,
@Language() language: LanguageEnum, @Language() language: LanguageEnum,
@Headers('origin') origin: string,
): Promise<AuthSignInRes> { ): Promise<AuthSignInRes> {
this.logger.info('/auth - SignIn'); 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); return this.authClient.signIn({ username, password, totp }, metadata);
} }
@@ -100,13 +101,15 @@ export class AuthController {
async refreshAccessToken( async refreshAccessToken(
@Body() body: AuthRefreshAccessTokenReq, @Body() body: AuthRefreshAccessTokenReq,
@Language() language: LanguageEnum, @Language() language: LanguageEnum,
@Headers('origin') origin: string,
) { ) {
this.logger.info('/auth - RefreshAccessToken'); this.logger.info('/auth - RefreshAccessToken');
const { refreshToken, customerName: customer_name } = body; const { refreshToken, customerName: customer_name } = body;
const frontHost = origin.replace(/^https?:\/\//, '');
const metadata = PackTheMetadata({ const metadata = PackTheMetadata({
customer_name,
language, language,
customer_name,
custom_host: frontHost,
}); });
return this.authClient.refreshAccessToken({ refreshToken }, metadata); return this.authClient.refreshAccessToken({ refreshToken }, metadata);
@@ -180,16 +183,23 @@ export class AuthController {
@ApiInternalOnlyEndpoint() @ApiInternalOnlyEndpoint()
@Post('confirm-reset-password') @Post('confirm-reset-password')
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.OK)
async confirmResetPassword(@Body() body: AuthConfirmResetPasswordRequest) { async confirmResetPassword(
@Body() body: AuthConfirmResetPasswordRequest,
@Headers('origin') origin: string,
) {
this.logger.info('/auth - confirm-reset-password'); this.logger.info('/auth - confirm-reset-password');
const frontHost = origin.replace(/^https?:\/\//, '');
const metadata = PackTheMetadata({ custom_host: frontHost });
const { username, code, newPassword } = body; const { username, code, newPassword } = body;
return this.authClient.confirmResetPassword({ return this.authClient.confirmResetPassword(
username, {
code, username,
newPassword, code,
}); newPassword,
},
metadata,
);
} }
@ApiInternalOnlyEndpoint() @ApiInternalOnlyEndpoint()
@@ -355,18 +365,18 @@ export class AuthController {
async blockUsers( async blockUsers(
@Language() language: LanguageEnum, @Language() language: LanguageEnum,
@User() user: RequestUser, @User() user: RequestUser,
@Body() body: BulkEditRequest @Body() body: BulkEditRequest,
) { ) {
this.logger.info('blockUsers - Starting request'); this.logger.info('blockUsers - Starting request');
try { try {
const metadata = PackTheMetadata(user); const metadata = PackTheMetadata(user);
this.logger.debug('Calling blockUsers service', { this.logger.debug('Calling blockUsers service', {
metadata: { metadata: {
access_token: metadata.get('access_token'), access_token: metadata.get('access_token'),
language: metadata.get('language') language: metadata.get('language'),
} },
}); });
const result = await this.authClient.blockUsers(body.users, metadata); const result = await this.authClient.blockUsers(body.users, metadata);
@@ -375,7 +385,7 @@ export class AuthController {
} catch (error) { } catch (error) {
this.logger.error('blockUsers - Error', { this.logger.error('blockUsers - Error', {
error: error.message, error: error.message,
stack: error.stack stack: error.stack,
}); });
throw error; throw error;
} }
@@ -388,7 +398,7 @@ export class AuthController {
async unblockUsers( async unblockUsers(
@Language() language: LanguageEnum, @Language() language: LanguageEnum,
@User() user: RequestUser, @User() user: RequestUser,
@Body() body: BulkEditRequest @Body() body: BulkEditRequest,
) { ) {
this.logger.info('unblockUsers'); this.logger.info('unblockUsers');
const metadata = PackTheMetadata(user); const metadata = PackTheMetadata(user);
@@ -403,11 +413,11 @@ export class AuthController {
async resetUsers( async resetUsers(
@Language() language: LanguageEnum, @Language() language: LanguageEnum,
@User() user: RequestUser, @User() user: RequestUser,
@Body() body: BulkEditRequest @Body() body: BulkEditRequest,
) { ) {
this.logger.info('resetUsers'); this.logger.info('resetUsers');
const metadata = PackTheMetadata(user); const metadata = PackTheMetadata(user);
return this.authClient.resetUsers(body.users, metadata); return this.authClient.resetUsers(body.users, metadata);
} }
} }
+32 -21
View File
@@ -113,19 +113,21 @@ export class AuthClientService implements OnModuleInit {
); );
} }
async confirmResetPassword({ async confirmResetPassword(
username, { username, code, newPassword }: AuthConfirmResetPasswordRequest,
code, metadata: Metadata,
newPassword, ) {
}: AuthConfirmResetPasswordRequest) {
this.logger.info('confirmResetPassword'); this.logger.info('confirmResetPassword');
return lastValueFrom( return lastValueFrom(
this.authService.AuthConfirmResetPassword({ this.authService.AuthConfirmResetPassword(
username, {
code, username,
newPassword, code,
}), newPassword,
},
metadata,
),
); );
} }
@@ -170,15 +172,18 @@ export class AuthClientService implements OnModuleInit {
); );
} }
async blockUsers(users: string[],metadata: Metadata): Promise<BulkEditResponse> { async blockUsers(
users: string[],
metadata: Metadata,
): Promise<BulkEditResponse> {
this.logger.info('blockUsers - Service starting'); this.logger.info('blockUsers - Service starting');
try { try {
this.logger.debug('Calling BlockUser gRPC method', { this.logger.debug('Calling BlockUser gRPC method', {
metadata: { metadata: {
access_token: metadata.get('access_token'), access_token: metadata.get('access_token'),
language: metadata.get('language') language: metadata.get('language'),
} },
}); });
const response = await lastValueFrom<BulkEditResponse>( const response = await lastValueFrom<BulkEditResponse>(
@@ -196,26 +201,32 @@ export class AuthClientService implements OnModuleInit {
} }
} }
async unblockUsers(users: string[],metadata: Metadata): Promise<BulkEditResponse> { async unblockUsers(
users: string[],
metadata: Metadata,
): Promise<BulkEditResponse> {
this.logger.info('unblockUsers'); this.logger.info('unblockUsers');
return await lastValueFrom( return await lastValueFrom(
this.authService.UnblockUser({ users }, metadata), this.authService.UnblockUser({ users }, metadata),
); );
} }
async resetUsers(users: string[], metadata: Metadata): Promise<BulkEditResponse> { async resetUsers(
users: string[],
metadata: Metadata,
): Promise<BulkEditResponse> {
this.logger.info('resetUsers'); this.logger.info('resetUsers');
try { try {
this.logger.debug('Calling ResetUser gRPC method', { this.logger.debug('Calling ResetUser gRPC method', {
metadata: { metadata: {
access_token: metadata.get('access_token'), access_token: metadata.get('access_token'),
language: metadata.get('language') language: metadata.get('language'),
} },
}); });
const response = await lastValueFrom<BulkEditResponse>( const response = await lastValueFrom<BulkEditResponse>(
this.authService.ResetUser({ users }, metadata) this.authService.ResetUser({ users }, metadata),
); );
this.logger.info('resetUsers - Success', { response }); this.logger.info('resetUsers - Success', { response });
@@ -223,7 +234,7 @@ export class AuthClientService implements OnModuleInit {
} catch (error) { } catch (error) {
this.logger.error('resetUsers - Error', { this.logger.error('resetUsers - Error', {
error: error.message, error: error.message,
stack: error.stack stack: error.stack,
}); });
throw error; throw error;
} }
@@ -0,0 +1,6 @@
import { ApiProperty } from "@nestjs/swagger";
export class NetworkPoliciesDTO {
@ApiProperty()
policies: string []
}
@@ -0,0 +1,64 @@
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Post } from '@nestjs/common';
import { ApiOkResponse } from '@nestjs/swagger';
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
import {
Authenticated,
RequireAllPermissions,
} from 'src/decorators/authentication.decorator';
import { NetworkPoliciesDTO } from './dto/network-policy.dto';
import { RequestUser, User } from 'src/decorators/user.decorator';
import { NetworkPolicyService } from './network-policy.service';
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
@Controller('network-policy')
export class NetworkPolicyController {
constructor(private networkPolicyService: NetworkPolicyService) {}
@Get()
@Authenticated()
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
@HttpCode(HttpStatus.OK)
async getNetworks(
@User() user: RequestUser,
) {
return await this.networkPolicyService.getByCustomer(
user.customer_id
);
}
@Post()
@Authenticated()
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
@ApiOkResponse()
@HttpCode(HttpStatus.CREATED)
async applyNetworkPolicies(
@User() user: RequestUser,
@Body() data: NetworkPoliciesDTO,
) {
const metadata = PackTheMetadata(user);
return await this.networkPolicyService.apply(
data.policies,
user.customer_id,
metadata,
);
}
@Delete()
@Authenticated()
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
@ApiOkResponse()
@HttpCode(HttpStatus.OK)
async removeNetworkPolicies(
@User() user: RequestUser,
@Body() data: NetworkPoliciesDTO,
) {
const metadata = PackTheMetadata(user);
return await this.networkPolicyService.delete(
data.policies,
user.customer_id,
metadata,
);
}
}
@@ -0,0 +1,19 @@
import { Module } from '@nestjs/common';
import { NetworkPolicyController } from './network-policy.controller';
import { NetworkPolicyService } from './network-policy.service';
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: [NetworkPolicyController],
providers: [NetworkPolicyService, DadosferaLogger]
})
export class NetworkPolicyModule {}
@@ -0,0 +1,74 @@
import { Inject, Injectable } from '@nestjs/common';
import { DucClient } from '../duc/client.config';
import { ClientGrpc } from '@nestjs/microservices';
import DadosferaLogger from '@dadosfera/dadosfera-logs';
import { CustomersProtoService } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service';
import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc';
import { Metadata } from '@grpc/grpc-js';
import { lastValueFrom } from 'rxjs';
import { NetworkPoliciesDTO } from './dto/network-policy.dto';
@Injectable()
export class NetworkPolicyService {
private customerService: CustomersProtoService;
private logger: DadosferaLogger;
constructor(
@Inject(DucClient.name) private readonly grpcClient: ClientGrpc,
@Inject(DadosferaLogger)
dadosferaLogger: DadosferaLogger,
) {
this.logger = dadosferaLogger.logger;
}
onModuleInit() {
this.customerService = this.grpcClient.getService<CustomersProtoService>(
ProtoServices.CustomersProtoService,
);
}
async getByCustomer(id: string): Promise<NetworkPoliciesDTO> {
const {
customer
} = await lastValueFrom(this.customerService.CustomerFindOneById({
id
}));
return {
policies: customer.networkPolicies
}
}
async apply(
networkPolicies: string[],
customerId: string,
metadata: Metadata,
) {
return await lastValueFrom(
this.customerService.CustomerCreateNetworkPolicy(
{
customerId,
networkPolicies,
},
metadata,
),
);
}
async delete(
networkPolicies: string[],
customerId: string,
metadata: Metadata,
) {
return await lastValueFrom(
this.customerService.CustomerRemoveNetworkPolicy(
{
customerId,
networkPolicies,
},
metadata,
),
);
}
}
+3
View File
@@ -11,6 +11,9 @@ interface IMetadata {
roles?: string[]; roles?: string[];
is_data_manager?: boolean; is_data_manager?: boolean;
access_token?: string; access_token?: string;
host?: string;
origin?: string;
custom_host?: string;
} }
export function PackTheMetadata(info: IMetadata): Metadata { export function PackTheMetadata(info: IMetadata): Metadata {