Skip to content

Commit 89e3c5a

Browse files
HCK-12311: add private key file validation to key pair connection (#208)
* HCK-12311: add private key file validation to key pair connection * HCK-12311: fixed remarks
1 parent d4312cf commit 89e3c5a

File tree

7 files changed

+52
-3
lines changed

7 files changed

+52
-3
lines changed

common/errorCodes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ module.exports = {
22
ERR_MISSING_PASSPHRASE: 'ERR_MISSING_PASSPHRASE',
33
ERR_OSSL_BAD_DECRYPT: 'ERR_OSSL_BAD_DECRYPT',
44
ERR_INVALID_USERNAME: '390144',
5+
ERR_INVALID_KEY_FILE: 'ERR_INVALID_KEY_FILE',
56
};

common/errorMessages.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ module.exports = {
77
'Native Okta auth doesn\'t support MFA. Please, use the "Identity Provider SSO (via external browser)" auth instead',
88
KEY_PAIR_PASSPHRASE_ERROR: 'Please check that the passphrase is provided and matches the key.',
99
KEY_PAIR_USERNAME_ERROR: 'Incorrect username was specified.',
10+
KEY_PAIR_INVALID_FILE_ERROR:
11+
"The selected file is not a valid key. Please choose a valid key file, check it's passphrase and try again.",
1012
};

common/getKeyPairConnectionErrorMessageByCode.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const ERROR_CODE_TO_MESSAGE = {
55
[errorCodes.ERR_MISSING_PASSPHRASE]: errorMessages.KEY_PAIR_PASSPHRASE_ERROR,
66
[errorCodes.ERR_OSSL_BAD_DECRYPT]: errorMessages.KEY_PAIR_PASSPHRASE_ERROR,
77
[errorCodes.ERR_INVALID_USERNAME]: errorMessages.KEY_PAIR_USERNAME_ERROR,
8+
[errorCodes.ERR_INVALID_KEY_FILE]: errorMessages.KEY_PAIR_INVALID_FILE_ERROR,
89
};
910

1011
const getKeyPairConnectionErrorMessageByCode = code => ERROR_CODE_TO_MESSAGE[code];

reverse_engineering/connection_settings_modal/connectionSettingsModalConfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@
171171
"inputKeyword": "privateKeyPath",
172172
"inputType": "file",
173173
"inputPlaceholder": "Private Key",
174-
"extensions": ["p8"],
174+
"extensions": ["p8", "pem", "cert", "crt"],
175175
"dependency": {
176176
"key": "authType",
177177
"value": ["keyPair"]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class ConnectionError extends Error {
2+
code;
3+
4+
constructor(message, code) {
5+
super(message);
6+
this.code = code;
7+
}
8+
}
9+
10+
module.exports = {
11+
ConnectionError,
12+
};

reverse_engineering/helpers/connections/keyPairConnection.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1+
const fs = require('fs');
2+
const crypto = require('crypto');
13
const { connectWithTimeout } = require('./connection.js');
4+
const errorCodes = require('../../../common/errorCodes.js');
5+
const errorMessages = require('../../../common/errorMessages.js');
6+
const { ConnectionError } = require('./connectionError.js');
7+
8+
const authByKeyPair = ({ account, role, timeout, username, privateKeyPath, privateKeyPass, logger }) => {
9+
if (
10+
!isValidPrivateKey({
11+
privateKeyPath,
12+
privateKeyPass,
13+
logger,
14+
})
15+
) {
16+
throw new ConnectionError(errorMessages.KEY_PAIR_INVALID_FILE_ERROR, errorCodes.ERR_INVALID_KEY_FILE);
17+
}
218

3-
const authByKeyPair = ({ account, role, timeout, username, privateKeyPath, privateKeyPass }) => {
419
return connectWithTimeout({
520
account,
621
role,
@@ -12,6 +27,24 @@ const authByKeyPair = ({ account, role, timeout, username, privateKeyPath, priva
1227
});
1328
};
1429

30+
const isValidPrivateKey = ({ privateKeyPath, privateKeyPass, logger }) => {
31+
const textFilePrivateKeyFormat = 'pem';
32+
const fileContent = fs.readFileSync(privateKeyPath, 'utf8');
33+
34+
try {
35+
crypto.createPrivateKey({
36+
key: fileContent,
37+
format: textFilePrivateKeyFormat,
38+
passphrase: privateKeyPass,
39+
});
40+
41+
return true;
42+
} catch (error) {
43+
logger.log('error', { error }, 'Connection error');
44+
return false;
45+
}
46+
};
47+
1548
module.exports = {
1649
authByKeyPair,
1750
};

reverse_engineering/helpers/snowflakeHelper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ const connect = async (
129129
logger,
130130
});
131131
} else if (authType === 'keyPair') {
132-
authPromise = authByKeyPair({ account, role, timeout, username, privateKeyPath, privateKeyPass });
132+
authPromise = authByKeyPair({ account, role, timeout, username, privateKeyPath, privateKeyPass, logger });
133133
} else {
134134
authPromise = authByCredentials({ account, username, password, role, warehouse, timeout });
135135
}

0 commit comments

Comments
 (0)