@elastic/elasticsearch-canary
Advanced tools
Comparing version 8.0.0-canary.14 to 8.0.0-canary.15
14
index.js
@@ -105,2 +105,3 @@ /* | ||
ssl: null, | ||
caFingerprint: null, | ||
agent: null, | ||
@@ -120,2 +121,6 @@ headers: {}, | ||
if (options.caFingerprint !== null && isHttpConnection(opts.node || opts.nodes)) { | ||
throw new ConfigurationError('You can\'t configure the caFingerprint with a http connection') | ||
} | ||
if (process.env.ELASTIC_CLIENT_APIVERSIONING === 'true') { | ||
@@ -151,2 +156,3 @@ options.headers = Object.assign({ accept: 'application/vnd.elasticsearch+json; compatible-with=7' }, options.headers) | ||
emit: this[kEventEmitter].emit.bind(this[kEventEmitter]), | ||
caFingerprint: options.caFingerprint, | ||
sniffEnabled: options.sniffInterval !== false || | ||
@@ -321,2 +327,10 @@ options.sniffOnStart !== false || | ||
function isHttpConnection (node) { | ||
if (Array.isArray(node)) { | ||
return node.some((n) => new URL(n).protocol === 'http:') | ||
} else { | ||
return new URL(node).protocol === 'http:' | ||
} | ||
} | ||
const events = { | ||
@@ -323,0 +337,0 @@ RESPONSE: 'response', |
@@ -43,2 +43,3 @@ /* | ||
proxy?: string | URL; | ||
caFingerprint?: string; | ||
} | ||
@@ -45,0 +46,0 @@ |
@@ -45,2 +45,3 @@ /* | ||
this.resurrectTimeout = 0 | ||
this.caFingerprint = opts.caFingerprint | ||
@@ -127,2 +128,25 @@ this._openRequests = 0 | ||
const onSocket = socket => { | ||
/* istanbul ignore else */ | ||
if (!socket.isSessionReused()) { | ||
socket.once('secureConnect', () => { | ||
const issuerCertificate = getIssuerCertificate(socket) | ||
/* istanbul ignore next */ | ||
if (issuerCertificate == null) { | ||
onError(new Error('Invalid or malformed certificate')) | ||
request.once('error', () => {}) // we need to catch the request aborted error | ||
return request.abort() | ||
} | ||
// Check if fingerprint matches | ||
/* istanbul ignore else */ | ||
if (this.caFingerprint !== issuerCertificate.fingerprint256) { | ||
onError(new Error('Server certificate CA fingerprint does not match the value configured in caFingerprint')) | ||
request.once('error', () => {}) // we need to catch the request aborted error | ||
return request.abort() | ||
} | ||
}) | ||
} | ||
} | ||
request.on('response', onResponse) | ||
@@ -132,2 +156,5 @@ request.on('timeout', onTimeout) | ||
request.on('abort', onAbort) | ||
if (this.caFingerprint != null) { | ||
request.on('socket', onSocket) | ||
} | ||
@@ -158,2 +185,3 @@ // Disables the Nagle algorithm | ||
request.removeListener('abort', onAbort) | ||
request.removeListener('socket', onSocket) | ||
cleanedListeners = true | ||
@@ -347,3 +375,23 @@ } | ||
function getIssuerCertificate (socket) { | ||
let certificate = socket.getPeerCertificate(true) | ||
while (certificate && Object.keys(certificate).length > 0) { | ||
// invalid certificate | ||
if (certificate.issuerCertificate == null) { | ||
return null | ||
} | ||
// We have reached the root certificate. | ||
// In case of self-signed certificates, `issuerCertificate` may be a circular reference. | ||
if (certificate.fingerprint256 === certificate.issuerCertificate.fingerprint256) { | ||
break | ||
} | ||
// continue the loop | ||
certificate = certificate.issuerCertificate | ||
} | ||
return certificate | ||
} | ||
module.exports = Connection | ||
module.exports.internals = { prepareHeaders } | ||
module.exports.internals = { prepareHeaders, getIssuerCertificate } |
@@ -100,4 +100,6 @@ /* | ||
} | ||
} else if (typeof meta.body === 'object' && meta.body != null) { | ||
this.message = JSON.stringify(meta.body) | ||
} else { | ||
this.message = 'Response Error' | ||
this.message = meta.body || 'Response Error' | ||
} | ||
@@ -104,0 +106,0 @@ this.meta = meta |
@@ -39,2 +39,3 @@ /* | ||
this._proxy = opts.proxy || null | ||
this._caFingerprint = opts.caFingerprint || null | ||
} | ||
@@ -76,2 +77,4 @@ | ||
if (opts.proxy == null) opts.proxy = this._proxy | ||
/* istanbul ignore else */ | ||
if (opts.caFingerprint == null) opts.caFingerprint = this._caFingerprint | ||
@@ -78,0 +81,0 @@ const connection = new this.Connection(opts) |
@@ -34,2 +34,3 @@ /* | ||
Connection: typeof Connection; | ||
caFingerprint?: string; | ||
} | ||
@@ -36,0 +37,0 @@ |
@@ -158,6 +158,6 @@ /* | ||
constructor(opts: TransportOptions); | ||
request(params: TransportRequestParams, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse>; | ||
request(params: TransportRequestParams, options?: TransportRequestOptions, callback?: (err: ApiError, result: ApiResponse) => void): TransportRequestCallback; | ||
request<TResponse = Record<string, any>, TContext = Context>(params: TransportRequestParams, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TResponse, TContext>>; | ||
request<TResponse = Record<string, any>, TContext = Context>(params: TransportRequestParams, options?: TransportRequestOptions, callback?: (err: ApiError, result: ApiResponse<TResponse, TContext>) => void): TransportRequestCallback; | ||
getConnection(opts: TransportGetConnectionOptions): Connection | null; | ||
sniff(opts?: TransportSniffOptions, callback?: (...args: any[]) => void): void; | ||
} |
@@ -72,3 +72,3 @@ /* | ||
this.opaqueIdPrefix = opts.opaqueIdPrefix | ||
this[kProductCheck] = 0 // 0 = to be checked, 1 = checking, 2 = checked-ok, 3 checked-notok | ||
this[kProductCheck] = 0 // 0 = to be checked, 1 = checking, 2 = checked-ok, 3 checked-notok, 4 checked-nodefault | ||
this[kApiVersioning] = process.env.ELASTIC_CLIENT_APIVERSIONING === 'true' | ||
@@ -241,2 +241,3 @@ | ||
const isCompressed = contentEncoding.indexOf('gzip') > -1 || contentEncoding.indexOf('deflate') > -1 | ||
const isVectorTile = (result.headers['content-type'] || '').indexOf('application/vnd.mapbox-vector-tile') > -1 | ||
@@ -260,4 +261,5 @@ /* istanbul ignore else */ | ||
// as buffer for allowing decompression later | ||
let payload = isCompressed ? [] : '' | ||
const onData = isCompressed | ||
// while if it's a vector tile, we should return it as buffer | ||
let payload = isCompressed || isVectorTile ? [] : '' | ||
const onData = isCompressed || isVectorTile | ||
? chunk => { payload.push(chunk) } | ||
@@ -278,3 +280,3 @@ : chunk => { payload += chunk } | ||
} else { | ||
onBody(null, payload) | ||
onBody(null, isVectorTile ? Buffer.concat(payload) : payload) | ||
} | ||
@@ -288,3 +290,3 @@ } | ||
if (!isCompressed) { | ||
if (!isCompressed && !isVectorTile) { | ||
response.setEncoding('utf8') | ||
@@ -305,3 +307,5 @@ } | ||
} | ||
if (Buffer.isBuffer(payload)) { | ||
const isVectorTile = (result.headers['content-type'] || '').indexOf('application/vnd.mapbox-vector-tile') > -1 | ||
if (Buffer.isBuffer(payload) && !isVectorTile) { | ||
payload = payload.toString() | ||
@@ -464,5 +468,8 @@ } | ||
// wait for product check to finish | ||
productCheckEmitter.once('product-check', status => { | ||
productCheckEmitter.once('product-check', (error, status) => { | ||
if (status === false) { | ||
const err = new ProductNotSupportedError(result) | ||
const err = error || new ProductNotSupportedError(result) | ||
if (this[kProductCheck] === 4) { | ||
err.message = 'The client noticed that the server is not a supported distribution of Elasticsearch' | ||
} | ||
this.emit('request', err, result) | ||
@@ -480,4 +487,7 @@ process.nextTick(callback, err, result) | ||
// the product check is finished and it's not Elasticsearch | ||
} else if (this[kProductCheck] === 3) { | ||
} else if (this[kProductCheck] === 3 || this[kProductCheck] === 4) { | ||
const err = new ProductNotSupportedError(result) | ||
if (this[kProductCheck] === 4) { | ||
err.message = 'The client noticed that the server is not a supported distribution of Elasticsearch' | ||
} | ||
this.emit('request', err, result) | ||
@@ -561,6 +571,6 @@ process.nextTick(callback, err, result) | ||
process.emitWarning('The client is unable to verify that the server is Elasticsearch due to security privileges on the server side. Some functionality may not be compatible if the server is running an unsupported product.') | ||
productCheckEmitter.emit('product-check', true) | ||
productCheckEmitter.emit('product-check', null, true) | ||
} else { | ||
this[kProductCheck] = 0 | ||
productCheckEmitter.emit('product-check', false) | ||
productCheckEmitter.emit('product-check', err, false) | ||
} | ||
@@ -571,3 +581,3 @@ } else { | ||
debug('Can\'t access Elasticsearch version') | ||
return productCheckEmitter.emit('product-check', false) | ||
return productCheckEmitter.emit('product-check', null, false) | ||
} | ||
@@ -579,17 +589,23 @@ const tagline = result.body.tagline | ||
if (major < 6) { | ||
return productCheckEmitter.emit('product-check', false) | ||
return productCheckEmitter.emit('product-check', null, false) | ||
} else if (major >= 6 && major < 7) { | ||
if (tagline !== 'You Know, for Search') { | ||
debug('Bad tagline') | ||
return productCheckEmitter.emit('product-check', false) | ||
return productCheckEmitter.emit('product-check', null, false) | ||
} | ||
} else if (major === 7 && minor < 14) { | ||
if (tagline !== 'You Know, for Search' || result.body.version.build_flavor !== 'default') { | ||
debug('Bad tagline or build_flavor') | ||
return productCheckEmitter.emit('product-check', false) | ||
if (tagline !== 'You Know, for Search') { | ||
debug('Bad tagline') | ||
return productCheckEmitter.emit('product-check', null, false) | ||
} | ||
if (result.body.version.build_flavor !== 'default') { | ||
debug('Bad build_flavor') | ||
this[kProductCheck] = 4 | ||
return productCheckEmitter.emit('product-check', null, false) | ||
} | ||
} else { | ||
if (result.headers['x-elastic-product'] !== 'Elasticsearch') { | ||
debug('x-elastic-product not recognized') | ||
return productCheckEmitter.emit('product-check', false) | ||
return productCheckEmitter.emit('product-check', null, false) | ||
} | ||
@@ -599,3 +615,3 @@ } | ||
this[kProductCheck] = 2 | ||
productCheckEmitter.emit('product-check', true) | ||
productCheckEmitter.emit('product-check', null, true) | ||
} | ||
@@ -602,0 +618,0 @@ }) |
@@ -14,4 +14,4 @@ { | ||
"homepage": "http://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html", | ||
"version": "8.0.0-canary.14", | ||
"versionCanary": "8.0.0-canary.14", | ||
"version": "8.0.0-canary.15", | ||
"versionCanary": "8.0.0-canary.15", | ||
"keywords": [ | ||
@@ -104,5 +104,6 @@ "elasticsearch", | ||
"coverage": false, | ||
"jobs-auto": true | ||
"jobs-auto": true, | ||
"check-coverage": false | ||
}, | ||
"commitHash": "304d251c" | ||
"commitHash": "c100edcc" | ||
} |
@@ -57,4 +57,6 @@ <img align="right" width="auto" height="auto" src="https://www.elastic.co/static-res/images/elastic-logo-200.png"> | ||
The library is compatible with all Elasticsearch versions since 5.x, and you should use the same major version of the Elasticsearch instance that you are using. | ||
Elastic language clients are guaranteed to be able to communicate with Elasticsearch or Elastic solutions running on the same major version and greater or equal minor version. | ||
Language clients are forward compatible; meaning that clients support communicating with greater minor versions of Elasticsearch. Elastic language clients are not guaranteed to be backwards compatible. | ||
| Elasticsearch Version | Client Version | | ||
@@ -61,0 +63,0 @@ | --------------------- |----------------| |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
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
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
35989
233
1980638