@agnostack/next-shopify
Version:
Please contact agnoStack via info@agnostack.com for any questions
113 lines • 5.01 kB
JavaScript
"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