Skip to content

Commit 1e46f63

Browse files
Merge branch 'master' into SNOW-1883649-wiremock
2 parents 8c6151c + 9cae043 commit 1e46f63

29 files changed

+683
-357
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,22 @@ npm pack
114114

115115
Note it is not required to build a package to run tests blow.
116116

117+
118+
Verifying the package signature
119+
----------------------------------------------------------------------
120+
121+
Starting from version v1.13.0 the driver package is signed with a signature allowing to verify its authenticity and integrity.
122+
Steps to verify the signature:
123+
1. Install `cosign`
124+
2. Download the driver package file (`tgz`) from npmjs.org, e.g.: https://registry.npmjs.org/snowflake-sdk/-/snowflake-sdk-1.13.0.tgz
125+
3. Download the signatures file (.sig and .pub) from the release, e.g.: https://github.com/snowflakedb/snowflake-connector-nodejs/releases/download/v1.13.0
126+
4. Verify the signature:
127+
```shell
128+
cosign verify-blob snowflake-sdk-1.13.0.tgz --key snowflake-connector-nodejs-v1.13.0.pub --signature resources.snowflake-sdk-1.13.0.tgz.sig
129+
130+
Verified OK
131+
```
132+
117133
Development
118134
======================================================================
119135

ci/container/test_authentication.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ export SNOWFLAKE_AUTH_TEST_PRIVATE_KEY_PATH=./.github/workflows/rsa_keys/rsa_key
99
export SNOWFLAKE_AUTH_TEST_ENCRYPTED_PRIVATE_KEY_PATH=./.github/workflows/rsa_keys/rsa_encrypted_key.p8
1010
export SNOWFLAKE_AUTH_TEST_INVALID_PRIVATE_KEY_PATH=./.github/workflows/rsa_keys/rsa_key_invalid.p8
1111

12-
npm run test:authentication
12+
npm run test:authentication

ci/image/proxy/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#This file is intended for testing purposes only and should not be used in production or released.
12
# Based on the Fedora image
23
FROM fedora
34

ci/image/proxy/Dockerfile.auth

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#This file is intended for testing purposes only and should not be used in production or released.
12
# Based on the Fedora image
23
FROM fedora
34

lib/authentication/secure_storage/json_credential_manager.js

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,9 @@ const Logger = require('../../logger');
77
const fs = require('node:fs/promises');
88
const os = require('os');
99
const Util = require('../../util');
10+
const { validateOnlyUserReadWritePermissionAndOwner } = require('../../file_util');
1011

1112
function JsonCredentialManager(credentialCacheDir) {
12-
13-
async function validatePermission(filePath) {
14-
try {
15-
await fs.access(filePath, fs.constants.F_OK);
16-
} catch (err) {
17-
return;
18-
}
19-
20-
const mode = (await fs.stat(filePath)).mode;
21-
const permission = mode & 0o600;
22-
23-
//This should be 600 permission, which means the file permission has not been changed by others.
24-
if (permission.toString(8) === '600') {
25-
Logger.getInstance().debug('Validated that the user has read and write permission');
26-
} else {
27-
throw new Error('You do not have read permission or the file has been changed on the user side. Please remove the token file and re run the driver.');
28-
}
29-
}
3013

3114
this.getTokenDir = async function () {
3215
let tokenDir = credentialCacheDir;
@@ -38,11 +21,11 @@ function JsonCredentialManager(credentialCacheDir) {
3821

3922
if (!Util.exists(tokenDir)) {
4023
throw new Error(`Temporary credential cache directory is invalid, and the driver is unable to use the default location(home).
41-
Please assign the environment variable value SF_TEMPORARY_CREDENTIAL_CACHE_DIR to enable the default credential manager.`);
24+
Please set 'credentialCacheDir' connection configuration option to enable the default credential manager.`);
4225
}
4326

4427
const tokenCacheFile = path.join(tokenDir, 'temporary_credential.json');
45-
await validatePermission(tokenCacheFile);
28+
await validateOnlyUserReadWritePermissionAndOwner(tokenCacheFile);
4629
return tokenCacheFile;
4730
};
4831

@@ -51,7 +34,7 @@ function JsonCredentialManager(credentialCacheDir) {
5134
const cred = await fs.readFile(await this.getTokenDir(), 'utf8');
5235
return JSON.parse(cred);
5336
} catch (err) {
54-
Logger.getInstance().warn('Failed to read token data from the file. Please check the permission or the file format of the token.');
37+
Logger.getInstance().warn('Failed to read token data from the file. Err: %s', err.message);
5538
return null;
5639
}
5740
};

lib/configuration/client_configuration.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
const os = require('os');
66
const path = require('path');
77
const fs = require('fs');
8-
const { isString, exists, isFileNotWritableByGroupOrOthers, getDriverDirectory } = require('../util');
8+
const { isString, exists, getDriverDirectory } = require('../util');
99
const Logger = require('../logger');
10+
const { isFileNotWritableByGroupOrOthers } = require('../file_util');
1011
const clientConfigFileName = 'sf_client_config.json';
1112

1213
const Levels = Object.freeze({

lib/configuration/connection_configuration.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
const toml = require('toml');
66
const os = require('os');
77
const fs = require('fs');
8-
const { validateOnlyUserReadWritePermission, generateChecksum } = require('../file_transfer_agent/file_util');
8+
const { validateOnlyUserReadWritePermissionAndOwner, generateChecksum } = require('../file_util');
99
const path = require('path');
1010
const Logger = require('../logger');
1111
const AuthenticationTypes = require('../authentication/authentication_types');
@@ -29,7 +29,7 @@ function readTokenFromFile(fixedConfiguration) {
2929
const tokenFilePath = fixedConfiguration.token_file_path ? fixedConfiguration.token_file_path : '/snowflake/session/token';
3030
const resolvedPath = fs.realpathSync(tokenFilePath);
3131
Logger.getInstance().trace('Token file path is : %s', tokenFilePath);
32-
validateOnlyUserReadWritePermission(resolvedPath);
32+
validateOnlyUserReadWritePermissionAndOwner(resolvedPath);
3333
fixedConfiguration.token = fs.readFileSync(resolvedPath, 'utf-8').trim();
3434
if (!fixedConfiguration.token) {
3535
Logger.getInstance().error('The token does not exist or has empty value.');
@@ -47,7 +47,7 @@ function loadConnectionConfiguration() {
4747
const resolvedPath = fs.realpathSync(filePath);
4848
Logger.getInstance().trace('Connection configuration file found under the path %s. Validating file access.', resolvedPath);
4949

50-
validateOnlyUserReadWritePermission(resolvedPath);
50+
validateOnlyUserReadWritePermissionAndOwner(resolvedPath);
5151
const str = fs.readFileSync(resolvedPath, { encoding: 'utf8' });
5252
const configurationChecksum = generateChecksum(str);
5353
Logger.getInstance().info('Connection configuration file is read from path: %s. Checksum: %s', resolvedPath, configurationChecksum);

lib/connection/connection_config.js

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const levenshtein = require('fastest-levenshtein');
1717
const RowMode = require('./../constants/row_mode');
1818
const DataTypes = require('./result/data_types');
1919
const Logger = require('../logger');
20-
const LoggingUtil = require('../logger/logging_util');
2120
const WAIT_FOR_BROWSER_ACTION_TIMEOUT = 120000;
2221
const DEFAULT_PARAMS =
2322
[
@@ -531,7 +530,6 @@ function ConnectionConfig(options, validateCredentials, qaMode, clientInfo) {
531530

532531
passcode = options.passcode;
533532
}
534-
535533

536534
if (validateDefaultParameters) {
537535
for (const [key] of Object.entries(options)) {
@@ -865,21 +863,7 @@ function ConnectionConfig(options, validateCredentials, qaMode, clientInfo) {
865863
this.describeIdentityAttributes = function () {
866864
return `host: ${this.host}, account: ${this.account}, accessUrl: ${this.accessUrl}, `
867865
+ `user: ${this.username}, role: ${this.getRole()}, database: ${this.getDatabase()}, `
868-
+ `schema: ${this.getSchema()}, warehouse: ${this.getWarehouse()}, ` + this.describeProxy();
869-
};
870-
871-
/**
872-
* @returns {string}
873-
*/
874-
this.describeProxy = function () {
875-
const proxy = this.getProxy();
876-
if (Util.exists(proxy)) {
877-
return `proxyHost: ${proxy.host}, proxyPort: ${proxy.port}, proxyUser: ${proxy.user}, `
878-
+ `proxyPassword is ${LoggingUtil.describePresence(proxy.password)}, `
879-
+ `proxyProtocol: ${proxy.protocol}, noProxy: ${proxy.noProxy}`;
880-
} else {
881-
return 'proxy was not configured';
882-
}
866+
+ `schema: ${this.getSchema()}, warehouse: ${this.getWarehouse()}, ` + ProxyUtil.describeProxy(this.getProxy());
883867
};
884868

885869
// save config options

lib/file_transfer_agent/azure_util.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
*/
44

55
const EncryptionMetadata = require('./encrypt_util').EncryptionMetadata;
6-
const FileHeader = require('./file_util').FileHeader;
6+
const FileHeader = require('../file_util').FileHeader;
77
const expandTilde = require('expand-tilde');
8-
const resultStatus = require('./file_util').resultStatus;
8+
const resultStatus = require('../file_util').resultStatus;
99
const ProxyUtil = require('../proxy_util');
1010
const { isBypassProxy } = require('../http/node');
1111
const Logger = require('../logger');
@@ -50,9 +50,8 @@ function AzureUtil(connectionConfig, azure, filestream) {
5050
if (proxy && !isBypassProxy(proxy, connectionString)) {
5151
Logger.getInstance().debug(`The destination host is: ${ProxyUtil.getHostFromURL(connectionString)} and the proxy host is: ${proxy.host}`);
5252
Logger.getInstance().trace(`Initializing the proxy information for the Azure Client: ${ProxyUtil.describeProxy(proxy)}`);
53-
53+
5454
proxy = ProxyUtil.getAzureProxy(proxy);
55-
Logger.getInstance().trace(connectionConfig.describe);
5655
}
5756
ProxyUtil.hideEnvironmentProxy();
5857
const blobServiceClient = new AZURE.BlobServiceClient(
@@ -218,7 +217,7 @@ function AzureUtil(connectionConfig, azure, filestream) {
218217
blobContentEncoding: 'UTF-8',
219218
blobContentType: 'application/octet-stream'
220219
}
221-
});
220+
});
222221
} catch (err) {
223222
if (err['statusCode'] === 403 && detectAzureTokenExpireError(err)) {
224223
meta['lastError'] = err;

lib/file_transfer_agent/file_transfer_agent.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ const SnowflakeRemoteStorageUtil = require('./remote_storage_util').RemoteStorag
1616
const LocalUtil = require('./local_util').LocalUtil;
1717
const SnowflakeFileEncryptionMaterial = require('./remote_storage_util').SnowflakeFileEncryptionMaterial;
1818
const SnowflakeS3Util = require('./s3_util');
19-
const { FileUtil, getMatchingFilePaths } = require('./file_util');
20-
const resultStatus = require('./file_util').resultStatus;
19+
const { FileUtil, getMatchingFilePaths } = require('../file_util');
20+
const resultStatus = require('../file_util').resultStatus;
2121

2222
const SnowflakeFileUtil = new FileUtil();
2323
const SnowflakeLocalUtil = new LocalUtil();

0 commit comments

Comments
 (0)