├── .gitignore ├── Gruntfile.js ├── LEEME.md ├── LICENSE ├── README.md ├── lib ├── openpay-data.v1.js ├── openpay-data.v1.min.js ├── openpay.v1.js └── openpay.v1.min.js ├── package.json └── test ├── openpay_data_js_test.html └── openpay_js_test.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // Project configuration. 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | uglify: { 7 | options : { 8 | ie8 : true, 9 | output : { 10 | ascii_only : true 11 | } 12 | }, 13 | openpayJs: { 14 | src: 'lib/openpay.v1.js', 15 | dest: 'lib/openpay.v1.min.js', 16 | options : { 17 | banner: '/*! openpay.js v<%= pkg.version %> <%= grunt.template.today("yyyy-mm-dd") %> */' 18 | } 19 | }, 20 | openpayData: { 21 | src: 'lib/openpay-data.v1.js', 22 | dest: 'lib/openpay-data.v1.min.js', 23 | options : { 24 | banner: '/*! openpay-data.js v<%= pkg.version %> <%= grunt.template.today("yyyy-mm-dd") %> */' 25 | } 26 | } 27 | } 28 | }); 29 | 30 | grunt.loadNpmTasks('grunt-contrib-uglify'); 31 | 32 | }; -------------------------------------------------------------------------------- /LEEME.md: -------------------------------------------------------------------------------- 1 | #Openpay.js 2 | 3 | [Documentacion en español](http://docs.openpay.mx/#openpay-js) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Openpay JS](https://www.openpay.mx/img/github/js.jpg) 2 | 3 | ## Introduction 4 | ### What is Openpay.js? 5 | Openpay.js is a Javascript library designed to makes it easy to collect credit card data without having the information touch your server. 6 | 7 | ### Benefits: 8 | * The transaction information does not have to pass through your server, it is sent directly to Openpay. 9 | * It is the easiest and fastest way to integrate a charges module on your ecommerce website. 10 | 11 | ## Getting started 12 | The first step in the integration is to add the library to the page from which payments will be made. Add the following script tag: 13 | ```HTML 14 | 15 | ``` 16 | ### Configuration 17 | Before you can use Openpay.js is necessary to configure both the merchant id, and public key that were assigned when you created your [OpenPay account](https://sandbox-dashboard.openpay.mx/login). With these data, Openpay can identify the account to which the charges are paid. 18 | 19 | You can configure both fields with the following methods **OpenPay.setId()** and **OpenPay.setApiKey()**, respectively: 20 | ```javascript 21 | OpenPay.setId('MERCHANT_ID'); 22 | OpenPay.setApiKey('PUBLIC_API_KEY'); 23 | ``` 24 | |Notes: | 25 | |:--------------------------------------------------------------------------------------------------------| 26 | |* Both **MERCHANT_ID** as **PUBLIC_API_KEY**, are obtained from the homepage of your OpenPay account. | 27 | |* You should never use your private key along with the library, because it is visible on the client side.| 28 | 29 | ### Enable sandbox Mode 30 | To test your implementation, there Sandox environment, which is enabled with the method: **OpenPay.setSandboxMode()** 31 | ```javascript 32 | OpenPay.setSandboxMode(FLAG); 33 | ``` 34 | The FLAG parameter is a true / false flag to enable or disable test mode. 35 | 36 | If is necessary, you can use the **OpenPay.getSandboxMode()** method to determine the status of the Sandbox Mode at any time: 37 | ```javascript 38 | OpenPay.getSandboxMode(); // TRUE/FALSE, depends if is activated or not activated. 39 | ``` 40 | |Notes: | 41 | |:-------------------------------------------------------------------------------------------------------------| 42 | |* The sandbox environment has the same features as production, but only allows the use of certain card | 43 | |numbers, chosen so that you can test, more information on the [test section](http://docs.openpay.mx/#pruebas).| 44 | 45 | ## Creating tokens 46 | Once you installed and configured the library, to create a token is necessary call the method: **OpenPay.token.create()** 47 | ```javascript 48 | OpenPay.token.create(CREATE_PARAMETERS_OBJECT, SUCCESS_CALLBACK, ERROR_CALLBACK); 49 | ``` 50 | The method's params are: 51 | * The **CREATE_PARAMETERS_OBJECT** parameter is an javascript object with credit card information. 52 | * The **SUCCESS_CALLBACK** parameter define the callback method which will be called when the operation is correct. 53 | * The **ERROR_CALLBACK** parameter define the callback method which will be called when the operation has failed. 54 | 55 | The method returns an object token. The definition of object token find it [here](http://docs.openpay.mx/#tokens). 56 | 57 | #### Example of creating a token card: 58 | 59 | ```javascript 60 | OpenPay.token.create({ 61 | "card_number":"4111111111111111", 62 | "holder_name":"Juan Perez Ramirez", 63 | "expiration_year":"20", 64 | "expiration_month":"12", 65 | "cvv2":"110", 66 | "address":{ 67 | "city":"Querétaro", 68 | "line3":"Queretaro", 69 | "postal_code":"76900", 70 | "line1":"Av 5 de Febrero", 71 | "line2":"Roble 207", 72 | "state":"Queretaro", 73 | "country_code":"MX" 74 | } 75 | }, onSuccess, onError); 76 | ``` 77 | 78 | ## Creating tokens from html form 79 | The Openpay.js library provides you extraction of the card information from the html form and subsequent delivery by the method: 80 | **OpenPay.token.extractFormAndCreate()** 81 | ```javascript 82 | OpenPay.token.extractFormAndCreate(CREATE_FORM_OBJECT, SUCCESS_CALLBACK, ERROR_CALLBACK, {CLIENTE-ID}); 83 | ``` 84 | The method's params are: 85 | * The **CREATE_PARAMETERS_OBJECT** parameter is an javascript object with credit card information. 86 | * The **SUCCESS_CALLBACK** parameter define the callback method which will be called when the operation is correct. 87 | * The **ERROR_CALLBACK** parameter define the callback method which will be called when the operation has failed. 88 | 89 | To begin to create tokens, you need a html form like this: 90 | 91 | ```html 92 |
93 |

Holder Name:

94 |

Card number:

95 |

Expiration year:

96 |

Expiration month:

97 |

cvv2:

98 |

Street:

99 |

Number:

100 |

References:

101 |

Postal code:

102 |

City:

103 |

State:

104 |

Country code:

105 | 106 |
107 | ``` 108 | Note: The more important thing is add data-attributes **data-openpay-card** and **data-card-data-openpay-address** on inputs where card information is captured and address respectively. 109 | 110 | Later when generating the token, make an invocation to **OpenPay.token.extractFormAndCreate()**, as show below: 111 | ```javascript 112 | OpenPay.token.extractFormAndCreate( 113 | $('#processCard'), 114 | successCard, 115 | errorCard, 116 | _customerId); 117 | ``` 118 | 119 | The method returns an object type token. The definition of object token find it [here](http://docs.openpay.mx/#tokens). 120 | 121 | For a complete example, download the test from the github site:[openpay.js](https://github.com/open-pay/openpay-js) 122 | 123 | ## Updating Cards 124 | 125 | Openpay.js allows you to update card information of stored customer cards. This is useful in order to avoid sending this information to your back-end for updating. 126 | 127 | The data that can be updated is: Holder name, expiration date, and expiration year. In addition, the API allows to send a CVV that will be used in the next charge with this card. 128 | The method used for this is: 129 | **OpenPay.card.update()** 130 | ```javascript 131 | OpenPay.card.update(UPDATE_CARD_OBJECT, SUCCESS_CALLBACK, ERROR_CALLBACK, {CLIENTE-ID}, CARD_ID); 132 | ``` 133 | 134 | You can find the definition of the UPDATE_CARD_OBJECT [here](http://docs.openpay.mx/#actualizar-c-digo-de-seguridad-de-tarjeta) 135 | 136 | ## Creating Group Tokens 137 | If your Merchant account is part of a group of merchants, you can use the library to create shared group tokens. To do so, you must first configure 138 | your group credentials: 139 | 140 | ```javascript 141 | OpenPay.Group.setId('GROUP_ID'); 142 | OpenPay.Group.setApiKey('PUBLIC_API_KEY'); 143 | ``` 144 | 145 | You can then use the following methods in the same way as with regular tokens: 146 | 147 | ```javascript 148 | OpenPay.Group.token.create(CREATE_PARAMETERS_OBJECT, SUCCESS_CALLBACK, ERROR_CALLBACK); 149 | 150 | OpenPay.Group.token.extractFormAndCreate(CREATE_FORM_OBJECT, SUCCESS_CALLBACK, ERROR_CALLBACK, {CLIENTE-ID}); 151 | ``` 152 | 153 | ## How to handle responses 154 | The response functions serve as handles of the result of the transaction. These, are simple Javascript functions but receive and object type response. 155 | 156 | The response object fields are described below: 157 | 158 | |Field|Format|Description| 159 | | -------- | --------- | --------- | 160 | |status|Integer|Describe the HTTP status of the transaction. If an error before sending the request occurs, the status will be zero. In case of success the response will be 200| 161 | |message|String|Only occurs in cases of error. Short description of the error that occurred. It can be one of the following values: "Unknown error", "Request error", "Response error (end Unknown status)", "Empty or invalid OpenPay ID", "Empty or invalid API Key", "Browser error", "timeout after X milliseconds ".| 162 | |data|Objeto|Contains an [Object Error](http://docs.openpay.mx/ # errors) with the error information in the transaction provided by the server OpenPay. On success contains a token type object.| 163 | 164 | 165 | | Notes | 166 | | :------------- | 167 | |* Although the response functions are optional, we recommend to implement the outcome of the transaction can be monitored on the website.| 168 | 169 | ### On success: SuccessCallback 170 | This function is called when the operation is successful from start to finish. It receives a single parameter which is a Javascript object with a data property representing a [card](http://docs.openpay.mx/#tarjetas) or a [token](http://docs.openpay.mx/#tokens) object. 171 | Complete example of implementing a function SuccessCallback: 172 | ```javascript 173 | function SuccessCallback(response) { 174 | alert('Successful operation'); 175 | var content = '', results = document.getElementById('resultDetail'); 176 | content .= 'Id card: ' + response.data.id+ '
'; 177 | content .= 'Holder Name: ' + response.data.holder_name + '
'; 178 | content .= 'Card brand: ' + response.data.brand + '
'; 179 | results.innerHTML = content; 180 | } 181 | } 182 | ``` 183 | 184 | ### In case of error: ErrorCallback 185 | This function will be executed each time an operation has failed (for any reason, before or after sending the request). Like the method **SuccessCallback()**, takes a single parameter which is a Javascript object with detailed fault. 186 | 187 | Complete example of implementing a function ErrorCallback: 188 | ```javascript 189 | function ErrorCallback(response) { 190 | alert('Fallo en la transacción'); 191 | var content = '', results = document.getElementById('resultDetail'); 192 | content .= 'Estatus del error: ' + response.data.status + '
'; 193 | content .= 'Error: ' + response.message + '
'; 194 | content .= 'Descripción: ' + response.data.description + '
'; 195 | content .= 'ID de la petición: ' + response.data.request_id + '
'; 196 | results.innerHTML = content; 197 | } 198 | ``` 199 | 200 | ### Types error responses 201 | In addition to the status field that saves the state of the transaction, it is possible to determine the error that happened through the message field. The message may be one of the following: 202 | 203 | * **"Empty or invalid OpenPay ID"**: It happens when you have not properly configured the user ID with the OpenPay.setId () method 204 | * **"Empty or invalid API Key"**: Like the above error happens when you have not configured your API Key with OpenPay.setApiKey () method 205 | * **"Browser error"**: It is triggered when there is an error in the browser that prevents the request to succeed. It may be caused by caracterísiticas that are necessary to run some code and are missing in the browser. For more information see the "Compatibility and Requirements" section. 206 | * **"Request error"**: This error indicates that an error occurred in the server Openpay. May be due to missing parameters, formats, or some other problem that prevents a successful transaction. 207 | * **"Response error (Unknown final status)"**: When this error occurs, it means that the transaction request was submitted successfully to Openpay server but no response was received. This may be due to a problem in Openpay. For more information contact OpenPay. 208 | * **"Timeout after X milliseconds"**: Thrown when the request has taken a long time to run and therefore the response time expires. 209 | * **"Unknown error"**: Raised when there is an unknown error that prevents the request is made. It may be due to problems in the browser or connectivity. 210 | 211 | ## Card Validation Functions 212 | Besides the functions to process card charges, Openpay.js also includes some functions to validate key data necessary to carry out the transaction, especially regarding card numbers. 213 | 214 | Available methods are: 215 | 216 | * `OpenPay.card.validateCardNumber()` 217 | * `OpenPay.card.validateCVC()` 218 | * `OpenPay.card.validateExpiry()` 219 | * `OpenPay.card.cardType()` 220 | 221 | ### Number card validation 222 | To validate a card number can use the method **OpenPay.card.validateCardNumber()**. 223 | 224 | This method receives as parameter a String with the card number to be validated and return one true / false if it is a valid card number and is accepted by Openpay. 225 | Example: 226 | ```javascript 227 | OpenPay.card.validateCardNumber('5555555555554444'); 228 | ``` 229 | This method is very useful for determining whether a card number is a valid candidate for use with Openpay, so we recommend that you use it before attempting to charge a card. 230 | 231 | Examples: 232 | ```javascript 233 | OpenPay.card.validateCardNumber('5555555555554444'); // TRUE. Valid card number and accepted by OpenPay (MASTERCARD) 234 | 235 | OpenPay.card.validateCardNumber('378282246310005'); // FALSE. Number of valid card but not accepted by OpenPay (AMEX) 236 | ``` 237 | ### Security Code Validation 238 | To validate a security code is used the method **OpenPay.card.validateCVC()**. 239 | 240 | This method takes a String as a parameter and returns true / false if the string is valid. Example: 241 | ```javascript 242 | OpenPay.card.validateCVC('123'); // válido 243 | OpenPay.card.validateCVC('1234'); // válido 244 | OpenPay.card.validateCVC('A23'); // inválido 245 | ``` 246 | ### Expiration date validation 247 | For this purpose is used the method **OpenPay.card.validateExpiry()**. 248 | 249 | Receive two strings as parameters to represent the month and year of expiry of the card. Returns true / false if the combination of both data, month and year, determine a valid expiration date. Example: 250 | ```javascript 251 | OpenPay.card.validateExpiry('01', '2013'); // inválido 252 | OpenPay.card.validateExpiry('01', '13'); // inválido 253 | OpenPay.card.validateExpiry('05', '2030'); // válido 254 | OpenPay.card.validateExpiry('05', '30'); // válido 255 | ``` 256 | 257 | ### Card Type 258 | The type of card that a card number belongs to can be determined most of the time. For this, use the method **OpenPay.card.cardType()**. 259 | 260 | The method receives as a parameter a card number and returns a String with the name of the card type. Examples: 261 | ```javascript 262 | OpenPay.card.cardType('5555555555554444'); // Mastercard 263 | ​OpenPay.card.cardType('4111111111111111'); //​ Visa 264 | OpenPay.card.cardType('4917300800000000'); // Visa Electron 265 | OpenPay.card.cardType('378282246310005'); // American Express 266 | OpenPay.card.cardType('30569309025904'); // Diners Club Carte Blanche 267 | OpenPay.card.cardType('6011111111111117'); // Discover 268 | OpenPay.card.cardType('3530111333300000'); // JCB 269 | ``` 270 | 271 | ## Fraud detection using device data 272 | OpenPay can use the device information of a transaction in order to better detect fraudulent transactions. 273 | To do this, add the following code to your checkout page, when collecting payment information: 274 | ```HTML 275 | 276 | ``` 277 | 278 | Then, in your javascript, call OpenPay.deviceData.setup() to generate a Device Data. 279 | 280 | ```javascript 281 | // If you are testing your application, set Sandbox Mode first 282 | // OpenPay.setSandboxMode(true); 283 | var deviceDataId = OpenPay.deviceData.setup("formId"); 284 | ``` 285 | 286 | This method generates an identifier for the customer's device data. This value needs to be stored during checkout, and sent to OpenPay when processing the charge. 287 | 288 | The method takes two optional parameters: 289 | 290 | The first is an existing form's id. If given, a new hidden input field will be added to it, with the value of the generated deviceDataId. 291 | 292 | The second parameter specifies the generated field's name and id. If ommited, they will default to "deviceDataId". 293 | 294 | ## Compatibility and requirements 295 | To use Openpay.js You must have one of the following browsers: 296 | 297 | * Chrome 29.0+ 298 | * Firefox 23.0+ 299 | * Safari 5.1+ 300 | * Opera 17.0+ 301 | * iOS Safari 4.0+ 302 | * Android Browser 2.1+ 303 | * Blackberry Browser 7.0+ 304 | * IE Mobile 10.0 305 | 306 | Browsers must have support for XMLHttpRequest and JSON Parser libraries. 307 | -------------------------------------------------------------------------------- /lib/openpay-data.v1.js: -------------------------------------------------------------------------------- 1 | //"use strict"; 2 | 3 | (function(){ 4 | var _deviceData = function() {}; 5 | var _deviceDataSC = function() {}; 6 | var _getBeaconKey = function() {}; 7 | _deviceData._hostname = "https://api.openpay.mx/"; 8 | _deviceData._sandboxHostname = "https://sandbox-api.openpay.mx/"; 9 | _deviceData._developHostname = "https://dev-api.openpay.mx/"; 10 | _deviceData._deviceDataId = undefined; 11 | 12 | /* Get current deviceDataId or generate new one */ 13 | function getDeviceDataId() { 14 | if (_deviceData._deviceDataId === undefined) { 15 | _deviceData._deviceDataId = sjcl.codec.base64.fromBits(sjcl.random.randomWords(6, 0)).replace(/[\+\/]/g,'0'); 16 | } 17 | return _deviceData._deviceDataId; 18 | } 19 | 20 | 21 | /* GET ANTI-FRAUD COMPONENTS */ 22 | function get_antifraud_comp(hostname, merchant, sessionId){ 23 | var antifraudURL = hostname+'antifraud/'+merchant+'/components?s='+sessionId; 24 | 25 | if (window.XDomainRequest) { 26 | var xdr = new XDomainRequest(); 27 | xdr.open("GET", antifraudURL); 28 | xdr.onload = function() { 29 | document.body.insertAdjacentHTML("beforeend",xdr.responseText); 30 | } 31 | setTimeout(function () {xdr.send();}, 0); 32 | }else{ 33 | var xmlhttp = new XMLHttpRequest(); 34 | xmlhttp.onreadystatechange = function(){ 35 | if(xmlhttp.readyState == 4 && xmlhttp.status == 200){ 36 | document.body.insertAdjacentHTML("beforeend",xmlhttp.responseText); 37 | } 38 | } 39 | xmlhttp.open('GET', antifraudURL , true); 40 | xmlhttp.send(); 41 | } 42 | 43 | } 44 | 45 | /* Collect device data */ 46 | function collect() { 47 | var hostname; 48 | var sessionId = getDeviceDataId(); 49 | 50 | if (OpenPay.developMode) { 51 | hostname = _deviceData._developHostname; 52 | } else if (OpenPay.sandboxMode) { 53 | hostname = _deviceData._sandboxHostname; 54 | } else { 55 | hostname = _deviceData._hostname; 56 | } 57 | 58 | var merchant = OpenPay.getId(); 59 | get_antifraud_comp(hostname,merchant,sessionId); 60 | 61 | return getDeviceDataId(); 62 | } 63 | 64 | /* Collect device data, and add a hidden field to the form with the given ID if specified. */ 65 | _deviceData['setup'] = function(_formId, _hiddenFieldName) { 66 | var sessionId = getDeviceDataId(); 67 | if(_formId && document.getElementById(_formId)){ 68 | var input = document.createElement("input"); 69 | input.setAttribute('type', 'hidden'); 70 | input.value = sessionId; 71 | input.name = _hiddenFieldName ? _hiddenFieldName : 'deviceDataId'; 72 | input.id = _hiddenFieldName ? _hiddenFieldName : 'deviceDataId'; 73 | document.getElementById(_formId).appendChild(input); 74 | } 75 | var isNewLibraryOpenPay = true; 76 | 77 | try { 78 | OpenPay.getId(); 79 | OpenPay.getApiKey(); 80 | } catch (e) { 81 | isNewLibraryOpenPay = false; 82 | } 83 | 84 | if(isNewLibraryOpenPay){ 85 | console.log("executing sift mode"); 86 | var publicId = OpenPay.getId(); 87 | var apiKey = OpenPay.getApiKey(); 88 | var hostname; 89 | if (OpenPay.developMode) { 90 | hostname = _deviceData._developHostname; 91 | } else if (OpenPay.sandboxMode) { 92 | hostname = _deviceData._sandboxHostname; 93 | } else { 94 | hostname = _deviceData._hostname; 95 | } 96 | var url = hostname + "v1/" + publicId +"/antifraudkeys"; 97 | //se obtiene el beaconKey de siftscience 98 | try { 99 | OpenPay.getBeaconKey.beaconKey(url, apiKey, "", sessionId,hostname); 100 | } catch(e){ 101 | console.log("continue without beaconkey" + e); 102 | } 103 | } 104 | 105 | return collect(); 106 | }; 107 | 108 | _getBeaconKey['beaconKey'] = function(endpoint, publicKey, userId, sessionId, hostname) { 109 | var _rhr = null, _timer = null, _url = endpoint, _headers = {}, _timeout = 0, _auth = btoa(publicKey + ":"); 110 | var _data = {}; 111 | 112 | function handleError(_message, _status, _responseText) { 113 | clearTimeout(_timer); 114 | var _data = null; 115 | _message = _message || 'Unknown error'; 116 | _status = _status || 0; 117 | _responseText = _responseText || '{}'; 118 | try { 119 | _data = JSON.parse(_responseText); 120 | } catch (e) { 121 | _message = 'Response error'; 122 | } 123 | }; 124 | 125 | if (typeof JSON === 'undefined') { 126 | handleError('Browser error (JSON library not found)'); 127 | return; 128 | } 129 | 130 | _timeout = 4e4; 131 | var hasCors = XMLHttpRequest && ("withCredentials" in new XMLHttpRequest()); 132 | if(!hasCors){ 133 | 134 | if (typeof XDomainRequest !== 'undefined') { 135 | // Inicia jsonp 136 | _data.apiKey = _auth; 137 | var handleResponse = function(data){ 138 | if(data.error){ 139 | handleError('Request error', data.httpStatus, JSON.stringify(data)); 140 | } else { 141 | try { 142 | var beaconKey = data.data; 143 | console.log("beaconKey ok"); 144 | if(beaconKey.length > 0){ 145 | //Se lanza el script siftScience con el beaconKey obtenido 146 | OpenPay.deviceDataSC.setupSC(userId, sessionId, beaconKey,hostname); 147 | }else{ 148 | console.log("Empty beaconKey normal in Sandbox"); 149 | } 150 | } catch (e) { 151 | handleError('Response error (Unknown final status)', _rhr.status, '{}'); 152 | } 153 | } 154 | }; 155 | 156 | var request = { 157 | callbackName:"getResultData", 158 | onSuccess:handleResponse, 159 | onError:handleError, 160 | timeout:_timeout, 161 | url:_url+ "/jsonp", 162 | data:_data 163 | }; 164 | 165 | $jsonp.send(request); 166 | // Finaliza jsonp 167 | }else{ 168 | handleError('Browser error (CORS not supported)'); 169 | return; 170 | } 171 | 172 | } else{ 173 | 174 | function getXhr(){ 175 | if (isHostMethod(window, "XMLHttpRequest")) { 176 | return new XMLHttpRequest(); 177 | } 178 | }; 179 | 180 | function isHostMethod(object, property){ 181 | var t = typeof object[property]; 182 | return t == 'function' || 183 | (!!(t == 'object' && object[property])) || 184 | t == 'unknown'; 185 | }; 186 | 187 | function handleResponseBK(){ 188 | // handle only if request has finished 189 | if (typeof _rhr.readyState !== 'undefined' && _rhr.readyState == 4 || !hasCors) { 190 | clearTimeout(_timer); 191 | if (_rhr.status < 200 || _rhr.status >= 300) { 192 | handleError('Request error NO IE', _rhr.status, _rhr.responseText); 193 | } else { 194 | try { 195 | var rt = _rhr.responseText; 196 | rt = rt.replace("(",""); 197 | rt = rt.replace(")",""); 198 | var jsonResponse = JSON.parse(rt); 199 | var beaconKey = jsonResponse.data; 200 | console.log("beaconKey ok"); 201 | if(beaconKey.length > 0){ 202 | //Se lanza el script siftScience con el beaconKey obtenido 203 | OpenPay.deviceDataSC.setupSC(userId, sessionId, beaconKey, hostname); 204 | }else{ 205 | console.log("Empty beaconKey normal in Sandbox"); 206 | } 207 | } catch (e) { 208 | handleError('Response error (Unknown final status) NO IE', _rhr.status, '{}'); 209 | } 210 | } 211 | } 212 | }; 213 | 214 | if (!(_rhr = getXhr())) { 215 | handleError('Browser error (CORS not supported)'); 216 | return; 217 | } 218 | 219 | _headers = { 220 | 'Accept': 'application/json', 221 | 'Content-Type': 'application/json', 222 | 'Authorization': "Basic " + _auth 223 | }; 224 | 225 | _rhr.open('GET', _url, true); 226 | 227 | if ('withCredentials' in _rhr) { 228 | _rhr.withCredentials = true; 229 | } 230 | 231 | for (var prop in _headers) { 232 | if (_headers.hasOwnProperty(prop) && _headers[prop]) { 233 | if ('setRequestHeader' in _rhr) { 234 | _rhr.setRequestHeader(prop, _headers[prop]); 235 | } 236 | } 237 | } 238 | 239 | if ('onreadystatechange' in _rhr) { 240 | _rhr.onreadystatechange = handleResponseBK; 241 | } else if ('onload' in _rhr && 'onerror' in _rhr) { 242 | _rhr.onload = handleResponseBK; 243 | _rhr.onerror = handleError; 244 | } 245 | 246 | _timer = setTimeout(function(){ 247 | 248 | if ('onload' in _rhr) { 249 | _rhr.onload = Function.prototype; 250 | } else { 251 | _rhr.onreadystatechange = Function.prototype; 252 | } 253 | _rhr.abort(); 254 | _rhr = null; 255 | handleError('Timeout after ' + _timeout + ' milliseconds'); 256 | }, _timeout); 257 | 258 | _rhr.send(); 259 | 260 | } 261 | 262 | } 263 | 264 | /* Initialize the siftscience snippet for device detection */ 265 | _deviceDataSC['setupSC'] = function(userId, sessionId, beaconKey, hostname) { 266 | console.log("Sift Snippet"); 267 | var _sift = window._sift = window._sift || []; 268 | _sift.push(['_setAccount', beaconKey]); 269 | _sift.push(['_setSessionId', sessionId]); 270 | _sift.push(['_trackPageview']); 271 | 272 | var e = document.createElement('script'); 273 | e.type = 'text/javascript'; 274 | e.async = true; 275 | e.src = hostname+'antifraud/sc.js'; 276 | 277 | var s = document.getElementsByTagName('script')[0]; 278 | s.parentNode.insertBefore(e, s); 279 | }; 280 | 281 | OpenPay['deviceData'] = _deviceData; 282 | 283 | OpenPay['getBeaconKey'] = _getBeaconKey; 284 | 285 | OpenPay['deviceDataSC'] = _deviceDataSC; 286 | 287 | /* Bundled SJCL library with modules CodecBase64 and Random */ 288 | 289 | /* 290 | * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh. All rights 291 | * reserved. Redistribution and use in source and binary forms, with or 292 | * without modification, are permitted provided that the following 293 | * conditions are met: 294 | * 295 | * 1. Redistributions of source code must retain the above copyright notice, 296 | * this list of conditions and the following disclaimer. 297 | * 298 | * 2. Redistributions in binary form must reproduce the above copyright 299 | * notice, this list of conditions and the following disclaimer in the 300 | * documentation and/or other materials provided with the distribution. 301 | * 302 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 303 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 304 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 305 | * IN NO EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY 306 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 307 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 308 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 309 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 310 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 311 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 312 | * POSSIBILITY OF SUCH DAMAGE. 313 | * 314 | * The views and conclusions contained in the software and documentation are 315 | * those of the authors and should not be interpreted as representing 316 | * official policies, either expressed or implied, of the authors. 317 | */ 318 | 319 | var sjcl = {cipher:{}, hash:{}, keyexchange:{}, mode:{}, misc:{}, codec:{}, exception:{corrupt:function(message) { 320 | this.toString = function() { 321 | return"CORRUPT: " + this.message 322 | }; 323 | this.message = message 324 | }, invalid:function(message) { 325 | this.toString = function() { 326 | return"INVALID: " + this.message 327 | }; 328 | this.message = message 329 | }, bug:function(message) { 330 | this.toString = function() { 331 | return"BUG: " + this.message 332 | }; 333 | this.message = message 334 | }, notReady:function(message) { 335 | this.toString = function() { 336 | return"NOT READY: " + this.message 337 | }; 338 | this.message = message 339 | }}}; 340 | if(typeof module !== "undefined" && module.exports) { 341 | module.exports = sjcl 342 | } 343 | sjcl.cipher.aes = function(key) { 344 | if(!this._tables[0][0][0]) { 345 | this._precompute() 346 | } 347 | var i, j, tmp, encKey, decKey, sbox = this._tables[0][4], decTable = this._tables[1], keyLen = key.length, rcon = 1; 348 | if(keyLen !== 4 && keyLen !== 6 && keyLen !== 8) { 349 | throw new sjcl.exception.invalid("invalid aes key size"); 350 | } 351 | this._key = [encKey = key.slice(0), decKey = []]; 352 | for(i = keyLen;i < 4 * keyLen + 28;i++) { 353 | tmp = encKey[i - 1]; 354 | if(i % keyLen === 0 || keyLen === 8 && i % keyLen === 4) { 355 | tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255]; 356 | if(i % keyLen === 0) { 357 | tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24; 358 | rcon = rcon << 1 ^ (rcon >> 7) * 283 359 | } 360 | } 361 | encKey[i] = encKey[i - keyLen] ^ tmp 362 | } 363 | for(j = 0;i;j++, i--) { 364 | tmp = encKey[j & 3 ? i : i - 4]; 365 | if(i <= 4 || j < 4) { 366 | decKey[j] = tmp 367 | }else { 368 | decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[3][sbox[tmp & 255]] 369 | } 370 | } 371 | }; 372 | sjcl.cipher.aes.prototype = {encrypt:function(data) { 373 | return this._crypt(data, 0) 374 | }, decrypt:function(data) { 375 | return this._crypt(data, 1) 376 | }, _tables:[[[], [], [], [], []], [[], [], [], [], []]], _precompute:function() { 377 | var encTable = this._tables[0], decTable = this._tables[1], sbox = encTable[4], sboxInv = decTable[4], i, x, xInv, d = [], th = [], x2, x4, x8, s, tEnc, tDec; 378 | for(i = 0;i < 0x100;i++) { 379 | th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i 380 | } 381 | for(x = xInv = 0;!sbox[x];x ^= x2 || 1, xInv = th[xInv] || 1) { 382 | s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4; 383 | s = s >> 8 ^ s & 255 ^ 99; 384 | sbox[x] = s; 385 | sboxInv[s] = x; 386 | x8 = d[x4 = d[x2 = d[x]]]; 387 | tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100; 388 | tEnc = d[s] * 0x101 ^ s * 0x1010100; 389 | for(i = 0;i < 4;i++) { 390 | encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8; 391 | decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8 392 | } 393 | } 394 | for(i = 0;i < 5;i++) { 395 | encTable[i] = encTable[i].slice(0); 396 | decTable[i] = decTable[i].slice(0) 397 | } 398 | }, _crypt:function(input, dir) { 399 | if(input.length !== 4) { 400 | throw new sjcl.exception.invalid("invalid aes block size"); 401 | } 402 | var key = this._key[dir], a = input[0] ^ key[0], b = input[dir ? 3 : 1] ^ key[1], c = input[2] ^ key[2], d = input[dir ? 1 : 3] ^ key[3], a2, b2, c2, nInnerRounds = key.length / 4 - 2, i, kIndex = 4, out = [0, 0, 0, 0], table = this._tables[dir], t0 = table[0], t1 = table[1], t2 = table[2], t3 = table[3], sbox = table[4]; 403 | for(i = 0;i < nInnerRounds;i++) { 404 | a2 = t0[a >>> 24] ^ t1[b >> 16 & 255] ^ t2[c >> 8 & 255] ^ t3[d & 255] ^ key[kIndex]; 405 | b2 = t0[b >>> 24] ^ t1[c >> 16 & 255] ^ t2[d >> 8 & 255] ^ t3[a & 255] ^ key[kIndex + 1]; 406 | c2 = t0[c >>> 24] ^ t1[d >> 16 & 255] ^ t2[a >> 8 & 255] ^ t3[b & 255] ^ key[kIndex + 2]; 407 | d = t0[d >>> 24] ^ t1[a >> 16 & 255] ^ t2[b >> 8 & 255] ^ t3[c & 255] ^ key[kIndex + 3]; 408 | kIndex += 4; 409 | a = a2; 410 | b = b2; 411 | c = c2 412 | } 413 | for(i = 0;i < 4;i++) { 414 | out[dir ? 3 & -i : i] = sbox[a >>> 24] << 24 ^ sbox[b >> 16 & 255] << 16 ^ sbox[c >> 8 & 255] << 8 ^ sbox[d & 255] ^ key[kIndex++]; 415 | a2 = a; 416 | a = b; 417 | b = c; 418 | c = d; 419 | d = a2 420 | } 421 | return out 422 | }}; 423 | sjcl.bitArray = {bitSlice:function(a, bstart, bend) { 424 | a = sjcl.bitArray._shiftRight(a.slice(bstart / 32), 32 - (bstart & 31)).slice(1); 425 | return bend === undefined ? a : sjcl.bitArray.clamp(a, bend - bstart) 426 | }, extract:function(a, bstart, blength) { 427 | var x, sh = Math.floor(-bstart - blength & 31); 428 | if((bstart + blength - 1 ^ bstart) & -32) { 429 | x = a[bstart / 32 | 0] << 32 - sh ^ a[bstart / 32 + 1 | 0] >>> sh 430 | }else { 431 | x = a[bstart / 32 | 0] >>> sh 432 | } 433 | return x & (1 << blength) - 1 434 | }, concat:function(a1, a2) { 435 | if(a1.length === 0 || a2.length === 0) { 436 | return a1.concat(a2) 437 | } 438 | var out, i, last = a1[a1.length - 1], shift = sjcl.bitArray.getPartial(last); 439 | if(shift === 32) { 440 | return a1.concat(a2) 441 | }else { 442 | return sjcl.bitArray._shiftRight(a2, shift, last | 0, a1.slice(0, a1.length - 1)) 443 | } 444 | }, bitLength:function(a) { 445 | var l = a.length, x; 446 | if(l === 0) { 447 | return 0 448 | } 449 | x = a[l - 1]; 450 | return(l - 1) * 32 + sjcl.bitArray.getPartial(x) 451 | }, clamp:function(a, len) { 452 | if(a.length * 32 < len) { 453 | return a 454 | } 455 | a = a.slice(0, Math.ceil(len / 32)); 456 | var l = a.length; 457 | len = len & 31; 458 | if(l > 0 && len) { 459 | a[l - 1] = sjcl.bitArray.partial(len, a[l - 1] & 2147483648 >> len - 1, 1) 460 | } 461 | return a 462 | }, partial:function(len, x, _end) { 463 | if(len === 32) { 464 | return x 465 | } 466 | return(_end ? x | 0 : x << 32 - len) + len * 0x10000000000 467 | }, getPartial:function(x) { 468 | return Math.round(x / 0x10000000000) || 32 469 | }, equal:function(a, b) { 470 | if(sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) { 471 | return false 472 | } 473 | var x = 0, i; 474 | for(i = 0;i < a.length;i++) { 475 | x |= a[i] ^ b[i] 476 | } 477 | return x === 0 478 | }, _shiftRight:function(a, shift, carry, out) { 479 | var i, last2 = 0, shift2; 480 | if(out === undefined) { 481 | out = [] 482 | } 483 | for(;shift >= 32;shift -= 32) { 484 | out.push(carry); 485 | carry = 0 486 | } 487 | if(shift === 0) { 488 | return out.concat(a) 489 | } 490 | for(i = 0;i < a.length;i++) { 491 | out.push(carry | a[i] >>> shift); 492 | carry = a[i] << 32 - shift 493 | } 494 | last2 = a.length ? a[a.length - 1] : 0; 495 | shift2 = sjcl.bitArray.getPartial(last2); 496 | out.push(sjcl.bitArray.partial(shift + shift2 & 31, shift + shift2 > 32 ? carry : out.pop(), 1)); 497 | return out 498 | }, _xor4:function(x, y) { 499 | return[x[0] ^ y[0], x[1] ^ y[1], x[2] ^ y[2], x[3] ^ y[3]] 500 | }}; 501 | sjcl.codec.utf8String = {fromBits:function(arr) { 502 | var out = "", bl = sjcl.bitArray.bitLength(arr), i, tmp; 503 | for(i = 0;i < bl / 8;i++) { 504 | if((i & 3) === 0) { 505 | tmp = arr[i / 4] 506 | } 507 | out += String.fromCharCode(tmp >>> 24); 508 | tmp <<= 8 509 | } 510 | return decodeURIComponent(escape(out)) 511 | }, toBits:function(str) { 512 | str = unescape(encodeURIComponent(str)); 513 | var out = [], i, tmp = 0; 514 | for(i = 0;i < str.length;i++) { 515 | tmp = tmp << 8 | str.charCodeAt(i); 516 | if((i & 3) === 3) { 517 | out.push(tmp); 518 | tmp = 0 519 | } 520 | } 521 | if(i & 3) { 522 | out.push(sjcl.bitArray.partial(8 * (i & 3), tmp)) 523 | } 524 | return out 525 | }}; 526 | sjcl.codec.base64 = {_chars:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", fromBits:function(arr, _noEquals, _url) { 527 | var out = "", i, bits = 0, c = sjcl.codec.base64._chars, ta = 0, bl = sjcl.bitArray.bitLength(arr); 528 | if(_url) { 529 | c = c.substr(0, 62) + "-_" 530 | } 531 | for(i = 0;out.length * 6 < bl;) { 532 | out += c.charAt((ta ^ arr[i] >>> bits) >>> 26); 533 | if(bits < 6) { 534 | ta = arr[i] << 6 - bits; 535 | bits += 26; 536 | i++ 537 | }else { 538 | ta <<= 6; 539 | bits -= 6 540 | } 541 | } 542 | while(out.length & 3 && !_noEquals) { 543 | out += "=" 544 | } 545 | return out 546 | }, toBits:function(str, _url) { 547 | str = str.replace(/\s|=/g, ""); 548 | var out = [], i, bits = 0, c = sjcl.codec.base64._chars, ta = 0, x; 549 | if(_url) { 550 | c = c.substr(0, 62) + "-_" 551 | } 552 | for(i = 0;i < str.length;i++) { 553 | x = c.indexOf(str.charAt(i)); 554 | if(x < 0) { 555 | throw new sjcl.exception.invalid("this isn't base64!"); 556 | } 557 | if(bits > 26) { 558 | bits -= 26; 559 | out.push(ta ^ x >>> bits); 560 | ta = x << 32 - bits 561 | }else { 562 | bits += 6; 563 | ta ^= x << 32 - bits 564 | } 565 | } 566 | if(bits & 56) { 567 | out.push(sjcl.bitArray.partial(bits & 56, ta, 1)) 568 | } 569 | return out 570 | }}; 571 | sjcl.codec.base64url = {fromBits:function(arr) { 572 | return sjcl.codec.base64.fromBits(arr, 1, 1) 573 | }, toBits:function(str) { 574 | return sjcl.codec.base64.toBits(str, 1) 575 | }}; 576 | sjcl.hash.sha256 = function(hash) { 577 | if(!this._key[0]) { 578 | this._precompute() 579 | } 580 | if(hash) { 581 | this._h = hash._h.slice(0); 582 | this._buffer = hash._buffer.slice(0); 583 | this._length = hash._length 584 | }else { 585 | this.reset() 586 | } 587 | }; 588 | sjcl.hash.sha256.hash = function(data) { 589 | return(new sjcl.hash.sha256).update(data).finalize() 590 | }; 591 | sjcl.hash.sha256.prototype = {blockSize:512, reset:function() { 592 | this._h = this._init.slice(0); 593 | this._buffer = []; 594 | this._length = 0; 595 | return this 596 | }, update:function(data) { 597 | if(typeof data === "string") { 598 | data = sjcl.codec.utf8String.toBits(data) 599 | } 600 | var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data), ol = this._length, nl = this._length = ol + sjcl.bitArray.bitLength(data); 601 | for(i = 512 + ol & -512;i <= nl;i += 512) { 602 | this._block(b.splice(0, 16)) 603 | } 604 | return this 605 | }, finalize:function() { 606 | var i, b = this._buffer, h = this._h; 607 | b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1, 1)]); 608 | for(i = b.length + 2;i & 15;i++) { 609 | b.push(0) 610 | } 611 | b.push(Math.floor(this._length / 0x100000000)); 612 | b.push(this._length | 0); 613 | while(b.length) { 614 | this._block(b.splice(0, 16)) 615 | } 616 | this.reset(); 617 | return h 618 | }, _init:[], _key:[], _precompute:function() { 619 | var i = 0, prime = 2, factor; 620 | function frac(x) { 621 | return(x - Math.floor(x)) * 0x100000000 | 0 622 | } 623 | outer:for(;i < 64;prime++) { 624 | for(factor = 2;factor * factor <= prime;factor++) { 625 | if(prime % factor === 0) { 626 | continue outer 627 | } 628 | } 629 | if(i < 8) { 630 | this._init[i] = frac(Math.pow(prime, 1 / 2)) 631 | } 632 | this._key[i] = frac(Math.pow(prime, 1 / 3)); 633 | i++ 634 | } 635 | }, _block:function(words) { 636 | var i, tmp, a, b, w = words.slice(0), h = this._h, k = this._key, h0 = h[0], h1 = h[1], h2 = h[2], h3 = h[3], h4 = h[4], h5 = h[5], h6 = h[6], h7 = h[7]; 637 | for(i = 0;i < 64;i++) { 638 | if(i < 16) { 639 | tmp = w[i] 640 | }else { 641 | a = w[i + 1 & 15]; 642 | b = w[i + 14 & 15]; 643 | tmp = w[i & 15] = (a >>> 7 ^ a >>> 18 ^ a >>> 3 ^ a << 25 ^ a << 14) + (b >>> 17 ^ b >>> 19 ^ b >>> 10 ^ b << 15 ^ b << 13) + w[i & 15] + w[i + 9 & 15] | 0 644 | } 645 | tmp = tmp + h7 + (h4 >>> 6 ^ h4 >>> 11 ^ h4 >>> 25 ^ h4 << 26 ^ h4 << 21 ^ h4 << 7) + (h6 ^ h4 & (h5 ^ h6)) + k[i]; 646 | h7 = h6; 647 | h6 = h5; 648 | h5 = h4; 649 | h4 = h3 + tmp | 0; 650 | h3 = h2; 651 | h2 = h1; 652 | h1 = h0; 653 | h0 = tmp + (h1 & h2 ^ h3 & (h1 ^ h2)) + (h1 >>> 2 ^ h1 >>> 13 ^ h1 >>> 22 ^ h1 << 30 ^ h1 << 19 ^ h1 << 10) | 0 654 | } 655 | h[0] = h[0] + h0 | 0; 656 | h[1] = h[1] + h1 | 0; 657 | h[2] = h[2] + h2 | 0; 658 | h[3] = h[3] + h3 | 0; 659 | h[4] = h[4] + h4 | 0; 660 | h[5] = h[5] + h5 | 0; 661 | h[6] = h[6] + h6 | 0; 662 | h[7] = h[7] + h7 | 0 663 | }}; 664 | sjcl.prng = function(defaultParanoia) { 665 | this._pools = [new sjcl.hash.sha256]; 666 | this._poolEntropy = [0]; 667 | this._reseedCount = 0; 668 | this._robins = {}; 669 | this._eventId = 0; 670 | this._collectorIds = {}; 671 | this._collectorIdNext = 0; 672 | this._strength = 0; 673 | this._poolStrength = 0; 674 | this._nextReseed = 0; 675 | this._key = [0, 0, 0, 0, 0, 0, 0, 0]; 676 | this._counter = [0, 0, 0, 0]; 677 | this._cipher = undefined; 678 | this._defaultParanoia = defaultParanoia; 679 | this._collectorsStarted = false; 680 | this._callbacks = {progress:{}, seeded:{}}; 681 | this._callbackI = 0; 682 | this._NOT_READY = 0; 683 | this._READY = 1; 684 | this._REQUIRES_RESEED = 2; 685 | this._MAX_WORDS_PER_BURST = 0x10000; 686 | this._PARANOIA_LEVELS = [0, 48, 64, 96, 128, 192, 0x100, 384, 512, 768, 1024]; 687 | this._MILLISECONDS_PER_RESEED = 3E4; 688 | this._BITS_PER_RESEED = 80 689 | }; 690 | sjcl.prng.prototype = {randomWords:function(nwords, paranoia) { 691 | var out = [], i, readiness = this.isReady(paranoia), g; 692 | if(readiness === this._NOT_READY) { 693 | throw new sjcl.exception.notReady("generator isn't seeded"); 694 | }else { 695 | if(readiness & this._REQUIRES_RESEED) { 696 | this._reseedFromPools(!(readiness & this._READY)) 697 | } 698 | } 699 | for(i = 0;i < nwords;i += 4) { 700 | if((i + 1) % this._MAX_WORDS_PER_BURST === 0) { 701 | this._gate() 702 | } 703 | g = this._gen4words(); 704 | out.push(g[0], g[1], g[2], g[3]) 705 | } 706 | this._gate(); 707 | return out.slice(0, nwords) 708 | }, setDefaultParanoia:function(paranoia, allowZeroParanoia) { 709 | if(paranoia === 0 && allowZeroParanoia !== "Setting paranoia=0 will ruin your security; use it only for testing") { 710 | throw"Setting paranoia=0 will ruin your security; use it only for testing"; 711 | } 712 | this._defaultParanoia = paranoia 713 | }, addEntropy:function(data, estimatedEntropy, source) { 714 | source = source || "user"; 715 | var id, i, tmp, t = (new Date).valueOf(), robin = this._robins[source], oldReady = this.isReady(), err = 0, objName; 716 | id = this._collectorIds[source]; 717 | if(id === undefined) { 718 | id = this._collectorIds[source] = this._collectorIdNext++ 719 | } 720 | if(robin === undefined) { 721 | robin = this._robins[source] = 0 722 | } 723 | this._robins[source] = (this._robins[source] + 1) % this._pools.length; 724 | switch(typeof data) { 725 | case "number": 726 | if(estimatedEntropy === undefined) { 727 | estimatedEntropy = 1 728 | } 729 | this._pools[robin].update([id, this._eventId++, 1, estimatedEntropy, t, 1, data | 0]); 730 | break; 731 | case "object": 732 | objName = Object.prototype.toString.call(data); 733 | if(objName === "[object Uint32Array]") { 734 | tmp = []; 735 | for(i = 0;i < data.length;i++) { 736 | tmp.push(data[i]) 737 | } 738 | data = tmp 739 | }else { 740 | if(objName !== "[object Array]") { 741 | err = 1 742 | } 743 | for(i = 0;i < data.length && !err;i++) { 744 | if(typeof data[i] !== "number") { 745 | err = 1 746 | } 747 | } 748 | } 749 | if(!err) { 750 | if(estimatedEntropy === undefined) { 751 | estimatedEntropy = 0; 752 | for(i = 0;i < data.length;i++) { 753 | tmp = data[i]; 754 | while(tmp > 0) { 755 | estimatedEntropy++; 756 | tmp = tmp >>> 1 757 | } 758 | } 759 | } 760 | this._pools[robin].update([id, this._eventId++, 2, estimatedEntropy, t, data.length].concat(data)) 761 | } 762 | break; 763 | case "string": 764 | if(estimatedEntropy === undefined) { 765 | estimatedEntropy = data.length 766 | } 767 | this._pools[robin].update([id, this._eventId++, 3, estimatedEntropy, t, data.length]); 768 | this._pools[robin].update(data); 769 | break; 770 | default: 771 | err = 1 772 | } 773 | if(err) { 774 | throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string"); 775 | } 776 | this._poolEntropy[robin] += estimatedEntropy; 777 | this._poolStrength += estimatedEntropy; 778 | if(oldReady === this._NOT_READY) { 779 | if(this.isReady() !== this._NOT_READY) { 780 | this._fireEvent("seeded", Math.max(this._strength, this._poolStrength)) 781 | } 782 | this._fireEvent("progress", this.getProgress()) 783 | } 784 | }, isReady:function(paranoia) { 785 | var entropyRequired = this._PARANOIA_LEVELS[paranoia !== undefined ? paranoia : this._defaultParanoia]; 786 | if(this._strength && this._strength >= entropyRequired) { 787 | return this._poolEntropy[0] > this._BITS_PER_RESEED && (new Date).valueOf() > this._nextReseed ? this._REQUIRES_RESEED | this._READY : this._READY 788 | }else { 789 | return this._poolStrength >= entropyRequired ? this._REQUIRES_RESEED | this._NOT_READY : this._NOT_READY 790 | } 791 | }, getProgress:function(paranoia) { 792 | var entropyRequired = this._PARANOIA_LEVELS[paranoia ? paranoia : this._defaultParanoia]; 793 | if(this._strength >= entropyRequired) { 794 | return 1 795 | }else { 796 | return this._poolStrength > entropyRequired ? 1 : this._poolStrength / entropyRequired 797 | } 798 | }, startCollectors:function() { 799 | if(this._collectorsStarted) { 800 | return 801 | } 802 | this._eventListener = {loadTimeCollector:this._bind(this._loadTimeCollector), mouseCollector:this._bind(this._mouseCollector), accelerometerCollector:this._bind(this._accelerometerCollector)}; 803 | if(window.addEventListener) { 804 | window.addEventListener("load", this._eventListener.loadTimeCollector, false); 805 | window.addEventListener("mousemove", this._eventListener.mouseCollector, false); 806 | window.addEventListener("devicemotion", this._eventListener.accelerometerCollector, false) 807 | }else { 808 | if(document.attachEvent) { 809 | document.attachEvent("onload", this._eventListener.loadTimeCollector); 810 | document.attachEvent("onmousemove", this._eventListener.mouseCollector); 811 | }else { 812 | throw new sjcl.exception.bug("can't attach event"); 813 | } 814 | } 815 | this._collectorsStarted = true 816 | }, stopCollectors:function() { 817 | if(!this._collectorsStarted) { 818 | return 819 | } 820 | if(window.removeEventListener) { 821 | window.removeEventListener("load", this._eventListener.loadTimeCollector, false); 822 | window.removeEventListener("mousemove", this._eventListener.mouseCollector, false); 823 | window.removeEventListener("devicemotion", this._eventListener.accelerometerCollector, false) 824 | }else { 825 | if(document.detachEvent) { 826 | document.detachEvent("onload", this._eventListener.loadTimeCollector); 827 | document.detachEvent("onmousemove", this._eventListener.mouseCollector); 828 | } 829 | } 830 | this._collectorsStarted = false 831 | }, addEventListener:function(name, callback) { 832 | this._callbacks[name][this._callbackI++] = callback 833 | }, removeEventListener:function(name, cb) { 834 | var i, j, cbs = this._callbacks[name], jsTemp = []; 835 | for(j in cbs) { 836 | if(cbs.hasOwnProperty(j) && cbs[j] === cb) { 837 | jsTemp.push(j) 838 | } 839 | } 840 | for(i = 0;i < jsTemp.length;i++) { 841 | j = jsTemp[i]; 842 | delete cbs[j] 843 | } 844 | }, _bind:function(func) { 845 | var that = this; 846 | return function() { 847 | func.apply(that, arguments) 848 | } 849 | }, _gen4words:function() { 850 | for(var i = 0;i < 4;i++) { 851 | this._counter[i] = this._counter[i] + 1 | 0; 852 | if(this._counter[i]) { 853 | break 854 | } 855 | } 856 | return this._cipher.encrypt(this._counter) 857 | }, _gate:function() { 858 | this._key = this._gen4words().concat(this._gen4words()); 859 | this._cipher = new sjcl.cipher.aes(this._key) 860 | }, _reseed:function(seedWords) { 861 | this._key = sjcl.hash.sha256.hash(this._key.concat(seedWords)); 862 | this._cipher = new sjcl.cipher.aes(this._key); 863 | for(var i = 0;i < 4;i++) { 864 | this._counter[i] = this._counter[i] + 1 | 0; 865 | if(this._counter[i]) { 866 | break 867 | } 868 | } 869 | }, _reseedFromPools:function(full) { 870 | var reseedData = [], strength = 0, i; 871 | this._nextReseed = reseedData[0] = (new Date).valueOf() + this._MILLISECONDS_PER_RESEED; 872 | for(i = 0;i < 16;i++) { 873 | reseedData.push(Math.random() * 0x100000000 | 0) 874 | } 875 | for(i = 0;i < this._pools.length;i++) { 876 | reseedData = reseedData.concat(this._pools[i].finalize()); 877 | strength += this._poolEntropy[i]; 878 | this._poolEntropy[i] = 0; 879 | if(!full && this._reseedCount & 1 << i) { 880 | break 881 | } 882 | } 883 | if(this._reseedCount >= 1 << this._pools.length) { 884 | this._pools.push(new sjcl.hash.sha256); 885 | this._poolEntropy.push(0) 886 | } 887 | this._poolStrength -= strength; 888 | if(strength > this._strength) { 889 | this._strength = strength 890 | } 891 | this._reseedCount++; 892 | this._reseed(reseedData) 893 | }, _mouseCollector:function(ev) { 894 | var x = ev.x || ev.clientX || ev.offsetX || 0, y = ev.y || ev.clientY || ev.offsetY || 0; 895 | sjcl.random.addEntropy([x, y], 2, "mouse"); 896 | this._addCurrentTimeToEntropy(0) 897 | }, _loadTimeCollector:function() { 898 | this._addCurrentTimeToEntropy(2) 899 | }, _addCurrentTimeToEntropy:function(estimatedEntropy) { 900 | if(window && window.performance && typeof window.performance.now === "function") { 901 | sjcl.random.addEntropy(window.performance.now(), estimatedEntropy, "loadtime") 902 | }else { 903 | sjcl.random.addEntropy((new Date).valueOf(), estimatedEntropy, "loadtime") 904 | } 905 | }, _accelerometerCollector:function(ev) { 906 | var ac = ev.accelerationIncludingGravity.x || ev.accelerationIncludingGravity.y || ev.accelerationIncludingGravity.z; 907 | if(window.orientation) { 908 | var or = window.orientation; 909 | if(typeof or === "number") { 910 | sjcl.random.addEntropy(or, 1, "accelerometer") 911 | } 912 | } 913 | if(ac) { 914 | sjcl.random.addEntropy(ac, 2, "accelerometer") 915 | } 916 | this._addCurrentTimeToEntropy(0) 917 | }, _fireEvent:function(name, arg) { 918 | var j, cbs = sjcl.random._callbacks[name], cbsTemp = []; 919 | for(j in cbs) { 920 | if(cbs.hasOwnProperty(j)) { 921 | cbsTemp.push(cbs[j]) 922 | } 923 | } 924 | for(j = 0;j < cbsTemp.length;j++) { 925 | cbsTemp[j](arg) 926 | } 927 | }}; 928 | sjcl.random = new sjcl.prng(6); 929 | (function() { 930 | try { 931 | var buf, crypt, getRandomValues, ab; 932 | if(typeof module !== "undefined" && module.exports && (crypt = require("crypto")) && crypt.randomBytes) { 933 | buf = crypt.randomBytes(1024 / 8); 934 | buf = new Uint32Array((new Uint8Array(buf)).buffer); 935 | sjcl.random.addEntropy(buf, 1024, "crypto.randomBytes") 936 | }else { 937 | if(window && Uint32Array) { 938 | ab = new Uint32Array(32); 939 | if(window.crypto && window.crypto.getRandomValues) { 940 | window.crypto.getRandomValues(ab) 941 | }else { 942 | if(window.msCrypto && window.msCrypto.getRandomValues) { 943 | window.msCrypto.getRandomValues(ab) 944 | }else { 945 | return 946 | } 947 | } 948 | sjcl.random.addEntropy(ab, 1024, "crypto.getRandomValues") 949 | }else { 950 | } 951 | } 952 | }catch(e) { 953 | console.log("There was an error collecting entropy from the browser:"); 954 | console.log(e) 955 | } 956 | })(); 957 | }).call(this); 958 | 959 | -------------------------------------------------------------------------------- /lib/openpay-data.v1.min.js: -------------------------------------------------------------------------------- 1 | /*! openpay-data.js v1.2.39 2023-07-25 */ 2 | !function(){var r=function(){},t=function(){},e=function(){};function s(){return r._deviceDataId=r._deviceDataId===undefined?v.codec.base64.fromBits(v.random.randomWords(6,0)).replace(/[\+\/]/g,"0"):r._deviceDataId}function a(){var t,e,n=s(),o=OpenPay.developMode?r._developHostname:OpenPay.sandboxMode?r._sandboxHostname:r._hostname,i=OpenPay.getId();return o=(o=o)+"antifraud/"+i+"/components?s="+n,window.XDomainRequest?((t=new XDomainRequest).open("GET",o),t.onload=function(){document.body.insertAdjacentHTML("beforeend",t.responseText)},setTimeout(function(){t.send()},0)):((e=new XMLHttpRequest).onreadystatechange=function(){4==e.readyState&&200==e.status&&document.body.insertAdjacentHTML("beforeend",e.responseText)},e.open("GET",o,!0),e.send()),s()}r._hostname="https://api.openpay.mx/",r._sandboxHostname="https://sandbox-api.openpay.mx/",r._developHostname="https://dev-api.openpay.mx/",r._deviceDataId=undefined,r.setup=function(t,e){var n=s(),e=(t&&document.getElementById(t)&&((o=document.createElement("input")).setAttribute("type","hidden"),o.value=n,o.name=e||"deviceDataId",o.id=e||"deviceDataId",document.getElementById(t).appendChild(o)),!0);try{OpenPay.getId(),OpenPay.getApiKey()}catch(i){e=!1}if(e){console.log("executing sift mode");var t=OpenPay.getId(),o=OpenPay.getApiKey(),e=OpenPay.developMode?r._developHostname:OpenPay.sandboxMode?r._sandboxHostname:r._hostname,t=e+"v1/"+t+"/antifraudkeys";try{OpenPay.getBeaconKey.beaconKey(t,o,"",n,e)}catch(i){console.log("continue without beaconkey"+i)}}return a()},e.beaconKey=function(t,e,o,i,r){var s=null,a=null,n={},e=btoa(e+":"),c={};function h(t,e,n){clearTimeout(a);n=n||"{}";try{JSON.parse(n)}catch(o){}}if("undefined"==typeof JSON)h();else{var l=XMLHttpRequest&&"withCredentials"in new XMLHttpRequest;if(l){function d(){if("undefined"!=typeof s.readyState&&4==s.readyState||!l)if(clearTimeout(a),s.status<200||300<=s.status)h(0,s.status,s.responseText);else try{var t=s.responseText;t=(t=t.replace("(","")).replace(")","");var e=JSON.parse(t).data;console.log("beaconKey ok"),0>>24]<<24^s[o>>16&255]<<16^s[o>>8&255]<<8^s[255&o],e%c==0)&&(o=o<<8^o>>>24^h<<24,h=h<<1^283*(h>>7)),i[e]=i[e-c]^o;for(n=0;e;n++,e--)o=i[3&n?e:e-4],r[n]=e<=4||n<4?o:a[0][s[o>>>24]]^a[1][s[o>>16&255]]^a[2][s[o>>8&255]]^a[3][s[255&o]]},v.cipher.aes.prototype={encrypt:function(t){return this._crypt(t,0)},decrypt:function(t){return this._crypt(t,1)},_tables:[[[],[],[],[],[]],[[],[],[],[],[]]],_precompute:function(){for(var t,e,n,o,i,r,s,a=this._tables[0],c=this._tables[1],h=a[4],l=c[4],d=[],u=[],p=0;p<256;p++)u[(d[p]=p<<1^283*(p>>7))^p]=p;for(t=e=0;!h[t];t^=n||1,e=u[e]||1)for(s=16843009*d[o=d[n=d[l[h[t]=i=(i=e^e<<1^e<<2^e<<3^e<<4)>>8^255&i^99]=t]]]^65537*o^257*n^16843008*t,r=257*d[i]^16843008*i,p=0;p<4;p++)a[p][t]=r=r<<24^r>>>8,c[p][i]=s=s<<24^s>>>8;for(p=0;p<5;p++)a[p]=a[p].slice(0),c[p]=c[p].slice(0)},_crypt:function(t,e){if(4!==t.length)throw new v.exception.invalid("invalid aes block size");for(var n,o,i,r=this._key[e],s=t[0]^r[0],a=t[e?3:1]^r[1],c=t[2]^r[2],h=t[e?1:3]^r[3],l=r.length/4-2,d=4,u=[0,0,0,0],t=this._tables[e],p=t[0],_=t[1],f=t[2],y=t[3],m=t[4],g=0;g>>24]^_[a>>16&255]^f[c>>8&255]^y[255&h]^r[d],o=p[a>>>24]^_[c>>16&255]^f[h>>8&255]^y[255&s]^r[d+1],i=p[c>>>24]^_[h>>16&255]^f[s>>8&255]^y[255&a]^r[d+2],h=p[h>>>24]^_[s>>16&255]^f[a>>8&255]^y[255&c]^r[d+3],d+=4,s=n,a=o,c=i;for(g=0;g<4;g++)u[e?3&-g:g]=m[s>>>24]<<24^m[a>>16&255]<<16^m[c>>8&255]<<8^m[255&h]^r[d++],n=s,s=a,a=c,c=h,h=n;return u}},v.bitArray={bitSlice:function(t,e,n){return t=v.bitArray._shiftRight(t.slice(e/32),32-(31&e)).slice(1),n===undefined?t:v.bitArray.clamp(t,n-e)},extract:function(t,e,n){var o=Math.floor(-e-n&31),e=-32&(e+n-1^e)?t[e/32|0]<<32-o^t[e/32+1|0]>>>o:t[e/32|0]>>>o;return e&(1<>e-1,1))),t},partial:function(t,e,n){return 32===t?e:(n?0|e:e<<32-t)+1099511627776*t},getPartial:function(t){return Math.round(t/1099511627776)||32},equal:function(t,e){if(v.bitArray.bitLength(t)!==v.bitArray.bitLength(e))return!1;for(var n=0,o=0;o>>e),n=t[i]<<32-e;return r=t.length?t[t.length-1]:0,r=v.bitArray.getPartial(r),o.push(v.bitArray.partial(e+r&31,32>>24),e<<=8;return decodeURIComponent(escape(n))},toBits:function(t){t=unescape(encodeURIComponent(t));for(var e=[],n=0,o=0;o>>r)>>>26),r<6?(a=t[o]<<6-r,r+=26,o++):(a<<=6,r-=6);for(;3&i.length&&!e;)i+="=";return i},toBits:function(t,e){t=t.replace(/\s|=/g,"");var n,o,i=[],r=0,s=v.codec.base64._chars,a=0;for(e&&(s=s.substr(0,62)+"-_"),n=0;n>>(r-=26)),a=o<<32-r):a^=o<<32-(r+=6)}return 56&r&&i.push(v.bitArray.partial(56&r,a,1)),i}},v.codec.base64url={fromBits:function(t){return v.codec.base64.fromBits(t,1,1)},toBits:function(t){return v.codec.base64.toBits(t,1)}},v.hash.sha256=function(t){this._key[0]||this._precompute(),t?(this._h=t._h.slice(0),this._buffer=t._buffer.slice(0),this._length=t._length):this.reset()},v.hash.sha256.hash=function(t){return(new v.hash.sha256).update(t).finalize()},v.hash.sha256.prototype={blockSize:512,reset:function(){return this._h=this._init.slice(0),this._buffer=[],this._length=0,this},update:function(t){"string"==typeof t&&(t=v.codec.utf8String.toBits(t));for(var e=this._buffer=v.bitArray.concat(this._buffer,t),n=this._length,o=this._length=n+v.bitArray.bitLength(t),i=512+n&-512;i<=o;i+=512)this._block(e.splice(0,16));return this},finalize:function(){for(var t=this._buffer,e=this._h,n=(t=v.bitArray.concat(t,[v.bitArray.partial(1,1)])).length+2;15&n;n++)t.push(0);for(t.push(Math.floor(this._length/4294967296)),t.push(0|this._length);t.length;)this._block(t.splice(0,16));return this.reset(),e},_init:[],_key:[],_precompute:function(){var t,e=0,n=2;function o(t){return 4294967296*(t-Math.floor(t))|0}t:for(;e<64;n++){for(t=2;t*t<=n;t++)if(n%t==0)continue t;e<8&&(this._init[e]=o(Math.pow(n,.5))),this._key[e]=o(Math.pow(n,1/3)),e++}},_block:function(t){for(var e,n,o=t.slice(0),t=this._h,i=this._key,r=t[0],s=t[1],a=t[2],c=t[3],h=t[4],l=t[5],d=t[6],u=t[7],p=0;p<64;p++)e=(e=p<16?o[p]:(e=o[p+1&15],n=o[p+14&15],o[15&p]=(e>>>7^e>>>18^e>>>3^e<<25^e<<14)+(n>>>17^n>>>19^n>>>10^n<<15^n<<13)+o[15&p]+o[p+9&15]|0))+u+(h>>>6^h>>>11^h>>>25^h<<26^h<<21^h<<7)+(d^h&(l^d))+i[p],u=d,d=l,l=h,h=c+e|0,c=a,a=s,r=e+((s=r)&a^c&(s^a))+(s>>>2^s>>>13^s>>>22^s<<30^s<<19^s<<10)|0;t[0]=t[0]+r|0,t[1]=t[1]+s|0,t[2]=t[2]+a|0,t[3]=t[3]+c|0,t[4]=t[4]+h|0,t[5]=t[5]+l|0,t[6]=t[6]+d|0,t[7]=t[7]+u|0}},v.prng=function(t){this._pools=[new v.hash.sha256],this._poolEntropy=[0],this._reseedCount=0,this._robins={},this._eventId=0,this._collectorIds={},this._collectorIdNext=0,this._strength=0,this._poolStrength=0,this._nextReseed=0,this._key=[0,0,0,0,0,0,0,0],this._counter=[0,0,0,0],this._cipher=undefined,this._defaultParanoia=t,this._collectorsStarted=!1,this._callbacks={progress:{},seeded:{}},this._callbackI=0,this._NOT_READY=0,this._READY=1,this._REQUIRES_RESEED=2,this._MAX_WORDS_PER_BURST=65536,this._PARANOIA_LEVELS=[0,48,64,96,128,192,256,384,512,768,1024],this._MILLISECONDS_PER_RESEED=3e4,this._BITS_PER_RESEED=80},v.prng.prototype={randomWords:function(t,e){var n,o,i=[],e=this.isReady(e);if(e===this._NOT_READY)throw new v.exception.notReady("generator isn't seeded");for(e&this._REQUIRES_RESEED&&this._reseedFromPools(!(e&this._READY)),n=0;n>>=1;this._pools[a].update([l,this._eventId++,2,e,s,t.length].concat(t))}break;case"string":e===undefined&&(e=t.length),this._pools[a].update([l,this._eventId++,3,e,s,t.length]),this._pools[a].update(t);break;default:h=1}if(h)throw new v.exception.bug("random: addEntropy only supports number, array of numbers or string");this._poolEntropy[a]+=e,this._poolStrength+=e,c===this._NOT_READY&&(this.isReady()!==this._NOT_READY&&this._fireEvent("seeded",Math.max(this._strength,this._poolStrength)),this._fireEvent("progress",this.getProgress()))},isReady:function(t){t=this._PARANOIA_LEVELS[t!==undefined?t:this._defaultParanoia];return this._strength&&this._strength>=t?this._poolEntropy[0]>this._BITS_PER_RESEED&&(new Date).valueOf()>this._nextReseed?this._REQUIRES_RESEED|this._READY:this._READY:this._poolStrength>=t?this._REQUIRES_RESEED|this._NOT_READY:this._NOT_READY},getProgress:function(t){t=this._PARANOIA_LEVELS[t||this._defaultParanoia];return this._strength>=t||this._poolStrength>t?1:this._poolStrength/t},startCollectors:function(){if(!this._collectorsStarted){if(this._eventListener={loadTimeCollector:this._bind(this._loadTimeCollector),mouseCollector:this._bind(this._mouseCollector),accelerometerCollector:this._bind(this._accelerometerCollector)},window.addEventListener)window.addEventListener("load",this._eventListener.loadTimeCollector,!1),window.addEventListener("mousemove",this._eventListener.mouseCollector,!1),window.addEventListener("devicemotion",this._eventListener.accelerometerCollector,!1);else{if(!document.attachEvent)throw new v.exception.bug("can't attach event");document.attachEvent("onload",this._eventListener.loadTimeCollector),document.attachEvent("onmousemove",this._eventListener.mouseCollector)}this._collectorsStarted=!0}},stopCollectors:function(){this._collectorsStarted&&(window.removeEventListener?(window.removeEventListener("load",this._eventListener.loadTimeCollector,!1),window.removeEventListener("mousemove",this._eventListener.mouseCollector,!1),window.removeEventListener("devicemotion",this._eventListener.accelerometerCollector,!1)):document.detachEvent&&(document.detachEvent("onload",this._eventListener.loadTimeCollector),document.detachEvent("onmousemove",this._eventListener.mouseCollector)),this._collectorsStarted=!1)},addEventListener:function(t,e){this._callbacks[t][this._callbackI++]=e},removeEventListener:function(t,e){var n,o,i=this._callbacks[t],r=[];for(o in i)i.hasOwnProperty(o)&&i[o]===e&&r.push(o);for(n=0;n=1<this._strength&&(this._strength=o),this._reseedCount++,this._reseed(n)},_mouseCollector:function(t){var e=t.x||t.clientX||t.offsetX||0,t=t.y||t.clientY||t.offsetY||0;v.random.addEntropy([e,t],2,"mouse"),this._addCurrentTimeToEntropy(0)},_loadTimeCollector:function(){this._addCurrentTimeToEntropy(2)},_addCurrentTimeToEntropy:function(t){window&&window.performance&&"function"==typeof window.performance.now?v.random.addEntropy(window.performance.now(),t,"loadtime"):v.random.addEntropy((new Date).valueOf(),t,"loadtime")},_accelerometerCollector:function(t){var e,t=t.accelerationIncludingGravity.x||t.accelerationIncludingGravity.y||t.accelerationIncludingGravity.z;window.orientation&&"number"==typeof(e=window.orientation)&&v.random.addEntropy(e,1,"accelerometer"),t&&v.random.addEntropy(t,2,"accelerometer"),this._addCurrentTimeToEntropy(0)},_fireEvent:function(t,e){var n,o=v.random._callbacks[t],i=[];for(n in o)o.hasOwnProperty(n)&&i.push(o[n]);for(n=0;n= 300) { 120 | handleError(_failure, _timer, 'Request error', _rhr.status, _rhr.responseText); 121 | } else { 122 | var jsonResponse; 123 | try { 124 | jsonResponse = JSON.parse(_rhr.responseText); 125 | } catch (e) { 126 | handleError(_failure, _timer, 'Response error (JSON parse failed)', _rhr.status, '{}'); 127 | } 128 | _success({ 129 | data: jsonResponse, 130 | status: 200 131 | }); 132 | } 133 | } 134 | }; 135 | 136 | if (!(_rhr = getXhr())) { 137 | handleError(_failure, _timer, 'Browser error (CORS not supported)'); 138 | return; 139 | } 140 | _payload = JSON.stringify(_data); 141 | _headers = { 142 | 'Accept': 'application/json', 143 | 'Content-Type': 'application/json', 144 | 'Authorization': 'Basic ' + _auth 145 | }; 146 | 147 | if(typeof _method === 'undefined'|| _method===null){ 148 | _method = 'POST'; 149 | } 150 | _rhr.open(_method, _url, true); 151 | 152 | // set the Credentials flag request header only if there is no 153 | // XHR2 features 154 | // must be set after opening the request to an 155 | // InvalidOperationException in IE 156 | if ('withCredentials' in _rhr) { 157 | _rhr.withCredentials = true; 158 | } 159 | 160 | // apply the request headers 161 | for (var prop in _headers) { 162 | if (_headers.hasOwnProperty(prop) && _headers[prop]) { 163 | if ('setRequestHeader' in _rhr) { 164 | _rhr.setRequestHeader(prop, _headers[prop]); 165 | } 166 | } 167 | } 168 | 169 | // define the onreadystate handler 170 | if ('onreadystatechange' in _rhr) { 171 | _rhr.onreadystatechange = handleResponse; 172 | } else if ('onload' in _rhr && 'onerror' in _rhr) { 173 | _rhr.onload = handleResponse; 174 | _rhr.onerror = handleError; 175 | } 176 | 177 | // set a timeout 178 | _timer = setTimeout(function(){ 179 | // reset the handler 180 | if ('onload' in _rhr) { 181 | _rhr.onload = Function.prototype; 182 | } else { 183 | _rhr.onreadystatechange = Function.prototype; 184 | } 185 | _rhr.abort(); 186 | _rhr = null; 187 | handleError(_failure, _timer, 'Timeout after ' + _timeout + ' milliseconds'); 188 | }, _timeout); 189 | 190 | // make the request 191 | _rhr.send(_payload); 192 | } 193 | }; 194 | 195 | function makeBaseAuth(user) { 196 | var tok = user + ':'; 197 | var hash = btoa(tok); 198 | return hash; 199 | }; 200 | 201 | function getHostname(){ 202 | if(_openpay.sandboxMode) { 203 | return _openpay.sandboxHostname; 204 | } else if(_openpay.developMode){ 205 | return _openpay.developHostname; 206 | } else { 207 | return _openpay.hostname; 208 | } 209 | } 210 | 211 | return _openpay.version = 1, 212 | _openpay.sandboxMode = false, 213 | _openpay.developMode = false, 214 | _openpay.hostname = "https://api.openpay.mx/v1/", 215 | _openpay.sandboxHostname = "https://sandbox-api.openpay.mx/v1/", 216 | _openpay.developHostname = "https://dev-api.openpay.mx/v1/", 217 | _openpay.Group = {}, 218 | _openpay.Update = {}, 219 | _openpay.setSandboxMode = function(f) { 220 | _openpay.sandboxMode = (f ? true : false); 221 | if(f){ 222 | _openpay.developMode = false; 223 | } 224 | }, 225 | _openpay.getSandboxMode = function() { 226 | return _openpay.sandboxMode; 227 | }, 228 | _openpay.setDevelopMode = function(f) { 229 | _openpay.developMode = (f ? true : false); 230 | if(f){ 231 | _openpay.sandboxMode = false; 232 | } 233 | }, 234 | _openpay.getDevelopMode = function() { 235 | return _openpay.developMode; 236 | }, 237 | _openpay.setId = function(t) { 238 | _openpay.id = t; 239 | }, 240 | _openpay.getId = function() { 241 | return _openpay.id; 242 | }, 243 | _openpay.setApiKey = function(t) { 244 | _openpay.key = t; 245 | }, 246 | _openpay.getApiKey = function() { 247 | return _openpay.key; 248 | }, 249 | _openpay.Group.setId = function(t) { 250 | _openpay.Group.id = t; 251 | }, 252 | _openpay.Group.getId = function() { 253 | return _openpay.Group.id; 254 | }, 255 | _openpay.Group.setApiKey = function(t) { 256 | _openpay.Group.key = t; 257 | }, 258 | _openpay.Group.getApiKey = function() { 259 | return _openpay.Group.key; 260 | }, 261 | 262 | _openpay.log = function(_message) { 263 | if (typeof _message === 'object' && 'toString' in _message) { 264 | _message = _message.toString(); 265 | } 266 | if (typeof console !== 'undefined' && 'log' in console) { 267 | console.log(_message); 268 | } 269 | }, 270 | _openpay.validate = function(_dictionary, _type) { 271 | if (!_dictionary) throw _type + ' required'; 272 | if (typeof _dictionary !== 'object') throw _type + ' invalid'; 273 | }, 274 | _openpay.formatData = function(_dictionary, _validAttributes) { 275 | return _dictionary; 276 | }, 277 | _openpay.extractFormInfo = function(form){ 278 | var cardFields, objectCard, objectAddress,addressFields; 279 | 280 | var extractForm = function (object) { 281 | if (window.jQuery && object instanceof jQuery) { 282 | return object[0]; 283 | } else if (object.nodeType && object.nodeType === 1) { 284 | return object; 285 | } else { 286 | return document.getElementById(object); 287 | } 288 | }; 289 | 290 | var findInputsData = function (element, attributeName) { 291 | var found = [], 292 | children = element.children, 293 | child, i; 294 | 295 | for (i = 0; i < children.length; i++) { 296 | child = children[i]; 297 | 298 | if (child.nodeType === 1 && child.attributes[attributeName]) { 299 | found.push(child); 300 | } else if (child.children.length > 0) { 301 | found = found.concat(findInputsData(child, attributeName)); 302 | } 303 | } 304 | 305 | return found; 306 | }; 307 | 308 | var createObject = function (element, attributeName) { 309 | var object = {}; 310 | 311 | for (var i = 0; i < element.length; i++) { 312 | fieldName = element[i].attributes[attributeName].value; 313 | inputValue=element[i].value; 314 | if(object[fieldName] !== undefined){ 315 | if (!object[fieldName].push) { 316 | object[this.name] = [object[this.name]]; 317 | } 318 | object[fieldName].push(inputValue || ''); 319 | } else { 320 | object[fieldName] = inputValue || ''; 321 | } 322 | } 323 | 324 | return object; 325 | }; 326 | 327 | form = extractForm(form); 328 | cardFields = findInputsData(form, 'data-openpay-card'); 329 | objectCard = createObject(cardFields, 'data-openpay-card'); 330 | addressFields = findInputsData(form, 'data-openpay-card-address'); 331 | if(addressFields!== undefined && addressFields.length && addressFields.length > 0){ 332 | objectAddress = createObject(addressFields, 'data-openpay-card-address'); 333 | if(objectAddress!== undefined){ 334 | objectCard["address"] = objectAddress; 335 | } 336 | } 337 | return objectCard; 338 | }, 339 | 340 | _openpay.send = function(_endpoint, _data, _success, _failure) { 341 | if (!validateCredentials(_failure, _openpay.id, _openpay.key)) { 342 | return; 343 | } 344 | var _auth = makeBaseAuth(_openpay.key); 345 | var _url = getHostname(); 346 | _url = _url + _openpay.id + '/' + _endpoint; 347 | return sendXhr(_url, _auth, _data, _success, _failure); 348 | }, 349 | 350 | _openpay.Group.send = function(_endpoint, _data, _success, _failure) { 351 | if (!validateCredentials(_failure, _openpay.Group.id, _openpay.Group.key)) { 352 | return; 353 | } 354 | var _auth = makeBaseAuth(_openpay.Group.key); 355 | var _url = getHostname(); 356 | _url = _url + 'groups/' + _openpay.Group.id + '/' + _endpoint; 357 | return sendXhr(_url, _auth, _data, _success, _failure); 358 | }, 359 | 360 | _openpay.Update.send = function(_isGruop, _data, _success, _failure, _url){ 361 | var _auth = ""; 362 | if(_isGruop){ 363 | if (!validateCredentials(_failure, _openpay.Group.id, _openpay.Group.key)) { 364 | return; 365 | } 366 | _auth = makeBaseAuth(_openpay.Group.key); 367 | } 368 | else { 369 | if (!validateCredentials(_failure, _openpay.id, _openpay.key)) { 370 | return; 371 | } 372 | _auth = makeBaseAuth(_openpay.key); 373 | } 374 | var url = getHostname()+_url; 375 | return sendXhr(url, _auth, _data, _success, _failure, 'PUT'); 376 | }, 377 | _openpay; 378 | }.call(this), 379 | INSTANCE = this.OpenPay, 380 | this.OpenPay.card = function(_parent) { 381 | function _card() { 382 | return _card.__super__.constructor.apply(this, arguments); 383 | } 384 | return addProperty(_parent, _card), 385 | _card.validateCardNumber = function(_number) { 386 | return _number = (_number + "").replace(/\s+|-/g, ""), /^\d+$/.test(_number) && _number.length >= 10 && _number.length <= 19 387 | && _card.luhnCheck(_number) && _card.validateCardNumberLength(_number) && _card.validateAcceptCardNumber(_number); 388 | }, 389 | _card.validateCVC = function(_cvv_number, _card_number) { 390 | switch (arguments.length) { 391 | case 1: 392 | return _cvv_number = INSTANCE.utils.trim(_cvv_number), /^\d+$/.test(_cvv_number) && _cvv_number.length >= 3 && _cvv_number.length <= 4; 393 | break; 394 | 395 | case 2: 396 | var cardType = _card.cardType(_card_number); 397 | if('American Express' == cardType){ 398 | return _cvv_number = INSTANCE.utils.trim(_cvv_number), /^\d+$/.test(_cvv_number) && _cvv_number.length ==4; 399 | }else{ 400 | return _cvv_number = INSTANCE.utils.trim(_cvv_number), /^\d+$/.test(_cvv_number) && _cvv_number.length ==3; 401 | } 402 | break; 403 | 404 | default: 405 | return false; 406 | break; 407 | } 408 | }, 409 | _card.validateExpiry = function(_month, _year) { 410 | var r, i; 411 | var _year = INSTANCE.utils.trim(_year); 412 | if (_year.length === 2) { 413 | _year = "20"+_year; 414 | } 415 | return _month = INSTANCE.utils.trim(_month), _year, /^\d+$/.test(_month) ? /^\d+$/.test(_year) ? 416 | parseInt(_month, 10) <= 12 && parseInt(_month, 10) >= 1 ? (i = new Date(_year, _month), 417 | r = new Date(), i.setMonth(i.getMonth() - 1), i.setMonth(i.getMonth() + 1, 1), i > r) : !1 : !1 : !1; 418 | }, 419 | _card.validateCardNumberLength = function(_number) { 420 | var _cardObj = null; 421 | if (_cardObj = _card.cardAbstract(_number)) { 422 | var _i = _cardObj.length.length; 423 | while (_i--) { 424 | if (_cardObj.length[_i] == _number.length) { 425 | return true; 426 | } 427 | } 428 | return false; 429 | } 430 | return _number.length >= 10 && _number.length <= 19; 431 | }, 432 | _card.validateAcceptCardNumber = function(_number) { 433 | return true; 434 | }, 435 | _card.luhnCheck = function(_number) { 436 | var n = (_number + "").split(""), digit = 0, sum = parseInt(n[_number.length - 1]); 437 | for (var index = n.length - 2, i = 1; index >= 0; index--, i++) { 438 | digit = parseInt(n[index]); 439 | if (i % 2 != 0) { 440 | digit *= 2; 441 | if (digit > 9) { 442 | digit -= 9; 443 | } 444 | } 445 | sum += digit; 446 | } 447 | return sum % 10 == 0; 448 | }, 449 | _card.cardType = function(_number) { 450 | var _cardObj = null; 451 | if (_cardObj = _card.cardAbstract(_number)) { 452 | return _cardObj.name; 453 | } 454 | return ''; 455 | }, 456 | _card.cardTypes = function() { 457 | return { 458 | 'visa_electron': { 459 | 'name': "Visa Electron", 460 | 'regx': /^(4026|417500|4508|4844|491(3|7))/, 461 | 'length': [ 16 ], 462 | 'accept': true 463 | }, 464 | 'visa': { 465 | 'name': "Visa", 466 | 'regx': /^4/, 467 | 'length': [ 16 ], 468 | 'accept': true 469 | }, 470 | 'mastercard': { 471 | 'name': "Mastercard", 472 | 'regx': /^5[1-5]/, 473 | 'length': [ 16 ], 474 | 'accept': true 475 | }, 476 | 'amex': { 477 | 'name': 'American Express', 478 | 'regx': /^3[47]/, 479 | 'length': [ 15 ], 480 | 'accept': true 481 | }, 482 | 'diners_cb': { 483 | 'name': "Diners Club Carte Blanche", 484 | 'regx': /^30[0-5]/, 485 | 'length': [ 14 ], 486 | 'accept': true 487 | }, 488 | 'diners_int': { 489 | 'name': "Diners Club International", 490 | 'regx': /^36/, 491 | 'length': [ 14 ], 492 | 'accept': true 493 | }, 494 | 'jcb': { 495 | 'name': "JCB", 496 | 'regx': /^35(2[89]|[3-8][0-9])/, 497 | 'length': [ 16 ], 498 | 'accept': true 499 | }, 500 | 'laser': { 501 | 'name': "Laser", 502 | 'regx': /^(6304|670[69]|6771)/, 503 | 'length': [ 16, 17, 18, 19 ], 504 | 'accept': true 505 | }, 506 | 'maestro': { 507 | 'name': "Maestro", 508 | 'regx': /^(5018|5020|5038|6304|6759|676[1-3])/, 509 | 'length': [ 12, 13, 14, 15, 16, 17, 18, 19 ], 510 | 'accept': true 511 | }, 512 | 'discover': { 513 | 'name': "Discover", 514 | 'regx': /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/, 515 | 'length': [ 16 ], 516 | 'accept': true 517 | } 518 | }; 519 | }, 520 | _card.cardAbstract = function(_number) { 521 | var _cardTypes = {}; 522 | _cardTypes = _card.cardTypes(); 523 | for (var _key in _cardTypes) { 524 | var _cardObj = _cardTypes[_key]; 525 | if (_number.match(_cardObj.regx)) { 526 | return _cardObj; 527 | } 528 | } 529 | return false; 530 | }, 531 | _card.whitelistedAttrs = ["holder_name", "cvv2", "expiration_month", "expiration_year"], 532 | _card.extractFormAndUpdateCard = function(_form, _success, _failure, _customerId, _mycard){ 533 | var _params = INSTANCE.extractFormInfo(_form); 534 | return _card.update(_params, _success, _failure, _customerId, _mycard); 535 | }, 536 | _card.update = function(_params, _success, _failure, _customerId, _mycard){ 537 | var url = "/"+this.getId(); 538 | if(typeof _customerId !== 'undefined' && _customerId!==null){ 539 | url=url+"/customers/"+_customerId; 540 | } 541 | if(typeof _mycard !== 'undefined' && _mycard!==null){ 542 | url=url+"/cards/"+_mycard; 543 | } 544 | return INSTANCE.formatData(_params, _card.whitelistedAttrs), INSTANCE.Update.send(false, _params, _success, _failure, url); 545 | }, 546 | _card; 547 | 548 | }.call(this, this.OpenPay), 549 | // Inicio seccion token 550 | this.OpenPay.token = function(_parent){ 551 | function _token(){ 552 | return _token.__super__.constructor.apply(this, arguments); 553 | } 554 | return addProperty(_parent, _token), 555 | _token.whitelistedAttrs = [ "card_number", "holder_name", "cvv2", "expiration_month", "expiration_year", "address" ], 556 | _token.extractFormAndCreate = function(_form, _success, _failure, _customerId){ 557 | var _params = INSTANCE.extractFormInfo(_form); 558 | return _token.create(_params, _success, _failure); 559 | }, 560 | _token.create = function(_params, _success, _failure) { 561 | var _endpoint = 'tokens'; 562 | return INSTANCE.validate(_params, "tarjeta"), INSTANCE.formatData(_params, _token.whitelistedAttrs), INSTANCE.send(_endpoint, _params, _success, _failure); 563 | }, _token; 564 | }.call(this, this.OpenPay), 565 | // fin seccion token 566 | 567 | // Tokens de Grupos 568 | this.OpenPay.Group.token = function(_parent){ 569 | function _token(){ 570 | return _token.__super__.constructor.apply(this, arguments); 571 | } 572 | return addProperty(_parent, _token), 573 | _token.whitelistedAttrs = [ "card_number", "holder_name", "cvv2", "expiration_month", "expiration_year", "address" ], 574 | _token.extractFormAndCreate = function(_form, _success, _failure, _customerId){ 575 | var _params = INSTANCE.extractFormInfo(_form); 576 | return _token.create(_params, _success, _failure); 577 | }, 578 | _token.create = function(_params, _success, _failure) { 579 | var _endpoint = 'tokens'; 580 | return INSTANCE.validate(_params, "tarjeta"), INSTANCE.formatData(_params, _token.whitelistedAttrs), INSTANCE.Group.send(_endpoint, _params, _success, _failure); 581 | }, _token; 582 | }.call(this, this.OpenPay), 583 | // fin Tokens de Grupos 584 | 585 | // Modificacion de Grupos 586 | this.OpenPay.Group.card = function(_parent){ 587 | function _group(){ 588 | return _group.__super__.constructor.apply(this, arguments); 589 | } 590 | return addProperty(_parent, _group), 591 | _group.whitelistedAttrs = ["holder_name", "cvv2", "expiration_month", "expiration_year"], 592 | _group.extractFormAndUpdateCard = function(_form, _success, _failure, _customerId, _mycard){ 593 | var _params = INSTANCE.extractFormInfo(_form); 594 | return _group.update(_params, _success, _failure, _customerId, _mycard); 595 | }, 596 | _group.update = function(_params, _success, _failure, _customerId, _mycard){ 597 | var url = "groups/"+this.Group.id+"/customers/"+_customerId+"/cards/"+_mycard; 598 | if(!_params.merchant_id){ 599 | _params.merchant_id = this.getId(); 600 | } 601 | return INSTANCE.formatData(_params, _group.whitelistedAttrs), INSTANCE.Update.send(true, _params, _success, _failure, url); 602 | }, _group; 603 | }.call(this, this.OpenPay), 604 | // fin de modificacion de groups 605 | 606 | this.OpenPay.utils = function(_parent) { 607 | function _utils() {} 608 | return addProperty(_parent, _utils), 609 | _utils.trim = function(e) { 610 | return (e + "").replace(/^\s+|\s+$/g, ""); 611 | }, 612 | _utils.underscore = function(e) { 613 | return (e + "").replace(/([A-Z])/g, function(e) { 614 | return "_" + e.toLowerCase(); 615 | }).replace(/-/g, "_"); 616 | }, 617 | _utils.underscoreKeys = function(e) { 618 | var n, r; 619 | r = []; 620 | for (var t in e) n = e[t], delete e[t], r.push(e[this.underscore(t)] = n); 621 | return r; 622 | }, 623 | _utils.isElement = function(e) { 624 | return typeof e != "object" ? !1 : typeof jQuery != "undefined" && jQuery !== null && e instanceof jQuery ? !0 : e.nodeType === 1; 625 | }, _utils; 626 | }.call(this, this.OpenPay), 627 | 628 | // Inicio seccion checkout 629 | this.OpenPay.checkout = function(_parent){ 630 | function _checkout(){ 631 | return _checkout.__super__.constructor.apply(this, arguments); 632 | } 633 | return addProperty(_parent, _checkout), 634 | _checkout.whitelistedAttrs = [ "amount", "currency", "description", "order_id", "send_email", "customer", "cancel_url", "redirect_url","expiration_date" ], 635 | _checkout.extractFormAndCreate = function(_form, _success, _failure){ 636 | var _params = INSTANCE.extractFormInfo(_form); 637 | return _checkout.create(_params, _success, _failure); 638 | }, 639 | _checkout.create = function(_params, _success, _failure) { 640 | var _endpoint = 'public-checkouts'; 641 | return INSTANCE.formatData(_params, _checkout.whitelistedAttrs), INSTANCE.send(_endpoint, _params, _success, _failure); 642 | }, _checkout; 643 | }.call(this, this.OpenPay), 644 | 645 | typeof module != "undefined" && module !== null && (module.exports = this.OpenPay), 646 | typeof define == "function" && define("openpay", [], function() { 647 | return CALLER.OpenPay; 648 | }); 649 | }).call(this); 650 | 651 | /* 652 | * Copyright (c) 2010 Nick Galbreath 653 | * http://code.google.com/p/stringencoders/source/browse/#svn/trunk/javascript 654 | * 655 | * Permission is hereby granted, free of charge, to any person obtaining a copy 656 | * of this software and associated documentation files (the "Software"), to deal 657 | * in the Software without restriction, including without limitation the rights 658 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 659 | * copies of the Software, and to permit persons to whom the Software is 660 | * furnished to do so, subject to the following conditions: 661 | * 662 | * The above copyright notice and this permission notice shall be included in 663 | * all copies or substantial portions of the Software. 664 | * 665 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 666 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 667 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 668 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 669 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 670 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 671 | * SOFTWARE. 672 | */ 673 | 674 | /* 675 | * base64 encode/decode compatible with window.btoa/atob 676 | * 677 | * window.atob/btoa is a Firefox extension to convert binary data (the "b") to 678 | * base64 (ascii, the "a"). 679 | * 680 | * It is also found in Safari and Chrome. It is not available in IE. 681 | * 682 | * if (!window.btoa) window.btoa = base64.encode if (!window.atob) window.atob = 683 | * base64.decode 684 | * 685 | * The original spec's for atob/btoa are a bit lacking 686 | * https://developer.mozilla.org/en/DOM/window.atob 687 | * https://developer.mozilla.org/en/DOM/window.btoa 688 | * 689 | * window.btoa and base64.encode takes a string where charCodeAt is [0,255] If 690 | * any character is not [0,255], then an DOMException(5) is thrown. 691 | * 692 | * window.atob and base64.decode take a base64-encoded string If the input 693 | * length is not a multiple of 4, or contains invalid characters then an 694 | * DOMException(5) is thrown. 695 | */ 696 | var base64 = {}; 697 | base64.PADCHAR = '='; 698 | base64.ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 699 | 700 | base64.makeDOMException = function() { 701 | // sadly in FF,Safari,Chrome you can't make a DOMException 702 | var e, tmp; 703 | 704 | try { 705 | return new DOMException(DOMException.INVALID_CHARACTER_ERR); 706 | } catch (tmp) { 707 | // not available, just passback a duck-typed equiv 708 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Error 709 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Error/prototype 710 | var ex = new Error("DOM Exception 5"); 711 | 712 | // ex.number and ex.description is IE-specific. 713 | ex.code = ex.number = 5; 714 | ex.name = ex.description = "INVALID_CHARACTER_ERR"; 715 | 716 | // Safari/Chrome output format 717 | ex.toString = function() { return 'Error: ' + ex.name + ': ' + ex.message; }; 718 | return ex; 719 | } 720 | } 721 | 722 | base64.getbyte64 = function(s,i) { 723 | // This is oddly fast, except on Chrome/V8. 724 | // Minimal or no improvement in performance by using a 725 | // object with properties mapping chars to value (eg. 'A': 0) 726 | var idx = base64.ALPHA.indexOf(s.charAt(i)); 727 | if (idx === -1) { 728 | throw base64.makeDOMException(); 729 | } 730 | return idx; 731 | } 732 | 733 | base64.decode = function(s) { 734 | // convert to string 735 | s = '' + s; 736 | var getbyte64 = base64.getbyte64; 737 | var pads, i, b10; 738 | var imax = s.length 739 | if (imax === 0) { 740 | return s; 741 | } 742 | 743 | if (imax % 4 !== 0) { 744 | throw base64.makeDOMException(); 745 | } 746 | 747 | pads = 0 748 | if (s.charAt(imax - 1) === base64.PADCHAR) { 749 | pads = 1; 750 | if (s.charAt(imax - 2) === base64.PADCHAR) { 751 | pads = 2; 752 | } 753 | // either way, we want to ignore this last block 754 | imax -= 4; 755 | } 756 | 757 | var x = []; 758 | for (i = 0; i < imax; i += 4) { 759 | b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) | 760 | (getbyte64(s,i+2) << 6) | getbyte64(s,i+3); 761 | x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff, b10 & 0xff)); 762 | } 763 | 764 | switch (pads) { 765 | case 1: 766 | b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) | (getbyte64(s,i+2) << 6); 767 | x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff)); 768 | break; 769 | case 2: 770 | b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12); 771 | x.push(String.fromCharCode(b10 >> 16)); 772 | break; 773 | } 774 | return x.join(''); 775 | } 776 | 777 | base64.getbyte = function(s,i) { 778 | var x = s.charCodeAt(i); 779 | if (x > 255) { 780 | throw base64.makeDOMException(); 781 | } 782 | return x; 783 | } 784 | 785 | base64.encode = function(s) { 786 | if (arguments.length !== 1) { 787 | throw new SyntaxError("Not enough arguments"); 788 | } 789 | var padchar = base64.PADCHAR; 790 | var alpha = base64.ALPHA; 791 | var getbyte = base64.getbyte; 792 | 793 | var i, b10; 794 | var x = []; 795 | 796 | // convert to string 797 | s = '' + s; 798 | 799 | var imax = s.length - s.length % 3; 800 | 801 | if (s.length === 0) { 802 | return s; 803 | } 804 | for (i = 0; i < imax; i += 3) { 805 | b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8) | getbyte(s,i+2); 806 | x.push(alpha.charAt(b10 >> 18)); 807 | x.push(alpha.charAt((b10 >> 12) & 0x3F)); 808 | x.push(alpha.charAt((b10 >> 6) & 0x3f)); 809 | x.push(alpha.charAt(b10 & 0x3f)); 810 | } 811 | switch (s.length - imax) { 812 | case 1: 813 | b10 = getbyte(s,i) << 16; 814 | x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) + 815 | padchar + padchar); 816 | break; 817 | case 2: 818 | b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8); 819 | x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) + 820 | alpha.charAt((b10 >> 6) & 0x3f) + padchar); 821 | break; 822 | } 823 | return x.join(''); 824 | }; 825 | 826 | (function (){ 827 | if (!window.btoa) { 828 | window.btoa = base64.encode 829 | } 830 | if (!window.atob){ 831 | window.atob = base64.decode 832 | } 833 | })(); 834 | 835 | /* jsonp.js, (c) Przemek Sobstel 2012, License: MIT */ 836 | 837 | var $jsonp = (function(){ 838 | var that = {}; 839 | 840 | that.send = function(request) { 841 | var requestID = new Date().getTime(); 842 | var callbackName = request.callbackName || 'callback', 843 | on_success = request.onSuccess || function(){}, 844 | on_error = request.onError || function(){}, 845 | timeout = request.timeout || 4000, 846 | url = request.url || '', 847 | data = request.data || {} 848 | dataIdName = "idData"; 849 | var e = encodeURIComponent; 850 | data.callback = "var "+dataIdName+"="+ (++requestID)+";"+callbackName; 851 | window[dataIdName]=undefined; 852 | var toCamelCase = function(string) { 853 | string = string.replace(/[\-_\s]+(.)?/g, function(match, chr) { 854 | return chr ? chr.toUpperCase() : ''; 855 | }); 856 | return string.replace(/^([A-Z])/, function(match, chr) { 857 | return chr ? chr.toLowerCase() : ''; 858 | }); 859 | }; 860 | 861 | var serializeData = function(object, result, scope) { 862 | var key, value; 863 | 864 | if (result == null) { 865 | result = []; 866 | } 867 | for (key in object) { 868 | value = object[key]; 869 | if (scope) { 870 | key = "" + scope + "." + key; 871 | } 872 | if (typeof value === 'object') { 873 | serializeData(value, result, key); 874 | } else { 875 | result.push(toCamelCase(""+ key) + "=" + (e(value))); 876 | } 877 | } 878 | return result.join('&').replace(/%20/g, '+'); 879 | }; 880 | 881 | timeout_trigger = window.setTimeout(function(){ 882 | window[callbackName] = function(){}; 883 | on_error('Timeout after ' + timeout + ' milliseconds'); 884 | }, timeout ); 885 | 886 | var script = document.createElement('script'); 887 | script.type = 'text/javascript'; 888 | script.async = true; 889 | script.src = url + '?' + serializeData(data); 890 | 891 | var removeScript = function(){ 892 | var _ref; 893 | if ((_ref = script.parentNode) != null) { 894 | _ref.removeChild(script); 895 | } 896 | }; 897 | 898 | var abort = function(){ 899 | window.clearTimeout(timeout_trigger); 900 | removeScript(); 901 | on_error("There was an error, please verify your authentication data or conection."); 902 | }; 903 | 904 | if ('onreadystatechange' in script) { 905 | script.onreadystatechange=function(){ 906 | if(script.readyState == "loaded"){ 907 | if (typeof window[dataIdName] === "undefined") { 908 | abort(); 909 | } 910 | } 911 | }; 912 | } else if ('onerror' in script) { 913 | script.onerror= function(){ 914 | abort(); 915 | }; 916 | } 917 | 918 | window[callbackName] = function(data){ 919 | window.clearTimeout(timeout_trigger); 920 | removeScript(); 921 | on_success(data); 922 | }; 923 | document.getElementsByTagName('head')[0].appendChild(script); 924 | }; 925 | 926 | return that; 927 | })(); 928 | if (typeof jQuery !== 'undefined') { 929 | (function( $ ) { 930 | if (typeof $ !== 'undefined') { 931 | 932 | $.fn.cardNumberInput = function() { 933 | return $(this).restrictedInput('card'); 934 | }; 935 | 936 | $.fn.numericInput = function() { 937 | return $(this).restrictedInput('numeric'); 938 | }; 939 | 940 | $.fn.restrictedInput = function(type) { 941 | var 942 | $this = $(this), 943 | cards = [ 944 | { 945 | 'type' : 'amex', 946 | 'regex' : /^3[47]/, 947 | 'format' : /(\d{1,4})(\d{1,6})?(\d{1,5})?/, 948 | 'length' : 15 949 | }, 950 | { 951 | 'type' : 'other', 952 | 'format' : /(\d{1,4})/g, 953 | 'length' : 16 954 | } 955 | ], 956 | gcard = function(num) { 957 | var 958 | card, 959 | i; 960 | 961 | num = ((num + '').replace(/\D/g, '')); 962 | for (i = 0; i < cards.length; i++) { 963 | card = cards[i]; 964 | if (card['regex'] && card['regex'].test(num)) { 965 | return card; 966 | } 967 | } 968 | }, 969 | rstnmb = function(e) { 970 | var inp; 971 | if (e.metaKey || e.ctrlKey) { 972 | return true; 973 | } else if (e.which === 0) { 974 | return true; 975 | } else if (e.which === 32) { 976 | return false; 977 | } else if (e.which < 33) { 978 | return true; 979 | } 980 | 981 | inp = String.fromCharCode(e.which); 982 | return !!/[\d\s]/.test(inp); 983 | }, 984 | onmb = function(e) { 985 | var 986 | $t = $(e.currentTarget), 987 | val = (($t.val() + String.fromCharCode(e.which)).replace(/\D/g, '')), 988 | card, 989 | isN; 990 | 991 | isN = rstnmb(e); 992 | card = gcard(val); 993 | if (card) { 994 | return isN && val.length <= card['length']; 995 | } 996 | return isN && val.length <= 16; 997 | }, 998 | refrmnmb = function(e) { 999 | var 1000 | $t = $(e.currentTarget), 1001 | val = $t.val(); 1002 | 1003 | if (e.which !== 8) { 1004 | return; 1005 | } 1006 | 1007 | if (/\d\s$/.test(val)) { 1008 | e.preventDefault(); 1009 | return setTimeout(function() { 1010 | return $t.val(val.replace(/\d\s$/, '')); 1011 | }); 1012 | } else if (/\s\d?$/.test(val)) { 1013 | e.preventDefault(); 1014 | return setTimeout(function() { 1015 | return $t.val(val.replace(/\s\d?$/, '')); 1016 | }); 1017 | } 1018 | }, 1019 | frmnmb = function(e) { 1020 | var 1021 | $t = $(e.currentTarget), 1022 | val = $t.val(), 1023 | digit = String.fromCharCode(e.which), 1024 | length = (val.replace(/\D/g, '') + digit).length, 1025 | upl = 16, 1026 | card = gcard(val + digit), 1027 | re; 1028 | 1029 | if (!/^\d+$/.test(digit)) { 1030 | return; 1031 | } 1032 | 1033 | if (card) { 1034 | upl = card['length']; 1035 | } 1036 | 1037 | if (length >= upl) { 1038 | return; 1039 | } 1040 | 1041 | if (card && card['type'] === 'amex') { 1042 | re = /^(\d{4}|\d{4}\s\d{6})$/; 1043 | } else { 1044 | re = /(?:^|\s)(\d{4})$/; 1045 | } 1046 | 1047 | if (re.test(val)) { 1048 | e.preventDefault(); 1049 | return setTimeout(function() { 1050 | return $t.val(val + ' ' + digit); 1051 | }); 1052 | } else if (re.test(val + digit)) { 1053 | e.preventDefault(); 1054 | return setTimeout(function() { 1055 | return $t.val(val + digit + ' '); 1056 | }); 1057 | } 1058 | }; 1059 | 1060 | if ('card' === type) { 1061 | $this 1062 | .on('keypress', onmb) 1063 | .on('keypress', frmnmb) 1064 | .on('keydown', refrmnmb) 1065 | .on('paste', onmb) 1066 | .on('paste', frmnmb) 1067 | .on('change', frmnmb) 1068 | .on('input', frmnmb); 1069 | } else if ('numeric' === type) { 1070 | $this 1071 | .on('keypress', rstnmb) 1072 | .on('paste', rstnmb) 1073 | .on('change', rstnmb) 1074 | .on('input', rstnmb); 1075 | } 1076 | return this; 1077 | }; 1078 | } 1079 | })( jQuery ); 1080 | } 1081 | -------------------------------------------------------------------------------- /lib/openpay.v1.min.js: -------------------------------------------------------------------------------- 1 | /*! openpay.js v1.2.39 2023-07-25 */ 2 | !function(){var u,a={}.hasOwnProperty,n=function(e,t){function n(){this.constructor=t}for(var r in e)a.call(e,r)&&(t[r]=e[r]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},e=this;this.OpenPay=function(){function f(){}function h(e,t,n,r,a){clearTimeout(t);t=null;n=n||"Unknown error",r=r||0,a=a||"{}";try{t=JSON.parse(a)}catch(o){n="Response error"}e({message:n,status:r,data:t,toString:function(){return this.message+" [status "+this.status+"]"}})}function i(e,t,n){if(void 0!==t&&/^[a-z0-9]+$/i.test(t)){if(void 0!==n&&/^pk_[a-z0-9]+$/i.test(n))return 1;h(e,null,"Empty or invalid Openpay API Key")}else h(e,null,"Empty or invalid Openpay ID")}function u(e,t,n,r,a,o){var i,u=null,s=null,c={};if("function"!=typeof r&&(r=f.log),"function"!=typeof a&&(a=f.log),"undefined"==typeof JSON)h(a,s,"Browser error (JSON library not found)");else{var d,p=XMLHttpRequest&&"withCredentials"in new XMLHttpRequest;if(p){function d(){if("undefined"!=typeof u.readyState&&4==u.readyState||!p)if(clearTimeout(s),u.status<200||300<=u.status)h(a,s,"Request error",u.status,u.responseText);else{var e;try{e=JSON.parse(u.responseText)}catch(t){h(a,s,"Response error (JSON parse failed)",u.status,"{}")}r({data:e,status:200})}}if(u=function(){if(e=window,"function"==(n=typeof e[t="XMLHttpRequest"])||"object"==n&&e[t]||"unknown"==n)return new XMLHttpRequest;var e,t,n}()){for(var l in i=JSON.stringify(n),c={Accept:"application/json","Content-Type":"application/json",Authorization:"Basic "+t},u.open(o=null==o?"POST":o,e,!0),"withCredentials"in u&&(u.withCredentials=!0),c)c.hasOwnProperty(l)&&c[l]&&"setRequestHeader"in u&&u.setRequestHeader(l,c[l]);"onreadystatechange"in u?u.onreadystatechange=d:"onload"in u&&"onerror"in u&&(u.onload=d,u.onerror=h),s=setTimeout(function(){"onload"in u?u.onload=Function.prototype:u.onreadystatechange=Function.prototype,u.abort(),u=null,h(a,s,"Timeout after 40000 milliseconds")},4e4),u.send(i)}else h(a,s,"Browser error (CORS not supported)")}else"undefined"!=typeof XDomainRequest?(n.apiKey=t,$jsonp.send({callbackName:"getResultData",onSuccess:d=function(e){e.error?h(a,s,"Request error",e.httpStatus,JSON.stringify(e)):r({data:e.data,status:200})},onError:h,timeout:4e4,url:e+"/jsonp",data:n})):h(a,s,"Browser error (CORS not supported)")}}function s(e){return btoa(e+":")}function c(){return f.sandboxMode?f.sandboxHostname:f.developMode?f.developHostname:f.hostname}return f.version=1,f.sandboxMode=!1,f.developMode=!1,f.hostname="https://api.openpay.mx/v1/",f.sandboxHostname="https://sandbox-api.openpay.mx/v1/",f.developHostname="https://dev-api.openpay.mx/v1/",f.Group={},f.Update={},f.setSandboxMode=function(e){f.sandboxMode=!!e,e&&(f.developMode=!1)},f.getSandboxMode=function(){return f.sandboxMode},f.setDevelopMode=function(e){f.developMode=!!e,e&&(f.sandboxMode=!1)},f.getDevelopMode=function(){return f.developMode},f.setId=function(e){f.id=e},f.getId=function(){return f.id},f.setApiKey=function(e){f.key=e},f.getApiKey=function(){return f.key},f.Group.setId=function(e){f.Group.id=e},f.Group.getId=function(){return f.Group.id},f.Group.setApiKey=function(e){f.Group.key=e},f.Group.getApiKey=function(){return f.Group.key},f.log=function(e){"object"==typeof e&&"toString"in e&&(e=e.toString()),"undefined"!=typeof console&&"log"in console&&console.log(e)},f.validate=function(e,t){if(!e)throw t+" required";if("object"!=typeof e)throw t+" invalid"},f.formatData=function(e,t){return e},f.extractFormInfo=function(e){var t,i=function(e,t){for(var n,r=[],a=e.children,o=0;o>16,n>>8&255,255&n));switch(t){case 1:n=r(e,i)<<18|r(e,i+1)<<12|r(e,i+2)<<6,o.push(String.fromCharCode(n>>16,n>>8&255));break;case 2:n=r(e,i)<<18|r(e,i+1)<<12,o.push(String.fromCharCode(n>>16))}return o.join("")},getbyte:function(e,t){t=e.charCodeAt(t);if(255>18)),i.push(a.charAt(n>>12&63)),i.push(a.charAt(n>>6&63)),i.push(a.charAt(63&n));switch(e.length-u){case 1:n=o(e,t)<<16,i.push(a.charAt(n>>18)+a.charAt(n>>12&63)+r+r);break;case 2:n=o(e,t)<<16|o(e,t+1)<<8,i.push(a.charAt(n>>18)+a.charAt(n>>12&63)+a.charAt(n>>6&63)+r)}return i.join("")}},$jsonp=(window.btoa||(window.btoa=base64.encode),window.atob||(window.atob=base64.decode),function(){var e={send:function(e){var t=(new Date).getTime(),n=e.callbackName||"callback",r=e.onSuccess||function(){},a=e.onError||function(){},o=e.timeout||4e3,i=e.url||"",e=e.data||{},u=(dataIdName="idData",encodeURIComponent),s=(e.callback="var "+dataIdName+"="+ ++t+";"+n,window[dataIdName]=undefined,function(e,t,n){var r,a;for(r in null==t&&(t=[]),e)a=e[r],n&&(r=n+"."+r),"object"==typeof a?s(a,t,r):t.push((""+r).replace(/[\-_\s]+(.)?/g,function(e,t){return t?t.toUpperCase():""}).replace(/^([A-Z])/,function(e,t){return t?t.toLowerCase():""})+"="+u(a));return t.join("&").replace(/%20/g,"+")}),c=(timeout_trigger=window.setTimeout(function(){window[n]=function(){},a("Timeout after "+o+" milliseconds")},o),document.createElement("script")),d=(c.type="text/javascript",c["async"]=!0,c.src=i+"?"+s(e),function(){var e;null!=(e=c.parentNode)&&e.removeChild(c)}),p=function(){window.clearTimeout(timeout_trigger),d(),a("There was an error, please verify your authentication data or conection.")};"onreadystatechange"in c?c.onreadystatechange=function(){"loaded"==c.readyState&&"undefined"==typeof window[dataIdName]&&p()}:"onerror"in c&&(c.onerror=function(){p()}),window[n]=function(e){window.clearTimeout(timeout_trigger),d(),r(e)},document.getElementsByTagName("head")[0].appendChild(c)}};return e}());"undefined"!=typeof jQuery&&!function(s){void 0!==s&&(s.fn.cardNumberInput=function(){return s(this).restrictedInput("card")},s.fn.numericInput=function(){return s(this).restrictedInput("numeric")},s.fn.restrictedInput=function(e){var t=s(this),r=[{type:"amex",regex:/^3[47]/,format:/(\d{1,4})(\d{1,6})?(\d{1,5})?/,length:15},{type:"other",format:/(\d{1,4})/g,length:16}],u=function(e){var t,n;for(e=(e+"").replace(/\D/g,""),n=0;n 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 22 | 64 | 65 |

OpenPay Javascript API Library Test

66 | 67 |
68 |
69 |
70 |

Mode:

71 | 75 |
76 |
77 |
78 |
79 |

Merchant ID:

80 | 81 |
82 |
83 |

Request API Key:

84 | 85 |
86 |
87 |
88 | 89 |
90 |
91 |
92 | SessionId 93 |
94 |
95 |

Generated Session Id:

96 |
97 |
98 |
99 |
100 |

Hidden value:

101 | 102 |
103 |
104 |
105 |
106 |
107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /test/openpay_js_test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 280 | 331 | 332 | 333 |

OpenPay Javascript API Library Test

334 | 335 |
336 |
337 |
338 |

Mode:

339 | 344 |
345 |
346 |
347 |
348 |

Merchant ID:

349 | 350 |
351 |
352 |

Request API Key:

353 | 355 |
356 |
357 |
358 | 359 | 360 |
361 | Create a : 364 |
365 |
366 |
367 |

Show Data:

368 | 372 |
373 |
374 |
375 | 376 |
377 |
378 |
379 |
380 |

Holder Name:

381 | 383 |
384 |
385 |

Card number:

386 | 388 |
389 |
390 |
391 |
392 |

Expiration year:

393 | 394 |
395 |
396 |

Expiration month:

397 | 399 |
400 |
401 | 402 |
403 |
404 |

cvv2:

405 | 406 |
407 |
408 | 409 |
410 | Address: 411 |
412 |
413 |

Street:

414 | 415 |
416 |
417 |

Number:

418 | 419 |
420 |
421 |

References:

422 | 423 |
424 |
425 |
426 |
427 |

Postal code:

428 | 429 |
430 |
431 |

City:

432 | 433 |
434 |
435 |

State:

436 | 437 |
438 |
439 |
440 |
441 |

Country code:

442 | 443 |
444 |
445 |
446 |
447 |
448 |
449 | 450 |
451 |
452 |

453 | Create Card Request data : 454 |

455 | 458 |
459 |
460 |

Request response:

461 | 463 |
464 |
465 |
466 |
467 | 468 |
469 |
470 |
471 |
472 | 473 |
474 | Validate a card: 475 |
476 |
477 |
478 |

Select Card Type:

479 | 492 |
493 |
494 |

Type Card Number:

495 | 496 |
497 |
498 |
499 |
500 |

Expiry Month / Year

501 | 526 |
527 |
528 |

CVC:

529 | 530 |
531 |
532 |
533 |
534 |

Validation:

535 |




540 |
541 |
542 |
543 | 544 |
545 |
546 |
547 | 548 |
549 | Update card data: 550 |
551 |
552 |
553 |

Request API Key:

554 |

Merchant ID:

555 |
556 |
557 |

Group ID:

558 |

Customer ID:

559 |
560 |
561 |

Card ID:

562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |

Holder Name:

570 | 572 |
573 |
574 |

cvv2:

575 | 576 |
577 |
578 |
579 |
580 |

Expiration year:

581 | 582 |
583 |
584 |

Expiration month:

585 | 587 |
588 |
589 |
590 |
591 |

* You can modified the fields.

592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 | 601 | 602 | 603 | --------------------------------------------------------------------------------