Skip to content

Commit

Permalink
Merge pull request #4519 from cloud-gov/chore-encrypt-build-task-task…
Browse files Browse the repository at this point in the history
…-params

chore: Encrypt build task CF task param values #4509
  • Loading branch information
apburnes authored May 28, 2024
2 parents 3f9a8cf + 6e59a85 commit 297bdc1
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 2 deletions.
30 changes: 29 additions & 1 deletion api/services/Encryptor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const Crypto = require('crypto');
const _ = require('underscore');

const ALGORITHM = 'aes-256-gcm';

Expand Down Expand Up @@ -32,6 +33,28 @@ function encrypt(value, key, { hintSize = 4 } = {}) {
return { ciphertext, hint };
}

function encryptObjectValues(obj, key, { hintSize = 4 } = {}) {
return _.mapObject(obj, (value) => {
if (_.isArray(value) || _.isFunction(value)) {
return value;
}

if (_.isObject(value)) {
return encryptObjectValues(value, key, { hintSize });
}

if (_.isString(value)) {
return encrypt(value, key, { hintSize }).ciphertext;
}

if (_.isNumber(value)) {
return encrypt(value.toString(), key, { hintSize }).ciphertext;
}

return value;
});
}

function decrypt(ciphertext, key) {
const hashedKey = Crypto.createHash('sha256').update(key).digest();
const [authTagHex, ivHex, encrypted] = ciphertext.split(':');
Expand All @@ -46,4 +69,9 @@ function decrypt(ciphertext, key) {
return decipher.update(encrypted, 'hex', 'utf8') + decipher.final('utf8');
}

module.exports = { ALGORITHM, encrypt, decrypt };
module.exports = {
ALGORITHM,
encrypt,
encryptObjectValues,
decrypt,
};
4 changes: 3 additions & 1 deletion api/utils/cfApiClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,9 @@ class CloudFoundryAPIClient {
// TODO: link to template documentation
const template = parse(task.BuildTaskType.metadata.template);

const taskParams = template({ task, job });
const encryptedTask = Encryptor.encryptObjectValues(task, encryption.key);
const encryptedJob = Encryptor.encryptObjectValues(job, encryption.key);
const taskParams = template({ task: encryptedTask, job: encryptedJob });

const appGUID = await this.fetchTaskAppGUID(
task.BuildTaskType.metadata.appName
Expand Down
72 changes: 72 additions & 0 deletions test/api/unit/services/Encryptor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,76 @@ describe('Encryptor', () => {
expect(hint).to.eq('');
});
});

describe('.encryptObjectValues', () => {
it('should only encrypt string and number values', () => {
const key = 'encrypt-key';
const data = {
id: 123,
name: 'this-is-a-data-object',
numberlist: [1, 2, 3],
stringList: ['a', 'b', 'c'],
getFunction: () => {},
};

const output = Encryptor.encryptObjectValues(data, key);
const decryptedId = Encryptor.decrypt(output.id, key);
const decryptedName = Encryptor.decrypt(output.name, key);

expect(decryptedId).to.equal(data.id.toString());
expect(decryptedName).to.equal(data.name);
expect(output.numberlist).to.equal(data.numberlist);
expect(output.stringList).to.equal(data.stringList);
expect(typeof output.getFunction).to.equal('function');
});

it('should only encrypt nested string and number values', () => {
const key = 'encrypt-key';
const data = {
id: 123,
name: 'this-is-a-data-object',
metadata: {
name: 'The metadata',
type: 'level 1',
meta: {
name: 'Meta metadata',
list: [1, 2, 3],
},
},
attributes: {
total: 1,
},
};

const output = Encryptor.encryptObjectValues(data, key);
const decryptedId = Encryptor.decrypt(output.id, key);
const decryptedName = Encryptor.decrypt(output.name, key);
const decryptedMetadataName = Encryptor.decrypt(
output.metadata.name,
key
);
const decryptedMetadataType = Encryptor.decrypt(
output.metadata.type,
key
);
const decryptedMetadataMetaName = Encryptor.decrypt(
output.metadata.meta.name,
key
);
const decryptedAttributesTotal = Encryptor.decrypt(
output.attributes.total,
key
);

expect(decryptedId).to.equal(data.id.toString());
expect(decryptedName).to.equal(data.name);
expect(decryptedMetadataName).to.equal(data.metadata.name);
expect(decryptedMetadataType).to.equal(data.metadata.type);
expect(decryptedMetadataMetaName).to.equal(data.metadata.meta.name);
expect(output.metadata.meta.list).to.equal(data.metadata.meta.list);
expect(decryptedAttributesTotal).to.equal(
data.attributes.total.toString()
);
});
});
});

0 comments on commit 297bdc1

Please sign in to comment.