cypher class tenant aware
MODIFY
src/integration/asset/schneider/SchneiderAssetIntegration.ts
src/integration/asset/schneider/SchneiderAssetIntegration.ts
@@ -127,9 +127,7 @@ export default class SchneiderAssetIntegration extends AssetIntegration<AssetSet
const params = new URLSearchParams();
params.append('grant_type', 'password');
params.append('username', this.connection.connection.user);
- // Get Crypto Setting
- const cryptoSetting = await Cypher.getCryptoSetting(this.tenantID);
- params.append('password', Cypher.decrypt(this.connection.connection.password, cryptoSetting));
+ params.append('password', (await Cypher.decrypt(this.connection.connection.password, this.tenantID)));
return params;
}

MODIFY
src/integration/billing/stripe/StripeBillingIntegration.ts
src/integration/billing/stripe/StripeBillingIntegration.ts
@@ -31,7 +31,6 @@ export default class StripeBillingIntegration extends BillingIntegration<StripeB
private stripe: Stripe;
private stripeSettings: StripeBillingSetting;
- // TODO refactor
constructor(tenantId: string, settings: StripeBillingSetting) {
super(tenantId, settings);
this.axiosInstance = AxiosFactory.getAxiosInstance(this.tenantID);
@@ -693,10 +692,8 @@ export default class StripeBillingIntegration extends BillingIntegration<StripeB
private async initializeStripe() {
this.settings.currency = this.stripeSettings.currency;
- // Get Crypto Setting
- const cryptoSetting = await Cypher.getCryptoSetting(this.tenantID);
if (this.settings.secretKey) {
- this.settings.secretKey = Cypher.decrypt(this.stripeSettings.secretKey, cryptoSetting);
+ this.settings.secretKey = await Cypher.decrypt(this.stripeSettings.secretKey, this.tenantID);
}
// Currently the public key is not encrypted
this.stripe = new Stripe(this.settings.secretKey);

MODIFY
src/migration/tasks/AddSensitiveDataInSettingsTask.ts
src/migration/tasks/AddSensitiveDataInSettingsTask.ts
@@ -25,8 +25,6 @@ export default class AddSensitiveDataInSettingsTask extends MigrationTask {
}
}])
.toArray();
- // Get Crypto Setting
- const cryptoSetting = await Cypher.getCryptoSetting(tenant.id);
// Process each setting
for (const setting of settings) {
// Add sensitiveData property if not present
@@ -36,7 +34,7 @@ export default class AddSensitiveDataInSettingsTask extends MigrationTask {
setting.sensitiveData = ['content.concur.clientSecret'];
// Encrypt
if (setting.content.concur.clientSecret) {
- setting.content.concur.clientSecret = Cypher.encrypt(setting.content.concur.clientSecret, cryptoSetting);
+ setting.content.concur.clientSecret = await Cypher.encrypt(setting.content.concur.clientSecret, tenant.id);
} else {
setting.content.concur.clientSecret = '';
}
@@ -44,7 +42,7 @@ export default class AddSensitiveDataInSettingsTask extends MigrationTask {
} else if (setting.content.type === PricingSettingsType.CONVERGENT_CHARGING) {
setting.sensitiveData = ['content.convergentCharging.password'];
if (setting.content.convergentCharging.password) {
- setting.content.convergentCharging.password = Cypher.encrypt(setting.content.convergentCharging.password, cryptoSetting);
+ setting.content.convergentCharging.password = Cypher.encrypt(setting.content.convergentCharging.password, tenant.id);
} else {
setting.content.convergentCharging.password = '';
}

MODIFY
src/server/rest/v1/service/SettingService.ts
src/server/rest/v1/service/SettingService.ts
@@ -115,10 +115,8 @@ export default class SettingService {
}
// Filter
const filteredRequest = SettingSecurity.filterSettingCreateRequest(req.body);
- // Get Crypto Setting
- const cryptoSetting = await Cypher.getCryptoSetting(req.user.tenantID);
// Process the sensitive data if any
- Cypher.encryptSensitiveDataInJSON(filteredRequest, cryptoSetting);
+ Cypher.encryptSensitiveDataInJSON(filteredRequest, req.user.tenantID);
// Update timestamp
filteredRequest.createdBy = { 'id': req.user.id };
filteredRequest.createdOn = new Date();
@@ -168,8 +166,6 @@ export default class SettingService {
user: req.user
});
}
- // Get Crypto Setting
- const cryptoSetting = await Cypher.getCryptoSetting(req.user.tenantID);
// Process sensitive properties
for (const property of settingUpdate.sensitiveData) {
// Get the sensitive property from the request
@@ -181,14 +177,14 @@ export default class SettingService {
const hashedValueInDB = Cypher.hash(valueInDb);
if (valueInRequest !== hashedValueInDB) {
// Yes: Encrypt
- _.set(settingUpdate, property, Cypher.encrypt(valueInRequest, cryptoSetting));
+ _.set(settingUpdate, property, await Cypher.encrypt(valueInRequest, req.user.tenantID));
} else {
// No: Put back the encrypted value
_.set(settingUpdate, property, valueInDb);
}
} else {
// Value in db is empty then encrypt
- _.set(settingUpdate, property, Cypher.encrypt(valueInRequest, cryptoSetting));
+ _.set(settingUpdate, property, Cypher.encrypt(valueInRequest, req.user.tenantID));
}
}
}

MODIFY
src/utils/Cypher.ts
src/utils/Cypher.ts
@@ -11,31 +11,20 @@ const MODULE_NAME = 'Cypher';
export default class Cypher {
- public static async getCryptoSetting(tenantID: string): Promise<CryptoSetting> {
- const cryptoSettings = (await SettingStorage.getCryptoSettings(tenantID)).crypto;
- if (!cryptoSettings) {
- throw new BackendError({
- source: Constants.CENTRAL_SERVER,
- module: MODULE_NAME,
- method: 'getCryptoSetting',
- message: 'No Crypto Settings found in the database'
- });
- }
- return cryptoSettings;
- }
-
- public static encrypt(data: string, cryptoSetting: CryptoSetting): string {
+ public static async encrypt(data: string, tenantID: string): Promise<string> {
const iv = crypto.randomBytes(IV_LENGTH);
+ const cryptoSetting = await this.getCryptoSetting(tenantID);
const cipher = crypto.createCipheriv(Utils.buildAlgorithm(cryptoSetting.keyProperties), Buffer.from(cryptoSetting.key), iv);
let encryptedData = cipher.update(data);
encryptedData = Buffer.concat([encryptedData, cipher.final()]);
return iv.toString('hex') + ':' + encryptedData.toString('hex');
}
- public static decrypt(data: string, cryptoSetting: CryptoSetting): string {
+ public static async decrypt(data: string, tenantID: string): Promise<string> {
const dataParts = data.split(':');
const iv = Buffer.from(dataParts.shift(), 'hex');
const encryptedData = Buffer.from(dataParts.join(':'), 'hex');
+ const cryptoSetting = await this.getCryptoSetting(tenantID);
const decipher = crypto.createDecipheriv(Utils.buildAlgorithm(cryptoSetting.keyProperties), Buffer.from(cryptoSetting.key), iv);
let decrypted = decipher.update(encryptedData);
decrypted = Buffer.concat([decrypted, decipher.final()]);
@@ -46,7 +35,7 @@ export default class Cypher {
return crypto.createHash('sha256').update(data).digest('hex');
}
- public static encryptSensitiveDataInJSON(obj: Record<string, any>, cryptoSetting: CryptoSetting): void {
+ public static encryptSensitiveDataInJSON(obj: Record<string, any>, tenantID: string): void {
if (typeof obj !== 'object') {
throw new BackendError({
source: Constants.CENTRAL_SERVER,
@@ -71,7 +60,7 @@ export default class Cypher {
const value = _.get(obj, property);
// If the value is undefined, null or empty then do nothing and skip to the next property
if (value && value.length > 0) {
- _.set(obj, property, Cypher.encrypt(value, cryptoSetting));
+ _.set(obj, property, Cypher.encrypt(value, tenantID));
}
}
}
@@ -80,7 +69,7 @@ export default class Cypher {
}
}
- public static decryptSensitiveDataInJSON(obj: Record<string, any>, cryptoSetting: CryptoSetting): void {
+ public static decryptSensitiveDataInJSON(obj: Record<string, any>, tenantID: string): void {
if (typeof obj !== 'object') {
throw new BackendError({
source: Constants.CENTRAL_SERVER,
@@ -105,7 +94,7 @@ export default class Cypher {
const value = _.get(obj, property);
// If the value is undefined, null or empty then do nothing and skip to the next property
if (value && value.length > 0) {
- _.set(obj, property, Cypher.decrypt(value, cryptoSetting));
+ _.set(obj, property, Cypher.decrypt(value, tenantID));
}
}
}
@@ -143,4 +132,17 @@ export default class Cypher {
}
}
}
+
+ private static async getCryptoSetting(tenantID: string): Promise<CryptoSetting> {
+ const cryptoSettings = (await SettingStorage.getCryptoSettings(tenantID)).crypto;
+ if (!cryptoSettings) {
+ throw new BackendError({
+ source: Constants.CENTRAL_SERVER,
+ module: MODULE_NAME,
+ method: 'getCryptoSetting',
+ message: 'No Crypto Settings found in the database'
+ });
+ }
+ return cryptoSettings;
+ }
}

MODIFY
test/api/BillingTest.ts
test/api/BillingTest.ts
@@ -45,18 +45,14 @@ class TestData {
public static async setBillingSystemValidCredentials(testData) {
const stripeSettings = TestData.getStripeSettings();
await TestData.saveBillingSettings(testData, stripeSettings);
- // Get Crypto Setting
- const cryptoSetting = await Cypher.getCryptoSetting(testData.tenantContext.getTenant().id);
- stripeSettings.secretKey = Cypher.encrypt(stripeSettings.secretKey, cryptoSetting);
+ stripeSettings.secretKey = await Cypher.encrypt(stripeSettings.secretKey, testData.tenantContext.getTenant().id);
billingImpl = new StripeBillingIntegration(testData.tenantContext.getTenant().id, stripeSettings);
expect(billingImpl).to.not.be.null;
}
public static async setBillingSystemInvalidCredentials(testData) {
const stripeSettings = TestData.getStripeSettings();
- // Get Crypto Setting
- const cryptoSetting = await Cypher.getCryptoSetting(testData.tenantContext.getTenant().id);
- stripeSettings.secretKey = Cypher.encrypt('sk_test_invalid_credentials', cryptoSetting);
+ stripeSettings.secretKey = await Cypher.encrypt('sk_test_invalid_credentials', testData.tenantContext.getTenant().id);
await TestData.saveBillingSettings(testData, stripeSettings);
billingImpl = new StripeBillingIntegration(testData.tenantContext.getTenant().id, stripeSettings);
expect(billingImpl).to.not.be.null;

MODIFY
test/api/SmartChargingTest.ts
test/api/SmartChargingTest.ts
@@ -47,9 +47,7 @@ class TestData {
public static async setSmartChargingValidCredentials(testData): Promise<void> {
const sapSmartChargingSettings = TestData.getSmartChargingSettings();
await TestData.saveSmartChargingSettings(testData, sapSmartChargingSettings);
- // Get Crypto Setting
- const cryptoSetting = await Cypher.getCryptoSetting(testData.tenantContext.getTenant().id);
- sapSmartChargingSettings.password = Cypher.encrypt(sapSmartChargingSettings.password, cryptoSetting);
+ sapSmartChargingSettings.password = await Cypher.encrypt(sapSmartChargingSettings.password, testData.tenantContext.getTenant().id);
aCBufferFactor = 1 + sapSmartChargingSettings.limitBufferAC / 100,
dCBufferFactor = 1 + sapSmartChargingSettings.limitBufferDC / 100,
smartChargingIntegration = await SmartChargingFactory.getSmartChargingImpl(testData.tenantContext.getTenant().id);

MODIFY
test/api/context/BillingContext.ts
test/api/context/BillingContext.ts
@@ -85,9 +85,7 @@ export default class BillingContext {
const tenantBillingSettings = await SettingStorage.getBillingSettings(this.tenantContext.getTenant().id);
tenantBillingSettings.stripe = stripeSettings;
tenantBillingSettings.sensitiveData = ['content.stripe.secretKey'];
- // Get Crypto Setting
- const cryptoSetting = await Cypher.getCryptoSetting(this.tenantContext.getTenant().id);
- tenantBillingSettings.stripe.secretKey = Cypher.encrypt(stripeSettings.secretKey, cryptoSetting);
+ tenantBillingSettings.stripe.secretKey = await Cypher.encrypt(stripeSettings.secretKey, this.tenantContext.getTenant().id);
await SettingStorage.saveBillingSettings(this.tenantContext.getTenant().id, tenantBillingSettings);
}
}

cypher class tenant aware