UNPKG

@agnostack/next-shopify

Version:

Please contact agnoStack via info@agnostack.com for any questions

113 lines 5.01 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getNonce = exports.CryptoHandler = exports.compareHashes = exports.generateHMAC = void 0; const crypto_1 = __importDefault(require("crypto")); const shared_1 = require("../../shared"); const wrapKeyData = (keyData, keyType = 'RSA PRIVATE') => (`-----BEGIN ${keyType} KEY-----${(0, shared_1.ensureString)(keyData).replace(/"/g, '')}-----END ${keyType} KEY-----\n`.replace(/\\n/g, '\n')); const getRecrypted = (encrypted) => { const [beginning, hiddenInitialVector, end = ''] = encrypted.split(/_(.*==)=/g); return { initialVector: hiddenInitialVector, encrypted: `${beginning}${end}` }; }; const decryptAES = (toDecrypt, sharedSecret, initialVector) => { if (!toDecrypt || !sharedSecret || !initialVector) return ''; const decipher = crypto_1.default.createDecipheriv('aes-256-cbc', Buffer.from(sharedSecret, 'base64'), Buffer.from(initialVector, 'base64')); const decrypted = Buffer.concat([ decipher.update(Buffer.from(toDecrypt, 'base64')), decipher.final() ]); return decrypted.toString('utf8'); }; // HMMMMMM: should this be toDecrypt == undefined?? const decryptRSAPublic = (toDecrypt, publicKey, encoding = 'utf8') => (!toDecrypt || !publicKey ? '' : crypto_1.default .publicDecrypt(publicKey, Buffer.from(toDecrypt, 'base64')) .toString(encoding)); // HMMMMMM: does this need the logic from encryptRSAPublic? // HMMMMMM: should this be toEncrypt == undefined?? const encryptRSAPrivate = (toEncrypt, privateKey, encoding = 'utf8') => (!toEncrypt || !privateKey ? '' : crypto_1.default .privateEncrypt(privateKey, Buffer.from(JSON.stringify(toEncrypt), encoding)) .toString('base64')); const generateHMAC = (message, apiSecret, digest = 'hex') => (crypto_1.default.createHmac('sha256', apiSecret) .update(message) .digest(digest)); exports.generateHMAC = generateHMAC; const compareHashes = (digestable, checkSumable, encoding = 'utf8') => { const digest = (digestable instanceof ArrayBuffer) ? digestable : Buffer.from(digestable, encoding); const checkSum = (checkSumable instanceof ArrayBuffer) ? checkSumable : Buffer.from(checkSumable, encoding); return ((digest.length === checkSum.length) && crypto_1.default.timingSafeEqual(digest, checkSum)); }; exports.compareHashes = compareHashes; const singleton = Symbol('singleton'); const singletonEnforcer = Symbol('singletonEnforcer'); const decryptKey = (encryptedKey, sharedSecret) => { const { initialVector: hiddenIv, encrypted: recryptedKey, } = getRecrypted(encryptedKey); return decryptAES(recryptedKey, sharedSecret, hiddenIv); }; class CryptoHandler { constructor(enforcer, config) { if (enforcer !== singletonEnforcer) { throw new Error('Cannot instantiate CryptoHandler directly, please use getInstance()'); } this.type = 'CryptoHandler'; this.config = config; } get isInitialized() { return (this.cryptoConfig != undefined); } initialize() { if ((0, shared_1.objectNotEmpty)(this.config)) { const { encryptedPrivateKey, encryptedPublicKey, sharedSecret } = this.config; this.cryptoConfig = { publicKey: wrapKeyData(decryptKey(encryptedPublicKey, sharedSecret), 'RSA PUBLIC'), privateKey: wrapKeyData(decryptKey(encryptedPrivateKey, sharedSecret)), }; } } static getInstance(config) { if (!this[singleton]) { this[singleton] = new CryptoHandler(singletonEnforcer, config); } if (!this[singleton].isInitialized) { this[singleton].initialize(); } return this[singleton]; } decrypt(encrypted) { return JSON.parse(decryptRSAPublic(encrypted, this.cryptoConfig.publicKey)); } encrypt(decrypted) { return encryptRSAPrivate(decrypted, this.cryptoConfig.privateKey); } verifyPublicKey(encryptedPublicKey, sharedSecret) { let publicKey; try { publicKey = wrapKeyData(decryptKey(encryptedPublicKey, sharedSecret), 'RSA PUBLIC'); // eslint-disable-next-line no-empty } catch (_ignore) { } return (publicKey === this.cryptoConfig.publicKey); } } exports.CryptoHandler = CryptoHandler; // NOTE replicated from @shopify/shopify-api-js const getNonce = (length = 15) => { // TODO Remove the randomBytes call when dropping Node 14 support const bytes = crypto_1.default.getRandomValues ? crypto_1.default.getRandomValues(new Uint8Array(length)) : crypto_1.default.randomBytes(length); return bytes.map((byte) => byte % 10).join(''); }; exports.getNonce = getNonce; //# sourceMappingURL=crypto.js.map