snowflake-sdk
Advanced tools
Comparing version 1.2.2 to 1.3.0
@@ -29,2 +29,5 @@ /* | ||
'use strict'; | ||
const process = require('process'); | ||
const ocsp = require('ocsp'); | ||
@@ -316,3 +319,2 @@ const rfc2560 = require('asn1.js-rfc2560'); | ||
const sd = tbs.responses[0]; | ||
const currentTime = Date.now() | ||
if (sd.certStatus.type === 'revoked') | ||
@@ -322,3 +324,5 @@ { | ||
} | ||
if (!isValidityRange(currentTime, sd.thisUpdate, sd.nextUpdate)) | ||
const currentTime = Date.now(); | ||
const isInjectValidity = process.env.SF_OCSP_TEST_INJECT_VALIDITY_ERROR || ''; | ||
if (isInjectValidity.toLowerCase() === 'true' || !isValidityRange(currentTime, sd.thisUpdate, sd.nextUpdate)) | ||
{ | ||
@@ -329,2 +333,7 @@ return done(Errors.createOCSPError( | ||
} | ||
const isInjectUnknown = process.env.SF_OCSP_TEST_INJECT_UNKNOWN_STATUS || ''; | ||
if (isInjectUnknown.toLowerCase() === 'true' || sd.certStatus.type === 'unknown') | ||
{ | ||
return done(Errors.createOCSPError(ErrorCodes.ERR_OCSP_UNKNOWN)); | ||
} | ||
if (sd.certStatus.type === 'good') | ||
@@ -334,8 +343,4 @@ { | ||
} | ||
if (sd.certStatus.type === 'unknown') | ||
{ | ||
return done(Errors.createOCSPError(ErrorCodes.ERR_OCSP_UNKNOWN)); | ||
} | ||
return done(Errors.createOCSPError(ErrorCodes.ERR_OCSP_UNKNOWN_STATE)); | ||
}; | ||
exports.verifyOCSPResponse = verifyOCSPResponse; | ||
exports.verifyOCSPResponse = verifyOCSPResponse; |
@@ -27,8 +27,14 @@ /* | ||
const http = require('http'); | ||
const url = require('url'); | ||
const util = require('util'); | ||
const ocsp = require('ocsp'); | ||
const rfc2560 = require('asn1.js-rfc2560'); | ||
const Util = require('../util'); | ||
const SnowflakeUtil = require('../util'); | ||
const CertUtil = require('./cert_util'); | ||
const GlobalConfig = require('../global_config'); | ||
const Errors = require('../errors'); | ||
const ErrorCodes = Errors.codes; | ||
@@ -44,10 +50,82 @@ const Logger = require('../logger'); | ||
{ | ||
return (statusCode >= 500 && statusCode < 600) || statusCode === 404 || statusCode === 403 || statusCode === 408; | ||
return (statusCode >= 500 && statusCode < 600) || | ||
statusCode === 404 || statusCode === 403 || statusCode === 408; | ||
}; | ||
function getResponse(uri, req, cb) | ||
{ | ||
uri = url.parse(uri); | ||
const timeout = process.env.SF_OCSP_TEST_OCSP_RESPONDER_TIMEOUT || 10000; | ||
const options = util._extend({ | ||
timeout: Number(timeout), | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/ocsp-request', | ||
'Content-Length': req.length, | ||
} | ||
}, uri); | ||
function done(err, response) | ||
{ | ||
if (cb) | ||
{ | ||
cb(err, response); | ||
} | ||
cb = null; | ||
} | ||
function onResponse(response) | ||
{ | ||
if (response.statusCode < 200 || response.statusCode >= 400) | ||
{ | ||
return done( | ||
Errors.createOCSPError(ErrorCodes.ERR_OCSP_FAILED_OBTAIN_OCSP_RESPONSE, | ||
response.statusCode), response); | ||
} | ||
const chunks = []; | ||
response.on('readable', function () | ||
{ | ||
var chunk = response.read(); | ||
if (!chunk) | ||
{ | ||
return; | ||
} | ||
chunks.push(chunk); | ||
}); | ||
response.on('end', function () | ||
{ | ||
Logger.getInstance().debug("Finish OCSP responder: %s", uri.host); | ||
const ocsp = Buffer.concat(chunks); | ||
done(null, ocsp); | ||
}); | ||
} | ||
const httpRequest = http.request(options, onResponse); | ||
httpRequest.on('error', function (e) | ||
{ | ||
if (cb) | ||
{ | ||
cb(e); | ||
} | ||
cb = null; | ||
}); | ||
httpRequest.on('timeout', function () | ||
{ | ||
httpRequest.abort(); | ||
Logger.getInstance().debug("Timeout OCSP responder: %s", uri.host); | ||
if (cb) | ||
{ | ||
cb(Errors.createOCSPError(ErrorCodes.ERR_OCSP_RESPONDER_TIMEOUT)); | ||
} | ||
cb = null; | ||
}); | ||
httpRequest.end(req); | ||
} | ||
module.exports = function check(options, cb) | ||
{ | ||
var sync = true; | ||
var req; | ||
const maxNumRetries = GlobalConfig.getOcspMode() === GlobalConfig.ocspModes.FAIL_CLOSED ? 10 : 3; | ||
let sync = true; | ||
const maxNumRetries = GlobalConfig.getOcspMode() === GlobalConfig.ocspModes.FAIL_CLOSED ? 5 : 1; | ||
@@ -69,2 +147,3 @@ function done(err, data) | ||
let req; | ||
try | ||
@@ -79,26 +158,37 @@ { | ||
var ocspMethod = rfc2560['id-pkix-ocsp'].join('.'); | ||
const ocspMethod = rfc2560['id-pkix-ocsp'].join('.'); | ||
var numRetries = 0; | ||
var sleep = 1; | ||
let numRetries = 1; | ||
let sleep = 1; | ||
function ocspResponseVerify(err, raw) | ||
{ | ||
let retry = false; | ||
if (err) | ||
{ | ||
if (!err.hasOwnProperty('message')) | ||
if (err.hasOwnProperty('code') && err.code === ErrorCodes.ERR_OCSP_RESPONDER_TIMEOUT) | ||
{ | ||
return done(err); | ||
retry = true; | ||
} | ||
const errorMessage = err.message.split(' '); | ||
if (errorMessage.length === 0) | ||
else if (err.hasOwnProperty('message')) | ||
{ | ||
return done(err); | ||
const errorMessage = err.message.split(' '); | ||
if (errorMessage.length === 0) | ||
{ | ||
return done(err); | ||
} | ||
try | ||
{ | ||
const statusCode = parseInt(errorMessage[errorMessage.length - 1], 10); | ||
retry = isRetryableHttpError(statusCode); | ||
} | ||
catch (e) | ||
{ | ||
// ignore | ||
} | ||
} | ||
const statusCode = errorMessage[errorMessage.length - 1]; | ||
if (numRetries < maxNumRetries && isRetryableHttpError(statusCode)) | ||
if (numRetries < maxNumRetries && retry) | ||
{ | ||
// SNOW-27001: HTTP 404 should be retried. | ||
numRetries++; | ||
sleep = Util.nextSleepTime(1, 10, sleep); | ||
sleep = SnowflakeUtil.nextSleepTime(1, 10, sleep); | ||
setTimeout(ocspRequestSend, sleep * 1000); | ||
@@ -108,2 +198,3 @@ } | ||
{ | ||
Logger.getInstance().debug("Failed to all retries to OCSP responder."); | ||
return done(err); | ||
@@ -115,3 +206,3 @@ } | ||
const status = CertUtil.verifyOCSPResponse(req.issuer, raw); | ||
done(null, status); | ||
done(status.err, status); | ||
} | ||
@@ -127,4 +218,10 @@ } | ||
Logger.getInstance().trace('Contacting OCSP responder: %s', uri); | ||
ocsp.utils.getResponse(uri, req.data, ocspResponseVerify); | ||
const responderUrl = process.env.SF_OCSP_RESPONDER_URL; | ||
if (responderUrl) | ||
{ | ||
uri = responderUrl; | ||
} | ||
Logger.getInstance().trace( | ||
'Contact OCSP responder: %s, (%s/%s)', uri, numRetries, maxNumRetries); | ||
getResponse(uri, req.data, ocspResponseVerify); | ||
} | ||
@@ -131,0 +228,0 @@ |
@@ -6,2 +6,5 @@ /* | ||
const http = require('http'); | ||
const url = require('url'); | ||
const util = require('util'); | ||
const path = require('path'); | ||
@@ -17,3 +20,2 @@ const fs = require('fs'); | ||
const OCSP_URL = 'http://ocsp.snowflakecomputing.com/ocsp_response_cache.json'; | ||
const status = { | ||
@@ -25,2 +27,30 @@ NOT_START: 'not_start', | ||
// validate input | ||
const capacity = GlobalConfig.getOcspResponseCacheMaxSize(); | ||
const maxAge = GlobalConfig.getOcspResponseCacheMaxAge(); | ||
Errors.assertInternal(Util.number.isPositiveInteger(capacity)); | ||
Errors.assertInternal(Util.number.isPositiveInteger(maxAge)); | ||
const cacheDir = GlobalConfig.mkdirCacheDir(); | ||
const cacheFileName = path.join(cacheDir, "ocsp_response_cache.json"); | ||
// create a cache to store the responses | ||
const cache = new SimpleCache({maxSize: capacity}); | ||
function deleteCache() | ||
{ | ||
try | ||
{ | ||
cache.reset(); | ||
fs.unlinkSync(cacheFileName); | ||
} | ||
catch (e) | ||
{ | ||
Logger.getInstance() | ||
.debug("Failed to delete OCSP cache file: %s, err: %s", cacheFileName, e); | ||
} | ||
} | ||
exports.deleteCache = deleteCache; | ||
/** | ||
@@ -36,20 +66,12 @@ * Cache for storing OCSP responses. This covers both client and server caches. | ||
// validate input | ||
const capacity = GlobalConfig.getOcspResponseCacheMaxSize(); | ||
const maxAge = GlobalConfig.getOcspResponseCacheMaxAge(); | ||
Errors.assertInternal(Util.number.isPositiveInteger(capacity)); | ||
Errors.assertInternal(Util.number.isPositiveInteger(maxAge)); | ||
// create a cache to store the responses | ||
const cache = new SimpleCache({maxSize: capacity}); | ||
/** | ||
* Reads OCSP cache file. | ||
*/ | ||
const cacheDir = GlobalConfig.mkdirCacheDir(); | ||
const cacheFileName = path.join(cacheDir, "ocsp_response_cache.json"); | ||
exports.cacheFileName = cacheFileName; | ||
const currentTime = Date.now() / 1000; | ||
const currentTime = Date.now() / 1000; | ||
let OCSP_URL = process.env.SF_OCSP_RESPONSE_CACHE_SERVER_URL; | ||
if (!OCSP_URL) | ||
{ | ||
OCSP_URL = 'http://ocsp.snowflakecomputing.com/ocsp_response_cache.json'; | ||
} | ||
try | ||
@@ -92,3 +114,3 @@ { | ||
downloadStatus = status.FINISHED; | ||
} | ||
}; | ||
@@ -173,3 +195,8 @@ /** | ||
{ | ||
if (downloadStatus === status.FINISHED) | ||
{ | ||
return; | ||
} | ||
downloadStatus = status.FINISHED; | ||
Logger.getInstance().debug("Finish OCSP Cache Server: %s", OCSP_URL); | ||
if (err) | ||
@@ -200,3 +227,3 @@ { | ||
{ | ||
cb(err, false); | ||
cb(e, false); | ||
} | ||
@@ -229,21 +256,33 @@ } | ||
http.get(OCSP_URL, onResponse).on('error', checkOCSPResponse); | ||
return true; | ||
}; | ||
/** | ||
* Deletes the OCSP cache | ||
*/ | ||
this.deleteCache = function () | ||
{ | ||
try | ||
const uri = url.parse(OCSP_URL); | ||
const timeout = process.env.SF_OCSP_TEST_OCSP_RESPONSE_CACHE_SERVER_TIMEOUT || 5000; | ||
const options = util._extend({ | ||
timeout: Number(timeout), | ||
method: 'GET', | ||
}, uri); | ||
const httpRequest = http.request(options, onResponse); | ||
httpRequest.on('error', function (e) | ||
{ | ||
cache.reset(); | ||
fs.unlinkSync(cacheFileName); | ||
} | ||
catch (e) | ||
downloadStatus = status.FINISHED; | ||
if (cb) | ||
{ | ||
cb(e, false); | ||
} | ||
cb = null; | ||
}); | ||
httpRequest.on('timeout', function () | ||
{ | ||
Logger.getInstance() | ||
.debug("Failed to delete OCSP cache file: %s, err: %s", cacheFileName, e); | ||
} | ||
downloadStatus = status.FINISHED; | ||
httpRequest.abort(); | ||
Logger.getInstance().debug("Timeout OCSP responder: %s, %ss", OCSP_URL, options.timeout); | ||
if (cb) | ||
{ | ||
cb(Errors.createOCSPError(ErrorCodes.ERR_OCSP_CACHE_SERVER_TIMEOUT), false); | ||
} | ||
cb = null; | ||
}); | ||
httpRequest.end(); | ||
Logger.getInstance().trace('Contact OCSP Cache Server: %s', OCSP_URL); | ||
return true; | ||
}; | ||
@@ -294,2 +333,2 @@ | ||
module.exports = OcspResponseCache; | ||
exports.OcspResponseCache = OcspResponseCache; |
@@ -40,3 +40,3 @@ /* | ||
{ | ||
variables.OCSP_RESPONSE_CACHE = new OcspResponseCache(); | ||
variables.OCSP_RESPONSE_CACHE = new OcspResponseCache.OcspResponseCache(); | ||
} | ||
@@ -55,2 +55,3 @@ | ||
* @param {String} host | ||
* @param {Object} mock | ||
* | ||
@@ -81,5 +82,9 @@ * @returns {Object} | ||
{ | ||
if (!socket.authorized) | ||
{ | ||
return socket; | ||
} | ||
// use ocsp to make sure the entire certificate chain can be trusted | ||
var certChain = socket.ssl.getPeerCertificate(true); | ||
const vcc = mock ? mock.validateCertChain : validateCertChain | ||
const certChain = socket.ssl.getPeerCertificate(true); | ||
const vcc = mock ? mock.validateCertChain : validateCertChain; | ||
@@ -222,2 +227,6 @@ vcc(certChain, function (err) | ||
errors[index] = err; | ||
if (err) | ||
{ | ||
Logger.getInstance().debug(err); | ||
} | ||
@@ -287,11 +296,6 @@ // if we have an ocsp response, cache it | ||
{ | ||
setTimeout(getOcspResonseAndVerify, 10); | ||
setTimeout(getOcspResonseAndVerify, 10); // ms | ||
return; | ||
} | ||
if (err) | ||
{ | ||
cb(err); | ||
return; | ||
} | ||
let decoded; | ||
@@ -330,3 +334,3 @@ try | ||
{ | ||
cb(status, null) | ||
cb(status.err, null) | ||
}); | ||
@@ -333,0 +337,0 @@ } |
@@ -236,2 +236,9 @@ /* | ||
var jsTreatIntegerAsBigInt = options.jsTreatIntegerAsBigInt; | ||
if (Util.exists(jsTreatIntegerAsBigInt)) | ||
{ | ||
Errors.checkArgumentValid(Util.isBoolean(jsTreatIntegerAsBigInt), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_TREAT_INTEGER_AS_BIGINT); | ||
} | ||
// remember if we're in qa mode | ||
@@ -382,2 +389,12 @@ this._qaMode = qaMode; | ||
/** | ||
* Returns the client treat integer as setting | ||
* | ||
* @returns {String} | ||
*/ | ||
this.getJsTreatIntegerAsBigInt = function () | ||
{ | ||
return jsTreatIntegerAsBigInt; | ||
}; | ||
// save config options | ||
@@ -451,15 +468,15 @@ this.username = options.username; | ||
var PARAM_TIMEOUT = 'timeout'; | ||
var PARAM_RESULT_PREFETCH = 'resultPrefetch'; | ||
var PARAM_RESULT_STREAM_INTERRUPTS = 'resultStreamInterrupts'; | ||
var PARAM_RESULT_CHUNK_CACHE_SIZE = 'resultChunkCacheSize'; | ||
var PARAM_RESULT_PROCESSING_BATCH_SIZE = 'resultProcessingBatchSize'; | ||
var PARAM_RESULT_PROCESSING_BATCH_DURATION = 'resultProcessingBatchDuration'; | ||
var PARAM_ROW_STREAM_HIGH_WATER_MARK = 'rowStreamHighWaterMark'; | ||
var PARAM_RETRY_LARGE_RESULT_SET_MAX_NUM_RETRIES = 'largeResultSetRetryMaxNumRetries'; | ||
var PARAM_RETRY_LARGE_RESULT_SET_MAX_SLEEP_TIME = 'largeResultSetRetryMaxSleepTime'; | ||
var PARAM_RETRY_SF_MAX_LOGIN_RETRIES = 'sfRetryMaxLoginRetries'; | ||
var PARAM_RETRY_SF_MAX_NUM_RETRIES = 'sfRetryMaxNumRetries'; | ||
var PARAM_RETRY_SF_STARTING_SLEEP_TIME = 'sfRetryStartingSleepTime'; | ||
var PARAM_RETRY_SF_MAX_SLEEP_TIME = 'sfRetryMaxSleepTime'; | ||
const PARAM_TIMEOUT = 'timeout'; | ||
const PARAM_RESULT_PREFETCH = 'resultPrefetch'; | ||
const PARAM_RESULT_STREAM_INTERRUPTS = 'resultStreamInterrupts'; | ||
const PARAM_RESULT_CHUNK_CACHE_SIZE = 'resultChunkCacheSize'; | ||
const PARAM_RESULT_PROCESSING_BATCH_SIZE = 'resultProcessingBatchSize'; | ||
const PARAM_RESULT_PROCESSING_BATCH_DURATION = 'resultProcessingBatchDuration'; | ||
const PARAM_ROW_STREAM_HIGH_WATER_MARK = 'rowStreamHighWaterMark'; | ||
const PARAM_RETRY_LARGE_RESULT_SET_MAX_NUM_RETRIES = 'largeResultSetRetryMaxNumRetries'; | ||
const PARAM_RETRY_LARGE_RESULT_SET_MAX_SLEEP_TIME = 'largeResultSetRetryMaxSleepTime'; | ||
const PARAM_RETRY_SF_MAX_LOGIN_RETRIES = 'sfRetryMaxLoginRetries'; | ||
const PARAM_RETRY_SF_MAX_NUM_RETRIES = 'sfRetryMaxNumRetries'; | ||
const PARAM_RETRY_SF_STARTING_SLEEP_TIME = 'sfRetryStartingSleepTime'; | ||
const PARAM_RETRY_SF_MAX_SLEEP_TIME = 'sfRetryMaxSleepTime'; | ||
@@ -533,2 +550,3 @@ /** | ||
defaultValue: 5, | ||
external: true, | ||
validate: isNonNegativeInteger | ||
@@ -535,0 +553,0 @@ }, |
@@ -56,2 +56,7 @@ /* | ||
this.getJsTreatIntegerAsBigInt = function () | ||
{ | ||
return services.sf.getJsTreatIntegerAsBigInt(); | ||
}; | ||
/** | ||
@@ -58,0 +63,0 @@ * Returns the connection id. |
@@ -30,2 +30,3 @@ /* | ||
var type = options.type; | ||
var precision = options.precision; | ||
@@ -93,2 +94,12 @@ /** | ||
/** | ||
* Returns the precision associated with this column | ||
* | ||
* @returns {Number} | ||
*/ | ||
this.getPrecision = function () | ||
{ | ||
return precision; | ||
}; | ||
// add methods that make it easy to check if the column is of a specific type | ||
@@ -116,10 +127,18 @@ this.isString = createFnIsColumnOfType(type, SqlTypes.isString, SqlTypes); | ||
{ | ||
if (this.getScale() > 0 || this.getType() === SqlTypes.values.REAL) | ||
let integerAs = statementParameters['JS_TREAT_INTEGER_AS_BIGINT']; | ||
if (!integerAs) | ||
{ | ||
convert = convertRawNumber; | ||
} | ||
// This is a integer so represent it as a big int | ||
else | ||
{ | ||
convert = convertRawBigInt; | ||
if (this.getScale() > 0 || this.getType() === SqlTypes.values.REAL) | ||
{ | ||
convert = convertRawNumber; | ||
} | ||
// This is a integer so represent it as a big int | ||
else | ||
{ | ||
convert = convertRawBigInt; | ||
} | ||
} | ||
@@ -126,0 +145,0 @@ toValue = toValueFromNumber; |
@@ -48,2 +48,3 @@ /* | ||
exports[404024] = 'Invalid clientSessionKeepAliveHeartbeatFrequency. The specified value must be a number.'; | ||
exports[404025] = 'Invalid jsTreatIntegerAsBigInt. The specified value must be a boolean'; | ||
@@ -116,2 +117,5 @@ // 405001 | ||
exports[412011] = 'Invalid Signing Certificate validity.'; | ||
exports[412012] = 'Timeout OCSP responder.'; | ||
exports[412013] = 'Timeout OCSP Cache server.'; | ||
exports[412014] = 'Failed to obtain OCSP response: %s'; | ||
@@ -118,0 +122,0 @@ // 450001 |
@@ -53,2 +53,3 @@ /* | ||
codes.ERR_CONN_CREATE_INVALID_KEEP_ALIVE_HEARTBEAT_FREQ = 404024; | ||
codes.ERR_CONN_CREATE_INVALID_TREAT_INTEGER_AS_BIGINT = 404025; | ||
@@ -122,2 +123,5 @@ // 405001 | ||
codes.ERR_OCSP_INVALID_CERTIFICATE_VALIDITY = 412011; | ||
codes.ERR_OCSP_RESPONDER_TIMEOUT = 412012; | ||
codes.ERR_OCSP_CACHE_SERVER_TIMEOUT = 412013; | ||
codes.ERR_OCSP_FAILED_OBTAIN_OCSP_RESPONSE = 412014; | ||
@@ -124,0 +128,0 @@ // 450001 |
@@ -5,10 +5,11 @@ /* | ||
const Os = require('os'); | ||
const Path = require('path'); | ||
const os = require('os'); | ||
const path = require('path'); | ||
const mkdirp = require('mkdirp'); | ||
const Util = require('./util'); | ||
const Errors = require('./errors'); | ||
const Logger = require('./logger'); | ||
const Mkdirp = require('mkdirp'); | ||
var insecureConnect = false; | ||
let insecureConnect = false; | ||
@@ -110,18 +111,18 @@ /** | ||
{ | ||
cacherootDir = Os.homedir(); | ||
cacheRootDir = os.homedir(); | ||
} | ||
if (!Util.exists(cacheRootDir)) | ||
{ | ||
cacheRootDir = Os.tmpdir(); // fallback to TMP if user home doesn't exist. | ||
cacheRootDir = os.tmpdir(); // fallback to TMP if user home doesn't exist. | ||
} | ||
var cacheDir; | ||
const platform = Os.platform(); | ||
let cacheDir; | ||
const platform = os.platform(); | ||
if (platform === 'darwin') | ||
{ | ||
cacheDir = Path.join(cacheRootDir, "Library", "Caches", "Snowflake"); | ||
cacheDir = path.join(cacheRootDir, "Library", "Caches", "Snowflake"); | ||
} | ||
else if (platform === 'win32') | ||
{ | ||
cacheDir = Path.join(cacheRootDir, "AppData", "Local", "Snowflake", "Caches"); | ||
cacheDir = path.join(cacheRootDir, "AppData", "Local", "Snowflake", "Caches"); | ||
} | ||
@@ -131,7 +132,7 @@ else | ||
// linux | ||
cacheDir = Path.join(cacheRootDir, ".cache", "snowflake"); | ||
cacheDir = path.join(cacheRootDir, ".cache", "snowflake"); | ||
} | ||
try | ||
{ | ||
Mkdirp.sync(cacheDir); | ||
mkdirp.sync(cacheDir); | ||
} | ||
@@ -138,0 +139,0 @@ catch (e) |
@@ -6,3 +6,2 @@ /* | ||
const zlib = require('zlib'); | ||
const uuidv4 = require('uuid/v4'); | ||
const Util = require('../util'); | ||
@@ -12,2 +11,4 @@ const Errors = require('../errors'); | ||
const DEFAULT_REQUEST_TIMEOUT = 60000; | ||
/** | ||
@@ -80,3 +81,4 @@ * Creates a new HTTP client. | ||
timeout: options.timeout || | ||
this._connectionConfig.getTimeout(), | ||
this._connectionConfig.getTimeout() || | ||
DEFAULT_REQUEST_TIMEOUT, | ||
requestOCSP: true, | ||
@@ -95,3 +97,3 @@ rejectUnauthorized: true | ||
// add the agent and proxy options | ||
var agentAndProxyOptions = this.getAgentAndProxyOptions( | ||
const agentAndProxyOptions = this.getAgentAndProxyOptions( | ||
url, this._connectionConfig.getProxy(), | ||
@@ -132,4 +134,2 @@ mock); | ||
headers['Content-Encoding'] = 'gzip'; | ||
Logger.getInstance().trace('Successfully compressed request body'); | ||
} | ||
@@ -208,3 +208,5 @@ else | ||
{ | ||
ret = {}; | ||
ret = { | ||
'user-agent': Util.userAgent | ||
}; | ||
@@ -211,0 +213,0 @@ // shallow copy the headers object and convert some headers like 'Accept' |
@@ -20,2 +20,7 @@ /* | ||
this.setLogger = function (logger) | ||
{ | ||
winstonLogger = logger; | ||
}; | ||
/** | ||
@@ -55,2 +60,12 @@ * Logs a message at a given level. | ||
this.getLevelTag = function () | ||
{ | ||
return common.getLevelTag(); | ||
}; | ||
this.getLevelTagsMap = function () | ||
{ | ||
return common.getLevelTagsMap(); | ||
}; | ||
/** | ||
@@ -57,0 +72,0 @@ * Configures this logger. |
@@ -60,2 +60,3 @@ /* | ||
names.CLIENT_SESSION_KEEP_ALIVE_HEARTBEAT_FREQUENCY = 'CLIENT_SESSION_KEEP_ALIVE_HEARTBEAT_FREQUENCY'; | ||
names.JS_TREAT_INTEGER_AS_BIGINT = 'JS_TREAT_INTEGER_AS_BIGINT'; | ||
@@ -89,2 +90,8 @@ var parameters = | ||
}), | ||
new Parameter( | ||
{ | ||
name: names.JS_TREAT_INTEGER_AS_BIGINT, | ||
value: false, | ||
desc: 'When true, enables the driver converts integer columns into BigInt' | ||
}), | ||
]; | ||
@@ -91,0 +98,0 @@ |
@@ -48,11 +48,34 @@ /* | ||
const uuidv4 = require('uuid/v4'); | ||
var EventEmitter = require('events').EventEmitter; | ||
var Util = require('../util'); | ||
var Errors = require('../errors'); | ||
var ErrorCodes = Errors.codes; | ||
var Url = require('url'); | ||
var QueryString = require('querystring'); | ||
var Parameters = require('../parameters'); | ||
var GSErrors = require('../constants/gs_errors') | ||
const EventEmitter = require('events').EventEmitter; | ||
const Util = require('../util'); | ||
const Errors = require('../errors'); | ||
const ErrorCodes = Errors.codes; | ||
const Url = require('url'); | ||
const QueryString = require('querystring'); | ||
const Parameters = require('../parameters'); | ||
const GSErrors = require('../constants/gs_errors') | ||
const Logger = require('../logger'); | ||
function isRetryableNetworkError(err) | ||
{ | ||
// anything other than REVOKED error can be retryable. | ||
return !err.hasOwnProperty('cause') || | ||
err.cause === undefined || | ||
!err.cause.hasOwnProperty('code') || | ||
( | ||
err.cause.code !== ErrorCodes.ERR_OCSP_REVOKED && | ||
err.cause.code !== 'DEPTH_ZERO_SELF_SIGNED_CERT' && | ||
err.cause.code !== 'CERT_HAS_EXPIRED' && | ||
err.cause.code !== 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' && | ||
err.cause.code !== 'SELF_SIGNED_CERT_IN_CHAIN' | ||
); | ||
} | ||
function isRetryableHttpError(err) | ||
{ | ||
return err.hasOwnProperty('response') && | ||
Util.isRetryableHttpError(err.response, false); | ||
} | ||
/** | ||
@@ -466,2 +489,7 @@ * Creates a new SnowflakeService instance. | ||
this.getJsTreatIntegerAsBigInt = function () | ||
{ | ||
return Parameters.getValue(Parameters.names.JS_TREAT_INTEGER_AS_BIGINT); | ||
}; | ||
// if we don't have any tokens, start out as pristine | ||
@@ -521,7 +549,15 @@ if (tokenInfo.isEmpty()) | ||
} | ||
else if (!response) | ||
{ | ||
// empty response | ||
err = Errors.createUnexpectedContentError( | ||
ErrorCodes.ERR_SF_RESPONSE_NOT_JSON, '(EMPTY)'); | ||
} | ||
// if we didn't get a 200, the request failed | ||
else if (!response || response.statusCode !== 200) | ||
else if (response.hasOwnProperty('statusCode') && | ||
response.statusCode !== 200) | ||
{ | ||
err = Errors.createRequestFailedError( | ||
ErrorCodes.ERR_SF_RESPONSE_FAILURE, response); | ||
Logger.getInstance().debug("HTTP Error: %s", response.statusCode); | ||
} | ||
@@ -573,3 +609,3 @@ else | ||
if (requestOptions.retry > 0) | ||
if (requestOptions.retry > 2) | ||
{ | ||
@@ -580,3 +616,3 @@ const includeParam = requestOptions.url.includes('?'); | ||
('clientStartTime=' + requestOptions.startTime | ||
+ "&" + 'retryCount=' + requestOptions.retry); | ||
+ "&" + 'retryCount=' + (requestOptions.retry - 1)); | ||
} | ||
@@ -997,2 +1033,8 @@ return httpClient.request(realRequestOptions); | ||
if (Util.exists(this.connectionConfig.getJsTreatIntegerAsBigInt())) | ||
{ | ||
sessionParameters.SESSION_PARAMETERS.JS_TREAT_INTEGER_AS_BIGINT = | ||
this.connectionConfig.getJsTreatIntegerAsBigInt(); | ||
} | ||
Util.apply(json.data, clientInfo); | ||
@@ -1002,3 +1044,3 @@ Util.apply(json.data, sessionParameters); | ||
const connectionConfig = this.connectionConfig; | ||
let numRetries = 0; | ||
let numRetries = 1; | ||
const startTime = connectionConfig.accessUrl.startsWith('https://') ? | ||
@@ -1034,4 +1076,4 @@ Date.now() : 'FIXEDTIMESTAMP'; | ||
{ | ||
if (numRetries < maxLoginRetries && | ||
err.response && Util.isRetryableHttpError(err.response, false)) | ||
if (numRetries < maxLoginRetries && ( | ||
isRetryableNetworkError(err) || isRetryableHttpError(err))) | ||
{ | ||
@@ -1045,2 +1087,3 @@ numRetries++; | ||
{ | ||
Logger.getInstance().debug("Failed to all retries to SF."); | ||
// we're now disconnected | ||
@@ -1071,5 +1114,8 @@ parent.snowflakeService.transitionToDisconnected(); | ||
{ | ||
const targetUrl = buildLoginUrl(connectionConfig); | ||
Logger.getInstance().debug( | ||
"Contacting SF: %s, (%s/%s)", targetUrl, numRetries, maxLoginRetries); | ||
const request = parent.createUnauthenticatedRequest({ | ||
method: 'POST', | ||
url: buildLoginUrl(connectionConfig), | ||
url: targetUrl, | ||
json: json, | ||
@@ -1076,0 +1122,0 @@ scope: this, |
@@ -26,5 +26,5 @@ /* | ||
{ | ||
version: require('./../package.json').version, | ||
version: Util.driverVersion, | ||
environment: clientEnvironment | ||
} | ||
}); |
@@ -429,2 +429,19 @@ /* | ||
return heartbeatFrequency; | ||
}; | ||
}; | ||
// driver version | ||
const driverVersion = require('./../package.json').version; | ||
exports.driverVersion = driverVersion; | ||
// nodeJS version | ||
let nodeJSVersion = process.version; | ||
if (nodeJSVersion && nodeJSVersion.startsWith('v')) | ||
{ | ||
nodeJSVersion = nodeJSVersion.substring(1); | ||
} | ||
// user-agent HTTP header | ||
const userAgent = 'JavaScript' + '/' + driverVersion | ||
+ '/' + 'NodeJS' + '/' + nodeJSVersion | ||
+ '/' + process.platform + '-' + process.arch; | ||
exports.userAgent = userAgent; |
{ | ||
"name": "snowflake-sdk", | ||
"version": "1.2.2", | ||
"version": "1.3.0", | ||
"description": "Node.js driver for Snowflake", | ||
@@ -5,0 +5,0 @@ "dependencies": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 6 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
317668
10352
9
6