├── test └── index.js ├── .gitignore ├── package.json ├── LICENSE ├── index.js ├── README.md └── lib └── hex_hmac_sha1.js /test/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aliyun-iot-mqtt", 3 | "version": "0.0.1", 4 | "description": "阿里云IoT物联网套件客户端", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "nyc mocha", 8 | "coverage": "nyc report --reporter=html", 9 | "coveralls": "nyc report --reporter=text-lcov | coveralls" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/xihu-fm/aliyun-iot-client-sdk.git" 14 | }, 15 | "keywords": [ 16 | "aliyun", 17 | "IoT", 18 | "aliyun-iot-mqtt", 19 | "iot-hub" 20 | ], 21 | "author": "wongxming", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/xihu-fm/aliyun-iot-client-sdk/issues" 25 | }, 26 | "engines": { 27 | "node": ">= 7.6" 28 | }, 29 | "readmeFilename": "README.md", 30 | "dependencies": { 31 | "mqtt": "^2.14.0", 32 | "uuid": "^3.1.0" 33 | }, 34 | "devDependencies": { 35 | "mocha": "^4.0.1", 36 | "nyc": "^11.3.0", 37 | "coveralls": "^3.0.0", 38 | "chai": "^4.1.2" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 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 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const crypto = require('./lib/hex_hmac_sha1'); 4 | const mqtt = require('mqtt'); 5 | /** 6 | * options 7 | productKey 8 | deviceName 9 | deviceSecret 10 | */ 11 | exports.getAliyunIotMqttClient = function(opts) { 12 | 13 | if (!opts || !opts.productKey || 14 | !opts.deviceName || !opts.deviceSecret) { 15 | throw new Error('options need productKey,deviceName,deviceSecret'); 16 | } 17 | 18 | if (opts.protocol === 'mqtts' && !opts.ca) { 19 | throw new Error('mqtts need ca '); 20 | } 21 | if (!opts.host && !opts.regionId) { 22 | throw new Error('options need host or regionId (aliyun regionId)'); 23 | } 24 | 25 | const deviceSecret = opts.deviceSecret; 26 | delete opts.deviceSecret; 27 | 28 | let secureMode = (opts.protocol === 'mqtts') ? 2 : 3; 29 | 30 | var options = { 31 | productKey: opts.productKey, 32 | deviceName: opts.deviceName, 33 | timestamp: Date.now(), 34 | clientId: Math.random().toString(36).substr(2) 35 | } 36 | let keys = Object.keys(options).sort(); 37 | // 按字典序排序 38 | keys = keys.sort(); 39 | const list = []; 40 | keys.map((key) => { 41 | list.push(`${key}${options[key]}`); 42 | }); 43 | const contentStr = list.join(''); 44 | 45 | opts.password = crypto.hex_hmac_sha1(deviceSecret, contentStr); 46 | opts.clientId = `${options.clientId}|securemode=${secureMode},signmethod=hmacsha1,timestamp=${options.timestamp}|`; 47 | opts.username = `${options.deviceName}&${options.productKey}`; 48 | 49 | opts.port = opts.port || 1883; 50 | opts.host = opts.host || `${opts.productKey}.iot-as-mqtt.${opts.regionId}.aliyuncs.com`; 51 | opts.protocol = opts.protocol || 'mqtt'; 52 | 53 | return mqtt.connect(opts); 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## aliyun-iot-mqtt 2 | 3 | [![npm-version](https://img.shields.io/npm/v/aliyun-iot-mqtt.svg)](https://npmjs.org/package/aliyun-iot-mqtt) 4 | [![travis-ci](https://travis-ci.org/xihu-fm/aliyun-iot-mqtt.svg?branch=master)](https://travis-ci.org/xihu-fm/aliyun-iot-mqtt) 5 | [![coverage](https://coveralls.io/repos/github/xihu-fm/aliyun-iot-mqtt/badge.svg?branch=master)](https://coveralls.io/github/xihu-fm/aliyun-iot-mqtt?branch=master) 6 | [![npm-download](https://img.shields.io/npm/dm/aliyun-iot-mqtt.svg)](https://npmjs.org/package/aliyun-iot-mqtt) 7 | 8 | [Aliyun IoT Hub](https://www.aliyun.com/product/iot) MQTT client for Node.js 9 | 10 | 11 | ## Installation 12 | 13 | You can install it as dependency with npm. 14 | 15 | ```sh 16 | $ # save into package.json dependencies with -S 17 | $ npm install aliyun-iot-mqtt -S 18 | ``` 19 | 20 | ## Usage 21 | 22 | Aliyun IoT Hub mqtt client with authrozied by productKey & deviceName & deviceSecret. 23 | 24 | 25 | ### GET Data 26 | 27 | ```js 28 | const Mqtt = require('aliyun-iot-mqtt'); 29 | 30 | const client = Mqtt.getAliyunIotMqttClient({ 31 | productKey: "", 32 | deviceName: "", 33 | deviceSecret: "", 34 | regionId: "cn-shanghai", 35 | 36 | keepalive:120 // mqtt options 37 | }); 38 | 39 | 40 | client.on('connect', function() { 41 | console.log("connect") 42 | }) 43 | 44 | client.end(function (){ 45 | console.log("end") 46 | }) 47 | 48 | ``` 49 | 50 | ### TLS mqtts 51 | [aliyun_iot_root.cer](http://aliyun-iot.oss-cn-hangzhou.aliyuncs.com/cert_pub/root.crt) 52 | 53 | ```js 54 | var trustedCA = fs.readFileSync(path.join(__dirname, '/aliyun_iot_root.cer')) 55 | 56 | var options = { 57 | productKey: "", 58 | deviceName: "", 59 | deviceSecret: "", 60 | regionId: "cn-shanghai", 61 | protocol: 'mqtts', 62 | ca: trustedCA, 63 | 64 | keepalive:120 // mqtt options 65 | }; 66 | 67 | ``` 68 | 69 | ### Subscribe Topic 70 | 71 | ```js 72 | client.subscribe(topic) 73 | 74 | ``` 75 | ### Publish Message 76 | 77 | ```js 78 | client.publish(topic, 'Hello mqtt') 79 | client.publish(topic, 'Hello mqtt', { qos: 1 }) 80 | 81 | ``` 82 | 83 | ### Receive Message 84 | 85 | ```js 86 | client.on('message', function(topic, message) { 87 | console.log(topic+"," + message.toString()) 88 | }) 89 | 90 | ``` 91 | -------------------------------------------------------------------------------- /lib/hex_hmac_sha1.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined 3 | * in FIPS PUB 180-1 4 | * Version 2.1a Copyright Paul Johnston 2000 - 2002. 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for details. 8 | */ 9 | 10 | /* 11 | * Configurable variables. You may need to tweak these to be compatible with 12 | * the server-side, but the defaults work in most cases. 13 | */ 14 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ 15 | /* 16 | * These are the functions you'll usually want to call 17 | * They take string arguments and return either hex or base-64 encoded strings 18 | */ 19 | exports.hex_hmac_sha1 = function (key, data){ return binb2hex(core_hmac_sha1(key, data));} 20 | 21 | /* 22 | * Calculate the SHA-1 of an array of big-endian words, and a bit length 23 | */ 24 | function core_sha1(x, len) 25 | { 26 | /* append padding */ 27 | x[len >> 5] |= 0x80 << (24 - len % 32); 28 | x[((len + 64 >> 9) << 4) + 15] = len; 29 | 30 | var w = Array(80); 31 | var a = 1732584193; 32 | var b = -271733879; 33 | var c = -1732584194; 34 | var d = 271733878; 35 | var e = -1009589776; 36 | 37 | for(var i = 0; i < x.length; i += 16) 38 | { 39 | var olda = a; 40 | var oldb = b; 41 | var oldc = c; 42 | var oldd = d; 43 | var olde = e; 44 | 45 | for(var j = 0; j < 80; j++) 46 | { 47 | if(j < 16) w[j] = x[i + j]; 48 | else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); 49 | var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), 50 | safe_add(safe_add(e, w[j]), sha1_kt(j))); 51 | e = d; 52 | d = c; 53 | c = rol(b, 30); 54 | b = a; 55 | a = t; 56 | } 57 | 58 | a = safe_add(a, olda); 59 | b = safe_add(b, oldb); 60 | c = safe_add(c, oldc); 61 | d = safe_add(d, oldd); 62 | e = safe_add(e, olde); 63 | } 64 | return Array(a, b, c, d, e); 65 | 66 | } 67 | 68 | /* 69 | * Perform the appropriate triplet combination function for the current 70 | * iteration 71 | */ 72 | function sha1_ft(t, b, c, d) 73 | { 74 | if(t < 20) return (b & c) | ((~b) & d); 75 | if(t < 40) return b ^ c ^ d; 76 | if(t < 60) return (b & c) | (b & d) | (c & d); 77 | return b ^ c ^ d; 78 | } 79 | 80 | /* 81 | * Determine the appropriate additive constant for the current iteration 82 | */ 83 | function sha1_kt(t) 84 | { 85 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : 86 | (t < 60) ? -1894007588 : -899497514; 87 | } 88 | 89 | /* 90 | * Calculate the HMAC-SHA1 of a key and some data 91 | */ 92 | function core_hmac_sha1(key, data) 93 | { 94 | var bkey = str2binb(key); 95 | if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); 96 | 97 | var ipad = Array(16), opad = Array(16); 98 | for(var i = 0; i < 16; i++) 99 | { 100 | ipad[i] = bkey[i] ^ 0x36363636; 101 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 102 | } 103 | 104 | var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); 105 | return core_sha1(opad.concat(hash), 512 + 160); 106 | } 107 | 108 | /* 109 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 110 | * to work around bugs in some JS interpreters. 111 | */ 112 | function safe_add(x, y) 113 | { 114 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 115 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 116 | return (msw << 16) | (lsw & 0xFFFF); 117 | } 118 | 119 | /* 120 | * Bitwise rotate a 32-bit number to the left. 121 | */ 122 | function rol(num, cnt) 123 | { 124 | return (num << cnt) | (num >>> (32 - cnt)); 125 | } 126 | 127 | /* 128 | * Convert an 8-bit or 16-bit string to an array of big-endian words 129 | * In 8-bit function, characters >255 have their hi-byte silently ignored. 130 | */ 131 | function str2binb(str) 132 | { 133 | var bin = Array(); 134 | var mask = (1 << chrsz) - 1; 135 | for(var i = 0; i < str.length * chrsz; i += chrsz) 136 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); 137 | return bin; 138 | } 139 | 140 | /* 141 | * Convert an array of big-endian words to a hex string. 142 | */ 143 | function binb2hex(binarray) 144 | { 145 | var hex_tab = "0123456789ABCDEF"; 146 | var str = ""; 147 | for(var i = 0; i < binarray.length * 4; i++) 148 | { 149 | str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + 150 | hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); 151 | } 152 | return str; 153 | } --------------------------------------------------------------------------------