snowflake-sdk
Advanced tools
Comparing version 1.9.2 to 1.9.3
@@ -51,23 +51,18 @@ /* | ||
*/ | ||
exports.buildCertId = function (cert) | ||
{ | ||
var issuer = cert.issuerCertificate; | ||
exports.buildCertId = function (cert) { | ||
let issuer = cert.issuerCertificate; | ||
cert = cert.raw; | ||
try | ||
{ | ||
try { | ||
cert = rfc5280.Certificate.decode(cert, 'der'); | ||
if (issuer) | ||
{ | ||
if (issuer) { | ||
issuer = issuer.raw; | ||
issuer = rfc5280.Certificate.decode(issuer, 'der'); | ||
} | ||
} | ||
catch (e) | ||
{ | ||
} catch (e) { | ||
return null; // if we encountered an error during decoding, return null | ||
} | ||
var tbsCert = cert.tbsCertificate; | ||
var tbsIssuer = issuer.tbsCertificate; | ||
const tbsCert = cert.tbsCertificate; | ||
const tbsIssuer = issuer.tbsCertificate; | ||
@@ -85,7 +80,6 @@ const certID = { | ||
const certIDDer = rfc2560.CertID.encode(certID, 'der'); | ||
return encodeKey(certIDDer.toString("BASE64")); | ||
return encodeKey(certIDDer.toString('BASE64')); | ||
}; | ||
function sha1(data) | ||
{ | ||
function sha1(data) { | ||
return crypto.createHash('sha1').update(data).digest(); | ||
@@ -103,5 +97,4 @@ } | ||
*/ | ||
exports.decode = function (cert) | ||
{ | ||
var issuer = cert.issuerCertificate; | ||
exports.decode = function (cert) { | ||
let issuer = cert.issuerCertificate; | ||
cert = cert.raw; | ||
@@ -111,4 +104,3 @@ | ||
cert = rfc5280.Certificate.decode(cert, 'der'); | ||
if (issuer) | ||
{ | ||
if (issuer) { | ||
issuer = issuer.raw; | ||
@@ -129,9 +121,8 @@ issuer = rfc5280.Certificate.decode(issuer, 'der'); | ||
*/ | ||
const encodeKey = function (base64Key) | ||
{ | ||
const encodeKey = function (base64Key) { | ||
const buff = Buffer.from(base64Key, 'base64'); | ||
const certID = rfc2560.CertID.decode(buff, 'der'); | ||
return certID.issuerNameHash.toString("BASE64") | ||
+ '#' + certID.issuerKeyHash.toString("BASE64") | ||
return certID.issuerNameHash.toString('BASE64') | ||
+ '#' + certID.issuerKeyHash.toString('BASE64') | ||
+ '#' + certID.serialNumber.toString(10); | ||
@@ -145,6 +136,5 @@ }; | ||
*/ | ||
const decodeKey = function (cacheKey) | ||
{ | ||
const decodeKey = function (cacheKey) { | ||
// serialNumber.eq(certID.serialNumber) | ||
const keys = cacheKey.split("#"); | ||
const keys = cacheKey.split('#'); | ||
const issuerNameHash = Buffer.from(keys[0], 'base64'); | ||
@@ -165,3 +155,3 @@ const issuerKeyHash = Buffer.from(keys[1], 'base64'); | ||
const certIDDer = rfc2560.CertID.encode(certID, 'der'); | ||
return certIDDer.toString("BASE64"); | ||
return certIDDer.toString('BASE64'); | ||
}; | ||
@@ -176,4 +166,3 @@ exports.decodeKey = decodeKey; | ||
*/ | ||
const calculateTolerableVadility = function (thisUpdate, nextUpdate) | ||
{ | ||
const calculateTolerableVadility = function (thisUpdate, nextUpdate) { | ||
const currentRange = (nextUpdate - thisUpdate) * | ||
@@ -192,4 +181,3 @@ TOLERABLE_VALIDITY_RANGE_RATIO; | ||
*/ | ||
const isValidityRange = function (currentTime, thisUpdate, nextUpdate) | ||
{ | ||
const isValidityRange = function (currentTime, thisUpdate, nextUpdate) { | ||
const tolerableValidity = calculateTolerableVadility(thisUpdate, nextUpdate); | ||
@@ -206,4 +194,3 @@ return thisUpdate - MAX_CLOCK_SKEW_IN_MILLISECONDS <= currentTime && | ||
*/ | ||
const toUTCString = function (epochInMilliSeconds) | ||
{ | ||
const toUTCString = function (epochInMilliSeconds) { | ||
return new Date(epochInMilliSeconds); | ||
@@ -218,29 +205,25 @@ }; | ||
*/ | ||
const findResponder = function (issuer, certs, raws) | ||
{ | ||
var issuerKey = issuer.tbsCertificate.subjectPublicKeyInfo; | ||
const findResponder = function (issuer, certs, raws) { | ||
let issuerKey = issuer.tbsCertificate.subjectPublicKeyInfo; | ||
issuerKey = ocsp.utils.toPEM( | ||
rfc5280.SubjectPublicKeyInfo.encode(issuerKey, 'der'), 'PUBLIC KEY'); | ||
if (certs.length > 0) | ||
{ | ||
if (certs.length > 0) { | ||
const currentTime = Date.now(); | ||
const cert = certs[0]; | ||
const certValidity = cert.tbsCertificate.validity; | ||
if (certValidity.notAfter.value < currentTime || certValidity.notBefore.value > currentTime) | ||
{ | ||
if (certValidity.notAfter.value < currentTime || certValidity.notBefore.value > currentTime) { | ||
return { | ||
err: Errors.createOCSPError( | ||
ErrorCodes.ERR_OCSP_INVALID_CERTIFICATE_VALIDITY, | ||
"Valid from:", toUTCString(certValidity.notBefore.value), | ||
", Valid to:", toUTCString(certValidity.notAfter.value)), | ||
'Valid from:', toUTCString(certValidity.notBefore.value), | ||
', Valid to:', toUTCString(certValidity.notAfter.value)), | ||
responderKey: null | ||
} | ||
}; | ||
} | ||
const signAlg = ocsp.utils.sign[cert.signatureAlgorithm.algorithm.join('.')]; | ||
if (!signAlg) | ||
{ | ||
if (!signAlg) { | ||
return { | ||
err: Errors.createOCSPError(ErrorCodes.ERR_OCSP_NO_SIGNATURE_ALGORITHM), | ||
responderKey: null | ||
} | ||
}; | ||
} | ||
@@ -251,8 +234,7 @@ | ||
verify.update(raws[0]); | ||
if (!verify.verify(issuerKey, cert.signature.data)) | ||
{ | ||
if (!verify.verify(issuerKey, cert.signature.data)) { | ||
return { | ||
err: Errors.createOCSPError(ErrorCodes.ERR_OCSP_INVALID_SIGNATURE), | ||
responderKey: null | ||
} | ||
}; | ||
} | ||
@@ -263,6 +245,6 @@ | ||
rfc5280.SubjectPublicKeyInfo.encode(certKey, 'der'), 'PUBLIC KEY'); | ||
return {err: null, responderKey: certKey}; | ||
return { err: null, responderKey: certKey }; | ||
} | ||
return {err: null, responderKey: issuerKey}; | ||
return { err: null, responderKey: issuerKey }; | ||
}; | ||
@@ -277,6 +259,4 @@ | ||
*/ | ||
const verifyOCSPResponse = function (issuer, rawRes) | ||
{ | ||
function done(err) | ||
{ | ||
const verifyOCSPResponse = function (issuer, rawRes) { | ||
function done(err) { | ||
return { | ||
@@ -289,28 +269,21 @@ err: err, | ||
let res; | ||
try | ||
{ | ||
try { | ||
res = ocsp.utils.parseResponse(rawRes); | ||
} | ||
catch (e) | ||
{ | ||
} catch (e) { | ||
return done(e); | ||
} | ||
const value = res.value; | ||
if (issuer) | ||
{ | ||
if (issuer) { | ||
// verify signature only if issuer is given | ||
const certs = res.certs; | ||
const rawTBS = rawRes.slice(res.start, res.end); | ||
const raws = res.certsTbs.map(function (tbs) | ||
{ | ||
const raws = res.certsTbs.map(function (tbs) { | ||
return rawRes.slice(tbs.start, tbs.end); | ||
}); | ||
const signAlg = ocsp.utils.sign[value.signatureAlgorithm.algorithm.join('.')]; | ||
if (!signAlg) | ||
{ | ||
if (!signAlg) { | ||
return done(Errors.createOCSPError(ErrorCodes.ERR_OCSP_NO_SIGNATURE_ALGORITHM)); | ||
} | ||
const responderStatus = findResponder(issuer, certs, raws); | ||
if (responderStatus.err) | ||
{ | ||
if (responderStatus.err) { | ||
return done(responderStatus.err); | ||
@@ -322,4 +295,3 @@ } | ||
v.update(rawTBS); | ||
if (!v.verify(responderKey, signature)) | ||
{ | ||
if (!v.verify(responderKey, signature)) { | ||
return done(Errors.createOCSPError(ErrorCodes.ERR_OCSP_INVALID_SIGNATURE)); | ||
@@ -329,9 +301,7 @@ } | ||
const tbs = value.tbsResponseData; | ||
if (tbs.responses.length < 1) | ||
{ | ||
if (tbs.responses.length < 1) { | ||
return done(Errors.createOCSPError(ErrorCodes.ERR_OCSP_NO_RESPONSE)); | ||
} | ||
const sd = tbs.responses[0]; | ||
if (sd.certStatus.type === 'revoked') | ||
{ | ||
if (sd.certStatus.type === 'revoked') { | ||
return done(Errors.createOCSPError(ErrorCodes.ERR_OCSP_REVOKED)); | ||
@@ -341,15 +311,12 @@ } | ||
const isInjectValidity = process.env.SF_OCSP_TEST_INJECT_VALIDITY_ERROR || ''; | ||
if (isInjectValidity.toLowerCase() === 'true' || !isValidityRange(currentTime, sd.thisUpdate, sd.nextUpdate)) | ||
{ | ||
if (isInjectValidity.toLowerCase() === 'true' || !isValidityRange(currentTime, sd.thisUpdate, sd.nextUpdate)) { | ||
return done(Errors.createOCSPError( | ||
ErrorCodes.ERR_OCSP_INVALID_VALIDITY, | ||
"Valid from:", toUTCString(sd.thisUpdate), ", Valid to:", toUTCString(sd.nextUpdate))); | ||
'Valid from:', toUTCString(sd.thisUpdate), ', Valid to:', toUTCString(sd.nextUpdate))); | ||
} | ||
const isInjectUnknown = process.env.SF_OCSP_TEST_INJECT_UNKNOWN_STATUS || ''; | ||
if (isInjectUnknown.toLowerCase() === 'true' || sd.certStatus.type === 'unknown') | ||
{ | ||
if (isInjectUnknown.toLowerCase() === 'true' || sd.certStatus.type === 'unknown') { | ||
return done(Errors.createOCSPError(ErrorCodes.ERR_OCSP_UNKNOWN)); | ||
} | ||
if (sd.certStatus.type === 'good') | ||
{ | ||
if (sd.certStatus.type === 'good') { | ||
return done(null); | ||
@@ -356,0 +323,0 @@ } |
@@ -47,4 +47,3 @@ /* | ||
*/ | ||
const isRetryableHttpError = function (statusCode) | ||
{ | ||
const isRetryableHttpError = function (statusCode) { | ||
return (statusCode >= 500 && statusCode < 600) || | ||
@@ -54,4 +53,3 @@ statusCode === 404 || statusCode === 403 || statusCode === 408; | ||
function getResponse(uri, req, cb) | ||
{ | ||
function getResponse(uri, req, cb) { | ||
uri = url.parse(uri); | ||
@@ -69,6 +67,4 @@ | ||
function done(err, response) | ||
{ | ||
if (cb) | ||
{ | ||
function done(err, response) { | ||
if (cb) { | ||
cb(err, response); | ||
@@ -79,6 +75,4 @@ } | ||
function onResponse(response) | ||
{ | ||
if (response.statusCode < 200 || response.statusCode >= 400) | ||
{ | ||
function onResponse(response) { | ||
if (response.statusCode < 200 || response.statusCode >= 400) { | ||
return done( | ||
@@ -90,7 +84,5 @@ Errors.createOCSPError(ErrorCodes.ERR_OCSP_FAILED_OBTAIN_OCSP_RESPONSE, | ||
const chunks = []; | ||
response.on('readable', function () | ||
{ | ||
var chunk = response.read(); | ||
if (!chunk) | ||
{ | ||
response.on('readable', function () { | ||
const chunk = response.read(); | ||
if (!chunk) { | ||
return; | ||
@@ -100,5 +92,4 @@ } | ||
}); | ||
response.on('end', function () | ||
{ | ||
Logger.getInstance().debug("Finish OCSP responder: %s", uri.host); | ||
response.on('end', function () { | ||
Logger.getInstance().debug('Finish OCSP responder: %s', uri.host); | ||
const ocsp = Buffer.concat(chunks); | ||
@@ -110,6 +101,4 @@ done(null, ocsp); | ||
const httpRequest = http.request(options, onResponse); | ||
httpRequest.on('error', function (e) | ||
{ | ||
if (cb) | ||
{ | ||
httpRequest.on('error', function (e) { | ||
if (cb) { | ||
cb(e); | ||
@@ -119,8 +108,6 @@ } | ||
}); | ||
httpRequest.on('timeout', function () | ||
{ | ||
httpRequest.on('timeout', function () { | ||
httpRequest.abort(); | ||
Logger.getInstance().debug("Timeout OCSP responder: %s", uri.host); | ||
if (cb) | ||
{ | ||
Logger.getInstance().debug('Timeout OCSP responder: %s', uri.host); | ||
if (cb) { | ||
cb(Errors.createOCSPError(ErrorCodes.ERR_OCSP_RESPONDER_TIMEOUT)); | ||
@@ -133,14 +120,10 @@ } | ||
module.exports = function check(options, cb, mock) | ||
{ | ||
module.exports = function check(options, cb, mock) { | ||
let sync = true; | ||
const maxNumRetries = GlobalConfig.getOcspMode() === GlobalConfig.ocspModes.FAIL_CLOSED ? 5 : 1; | ||
function done(err, data) | ||
{ | ||
if (sync) | ||
{ | ||
function done(err, data) { | ||
if (sync) { | ||
sync = false; | ||
process.nextTick(function () | ||
{ | ||
process.nextTick(function () { | ||
cb(err, data); | ||
@@ -155,8 +138,5 @@ }); | ||
let req; | ||
try | ||
{ | ||
try { | ||
req = mock ? mock.req : ocsp.request.generate(options.cert, options.issuer); | ||
} | ||
catch (e) | ||
{ | ||
} catch (e) { | ||
return done(e); | ||
@@ -170,42 +150,28 @@ } | ||
function ocspResponseVerify(err, raw) | ||
{ | ||
function ocspResponseVerify(err, raw) { | ||
let retry = false; | ||
if (err) | ||
{ | ||
if (err.hasOwnProperty('code') && err.code === ErrorCodes.ERR_OCSP_RESPONDER_TIMEOUT) | ||
{ | ||
if (err) { | ||
if (Object.prototype.hasOwnProperty.call(err, 'code') && err.code === ErrorCodes.ERR_OCSP_RESPONDER_TIMEOUT) { | ||
retry = true; | ||
} | ||
else if (err.hasOwnProperty('message')) | ||
{ | ||
} else if (Object.prototype.hasOwnProperty.call(err, 'message')) { | ||
const errorMessage = err.message.split(' '); | ||
if (errorMessage.length === 0) | ||
{ | ||
if (errorMessage.length === 0) { | ||
return done(err); | ||
} | ||
try | ||
{ | ||
try { | ||
const statusCode = parseInt(errorMessage[errorMessage.length - 1], 10); | ||
retry = isRetryableHttpError(statusCode); | ||
} | ||
catch (e) | ||
{ | ||
} catch (e) { | ||
// ignore | ||
} | ||
} | ||
if (numRetries < maxNumRetries && retry) | ||
{ | ||
if (numRetries < maxNumRetries && retry) { | ||
numRetries++; | ||
sleep = SnowflakeUtil.nextSleepTime(1, 10, sleep); | ||
setTimeout(ocspRequestSend, sleep * 1000); | ||
} | ||
else | ||
{ | ||
Logger.getInstance().debug("Failed to all retries to OCSP responder."); | ||
} else { | ||
Logger.getInstance().debug('Failed to all retries to OCSP responder.'); | ||
return done(err); | ||
} | ||
} | ||
else | ||
{ | ||
} else { | ||
const status = CertUtil.verifyOCSPResponse(req.issuer, raw); | ||
@@ -216,17 +182,13 @@ done(status.err, status); | ||
function setOcspResponderUrl(uri) | ||
{ | ||
var parsedUrl = require('url').parse(process.env.SF_OCSP_RESPONSE_CACHE_SERVER_URL); | ||
function setOcspResponderUrl(uri) { | ||
let parsedUrl = require('url').parse(process.env.SF_OCSP_RESPONSE_CACHE_SERVER_URL); | ||
var targetUrl; | ||
if (parsedUrl.port) | ||
{ | ||
let targetUrl; | ||
if (parsedUrl.port) { | ||
targetUrl = `${parsedUrl.protocol}//${parsedUrl.hostname}:${parsedUrl.port}/retry`; | ||
} | ||
else | ||
{ | ||
} else { | ||
targetUrl = `${parsedUrl.protocol}//${parsedUrl.hostname}/retry`; | ||
} | ||
var b64data = req.data.toString('base64'); | ||
const b64data = req.data.toString('base64'); | ||
parsedUrl = require('url').parse(uri); | ||
@@ -237,6 +199,4 @@ | ||
function ocspRequestCallback(err, uri) | ||
{ | ||
if (err) | ||
{ | ||
function ocspRequestCallback(err, uri) { | ||
if (err) { | ||
return done(err); | ||
@@ -246,4 +206,3 @@ } | ||
if (process.env.SF_OCSP_RESPONSE_CACHE_SERVER_URL && | ||
process.env.SF_OCSP_RESPONSE_CACHE_SERVER_URL.includes('ocsp_response_cache.json')) | ||
{ | ||
process.env.SF_OCSP_RESPONSE_CACHE_SERVER_URL.includes('ocsp_response_cache.json')) { | ||
setOcspResponderUrl(uri); | ||
@@ -253,4 +212,3 @@ } | ||
const responderUrl = process.env.SF_OCSP_RESPONDER_URL; | ||
if (responderUrl) | ||
{ | ||
if (responderUrl) { | ||
uri = responderUrl; | ||
@@ -261,4 +219,3 @@ } | ||
if (!mock) | ||
{ | ||
if (!mock) { | ||
getResponse(uri, req.data, ocspResponseVerify); | ||
@@ -268,12 +225,8 @@ } | ||
function ocspRequestSend() | ||
{ | ||
if (!mock) | ||
{ | ||
function ocspRequestSend() { | ||
if (!mock) { | ||
ocsp.utils.getAuthorityInfo(req.cert, ocspMethod, ocspRequestCallback); | ||
} else { | ||
ocspRequestCallback(null, mock.uri); | ||
} | ||
else | ||
{ | ||
ocspRequestCallback(null, mock.uri) | ||
} | ||
} | ||
@@ -280,0 +233,0 @@ |
@@ -5,5 +5,5 @@ /* | ||
var Util = require('../util'); | ||
var HttpsAgent = require('https').Agent; | ||
var SocketUtil = require('./socket_util'); | ||
const Util = require('../util'); | ||
const HttpsAgent = require('https').Agent; | ||
const SocketUtil = require('./socket_util'); | ||
@@ -18,7 +18,5 @@ /** | ||
*/ | ||
function HttpsOcspAgent(options) | ||
{ | ||
var agent = HttpsAgent.apply(this, arguments); | ||
agent.createConnection = function (port, host, options) | ||
{ | ||
function HttpsOcspAgent(options) { | ||
const agent = HttpsAgent.apply(this, arguments); | ||
agent.createConnection = function (port, host, options) { | ||
// make sure the 'options' variables references the argument that actually | ||
@@ -28,17 +26,11 @@ // contains the options | ||
// written this way | ||
if (port !== null && typeof port === 'object') | ||
{ | ||
if (port !== null && typeof port === 'object') { | ||
options = port; | ||
} | ||
else if (host !== null && typeof host === 'object') | ||
{ | ||
} else if (host !== null && typeof host === 'object') { | ||
options = host; | ||
} | ||
else if (options === null || typeof options !== 'object') | ||
{ | ||
} else if (options === null || typeof options !== 'object') { | ||
options = {}; | ||
} | ||
if (typeof host !== 'string') | ||
{ | ||
if (typeof host !== 'string') { | ||
host = options.host; | ||
@@ -48,3 +40,3 @@ } | ||
// call super | ||
var socket = HttpsAgent.prototype.createConnection.apply(this, arguments); | ||
const socket = HttpsAgent.prototype.createConnection.apply(this, arguments); | ||
@@ -51,0 +43,0 @@ // secure the socket and return it |
@@ -28,3 +28,3 @@ /* | ||
// ocsp cache max age in second | ||
var maxAgeSec = GlobalConfig.getOcspResponseCacheMaxAge(); | ||
let maxAgeSec = GlobalConfig.getOcspResponseCacheMaxAge(); | ||
@@ -35,22 +35,18 @@ Errors.assertInternal(Util.number.isPositiveInteger(sizeLimit)); | ||
const cacheDir = GlobalConfig.mkdirCacheDir(); | ||
const cacheFileName = path.join(cacheDir, "ocsp_response_cache.json"); | ||
const cacheFileName = path.join(cacheDir, 'ocsp_response_cache.json'); | ||
// create a cache to store the responses, dynamically changes in size | ||
var cache; | ||
let cache; | ||
// JSON object with previous cache's responses | ||
var prevCacheObj; | ||
let prevCacheObj; | ||
// Cache updated time, in seconds, initialized as current time. | ||
// Will be updated when load from local cache file or refresh by downloading | ||
var cacheUpdateTimeSec = Date.now() / 1000; | ||
let cacheUpdateTimeSec = Date.now() / 1000; | ||
function deleteCache() | ||
{ | ||
try | ||
{ | ||
function deleteCache() { | ||
try { | ||
cache.reset(); | ||
fs.unlinkSync(cacheFileName); | ||
} | ||
catch (e) | ||
{ | ||
} catch (e) { | ||
Logger.getInstance() | ||
.debug("Failed to delete OCSP cache file: %s, err: %s", cacheFileName, e); | ||
.debug('Failed to delete OCSP cache file: %s, err: %s', cacheFileName, e); | ||
} | ||
@@ -66,4 +62,3 @@ } | ||
*/ | ||
function OcspResponseCache() | ||
{ | ||
function OcspResponseCache() { | ||
let downloadStatus = status.NOT_START; | ||
@@ -82,9 +77,7 @@ let cacheUpdated = false; | ||
let OCSP_URL = process.env.SF_OCSP_RESPONSE_CACHE_SERVER_URL; | ||
if (!OCSP_URL) | ||
{ | ||
if (!OCSP_URL) { | ||
OCSP_URL = 'http://ocsp.snowflakecomputing.com/ocsp_response_cache.json'; | ||
} | ||
try | ||
{ | ||
Logger.getInstance().debug("Reading OCSP cache file. %s", cacheFileName); | ||
try { | ||
Logger.getInstance().debug('Reading OCSP cache file. %s', cacheFileName); | ||
const contents = fs.readFileSync(cacheFileName, 'utf-8'); | ||
@@ -95,7 +88,5 @@ prevCacheObj = JSON.parse(contents); | ||
cacheInitialized = true; | ||
} catch (e) { | ||
Logger.getInstance().debug('Failed to read OCSP cache file: %s, err: %s', cacheFileName, e); | ||
} | ||
catch (e) | ||
{ | ||
Logger.getInstance().debug("Failed to read OCSP cache file: %s, err: %s", cacheFileName, e); | ||
} | ||
@@ -107,6 +98,5 @@ /** | ||
*/ | ||
this.setAgent = function setAgent(agent) | ||
{ | ||
proxyAgent = agent; | ||
} | ||
this.setAgent = function setAgent(agent) { | ||
proxyAgent = agent; | ||
}; | ||
@@ -119,7 +109,6 @@ /** | ||
*/ | ||
this.initCache = function initCache(cert, response) | ||
{ | ||
this.initCache = function initCache(cert, response) { | ||
cache = new SimpleCache({ maxSize: 1 }); | ||
this.set(cert, response); | ||
} | ||
}; | ||
@@ -130,4 +119,3 @@ /** | ||
*/ | ||
this.isInitialized = function () | ||
{ | ||
this.isInitialized = function () { | ||
return cacheInitialized; | ||
@@ -140,4 +128,3 @@ }; | ||
*/ | ||
this.isDownloadFinished = function () | ||
{ | ||
this.isDownloadFinished = function () { | ||
return downloadStatus === status.FINISHED; | ||
@@ -149,4 +136,3 @@ }; | ||
*/ | ||
this.forceDownloadToFinish = function () | ||
{ | ||
this.forceDownloadToFinish = function () { | ||
downloadStatus = status.FINISHED; | ||
@@ -159,6 +145,4 @@ }; | ||
*/ | ||
this.IsCacheExpired = function () | ||
{ | ||
if (!cacheInitialized) | ||
{ | ||
this.IsCacheExpired = function () { | ||
if (!cacheInitialized) { | ||
return false; | ||
@@ -173,6 +157,5 @@ } | ||
if ((currentTimeSec - cacheUpdateTimeSec) > maxAgeSec) | ||
{ | ||
if ((currentTimeSec - cacheUpdateTimeSec) > maxAgeSec) { | ||
Logger.getInstance().debug( | ||
"OCSP local cache validity is out of range. currentTime: %s, timestamp: %s, maxAge: %s", | ||
'OCSP local cache validity is out of range. currentTime: %s, timestamp: %s, maxAge: %s', | ||
currentTimeSec, cacheUpdateTimeSec, maxAgeSec); | ||
@@ -183,3 +166,3 @@ return true; | ||
return false; | ||
} | ||
}; | ||
@@ -189,7 +172,5 @@ /** | ||
*/ | ||
this.resetCacheStatus = function () | ||
{ | ||
this.resetCacheStatus = function () { | ||
downloadStatus = status.NOT_START; | ||
if (cacheUpdated) | ||
{ | ||
if (cacheUpdated) { | ||
Logger.getInstance().debug(cacheFileName); | ||
@@ -200,18 +181,14 @@ | ||
const cacheOutput = {}; | ||
cache.forEach(function (v, k) | ||
{ | ||
cache.forEach(function (v, k) { | ||
const certIdInBase64 = CertUtil.decodeKey(k); | ||
const ocspResponseInBase64 = v.toString("BASE64"); | ||
const ocspResponseInBase64 = v.toString('BASE64'); | ||
cacheOutput[certIdInBase64] = [currentTimeSec, ocspResponseInBase64]; | ||
}); | ||
const writeContent = JSON.stringify(cacheOutput); | ||
Logger.getInstance().debug("Writing OCSP cache file. %s", cacheFileName); | ||
try | ||
{ | ||
Logger.getInstance().debug('Writing OCSP cache file. %s', cacheFileName); | ||
try { | ||
fs.writeFileSync(cacheFileName, writeContent, 'utf-8'); | ||
} catch (e) { | ||
Logger.getInstance().debug('Failed to update OCSP cache file: %s, err: %s', cacheFileName, e); | ||
} | ||
catch (e) | ||
{ | ||
Logger.getInstance().debug("Failed to update OCSP cache file: %s, err: %s", cacheFileName, e); | ||
} | ||
cacheUpdated = false; | ||
@@ -227,14 +204,10 @@ } | ||
*/ | ||
this.set = function set(cert, response) | ||
{ | ||
try | ||
{ | ||
this.set = function set(cert, response) { | ||
try { | ||
const certId = CertUtil.buildCertId(cert); | ||
cache.set(certId, response); | ||
cacheUpdated = true; | ||
} catch (e) { | ||
Logger.getInstance().debug('Failed to add certificate to OCSP cache file. err: %s', e); | ||
} | ||
catch (e) | ||
{ | ||
Logger.getInstance().debug("Failed to add certificate to OCSP cache file. err: %s", e); | ||
} | ||
}; | ||
@@ -248,12 +221,8 @@ | ||
*/ | ||
this.get = function get(cert) | ||
{ | ||
try | ||
{ | ||
this.get = function get(cert) { | ||
try { | ||
const certId = CertUtil.buildCertId(cert); | ||
return cache.get(certId); | ||
} | ||
catch (e) | ||
{ | ||
Logger.getInstance().debug("Failed to get certificate from OCSP cache. err: %s", e); | ||
} catch (e) { | ||
Logger.getInstance().debug('Failed to get certificate from OCSP cache. err: %s', e); | ||
return null; | ||
@@ -267,11 +236,7 @@ } | ||
*/ | ||
this.downloadCache = function (cb) | ||
{ | ||
if (downloadStatus === status.STARTED) | ||
{ | ||
this.downloadCache = function (cb) { | ||
if (downloadStatus === status.STARTED) { | ||
// reschedule calling cb | ||
return false; | ||
} | ||
else if (downloadStatus === status.FINISHED) | ||
{ | ||
} else if (downloadStatus === status.FINISHED) { | ||
// call cb immediately | ||
@@ -283,25 +248,19 @@ cb(null, false); | ||
function checkOCSPResponse(err, cacheContent) | ||
{ | ||
if (downloadStatus === status.FINISHED) | ||
{ | ||
function checkOCSPResponse(err, cacheContent) { | ||
if (downloadStatus === status.FINISHED) { | ||
return; | ||
} | ||
downloadStatus = status.FINISHED; | ||
Logger.getInstance().debug("Finish OCSP Cache Server: %s", OCSP_URL); | ||
if (err) | ||
{ | ||
Logger.getInstance().debug('Finish OCSP Cache Server: %s', OCSP_URL); | ||
if (err) { | ||
Logger.getInstance() | ||
.debug("Failed to download OCSP cache file. %s. Ignored", err); | ||
.debug('Failed to download OCSP cache file. %s. Ignored', err); | ||
return cb(err, false); | ||
} | ||
try | ||
{ | ||
let jsonParsed = JSON.parse(cacheContent); | ||
try { | ||
const jsonParsed = JSON.parse(cacheContent); | ||
updateCache(jsonParsed); | ||
cacheUpdated = true; | ||
return cb(null, false); | ||
} | ||
catch (e) | ||
{ | ||
} catch (e) { | ||
cb(e, false); | ||
@@ -311,6 +270,4 @@ } | ||
function onResponse(response) | ||
{ | ||
if (response.statusCode < 200 || response.statusCode >= 400) | ||
{ | ||
function onResponse(response) { | ||
if (response.statusCode < 200 || response.statusCode >= 400) { | ||
return checkOCSPResponse( | ||
@@ -324,4 +281,3 @@ new Error('Failed to obtain OCSP response: ' + | ||
// A chunk of data has been received. | ||
response.on('data', function (chunk) | ||
{ | ||
response.on('data', function (chunk) { | ||
rawData += chunk; | ||
@@ -331,5 +287,4 @@ }); | ||
// The whole response has been received. Print out the result. | ||
response.on('end', function () | ||
{ | ||
checkOCSPResponse(null, rawData) | ||
response.on('end', function () { | ||
checkOCSPResponse(null, rawData); | ||
}); | ||
@@ -346,7 +301,5 @@ } | ||
const httpRequest = http.request(options, onResponse); | ||
httpRequest.on('error', function (e) | ||
{ | ||
httpRequest.on('error', function (e) { | ||
downloadStatus = status.FINISHED; | ||
if (cb) | ||
{ | ||
if (cb) { | ||
cb(e, false); | ||
@@ -356,9 +309,7 @@ } | ||
}); | ||
httpRequest.on('timeout', function () | ||
{ | ||
httpRequest.on('timeout', function () { | ||
downloadStatus = status.FINISHED; | ||
httpRequest.abort(); | ||
Logger.getInstance().debug("Timeout OCSP responder: %s, %ss", OCSP_URL, options.timeout); | ||
if (cb) | ||
{ | ||
Logger.getInstance().debug('Timeout OCSP responder: %s, %ss', OCSP_URL, options.timeout); | ||
if (cb) { | ||
cb(Errors.createOCSPError(ErrorCodes.ERR_OCSP_CACHE_SERVER_TIMEOUT), false); | ||
@@ -380,23 +331,18 @@ } | ||
*/ | ||
function validateCacheEntry(certIdBase64, ocspResponseBase64) | ||
{ | ||
var err; | ||
if (ocspResponseBase64.length !== 2) | ||
{ | ||
function validateCacheEntry(certIdBase64, ocspResponseBase64) { | ||
let err; | ||
if (ocspResponseBase64.length !== 2) { | ||
Logger.getInstance() | ||
.debug("OCSP cache value doesn't consist of two elements. Ignored."); | ||
.debug('OCSP cache value doesn\'t consist of two elements. Ignored.'); | ||
err = Errors.createOCSPError(ErrorCodes.ERR_OCSP_NOT_TWO_ELEMENTS); | ||
} | ||
if ((currentTimeSec - ocspResponseBase64[0]) > maxAgeSec) | ||
{ | ||
if ((currentTimeSec - ocspResponseBase64[0]) > maxAgeSec) { | ||
Logger.getInstance().debug( | ||
"OCSP cache validity is out of range. currentTime: %s, timestamp: %s, maxAge: %s", | ||
'OCSP cache validity is out of range. currentTime: %s, timestamp: %s, maxAge: %s', | ||
currentTimeSec, ocspResponseBase64[0], maxAgeSec); | ||
err = Errors.createOCSPError(ErrorCodes.ERR_OCSP_CACHE_EXPIRED); | ||
} | ||
try | ||
{ | ||
try { | ||
const k = CertUtil.encodeKey(certIdBase64); | ||
if (err) | ||
{ | ||
if (err) { | ||
return { err: err, key: k }; | ||
@@ -406,31 +352,24 @@ } | ||
const status = CertUtil.verifyOCSPResponse(null, rawOCSPResponse); | ||
if (!status.err) | ||
{ | ||
return {err: null, key: k, value: rawOCSPResponse}; | ||
if (!status.err) { | ||
return { err: null, key: k, value: rawOCSPResponse }; | ||
} | ||
return {err: status.err}; | ||
} | ||
catch (e) | ||
{ | ||
return { err: status.err }; | ||
} catch (e) { | ||
Logger.getInstance() | ||
.debug("Failed to parse OCSP response. %s. Ignored.", e); | ||
return {err: Errors.createOCSPError(ErrorCodes.ERR_OCSP_FAILED_PARSE_RESPONSE)}; | ||
.debug('Failed to parse OCSP response. %s. Ignored.', e); | ||
return { err: Errors.createOCSPError(ErrorCodes.ERR_OCSP_FAILED_PARSE_RESPONSE) }; | ||
} | ||
} | ||
function updateCache(jsonObject) | ||
{ | ||
function updateCache(jsonObject) { | ||
// Get the size of cache retrieved from the cache server | ||
var responseCacheSize = Object.keys(jsonObject).length; | ||
const responseCacheSize = Object.keys(jsonObject).length; | ||
// Check if there are previous entries to append | ||
if (prevCacheObj) | ||
{ | ||
if (prevCacheObj) { | ||
// Count overlap between previous cache and response cache | ||
// And delete entry if expired | ||
var cacheOverlapCount = 0; | ||
for (let entry in jsonObject) | ||
{ | ||
if (entryExists(prevCacheObj, entry)) | ||
{ | ||
let cacheOverlapCount = 0; | ||
for (const entry in jsonObject) { | ||
if (entryExists(prevCacheObj, entry)) { | ||
cacheOverlapCount++; | ||
@@ -442,6 +381,6 @@ updateOrDeleteEntry(prevCacheObj, entry); | ||
// Count entries from previous cache | ||
var prevCacheSize = Object.keys(prevCacheObj).length; | ||
const prevCacheSize = Object.keys(prevCacheObj).length; | ||
// New cache size = previous cache size + response cache size - overlap between the two caches | ||
var newCacheSize = prevCacheSize + responseCacheSize - cacheOverlapCount; | ||
const newCacheSize = prevCacheSize + responseCacheSize - cacheOverlapCount; | ||
@@ -456,5 +395,3 @@ // Create cache using new cache size if it doesn't exceed the upper limit | ||
setCacheEntries(prevCacheObj); | ||
} | ||
else | ||
{ | ||
} else { | ||
// Create cache using response cache size if it doesn't exceed the upper limit | ||
@@ -471,8 +408,5 @@ cache = new SimpleCache({ maxSize: responseCacheSize < sizeLimit ? responseCacheSize : sizeLimit }); | ||
function setCacheEntries(jsonObject) | ||
{ | ||
for (let entry in jsonObject) | ||
{ | ||
if (jsonObject.hasOwnProperty(entry)) | ||
{ | ||
function setCacheEntries(jsonObject) { | ||
for (const entry in jsonObject) { | ||
if (Object.prototype.hasOwnProperty.call(jsonObject, entry)) { | ||
updateOrDeleteEntry(jsonObject, entry); | ||
@@ -483,17 +417,12 @@ } | ||
function updateOrDeleteEntry(jsonObject, entry) | ||
{ | ||
function updateOrDeleteEntry(jsonObject, entry) { | ||
const status = validateCacheEntry(entry, jsonObject[entry]); | ||
if (!status.err) | ||
{ | ||
if (!status.err) { | ||
// Add new entry or update existing one | ||
cache.set(status.key, status.value); | ||
// change cache update time if needed | ||
if (jsonObject[entry][0] < cacheUpdateTimeSec) | ||
{ | ||
if (jsonObject[entry][0] < cacheUpdateTimeSec) { | ||
cacheUpdateTimeSec = jsonObject[entry][0]; | ||
} | ||
} | ||
else if (status.err.code === ErrorCodes.ERR_OCSP_CACHE_EXPIRED) | ||
{ | ||
} else if (status.err.code === ErrorCodes.ERR_OCSP_CACHE_EXPIRED) { | ||
// If timestamp expired, delete entry | ||
@@ -504,8 +433,5 @@ cache.del(status.key); | ||
function entryExists(jsonObject, entry) | ||
{ | ||
for (let otherEntry in jsonObject) | ||
{ | ||
if (entry === otherEntry) | ||
{ | ||
function entryExists(jsonObject, entry) { | ||
for (const otherEntry in jsonObject) { | ||
if (entry === otherEntry) { | ||
return true; | ||
@@ -512,0 +438,0 @@ } |
@@ -28,3 +28,3 @@ /* | ||
SF_OCSP_RESPONSE_CACHE_SERVER_ENABLED: | ||
!rawOcspFlag || rawOcspFlag && rawOcspFlag.toLowerCase() !== "false", | ||
!rawOcspFlag || rawOcspFlag && rawOcspFlag.toLowerCase() !== 'false', | ||
OCSP_RESPONSE_CACHE: undefined | ||
@@ -38,7 +38,5 @@ }; | ||
*/ | ||
function getOcspResponseCache() | ||
{ | ||
function getOcspResponseCache() { | ||
// initialize the ocsp response cache if needed | ||
if (!variables.OCSP_RESPONSE_CACHE) | ||
{ | ||
if (!variables.OCSP_RESPONSE_CACHE) { | ||
variables.OCSP_RESPONSE_CACHE = new OcspResponseCache.OcspResponseCache(); | ||
@@ -62,7 +60,5 @@ } | ||
*/ | ||
exports.secureSocket = function (socket, host, agent, mock) | ||
{ | ||
exports.secureSocket = function (socket, host, agent, mock) { | ||
// if ocsp validation is disabled for the given host, return the socket as is | ||
if (isOcspValidationDisabled(host)) | ||
{ | ||
if (isOcspValidationDisabled(host)) { | ||
Logger.getInstance().debug('OCSP validation disabled for %s', host); | ||
@@ -72,9 +68,7 @@ return socket; | ||
if (agent != null) | ||
{ | ||
if (agent != null) { | ||
getOcspResponseCache().setAgent(agent); | ||
} | ||
const validate = function () | ||
{ | ||
const validate = function () { | ||
// stop listening for the secure event | ||
@@ -87,10 +81,6 @@ socket.removeListener(socketSecuredEvent, validate); | ||
// writes without performing any additional validation | ||
if (socket.isSessionReused()) | ||
{ | ||
if (socket.isSessionReused()) { | ||
socket.uncork(); | ||
} | ||
else | ||
{ | ||
if (!socket.authorized) | ||
{ | ||
} else { | ||
if (!socket.authorized) { | ||
Logger.getInstance().warn('Socket is not authorized: %s', socket.authorizationError); | ||
@@ -103,7 +93,5 @@ return socket.destroy(socket.authorizationError); | ||
vcc(certChain, function (err) | ||
{ | ||
vcc(certChain, function (err) { | ||
getOcspResponseCache().resetCacheStatus(); | ||
if (err) | ||
{ | ||
if (err) { | ||
// if there's an error, destroy the socket | ||
@@ -137,4 +125,3 @@ Logger.getInstance().error('OCSP validation failed: %s', err); | ||
*/ | ||
function isOcspValidationDisabled(host) | ||
{ | ||
function isOcspValidationDisabled(host) { | ||
// ocsp is disabled if insecure-connect is enabled, or if we've disabled ocsp | ||
@@ -152,4 +139,3 @@ // for non-snowflake endpoints and the host is a non-snowflake endpoint | ||
*/ | ||
function isValidOCSPError(err) | ||
{ | ||
function isValidOCSPError(err) { | ||
return err && (err.code === ErrorCodes.ERR_OCSP_REVOKED || | ||
@@ -164,33 +150,23 @@ err.code === ErrorCodes.ERR_OCSP_UNKNOWN); | ||
*/ | ||
function canEarlyExitForOCSP(errors) | ||
{ | ||
if (GlobalConfig.getOcspMode() === GlobalConfig.ocspModes.FAIL_CLOSED) | ||
{ | ||
function canEarlyExitForOCSP(errors) { | ||
if (GlobalConfig.getOcspMode() === GlobalConfig.ocspModes.FAIL_CLOSED) { | ||
for (let errorIndex = 0, length = errors.length; | ||
errorIndex < length; errorIndex++) | ||
{ | ||
errorIndex < length; errorIndex++) { | ||
// first error | ||
const err = errors[errorIndex]; | ||
if (err) | ||
{ | ||
return err.hasOwnProperty('err') ? err.err : err; | ||
if (err) { | ||
return Object.prototype.hasOwnProperty.call(err, 'err') ? err.err : err; | ||
} | ||
} | ||
} | ||
else | ||
{ | ||
} else { | ||
let anyRevoked = null; | ||
for (let errorIndex = 0, length = errors.length; | ||
errorIndex < length; errorIndex++) | ||
{ | ||
errorIndex < length; errorIndex++) { | ||
// first error | ||
const err = errors[errorIndex]; | ||
if (err && !isValidOCSPError(err)) | ||
{ | ||
if (err && !isValidOCSPError(err)) { | ||
// any of the errors is NOT good/revoked/unknown | ||
Logger.getInstance().warn(ocspFailOpenWarning + err); | ||
return null; | ||
} | ||
else if (err && err.code === ErrorCodes.ERR_OCSP_REVOKED) | ||
{ | ||
} else if (err && err.code === ErrorCodes.ERR_OCSP_REVOKED) { | ||
anyRevoked = err; | ||
@@ -212,9 +188,7 @@ } | ||
*/ | ||
function validateCertChain(cert, cb) | ||
{ | ||
function validateCertChain(cert, cb) { | ||
// walk up the certificate chain and collect all the certificates in an array | ||
var certs = []; | ||
const certs = []; | ||
while (cert && cert.issuerCertificate && | ||
(cert.fingerprint !== cert.issuerCertificate.fingerprint)) | ||
{ | ||
(cert.fingerprint !== cert.issuerCertificate.fingerprint)) { | ||
certs.push(cert); | ||
@@ -226,3 +200,3 @@ cert = cert.issuerCertificate; | ||
// while validating the certificate chain | ||
var errors = new Array(certs.length); | ||
const errors = new Array(certs.length); | ||
@@ -236,11 +210,8 @@ /** | ||
*/ | ||
const eachCallback = function (certs, index) | ||
{ | ||
let cert = certs[index]; | ||
validateCert(cert, function (err, data) | ||
{ | ||
const eachCallback = function (certs, index) { | ||
const cert = certs[index]; | ||
validateCert(cert, function (err, data) { | ||
completed++; | ||
errors[index] = err; | ||
if (err) | ||
{ | ||
if (err) { | ||
Logger.getInstance().debug(err); | ||
@@ -250,7 +221,5 @@ } | ||
// if we have an ocsp response, cache it | ||
if (data && (!data.err || isValidOCSPError(data.err))) | ||
{ | ||
if (data && (!data.err || isValidOCSPError(data.err))) { | ||
// check if cache is initialized before setting entry | ||
if (getOcspResponseCache().isInitialized()) | ||
{ | ||
if (getOcspResponseCache().isInitialized()) { | ||
getOcspResponseCache().set(cert, data.res); | ||
@@ -260,4 +229,3 @@ } else { | ||
} | ||
if (data.err) | ||
{ | ||
if (data.err) { | ||
err = data.err; | ||
@@ -269,4 +237,3 @@ errors[index] = err; | ||
// if this is the last request to complete | ||
if (completed === certs.length) | ||
{ | ||
if (completed === certs.length) { | ||
const validError = canEarlyExitForOCSP(errors); | ||
@@ -280,4 +247,3 @@ cb(validError); | ||
let completed = 0; | ||
for (let index = 0, length = certs.length; index < length; index++) | ||
{ | ||
for (let index = 0, length = certs.length; index < length; index++) { | ||
eachCallback(certs, index); | ||
@@ -293,17 +259,10 @@ } | ||
*/ | ||
function validateCert(cert, cb) | ||
{ | ||
function getOcspCache() | ||
{ | ||
try | ||
{ | ||
if (!getOcspResponseCache().downloadCache(getOcspResonseAndVerify)) | ||
{ | ||
function validateCert(cert, cb) { | ||
function getOcspCache() { | ||
try { | ||
if (!getOcspResponseCache().downloadCache(getOcspResonseAndVerify)) { | ||
setTimeout(getOcspCache, 10); | ||
} | ||
} | ||
catch (e) | ||
{ | ||
process.nextTick(function () | ||
{ | ||
} catch (e) { | ||
process.nextTick(function () { | ||
cb(e); | ||
@@ -319,6 +278,4 @@ }); | ||
*/ | ||
function getOcspResonseAndVerify(err, useCacheServer) | ||
{ | ||
if (!useCacheServer && !getOcspResponseCache().isDownloadFinished()) | ||
{ | ||
function getOcspResonseAndVerify(err, useCacheServer) { | ||
if (!useCacheServer && !getOcspResponseCache().isDownloadFinished()) { | ||
setTimeout(getOcspResonseAndVerify, 10); // ms | ||
@@ -329,10 +286,6 @@ return; | ||
let decoded; | ||
try | ||
{ | ||
try { | ||
decoded = CertUtil.decode(cert); | ||
} | ||
catch (e) | ||
{ | ||
process.nextTick(function () | ||
{ | ||
} catch (e) { | ||
process.nextTick(function () { | ||
cb(e); | ||
@@ -344,11 +297,7 @@ }); | ||
// check if cache is initialized before getting entry | ||
if (getOcspResponseCache().isInitialized()) | ||
{ | ||
if (getOcspResponseCache().IsCacheExpired()) | ||
{ | ||
if (getOcspResponseCache().isInitialized()) { | ||
if (getOcspResponseCache().IsCacheExpired()) { | ||
// reset cache status so it can be refreshed | ||
getOcspResponseCache().resetCacheStatus(); | ||
} | ||
else | ||
{ | ||
} else { | ||
// if we already have a valid entry in the cache, use it | ||
@@ -358,42 +307,29 @@ ocspResponse = getOcspResponseCache().get(cert); | ||
} | ||
if (ocspResponse) | ||
{ | ||
if (ocspResponse) { | ||
Logger.getInstance().trace( | ||
'Returning OCSP status for certificate %s from cache', cert.serialNumber); | ||
const status = CertUtil.verifyOCSPResponse(decoded.issuer, ocspResponse); | ||
if (!status.err) | ||
{ | ||
if (!status.err) { | ||
// verification was success with the cache | ||
process.nextTick(function () | ||
{ | ||
cb(null, null) | ||
process.nextTick(function () { | ||
cb(null, null); | ||
}); | ||
} | ||
else | ||
{ | ||
} else { | ||
// verification was failure with the cache | ||
process.nextTick(function () | ||
{ | ||
cb(status.err, null) | ||
process.nextTick(function () { | ||
cb(status.err, null); | ||
}); | ||
} | ||
} | ||
else | ||
{ | ||
if (useCacheServer) | ||
{ | ||
process.nextTick(function () | ||
{ | ||
getOcspCache() | ||
} else { | ||
if (useCacheServer) { | ||
process.nextTick(function () { | ||
getOcspCache(); | ||
}); | ||
} else { | ||
Check(decoded, cb); | ||
} | ||
else | ||
{ | ||
Check(decoded, cb) | ||
} | ||
} | ||
} | ||
if (!variables.SF_OCSP_RESPONSE_CACHE_SERVER_ENABLED) | ||
{ | ||
if (!variables.SF_OCSP_RESPONSE_CACHE_SERVER_ENABLED) { | ||
getOcspResponseCache().forceDownloadToFinish(); | ||
@@ -400,0 +336,0 @@ } |
@@ -13,6 +13,3 @@ /* | ||
*/ | ||
function auth_default(password) | ||
{ | ||
var password = password; | ||
function AuthDefault(password) { | ||
/** | ||
@@ -25,9 +22,7 @@ * Update JSON body with password. | ||
*/ | ||
this.updateBody = function (body) | ||
{ | ||
this.updateBody = function (body) { | ||
body['data']['PASSWORD'] = password; | ||
}; | ||
this.authenticate = async function (authenticator, serviceName, account, username) | ||
{ | ||
this.authenticate = async function (authenticator, serviceName, account, username) { | ||
return; | ||
@@ -37,2 +32,2 @@ }; | ||
module.exports = auth_default; | ||
module.exports = AuthDefault; |
@@ -5,3 +5,3 @@ /* | ||
var util = require('../util'); | ||
const util = require('../util'); | ||
@@ -21,21 +21,16 @@ /** | ||
*/ | ||
function auth_keypair(privateKey, privateKeyPath, privateKeyPass, cryptomod, jwtmod, filesystem) | ||
{ | ||
var crypto = typeof cryptomod !== "undefined" ? cryptomod : require('crypto'); | ||
var jwt = typeof jwtmod !== "undefined" ? jwtmod : require('jsonwebtoken'); | ||
var fs = typeof filesystem !== "undefined" ? filesystem : require('fs'); | ||
function AuthKeypair(privateKey, privateKeyPath, privateKeyPass, cryptomod, jwtmod, filesystem) { | ||
const crypto = typeof cryptomod !== 'undefined' ? cryptomod : require('crypto'); | ||
const jwt = typeof jwtmod !== 'undefined' ? jwtmod : require('jsonwebtoken'); | ||
const fs = typeof filesystem !== 'undefined' ? filesystem : require('fs'); | ||
var privateKey = privateKey; | ||
var privateKeyPath = privateKeyPath; | ||
var privateKeyPass = privateKeyPass; | ||
let jwtToken; | ||
var jwtToken; | ||
const LIFETIME = 120; // seconds | ||
const ALGORITHM = 'RS256'; | ||
const ISSUER = 'iss'; | ||
const SUBJECT = 'sub'; | ||
const EXPIRE_TIME = 'exp'; | ||
const ISSUE_TIME = 'iat'; | ||
var LIFETIME = 120; // seconds | ||
var ALGORITHM = 'RS256'; | ||
var ISSUER = 'iss'; | ||
var SUBJECT = 'sub'; | ||
var EXPIRE_TIME = 'exp'; | ||
var ISSUE_TIME = 'iat'; | ||
/** | ||
@@ -48,4 +43,3 @@ * Update JSON body with token. | ||
*/ | ||
this.updateBody = function (body) | ||
{ | ||
this.updateBody = function (body) { | ||
body['data']['TOKEN'] = jwtToken; | ||
@@ -62,37 +56,18 @@ }; | ||
*/ | ||
function loadPrivateKey(privateKeyPath, privateKeyPass) | ||
{ | ||
function loadPrivateKey(privateKeyPath, privateKeyPass) { | ||
// Load private key file | ||
var privateKeyFile; | ||
try | ||
{ | ||
privateKeyFile = fs.readFileSync(privateKeyPath); | ||
} | ||
catch (loadErr) | ||
{ | ||
throw loadErr; | ||
} | ||
const privateKeyFile = fs.readFileSync(privateKeyPath); | ||
var privateKeyObject; | ||
let privateKeyObject; | ||
// For encrypted private key | ||
if (privateKeyPass) | ||
{ | ||
if (privateKeyPass) { | ||
// Get private key with passphrase | ||
try | ||
{ | ||
privateKeyObject = crypto.createPrivateKey({ | ||
key: privateKeyFile, | ||
format: 'pem', | ||
passphrase: privateKeyPass | ||
}); | ||
} | ||
catch (decryptErr) | ||
{ | ||
throw decryptErr; | ||
} | ||
privateKeyObject = crypto.createPrivateKey({ | ||
key: privateKeyFile, | ||
format: 'pem', | ||
passphrase: privateKeyPass | ||
}); | ||
} | ||
else | ||
{ // For unencrypted private key | ||
} else { // For unencrypted private key | ||
privateKeyObject = crypto.createPrivateKey({ | ||
@@ -104,3 +79,3 @@ key: privateKeyFile, | ||
var privateKey = privateKeyObject.export({ | ||
const privateKey = privateKeyObject.export({ | ||
format: 'pem', | ||
@@ -120,20 +95,11 @@ type: 'pkcs8' | ||
*/ | ||
function calculatePublicKeyFingerprint(privateKey) | ||
{ | ||
var pubKeyObject; | ||
try | ||
{ | ||
// Extract public key object from private key | ||
pubKeyObject = crypto.createPublicKey({ | ||
key: privateKey, | ||
format: 'pem' | ||
}); | ||
} | ||
catch (err) | ||
{ | ||
throw err; | ||
} | ||
function calculatePublicKeyFingerprint(privateKey) { | ||
// Extract public key object from private key | ||
const pubKeyObject = crypto.createPublicKey({ | ||
key: privateKey, | ||
format: 'pem' | ||
}); | ||
// Obtain public key string | ||
var publicKey = pubKeyObject.export({ | ||
const publicKey = pubKeyObject.export({ | ||
format: 'der', | ||
@@ -144,3 +110,3 @@ type: 'spki' | ||
// Generate SHA256 hash of public key and encode in base64 | ||
var publicKeyFingerprint = 'SHA256:' + | ||
const publicKeyFingerprint = 'SHA256:' + | ||
crypto.createHash('sha256') | ||
@@ -163,14 +129,10 @@ .update(publicKey, 'utf8') | ||
*/ | ||
this.authenticate = async function (authenticator, serviceName, account, username) | ||
{ | ||
var publicKeyFingerprint; | ||
this.authenticate = async function (authenticator, serviceName, account, username) { | ||
let publicKeyFingerprint; | ||
// Use private key if already set in connection string, otherwise use private key file location | ||
if (privateKey) | ||
{ | ||
if (privateKey) { | ||
// Get public key fingerprint | ||
publicKeyFingerprint = calculatePublicKeyFingerprint(privateKey); | ||
} | ||
else if (privateKeyPath) | ||
{ | ||
} else if (privateKeyPath) { | ||
// Extract private key and get fingerprint | ||
@@ -182,7 +144,7 @@ privateKey = loadPrivateKey(privateKeyPath, privateKeyPass); | ||
// Current time + 120 seconds | ||
var currentTime = Date.now(); | ||
var jwtTokenExp = currentTime + LIFETIME; | ||
const currentTime = Date.now(); | ||
const jwtTokenExp = currentTime + LIFETIME; | ||
// Create payload containing jwt token and lifetime span | ||
var payload = { | ||
const payload = { | ||
[ISSUER]: util.format('%s.%s.%s', account.toUpperCase(), username.toUpperCase(), publicKeyFingerprint), | ||
@@ -195,13 +157,6 @@ [SUBJECT]: util.format('%s.%s', account.toUpperCase(), username.toUpperCase()), | ||
// Sign payload with RS256 algorithm | ||
try | ||
{ | ||
jwtToken = jwt.sign(payload, privateKey, {algorithm: ALGORITHM}); | ||
} | ||
catch (jwtErr) | ||
{ | ||
throw jwtErr; | ||
} | ||
} | ||
jwtToken = jwt.sign(payload, privateKey, { algorithm: ALGORITHM }); | ||
}; | ||
} | ||
module.exports = auth_keypair; | ||
module.exports = AuthKeypair; |
@@ -13,6 +13,3 @@ /* | ||
*/ | ||
function auth_oauth(token) | ||
{ | ||
var token = token; | ||
function AuthOauth(token) { | ||
/** | ||
@@ -25,9 +22,7 @@ * Update JSON body with token. | ||
*/ | ||
this.updateBody = function (body) | ||
{ | ||
this.updateBody = function (body) { | ||
body['data']['TOKEN'] = token; | ||
}; | ||
this.authenticate = async function (authenticator, serviceName, account, username) | ||
{ | ||
this.authenticate = async function (authenticator, serviceName, account, username) { | ||
return; | ||
@@ -37,2 +32,2 @@ }; | ||
module.exports = auth_oauth; | ||
module.exports = AuthOauth; |
@@ -5,4 +5,4 @@ /* | ||
var util = require('../util'); | ||
var rest = require('../global_config').rest; | ||
const util = require('../util'); | ||
const rest = require('../global_config').rest; | ||
@@ -22,11 +22,10 @@ /** | ||
*/ | ||
function auth_okta(password, region, account, clientType, clientVersion, httpClient) | ||
{ | ||
var host = util.construct_hostname(region, account); | ||
var port = rest.HTTPS_PORT; | ||
var protocol = rest.HTTPS_PROTOCOL; | ||
function AuthOkta(password, region, account, clientType, clientVersion, httpClient) { | ||
const host = util.constructHostname(region, account); | ||
const port = rest.HTTPS_PORT; | ||
const protocol = rest.HTTPS_PROTOCOL; | ||
var clientAppId = clientType; | ||
var clientAppVersion = clientVersion; | ||
var samlResponse; | ||
const clientAppId = clientType; | ||
const clientAppVersion = clientVersion; | ||
let samlResponse; | ||
@@ -40,4 +39,3 @@ /** | ||
*/ | ||
this.updateBody = function (body) | ||
{ | ||
this.updateBody = function (body) { | ||
body['data']['RAW_SAML_RESPONSE'] = samlResponse; | ||
@@ -56,8 +54,6 @@ }; | ||
*/ | ||
this.authenticate = async function (authenticator, serviceName, account, username) | ||
{ | ||
var ssoUrl; | ||
var tokenUrl; | ||
await step1(authenticator, serviceName, account, username).then((response) => | ||
{ | ||
this.authenticate = async function (authenticator, serviceName, account, username) { | ||
let ssoUrl; | ||
let tokenUrl; | ||
await step1(authenticator, serviceName, account, username).then((response) => { | ||
const responseData = response['data']; | ||
@@ -82,18 +78,15 @@ const success = responseData['success']; | ||
var oneTimeToken; | ||
await step3(tokenUrl, username, password).then((response) => | ||
{ | ||
var data = response['data']; | ||
let oneTimeToken; | ||
await step3(tokenUrl, username, password).then((response) => { | ||
const data = response['data']; | ||
if (data['sessionToken']) { | ||
oneTimeToken = data['sessionToken']; | ||
} | ||
else { | ||
oneTimeToken = data['cookieToken']; | ||
} | ||
if (data['sessionToken']) { | ||
oneTimeToken = data['sessionToken']; | ||
} else { | ||
oneTimeToken = data['cookieToken']; | ||
} | ||
}); | ||
var responseHtml; | ||
await step4(oneTimeToken, ssoUrl).then((response) => | ||
{ | ||
let responseHtml; | ||
await step4(oneTimeToken, ssoUrl).then((response) => { | ||
responseHtml = response['data']; | ||
@@ -115,25 +108,23 @@ }); | ||
*/ | ||
function step1(authenticator, serviceName, account, username) | ||
{ | ||
function step1(authenticator, serviceName, account, username) { | ||
// Create URL to send POST request to | ||
var url = protocol + "://" + host + "/session/authenticator-request"; | ||
const url = protocol + '://' + host + '/session/authenticator-request'; | ||
var header; | ||
if (serviceName) | ||
{ | ||
let header; | ||
if (serviceName) { | ||
header = { | ||
'HTTP_HEADER_SERVICE_NAME': serviceName | ||
} | ||
}; | ||
} | ||
// JSON body to send with POST request | ||
var body = { | ||
"data": { | ||
"ACCOUNT_NAME": account, | ||
"LOGIN_NAME": username, | ||
"PORT": port, | ||
"PROTOCOL": protocol, | ||
"AUTHENTICATOR": authenticator, | ||
"CLIENT_APP_ID": clientAppId, | ||
"CLIENT_APP_VERSION": clientAppVersion | ||
const body = { | ||
'data': { | ||
'ACCOUNT_NAME': account, | ||
'LOGIN_NAME': username, | ||
'PORT': port, | ||
'PROTOCOL': protocol, | ||
'AUTHENTICATOR': authenticator, | ||
'CLIENT_APP_ID': clientAppId, | ||
'CLIENT_APP_VERSION': clientAppVersion | ||
} | ||
@@ -147,7 +138,6 @@ }; | ||
}) | ||
.catch(requestErr => | ||
{ | ||
.catch(requestErr => { | ||
throw requestErr; | ||
}); | ||
}; | ||
} | ||
@@ -163,11 +153,9 @@ /** | ||
*/ | ||
function step2(authenticator, ssoUrl, tokenUrl) | ||
{ | ||
function step2(authenticator, ssoUrl, tokenUrl) { | ||
authenticator = authenticator.toLowerCase(); | ||
if (!(authenticator.startsWith(ssoUrl.substring(0, authenticator.length)) && | ||
authenticator.startsWith(tokenUrl.substring(0, authenticator.length)))) | ||
{ | ||
throw new Error("The prefix of the SSO/token URL and the specified authenticator do not match."); | ||
authenticator.startsWith(tokenUrl.substring(0, authenticator.length)))) { | ||
throw new Error('The prefix of the SSO/token URL and the specified authenticator do not match.'); | ||
} | ||
}; | ||
} | ||
@@ -183,8 +171,7 @@ /** | ||
*/ | ||
function step3(tokenUrl, username, password) | ||
{ | ||
function step3(tokenUrl, username, password) { | ||
// JSON body to send with POST request | ||
var body = { | ||
"username": username, | ||
"password": password | ||
const body = { | ||
'username': username, | ||
'password': password | ||
}; | ||
@@ -195,7 +182,6 @@ | ||
.post(tokenUrl, body) | ||
.catch(requestErr => | ||
{ | ||
.catch(requestErr => { | ||
throw requestErr; | ||
}); | ||
}; | ||
} | ||
@@ -210,4 +196,3 @@ /** | ||
*/ | ||
function step4(oneTimeToken, ssoUrl) | ||
{ | ||
function step4(oneTimeToken, ssoUrl) { | ||
// Query IDP URL to get SAML response | ||
@@ -217,11 +202,10 @@ return httpClient | ||
params: { | ||
'RelayState': "/some/deep/link", | ||
'RelayState': '/some/deep/link', | ||
'onetimetoken': oneTimeToken, | ||
}} | ||
} } | ||
) | ||
.catch(requestErr => | ||
{ | ||
.catch(requestErr => { | ||
throw requestErr; | ||
}); | ||
}; | ||
} | ||
@@ -235,6 +219,5 @@ /** | ||
*/ | ||
function step5(responseHtml) | ||
{ | ||
var postBackUrl = getPostBackUrlFromHtml(responseHtml); | ||
var fullUrl = util.format("%s://%s:%s", protocol, host, port); | ||
function step5(responseHtml) { | ||
const postBackUrl = getPostBackUrlFromHtml(responseHtml); | ||
const fullUrl = util.format('%s://%s:%s', protocol, host, port); | ||
@@ -244,6 +227,5 @@ // Validate the post back url come back with the SAML response | ||
// intended destination url to Snowflake. | ||
if (postBackUrl.substring(0, 20) !== fullUrl.substring(0, 20)) | ||
{ | ||
throw new Error(util.format("The specified authenticator and destination URL " + | ||
"in the SAML assertion do not match: expected: %s postback: %s", fullUrl, postBackUrl)); | ||
if (postBackUrl.substring(0, 20) !== fullUrl.substring(0, 20)) { | ||
throw new Error(util.format('The specified authenticator and destination URL ' + | ||
'in the SAML assertion do not match: expected: %s postback: %s', fullUrl, postBackUrl)); | ||
} | ||
@@ -261,7 +243,6 @@ | ||
*/ | ||
function getPostBackUrlFromHtml(html) | ||
{ | ||
var index = html.search("<form"); | ||
var startIndex = html.indexOf("action=\"", index); | ||
var endIndex = html.indexOf("\"", startIndex + 8); | ||
function getPostBackUrlFromHtml(html) { | ||
const index = html.search('<form'); | ||
const startIndex = html.indexOf('action="', index); | ||
const endIndex = html.indexOf('"', startIndex + 8); | ||
@@ -278,10 +259,9 @@ return unescapeHtml(html.substring(startIndex + 8, endIndex)); | ||
*/ | ||
function unescapeHtml(html) | ||
{ | ||
function unescapeHtml(html) { | ||
return html | ||
.replace(/:/g, ":") | ||
.replace(///g, "/"); | ||
.replace(/:/g, ':') | ||
.replace(///g, '/'); | ||
} | ||
} | ||
module.exports = auth_okta; | ||
module.exports = AuthOkta; |
@@ -11,2 +11,4 @@ /* | ||
const SsoUrlProvider = require('../authentication/sso_url_provider'); | ||
const crypto = require('crypto'); | ||
const { rest } = require('../global_config'); | ||
@@ -23,3 +25,3 @@ /** | ||
*/ | ||
function auth_web(connectionConfig, httpClient, webbrowser) { | ||
function AuthWeb(connectionConfig, httpClient, webbrowser) { | ||
@@ -37,3 +39,3 @@ const host = connectionConfig.host; | ||
const open = typeof webbrowser !== "undefined" ? webbrowser : require('open'); | ||
const open = typeof webbrowser !== 'undefined' ? webbrowser : require('open'); | ||
@@ -52,4 +54,3 @@ let proofKey; | ||
*/ | ||
this.updateBody = function (body) | ||
{ | ||
this.updateBody = function (body) { | ||
body['data']['TOKEN'] = token; | ||
@@ -71,4 +72,5 @@ body['data']['PROOF_KEY'] = proofKey; | ||
let server; | ||
let loginUrl; | ||
const receiveData = new Promise(async (resolve) => { | ||
const receiveData = new Promise( (resolve) => { | ||
// Server to receive SAML token | ||
@@ -83,26 +85,44 @@ server = createServer(resolve); | ||
// Step 1: query Snowflake to obtain SSO url | ||
const ssoData = await ssoUrlProvider.getSSOURL(authenticator, | ||
serviceName, | ||
account, | ||
server.address().port, | ||
username, | ||
host); | ||
if (connectionConfig.getDisableConsoleLogin()) { | ||
// Step 1: query Snowflake to obtain SSO url | ||
const ssoData = await ssoUrlProvider.getSSOURL(authenticator, | ||
serviceName, | ||
account, | ||
server.address().port, | ||
username, | ||
host); | ||
proofKey = ssoData['proofKey']; | ||
proofKey = ssoData['proofKey']; | ||
loginUrl = ssoData['ssoUrl']; | ||
} else { | ||
proofKey = this.generateProofKey(); | ||
loginUrl = this.getLoginUrl(username, proofKey, server.address().port); | ||
} | ||
// Step 2: validate URL | ||
let ssoURL = ssoData['ssoUrl']; | ||
if (!URLUtil.isValidURL(ssoURL)) { | ||
throw new Error(util.format("Invalid SSO URL found - %s ", ssoURL)); | ||
if (!URLUtil.isValidURL(loginUrl)) { | ||
throw new Error(util.format('Invalid SSO URL found - %s ', loginUrl)); | ||
} | ||
// Step 3: open browser | ||
open(ssoURL); | ||
open(loginUrl); | ||
// Step 4: get SAML token | ||
const tokenData = await withBrowserActionTimeout(browserActionTimeout, receiveData) | ||
const tokenData = await withBrowserActionTimeout(browserActionTimeout, receiveData); | ||
processGet(tokenData); | ||
}; | ||
this.generateProofKey = function () { | ||
const randomness = crypto.randomBytes(32); | ||
return Buffer.from(randomness, 'utf8').toString('base64'); | ||
}; | ||
this.getLoginUrl = function (username, proofKey, port) { | ||
const url = new URL(rest.HTTPS_PROTOCOL + '://' + host + '/console/login'); | ||
url.searchParams.append('login_name', username); | ||
url.searchParams.append('proof_key', proofKey); | ||
url.searchParams.append('browser_mode_redirect_port', port); | ||
return url.toString(); | ||
}; | ||
/** | ||
@@ -115,8 +135,5 @@ * Create server to retrieve SAML token. | ||
*/ | ||
function createServer(resolve) | ||
{ | ||
var server = net.createServer(function (socket) | ||
{ | ||
socket.on('data', function (chunk) | ||
{ | ||
function createServer(resolve) { | ||
const server = net.createServer(function (socket) { | ||
socket.on('data', function (chunk) { | ||
// User successfully entered credentials | ||
@@ -126,3 +143,3 @@ socket.write(successResponse); | ||
// Receive the data and split by line | ||
var data = chunk.toString().split("\r\n"); | ||
const data = chunk.toString().split('\r\n'); | ||
@@ -135,10 +152,6 @@ // Stop accepting connections and close | ||
}); | ||
socket.on('error', (socketErr) => | ||
{ | ||
if (socketErr['code'] === 'ECONNRESET') | ||
{ | ||
socket.on('error', (socketErr) => { | ||
if (socketErr['code'] === 'ECONNRESET') { | ||
socket.end(); | ||
} | ||
else | ||
{ | ||
} else { | ||
throw socketErr; | ||
@@ -150,3 +163,3 @@ } | ||
return server; | ||
}; | ||
} | ||
@@ -160,15 +173,10 @@ /** | ||
*/ | ||
function processGet(data) | ||
{ | ||
var targetLine; | ||
function processGet(data) { | ||
let targetLine; | ||
for (const line of data) | ||
{ | ||
if (line.startsWith("GET ")) | ||
{ | ||
for (const line of data) { | ||
if (line.startsWith('GET ')) { | ||
targetLine = line; | ||
break; | ||
} | ||
else | ||
{ | ||
} else { | ||
return; | ||
@@ -178,9 +186,8 @@ } | ||
// Split the GET request line | ||
targetLine = targetLine.split(" "); | ||
targetLine = targetLine.split(' '); | ||
// Get value of the "token" query parameter | ||
token = querystring.parse(targetLine[1])["/?token"]; | ||
}; | ||
token = querystring.parse(targetLine[1])['/?token']; | ||
} | ||
@@ -199,2 +206,2 @@ const withBrowserActionTimeout = (millis, promise) => { | ||
module.exports = auth_web; | ||
module.exports = AuthWeb; |
@@ -5,7 +5,7 @@ /* | ||
const auth_default = require('./auth_default'); | ||
const auth_web = require('./auth_web'); | ||
const auth_keypair = require('./auth_keypair'); | ||
const auth_oauth = require('./auth_oauth'); | ||
const auth_okta = require('./auth_okta'); | ||
const AuthDefault = require('./auth_default'); | ||
const AuthWeb = require('./auth_web'); | ||
const AuthKeypair = require('./auth_keypair'); | ||
const AuthOauth = require('./auth_oauth'); | ||
const AuthOkta = require('./auth_okta'); | ||
@@ -75,14 +75,14 @@ const authenticationTypes = | ||
if (auth === authenticationTypes.DEFAULT_AUTHENTICATOR) { | ||
return new auth_default(connectionConfig.password); | ||
return new AuthDefault(connectionConfig.password); | ||
} else if (auth === authenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR) { | ||
return new auth_web(connectionConfig, httpClient); | ||
return new AuthWeb(connectionConfig, httpClient); | ||
} | ||
if (auth === authenticationTypes.KEY_PAIR_AUTHENTICATOR) { | ||
return new auth_keypair(connectionConfig.getPrivateKey(), | ||
return new AuthKeypair(connectionConfig.getPrivateKey(), | ||
connectionConfig.getPrivateKeyPath(), | ||
connectionConfig.getPrivateKeyPass()); | ||
} else if (auth === authenticationTypes.OAUTH_AUTHENTICATOR) { | ||
return new auth_oauth(connectionConfig.getToken()); | ||
return new AuthOauth(connectionConfig.getToken()); | ||
} else if (this.isOktaAuth(auth)) { | ||
return new auth_okta(connectionConfig.password, | ||
return new AuthOkta(connectionConfig.password, | ||
connectionConfig.region, | ||
@@ -96,3 +96,3 @@ connectionConfig.account, | ||
// Authenticator specified does not exist | ||
return new auth_default(connectionConfig.password); | ||
return new AuthDefault(connectionConfig.password); | ||
} | ||
@@ -99,0 +99,0 @@ }; |
@@ -5,3 +5,3 @@ /* | ||
var core = require('./core'); | ||
const core = require('./core'); | ||
@@ -8,0 +8,0 @@ module.exports = core( |
@@ -7,3 +7,3 @@ /* | ||
const fs = require('fs'); | ||
const {isString} = require('../util'); | ||
const { isString } = require('../util'); | ||
const Logger = require('../logger'); | ||
@@ -24,3 +24,3 @@ const clientConfigFileName = 'sf_client_config.json'; | ||
class ClientConfig { | ||
constructor (loggingConfig) { | ||
constructor(loggingConfig) { | ||
this.loggingConfig = loggingConfig; | ||
@@ -31,3 +31,3 @@ } | ||
class ClientLoggingConfig { | ||
constructor (logLevel, logPath) { | ||
constructor(logLevel, logPath) { | ||
this.logLevel = logLevel; | ||
@@ -57,3 +57,3 @@ this.logPath = logPath; | ||
*/ | ||
function levelFromString (value) { | ||
function levelFromString(value) { | ||
const level = value.toUpperCase(); | ||
@@ -88,3 +88,3 @@ if (!allLevels.includes(level)) { | ||
function readFileConfig (filePath) { | ||
function readFileConfig(filePath) { | ||
if (!filePath) { | ||
@@ -99,3 +99,3 @@ return Promise.resolve(null); | ||
function parseConfigFile (configurationJson) { | ||
function parseConfigFile(configurationJson) { | ||
try { | ||
@@ -115,3 +115,3 @@ const parsedConfiguration = JSON.parse(configurationJson); | ||
function validate (configuration) { | ||
function validate(configuration) { | ||
validateLogLevel(configuration); | ||
@@ -142,11 +142,11 @@ validateLogPath(configuration); | ||
function getLogLevel (configuration) { | ||
function getLogLevel(configuration) { | ||
return configuration.common.log_level; | ||
} | ||
function getLogPath (configuration) { | ||
function getLogPath(configuration) { | ||
return configuration.common.log_path; | ||
} | ||
function findConfig (filePathFromConnectionString) { | ||
function findConfig(filePathFromConnectionString) { | ||
return verifyNotEmpty(filePathFromConnectionString) | ||
@@ -159,11 +159,11 @@ .then((filePath) => filePath ?? getFilePathFromEnvironmentVariable()) | ||
async function verifyNotEmpty (filePath) { | ||
async function verifyNotEmpty(filePath) { | ||
return filePath ? filePath : null; | ||
} | ||
function getFilePathFromEnvironmentVariable () { | ||
function getFilePathFromEnvironmentVariable() { | ||
return verifyNotEmpty(process.env.SF_CLIENT_CONFIG_FILE); | ||
} | ||
async function searchForConfigInDictionary (directoryProvider, directoryDescription) { | ||
async function searchForConfigInDictionary(directoryProvider, directoryDescription) { | ||
try { | ||
@@ -179,3 +179,3 @@ const directory = directoryProvider(); | ||
async function onlyIfFileExists (filePath) { | ||
async function onlyIfFileExists(filePath) { | ||
return await fsPromises.access(filePath, fs.constants.F_OK) | ||
@@ -182,0 +182,0 @@ .then(() => filePath) |
/* | ||
* Copyright (c) 2015-2021 Snowflake Computing Inc. All rights reserved. | ||
*/ | ||
var Logger = require('../logger'); | ||
const Logger = require('../logger'); | ||
const Readable = require('stream').Readable; | ||
const fs = require('fs'); | ||
const tmp = require('tmp'); | ||
var os = require('os'); | ||
var path = require('path'); | ||
var Statement = require('./statement'); | ||
var fileCompressionType = require('.././file_transfer_agent/file_compression_type'); | ||
const Statement = require('./statement'); | ||
const fileCompressionType = require('.././file_transfer_agent/file_compression_type'); | ||
const STAGE_NAME = 'SYSTEM$BIND'; | ||
const CREATE_STAGE_STMT = "CREATE OR REPLACE TEMPORARY STAGE " | ||
const CREATE_STAGE_STMT = 'CREATE OR REPLACE TEMPORARY STAGE ' | ||
+ STAGE_NAME | ||
+ " file_format=( type=csv field_optionally_enclosed_by='\"')"; | ||
+ ' file_format=( type=csv field_optionally_enclosed_by=\'"\')'; | ||
@@ -31,131 +28,122 @@ /** | ||
function BindUploader(options, services, connectionConfig, requestId) | ||
{ | ||
const MAX_BUFFER_SIZE = 1024 * 1024 * 100; | ||
function BindUploader(options, services, connectionConfig, requestId) { | ||
const MAX_BUFFER_SIZE = 1024 * 1024 * 100; | ||
Logger.getInstance().debug('BindUploaders'); | ||
this.options = options; | ||
this.services = services; | ||
this.connectionConfig = connectionConfig; | ||
this.requestId = requestId; | ||
this.stagePath = '@' + STAGE_NAME + '/' + requestId; | ||
Logger.getInstance().debug('token = %s', connectionConfig.getToken()); | ||
Logger.getInstance().debug('BindUploaders'); | ||
this.options = options; | ||
this.services = services; | ||
this.connectionConfig = connectionConfig; | ||
this.requestId = requestId; | ||
this.stagePath = '@' + STAGE_NAME + '/' + requestId; | ||
Logger.getInstance().debug('token = %s', connectionConfig.getToken()); | ||
this.createStage = async function () { | ||
var createStageOptions = { sqlText: GetCreateStageStmt() }; | ||
var newContext = Statement.createContext(createStageOptions, this.services, this.connectionConfig); | ||
if (this.connectionConfig.getForceStageBindError() == 0) { | ||
throw new Error("Failed to create stage"); | ||
} | ||
var ret = await Statement.sendRequest(newContext); | ||
if (ret["status"] != 200) { | ||
throw new Error("Failed to create stage"); | ||
} | ||
} | ||
this.createStage = async function () { | ||
const createStageOptions = { sqlText: GetCreateStageStmt() }; | ||
const newContext = Statement.createContext(createStageOptions, this.services, this.connectionConfig); | ||
if (this.connectionConfig.getForceStageBindError() === 0) { | ||
throw new Error('Failed to create stage'); | ||
} | ||
const ret = await Statement.sendRequest(newContext); | ||
if (ret['status'] !== 200) { | ||
throw new Error('Failed to create stage'); | ||
} | ||
}; | ||
this.uploadFilestream = async function (fileName, fileData) { | ||
Logger.getInstance().debug('BindUploaders::uploadFilestream'); | ||
var stageName = this.stagePath; | ||
if (stageName == null) { | ||
throw new Error("Stage name is null."); | ||
} | ||
if (fileName == null) { | ||
throw new Error("File name is null."); | ||
} | ||
if (this.connectionConfig.getForceStageBindError() == 1) { | ||
throw new Error("Failed to upload file"); | ||
} | ||
this.uploadFilestream = async function (fileName, fileData) { | ||
Logger.getInstance().debug('BindUploaders::uploadFilestream'); | ||
const stageName = this.stagePath; | ||
if (stageName == null) { | ||
throw new Error('Stage name is null.'); | ||
} | ||
if (fileName == null) { | ||
throw new Error('File name is null.'); | ||
} | ||
if (this.connectionConfig.getForceStageBindError() === 1) { | ||
throw new Error('Failed to upload file'); | ||
} | ||
await new Promise((resolve, reject) => { | ||
var putStmt = "PUT file://" + fileName + "'" + stageName + "' overwrite=true auto_compress=false source_compression=gzip"; | ||
var uploadFileOptions = { | ||
sqlText: putStmt, fileStream: fileData, | ||
complete: function (err, stmt, rows) { | ||
if (err) { | ||
Logger.getInstance().debug('err ' + err); | ||
reject(err); | ||
} | ||
Logger.getInstance().debug('uploadFiles done '); | ||
resolve(stmt.streamRows()); | ||
} | ||
}; | ||
Statement.createStatementPreExec(uploadFileOptions, this.services, this.connectionConfig); | ||
}); | ||
} | ||
await new Promise((resolve, reject) => { | ||
const putStmt = 'PUT file://' + fileName + '\'' + stageName + '\' overwrite=true auto_compress=false source_compression=gzip'; | ||
const uploadFileOptions = { | ||
sqlText: putStmt, fileStream: fileData, | ||
complete: function (err, stmt, rows) { | ||
if (err) { | ||
Logger.getInstance().debug('err ' + err); | ||
reject(err); | ||
} | ||
Logger.getInstance().debug('uploadFiles done '); | ||
resolve(stmt.streamRows()); | ||
} | ||
}; | ||
Statement.createStatementPreExec(uploadFileOptions, this.services, this.connectionConfig); | ||
}); | ||
}; | ||
this.Upload = async function (bindings) | ||
{ | ||
Logger.getInstance().debug('BindUploaders::Upload'); | ||
this.Upload = async function (bindings) { | ||
Logger.getInstance().debug('BindUploaders::Upload'); | ||
if(bindings == null) | ||
return null; | ||
if (!this.services.sf.isStageCreated) { | ||
await this.createStage(); | ||
this.services.sf.isStageCreated = true; | ||
} | ||
if (bindings == null) { | ||
return null; | ||
} | ||
if (!this.services.sf.isStageCreated) { | ||
await this.createStage(); | ||
this.services.sf.isStageCreated = true; | ||
} | ||
var fileCount = 0; | ||
var strbuffer = ""; | ||
let fileCount = 0; | ||
let strbuffer = ''; | ||
for(var i=0; i<bindings.length; i++) | ||
{ | ||
for(var j=0; j< bindings[i].length; j++) | ||
{ | ||
if (j>0) | ||
strbuffer += ','; | ||
var value = this.cvsData(bindings[i][j]); | ||
strbuffer += value; | ||
} | ||
strbuffer += '\n'; | ||
for (let i = 0; i < bindings.length; i++) { | ||
for (let j = 0; j < bindings[i].length; j++) { | ||
if (j > 0) { | ||
strbuffer += ','; | ||
} | ||
const value = this.cvsData(bindings[i][j]); | ||
strbuffer += value; | ||
} | ||
strbuffer += '\n'; | ||
if ((strbuffer.length >= MAX_BUFFER_SIZE) || (i == bindings.length -1)) | ||
{ | ||
var fileName = (++fileCount).toString(); | ||
Logger.getInstance().debug('fileName=' + fileName); | ||
await this.uploadFilestream(fileName, strbuffer); | ||
strbuffer = ""; | ||
} | ||
} | ||
}; | ||
if ((strbuffer.length >= MAX_BUFFER_SIZE) || (i === bindings.length - 1)) { | ||
const fileName = (++fileCount).toString(); | ||
Logger.getInstance().debug('fileName=' + fileName); | ||
await this.uploadFilestream(fileName, strbuffer); | ||
strbuffer = ''; | ||
} | ||
} | ||
}; | ||
this.cvsData = function(data) | ||
{ | ||
if(data == null || data.toString() == "") | ||
return "\"\""; | ||
if(data.toString().indexOf('"') >= 0 | ||
this.cvsData = function (data) { | ||
if (data == null || data.toString() === '') { | ||
return '""'; | ||
} | ||
if (data.toString().indexOf('"') >= 0 | ||
|| data.toString().indexOf(',') >= 0 | ||
|| data.toString().indexOf('\\') >= 0 | ||
|| data.toString().indexOf('\n') >= 0 | ||
|| data.toString().indexOf('\t') >= 0) | ||
return '"' + data.toString().replaceAll("\"", "\"\"") + '"'; | ||
else | ||
return data; | ||
} | ||
|| data.toString().indexOf('\t') >= 0) { | ||
return '"' + data.toString().replaceAll('"', '""') + '"'; | ||
} else { | ||
return data; | ||
} | ||
}; | ||
} | ||
function GetCreateStageStmt() | ||
{ | ||
return CREATE_STAGE_STMT; | ||
function GetCreateStageStmt() { | ||
return CREATE_STAGE_STMT; | ||
} | ||
function GetStageName(requestId) | ||
{ | ||
return '@' + STAGE_NAME + '/' + requestId; | ||
function GetStageName(requestId) { | ||
return '@' + STAGE_NAME + '/' + requestId; | ||
} | ||
function CleanFile(fileName) | ||
{ | ||
try | ||
{ | ||
if(fs.existsSync(fileName)) | ||
{ | ||
fs.unlinkSync(fileName); | ||
} | ||
} | ||
catch(err) | ||
{ | ||
Logger.getInstance().debug('Delete file failed: %s', fileName); | ||
} | ||
function CleanFile(fileName) { | ||
try { | ||
if (fs.existsSync(fileName)) { | ||
fs.unlinkSync(fileName); | ||
} | ||
} catch (err) { | ||
Logger.getInstance().debug('Delete file failed: %s', fileName); | ||
} | ||
} | ||
module.exports = {BindUploader, GetCreateStageStmt, GetStageName, CleanFile}; | ||
module.exports = { BindUploader, GetCreateStageStmt, GetStageName, CleanFile }; |
@@ -58,4 +58,3 @@ /* | ||
function consolidateHostAndAccount(options) | ||
{ | ||
function consolidateHostAndAccount(options) { | ||
let dotPos = -1; | ||
@@ -70,45 +69,36 @@ let realAccount = undefined; | ||
if (Util.exists(options.account)) | ||
{ | ||
if (Util.exists(options.account)) { | ||
Errors.checkArgumentValid(Util.isString(options.account), ErrorCodes.ERR_CONN_CREATE_INVALID_ACCOUNT); | ||
Errors.checkArgumentValid(Util.isCorrectSubdomain(options.account), ErrorCodes.ERR_CONN_CREATE_INVALID_ACCOUNT_REGEX); | ||
options.host = Util.construct_hostname(options.region, options.account); | ||
dotPos = options.account.indexOf('.'); | ||
realAccount = options.account; | ||
if (dotPos > 0) | ||
{ | ||
if (dotPos > 0) { | ||
realRegion = realAccount.substring(dotPos + 1); | ||
realAccount = realAccount.substring(0, dotPos); | ||
} | ||
if (!Util.exists(options.host)) { | ||
options.host = Util.constructHostname(realRegion, realAccount); | ||
} | ||
} | ||
if (!Util.isString(options.accessUrl) || !Util.exists(options.accessUrl)) | ||
{ | ||
if (options.region === 'us-west-2') | ||
{ | ||
if (!Util.isString(options.accessUrl) || !Util.exists(options.accessUrl)) { | ||
if (options.region === 'us-west-2') { | ||
options.region = ''; | ||
} | ||
if (dotPos < 0 && Util.isString(options.region) && options.region.length > 0) | ||
{ | ||
if (Util.exists(options.host)) { | ||
options.accessUrl = Util.format('https://%s', options.host); | ||
} else if (dotPos < 0 && Util.isString(options.region) && options.region.length > 0) { | ||
options.accessUrl = Util.format('https://%s.%s.snowflakecomputing.com', options.account, options.region); | ||
} | ||
else | ||
{ | ||
} else { | ||
options.accessUrl = Util.format('https://%s.snowflakecomputing.com', options.account); | ||
} | ||
} | ||
else if (!Util.exists(options.account)) | ||
{ | ||
try | ||
{ | ||
} else if (!Util.exists(options.account)) { | ||
try { | ||
const parsedUrl = url.parse(options.accessUrl); | ||
Errors.checkArgumentValid(Util.exists(parsedUrl.hostname), ErrorCodes.ERR_CONN_CREATE_INVALID_ACCESS_URL); | ||
const dotPos = parsedUrl.hostname.indexOf('.'); | ||
if (dotPos > 0) | ||
{ | ||
if (dotPos > 0) { | ||
realAccount = parsedUrl.hostname.substring(0, dotPos); | ||
} | ||
} | ||
catch (e) | ||
{ | ||
} catch (e) { | ||
Errors.checkArgumentValid( | ||
@@ -118,7 +108,5 @@ false, ErrorCodes.ERR_CONN_CREATE_INVALID_ACCESS_URL); | ||
} | ||
if (Util.exists(realAccount) && options.accessUrl.endsWith("global.snowflakecomputing.com")) | ||
{ | ||
if (Util.exists(realAccount) && options.accessUrl.endsWith('global.snowflakecomputing.com')) { | ||
const dashPos = realAccount.indexOf('-'); | ||
if (dashPos > 0) | ||
{ | ||
if (dashPos > 0) { | ||
// global URL | ||
@@ -145,7 +133,5 @@ realAccount = realAccount.substring(0, dashPos); | ||
*/ | ||
function ConnectionConfig(options, validateCredentials, qaMode, clientInfo) | ||
{ | ||
function ConnectionConfig(options, validateCredentials, qaMode, clientInfo) { | ||
// if no value is specified for the validate credentials flag, default to true | ||
if (!Util.exists(validateCredentials)) | ||
{ | ||
if (!Util.exists(validateCredentials)) { | ||
validateCredentials = true; | ||
@@ -163,9 +149,7 @@ } | ||
// only validate credentials if necessary | ||
if (validateCredentials) | ||
{ | ||
if (validateCredentials) { | ||
// username is not required for oauth and external browser authenticators | ||
if (!Util.exists(options.authenticator) || | ||
(options.authenticator !== authenticationTypes.OAUTH_AUTHENTICATOR && | ||
options.authenticator !== authenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR)) | ||
{ | ||
options.authenticator !== authenticationTypes.EXTERNAL_BROWSER_AUTHENTICATOR)) { | ||
// check for missing username | ||
@@ -176,4 +160,3 @@ Errors.checkArgumentExists(Util.exists(options.username), | ||
if (Util.exists(options.username)) | ||
{ | ||
if (Util.exists(options.username)) { | ||
// check for invalid username | ||
@@ -186,11 +169,10 @@ Errors.checkArgumentValid(Util.isString(options.username), | ||
if (!Util.exists(options.authenticator) || | ||
options.authenticator == authenticationTypes.DEFAULT_AUTHENTICATOR) | ||
{ | ||
options.authenticator === authenticationTypes.DEFAULT_AUTHENTICATOR) { | ||
// check for missing password | ||
Errors.checkArgumentExists(Util.exists(options.password), | ||
ErrorCodes.ERR_CONN_CREATE_MISSING_PASSWORD); | ||
ErrorCodes.ERR_CONN_CREATE_MISSING_PASSWORD); | ||
// check for invalid password | ||
Errors.checkArgumentValid(Util.isString(options.password), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_PASSWORD); | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_PASSWORD); | ||
} | ||
@@ -209,13 +191,12 @@ | ||
var proxyHost = options.proxyHost; | ||
var proxyPort = options.proxyPort; | ||
var proxyUser = options.proxyUser; | ||
var proxyPassword = options.proxyPassword; | ||
var proxyProtocol = options.proxyProtocol || 'http'; | ||
var noProxy = options.noProxy; | ||
const proxyHost = options.proxyHost; | ||
const proxyPort = options.proxyPort; | ||
const proxyUser = options.proxyUser; | ||
const proxyPassword = options.proxyPassword; | ||
const proxyProtocol = options.proxyProtocol || 'http'; | ||
const noProxy = options.noProxy; | ||
// if we're running in node and some proxy information is specified | ||
var proxy; | ||
if (Util.isNode() && (Util.exists(proxyHost) || Util.exists(proxyPort))) | ||
{ | ||
let proxy; | ||
if (Util.isNode() && (Util.exists(proxyHost) || Util.exists(proxyPort))) { | ||
// check for missing proxyHost | ||
@@ -237,11 +218,9 @@ Errors.checkArgumentExists(Util.exists(proxyHost), | ||
if (Util.exists(noProxy)) | ||
{ | ||
// check for invalid noProxy | ||
Errors.checkArgumentValid(Util.isString(noProxy), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_NO_PROXY); | ||
} | ||
if (Util.exists(noProxy)) { | ||
// check for invalid noProxy | ||
Errors.checkArgumentValid(Util.isString(noProxy), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_NO_PROXY); | ||
} | ||
if (Util.exists(proxyUser) || Util.exists(proxyPassword)) | ||
{ | ||
if (Util.exists(proxyUser) || Util.exists(proxyPassword)) { | ||
// check for missing proxyUser | ||
@@ -272,5 +251,3 @@ Errors.checkArgumentExists(Util.exists(proxyUser), | ||
}; | ||
} | ||
else | ||
{ | ||
} else { | ||
proxy = | ||
@@ -286,12 +263,9 @@ { | ||
var serviceName = options.serviceName; | ||
var authenticator = options.authenticator; | ||
const serviceName = options.serviceName; | ||
let authenticator = options.authenticator; | ||
// if no value is specified for authenticator, default to Snowflake | ||
if (!Util.exists(authenticator)) | ||
{ | ||
if (!Util.exists(authenticator)) { | ||
authenticator = authenticationTypes.DEFAULT_AUTHENTICATOR; | ||
} | ||
else | ||
{ | ||
} else { | ||
authenticator = authenticator.toUpperCase(); | ||
@@ -308,5 +282,4 @@ } | ||
var privateKey = options.privateKey; | ||
if (Util.exists(options.privateKey)) | ||
{ | ||
const privateKey = options.privateKey; | ||
if (Util.exists(options.privateKey)) { | ||
Errors.checkArgumentValid((Util.isString(privateKey) && Util.isPrivateKey(privateKey)), | ||
@@ -316,5 +289,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_PRIVATE_KEY); | ||
var privateKeyPath = options.privateKeyPath; | ||
if (Util.exists(options.privateKeyPath)) | ||
{ | ||
const privateKeyPath = options.privateKeyPath; | ||
if (Util.exists(options.privateKeyPath)) { | ||
Errors.checkArgumentValid(Util.isString(privateKeyPath), | ||
@@ -324,5 +296,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_PRIVATE_KEY_PATH); | ||
var privateKeyPass = options.privateKeyPass; | ||
if (Util.exists(options.privateKeyPass)) | ||
{ | ||
const privateKeyPass = options.privateKeyPass; | ||
if (Util.exists(options.privateKeyPass)) { | ||
Errors.checkArgumentValid(Util.isString(privateKeyPass), | ||
@@ -332,5 +303,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_PRIVATE_KEY_PASS); | ||
var token = options.token; | ||
if (Util.exists(options.token)) | ||
{ | ||
const token = options.token; | ||
if (Util.exists(options.token)) { | ||
Errors.checkArgumentValid(Util.isString(token), | ||
@@ -340,10 +310,9 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_OAUTH_TOKEN); | ||
var warehouse = options.warehouse; | ||
var database = options.database; | ||
var schema = options.schema; | ||
var role = options.role; | ||
const warehouse = options.warehouse; | ||
const database = options.database; | ||
const schema = options.schema; | ||
const role = options.role; | ||
// check for invalid warehouse | ||
if (Util.exists(warehouse)) | ||
{ | ||
if (Util.exists(warehouse)) { | ||
Errors.checkArgumentValid(Util.isString(warehouse), | ||
@@ -354,4 +323,3 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_WAREHOUSE); | ||
// check for invalid database | ||
if (Util.exists(database)) | ||
{ | ||
if (Util.exists(database)) { | ||
Errors.checkArgumentValid(Util.isString(database), | ||
@@ -362,4 +330,3 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_DATABASE); | ||
// check for invalid schema | ||
if (Util.exists(schema)) | ||
{ | ||
if (Util.exists(schema)) { | ||
Errors.checkArgumentValid(Util.isString(schema), | ||
@@ -370,4 +337,3 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_SCHEMA); | ||
// check for invalid role | ||
if (Util.exists(role)) | ||
{ | ||
if (Util.exists(role)) { | ||
Errors.checkArgumentValid(Util.isString(role), | ||
@@ -378,5 +344,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_ROLE); | ||
// check for invalid streamResult | ||
var streamResult = options.streamResult; | ||
if (Util.exists(streamResult)) | ||
{ | ||
const streamResult = options.streamResult; | ||
if (Util.exists(streamResult)) { | ||
Errors.checkArgumentValid(Util.isBoolean(streamResult), | ||
@@ -387,5 +352,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_STREAM_RESULT); | ||
// check for invalid fetchAsString | ||
var fetchAsString = options.fetchAsString; | ||
if (Util.exists(fetchAsString)) | ||
{ | ||
const fetchAsString = options.fetchAsString; | ||
if (Util.exists(fetchAsString)) { | ||
// check that the value is an array | ||
@@ -396,3 +360,3 @@ Errors.checkArgumentValid(Util.isArray(fetchAsString), | ||
// check that all the array elements are valid | ||
var invalidValueIndex = NativeTypes.findInvalidValue(fetchAsString); | ||
const invalidValueIndex = NativeTypes.findInvalidValue(fetchAsString); | ||
Errors.checkArgumentValid(invalidValueIndex === -1, | ||
@@ -409,5 +373,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_FETCH_AS_STRING_VALUES, | ||
// check for invalid clientSessionKeepAlive | ||
var clientSessionKeepAlive = options.clientSessionKeepAlive; | ||
if (Util.exists(clientSessionKeepAlive)) | ||
{ | ||
const clientSessionKeepAlive = options.clientSessionKeepAlive; | ||
if (Util.exists(clientSessionKeepAlive)) { | ||
Errors.checkArgumentValid(Util.isBoolean(clientSessionKeepAlive), | ||
@@ -418,5 +381,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_KEEP_ALIVE); | ||
// check for invalid clientSessionKeepAliveHeartbeatFrequency | ||
var clientSessionKeepAliveHeartbeatFrequency = options.clientSessionKeepAliveHeartbeatFrequency; | ||
if (Util.exists(clientSessionKeepAliveHeartbeatFrequency)) | ||
{ | ||
let clientSessionKeepAliveHeartbeatFrequency = options.clientSessionKeepAliveHeartbeatFrequency; | ||
if (Util.exists(clientSessionKeepAliveHeartbeatFrequency)) { | ||
Errors.checkArgumentValid(Util.isNumber(clientSessionKeepAliveHeartbeatFrequency), | ||
@@ -428,5 +390,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_KEEP_ALIVE_HEARTBEAT_FREQ); | ||
var jsTreatIntegerAsBigInt = options.jsTreatIntegerAsBigInt; | ||
if (Util.exists(jsTreatIntegerAsBigInt)) | ||
{ | ||
const jsTreatIntegerAsBigInt = options.jsTreatIntegerAsBigInt; | ||
if (Util.exists(jsTreatIntegerAsBigInt)) { | ||
Errors.checkArgumentValid(Util.isBoolean(jsTreatIntegerAsBigInt), | ||
@@ -436,5 +397,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_TREAT_INTEGER_AS_BIGINT); | ||
var gcsUseDownscopedCredential = options.gcsUseDownscopedCredential; | ||
if (Util.exists(gcsUseDownscopedCredential)) | ||
{ | ||
const gcsUseDownscopedCredential = options.gcsUseDownscopedCredential; | ||
if (Util.exists(gcsUseDownscopedCredential)) { | ||
Errors.checkArgumentValid(Util.isBoolean(gcsUseDownscopedCredential), | ||
@@ -444,3 +404,3 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_GCS_USE_DOWNSCOPED_CREDENTIAL); | ||
var clientConfigFile = options.clientConfigFile; | ||
const clientConfigFile = options.clientConfigFile; | ||
if (Util.exists(clientConfigFile)) { | ||
@@ -454,8 +414,7 @@ Errors.checkArgumentValid(Util.isString(clientConfigFile), ErrorCodes.ERR_CONN_CREATE_INVALID_CLIENT_CONFIG_FILE); | ||
// if a client-info argument is specified, validate it | ||
var clientType = 'JavaScript'; | ||
var clientName; | ||
var clientVersion; | ||
var clientEnvironment; | ||
if (Util.exists(clientInfo)) | ||
{ | ||
const clientType = 'JavaScript'; | ||
let clientName; | ||
let clientVersion; | ||
let clientEnvironment; | ||
if (Util.exists(clientInfo)) { | ||
Errors.assertInternal(Util.isObject(clientInfo)); | ||
@@ -473,5 +432,4 @@ Errors.assertInternal(Util.isString(clientInfo.version)); | ||
var clientApplication = options.application; | ||
if (Util.exists(clientApplication)) | ||
{ | ||
const clientApplication = options.application; | ||
if (Util.exists(clientApplication)) { | ||
Errors.checkArgumentValid(Util.isString(clientApplication), | ||
@@ -487,5 +445,4 @@ ErrorCodes.ERR_CONN_CREATE_INVALID_APPLICATION); | ||
var validateDefaultParameters = false; | ||
if (Util.exists(options.validateDefaultParameters)) | ||
{ | ||
let validateDefaultParameters = false; | ||
if (Util.exists(options.validateDefaultParameters)) { | ||
// check for invalid validateDefaultParameters | ||
@@ -498,8 +455,7 @@ Errors.checkArgumentValid(Util.isBoolean(options.validateDefaultParameters), | ||
var bindThreshold = null; | ||
if (Util.exists(options.arrayBindingThreshold)) | ||
{ | ||
let bindThreshold = null; | ||
if (Util.exists(options.arrayBindingThreshold)) { | ||
// check for invalid arrayBindingThreshold | ||
Errors.checkArgumentValid(Util.isNumber(options.arrayBindingThreshold), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_ARRAY_BINDING_THRESHOLD); | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_ARRAY_BINDING_THRESHOLD); | ||
@@ -509,8 +465,7 @@ bindThreshold = options.arrayBindingThreshold; | ||
var forceStageBindError = null; | ||
if (Util.exists(options.forceStageBindError)) | ||
{ | ||
let forceStageBindError = null; | ||
if (Util.exists(options.forceStageBindError)) { | ||
// check for invalid forceStageBindError | ||
Errors.checkArgumentValid(Util.isNumber(options.forceStageBindError), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_FORCE_STAGE_BIND_ERROR); | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_FORCE_STAGE_BIND_ERROR); | ||
@@ -523,3 +478,3 @@ forceStageBindError = options.forceStageBindError; | ||
Errors.checkArgumentValid(Util.isBoolean(options.disableQueryContextCache), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_DISABLED_QUERY_CONTEXT_CACHE); | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_DISABLED_QUERY_CONTEXT_CACHE); | ||
@@ -532,3 +487,3 @@ disableQueryContextCache = options.disableQueryContextCache; | ||
Errors.checkArgumentValid(Util.isNumber(options.retryTimeout), | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_MAX_RETRY_TIMEOUT); | ||
ErrorCodes.ERR_CONN_CREATE_INVALID_MAX_RETRY_TIMEOUT); | ||
@@ -538,8 +493,5 @@ retryTimeout = options.retryTimeout !== 0 ? Math.max(retryTimeout, options.retryTimeout) : 0; | ||
if (validateDefaultParameters) | ||
{ | ||
for (const [key] of Object.entries(options)) | ||