feat: implement encryption helper and transaction setting handler
- Added EncryptionHelper for encrypting and decrypting transaction settings. - Introduced TransactionSettingHandler to manage changes in transaction settings. - Updated SalesPriceFormulaModel to use decrypted values. - Enhanced SalesPriceFormulaDataService with methods to get and update transaction settings. - Modified SalesPriceFormulaReadService to return decrypted values in the response.pull/172/head
parent
bd14dc0b4b
commit
0f46f5ff39
|
@ -6,6 +6,7 @@ import {
|
||||||
import { Column, Entity } from 'typeorm';
|
import { Column, Entity } from 'typeorm';
|
||||||
import { BaseModel } from 'src/core/modules/data/model/base.model';
|
import { BaseModel } from 'src/core/modules/data/model/base.model';
|
||||||
import { FormulaType } from '../../constants';
|
import { FormulaType } from '../../constants';
|
||||||
|
import { EncryptionHelper } from '../../domain/helpers/encryption.helper';
|
||||||
|
|
||||||
@Entity(TABLE_NAME.PRICE_FORMULA)
|
@Entity(TABLE_NAME.PRICE_FORMULA)
|
||||||
export class SalesPriceFormulaModel
|
export class SalesPriceFormulaModel
|
||||||
|
@ -48,6 +49,7 @@ export class TransactionSettingModel
|
||||||
|
|
||||||
//TODO: add logic to get value from key
|
//TODO: add logic to get value from key
|
||||||
percentValue(): number {
|
percentValue(): number {
|
||||||
return this.value ?? 100;
|
const value = EncryptionHelper.decrypt(this.key);
|
||||||
|
return Number(value) ?? 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,4 +158,15 @@ export class TransactionSettingDataService extends BaseDataService<TransactionSe
|
||||||
) {
|
) {
|
||||||
super(repo);
|
super(repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create function get one transaction setting
|
||||||
|
async getTransactionSetting() {
|
||||||
|
return this.repo.findOne({
|
||||||
|
where: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateTransactionSetting(payload: any) {
|
||||||
|
return this.repo.update(payload.id, payload);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,12 @@ export class SalesPriceFormulaReadService extends BaseReadService<SalesPriceForm
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return data;
|
const value = data.percentValue();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
value: value,
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
import * as crypto from 'crypto';
|
||||||
|
|
||||||
|
export class EncryptionHelper {
|
||||||
|
private static readonly algorithm = 'aes-256-cbc';
|
||||||
|
private static readonly secretKey = crypto.scryptSync(
|
||||||
|
'sales-price-formula-secret',
|
||||||
|
'salt',
|
||||||
|
32,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts a string using AES-256-CBC algorithm
|
||||||
|
* @param text - The string to encrypt
|
||||||
|
* @returns Encrypted string in format: iv:encryptedData
|
||||||
|
*/
|
||||||
|
static encrypt(text: string): string {
|
||||||
|
if (!text) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const iv = crypto.randomBytes(16);
|
||||||
|
const cipher = crypto.createCipheriv(this.algorithm, this.secretKey, iv);
|
||||||
|
let encrypted = cipher.update(text, 'utf8', 'hex');
|
||||||
|
encrypted += cipher.final('hex');
|
||||||
|
|
||||||
|
return `${iv.toString('hex')}:${encrypted}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a string that was encrypted using the encrypt method
|
||||||
|
* @param encryptedText - The encrypted string in format: iv:encryptedData
|
||||||
|
* @returns Decrypted original string
|
||||||
|
*/
|
||||||
|
static decrypt(encryptedText: string): string {
|
||||||
|
if (!encryptedText) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [ivHex, encrypted] = encryptedText.split(':');
|
||||||
|
if (!ivHex || !encrypted) {
|
||||||
|
throw new Error('Invalid encrypted text format');
|
||||||
|
}
|
||||||
|
|
||||||
|
const iv = Buffer.from(ivHex, 'hex');
|
||||||
|
const decipher = crypto.createDecipheriv(
|
||||||
|
this.algorithm,
|
||||||
|
this.secretKey,
|
||||||
|
iv,
|
||||||
|
);
|
||||||
|
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
||||||
|
decrypted += decipher.final('utf8');
|
||||||
|
|
||||||
|
return decrypted;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error('Failed to decrypt data: Invalid encrypted text format');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a hash of the input string using SHA-256
|
||||||
|
* @param text - The string to hash
|
||||||
|
* @returns SHA-256 hash of the input string
|
||||||
|
*/
|
||||||
|
static hash(text: string): string {
|
||||||
|
if (!text) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return crypto.createHash('sha256').update(text).digest('hex');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
|
||||||
|
import { ChangeDocEvent } from 'src/modules/configuration/couch/domain/events/change-doc.event';
|
||||||
|
import { TransactionSettingDataService } from '../../../data/services/sales-price-formula-data.service';
|
||||||
|
import { EncryptionHelper } from '../../helpers/encryption.helper';
|
||||||
|
|
||||||
|
@EventsHandler(ChangeDocEvent)
|
||||||
|
export class TransactionSettingHandler
|
||||||
|
implements IEventHandler<ChangeDocEvent>
|
||||||
|
{
|
||||||
|
constructor(
|
||||||
|
private transactionSettingService: TransactionSettingDataService, // private orchestrator: SalesPriceFormulaDataOrchestrator,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async handle(event: ChangeDocEvent) {
|
||||||
|
const data = event.data.data;
|
||||||
|
const database = event.data.database;
|
||||||
|
|
||||||
|
if (database !== 'api_configuration') return;
|
||||||
|
const value = data.value;
|
||||||
|
|
||||||
|
const currentTransactionSetting =
|
||||||
|
await this.transactionSettingService.getTransactionSetting();
|
||||||
|
|
||||||
|
if (value === currentTransactionSetting.value) return;
|
||||||
|
const key = EncryptionHelper.encrypt(`${value}`);
|
||||||
|
const payload = {
|
||||||
|
id: currentTransactionSetting.id,
|
||||||
|
value: 0,
|
||||||
|
key,
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.transactionSettingService.updateTransactionSetting(payload);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'
|
||||||
import { UpdateTransactionSettingManager } from './domain/usecases/managers/update-transaction-setting.manager';
|
import { UpdateTransactionSettingManager } from './domain/usecases/managers/update-transaction-setting.manager';
|
||||||
import { TransactionModel } from '../transaction/data/models/transaction.model';
|
import { TransactionModel } from '../transaction/data/models/transaction.model';
|
||||||
import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
||||||
|
import { TransactionSettingHandler } from './domain/usecases/handlers/transaction-setting.handler';
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
|
@ -58,6 +59,7 @@ import { CouchModule } from 'src/modules/configuration/couch/couch.module';
|
||||||
|
|
||||||
SalesPriceFormulaDataOrchestrator,
|
SalesPriceFormulaDataOrchestrator,
|
||||||
SalesPriceFormulaReadOrchestrator,
|
SalesPriceFormulaReadOrchestrator,
|
||||||
|
TransactionSettingHandler,
|
||||||
],
|
],
|
||||||
exports: [SalesPriceFormulaDataService, SalesPriceFormulaReadService],
|
exports: [SalesPriceFormulaDataService, SalesPriceFormulaReadService],
|
||||||
})
|
})
|
||||||
|
|
|
@ -97,7 +97,8 @@ export class WhatsappService {
|
||||||
{
|
{
|
||||||
parameter_name: 'queue_time',
|
parameter_name: 'queue_time',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: toTime(data.time), // replace with queue_time variable
|
// text: toTime(data.time), // replace with queue_time variable
|
||||||
|
text: '--:--',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue