├── index.js ├── lib ├── createLicense.js ├── validateLicense.js ├── errors.js ├── encrypt-decrypt.js ├── supported.js └── License.js ├── package.json ├── LICENSE └── Readme.md /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // 3 | var validateLicense = require('./lib/validateLicense') 4 | var createLicense = require('./lib/createLicense') 5 | // 6 | module.exports = { validateLicense, createLicense } 7 | 8 | -------------------------------------------------------------------------------- /lib/createLicense.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // 3 | const License = require('./License') 4 | const errors = require('./errors') 5 | // 6 | module.exports = (licenseData) => { 7 | // 8 | try { 9 | const license = new License(licenseData) 10 | let result = errors() 11 | result.license = license.getSerial() 12 | return result 13 | } catch (err) { 14 | throw err 15 | } 16 | // 17 | } 18 | -------------------------------------------------------------------------------- /lib/validateLicense.js: -------------------------------------------------------------------------------- 1 | 'strict use' 2 | // 3 | const License = require('./License') 4 | const errors = require('./errors') 5 | // 6 | module.exports = (licenseData, serial) => { 7 | // 8 | if (!licenseData) throw errors('WINFO_MISSING') 9 | if (!serial) throw errors('WNOT_STRING') 10 | // 11 | try { 12 | // 13 | const license = new License(licenseData) 14 | // 15 | if (license.serial === serial) { 16 | return errors() 17 | } else { 18 | throw errors('NOT_VALID') 19 | } 20 | // 21 | } catch (err) { 22 | throw (err) 23 | } 24 | // 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-license-key", 3 | "version": "1.0.1", 4 | "description": "Project fork from https://www.npmjs.com/package/licensekey", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/indianazhao/nodejs-license-key.git" 12 | }, 13 | "author": "Indiana Zhao", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/indianazhao/nodejs-license-key/issues" 17 | }, 18 | "homepage": "https://github.com/indianazhao/nodejs-license-key#readme", 19 | "dependencies": { 20 | "chai": "^3.5.0", 21 | "dotenv": "^2.0.0", 22 | "md5": "^2.2.1", 23 | "uid-safe": "^2.1.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Indiana Zhao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/errors.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // 3 | module.exports = (err = 0) => { 4 | // 5 | var message 6 | var errNum = 0 7 | // 8 | if (err) { 9 | // find err 10 | var errorTypes = { 11 | OK: 0, 12 | WINFO_MISSING: 1000, 13 | WPRODCODE_MISSING: 1002, 14 | WNOT_STRING: 1004, 15 | NOT_VALID: 1006, 16 | WLICENSE_FAILED: 1008, 17 | WUNKNOWN: 1010, 18 | ENCRYPT_ERROR: 1012, 19 | DECRYPT_ERROR: 1014 20 | } 21 | errNum = errorTypes[err] 22 | } 23 | // 24 | var errorObject = { errorCode: errNum, message: '' } 25 | // 26 | switch (errNum) { 27 | case 0: 28 | message = 'ok' 29 | break 30 | case 1000: 31 | message = 'user info missing' 32 | break 33 | case 1002: 34 | message = 'product code missing' 35 | break 36 | case 1004: 37 | message = 'license must be a string' 38 | break 39 | case 1006: 40 | message = 'license not valid' 41 | break 42 | case 1008: 43 | message = 'no encryption key provided' 44 | break 45 | case 1010: 46 | message = 'license generation failed' 47 | break 48 | case 1012: 49 | message = 'encryption error' 50 | break 51 | case 1014: 52 | message = 'decryption error' 53 | break 54 | default: 55 | message = 'no idea' 56 | } 57 | errorObject.message = message 58 | return errorObject 59 | } 60 | -------------------------------------------------------------------------------- /lib/encrypt-decrypt.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // 3 | const errors = require('./errors') 4 | // 5 | let encryptString = (str, privKey = '1230A6701B12cc39') => { 6 | // 7 | if (!str) throw (errors('ENCRYPT_ERROR')) 8 | if (privKey === '') throw (errors('ENCRYPT_ERROR')) 9 | // 10 | const alfaKeys = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 11 | const alfaArray = alfaKeys.split('') 12 | let encryptedString = '' 13 | let z = 0 14 | // 15 | str.split('').forEach((theChar) => { 16 | // 17 | const pos1 = alfaArray.indexOf(theChar) + 1 18 | const theStr = privKey.charAt(z) 19 | const pos2 = alfaArray.indexOf(theStr) + 1 20 | const pos3 = ((pos1 + pos2) % (alfaKeys.length)) - 1 21 | // 22 | if (pos1 > -1 && pos2 > -1 && pos3 > -1) encryptedString += alfaKeys.charAt(pos3) 23 | z++ 24 | // 25 | }) 26 | return encryptedString 27 | } 28 | 29 | let decryptString = (str, privKey = '1230A6701B12cc39') => { 30 | // 31 | if (!str) throw errors('DECRYPT_ERROR') 32 | const alfaKeys = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 33 | const alfaArray = alfaKeys.split('') 34 | let decryptedString = '' 35 | let z = 0 36 | // 37 | str.split('').forEach((theChar) => { 38 | // 39 | const pos1 = alfaArray.indexOf(theChar) + 1 40 | const theStr = privKey.charAt(z) 41 | const pos2 = alfaArray.indexOf(theStr) + 1 42 | const pos3 = ((alfaKeys.length + pos1 - pos2) % (alfaKeys.length)) - 1 43 | // 44 | if (pos1 > -1 && pos2 > -1 && pos3 > -1) decryptedString += alfaKeys.charAt(pos3) 45 | z++ 46 | // 47 | }) 48 | return decryptedString 49 | } 50 | // 51 | module.exports = { encryptString, decryptString } 52 | -------------------------------------------------------------------------------- /lib/supported.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // 3 | module.exports = { 4 | WIN: {os: 'Windows', version: '1.0', type: 'desktop'}, 5 | WIN7: {os: 'Windows 7', version: '7.0', type: 'desktop'}, 6 | WIN8: {os: 'Windows 8', version: '8.0', type: 'desktop'}, 7 | WIN10: {os: 'Windows 10', version: '10.0', type: 'desktop'}, 8 | OSX: {os: 'Macintosh', version: '1.0', type: 'desktop'}, 9 | OSX1: {os: 'Cheetah/Puma', version: '1.0', type: 'desktop'}, 10 | OSX2: {os: 'Jaguar', version: '2.0', type: 'desktop'}, 11 | OSX3: {os: 'Panther', version: '3.0', type: 'desktop'}, 12 | OSX4: {os: 'Tiger', version: '4.0', type: 'desktop'}, 13 | OSX5: {os: 'Leopard', version: '5.0', type: 'desktop'}, 14 | OSX6: {os: 'Snow Leopard', version: '6.0', type: 'desktop'}, 15 | OSX7: {os: 'Lion', version: '7.0', type: 'desktop'}, 16 | OSX8: {os: 'Mountain Lion', version: '8.0', type: 'desktop'}, 17 | OSX9: {os: 'Mavericks', version: '9.0', type: 'desktop'}, 18 | OSX10: {os: 'Yosemite', version: '10.0', type: 'desktop'}, 19 | OSX11: {os: 'El Capitan', version: '11.0', type: 'desktop'}, 20 | OSX12: {os: 'Sierra', version: '12.0', type: 'desktop'}, 21 | IOS: {os: 'ios', version: '1.0', type: 'mobile'}, 22 | IOS5: {os: 'ios-5', version: '5.0', type: 'mobile'}, 23 | IOS6: {os: 'ios-6', version: '6.0', type: 'mobile'}, 24 | IOS7: {os: 'ios-7', version: '7.0', type: 'mobile'}, 25 | IOS8: {os: 'ios-8', version: '8.0', type: 'mobile'}, 26 | IOS9: {os: 'ios-9', version: '9.0', type: 'mobile'}, 27 | IOS10: {os: 'ios-10', version: '10.0', type: 'mobile'}, 28 | ANDROID: {os: 'Android', version: '1.0', type: 'mobile'}, 29 | ANDROID2: {os: 'Gingerbread', version: '2.0', type: 'mobile'}, 30 | ANDROID3: {os: 'Honeycomb', version: '3.0', type: 'mobile'}, 31 | ANDROID4: {os: 'Ice Cream Sandwich', version: '4.0', type: 'mobile'}, 32 | ANDROID43: {os: 'Jelly Bean', version: '4.3', type: 'mobile'}, 33 | ANDROID44: {os: 'KitKat', version: '4.4', type: 'mobile'}, 34 | ANDROID5: {os: 'Lollipop', version: '5.0', type: 'mobile'}, 35 | ANDROID6: {os: 'Marshmallow', version: '6.0', type: 'mobile'}, 36 | ANDROID7: {os: 'Nougat', version: '7.0', type: 'mobile'}, 37 | OTHER: {os: 'unknown mobile os', version: '1.0', type: 'unknown'} 38 | } 39 | -------------------------------------------------------------------------------- /lib/License.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // 3 | const md5 = require('md5') 4 | // 5 | const crypt = require('./encrypt-decrypt') 6 | const errors = require('./errors') 7 | const os = require('./supported') 8 | // 9 | module.exports = class License { 10 | // 11 | constructor ({ info, prodCode, appVersion = '1.0', osType } = {}) { 12 | // 13 | if (!info || typeof info !== 'object') throw errors('WINFO_MISSING') 14 | if (!prodCode) throw errors('WPRODCODE_MISSING') 15 | // setters 16 | this._info = info 17 | this._prodCode = prodCode 18 | this._appVersion = appVersion 19 | this._osType = os[osType] 20 | this.id 21 | this.serial 22 | this.updateSerial() 23 | } 24 | // setters 25 | set info (info) { 26 | if (info) { 27 | this._info = info 28 | updateSerial() 29 | } 30 | } 31 | // 32 | set prodCode (prodCode) { 33 | if (prodCode) { 34 | this._prodCode = prodCode 35 | updateSerial() 36 | } 37 | } 38 | set appVersion (appVersion) { 39 | if (appVersion) { 40 | this._appVersion = appVersion 41 | updateSerial() 42 | } 43 | } 44 | set osType (osType) { 45 | if (osType) { 46 | this._osType = osType 47 | updateSerial() 48 | } 49 | } 50 | // 51 | updateSerial () { 52 | this.id = generateHash(this._info, this._prodCode, this._appVersion, this._osType) 53 | this.serial = createSerial(this.id, this._info) 54 | } 55 | // 56 | getSerial () { 57 | return this.serial 58 | } 59 | } 60 | 61 | let createSerial = (id) => { 62 | return generateSerial(id) 63 | } 64 | 65 | let generateHash = (info, prodCode, appVersion, osType) => { 66 | // 67 | let userInfo = [] 68 | // 69 | Object.keys(info).forEach((key) => { 70 | const val = info[key] 71 | userInfo.push(val) 72 | }) 73 | // 74 | let str = userInfo.join() 75 | const reg = new RegExp('[^0-9a-zA-Z]+', 'g') 76 | info = str.replace(reg, '') 77 | // 78 | const infoClean = info.toUpperCase() 79 | // 80 | const regVr = new RegExp('\\.+', 'g') 81 | const appVr = appVersion.replace(regVr, '') 82 | // 83 | const uniqueOSID = generateOSHash(osType) 84 | // 85 | const userInfoStr = infoClean + prodCode + appVr + uniqueOSID 86 | return (md5(userInfoStr)).toUpperCase() 87 | } 88 | 89 | let generateSerial = (id) => { 90 | var regKey = crypt.encryptString(id).toString() 91 | return chunkString(regKey, 5) 92 | } 93 | 94 | let chunkString = (str, length) => { 95 | const regEx = new RegExp('.{1,' + length + '}', 'g') 96 | let newStr = str.match(regEx) 97 | // trim extra 98 | if (newStr.length > 6) newStr.pop() 99 | return newStr.join('-').toUpperCase() 100 | } 101 | 102 | let generateOSHash = (osType) => { 103 | var osHash = '' 104 | if (osType) { 105 | var strObj = osType.os + osType.type + osType.version 106 | osHash = strObj.replace('.', '').replace('-', '').toUpperCase() 107 | } 108 | return osHash 109 | } 110 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Nodejs-License-Key v1.0.1 2 | 3 | This project is forked from the NPM module [LicenseKey](https://www.npmjs.com/package/licensekey). 4 | 5 | ## Docs 6 | 7 | Generate a License Key and validate the license. This is typically used for software licensing (serial number). 8 | 9 | ## Installation 10 | ``` 11 | npm install nodejs-license-key 12 | ``` 13 | 14 | ## Data Structure 15 | To create a license key - Enter the users information that your are able to recieve. 16 | 17 | This object can be any data you wish to tie the license to - format Object 18 | ``` 19 | var userInfo = { 20 | company: 'www.funwoo.com', 21 | street: 'Taipei 101', 22 | city: 'Taipei', 23 | state: 'Taiwan', 24 | zip: '100' 25 | }; 26 | ``` 27 | Must include: 28 | 1) prodCode (string) - product abbr name, can be any size 29 | 2) appVersion (string) - optional if you want to tie the license to a version number 30 | 3) osType (string) - lock the license to a specific operating system, supported: 31 | * Windows: WIN, WIN7, WIN8,WIN10 32 | * Macintosh: OSX, OSX1, OSX2, OSX3, OSX4, OSX5, OSX6, OSX7, OSX8, OSX9, OSX10, OSX11, OSX12 33 | * Apple Mobile: IOS, IOS5, IOS6, IOS7, IOS8, IOS9,IOS10 34 | * Google Mobile: ANDROID, ANDROID2, ANDROID3, ANDROID4, ANDROID43, ANDROID44, ANDROID5, ANDROID6, ANDROID7 35 | OTHER 36 | 37 | ``` 38 | var userLicense = { 39 | info: userInfo, 40 | prodCode: 'MyProject', 41 | appVersion: '1.5', 42 | osType: 'WIN' 43 | }; 44 | ``` 45 | 46 | ## Init 47 | ``` 48 | var licenseKey = require('licensekey'); 49 | ``` 50 | 51 | ## Create a License Key 52 | Then run the following code to recieve the License for the client 53 | This function to be run ONLY for you to generate the license code for the client 54 | ``` 55 | var licenseKey = require('licensekey'); 56 | 57 | var userLicense = { 58 | info: userInfo, 59 | prodCode: 'LEN100120', 60 | appVersion: '1.5', 61 | osType: 'IOS8' 62 | }; 63 | 64 | try{ 65 | var license = licenseKey.createLicense(userLicense) 66 | console.log(license); 67 | }catch(err){ 68 | console.log(err); 69 | } 70 | ``` 71 | 72 | if success returns 73 | ``` 74 | { errorCode: 0, message: 'ok', license: 'WTYSA-XZ31V-7ZYV6-21A22-3E53F-D675B' } 75 | ``` 76 | 77 | if error, returns 78 | ``` 79 | { errorCode: 1002, message: 'product code missing' } 80 | ``` 81 | 82 | ## Validate a License Key 83 | On client side your application will pass the user information (Data Structure) and License Key: 84 | ``` 85 | var licenseKey = require('licensekey'); 86 | 87 | var userLicense = { 88 | info: userInfo, 89 | prodCode: 'LEN100120', 90 | appVersion: '1.5', 91 | osType: 'IOS8' 92 | }; 93 | 94 | try{ 95 | var license = licensekey.validateLicense(userLicense, 'WTYSA-XZ31V-7ZYV6-21A22-3E53F-D675B'); 96 | console.log(license); 97 | }catch(err){ 98 | console.log(err); 99 | } 100 | ``` 101 | if success returns 102 | ``` 103 | { errorCode: 0, message: 'ok' } 104 | ``` 105 | 106 | if error, returns 107 | ``` 108 | { errorCode: 1006, message: 'license not valid' } 109 | ``` 110 | 111 | ## Support 112 | Tested in Chrome 53-54, Firefox 48-49, IE 11, Edge 14, Safari 9-10, Node.js 6-7, & PhantomJS 2.1.1.
113 | Automated test runs are available. 114 | 115 | 116 | --------------------------------------------------------------------------------