@evervault/sdk
Advanced tools
Comparing version 4.2.0 to 4.3.0
@@ -11,2 +11,3 @@ const { version } = require('../package.json'); | ||
const DEFAULT_MAX_FILE_SIZE_IN_MB = 25; | ||
const DEFAULT_ATTEST_POLL_INTERVAL = 7200; | ||
@@ -24,2 +25,4 @@ module.exports = () => ({ | ||
pollInterval: process.env.EV_POLL_INTERVAL || DEFAULT_POLL_INTERVAL, | ||
attestationDocPollInterval: | ||
process.env.EV_ATTEST_POLL_INTERVAL || DEFAULT_ATTEST_POLL_INTERVAL, | ||
}, | ||
@@ -26,0 +29,0 @@ encryption: { |
@@ -25,9 +25,18 @@ const { errors, Datatypes } = require('../utils'); | ||
} | ||
return phin({ | ||
url: path.startsWith('https://') ? path : `${config.baseUrl}/${path}`, | ||
method, | ||
headers, | ||
data, | ||
parse, | ||
}); | ||
if (!additionalHeaders['x-async']) { | ||
return phin({ | ||
url: path.startsWith('https://') ? path : `${config.baseUrl}/${path}`, | ||
method, | ||
headers, | ||
data, | ||
parse, | ||
}); | ||
} else { | ||
return phin({ | ||
url: path.startsWith('https://') ? path : `${config.baseUrl}/${path}`, | ||
method, | ||
headers, | ||
data, | ||
}); | ||
} | ||
}; | ||
@@ -104,2 +113,25 @@ | ||
const getCageAttestationDoc = async (cageName, appUuid) => { | ||
let url = `https://${cageName}.${appUuid}.${config.cagesHostname}/.well-known/attestation`; | ||
const response = await phin({ | ||
url, | ||
method: 'GET', | ||
parse: 'json', | ||
}) | ||
.catch(() => { | ||
// Blindly retry | ||
return phin({ | ||
url, | ||
method: 'GET', | ||
parse: 'json', | ||
}); | ||
}) | ||
.catch((err) => { | ||
throw new errors.CertError( | ||
`Unable to download attestation doc from ${url} (${err.message})` | ||
); | ||
}); | ||
return response.body; | ||
}; | ||
const getRelayOutboundConfig = async () => { | ||
@@ -267,3 +299,4 @@ const response = await get('v2/relay-outbound').catch((e) => { | ||
createToken, | ||
getCageAttestationDoc, | ||
}; | ||
}; |
@@ -6,2 +6,3 @@ module.exports = { | ||
RelayOutboundConfig: require('./relayOutboundConfig'), | ||
AttestationDoc: require('./cageAttestationDoc'), | ||
}; |
@@ -1,14 +0,42 @@ | ||
import HttpsProxyAgent from "./utils/proxyAgent"; | ||
declare module "@evervault/sdk" { | ||
export default class Evervault { | ||
constructor(appId: string, apiKey: string) | ||
encrypt: (data: any) => Promise<any>; | ||
decrypt: (encryptedData: any) => Promise<any>; | ||
createClientSideDecryptToken: (payload: any, expiry?: Date) => Promise<{ id: string, token: string, createdAt: Date, expiry: Date }>; | ||
run: <T>(functionName: string, data: object, options?: { async?: boolean, version?: string }) => Promise<{ result: T, runId: string, appUuid: string }>; | ||
createRunToken: (functionName: string, data: object) => Promise<{ token: string }>; | ||
enableOutboundRelay: (options?: { decryptionDomains: string[], debugRequests: boolean }) => Promise<void>; | ||
enableCagesBeta: (cageAttestationData: Record<string, { pcr0?: string, pcr1?: string, pcr2?: string, pcr8?: string } | {pcr0?: string, pcr1?: string, pcr2?: string, pcr8?: string }[]>) => Promise<void>; | ||
createRelayHttpsAgent: () => HttpsProxyAgent; | ||
} | ||
declare module '@evervault/sdk' { | ||
export default class Evervault { | ||
constructor(appId: string, apiKey: string); | ||
encrypt: (data: any) => Promise<any>; | ||
decrypt: (encryptedData: any) => Promise<any>; | ||
createClientSideDecryptToken: ( | ||
payload: any, | ||
expiry?: Date | ||
) => Promise<{ id: string; token: string; createdAt: Date; expiry: Date }>; | ||
run: <T>( | ||
functionName: string, | ||
data: object, | ||
options?: { async?: boolean; version?: string } | ||
) => Promise<{ result: T; runId: string; appUuid: string }>; | ||
createRunToken: ( | ||
functionName: string, | ||
data: object | ||
) => Promise<{ token: string }>; | ||
enableOutboundRelay: (options: { | ||
decryptionDomains: string[]; | ||
debugRequests: boolean; | ||
}) => Promise<void>; | ||
/** | ||
* @deprecated use enableCages instead | ||
*/ | ||
enableCagesBeta: ( | ||
cageAttestationData: Record< | ||
string, | ||
| { pcr0?: string; pcr1?: string; pcr2?: string; pcr8?: string } | ||
| { pcr0?: string; pcr1?: string; pcr2?: string; pcr8?: string }[] | ||
> | ||
) => Promise<void>; | ||
createRelayHttpsAgent: () => HttpsProxyAgent; | ||
enableCages: ( | ||
cageAttestationData: Record< | ||
string, | ||
| { pcr0?: string; pcr1?: string; pcr2?: string; pcr8?: string } | ||
| { pcr0?: string; pcr1?: string; pcr2?: string; pcr8?: string }[] | ||
> | ||
) => Promise<void>; | ||
} | ||
} |
@@ -5,2 +5,3 @@ const crypto = require('crypto'); | ||
const { Buffer } = require('buffer'); | ||
const util = require('util'); | ||
@@ -10,4 +11,2 @@ const { | ||
errors, | ||
cageLock, | ||
environment, | ||
validationHelper, | ||
@@ -18,4 +17,5 @@ httpsHelper, | ||
const Config = require('./config'); | ||
const { Crypto, Http, RelayOutboundConfig } = require('./core'); | ||
const { Crypto, Http, RelayOutboundConfig, AttestationDoc } = require('./core'); | ||
const { TokenCreationError } = require('./utils/errors'); | ||
const console = require('console'); | ||
const HttpsProxyAgent = require('./utils/proxyAgent'); | ||
@@ -76,6 +76,12 @@ | ||
/** | ||
* @deprecated use enableCages instead | ||
*/ | ||
async enableCagesBeta(cagesAttestationData) { | ||
if (cageAttest.hasAttestationBindings()) { | ||
await cageAttest.trustCagesRootCA(this.http); | ||
cageAttest.addAttestationListener(this.config.http, cagesAttestationData); | ||
cageAttest.addAttestationListenerBeta( | ||
this.config.http, | ||
cagesAttestationData | ||
); | ||
} else { | ||
@@ -88,2 +94,23 @@ console.error( | ||
async enableCages(cagesAttestationData) { | ||
if (cageAttest.hasAttestationBindings()) { | ||
let attestationCache = new AttestationDoc( | ||
this.config, | ||
this.http, | ||
Object.keys(cagesAttestationData), | ||
this.appId | ||
); | ||
await attestationCache.init(); | ||
cageAttest.addAttestationListener( | ||
this.config.http, | ||
cagesAttestationData, | ||
attestationCache | ||
); | ||
} else { | ||
console.error( | ||
'EVERVAULT ERROR :: Cannot enable Cages without installing the Evervault attestation bindings' | ||
); | ||
} | ||
} | ||
async generateNonce() { | ||
@@ -90,0 +117,0 @@ const nonce = await this.crypto.generateBytes(16); |
@@ -32,13 +32,13 @@ const certHelper = require('./certHelper'); | ||
function parseCageNameFromHost(hostname) { | ||
function parseCageNameAndAppFromHost(hostname) { | ||
const hostnameTokens = hostname.split('.'); | ||
// Check if nonce prefix is present | ||
if (hostnameTokens[1] === 'attest') { | ||
return hostnameTokens[2]; | ||
return { cageName: hostnameTokens[2], appUuid: hostnameTokens[3] }; | ||
} else { | ||
return hostnameTokens[0]; | ||
return { cageName: hostnameTokens[0], appUuid: hostnameTokens[1] }; | ||
} | ||
} | ||
function attestCageConnection(hostname, cert, cagesAttestationInfo = {}) { | ||
function attestCageConnectionBeta(hostname, cert, cagesAttestationInfo = {}) { | ||
try { | ||
@@ -52,4 +52,5 @@ if (!hasAttestationBindings()) { | ||
} | ||
// Pull cage name from cage hostname | ||
const cageName = parseCageNameFromHost(hostname); | ||
const { cageName } = parseCageNameAndAppFromHost(hostname); | ||
// check if PCRs for this cage have been given | ||
@@ -63,2 +64,3 @@ const pcrs = cagesAttestationInfo[cageName]; | ||
} | ||
const isConnectionValid = attestationBindings.attestConnection( | ||
@@ -68,2 +70,3 @@ cert.raw, | ||
); | ||
if (!isConnectionValid) { | ||
@@ -88,3 +91,94 @@ console.warn( | ||
function addAttestationListener(config, cagesAttestationInfo) { | ||
async function attestCageConnection( | ||
hostname, | ||
cert, | ||
cagesAttestationInfo = {}, | ||
attestationCache | ||
) { | ||
try { | ||
if (!hasAttestationBindings()) { | ||
throw new CageAttestationError( | ||
'Cage attestation bindings have not been installed.', | ||
hostname, | ||
cert | ||
); | ||
} | ||
// Pull cage name from cage hostname | ||
const { cageName, appUuid } = 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]; | ||
} | ||
let attestationDoc = await attestationCache.get(cageName); | ||
if (!attestationDoc) { | ||
await attestationCache.loadCageDoc(cageName); | ||
attestationDoc = await attestationCache.get(cageName); | ||
if (!attestationDoc) { | ||
throw new CageAttestationError( | ||
"Couldn't find attestation doc in cache", | ||
hostname, | ||
cert | ||
); | ||
} | ||
} | ||
let attestationDocBytes = Buffer.from(attestationDoc, 'base64'); | ||
let isConnectionValid = attestationBindings.attestCage( | ||
cert, | ||
pcrsList, | ||
attestationDocBytes | ||
); | ||
// Reload cache to check if deployment has happened between polling | ||
if (!isConnectionValid) { | ||
attestationCache.loadCageDoc(cageName); | ||
isConnectionValid = await getCageAttestationDoc( | ||
cageName, | ||
cert, | ||
pcrsList, | ||
attestationCache | ||
); | ||
} | ||
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; | ||
} | ||
} | ||
async function getCageAttestationDoc( | ||
cageName, | ||
cert, | ||
pcrsList, | ||
attestationCache | ||
) { | ||
const attestationDoc = await attestationCache.get(cageName); | ||
if (!attestationDoc) { | ||
let attestationDocBytes = Buffer.from(attestationDoc, 'base64'); | ||
attestationBindings.attestCage(cert, pcrsList, attestationDocBytes); | ||
} else { | ||
console.warn(`No attestation doc found for ${cageName}`); | ||
false; | ||
} | ||
} | ||
function addAttestationListenerBeta(config, cagesAttestationInfo) { | ||
tls.checkServerIdentity = function (hostname, cert) { | ||
@@ -94,3 +188,3 @@ // only attempt attestation if the host is a cage | ||
// we expect undefined when attestation is successful, else an error | ||
const attestationResult = attestCageConnection( | ||
const attestationResult = attestCageConnectionBeta( | ||
hostname, | ||
@@ -109,2 +203,26 @@ cert, | ||
function addAttestationListener( | ||
config, | ||
cagesAttestationInfo, | ||
attestationCache | ||
) { | ||
tls.checkServerIdentity = function (hostname, cert) { | ||
// only attempt attestation if the host is a cage | ||
if (hostname.endsWith(config.cagesHostname)) { | ||
// we expect undefined when attestation is successful, else an error | ||
const attestationResult = attestCageConnection( | ||
hostname, | ||
cert.raw, | ||
cagesAttestationInfo, | ||
attestationCache | ||
); | ||
if (attestationResult != null) { | ||
return attestationResult; | ||
} | ||
} | ||
// always perform base checks | ||
return origCheckServerIdentity(hostname, cert); | ||
}; | ||
} | ||
module.exports = { | ||
@@ -114,4 +232,6 @@ trustCagesRootCA, | ||
attestCageConnection, | ||
parseCageNameFromHost, | ||
parseCageNameAndAppFromHost, | ||
hasAttestationBindings, | ||
addAttestationListenerBeta, | ||
attestCageConnectionBeta, | ||
}; |
{ | ||
"name": "@evervault/sdk", | ||
"version": "4.2.0", | ||
"version": "4.3.0", | ||
"description": "Node.js SDK for Evervault", | ||
@@ -11,2 +11,3 @@ "main": "lib/index.js", | ||
"test": "mocha 'tests/**/*.test.js'", | ||
"test:e2e": "mocha 'e2e/**/*.test.js' --exit", | ||
"test:filter": "mocha 'tests/**/*.test.js' --grep", | ||
@@ -36,3 +37,2 @@ "test:coverage": "nyc --reporter=text npm run test" | ||
"async-retry": "^1.3.3", | ||
"axios": "^1.5.0", | ||
"crc-32": "^1.2.2", | ||
@@ -44,7 +44,5 @@ "phin": "^3.5.0", | ||
"devDependencies": { | ||
"@commitlint/cli": "^13.1.0", | ||
"@commitlint/config-conventional": "^13.1.0", | ||
"@changesets/cli": "^2.26.2", | ||
"axios": "^1.5.0", | ||
"chai": "^4.2.0", | ||
"commitizen": "^4.2.4", | ||
"cz-conventional-changelog": "^3.2.0", | ||
"husky": "^7.0.2", | ||
@@ -69,10 +67,5 @@ "lint-staged": "^11.1.2", | ||
}, | ||
"config": { | ||
"commitizen": { | ||
"path": "./node_modules/cz-conventional-changelog" | ||
} | ||
}, | ||
"optionalDependencies": { | ||
"evervault-attestation-bindings": "^0.2.0" | ||
"evervault-attestation-bindings": "^0.3.2" | ||
} | ||
} |
@@ -49,4 +49,4 @@ [![Evervault](https://evervault.com/evervault.svg)](https://evervault.com/) | ||
const httpsAgent = evervault.createRelayHttpsAgent(); | ||
const response = await axios.get('https://example.com', { | ||
httpsAgent | ||
const response = await axios.get('https://example.com', { | ||
httpsAgent, | ||
}); | ||
@@ -57,8 +57,8 @@ | ||
// Enable the Cages beta client | ||
await evervaultClient.enableCagesBeta({ 'my-cage': { pcr8: '...' } }); | ||
// Enable the Cages client | ||
await evervaultClient.enableCages({ 'my-cage': { pcr8: '...' } }); | ||
const response = await axios.post( | ||
'https://my-cage.my-app.cages.evervault.com', | ||
encrypted | ||
); // This connection will be attested by the Cages beta client | ||
); // This connection will be attested by the Cages client | ||
``` | ||
@@ -91,5 +91,5 @@ | ||
| Parameter | Type | Description | | ||
| -------------- | --------------------------------| --------------------- | | ||
| encrypted | String, Array, Object or Buffer | Data to be decrypted. | | ||
| Parameter | Type | Description | | ||
| --------- | ------------------------------- | --------------------- | | ||
| encrypted | String, Array, Object or Buffer | Data to be decrypted. | | ||
@@ -106,6 +106,6 @@ ### evervault.createClientSideDecryptToken() | ||
| Parameter | Type | Description | | ||
| -------------- | --------------------------------| --------------------------------------------------------------------- | | ||
| payload | String, Array, or Object | Data that the token can decrypt. | | ||
| expiry | Date | The expiry of the token, must be < 10 mins from now. (Default 5 mins) | | ||
| Parameter | Type | Description | | ||
| --------- | ------------------------ | --------------------------------------------------------------------- | | ||
| payload | String, Array, or Object | Data that the token can decrypt. | | ||
| expiry | Date | The expiry of the token, must be < 10 mins from now. (Default 5 mins) | | ||
@@ -165,7 +165,8 @@ ### evervault.run() | ||
`evervault.createRelayHttpsAgent()` will return a `HttpsProxyAgent` configred to proxy traffic through Relay. | ||
`evervault.createRelayHttpsAgent()` will return a `HttpsProxyAgent` configred to proxy traffic through Relay. | ||
```javascript | ||
async evervault.createRelayHttpsAgent([options: Object]) | ||
evervault.createRelayHttpsAgent(); | ||
``` | ||
#### createRelayHttpsAgent axios example | ||
@@ -175,17 +176,17 @@ | ||
const httpsAgent = evervault.createRelayHttpsAgent(); | ||
const response = await axios.get('https://example.com', { | ||
httpsAgent | ||
const response = await axios.get('https://example.com', { | ||
httpsAgent, | ||
}); | ||
``` | ||
### evervault.enableCagesBeta() | ||
### evervault.enableCages() | ||
`evervault.enableCagesBeta()` configures your client to automatically attest any requests to Cages. See the [Cage attestation docs](https://docs.evervault.com/products/cages#how-does-attestation-work-with-cages) to learn more. | ||
`evervault.enableCages()` configures your client to automatically attest any requests to Cages. See the [Cage attestation docs](https://docs.evervault.com/products/cages#how-does-attestation-work-with-cages) to learn more. | ||
```javascript | ||
async evervault.enableCagesBeta([cageAttestationData: Object]) | ||
async evervault.enableCages([cageAttestationData: Object]) | ||
``` | ||
| Key | Type | Default | Description | | ||
| ------------ | ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| Key | Type | Default | Description | | ||
| ------------ | ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ||
| `<CageName>` | `Object` `Array` | `undefined` | Requests to a Cage specified in this object will include a check to verify that the PCRs provided in the object are included in the attestation document. The provided data can be either a single Object, or an Array of Objects to allow roll-over between different sets of PCRs. | | ||
@@ -196,3 +197,3 @@ | ||
```javascript | ||
await evervault.enableCagesBeta({ | ||
await evervault.enableCages({ | ||
'hello-cage': { | ||
@@ -199,0 +200,0 @@ pcr8: '97c5395a83c0d6a04d53ff962663c714c178c24500bf97f78456ed3721d922cf3f940614da4bb90107c439bc4a1443ca', |
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 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
77305
7
13
29
2193
207
11
+ Addedevervault-attestation-bindings@0.3.2(transitive)
+ Addedevervault-attestation-bindings-android-arm-eabi@0.3.2(transitive)
+ Addedevervault-attestation-bindings-android-arm64@0.3.2(transitive)
+ Addedevervault-attestation-bindings-darwin-arm64@0.3.2(transitive)
+ Addedevervault-attestation-bindings-darwin-universal@0.3.2(transitive)
+ Addedevervault-attestation-bindings-darwin-x64@0.3.2(transitive)
+ Addedevervault-attestation-bindings-linux-arm-gnueabihf@0.3.2(transitive)
+ Addedevervault-attestation-bindings-linux-arm64-gnu@0.3.2(transitive)
+ Addedevervault-attestation-bindings-linux-arm64-musl@0.3.2(transitive)
+ Addedevervault-attestation-bindings-linux-x64-gnu@0.3.2(transitive)
+ Addedevervault-attestation-bindings-linux-x64-musl@0.3.2(transitive)
+ Addedevervault-attestation-bindings-win32-ia32-msvc@0.3.2(transitive)
+ Addedevervault-attestation-bindings-win32-x64-msvc@0.3.2(transitive)
- Removedaxios@^1.5.0
- Removedasynckit@0.4.0(transitive)
- Removedaxios@1.7.7(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedevervault-attestation-bindings@0.2.0(transitive)
- Removedevervault-attestation-bindings-android-arm-eabi@0.2.0(transitive)
- Removedevervault-attestation-bindings-android-arm64@0.2.0(transitive)
- Removedevervault-attestation-bindings-darwin-arm64@0.2.0(transitive)
- Removedevervault-attestation-bindings-darwin-universal@0.2.0(transitive)
- Removedevervault-attestation-bindings-darwin-x64@0.2.0(transitive)
- Removedevervault-attestation-bindings-linux-arm-gnueabihf@0.2.0(transitive)
- Removedevervault-attestation-bindings-linux-arm64-gnu@0.2.0(transitive)
- Removedevervault-attestation-bindings-linux-arm64-musl@0.2.0(transitive)
- Removedevervault-attestation-bindings-linux-x64-gnu@0.2.0(transitive)
- Removedevervault-attestation-bindings-linux-x64-musl@0.2.0(transitive)
- Removedevervault-attestation-bindings-win32-ia32-msvc@0.2.0(transitive)
- Removedevervault-attestation-bindings-win32-x64-msvc@0.2.0(transitive)
- Removedform-data@4.0.1(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedproxy-from-env@1.1.0(transitive)