├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── package.json ├── src ├── index.js ├── shared.js ├── token.js ├── verify.js ├── verifyCheck.js ├── verifyControl.js ├── verifyLogout.js └── verifySearch.js └── tests ├── config.example.json ├── shared.js ├── token.js ├── verify.js ├── verifyCheck.js ├── verifyControl.js ├── verifyLogout.js └── verifySearch.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # we recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [{package,bower}.json] 24 | indent_style = space 25 | indent_size = 2 26 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | examples 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "mocha": true 7 | }, 8 | "ecmaFeatures": { 9 | "arrowFunctions": true, 10 | "blockBindings": true, 11 | "classes": true, 12 | "defaultParams": true, 13 | "destructuring": true, 14 | "forOf": true, 15 | "generators": false, 16 | "modules": true, 17 | "objectLiteralComputedProperties": true, 18 | "objectLiteralDuplicateProperties": false, 19 | "objectLiteralShorthandMethods": true, 20 | "objectLiteralShorthandProperties": true, 21 | "spread": true, 22 | "superInFunctions": true, 23 | "templateStrings": true 24 | }, 25 | "rules": { 26 | "strict": [2, "never"], 27 | "no-var": 2, 28 | "prefer-const": 2, 29 | "no-shadow": 2, 30 | "no-shadow-restricted-names": 2, 31 | "no-unused-vars": [2, { 32 | "vars": "local", 33 | "args": "after-used" 34 | }], 35 | "no-use-before-define": 2, 36 | "comma-dangle": [2, "always-multiline"], 37 | "no-cond-assign": [2, "always"], 38 | "no-console": 1, 39 | "no-debugger": 1, 40 | "no-alert": 1, 41 | "no-constant-condition": 1, 42 | "no-dupe-keys": 2, 43 | "no-duplicate-case": 2, 44 | "no-empty": 2, 45 | "no-ex-assign": 2, 46 | "no-extra-boolean-cast": 0, 47 | "no-extra-semi": 2, 48 | "no-func-assign": 2, 49 | "no-inner-declarations": 2, 50 | "no-invalid-regexp": 2, 51 | "no-irregular-whitespace": 2, 52 | "no-obj-calls": 2, 53 | "no-sparse-arrays": 2, 54 | "no-unreachable": 2, 55 | "use-isnan": 2, 56 | "block-scoped-var": 2, 57 | "consistent-return": 2, 58 | "curly": [2, "multi-line"], 59 | "default-case": 2, 60 | "dot-notation": [2, { 61 | "allowKeywords": true 62 | }], 63 | "eqeqeq": 2, 64 | "guard-for-in": 2, 65 | "no-caller": 2, 66 | "no-eq-null": 2, 67 | "no-eval": 2, 68 | "no-extend-native": 2, 69 | "no-extra-bind": 2, 70 | "no-fallthrough": 2, 71 | "no-floating-decimal": 2, 72 | "no-implied-eval": 2, 73 | "no-lone-blocks": 2, 74 | "no-loop-func": 2, 75 | "no-multi-str": 2, 76 | "no-native-reassign": 2, 77 | "no-new": 2, 78 | "no-new-func": 2, 79 | "no-new-wrappers": 2, 80 | "no-octal": 2, 81 | "no-octal-escape": 2, 82 | "no-param-reassign": 2, 83 | "no-proto": 2, 84 | "no-redeclare": 2, 85 | "no-return-assign": 2, 86 | "no-script-url": 2, 87 | "no-self-compare": 2, 88 | "no-sequences": 2, 89 | "no-throw-literal": 2, 90 | "no-with": 2, 91 | "radix": 2, 92 | "vars-on-top": 2, 93 | "wrap-iife": [2, "any"], 94 | "yoda": 2, 95 | "indent": [2, 2], 96 | "brace-style": [2, 97 | "1tbs", { 98 | "allowSingleLine": true 99 | } 100 | ], 101 | "quotes": [ 102 | 2, "single", "avoid-escape" 103 | ], 104 | "camelcase": [2, { 105 | "properties": "never" 106 | }], 107 | "comma-spacing": [2, { 108 | "before": false, 109 | "after": true 110 | }], 111 | "comma-style": [2, "last"], 112 | "eol-last": 2, 113 | "func-names": 1, 114 | "key-spacing": [2, { 115 | "beforeColon": false, 116 | "afterColon": true 117 | }], 118 | "new-cap": [2, { 119 | "newIsCap": true 120 | }], 121 | "no-multiple-empty-lines": [2, { 122 | "max": 2 123 | }], 124 | "no-nested-ternary": 2, 125 | "no-new-object": 2, 126 | "no-spaced-func": 2, 127 | "no-trailing-spaces": 2, 128 | "no-underscore-dangle": 0, 129 | "one-var": [2, "never"], 130 | "padded-blocks": [2, "never"], 131 | "semi": [2, "always"], 132 | "semi-spacing": [2, { 133 | "before": false, 134 | "after": true 135 | }], 136 | "space-after-keywords": 2, 137 | "space-before-blocks": 2, 138 | "space-before-function-paren": [2, "never"], 139 | "space-infix-ops": 2, 140 | "space-return-throw-case": 2, 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib/ 3 | .DS_Store 4 | config.json 5 | debug.js 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | debug.js 3 | config.js 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | NEXMO VERIFY SDK LICENSE AGREEMENT 2 | By downloading or using the Verify Software Development Kit or any documentation that accompanies it (collectively, the “SDK”), 3 | you and the company or entity that you represent (collectively, “you” or “your”) are consenting to be bound by and are becoming 4 | a party to this Nexmo Verify SDK License Agreement (“Agreement”). You hereby represent and warrant that you are authorized and 5 | lawfully able to bind such company or entity that you represent to this Agreement. If you do not have such authority or do not 6 | agree to all of the terms of this Agreement, you may not download or use the SDK. 7 | 8 | 1. LICENSE GRANT. The SDK is licensed and not sold. Subject to your compliance with this Agreement, Nexmo Inc. (“Nexmo”) 9 | hereby grants you a limited, personal, non-exclusive, non-sublicensable, non-transferable, royalty-free license to (a) use, 10 | install, and run the SDK solely in connection with internally evaluating and developing applications and services that are 11 | interoperable with Nexmo’s products and services located at www.nexmo.com/product/ (collectively, “Nexmo’s Services”), and such 12 | applications and services you develop, excluding the SDK and Nexmo’s Services, are referred to herein as “Your Products”; and 13 | (b) modify and prepare derivative works of the SDK solely to develop Your Products that are interoperable with Nexmo’s Services, 14 | provided that you make any such modifications and derivative works of the library available to the public with this Agreement 15 | covering the SDK and an open source license covering your original content; and provided further that, for the avoidance of 16 | doubt, any use or access to Nexmo’s Services shall be governed by the Terms of Use located at www.nexmo.com/terms-use/ and the 17 | Privacy Policy located at www.nexmo.com/privacy-policy/. You acknowledge that your use of any components provided with the SDK 18 | that are licensed under an open source software license (“Open Source Components”) are not part of the SDK licensed hereunder 19 | and are subject to and governed solely by the terms of the applicable license(s) for that software, and not by this Agreement. 20 | Open Source Components provided with the SDK are listed here: 21 | 22 | Gson (Licensed under the Apache License, Version 2.0 available at http://www.apache.org/licenses/LICENSE-2.0.txt). 23 | Gson is available at http://mvnrepository.com/artifact/com.google.code.gson/gson). 24 | 25 | Gson (Google, Inc.) 26 | 27 | Copyright 2008-2011 Google Inc. 28 | 29 | Licensed under the Apache License, Version 2.0 (the “License”); 30 | you may not use this file except in compliance with the License. 31 | You may obtain a copy of the License at 32 | 33 | http://www.apache.org/licenses/LICENSE-2.0 34 | 35 | Unless required by applicable law or agreed to in writing, software 36 | distributed under the License is distributed on an “AS IS” BASIS, 37 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 38 | See the License for the specific language governing permissions and limitations under the License. 39 | 40 | 2. RESTRICTIONS. Except as otherwise expressly authorized by Nexmo, you may not directly or indirectly: sublicense, sell, 41 | assign, distribute, make any commercial use of, use on a timeshare or service bureau basis or otherwise commercialize the SDK 42 | (or any portion thereof), provided that the foregoing will not prohibit your commercialization of Your Product so long as you 43 | do not commercialize the SDK (or any modifications or derivative works thereof) separately from Your Product or on a stand-alone 44 | basis; use the SDK (or any modifications or derivative works thereof) to create or facilitate the creation of, or otherwise 45 | incorporate any portion of the SDK in, any product or service that is competitive with Nexmo’s Service; use the SDK to perform 46 | comparisons or other “benchmarking” activities; remove any proprietary notices or branding from the SDK; and/or use the SDK in 47 | violation of Section 11 or any applicable laws or regulations or outside of the scope of the license granted in Section 1. 48 | 49 | 3. OWNERSHIP. As between you and Nexmo, all right, title and interest (and all related intellectual property rights) in and to 50 | the SDK (for clarity, excluding Open Source Components), and any copies or portions thereof, shall remain with Nexmo and its 51 | suppliers or licensors. All right, title and interest in and to any of Your Products properly made by you using the SDK (but 52 | excluding the SDK itself and any components thereof, and Nexmo’s Services, for the avoidance of doubt) shall remain yours, 53 | subject to Section 2 and 10. You understand that Nexmo may modify or discontinue offering the SDK at any time without notice. 54 | The SDK is protected by the copyright laws of the United States and international copyright treaties. Nothing in this Agreement 55 | gives you a right to use any of Nexmo’s trade names, trademarks, service marks, logos, domain names, or other distinctive brand 56 | features. Nexmo does not grant any and reserves all rights not expressly and unambiguously granted herein. 57 | 58 | 4. SUPPORT AND UPGRADES. If Nexmo provides you with any upgrades, patches, enhancements or fixes for the SDK that it makes 59 | generally available free of charge in connection with the SDK (“Updates”), then the items that are provided will become part of 60 | the SDK and subject to this Agreement. You shall keep the SDK library relevant to Your Product up to date including any such 61 | Updates. Nexmo shall have no obligation, however, under this Agreement or otherwise to provide any upgrades, patches, 62 | enhancements, fixes or any other support to you for the SDK. 63 | 64 | 5. INDEMNITY. You agree that Nexmo shall have no liability whatsoever for any use you make of the SDK. You hereby agree to 65 | indemnify and hold harmless Nexmo and its affiliates, and each of their directors, officers, employees and agents, from any and 66 | all damages, liabilities, losses, costs, and expenses (including, without limitation, attorneys’ fees) arising from Your 67 | Products or your use of the SDK (or any modifications or derivative works thereof) or any Open Source Components. 68 | 69 | 6. WARRANTY AND DISCLAIMER. NEXMO PROVIDES THE SDK “AS IS” AND “AS AVAILABLE” WITHOUT ANY WARRANTY OF ANY KIND AND HEREBY 70 | DISCLAIMS, FOR ITSELF AND ITS LICENSORS AND SUPPLIERS, ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING WITHOUT LIMITATION 71 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, PERFORMANCE, ACCURACY, RELIABILITY, NON-INFRINGEMENT, AND 72 | WARRANTIES ARISING OUT OF COURSE OF PERFORMANCE, COURSE OF DEALING OR USAGE IN TRADE. THIS DISCLAIMER OF WARRANTY CONSTITUTES 73 | AN ESSENTIAL PART OF THE AGREEMENT. 74 | 75 | 7. LIMITATION OF LIABILITY. NOTWITHSTANDING ANYTHING ELSE, UNDER NO CIRCUMSTANCES SHALL NEXMO OR ITS LICENSORS OR SUPPLIERS, 76 | BE LIABLE TO YOU OR ANY OTHER PERSON WITH RESPECT TO THE SUBJECT MATTER OF THIS AGREEMENT UNDER ANY CONTRACT, TORT, NEGLIGENCE, 77 | STRICT LIABILITY, WARRANTY OR OTHER LEGAL OR EQUITABLE THEORY, FOR ANY INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES 78 | OF ANY KIND INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, LOSS OF DATA, COSTS OF PROCUREMENT OF 79 | SUBSTITUTE GOODS, SERVICES, TECHNOLOGY OR RIGHTS, INTERRUPTION OF BUSINESS, ACCURACY OF RESULTS, COMPUTER FAILURE OR 80 | MALFUNCTION, OR OTHER DAMAGES IN EXCESS OF ONE HUNDRED DOLLARS (US$100), EVEN IF AWARE OF THE POSSIBILITY OF SUCH DAMAGES. 81 | 82 | 8. BASIS OF BARGAIN. YOU AND NEXMO EACH RECOGNIZE AND AGREE THAT THE WARRANTY DISCLAIMERS AND LIABILITY AND REMEDY LIMITATIONS 83 | IN THIS AGREEMENT ARE MATERIAL, BARGAINED FOR BASES FOR THIS AGREEMENT AND THAT THEY HAVE BEEN TAKEN INTO ACCOUNT AND REFLECTED 84 | IN DETERMINING THE CONSIDERATION TO BE GIVEN BY EACH PARTY UNDER THIS AGREEMENT AND IN THE DECISION BY EACH PARTY TO ENTER INTO 85 | THIS AGREEMENT. 86 | 87 | 9. TERMINATION. You may terminate this Agreement and the license granted by Nexmo to you herein at any time. Nexmo may 88 | terminate this Agreement and the licenses granted by Nexmo to you in this Agreement immediately if you breach any provision of 89 | this Agreement, in additional to all other available remedies. Upon termination, all of your rights and licenses from Nexmo 90 | under this Agreement cease; you must cease exercise of the licensed rights herein; you must destroy or remove from all hard 91 | drives, networks, and storage media, all copies and extracts of the SDK; and this sentence, all remedies for breach, and 92 | Sections 2 through 8 and 10 through 13 shall survive any termination of this Agreement. YOU ACKNOWLEDGE THAT TERMINATION OF 93 | YOUR RIGHTS TO THE SDK MAY CAUSE YOUR PRODUCT(S) TO NOT OPERATE PROPERLY, AND NEXMO WILL HAVE NO LIABILITY OR RESPONSIBILITY 94 | WHATSOEVER AS A RESULT THEREOF. 95 | 96 | 10. FREEDOM TO OPERATE. You agree that Nexmo may collect or you may provide to Nexmo (or publicly) comments, feedback, 97 | suggestions or other information related to the SDK, or modifications, corrections, improvements, derivatives and extensions 98 | to the SDK, or use thereof (collectively, “Feedback”), and you hereby grant Nexmo the perpetual and irrevocable right (and the 99 | perpetual and irrevocable right to permit others) to use and fully exercise and exploit the Feedback in any manner to improve, 100 | develop and otherwise exploit applications, services or technology, and otherwise in connection with its business during and 101 | after the term of this Agreement. 102 | 103 | 11. EXPORT. You shall comply with all laws, rules and regulations of the Department of Commerce, the United States Department 104 | of the Treasury Office of Foreign Assets Control (“OFAC”), and other United States or foreign agency or authority, and not 105 | export, or allow the export or re-export of the SDK in violation of any such restrictions, laws or regulations. By downloading 106 | or using the SDK or exercising any of the rights granted in this Agreement, you are agreeing to the foregoing and representing 107 | and warranting that you are not located in, under the control of, or a national or resident of any country to which the United 108 | States has embargoed good or services or similar restrictions (e.g. the Crimea region of Ukraine, Cuba, Iran, North Korea, 109 | Sudan or Syria without an appropriate exemption), and you are not identified as a “Specially Designated National” or “Foreign 110 | Sanctions Evader” by OFAC, you are not placed on the U.S. Commerce Department’s Denied Persons, Entity or Unverified List or 111 | any similar lists, you are not an entity that a Specially Designated National owns in the aggregate a 50% or greater interest 112 | in directly or indirectly, and you will not access or use the SDK if any applicable laws in your country prohibit you from 113 | doing so in accordance with this Agreement or limit the terms of this Agreement. You will not export the SDK or any modificat 114 | ion or derivative work thereof to support any nuclear proliferation, chemical weapons, biological weapons or missile proliferation activity. 115 | 116 | 12. GOVERNMENT RESTRICTED RIGHTS. All software, technology, and accompanying documentation are deemed to be “commercial 117 | computer software” and “commercial computer software documentation,” respectively, pursuant to DFAR Section 227.7202 and FAR 118 | Section 12.212, as applicable. Any use, modification, reproduction, release, performance, display, transfer or disclosure of 119 | the SDK and accompanying documentation by any agency, department or other entity of any government, shall be governed solely by 120 | the terms of this Agreement and shall be prohibited except to the extent expressly permitted by the terms herein or in a 121 | writing signed by an authorized signatory on behalf of Nexmo Inc. No other rights are granted. 122 | 123 | 13. MISCELLANEOUS. This Agreement contains the complete agreement between you and Nexmo regarding the SDK and supersedes all 124 | prior agreements and representations between you and Nexmo regarding the SDK. Nexmo reserves the right, in its sole 125 | discretion, to modify or replace this Agreement at any time by posting a notice on this webpage, on its website located at 126 | www.nexmo.com or by sending you a notice through the Services, or by another appropriate means of electronic communication. 127 | This Agreement may only be amended and any provision may only be waived by a writing executed by both parties except as 128 | otherwise set forth above. You agree to promptly provide Nexmo with all information and documentation that Nexmo requests to 129 | verify your compliance with this Agreement. If any provision of this Agreement is held to be invalid or unenforceable, it 130 | shall be reformed to the limited extent necessary to make it enforceable. This Agreement shall be governed by and construed 131 | in accordance with the laws of California, without regard to its conflicts of laws provisions. California will have exclusive 132 | jurisdiction and venue under this Agreement. You may not assign or transfer any part of this Agreement to any third party. 133 | Nexmo may assign and transfer this Agreement without consent to a successor to all or substantially all of its business or 134 | assets to which this Agreement relates. 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Verify SDK will shut down effective 14th November, 2018. 2 | 3 | ## To assist with a seamless migration to the Verify API, we have prepared [technical documentation](https://www.nexmo.com/blog/2018/05/10/nexmo-verify-api-implementation-guide-dr/) that will guide you in implementing the Verify API into your client side applications. 4 | 5 | # Nexmo Verify SDK for JavaScript 6 | 7 | You use Nexmo Verify to verify that a user has access to a specific phone number. Nexmo sends a PIN code in an SMS or Text-To-Speech, your user enters this PIN into your App, you validate the PIN with Nexmo. With Verify SDK for JavaScript you easily integrate Verify functionality into your App. 8 | 9 | In order to implement the Verify SDK for JavaScript: 10 | * [Setting up your environment](https://docs.nexmo.com/verify/verify-sdk-for-javascript): before you start coding, create a Verify SDK app in the Dashboard and configure for JavaScript. 11 | * [Integrating Verify SDK for JavaScript](https://docs.nexmo.com/verify/verify-sdk-for-javascript/integration): create and run your first App. 12 | * [API reference](https://docs.nexmo.com/verify/verify-sdk-for-javascript/api-reference): check the parameters for the calls in Verify SDK for JavaScript 13 | 14 | ## License 15 | 16 | Copyright (c) 2015 Nexmo, Inc. 17 | All rights reserved. 18 | Licensed only under the Nexmo Verify SDK License Agreement (the "License") located at 19 | 20 | https://www.nexmo.com/terms-use/verify-sdk/ 21 | 22 | By downloading or otherwise using our software or services, you acknowledge 23 | that you have read, understand and agree to be bound by the 24 | [Nexmo Verify SDK License Agreement][1] and [Privacy Policy][2]. 25 | 26 | You may not use, exercise any rights with respect to or exploit this SDK, 27 | or any modifications or derivative works thereof, except in accordance with the License. 28 | 29 | [1]: https://www.nexmo.com/terms-use/verify-sdk/ 30 | [2]: https://www.nexmo.com/privacy-policy/ 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "verify-javascript-sdk", 3 | "version": "0.2.3", 4 | "description": "JS SDK for Nexmo Verify API", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": "mocha tests/*.js --reporter nyan --compilers js:babel-register", 8 | "build": "babel src -d lib", 9 | "prepublish": "npm run build", 10 | "watch": "babel src --watch -d lib", 11 | "eslint": "eslint ./src/*.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/Nexmo/verify-javascript-sdk" 16 | }, 17 | "keywords": [ 18 | "nexmo", 19 | "verify", 20 | "number-verify", 21 | "api", 22 | "SDK" 23 | ], 24 | "author": "Mattia Asti", 25 | "license": "SEE LICENSE IN ", 26 | "bugs": { 27 | "url": "https://github.com/Nexmo/verify-javascript-sdk/issues" 28 | }, 29 | "homepage": "https://github.com/Nexmo/verify-javascript-sdk#readme", 30 | "dependencies": { 31 | "ip": "^1.1.0", 32 | "macaddress": "^0.2.8", 33 | "popsicle": "^2.0.1", 34 | "sort-keys": "^1.1.1" 35 | }, 36 | "devDependencies": { 37 | "babel-cli": "^6.3.17", 38 | "babel-eslint": "^5.0.0-beta6", 39 | "babel-preset-es2015": "^6.3.13", 40 | "babel-register": "^6.3.13", 41 | "chai": "^3.4.1", 42 | "chai-as-promised": "^5.2.0", 43 | "del": "^2.2.0", 44 | "eslint": "^1.10.3", 45 | "mocha": "^2.3.4", 46 | "nock": "^4.0.0", 47 | "pre-commit": "^1.1.2" 48 | }, 49 | "pre-commit": [ 50 | "eslint", 51 | "test" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import verify from './verify.js'; 2 | import verifyCheck from './verifyCheck.js'; 3 | import verifyControl from './verifyControl.js'; 4 | import verifySearch from './verifySearch.js'; 5 | import verifyLogout from './verifyLogout.js'; 6 | import macaddress from 'macaddress'; 7 | 8 | const ip = require('ip').address(); 9 | 10 | const deviceId = macaddress.one((err, mac) => { 11 | if (err) { 12 | throw err; 13 | } 14 | return mac; 15 | }); 16 | 17 | 18 | function NexmoVerify(config = {}) { 19 | this.appId = config.appId; 20 | this.sharedSecret = config.sharedSecret; 21 | this.deviceId = deviceId; 22 | this.sourceIp = ip; 23 | 24 | this.verify = verify.bind(this); 25 | this.verifyCheck = this.verifyCheck.bind(this); 26 | this.verifyControl = this.verifyControl.bind(this); 27 | this.verifySearch = this.verifySearch.bind(this); 28 | this.verifyLogout = this.verifyLogout.bind(this); 29 | } 30 | 31 | NexmoVerify.prototype.verify = verify; 32 | NexmoVerify.prototype.verifyCheck = verifyCheck; 33 | NexmoVerify.prototype.verifyControl = verifyControl; 34 | NexmoVerify.prototype.verifySearch = verifySearch; 35 | NexmoVerify.prototype.verifyLogout = verifyLogout; 36 | 37 | module.exports = NexmoVerify; 38 | -------------------------------------------------------------------------------- /src/shared.js: -------------------------------------------------------------------------------- 1 | import sortKeys from 'sort-keys'; 2 | import querystring from 'querystring'; 3 | import crypto from 'crypto'; 4 | 5 | const apiEndpoints = { 6 | getToken: 'https://api.nexmo.com/sdk/token/json?', 7 | verify: 'https://api.nexmo.com/sdk/verify/json?', 8 | verifyCheck: 'https://api.nexmo.com/sdk/verify/check/json?', 9 | verifyControl: 'https://api.nexmo.com/sdk/verify/control/json?', 10 | verifySearch: 'https://api.nexmo.com/sdk/verify/search/json?', 11 | verifyLogout: 'https://api.nexmo.com/sdk/verify/logout/json?', 12 | }; 13 | 14 | function nexmoHeaders() { 15 | return (req) => { 16 | req.set('Content-type', 'application/x-www-form-urlencoded'); 17 | req.set('Content-Encoding', 'UTF-8'); 18 | req.set('X-NEXMO-SDK-OS-FAMILY', 'JS'); 19 | req.set('X-NEXMO-SDK-REVISION', '0.2'); 20 | }; 21 | } 22 | 23 | 24 | function isClientSet(client) { 25 | if (client.appId === undefined || client.sharedSecret === undefined) { 26 | return false; 27 | } else { 28 | return true; 29 | } 30 | } 31 | 32 | function isResponseValid(response, sharedSecret) { 33 | if (!response.headers['x-nexmo-response-signature']) { 34 | return false; 35 | } 36 | let r = JSON.stringify(response.body, null, 4); 37 | const s = response.headers['x-nexmo-response-signature']; 38 | r = r + sharedSecret; 39 | const responseMd5 = crypto.createHash('md5').update(r).digest('hex'); 40 | 41 | if (responseMd5 === s) { 42 | return true; 43 | } else { 44 | return false; 45 | } 46 | } 47 | 48 | function createSignature(signatureParams, sharedSecret) { 49 | let s = signatureParams; 50 | s = decodeURIComponent(s); 51 | s = '&' + s + sharedSecret; 52 | return crypto.createHash('md5').update(s).digest('hex'); 53 | } 54 | 55 | function generateParameters(params, client) { 56 | const now = Math.round(new Date().getTime() / 1000); 57 | 58 | let tokenForRequest; 59 | let tokenForSignature; 60 | 61 | // Generate parameters for verify* requests (you have the token) 62 | if (client.hasOwnProperty('token')) { 63 | tokenForRequest = JSON.parse(JSON.stringify(client.token)); 64 | tokenForSignature = JSON.parse(JSON.stringify(client.token)); 65 | tokenForSignature = tokenForSignature.replace(/[&,=]/g, '_'); 66 | } 67 | 68 | let signatureParams = params; 69 | if (client.hasOwnProperty('token')) { 70 | signatureParams.token = tokenForSignature; 71 | } 72 | signatureParams.timestamp = now; 73 | signatureParams = sortKeys(signatureParams); 74 | signatureParams = querystring.stringify(signatureParams); 75 | const signature = createSignature(signatureParams, client.sharedSecret); 76 | 77 | let requestParameters = params; 78 | requestParameters.timestamp = now; 79 | if (client.hasOwnProperty('token')) { 80 | requestParameters.token = tokenForRequest; 81 | } 82 | requestParameters = sortKeys(requestParameters); 83 | requestParameters = querystring.stringify(requestParameters); 84 | requestParameters = requestParameters + '&sig=' + signature; 85 | 86 | return requestParameters; 87 | } 88 | 89 | module.exports = { 90 | apiEndpoints: apiEndpoints, 91 | createSignature: createSignature, 92 | isClientSet: isClientSet, 93 | isResponseValid: isResponseValid, 94 | nexmoHeaders: nexmoHeaders, 95 | generateParameters: generateParameters, 96 | }; 97 | -------------------------------------------------------------------------------- /src/token.js: -------------------------------------------------------------------------------- 1 | import popsicle from 'popsicle'; 2 | import shared from './shared.js'; 3 | 4 | const generateParameters = shared.generateParameters; 5 | const nexmoHeaders = shared.nexmoHeaders; 6 | const apiEndpoint = shared.apiEndpoints.getToken; 7 | 8 | function getToken(client) { 9 | return new Promise((resolve, reject) => { 10 | const queryParams = { 11 | 'app_id': client.appId, 12 | 'device_id': client.deviceId, 13 | 'source_ip_address': client.sourceIp, 14 | }; 15 | 16 | popsicle(apiEndpoint + generateParameters(queryParams, client)) 17 | .use(nexmoHeaders()) 18 | .then((res) => { 19 | // Any result_code different than zero means an error, return the error. 20 | if (res.body.result_code !== 0) { 21 | return reject(res.body.result_message); 22 | } 23 | 24 | if (!shared.isResponseValid(res, client.sharedSecret)) { 25 | return reject('Response verification failed'); 26 | } else { 27 | return resolve(res.body.token); 28 | } 29 | }) 30 | .catch((err) => { 31 | return reject(err); 32 | }); 33 | }); 34 | } 35 | 36 | function checkToken(client) { 37 | return new Promise((resolve, reject) => { 38 | if (!client || !client.token || client.token === 'invalid') { 39 | getToken(client) 40 | .then((token) => { 41 | return resolve(token); 42 | }) 43 | .catch((error) => { 44 | return reject(error); 45 | }); 46 | } else { 47 | return resolve(client.token); 48 | } 49 | }); 50 | } 51 | 52 | module.exports = { 53 | checkToken: checkToken, 54 | getToken: getToken, 55 | }; 56 | -------------------------------------------------------------------------------- /src/verify.js: -------------------------------------------------------------------------------- 1 | import popsicle from 'popsicle'; 2 | import shared from './shared.js'; 3 | import { 4 | checkToken, 5 | } 6 | from './token.js'; 7 | 8 | const nexmoHeaders = shared.nexmoHeaders; 9 | const apiEndpoint = shared.apiEndpoints.verify; 10 | const generateParameters = shared.generateParameters; 11 | 12 | let retry = 0; 13 | 14 | function verify(params) { 15 | const client = this; 16 | 17 | return new Promise((resolve, reject) => { 18 | if (!shared.isClientSet(client)) { 19 | // console.log('console: credentials missing'); 20 | return reject('You need to set credentials'); 21 | } 22 | 23 | if (!params || !params.number) { 24 | // console.log('console: number missing'); 25 | return reject('You need to pass a number'); 26 | } 27 | 28 | // console.log('retry: ', retry); 29 | 30 | checkToken(client) 31 | .then((token) => { 32 | client.token = token; 33 | 34 | const queryParams = { 35 | 'app_id': client.appId, 36 | 'device_id': client.deviceId, 37 | 'number': params.number, 38 | 'source_ip_address': client.sourceIp, 39 | }; 40 | 41 | if (params.lg) { 42 | queryParams.lg = params.lg; 43 | } 44 | 45 | if (params.country) { 46 | queryParams.country = params.country; 47 | } 48 | 49 | popsicle(apiEndpoint + generateParameters(queryParams, client)) 50 | .use(nexmoHeaders()) 51 | .then((res) => { 52 | // Check if the token is invalid request a new one and call again the function 53 | if (res.body.result_code === 3) { 54 | if (retry < 1) { 55 | retry = 1; 56 | client.token = 'invalid'; 57 | return verify.call(client, params); 58 | } 59 | // what happens if the second time it can't retrieve the token? 60 | // should it try again n times? 61 | // else { 62 | // retry += 1; 63 | // return reject(res.body.result_message); 64 | // } 65 | } else { 66 | retry = 0; 67 | } 68 | 69 | // Any result_code different than zero means an error, return the error. 70 | if (res.body.result_code !== 0) { 71 | return reject(res.body.result_message); 72 | } 73 | 74 | if (!shared.isResponseValid(res, client.sharedSecret)) { 75 | return reject('Response verification failed'); 76 | } else { 77 | return resolve(res.body.user_status); 78 | } 79 | }) 80 | .catch((err) => { 81 | return reject(err); 82 | }); 83 | }) 84 | .catch((err) => { 85 | return reject(err); 86 | }); 87 | }); 88 | } 89 | 90 | module.exports = verify; 91 | -------------------------------------------------------------------------------- /src/verifyCheck.js: -------------------------------------------------------------------------------- 1 | import popsicle from 'popsicle'; 2 | import shared from './shared.js'; 3 | import {checkToken} from './token.js'; 4 | 5 | const nexmoHeaders = shared.nexmoHeaders; 6 | const apiEndpoint = shared.apiEndpoints.verifyCheck; 7 | const generateParameters = shared.generateParameters; 8 | 9 | let retry = 0; 10 | 11 | function verifyCheck(params) { 12 | const client = this; 13 | 14 | return new Promise((resolve, reject) => { 15 | if (!shared.isClientSet(client)) { 16 | return reject('You need to set credentials'); 17 | } 18 | 19 | if (!params || !params.number) { 20 | return reject('You need to pass a number'); 21 | } else if (!params || !params.code) { 22 | return reject('You need to pass a pin code'); 23 | } 24 | 25 | checkToken(client).then((token) => { 26 | client.token = token; 27 | 28 | const queryParams = { 29 | 'app_id': client.appId, 30 | 'code': params.code, 31 | 'device_id': client.deviceId, 32 | 'number': params.number, 33 | 'source_ip_address': client.sourceIp, 34 | }; 35 | 36 | if (params.country) { 37 | queryParams.country = params.country; 38 | } 39 | 40 | popsicle(apiEndpoint + generateParameters(queryParams, client)) 41 | .use(nexmoHeaders()) 42 | .then((res) => { 43 | // Check if the token is invalid request a new one and call again the function 44 | if (res.body.result_code === 3) { 45 | if (retry < 1) { 46 | retry = 1; 47 | client.token = 'invalid'; 48 | return verifyCheck.call(client, params); 49 | } 50 | } else { 51 | retry = 0; 52 | } 53 | 54 | // Any result_code different than zero means an error, return the error. 55 | if (res.body.result_code !== 0) { 56 | return reject(res.body.result_message); 57 | } 58 | 59 | if (!shared.isResponseValid(res, client.sharedSecret)) { 60 | return reject('Response verification failed'); 61 | } else { 62 | return resolve(res.body.user_status); 63 | } 64 | }) 65 | .catch((err) => { 66 | return reject(err); 67 | }); 68 | }) 69 | .catch((err) => { 70 | return reject(err); 71 | }); 72 | }); 73 | } 74 | 75 | module.exports = verifyCheck; 76 | -------------------------------------------------------------------------------- /src/verifyControl.js: -------------------------------------------------------------------------------- 1 | import popsicle from 'popsicle'; 2 | import shared from './shared.js'; 3 | import {checkToken} from './token.js'; 4 | 5 | const nexmoHeaders = shared.nexmoHeaders; 6 | const apiEndpoint = shared.apiEndpoints.verifyControl; 7 | const generateParameters = shared.generateParameters; 8 | 9 | let retry = 0; 10 | 11 | function verifyControl(params) { 12 | const client = this; 13 | 14 | return new Promise((resolve, reject) => { 15 | if (!shared.isClientSet(client)) { 16 | return reject('You need to set credentials'); 17 | } 18 | 19 | if (!params.number) { 20 | return reject('You need to pass a number'); 21 | } else if (!params.cmd) { 22 | return reject('You need to pass a command'); 23 | } 24 | 25 | checkToken(client).then((token) => { 26 | client.token = token; 27 | 28 | const queryParams = { 29 | 'app_id': client.appId, 30 | 'cmd': params.cmd, 31 | 'device_id': client.deviceId, 32 | 'number': params.number, 33 | 'source_ip_address': client.sourceIp, 34 | }; 35 | 36 | if (params.country) { 37 | queryParams.country = params.country; 38 | } 39 | 40 | popsicle(apiEndpoint + generateParameters(queryParams, client)) 41 | .use(nexmoHeaders()) 42 | .then((res) => { 43 | // Check if the token is invalid request a new one and call again the function 44 | if (res.body.result_code === 3) { 45 | if (retry < 1) { 46 | retry = 1; 47 | client.token = 'invalid'; 48 | return verifyControl.call(client, params); 49 | } 50 | } else { 51 | retry = 0; 52 | } 53 | 54 | // Any result_code different than zero means an error, return the error. 55 | if (res.body.result_code !== 0) { 56 | return reject(res.body.result_message); 57 | } 58 | 59 | if (!shared.isResponseValid(res, client.sharedSecret)) { 60 | return reject('Response verification failed'); 61 | } else { 62 | return resolve(res.body.user_status); 63 | } 64 | }) 65 | .catch((err) => { 66 | return reject(err); 67 | }); 68 | }) 69 | .catch((err) => { 70 | return reject(err); 71 | }); 72 | }); 73 | } 74 | 75 | module.exports = verifyControl; 76 | -------------------------------------------------------------------------------- /src/verifyLogout.js: -------------------------------------------------------------------------------- 1 | import popsicle from 'popsicle'; 2 | import shared from './shared.js'; 3 | import {checkToken} from './token.js'; 4 | 5 | const nexmoHeaders = shared.nexmoHeaders; 6 | const apiEndpoint = shared.apiEndpoints.verifyLogout; 7 | const generateParameters = shared.generateParameters; 8 | 9 | let retry = 0; 10 | 11 | function verifyLogout(params) { 12 | const client = this; 13 | 14 | return new Promise((resolve, reject) => { 15 | if (!shared.isClientSet(client)) { 16 | return reject('You need to set credentials'); 17 | } 18 | 19 | if (!params.number) { 20 | return reject('You need to pass a number'); 21 | } 22 | 23 | checkToken(client).then((token) => { 24 | client.token = token; 25 | 26 | const queryParams = { 27 | 'app_id': client.appId, 28 | 'device_id': client.deviceId, 29 | 'number': params.number, 30 | 'source_ip_address': client.sourceIp, 31 | }; 32 | 33 | if (params.country) { 34 | queryParams.country = params.country; 35 | } 36 | 37 | popsicle(apiEndpoint + generateParameters(queryParams, client)) 38 | .use(nexmoHeaders()) 39 | .then((res) => { 40 | // Check if the token is invalid request a new one and call again the function 41 | if (res.body.result_code === 3) { 42 | if (retry < 1) { 43 | retry = 1; 44 | client.token = 'invalid'; 45 | return verifyLogout.call(client, params); 46 | } 47 | } else { 48 | retry = 0; 49 | } 50 | 51 | // Any result_code different than zero means an error, return the error. 52 | if (res.body.result_code !== 0) { 53 | return reject(res.body.result_message); 54 | } 55 | 56 | if (!shared.isResponseValid(res, client.sharedSecret)) { 57 | return reject('Response verification failed'); 58 | } else { 59 | return resolve(res.body.user_status); 60 | } 61 | }) 62 | .catch((err) => { 63 | return reject(err); 64 | }); 65 | }) 66 | .catch((err) => { 67 | return reject(err); 68 | }); 69 | }); 70 | } 71 | 72 | module.exports = verifyLogout; 73 | -------------------------------------------------------------------------------- /src/verifySearch.js: -------------------------------------------------------------------------------- 1 | import popsicle from 'popsicle'; 2 | import shared from './shared.js'; 3 | import {checkToken} from './token.js'; 4 | 5 | const nexmoHeaders = shared.nexmoHeaders; 6 | const apiEndpoint = shared.apiEndpoints.verifySearch; 7 | const generateParameters = shared.generateParameters; 8 | 9 | let retry = 0; 10 | 11 | function verifySearch(params) { 12 | const client = this; 13 | 14 | return new Promise((resolve, reject) => { 15 | if (!shared.isClientSet(client)) { 16 | return reject('You need to set credentials'); 17 | } 18 | 19 | if (!params.number) { 20 | return reject('You need to pass a number'); 21 | } 22 | 23 | checkToken(client).then((token) => { 24 | client.token = token; 25 | 26 | const queryParams = { 27 | 'app_id': client.appId, 28 | 'device_id': client.deviceId, 29 | 'number': params.number, 30 | 'source_ip_address': client.sourceIp, 31 | }; 32 | 33 | if (params.country) { 34 | queryParams.country = params.country; 35 | } 36 | 37 | popsicle(apiEndpoint + generateParameters(queryParams, client)) 38 | .use(nexmoHeaders()) 39 | .then((res) => { 40 | // Check if the token is invalid request a new one and call again the function 41 | if (res.body.result_code === 3) { 42 | if (retry < 1) { 43 | retry = 1; 44 | client.token = 'invalid'; 45 | return verifySearch.call(client, params); 46 | } 47 | } else { 48 | retry = 0; 49 | } 50 | 51 | // Any result_code different than zero means an error, return the error. 52 | if (res.body.result_code !== 0) { 53 | return reject(res.body.result_message); 54 | } 55 | 56 | if (!shared.isResponseValid(res, client.sharedSecret)) { 57 | return reject('Response verification failed'); 58 | } else { 59 | return resolve(res.body.user_status); 60 | } 61 | }) 62 | .catch((err) => { 63 | return reject(err); 64 | }); 65 | }) 66 | .catch((err) => { 67 | return reject(err); 68 | }); 69 | }); 70 | } 71 | 72 | module.exports = verifySearch; 73 | -------------------------------------------------------------------------------- /tests/config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "appId":"12345678-1234-1234-1234-123456789012", 3 | "sharedSecret": "a1b2c3d4c5e6d7" 4 | } 5 | -------------------------------------------------------------------------------- /tests/shared.js: -------------------------------------------------------------------------------- 1 | import config from './config.example.json'; 2 | import Nexmo from '../src/index.js'; 3 | import chai from 'chai'; 4 | import nock from 'nock'; 5 | import shared from '../src/shared.js'; 6 | import popsicle from 'popsicle'; 7 | const assert = chai.assert; 8 | 9 | describe('Popsicle nexmoHeaders plugin', () => { 10 | it('should add Nexmo headers to every request', () => { 11 | nock('https://api.nexmo.com') 12 | .get('/sdk/token/json') 13 | .query(true) 14 | .reply(200); 15 | 16 | popsicle('https://api.nexmo.com/sdk/token/json') 17 | .use(shared.nexmoHeaders()) 18 | .then((res) => { 19 | assert.equal(res.request.headers['content-type'], 'application/x-www-form-urlencoded'); 20 | assert.equal(res.request.headers['content-encoding'], 'UTF-8'); 21 | assert.equal(res.request.headers['x-nexmo-sdk-os-family'], 'JS'); 22 | assert.equal(res.request.headers['x-nexmo-sdk-revision'], '0.1'); 23 | }); 24 | }); 25 | }); 26 | 27 | describe('Check if client is set (appId and sharedSecret)', () => { 28 | it('should return true if set', () => { 29 | const n = new Nexmo(config); 30 | assert.equal(shared.isClientSet(n), true); 31 | }); 32 | it('should return false if one or both are missing', () => { 33 | const n = new Nexmo(); 34 | assert.equal(shared.isClientSet(n), false); 35 | }); 36 | }); 37 | 38 | describe('Check the server response', () => { 39 | it('should return false if header "x-nexmo-response-signature" is missing', () => { 40 | const response = { 41 | headers: {}, 42 | body: {}, 43 | }; 44 | return assert.equal(shared.isResponseValid(response), false); 45 | }); 46 | 47 | it('should return false if the signature is invalid', () => { 48 | const response = { 49 | headers: { 50 | 'x-nexmo-response-signature': 'wrong_signature', 51 | }, 52 | body: { 53 | result_code: 0, 54 | result_message: 'OK', 55 | timestamp: '1234567890', 56 | token: 'UBR51htkeMhUoQ0cIWEyffIeCcytVxqEGhwav0b8/nUAbjaQvPURuTtCYtIQ1YztbiNxSVRnXWLB\n2Meby4EVsYNumN4savfON3GpvSYg4BhmJPzZ2eWPiq0DnL/NwiPc75kM1KZE+otU98OC1X0T7w==\n', 57 | }, 58 | }; 59 | const sharedSecret = '1234567890abcdef'; 60 | return assert.equal(shared.isResponseValid(response, sharedSecret), false); 61 | }); 62 | 63 | it('should return true if the signature is valid', () => { 64 | const response = { 65 | headers: { 66 | 'x-nexmo-response-signature': '41d30b9d645e32f386fa0719b819ee7a', 67 | }, 68 | body: { 69 | result_code: 0, 70 | result_message: 'OK', 71 | timestamp: '1234567890', 72 | token: 'UBR51htkeMhUoQ0cIWEyffIeCcytVxqEGhwav0b8/nUAbjaQvPURuTtCYtIQ1YztbiNxSVRnXWLB\n2Meby4EVsYNumN4savfON3GpvSYg4BhmJPzZ2eWPiq0DnL/NwiPc75kM1KZE+otU98OC1X0T7w==\n', 73 | }, 74 | }; 75 | const sharedSecret = '1234567890abcdef'; 76 | return assert.equal(shared.isResponseValid(response, sharedSecret), true); 77 | }); 78 | }); 79 | 80 | describe('Create signature', () => { 81 | it('should return a valid signature', () => { 82 | const sigParams = 'app_id=123456&device_id=80%3Ae6%3A50%3A04%3A23%3A52&source_ip_address=192.168.1.140×tamp=1438811485'; 83 | const sharedSecret = '123456'; 84 | return assert.equal(shared.createSignature(sigParams, sharedSecret), '92bbbf636173e58fbb9a34af24fa080c'); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /tests/token.js: -------------------------------------------------------------------------------- 1 | import config from './config.example.json'; 2 | import Nexmo from '../src/index.js'; 3 | import chai from 'chai'; 4 | import nock from 'nock'; 5 | import Token from '../src/token.js'; 6 | const checkToken = Token.checkToken; 7 | const assert = chai.assert; 8 | import chaiAsPromised from 'chai-as-promised'; 9 | 10 | chai.use(chaiAsPromised); 11 | 12 | describe('Check if there is a token', () => { 13 | it('returns the token if it\'s already present', () => { 14 | const n = new Nexmo(config); 15 | n.token = '1234567890'; 16 | assert.eventually.equal(checkToken(n), '1234567890'); 17 | }); 18 | 19 | it('returns a valid token if it\'s not present', () => { 20 | const n = new Nexmo({ 21 | appId: '123456', 22 | sharedSecret: '123456', 23 | }); 24 | nock('https://api.nexmo.com') 25 | .get('/sdk/token/json') 26 | .query(true) 27 | .reply(200, { 28 | result_code: 0, 29 | result_message: 'OK', 30 | timestamp: '1234567890', 31 | token: 'UBR51htkeMhUoQ0cIWEyffIeCcytVxqEGhwav0b8/nUAbjaQvPURuTtCYtIQ1YztbiNxSVRnXWLB\n2Meby4EVsYNumN4savfON3GpvSYg4BhmJPzZ2eWPiq0DnL/NwiPc75kM1KZE+otU98OC1X0T7w==\n', 32 | }, { 33 | 'Content-type': 'application/json', 34 | 'x-nexmo-response-signature': '78d054882b2a8d1562d90d7eb4cb0987', 35 | }); 36 | assert.isFulfilled(checkToken(n)); 37 | assert.eventually.equal(checkToken(n), 'UBR51htkeMhUoQ0cIWEyffIeCcytVxqEGhwav0b8/nUAbjaQvPURuTtCYtIQ1YztbiNxSVRnXWLB\n2Meby4EVsYNumN4savfON3GpvSYg4BhmJPzZ2eWPiq0DnL/NwiPc75kM1KZE+otU98OC1X0T7w==\n'); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /tests/verify.js: -------------------------------------------------------------------------------- 1 | import config from './config.example.json'; 2 | import Nexmo from '../src/index.js'; 3 | import chai from 'chai'; 4 | import nock from 'nock'; 5 | const assert = chai.assert; 6 | import chaiAsPromised from 'chai-as-promised'; 7 | chai.use(chaiAsPromised); 8 | 9 | describe('Verify', () => { 10 | it('returns an error if the credentials are not set', () => { 11 | const n = new Nexmo(); 12 | return assert.isRejected(n.verify(), 'You need to set credentials'); 13 | }); 14 | 15 | it('returns an error if the number is not passed as parameter', () => { 16 | const n = new Nexmo(config); 17 | return assert.isRejected(n.verify(), 'You need to pass a number'); 18 | }); 19 | 20 | it('when the token is expired ask for a new one', () => { 21 | const n = new Nexmo({ 22 | appId: '123456', 23 | sharedSecret: '123456', 24 | }); 25 | 26 | // there is already a token that we pretend it's expired 27 | n.token = 'UBR51htkeMhUoQ0cIWEyffIeCcytVxqEGhwav0b8/nUAbjaQvPURuTtCYtIQ1YztbiNxSVRnXWLB\n2Meby4EVsYNumN4savfON3GpvSYg4BhmJPzZ2eWPiq0DnL/NwiPc75kM1KZE+otU98OC1X0T7w==\n'; 28 | 29 | // mock the call to verify, token expired error code 30 | nock('https://api.nexmo.com') 31 | .get('/sdk/verify/json') 32 | .query(true) 33 | .reply(200, { 34 | result_code: 3, 35 | }, { 36 | 'Content-type': 'application/json', 37 | 'x-nexmo-response-signature': '8f80b7d048034c5bce757b8dddc02bce', 38 | }); 39 | 40 | // mock the call to ask for a new token 41 | nock('https://api.nexmo.com') 42 | .get('/sdk/token/json') 43 | .query(true) 44 | .reply(200, { 45 | result_code: 0, 46 | result_message: 'OK', 47 | timestamp: '1234567890', 48 | token: 'UBR51htkeMhUoQ0cIWEyffIeCcytVxqEGhwav0b8/nUAbjaQvPURuTtCYtIQ1YztbiNxSVRnXWLB\n2Meby4EVsYNumN4savfON3GpvSYg4BhmJPzZ2eWPiq0DnL/NwiPc75kM1KZE+otU98OC1X0T7w==\n', 49 | }, { 50 | 'Content-type': 'application/json', 51 | 'x-nexmo-response-signature': '8f80b7d048034c5bce757b8dddc02bce', 52 | }); 53 | 54 | // mock the call to verify again (successfully) 55 | nock('https://api.nexmo.com') 56 | .get('/sdk/verify/json') 57 | .query(true) 58 | .reply(200, { 59 | result_code: 0, 60 | result_message: 'OK', 61 | timestamp: '1234567890', 62 | user_status: 'verified', 63 | }, { 64 | 'Content-type': 'application/json', 65 | 'x-nexmo-response-signature': 'df3000e7135f0ae477c2031f5fb7cf05', 66 | }); 67 | 68 | assert.isFulfilled(n.verify({ 69 | number: 44123456789, 70 | })); 71 | assert.eventually.equal(n.verify({ 72 | number: 44123456789, 73 | }), 'verified'); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /tests/verifyCheck.js: -------------------------------------------------------------------------------- 1 | import config from './config.example.json'; 2 | import Nexmo from '../src/index.js'; 3 | import chai from 'chai'; 4 | const assert = chai.assert; 5 | import chaiAsPromised from 'chai-as-promised'; 6 | chai.use(chaiAsPromised); 7 | 8 | describe('Verify Check', () => { 9 | it('returns an error if the credentials are not set', () => { 10 | const n = new Nexmo(); 11 | return assert.isRejected(n.verifyCheck(), 'You need to set credentials'); 12 | }); 13 | 14 | it('returns an error if the number is not passed as parameter', () => { 15 | const n = new Nexmo(config); 16 | return assert.isRejected(n.verifyCheck(), 'You need to pass a number'); 17 | }); 18 | 19 | it('returns an error if the pin is not passed as parameter', () => { 20 | const n = new Nexmo(config); 21 | return assert.isRejected(n.verifyCheck({ 22 | number: 123456789, 23 | }), 'You need to pass a pin code'); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tests/verifyControl.js: -------------------------------------------------------------------------------- 1 | import config from './config.example.json'; 2 | import Nexmo from '../src/index.js'; 3 | import chai from 'chai'; 4 | const assert = chai.assert; 5 | import chaiAsPromised from 'chai-as-promised'; 6 | chai.use(chaiAsPromised); 7 | 8 | describe('Verify Control', () => { 9 | it('returns an error if the credentials are not set', () => { 10 | const n = new Nexmo(); 11 | return assert.isRejected(n.verifyControl(), 'You need to set credentials'); 12 | }); 13 | 14 | it('returns an error if the number is not passed as parameter', () => { 15 | const n = new Nexmo(config); 16 | return assert.isRejected(n.verifyControl(), 'You need to pass a number'); 17 | }); 18 | 19 | it('returns an error if the pin is not passed as parameter', () => { 20 | const n = new Nexmo(config); 21 | return assert.isRejected(n.verifyControl({ 22 | number: 123456789, 23 | }), 'You need to pass a command'); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tests/verifyLogout.js: -------------------------------------------------------------------------------- 1 | import config from './config.example.json'; 2 | import Nexmo from '../src/index.js'; 3 | import chai from 'chai'; 4 | const assert = chai.assert; 5 | import chaiAsPromised from 'chai-as-promised'; 6 | chai.use(chaiAsPromised); 7 | 8 | describe('Verify Logout', () => { 9 | it('returns an error if the credentials are not set', () => { 10 | const n = new Nexmo(); 11 | return assert.isRejected(n.verifyLogout(), 'You need to set credentials'); 12 | }); 13 | 14 | it('returns an error if the number is not passed as parameter', () => { 15 | const n = new Nexmo(config); 16 | return assert.isRejected(n.verifyLogout(), 'You need to pass a number'); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /tests/verifySearch.js: -------------------------------------------------------------------------------- 1 | import config from './config.example.json'; 2 | import Nexmo from '../src/index.js'; 3 | import chai from 'chai'; 4 | const assert = chai.assert; 5 | import chaiAsPromised from 'chai-as-promised'; 6 | chai.use(chaiAsPromised); 7 | 8 | describe('Verify Search', () => { 9 | it('returns an error if the credentials are not set', () => { 10 | const n = new Nexmo(); 11 | return assert.isRejected(n.verifySearch(), 'You need to set credentials'); 12 | }); 13 | 14 | it('returns an error if the number is not passed as parameter', () => { 15 | const n = new Nexmo(config); 16 | return assert.isRejected(n.verifySearch(), 'You need to pass a number'); 17 | }); 18 | }); 19 | --------------------------------------------------------------------------------