{"version":3,"sources":["jsdelivr-header.js","/npm/robokassa-gate@1.1.1/src/RoboGate.js"],"names":[],"mappings":"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","file":"/npm/robokassa-gate@1.1.1/src/RoboGate.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/robokassa-gate@1.1.1/src/RoboGate.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","import url from 'url';\r\nimport crypto from 'crypto';\r\nimport helpers from './helpers.js';\r\n\r\n/**\r\n * @typedef TConfigReceipt\r\n * @property {string} sno .\r\n * @property {string} paymentMethod .\r\n * @property {string} paymentObject .\r\n * @property {string} tax .\r\n */\r\n\r\n/**\r\n * @typedef {object} TConfig\r\n * @property {string} merchantLogin .\r\n * @property {string} password1 .\r\n * @property {string} password2 .\r\n * @property {string} testPassword1 .\r\n * @property {string} testPassword2 .\r\n * @property {TConfigReceipt} receipt .\r\n * @property {boolean} [testMode] .\r\n * @property {string} [hashingAlgorithm] .\r\n * @property {string} [resultUrlRequestMethod] .\r\n */\r\n\r\n/**\r\n * @module RoboGate\r\n */\r\nclass RoboGate {\r\n    /**\r\n    * @param {TConfig} config configuration object\r\n    */\r\n    constructor(config) {\r\n        helpers.validateInputConfig(config);\r\n        \r\n        this.config = {\r\n            merchantLogin: config.merchantLogin,\r\n            hashingAlgorithm: config.hashingAlgorithm || 'md5',\r\n\r\n            password1: config.password1,\r\n            password2: config.password2,\r\n\r\n            testMode: config.testMode || false,\r\n            testPassword1: config.testPassword1,\r\n            testPassword2: config.testPassword2,\r\n\r\n            resultUrlRequestMethod: config.resultUrlRequestMethod || 'GET',\r\n\r\n            paymentUrlTemplate: 'https://auth.robokassa.ru/Merchant/Index.aspx',\r\n            customDataKeyPrefix: 'Shp_', // Custom params must start from Shp, SHP, shp.\r\n\r\n            resultURLKeys: {\r\n                OutSum: true,\r\n                InvId: true,\r\n                SignatureValue: true\r\n            },\r\n\r\n            receipt: config.receipt || null\r\n        };\r\n\r\n        // Check required keys\r\n        for (let key in this.config) {\r\n            if (this.config[key] === undefined || this.config[key] === '') {\r\n                throw new Error('Missing required key ' + key);\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Function to generate unique payment URL\r\n         * @param  {object} options { invSumm, invDescr, invId, invSummCurrency, email, encoding, items, customData }\r\n         * @return {string} unique payment URL\r\n         */\r\n        this.generatePaymentURL = (options) => {\r\n            const optionsDefaults = {\r\n                invId: null,\r\n                email: null,\r\n                outSumCurrency: null,\r\n                customData: {}\r\n            };\r\n\r\n            options = { ...optionsDefaults, ...options };\r\n\r\n            let params = {\r\n                MerchantLogin: this.config.merchantLogin,\r\n                OutSum: options.invSumm,\r\n                Description: options.invDescr,\r\n                SignatureValue: this.calcURLHash(options.invSumm, this.config.merchantLogin, options),\r\n                Encoding: (options.encoding || 'UTF-8')\r\n            };\r\n\r\n            if (this.config.receipt !== null && options.items && options.items.length !== 0) {\r\n                let receipt = new this.Receipt(options.items, this.config.receipt);\r\n                // @ts-ignore\r\n                receipt = helpers.convertJSONtoURI(receipt);\r\n                options.receipt = receipt;\r\n\r\n                params.Receipt = receipt;\r\n                params.SignatureValue = this.calcURLHash(options.invSumm, this.config.merchantLogin, options);\r\n            };\r\n\r\n            // Invoice ID\r\n            if (options.invId) params.InvId = options.invId;\r\n\r\n            // User email\r\n            if (options.email) params.Email = options.email;\r\n\r\n            // OutSumCurrency\r\n            if (options.invSummCurrency) params.OutSumCurrency = options.invSummCurrency;\r\n\r\n            // Enable/Disable test mode\r\n            if (this.config.testMode) params.IsTest = 1;\r\n\r\n            // Custom user data\r\n            if (options.customData) {\r\n                for (const [key, value] of Object.entries(options.customData)) {\r\n                    let keyRe = this.config.customDataKeyPrefix + key;\r\n                    params[keyRe] = value;\r\n                };\r\n            }\r\n\r\n            const oUrl = url.parse(this.config.paymentUrlTemplate, true);\r\n\r\n            // @ts-ignore\r\n            delete oUrl.search;\r\n\r\n            oUrl.query = { ...oUrl.query, ...params };\r\n\r\n            let output = url.format(oUrl);\r\n\r\n            if (output.length > 2048) throw new Error('Final payment URL exceeds limit of 2048 symbols');\r\n\r\n            return output;\r\n        };\r\n\r\n        /**\r\n         * Generates receipt object that will be converted later\r\n         * @param  {Array} orderItems\r\n         * @param  {object} receiptConfig\r\n         * @returns {object} receipt object\r\n         */\r\n        this.Receipt = function(orderItems = [], receiptConfig) {\r\n            if (!receiptConfig) throw new Error('No receiptConfig provided');\r\n            if (!receiptConfig.sno\r\n                || !receiptConfig.paymentMethod\r\n                || !receiptConfig.paymentObject\r\n                || !receiptConfig.tax) throw new Error('Missing required field in receiptConfig object');\r\n\r\n            this.sno = receiptConfig.sno;\r\n            this.items = [];\r\n\r\n            orderItems.forEach(el => {\r\n                this.items.push({\r\n                    'name': el.name,\r\n                    'quantity': el.quantity || 1,\r\n                    'sum': el.price * (el.quantity || 1),\r\n                    'payment_method': receiptConfig.paymentMethod,\r\n                    'payment_object': receiptConfig.paymentObject,\r\n                    'tax': receiptConfig.tax\r\n                });\r\n            });\r\n        };\r\n\r\n        this.calcURLHash = (invSumm, merchantLogin, options) => {\r\n            // Attention!\r\n            // Do not change order of values pushed\r\n            // Order is strict for generating hash\r\n            let values = [merchantLogin, invSumm];\r\n\r\n            // Add internal invoice number\r\n            if (options.invId) values.push(options.invId);\r\n            else values.push('');\r\n\r\n            // Add data necessary for generating receipt\r\n            if (options.receipt) values.push(options.receipt);\r\n\r\n            // Invoice currency (for non-default)\r\n            if (options.invSummCurrency) {\r\n                values.push(options.invSummCurrency);\r\n            }\r\n\r\n            // Add either test password or prod password\r\n            if (this.config.testMode === true) values.push(this.config.testPassword1);\r\n            else values.push(this.config.password1);\r\n\r\n            // Prepare and add custom params if it is presented\r\n            if (options.customData) {\r\n                let customData = [];\r\n\r\n                for (const [key, value] of Object.entries(options.customData)) {\r\n                    const customKey = this.config.customDataKeyPrefix + key;\r\n                    customData.push(customKey + '=' + value);\r\n                }\r\n\r\n                // custom params must be sorted alphabatically\r\n                values = values.concat(customData.sort());\r\n            }\r\n\r\n            // Calculate hash\r\n            let outputHash = this.calcHash(values.join(':'), this.config.hashingAlgorithm);\r\n\r\n            return outputHash;\r\n        };\r\n\r\n        this.calcHash = (value, algorithm) => {\r\n            const hash = crypto.createHash(algorithm);\r\n            hash.update(value);\r\n\r\n            let output = hash.digest('hex');\r\n\r\n            return output;\r\n        };\r\n        /**\r\n         * @param  {object} req express req object containing either query or body\r\n         * @param  {object} options \r\n         * @returns {{validated: boolean, details: string} } result\r\n         */\r\n        this.validateResult = (req, options = {}) => {\r\n            let method = (options.requestMethod || this.config.resultUrlRequestMethod);\r\n            method = method.toUpperCase();\r\n\r\n            // Define result data object based on request method\r\n            let data = {};\r\n            \r\n            switch (method) {\r\n            case 'GET':\r\n                data = req.query;\r\n                break;\r\n            case 'POST':\r\n                data = req.body;\r\n                break;\r\n            }\r\n\r\n            // Validating and parsing request\r\n            let values = {};\r\n            try {\r\n                const keys = (this.config.resultURLKeys);\r\n\r\n                for (const [key, isRequired] of Object.entries(keys)) {\r\n                    const value = data[key];\r\n\r\n                    if (!value && isRequired === true) {\r\n                        throw new Error('Missing required key: ' + key);\r\n                    }\r\n\r\n                    if (value) {\r\n                        const keyRe = helpers.toCamelCase(key);\r\n                        values[keyRe] = value;\r\n                    }\r\n                }\r\n            } catch (error) {\r\n                return { validated: false, details: error.message };\r\n            }\r\n\r\n            // Extracting user data from request\r\n            const customData = {};\r\n\r\n            for (const [key, value] of Object.entries(data)) {\r\n                const keyRe = key.toLowerCase();\r\n                if (helpers.strStartsFrom(keyRe, this.config.customDataKeyPrefix.toLowerCase())) {\r\n                    customData[key] = value;\r\n                }\r\n            }\r\n\r\n            let isValid = this.validateResultUrlHash(\r\n                values.signatureValue,\r\n                values.outSum,\r\n                values.invId,\r\n                customData\r\n            );\r\n\r\n            if (isValid === true) {\r\n                return { validated: true, details: 'Result hash is valid' };\r\n            } else {\r\n                return { validated: false, details: 'Result hash is NOT valid' };\r\n            }\r\n        };\r\n\r\n        this.validateResultUrlHash = (hash, outSum, invId, customData) => {\r\n            return (hash.toLowerCase() == this.calculateResultUrlHash(outSum, invId, customData).toLowerCase());\r\n        };\r\n\r\n        this.calculateResultUrlHash = (outSum, invId, customData) => {\r\n            let values = [outSum];\r\n\r\n            if (invId) {\r\n                values.push(invId);\r\n            }\r\n\r\n            if (this.config.testMode === true) values.push(this.config.testPassword2);\r\n            else values.push(this.config.password2);\r\n\r\n            // Handle custom data\r\n            if (customData) {\r\n                let strings = [];\r\n\r\n                for (const [key, value] of Object.entries(customData)) {\r\n                    strings.push(key + '=' + value);\r\n                };\r\n\r\n                values = values.concat(strings.sort());\r\n            }\r\n\r\n            return this.calcHash(values.join(':'), this.config.hashingAlgorithm);\r\n        };\r\n    }\r\n}\r\n\r\nexport default RoboGate;"]}