mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-24 14:34:21 +00:00
fix!: drop legacy rsa encryption (#39111)
This commit is contained in:
committed by
Jamie Tanna
parent
0d5d7a8669
commit
f1eefcf393
@@ -1,27 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAzVLc1KmhWxcLnoPTPpQwxVHySFx4vY+0Sk+2AdnlJvrTFlNR
|
||||
8XgBPdgU9SDwHFFTYyXRQ/msm0YMOBRoIdz4/psz6IzRV80aOtDIkUPAU+cdqnje
|
||||
3rusrPnqCykDuIHGoBZ8zlt57t/8OVNOduUflrQRqMFors8iLWcNjuGJfZAusI5B
|
||||
M8KYYDPL2oUo/8AV0bWN8MdNnxDSwGtan4bbzrtG6dpNzyntsG5DkL1h8OZRki4S
|
||||
kHf+71ZzJFz1KcyrzBVJ9DBxdiJdmLLkv9caLLc2QS0VFmtfLnlrga3Sahy6YNwc
|
||||
rN33aaNOXwFPSErsKWIgIf16eOaSUQCFusXY9QIDAQABAoIBAQCkltMM6nm9Ikkf
|
||||
JX9V/8bkth7o4K+tDSAyHZnB/CBUUeaaU+oxDci5AZkzMtcnbA3TQcJxohg6VDmB
|
||||
TuJ2msNCnblLpm492t023pyYzd3DpFXEjKXjmEAAXUm+7n7cDbPiKoSbivrAgO6Y
|
||||
KW6RonPjA6/QPlIjJ0m3aY+VxLfJXTYVfFBk+0HGEAvmrSSSEezXej8Qzs9CRKtz
|
||||
cQkR5Bs749SS509MHxaslP7n366EvJBJkqrjUxA6kbxOxUkuuOWF9jfduDAG+NYc
|
||||
pe4IXFOYMpK/w29wqvkNulKYs+FHXr1sGjkztGjyNnjP0NnX+r0EYU07xLJ26krD
|
||||
KMWQG8sBAoGBAO93iFrPnEBnnKojI8b+u3YowVCz0HVuHHIStHd9uUgfsn/Bxfls
|
||||
HRIlg8l1MJd69TT0knOhkJxBCP+b/qBvid7YLbTxIVELCAfLAzsmGgY+DEN/TTUb
|
||||
FDvHGa/drCnkSR/O/RbtHvMQISzTja1siYrdwwY+wpwzR2tB7ZH/9iO1AoGBANt/
|
||||
3Srpv4BbP7JZ+cNte4JfI2gZq41mo+DF5ryuFZzsP3R5SZ1BOapQGyLEATQaoxsJ
|
||||
QZsI73KPBzab0/+E75qJuXckIGmFftHXgoQpClGvPaEDF9M21QW5Y3vKVa/45qhy
|
||||
3wpb8gEYqrt1x0rmzyumCtCD8J470Er64gE1eKhBAoGBALW6ScFYwqRhvROkvTb8
|
||||
A7mE7kfXXgBwAqhTJ59yytRAMc8gd6R0do9Z5uxQwgKDLmj0ndugpcTe2fxZHuAU
|
||||
JVX3SqCBSZ5eN8bqOtZ9cMyB8/6ZMjd2CGHhE85R9KCJ/TBlfc4TPySIfhStq1wL
|
||||
/UlkR+eKY1f01mNAUhE1ZU7tAoGBAKwS/B51KsSERFYcRToYbRfSX55vaVarnVNL
|
||||
scw+qQDhEAnOP5CBHqTOscc6YzsmmrFKO10/zv8+80ezN6n73B6JU5T8BFDU74uv
|
||||
6EiVJ9rLh4PfOeFB/hPDtyLHhw8yEBkEHKgxVnHXlZjqBzdH5Cdyvs2icZKKj4sI
|
||||
TP7nnVRBAoGAPZBjjTn9HgB9et5Kdovp+7nr842WboxwklVyTpbNGAjIxNXIXex+
|
||||
TST21UbquTIpIrpYRk1WMIu9T5PndAagDWVEsmUYQZeuhmuY64K+iviRsfdGthws
|
||||
nbbR8sMEkn4XEtPZfrEBq27g01RNmIIMW5Es2O5N2AjLlyeBOh099Fw=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+8
-43
@@ -6,10 +6,6 @@ import { regEx } from '../util/regex';
|
||||
import { addSecretForSanitizing } from '../util/sanitize';
|
||||
import { ensureTrailingSlash, parseUrl, trimSlashes } from '../util/url';
|
||||
import { tryDecryptKbPgp } from './decrypt/kbpgp';
|
||||
import {
|
||||
tryDecryptPublicKeyDefault,
|
||||
tryDecryptPublicKeyPKCS1,
|
||||
} from './decrypt/legacy';
|
||||
import { tryDecryptOpenPgp } from './decrypt/openpgp';
|
||||
import { GlobalConfig } from './global';
|
||||
import { DecryptedObject } from './schema';
|
||||
@@ -30,35 +26,14 @@ export async function tryDecrypt(
|
||||
key: string,
|
||||
encryptedStr: string,
|
||||
repository: string,
|
||||
keyName: string,
|
||||
): Promise<string | null> {
|
||||
let decryptedStr: string | null = null;
|
||||
if (key?.startsWith('-----BEGIN PGP PRIVATE KEY BLOCK-----')) {
|
||||
const decryptedObjStr =
|
||||
getEnv().RENOVATE_X_USE_OPENPGP === 'true'
|
||||
? await tryDecryptOpenPgp(key, encryptedStr)
|
||||
: await tryDecryptKbPgp(key, encryptedStr);
|
||||
if (decryptedObjStr) {
|
||||
decryptedStr = validateDecryptedValue(decryptedObjStr, repository);
|
||||
}
|
||||
} else {
|
||||
decryptedStr = tryDecryptPublicKeyDefault(key, encryptedStr);
|
||||
if (is.string(decryptedStr)) {
|
||||
logger.warn(
|
||||
{ keyName },
|
||||
'Encrypted value is using deprecated default padding, please change to using PGP encryption.',
|
||||
);
|
||||
} else {
|
||||
decryptedStr = tryDecryptPublicKeyPKCS1(key, encryptedStr);
|
||||
/* v8 ignore start -- not testable */
|
||||
if (is.string(decryptedStr)) {
|
||||
logger.warn(
|
||||
{ keyName },
|
||||
'Encrypted value is using deprecated PKCS1 padding, please change to using PGP encryption.',
|
||||
);
|
||||
}
|
||||
/* v8 ignore stop */
|
||||
}
|
||||
const decryptedObjStr =
|
||||
getEnv().RENOVATE_X_USE_OPENPGP === 'true'
|
||||
? await tryDecryptOpenPgp(key, encryptedStr)
|
||||
: await tryDecryptKbPgp(key, encryptedStr);
|
||||
if (decryptedObjStr) {
|
||||
decryptedStr = validateDecryptedValue(decryptedObjStr, repository);
|
||||
}
|
||||
return decryptedStr;
|
||||
}
|
||||
@@ -170,20 +145,10 @@ export async function decryptConfig(
|
||||
if (privateKey) {
|
||||
for (const [eKey, eVal] of Object.entries(val)) {
|
||||
logger.debug(`Trying to decrypt ${eKey} in ${path}`);
|
||||
let decryptedStr = await tryDecrypt(
|
||||
privateKey,
|
||||
eVal,
|
||||
repository,
|
||||
eKey,
|
||||
);
|
||||
let decryptedStr = await tryDecrypt(privateKey, eVal, repository);
|
||||
if (privateKeyOld && !is.nonEmptyString(decryptedStr)) {
|
||||
logger.debug(`Trying to decrypt with old private key`);
|
||||
decryptedStr = await tryDecrypt(
|
||||
privateKeyOld,
|
||||
eVal,
|
||||
repository,
|
||||
eKey,
|
||||
);
|
||||
decryptedStr = await tryDecrypt(privateKeyOld, eVal, repository);
|
||||
}
|
||||
if (!is.nonEmptyString(decryptedStr)) {
|
||||
const error = new Error('config-validation');
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import { CONFIG_VALIDATION } from '../../constants/error-messages';
|
||||
import { decryptConfig, setPrivateKeys } from '../decrypt';
|
||||
import { GlobalConfig } from '../global';
|
||||
import type { RenovateConfig } from '../types';
|
||||
import { Fixtures } from '~test/fixtures';
|
||||
|
||||
const privateKey = Fixtures.get('private.pem', '..');
|
||||
const repository = 'abc/def';
|
||||
|
||||
describe('config/decrypt/legacy', () => {
|
||||
describe('decryptConfig()', () => {
|
||||
let config: RenovateConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
config = {};
|
||||
GlobalConfig.reset();
|
||||
setPrivateKeys(undefined, undefined);
|
||||
});
|
||||
|
||||
it('handles invalid encrypted type', async () => {
|
||||
config.encrypted = 1;
|
||||
setPrivateKeys(privateKey, undefined);
|
||||
const res = await decryptConfig(config, repository);
|
||||
expect(res.encrypted).toBeUndefined();
|
||||
});
|
||||
|
||||
it('handles invalid encrypted value', async () => {
|
||||
config.encrypted = { a: 1 };
|
||||
setPrivateKeys(privateKey, 'invalid-key');
|
||||
await expect(decryptConfig(config, repository)).rejects.toThrow(
|
||||
CONFIG_VALIDATION,
|
||||
);
|
||||
});
|
||||
|
||||
it('replaces npm token placeholder in npmrc', async () => {
|
||||
setPrivateKeys('invalid-key', privateKey); // test old key failover
|
||||
config.npmrc =
|
||||
'//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n';
|
||||
config.encrypted = {
|
||||
npmToken:
|
||||
'FLA9YHIzpE7YetAg/P0X46npGRCMqn7hgyzwX5ZQ9wYgu9BRRbTiBVsUIFTyM5BuP1Q22slT2GkWvFvum7GU236Y6QiT7Nr8SLvtsJn2XUuq8H7REFKzdy3+wqyyWbCErYTFyY1dcPM7Ht+CaGDWdd8u/FsoX7AdMRs/X1jNUo6iSmlUiyGlYDKF+QMnCJom1VPVgZXWsGKdjI2MLny991QMaiv0VajmFIh4ENv4CtXOl/1twvIl/6XTXAaqpJJKDTPZEuydi+PHDZmal2RAOfrkH4m0UURa7SlfpUlIg+EaqbNGp85hCYXLwRcEET1OnYr3rH1oYkcYJ40any1tvQ==',
|
||||
};
|
||||
const res = await decryptConfig(config, repository);
|
||||
expect(res.encrypted).toBeUndefined();
|
||||
expect(res.npmToken).toBe('abcdef-ghijklm-nopqf-stuvwxyz');
|
||||
});
|
||||
|
||||
it('appends npm token in npmrc', async () => {
|
||||
setPrivateKeys(privateKey, undefined);
|
||||
config.npmrc = 'foo=bar\n';
|
||||
config.encrypted = {
|
||||
npmToken:
|
||||
'FLA9YHIzpE7YetAg/P0X46npGRCMqn7hgyzwX5ZQ9wYgu9BRRbTiBVsUIFTyM5BuP1Q22slT2GkWvFvum7GU236Y6QiT7Nr8SLvtsJn2XUuq8H7REFKzdy3+wqyyWbCErYTFyY1dcPM7Ht+CaGDWdd8u/FsoX7AdMRs/X1jNUo6iSmlUiyGlYDKF+QMnCJom1VPVgZXWsGKdjI2MLny991QMaiv0VajmFIh4ENv4CtXOl/1twvIl/6XTXAaqpJJKDTPZEuydi+PHDZmal2RAOfrkH4m0UURa7SlfpUlIg+EaqbNGp85hCYXLwRcEET1OnYr3rH1oYkcYJ40any1tvQ==',
|
||||
};
|
||||
const res = await decryptConfig(config, repository);
|
||||
expect(res.encrypted).toBeUndefined();
|
||||
expect(res.npmToken).toBe('abcdef-ghijklm-nopqf-stuvwxyz');
|
||||
});
|
||||
|
||||
it('decrypts nested', async () => {
|
||||
setPrivateKeys(privateKey, undefined);
|
||||
config.packageFiles = [
|
||||
{
|
||||
packageFile: 'package.json',
|
||||
devDependencies: {
|
||||
encrypted: {
|
||||
branchPrefix:
|
||||
'FLA9YHIzpE7YetAg/P0X46npGRCMqn7hgyzwX5ZQ9wYgu9BRRbTiBVsUIFTyM5BuP1Q22slT2GkWvFvum7GU236Y6QiT7Nr8SLvtsJn2XUuq8H7REFKzdy3+wqyyWbCErYTFyY1dcPM7Ht+CaGDWdd8u/FsoX7AdMRs/X1jNUo6iSmlUiyGlYDKF+QMnCJom1VPVgZXWsGKdjI2MLny991QMaiv0VajmFIh4ENv4CtXOl/1twvIl/6XTXAaqpJJKDTPZEuydi+PHDZmal2RAOfrkH4m0UURa7SlfpUlIg+EaqbNGp85hCYXLwRcEET1OnYr3rH1oYkcYJ40any1tvQ==',
|
||||
npmToken:
|
||||
'FLA9YHIzpE7YetAg/P0X46npGRCMqn7hgyzwX5ZQ9wYgu9BRRbTiBVsUIFTyM5BuP1Q22slT2GkWvFvum7GU236Y6QiT7Nr8SLvtsJn2XUuq8H7REFKzdy3+wqyyWbCErYTFyY1dcPM7Ht+CaGDWdd8u/FsoX7AdMRs/X1jNUo6iSmlUiyGlYDKF+QMnCJom1VPVgZXWsGKdjI2MLny991QMaiv0VajmFIh4ENv4CtXOl/1twvIl/6XTXAaqpJJKDTPZEuydi+PHDZmal2RAOfrkH4m0UURa7SlfpUlIg+EaqbNGp85hCYXLwRcEET1OnYr3rH1oYkcYJ40any1tvQ==',
|
||||
},
|
||||
},
|
||||
},
|
||||
'backend/package.json',
|
||||
];
|
||||
// TODO: fix types #22198
|
||||
const res = (await decryptConfig(config, repository)) as any;
|
||||
expect(res.encrypted).toBeUndefined();
|
||||
expect(res.packageFiles[0].devDependencies.encrypted).toBeUndefined();
|
||||
expect(res.packageFiles[0].devDependencies.branchPrefix).toBe(
|
||||
'abcdef-ghijklm-nopqf-stuvwxyz',
|
||||
);
|
||||
expect(res.packageFiles[0].devDependencies.npmToken).toBe(
|
||||
'abcdef-ghijklm-nopqf-stuvwxyz',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,39 +0,0 @@
|
||||
import crypto from 'node:crypto';
|
||||
import { logger } from '../../logger';
|
||||
|
||||
export function tryDecryptPublicKeyPKCS1(
|
||||
privateKey: string,
|
||||
encryptedStr: string,
|
||||
): string | null {
|
||||
let decryptedStr: string | null = null;
|
||||
try {
|
||||
decryptedStr = crypto
|
||||
.privateDecrypt(
|
||||
{
|
||||
key: privateKey,
|
||||
padding: crypto.constants.RSA_PKCS1_PADDING,
|
||||
},
|
||||
Buffer.from(encryptedStr, 'base64'),
|
||||
)
|
||||
.toString();
|
||||
} catch {
|
||||
logger.debug('Could not decrypt using PKCS1 padding');
|
||||
}
|
||||
return decryptedStr;
|
||||
}
|
||||
|
||||
export function tryDecryptPublicKeyDefault(
|
||||
privateKey: string,
|
||||
encryptedStr: string,
|
||||
): string | null {
|
||||
let decryptedStr: string | null = null;
|
||||
try {
|
||||
decryptedStr = crypto
|
||||
.privateDecrypt(privateKey, Buffer.from(encryptedStr, 'base64'))
|
||||
.toString();
|
||||
logger.debug('Decrypted config using default padding');
|
||||
} catch {
|
||||
logger.debug('Could not decrypt using default padding');
|
||||
}
|
||||
return decryptedStr;
|
||||
}
|
||||
Reference in New Issue
Block a user