UNPKG

box-node-sdk

Version:

Official SDK for Box Platform APIs

241 lines 9.66 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultPrivateKeyDecryptor = exports.Hash = exports.utilLib = exports.FormData = exports.ByteStream = exports.Buffer = void 0; exports.generateByteBuffer = generateByteBuffer; exports.generateReadableStreamFromFile = generateReadableStreamFromFile; exports.generateByteStreamFromBuffer = generateByteStreamFromBuffer; exports.decodeBase64ByteStream = decodeBase64ByteStream; exports.stringToByteStream = stringToByteStream; exports.readByteStream = readByteStream; exports.iterateChunks = iterateChunks; exports.createJwtAssertion = createJwtAssertion; exports.readTextFromFile = readTextFromFile; exports.createAgent = createAgent; exports.jsonStringifyWithEscapedUnicode = jsonStringifyWithEscapedUnicode; exports.computeWebhookSignature = computeWebhookSignature; exports.compareSignatures = compareSignatures; exports.random = random; exports.calculateMD5Hash = calculateMD5Hash; exports.getEnvVar = getEnvVar; exports.setEnvVar = setEnvVar; const buffer_1 = require("buffer"); Object.defineProperty(exports, "Buffer", { enumerable: true, get: function () { return buffer_1.Buffer; } }); const stream_1 = require("stream"); Object.defineProperty(exports, "ByteStream", { enumerable: true, get: function () { return stream_1.Readable; } }); const jose_1 = require("jose"); const crypto_1 = __importDefault(require("crypto")); const fs_1 = __importDefault(require("fs")); const proxy_agent_1 = require("proxy-agent"); const form_data_1 = __importDefault(require("form-data")); Object.defineProperty(exports, "FormData", { enumerable: true, get: function () { return form_data_1.default; } }); const util_1 = __importDefault(require("util")); exports.utilLib = util_1.default; class Hash { hash; algorithm; constructor({ algorithm }) { this.algorithm = algorithm; this.hash = crypto_1.default.createHash(algorithm); } async updateHash(data) { this.hash.update(data); } async digestHash(encoding = 'base64') { return this.hash.digest(encoding); } } exports.Hash = Hash; function generateByteBuffer(size) { return crypto_1.default.randomBytes(size); } function generateReadableStreamFromFile(file, chunkSize = 1024 * 1024) { throw new Error('This function is only supported in the browser'); } function generateByteStreamFromBuffer(buffer) { const buf = buffer_1.Buffer.isBuffer(buffer) ? buffer : buffer_1.Buffer.from(buffer); return stream_1.Readable.from(buf); } function decodeBase64ByteStream(data) { return stream_1.Readable.from(buffer_1.Buffer.from(data, 'base64')); } function stringToByteStream(data) { return stream_1.Readable.from(buffer_1.Buffer.from(data, 'ascii')); } async function readByteStream(byteStream) { const buffers = []; for await (const data of byteStream) { buffers.push(data); } return buffer_1.Buffer.concat(buffers); } async function* iterateChunks(stream, chunkSize, fileSize) { let buffers = []; let totalSize = 0; let consumedSize = 0; while (consumedSize < fileSize && !stream.readableEnded) { for await (const chunk of stream) { const data = buffer_1.Buffer.isBuffer(chunk) ? chunk : buffer_1.Buffer.from(chunk); if (!buffer_1.Buffer.isBuffer(data)) { throw new Error('Expecting a chunk of stream to be a Buffer'); } consumedSize += data.length; buffers.push(data); totalSize += data.length; if (totalSize < chunkSize) { continue; } const buffer = buffer_1.Buffer.concat(buffers); let start = 0; while (totalSize >= chunkSize) { yield generateByteStreamFromBuffer(buffer.subarray(start, start + chunkSize)); start += chunkSize; totalSize -= chunkSize; } buffers = totalSize > 0 ? [buffer.subarray(start)] : []; } } if (consumedSize !== fileSize) { throw new Error(`Stream size ${consumedSize} does not match expected file size ${fileSize}`); } if (totalSize > 0) { yield generateByteStreamFromBuffer(buffer_1.Buffer.concat(buffers)); } } class DefaultPrivateKeyDecryptor { constructor(fields) { } decryptPrivateKey(encryptedPrivateKey, passphrase) { const privateKey = crypto_1.default.createPrivateKey({ key: encryptedPrivateKey, format: 'pem', type: 'pkcs8', passphrase: passphrase, }); const pem = privateKey.export({ type: 'pkcs8', format: 'pem' }).toString(); return pem; } } exports.DefaultPrivateKeyDecryptor = DefaultPrivateKeyDecryptor; /** * Creates a JWT assertion. * * @param claims * @param key * @param options * @returns */ async function createJwtAssertion(claims, key, options) { const pem = options.privateKeyDecryptor?.decryptPrivateKey(key.key, key.passphrase); if (!pem) { throw new Error(`Decrypted jwt private key is empty`); } const pkcs8 = await (0, jose_1.importPKCS8)(pem, options.algorithm || 'RS256'); let signer = new jose_1.SignJWT(claims); signer = options.audience ? signer.setAudience(options.audience) : signer; signer = options.expiresIn ? signer.setExpirationTime(options.expiresIn) : signer; signer = options.issuer ? signer.setIssuer(options.issuer) : signer; signer = options.jwtid ? signer.setJti(options.jwtid) : signer; signer = options.notBefore ? signer.setNotBefore(options.notBefore) : signer; signer = options.subject ? signer.setSubject(options.subject) : signer; signer = options.algorithm ? signer.setProtectedHeader({ alg: options.algorithm }) : signer; signer = signer.setIssuedAt(); return await signer.sign(pkcs8); } /** * Reads a text file and returns its content. */ function readTextFromFile(filepath) { return fs_1.default.readFileSync(filepath, 'utf8'); } /** * Create web agent from proxy agent options. */ function createAgent(options, proxyConfig) { let agentOptions = options; if (proxyConfig && proxyConfig.url) { if (!proxyConfig.url.startsWith('http')) { throw new Error('Invalid proxy URL'); } const proxyHost = proxyConfig.url.split('//')[1]; const proxyAuth = proxyConfig.username && proxyConfig.password ? `${proxyConfig.username}:${proxyConfig.password}@` : ''; const proxyUrl = `http://${proxyAuth}${proxyHost}`; agentOptions = Object.assign({ getProxyForUrl: (url) => proxyUrl }, options || {}); } return agentOptions ? new proxy_agent_1.ProxyAgent(agentOptions) : new proxy_agent_1.ProxyAgent(); } /** * Stringify JSON with escaped multibyte Unicode characters and slashes to ensure computed signatures match PHP's default behavior * * @param {Object} body - The parsed JSON object * @returns {string} - Stringified JSON with escaped multibyte Unicode characters * @private */ function jsonStringifyWithEscapedUnicode(body) { return body .replace(/[\u007f-\uffff]/g, (char) => `\\u${`0000${char.charCodeAt(0).toString(16)}`.slice(-4)}`) .replace(/(?<!\\)\//g, '\\/'); } /** * Compute the message signature * @see {@Link https://developer.box.com/en/guides/webhooks/handle/setup-signatures/} * * @param {string} body - The request body of the webhook message * @param {Object} headers - The request headers of the webhook message * @param {string} signatureKey - The signature to verify the message with * @param {string} escapeBody - Indicates if payload should be escaped or left as is * @returns {?string} - The message signature (or null, if it can't be computed) * @private */ async function computeWebhookSignature(body, headers, signatureKey, escapeBody = false) { if (headers['box-signature-version'] !== '1') { return null; } if (headers['box-signature-algorithm'] !== 'HmacSHA256') { return null; } let signature = null; const escapedBody = escapeBody ? jsonStringifyWithEscapedUnicode(body) : body; let hmac = crypto_1.default.createHmac('sha256', signatureKey); hmac.update(escapedBody); hmac.update(headers['box-delivery-timestamp']); signature = hmac.digest('base64'); return signature; } async function compareSignatures(expectedSignature, receivedSignature) { if (!expectedSignature || !receivedSignature) { return false; } const expectedBuffer = buffer_1.Buffer.from(expectedSignature, 'base64'); const receivedBuffer = buffer_1.Buffer.from(receivedSignature, 'base64'); if (expectedBuffer.length !== receivedBuffer.length) { return false; } return crypto_1.default.timingSafeEqual(expectedBuffer, receivedBuffer); } function random(min, max) { return Math.random() * (max - min) + min; } async function calculateMD5Hash(data) { return crypto_1.default.createHash('sha1').update(data).digest('hex'); } function getEnvVar(name) { if (typeof process === 'undefined' || !process.env) { throw new Error('This function requires a Node.js environment'); } return process.env[name] || ''; } function setEnvVar(name, value) { if (typeof process === 'undefined' || !process.env) { throw new Error('This function requires a Node.js environment'); } process.env[name] = value; } //# sourceMappingURL=utilsNode.js.map