@evervault/sdk
Advanced tools
Comparing version 5.1.6 to 6.0.0
@@ -6,5 +6,2 @@ const { version } = require('../package.json'); | ||
const DEFAULT_CA_HOSTNAME = 'https://ca.evervault.com'; | ||
const DEFAULT_CAGES_CA_HOSTNAME = 'https://cages-ca.evervault.com'; | ||
const DEFAULT_CAGES_BETA_HOSTNAME = 'cages.evervault.com'; | ||
const DEFAULT_CAGES_HOSTNAME = 'cage.evervault.com'; | ||
const DEFAULT_ENCLAVES_HOSTNAME = 'enclave.evervault.com'; | ||
@@ -16,3 +13,4 @@ const DEFAULT_POLL_INTERVAL = 5; | ||
module.exports = () => ({ | ||
/** @type {import('./types').MasterConfig} */ | ||
module.exports = { | ||
http: { | ||
@@ -23,7 +21,2 @@ baseUrl: process.env.EV_API_URL || DEFAULT_API_URL, | ||
certHostname: process.env.EV_CERT_HOSTNAME || DEFAULT_CA_HOSTNAME, | ||
cagesCertHostname: | ||
process.env.EV_CAGE_CERT_HOSTNAME || DEFAULT_CAGES_CA_HOSTNAME, | ||
cagesBetaHostname: | ||
process.env.EV_CAGES_BETA_HOSTNAME || DEFAULT_CAGES_BETA_HOSTNAME, | ||
cagesHostname: process.env.EV_CAGES_HOSTNAME || DEFAULT_CAGES_HOSTNAME, | ||
enclavesHostname: | ||
@@ -72,2 +65,2 @@ process.env.EV_ENCLAVES_HOSTNAME || DEFAULT_ENCLAVES_HOSTNAME, | ||
}, | ||
}); | ||
}; |
const RepeatedTimer = require('./repeatedTimer'); | ||
class AttestationDoc { | ||
constructor(config, http, cages, appUuid, hostname) { | ||
constructor(config, http, enclaves, appUuid, hostname) { | ||
this.appUuid = appUuid.replace(/_/g, '-'); | ||
this.http = http; | ||
this.cages = cages; | ||
this.enclaves = enclaves; | ||
this.config = config; | ||
@@ -28,19 +28,19 @@ this.polling = null; | ||
loadAttestationDoc = async (cageName) => { | ||
loadAttestationDoc = async (name) => { | ||
try { | ||
const response = await this.http.getAttestationDoc( | ||
cageName, | ||
name, | ||
this.appUuid, | ||
this.hostname | ||
); | ||
this.attestationDocCache[cageName] = response.attestation_doc; | ||
this.attestationDocCache[name] = response.attestation_doc; | ||
} catch (e) { | ||
console.warn(`Couldn't load attestation doc for ${cageName} ${e}`); | ||
console.warn(`Couldn't load attestation doc for ${name} ${e}`); | ||
} | ||
}; | ||
get = (cageName) => { | ||
const doc = this.attestationDocCache[cageName]; | ||
get = (name) => { | ||
const doc = this.attestationDocCache[name]; | ||
if (!doc) { | ||
console.warn(`No attestation doc found for ${cageName}`); | ||
console.warn(`No attestation doc found for ${name}`); | ||
} | ||
@@ -68,4 +68,4 @@ return doc; | ||
await Promise.all( | ||
this.cages.map(async (cageName) => { | ||
await this.loadAttestationDoc(cageName, this.appUuid); | ||
this.enclaves.map(async (name) => { | ||
await this.loadAttestationDoc(name, this.appUuid); | ||
}) | ||
@@ -72,0 +72,0 @@ ); |
@@ -23,2 +23,5 @@ const crypto = require('crypto'); | ||
/** | ||
* @param {import('../types').CurveConfig} config | ||
*/ | ||
module.exports = (config) => { | ||
@@ -25,0 +28,0 @@ let MAX_FILE_SIZE_IN_BYTES = config.maxFileSizeInMB * 1024 * 1024; |
@@ -5,2 +5,8 @@ const { errors, Datatypes } = require('../utils'); | ||
/** | ||
* @param {string} appUuid | ||
* @param {string} apiKey | ||
* @param {import('../types').HttpConfig} config | ||
* @returns | ||
*/ | ||
module.exports = (appUuid, apiKey, config) => { | ||
@@ -82,27 +88,5 @@ const request = ( | ||
const getCagesCert = async () => { | ||
const response = await phin({ | ||
url: `${config.cagesCertHostname}/cages-ca.crt`, | ||
method: 'GET', | ||
parse: 'cer', | ||
}) | ||
.catch(() => { | ||
// Blindly retry | ||
return phin({ | ||
url: config.cagesCertHostname, | ||
method: 'GET', | ||
parse: 'cer', | ||
}); | ||
}) | ||
.catch((err) => { | ||
throw new errors.EvervaultError( | ||
`Unable to download cert from ${config.cagesCertHostname} (${err.message})` | ||
); | ||
}); | ||
return response.body; | ||
}; | ||
const getAttestationDoc = async (cageName, appUuid, hostname) => { | ||
let url = `https://${cageName}.${appUuid}.${ | ||
hostname ? hostname : config.cagesHostname | ||
const getAttestationDoc = async (enclaveName, appUuid, hostname) => { | ||
let url = `https://${enclaveName}.${appUuid}.${ | ||
hostname ? hostname : config.enclavesHostname | ||
}/.well-known/attestation`; | ||
@@ -288,3 +272,2 @@ const response = await phin({ | ||
getCert, | ||
getCagesCert, | ||
createRunToken, | ||
@@ -291,0 +274,0 @@ getRelayOutboundConfig, |
@@ -15,11 +15,11 @@ const RepeatedTimer = require('./repeatedTimer'); | ||
const providers = {}; | ||
for (const [cageName, value] of Object.entries(attestationData)) { | ||
for (const [enclaveName, value] of Object.entries(attestationData)) { | ||
if (Array.isArray(value)) { | ||
providers[cageName] = staticPcrsToProvider(value); | ||
providers[enclaveName] = staticPcrsToProvider(value); | ||
} else if (typeof value === 'object') { | ||
providers[cageName] = staticPcrsToProvider([value]); | ||
providers[enclaveName] = staticPcrsToProvider([value]); | ||
} else if (typeof value === 'function') { | ||
providers[cageName] = { pcrs: [], provider: value }; | ||
providers[enclaveName] = { pcrs: [], provider: value }; | ||
} else { | ||
console.warn(`Invalid attestation data for ${cageName}.`); | ||
console.warn(`Invalid attestation data for ${enclaveName}.`); | ||
} | ||
@@ -31,5 +31,5 @@ } | ||
class CagePcrManager { | ||
constructor(config, cagesAttestationData) { | ||
this.store = loadPcrStore(cagesAttestationData); | ||
class PcrManager { | ||
constructor(config, attestationData) { | ||
this.store = loadPcrStore(attestationData); | ||
this.config = config; | ||
@@ -53,8 +53,8 @@ this.polling = null; | ||
fetchPcrs = async (cageName) => { | ||
const cage = this.store[cageName]; | ||
fetchPcrs = async (enclaveName) => { | ||
const enclave = this.store[enclaveName]; | ||
if (!cage || !cage.provider) { | ||
if (!enclave || !enclave.provider) { | ||
console.warn( | ||
`PCR provider for ${cageName} is not registered. Cannot fetch PCRs.` | ||
`PCR provider for ${enclaveName} is not registered. Cannot fetch PCRs.` | ||
); | ||
@@ -70,13 +70,13 @@ return; | ||
try { | ||
const newPcrs = await cage.provider(); | ||
const newPcrs = await enclave.provider(); | ||
if (!newPcrs) { | ||
console.warn( | ||
`PCR provider for ${cageName} did not return PCRs. Cannot fetch PCRs. Using old PCRs` | ||
`PCR provider for ${enclaveName} did not return PCRs. Cannot fetch PCRs. Using old PCRs` | ||
); | ||
} else { | ||
cage.pcrs = newPcrs; | ||
enclave.pcrs = newPcrs; | ||
} | ||
this.store[cageName] = cage; | ||
this.store[enclaveName] = enclave; | ||
break; | ||
@@ -86,3 +86,3 @@ } catch (error) { | ||
console.warn( | ||
`Couldn't fetch PCRs for ${cageName}. Retrying in ${delay} ms. Error: ${error}` | ||
`Couldn't fetch PCRs for ${enclaveName}. Retrying in ${delay} ms. Error: ${error}` | ||
); | ||
@@ -93,3 +93,3 @@ await new Promise((res) => setTimeout(res, delay)); | ||
console.warn( | ||
`Couldn't fetch PCRs after ${retries} retries for ${cageName}. Error: ${error}` | ||
`Couldn't fetch PCRs after ${retries} retries for ${enclaveName}. Error: ${error}` | ||
); | ||
@@ -101,5 +101,5 @@ } | ||
get = (cageName) => { | ||
const storedCageData = this.store[cageName]; | ||
const pcrs = storedCageData ? storedCageData.pcrs : undefined; | ||
get = (enclaveName) => { | ||
const storedAttestationData = this.store[enclaveName]; | ||
const pcrs = storedAttestationData ? storedAttestationData.pcrs : undefined; | ||
@@ -110,3 +110,3 @@ if (!pcrs) { | ||
// to make best effort to have the PCRs next time if they weren't available. | ||
this.fetchPcrs(cageName); | ||
this.fetchPcrs(enclaveName); | ||
} | ||
@@ -130,4 +130,4 @@ | ||
clearStoredPcrs = () => { | ||
for (const [cageName, value] of Object.entries(this.store)) { | ||
this.store[cageName] = { pcrs: null, provider: value.provider }; | ||
for (const [enclaveName, value] of Object.entries(this.store)) { | ||
this.store[enclaveName] = { pcrs: null, provider: value.provider }; | ||
} | ||
@@ -143,3 +143,3 @@ }; | ||
Object.keys(this.store).map( | ||
async (cageName) => await this.fetchPcrs(cageName) | ||
async (enclaveName) => await this.fetchPcrs(enclaveName) | ||
) | ||
@@ -150,2 +150,2 @@ ); | ||
module.exports = CagePcrManager; | ||
module.exports = PcrManager; |
@@ -0,2 +1,8 @@ | ||
const { InvalidInterval } = require('../utils/errors'); | ||
module.exports = (defaultInterval, cb) => { | ||
const parsedInterval = parseFloat(defaultInterval); | ||
if (Number.isNaN(parsedInterval)) { | ||
throw new InvalidInterval(`Expected number, received ${parsedInterval}`); | ||
} | ||
const createInterval = () => { | ||
@@ -3,0 +9,0 @@ const initializedInterval = setInterval(async () => { |
188
lib/index.js
@@ -13,3 +13,3 @@ const crypto = require('crypto'); | ||
} = require('./utils'); | ||
const Config = require('./config'); | ||
const config = require('./config'); | ||
const { | ||
@@ -23,3 +23,2 @@ Crypto, | ||
const { TokenCreationError } = require('./utils/errors'); | ||
const console = require('console'); | ||
const HttpsProxyAgent = require('./utils/proxyAgent'); | ||
@@ -29,11 +28,4 @@ | ||
/** | ||
* @typedef PCRs | ||
* @property {string | undefined} PCR0 | ||
* @property {string | undefined} PCR1 | ||
* @property {string | undefined} PCR2 | ||
* @property {string | undefined} PCR8 | ||
*/ | ||
class EvervaultClient { | ||
/** @type {{ [curveName: string]: import('./types').SupportedCurve }} */ | ||
static CURVES = { | ||
@@ -45,4 +37,18 @@ SECP256K1: 'secp256k1', | ||
/** @typedef {ReturnType<import('./core/repeatedTimer')>} Timer */ | ||
/** @type {{ enclaves: Timer[] | null, relayOutbound: Timer | null}} */ | ||
_backgroundJobs; | ||
/** @private @type {{ enclaves: Timer[] | null, relayOutbound: Timer | null}} */ _backgroundJobs; | ||
/** @private @type {string} */ apiKey; | ||
/** @private @type {string} */ appId; | ||
/** @private @type {import('./types')} */ config; | ||
/** @private @type {import('./types').SupportedCurve} */ curve; | ||
/** @private @type {ReturnType<import('./core/http')>} */ http; | ||
/** @private @type {import('./utils/httpsHelper')} */ httpsHelper; | ||
/** @private @type {boolean | undefined} */ retry; | ||
/** @private @type {ReturnType<import('./core/crypto')>} */ crypto; | ||
/** | ||
* @param {string} appId | ||
* @param {string} apiKey | ||
* @param {Partial<import('./types').SdkOptions & import('./types').OutboundRelayOptions>} options | ||
*/ | ||
constructor(appId, apiKey, options = {}) { | ||
@@ -68,3 +74,3 @@ if ( | ||
this.config = Config(apiKey); | ||
this.config = config; | ||
@@ -81,3 +87,3 @@ let curve; | ||
this.http = Http(appId, apiKey, this.config.http); | ||
this.crypto = Crypto(this.config.encryption[curve], this.http); | ||
this.crypto = Crypto(this.config.encryption[curve]); | ||
this.httpsHelper = httpsHelper; | ||
@@ -100,84 +106,32 @@ this.apiKey = apiKey; | ||
/** | ||
* @deprecated use enableEnclaves instead | ||
*/ | ||
async enableCagesBeta(cagesAttestationData) { | ||
if (attest.hasAttestationBindings()) { | ||
await attest.trustCagesRootCA(this.http); | ||
attest.addAttestationListenerBeta(this.config.http, cagesAttestationData); | ||
} else { | ||
console.error( | ||
'EVERVAULT ERROR :: Cannot enable Cages Beta without installing the Evervault attestation bindings' | ||
); | ||
} | ||
} | ||
/** | ||
* @deprecated use enableEnclaves instead | ||
*/ | ||
async enableCages(cagesAttestationData) { | ||
if (attest.hasAttestationBindings()) { | ||
//Store attestation documents from cages in cache | ||
let attestationCache = new AttestationDoc( | ||
this.config, | ||
this.http, | ||
Object.keys(cagesAttestationData), | ||
this.appId | ||
); | ||
const attestationCachePollingRef = await attestationCache.init(); | ||
this._backgroundJobs.enclaves = [attestationCachePollingRef]; | ||
//Store client PCR providers to periodically pull new PCRs | ||
const pcrManager = new PcrManager(this.config, cagesAttestationData); | ||
const pollingRef = await pcrManager.init(); | ||
this._backgroundJobs.enclaves.push(pollingRef); | ||
attest.addAttestationListener( | ||
this.config.http, | ||
attestationCache, | ||
pcrManager | ||
); | ||
} else { | ||
console.error( | ||
'EVERVAULT ERROR :: Cannot enable Cages without installing the Evervault attestation bindings' | ||
); | ||
} | ||
} | ||
/** | ||
* @param {{ [key: string]: PCRs | PCRs[] | (() => Promise<PCRs | PCRs[]>) }} attestationData | ||
* @param {Record<string, import('./types').AttestationData | import('./types').AttestationCallback>} attestationData | ||
* @param {import('./types').AttestationBindings} attestationBindings | ||
* @throws {import('./utils/errors').MalformedAttestationData} | ||
*/ | ||
async enableEnclaves(attestationData) { | ||
async enableEnclaves(attestationData, attestationBindings) { | ||
attest.validateAttestationData(attestationData); | ||
if (attest.hasAttestationBindings()) { | ||
//Store attestation documents in cache | ||
let attestationCache = new AttestationDoc( | ||
this.config, | ||
this.http, | ||
Object.keys(attestationData), | ||
this.appId, | ||
this.config.http.enclavesHostname | ||
); | ||
// Store attestation documents in cache | ||
let attestationCache = new AttestationDoc( | ||
this.config, | ||
this.http, | ||
Object.keys(attestationData), | ||
this.appId, | ||
this.config.http.enclavesHostname | ||
); | ||
const attestationCachePollingRef = await attestationCache.init(); | ||
this._backgroundJobs.enclaves = [attestationCachePollingRef]; | ||
const attestationCachePollingRef = await attestationCache.init(); | ||
this._backgroundJobs.enclaves = [attestationCachePollingRef]; | ||
//Store client PCR providers to periodically pull new PCRs | ||
const pcrManager = new PcrManager(this.config, attestationData); | ||
//Store client PCR providers to periodically pull new PCRs | ||
const pcrManager = new PcrManager(this.config, attestationData); | ||
const pcrManagerPollingRef = await pcrManager.init(); | ||
this._backgroundJobs.enclaves.push(pcrManagerPollingRef); | ||
const pcrManagerPollingRef = await pcrManager.init(); | ||
this._backgroundJobs.enclaves.push(pcrManagerPollingRef); | ||
attest.addAttestationListener( | ||
this.config.http, | ||
attestationCache, | ||
pcrManager | ||
); | ||
} else { | ||
console.error( | ||
'EVERVAULT ERROR :: Cannot enable Enclaves without installing the Evervault attestation bindings' | ||
); | ||
} | ||
attest.addAttestationListener( | ||
this.config.http, | ||
attestationCache, | ||
pcrManager, | ||
attestationBindings | ||
); | ||
} | ||
@@ -193,2 +147,3 @@ | ||
/** @returns {Promise<string>} */ | ||
async generateNonce() { | ||
@@ -199,2 +154,8 @@ const nonce = await this.crypto.generateBytes(16); | ||
/** | ||
* @private | ||
* @param {Partial<import('./types').SdkOptions & import('./types').OutboundRelayOptions>} options | ||
* @param {string} apiKey | ||
* @returns {Promise<void>} | ||
*/ | ||
async _shouldOverloadHttpModule(options, apiKey) { | ||
@@ -227,11 +188,18 @@ if (options.decryptionDomains && options.decryptionDomains.length > 0) { | ||
/** | ||
* @private | ||
* @returns {string[]} | ||
*/ | ||
_alwaysIgnoreDomains() { | ||
const caHost = new URL(this.config.http.certHostname).host; | ||
const apiHost = new URL(this.config.http.baseUrl).host; | ||
const cagesCaHost = new URL(this.config.http.cagesCertHostname).host; | ||
const cagesHost = this.config.http.cagesHostname; | ||
return [cagesCaHost, caHost, apiHost, cagesHost]; | ||
return [caHost, apiHost, this.config.http.enclavesHostname]; | ||
} | ||
/** | ||
* @private | ||
* @param {string[]} decryptionDomains | ||
* @returns {(domain: string) => boolean} | ||
*/ | ||
_decryptionDomainsFilter(decryptionDomains) { | ||
@@ -246,2 +214,8 @@ return (domain) => | ||
/** | ||
* @private | ||
* @param {string} domain | ||
* @param {string[]} decryptionDomains | ||
* @param {string[]} alwaysIgnore | ||
*/ | ||
_isDecryptionDomain(domain, decryptionDomains, alwaysIgnore) { | ||
@@ -259,2 +233,3 @@ if (alwaysIgnore.includes(domain)) return false; | ||
/** @private @returns {(domain: string) => boolean} */ | ||
_relayOutboundConfigDomainFilter() { | ||
@@ -270,2 +245,9 @@ return (domain) => { | ||
/** | ||
* @private | ||
* @param {string} domain | ||
* @param {string[]} exactDomains | ||
* @param {string[]} endsWithDomains | ||
* @returns {boolean} | ||
*/ | ||
_exactOrEndsWith(domain, exactDomains, endsWithDomains) { | ||
@@ -279,2 +261,6 @@ if (exactDomains.includes(domain)) return true; | ||
/** | ||
* @private | ||
* @param {string | undefined} role | ||
*/ | ||
_refreshKeys(role) { | ||
@@ -356,3 +342,2 @@ this._ecdh.generateKeys(); | ||
/** | ||
* | ||
* @param {any} encryptedData | ||
@@ -366,5 +351,4 @@ * @returns {Promise<any>} | ||
/** | ||
* @param {String} functionName | ||
* @param {Object} payload | ||
* @param {Object} [options] | ||
* @param {string} functionName | ||
* @param {object} payload | ||
* @returns {Promise<*>} | ||
@@ -391,4 +375,4 @@ */ | ||
/** | ||
* @param {String} functionName | ||
* @param {Object} payload | ||
* @param {string} functionName | ||
* @param {object} payload | ||
* @returns {Promise<*>} | ||
@@ -404,2 +388,5 @@ */ | ||
/** | ||
* @param {import('./types').OutboundRelayOptions} options | ||
*/ | ||
async enableOutboundRelay(options = {}) { | ||
@@ -461,2 +448,7 @@ validationHelper.validateRelayOutboundOptions(options); | ||
/** | ||
* @private | ||
* @param {string | number | symbol} property | ||
* @param {*} value | ||
*/ | ||
defineHiddenProperty(property, value) { | ||
@@ -463,0 +455,0 @@ Object.defineProperty(this, property, { |
@@ -1,97 +0,34 @@ | ||
const certHelper = require('./certHelper'); | ||
const { CageAttestationError, MalformedAttestationData } = require('./errors'); | ||
const { AttestationError, MalformedAttestationData } = require('./errors'); | ||
const tls = require('tls'); | ||
const origCreateSecureContext = tls.createSecureContext; | ||
const origCheckServerIdentity = tls.checkServerIdentity; | ||
const attestationBindings = loadAttestationBindings(); | ||
function loadAttestationBindings() { | ||
try { | ||
return require('evervault-attestation-bindings'); | ||
} catch (_) { | ||
return null; | ||
} | ||
} | ||
function hasAttestationBindings() { | ||
return attestationBindings != null; | ||
} | ||
async function trustCagesRootCA(evClient) { | ||
const pem = await evClient.getCagesCert(); | ||
let cert = pem.toString(); | ||
x509 = certHelper.parseX509(cert); | ||
tls.createSecureContext = (options) => { | ||
const context = origCreateSecureContext(options); | ||
context.context.addCACert(pem); | ||
return context; | ||
}; | ||
} | ||
function parseCageNameAndAppFromHost(hostname) { | ||
function parseNameAndAppFromHost(hostname) { | ||
const hostnameTokens = hostname.split('.'); | ||
// Check if nonce prefix is present | ||
if (hostnameTokens[1] === 'attest') { | ||
return { cageName: hostnameTokens[2], appUuid: hostnameTokens[3] }; | ||
return { name: hostnameTokens[2], appUuid: hostnameTokens[3] }; | ||
} else { | ||
return { cageName: hostnameTokens[0], appUuid: hostnameTokens[1] }; | ||
return { name: hostnameTokens[0], appUuid: hostnameTokens[1] }; | ||
} | ||
} | ||
function attestCageConnectionBeta(hostname, cert, cagesAttestationInfo = {}) { | ||
try { | ||
if (!hasAttestationBindings()) { | ||
throw new CageAttestationError( | ||
'Cage attestation bindings have not been installed.', | ||
hostname, | ||
cert | ||
); | ||
} | ||
// Pull cage name from cage hostname | ||
const { cageName } = parseCageNameAndAppFromHost(hostname); | ||
// check if PCRs for this cage have been given | ||
const pcrs = cagesAttestationInfo[cageName]; | ||
var pcrsList = []; | ||
if (Array.isArray(pcrs)) { | ||
pcrsList = pcrs; | ||
} else if (typeof pcrs === 'object') { | ||
pcrsList = [pcrs]; | ||
} | ||
const isConnectionValid = attestationBindings.attestConnection( | ||
cert.raw, | ||
pcrsList | ||
); | ||
if (!isConnectionValid) { | ||
console.warn( | ||
`EVERVAULT WARN :: Connection to Cage ${cageName} failed attestation` | ||
); | ||
throw new CageAttestationError( | ||
`Attestation to ${cageName} failed`, | ||
hostname, | ||
cert | ||
); | ||
} | ||
} catch (err) { | ||
console.error( | ||
`EVERVAULT ERROR :: An unexpected error occurred while attempting to attest a connection to your Cage`, | ||
err.message | ||
); | ||
return err; | ||
} | ||
} | ||
function attestCageConnection( | ||
/** | ||
* @param {string} hostname | ||
* @param {Buffer} cert | ||
* @param {import('../core/pcrManager')} pcrManager | ||
* @param {import('../core/attestationDoc')} attestationCache | ||
* @param {import('../types').AttestationBindings} attestationBindings | ||
* @returns {Error | undefined} | ||
*/ | ||
function attestConnection( | ||
hostname, | ||
cert, | ||
cagePcrManager, | ||
attestationCache | ||
attestationCache, | ||
attestationBindings | ||
) { | ||
try { | ||
if (!hasAttestationBindings()) { | ||
throw new CageAttestationError( | ||
'Cage attestation bindings have not been installed.', | ||
if (!attestationBindings == null) { | ||
throw new AttestationError( | ||
'Enclave attestation bindings have not been installed.', | ||
hostname, | ||
@@ -102,6 +39,6 @@ cert | ||
// Pull cage name from cage hostname | ||
const { cageName } = parseCageNameAndAppFromHost(hostname); | ||
const { name } = parseNameAndAppFromHost(hostname); | ||
// check if PCRs for this cage have been given | ||
const pcrs = cagePcrManager.get(cageName); | ||
const pcrs = cagePcrManager.get(name); | ||
var pcrsList = []; | ||
@@ -114,7 +51,7 @@ if (Array.isArray(pcrs)) { | ||
let attestationDoc = attestationCache.get(cageName); | ||
let attestationDoc = attestationCache.get(name); | ||
let attestationDocBytes = Buffer.from(attestationDoc, 'base64'); | ||
let isConnectionValid = attestationBindings.attestCage( | ||
let isConnectionValid = attestationBindings.attestEnclave( | ||
cert, | ||
@@ -127,6 +64,6 @@ pcrsList, | ||
console.warn( | ||
`EVERVAULT WARN :: Connection to Cage ${cageName} failed attestation` | ||
`EVERVAULT WARN :: Connection to Enclave ${name} failed attestation` | ||
); | ||
throw new CageAttestationError( | ||
`Attestation to ${cageName} failed`, | ||
throw new AttestationError( | ||
`Attestation to ${name} failed`, | ||
hostname, | ||
@@ -138,3 +75,3 @@ cert | ||
console.error( | ||
`EVERVAULT ERROR :: An unexpected error occurred while attempting to attest a connection to your Cage`, | ||
`EVERVAULT ERROR :: An unexpected error occurred while attempting to attest a connection to your Enclave`, | ||
err.message | ||
@@ -146,34 +83,30 @@ ); | ||
function addAttestationListenerBeta(config, cagesAttestationInfo) { | ||
/** | ||
* | ||
* @param {import('../types').HttpConfig} config | ||
* @param {import('../core/attestationDoc')} attestationCache | ||
* @param {import('../core/pcrManager')} pcrManager | ||
* @param {import('../types').AttestationBindings} attestationBindings | ||
*/ | ||
function addAttestationListener( | ||
config, | ||
attestationCache, | ||
pcrManager, | ||
attestationBindings | ||
) { | ||
/** | ||
* @param {string} hostname | ||
* @param {import('node:tls').PeerCertificate} cert | ||
* @returns {Error | undefined} | ||
*/ | ||
tls.checkServerIdentity = function (hostname, cert) { | ||
// only attempt attestation if the host is a cage | ||
if (hostname.endsWith(config.cagesBetaHostname)) { | ||
if (hostname.endsWith(config.enclavesHostname)) { | ||
// we expect undefined when attestation is successful, else an error | ||
const attestationResult = attestCageConnectionBeta( | ||
const attestationResult = attestConnection( | ||
hostname, | ||
cert, | ||
cagesAttestationInfo | ||
); | ||
if (attestationResult != null) { | ||
return attestationResult; | ||
} | ||
} | ||
// always perform base checks | ||
return origCheckServerIdentity(hostname, cert); | ||
}; | ||
} | ||
function addAttestationListener(config, attestationCache, pcrManager) { | ||
tls.checkServerIdentity = function (hostname, cert) { | ||
// only attempt attestation if the host is a cage | ||
if ( | ||
hostname.endsWith(config.cagesHostname) || | ||
hostname.endsWith(config.enclavesHostname) | ||
) { | ||
// we expect undefined when attestation is successful, else an error | ||
const attestationResult = attestCageConnection( | ||
hostname, | ||
cert.raw, | ||
pcrManager, | ||
attestationCache | ||
attestationCache, | ||
attestationBindings | ||
); | ||
@@ -222,10 +155,6 @@ | ||
module.exports = { | ||
trustCagesRootCA, | ||
attestConnection, | ||
addAttestationListener, | ||
attestCageConnection, | ||
parseCageNameAndAppFromHost, | ||
hasAttestationBindings, | ||
addAttestationListenerBeta, | ||
attestCageConnectionBeta, | ||
parseNameAndAppFromHost, | ||
validateAttestationData, | ||
}; |
@@ -20,3 +20,3 @@ class EvervaultError extends Error { | ||
class CageAttestationError extends EvervaultError { | ||
class AttestationError extends EvervaultError { | ||
constructor(reason, host, cert) { | ||
@@ -35,2 +35,8 @@ super(reason); | ||
class InvalidInterval extends EvervaultError { | ||
constructor(reason) { | ||
super(`Invalid interval provided to repeated timer. ${reason}`); | ||
} | ||
} | ||
class ExceededMaxFileSizeError extends EvervaultError {} | ||
@@ -65,3 +71,3 @@ | ||
return new EvervaultError( | ||
body.message || "IP is not present on the invoked Cage's whitelist." | ||
body.message || "IP is not present on the invoked Enclave's whitelist." | ||
); | ||
@@ -88,3 +94,3 @@ } | ||
mapFunctionFailureResponseToError, | ||
CageAttestationError, | ||
AttestationError, | ||
ExceededMaxFileSizeError, | ||
@@ -96,2 +102,3 @@ TokenCreationError, | ||
MalformedAttestationData, | ||
InvalidInterval, | ||
}; |
@@ -40,3 +40,3 @@ const https = require('https'); | ||
/** | ||
* @param {String} apiKey | ||
* @param {string} apiKey | ||
* @returns {void} | ||
@@ -43,0 +43,0 @@ */ |
module.exports = { | ||
Datatypes: require('./datatypes'), | ||
errors: require('./errors'), | ||
cageLock: require('./cagelock'), | ||
certHelper: require('./certHelper'), | ||
environment: require('./environment'), | ||
certHelper: require('./certHelper'), | ||
validationHelper: require('./validationHelper'), | ||
@@ -8,0 +7,0 @@ httpsHelper: require('./httpsHelper'), |
{ | ||
"name": "@evervault/sdk", | ||
"version": "5.1.6", | ||
"version": "6.0.0", | ||
"description": "Node.js SDK for Evervault", | ||
"main": "lib/index.js", | ||
"typings": "lib/evervault.d.ts", | ||
"typings": "types/index.d.ts", | ||
"scripts": { | ||
@@ -13,3 +13,5 @@ "prepare": "husky install", | ||
"test:filter": "mocha 'tests/**/*.test.js' --grep", | ||
"test:coverage": "nyc --reporter=text npm run test" | ||
"test:coverage": "nyc --reporter=text npm run test", | ||
"prepublishOnly": "npm run generate-types", | ||
"generate-types": "tsc lib/*.js lib/**/*.js --declaration --allowJs --emitDeclarationOnly --allowSyntheticDefaultImports --outDir types" | ||
}, | ||
@@ -23,3 +25,5 @@ "repository": { | ||
"evervault", | ||
"cages" | ||
"enclaves", | ||
"encryption", | ||
"cryptography" | ||
], | ||
@@ -32,3 +36,4 @@ "author": "Evervault (https://evervault.com)", | ||
"files": [ | ||
"lib" | ||
"lib", | ||
"types" | ||
], | ||
@@ -59,3 +64,4 @@ "homepage": "https://github.com/evervault/evervault-node#readme", | ||
"sinon": "^9.0.2", | ||
"sinon-chai": "^3.5.0" | ||
"sinon-chai": "^3.5.0", | ||
"typescript": "^5.3.3" | ||
}, | ||
@@ -69,6 +75,3 @@ "release": { | ||
"**/*.js": "prettier --write --ignore-unknown \"./**/*.js\"" | ||
}, | ||
"optionalDependencies": { | ||
"evervault-attestation-bindings": "^0.3.2" | ||
} | ||
} |
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
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
89974
6
53
2791
9
16