From f7172c75872c0f77ffb893d64ee1281d7f212e80 Mon Sep 17 00:00:00 2001 From: Rob Griffiths Date: Mon, 13 Jan 2025 20:26:23 +0000 Subject: [PATCH] 1.0.16 (#94) * version changes * update node version requirement * Bump axios from 0.21.4 to 0.28.0 Bumps [axios](https://github.com/axios/axios) from 0.21.4 to 0.28.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v0.28.0/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.21.4...v0.28.0) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] * mosquitto example dockerfile * use fixed engine range, remove unused deps * removed old directories from .gitignore * updated node version * add vscode workspace settings * updated dockerfile example * coding style * information about CVE-2022-32214 resolution in node >21 that affects parsing device responses * update packages and engines * update to new versions * 1.0.16 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/npm-publish.yml | 27 +- .github/workflows/stale.yml | 3 + .gitignore | 8 +- .npmignore | 4 - .prettierrc | 4 +- .vscode/settings.json | 4 + Dockerfile | 16 + README.md | 3 +- VERSION | 1 - certs/ca.crt | 23 - certs/server.crt | 21 - lib/api.js | 767 ++++++++++++++++-------------- mosquitto/basic.conf | 12 +- package-lock.json | 306 +++--------- package.json | 11 +- 15 files changed, 524 insertions(+), 686 deletions(-) create mode 100644 .github/workflows/stale.yml create mode 100644 .vscode/settings.json create mode 100644 Dockerfile delete mode 100644 VERSION delete mode 100644 certs/ca.crt delete mode 100644 certs/server.crt diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 648cd6b..e7ff733 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -1,34 +1,25 @@ # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages -name: Node.js Package +name: Publish Package to npmjs on: release: - types: [created] - workflow_dispatch: + types: [published] + branches: + - main jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: '20.x' + registry-url: https://registry.npmjs.org - run: npm ci - run: npm test - - publish-npm: - needs: build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - registry-url: https://registry.npmjs.org/ - - run: npm ci - - run: npm publish + - run: npm publish --access public env: NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..c912f97 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,3 @@ +- name: Close Stale Issues + uses: actions/stale@v9.0.0 + \ No newline at end of file diff --git a/.gitignore b/.gitignore index ccce27f..c7f6c7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -bin/src/node_modules -cmd/ -dumps/ -old_certs/ +# directories +node_modules/ + +#files \ No newline at end of file diff --git a/.npmignore b/.npmignore index 344ca8f..82e6f7c 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,2 @@ -certs/ -cmd/ -dumps/ mosquito/ -old_certs/ teardown/ diff --git a/.prettierrc b/.prettierrc index 4dc8b16..9571dda 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,5 +3,7 @@ "useTabs": false, "semi": true, "arrowParens": "always", - "singleQuote": true + "singleQuote": true, + "trailingComma": "all", + "printWidth": 80 } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..10af2e8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.tabSize": 2, + "editor.defaultFormatter": "esbenp.prettier-vscode" +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a1209fd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM eclipse-mosquitto:1.6.15-openssl + +COPY mosquitto/basic.conf ./mosquitto/config/mosquitto.conf +RUN apk add --update --no-cache openssl && \ + mkdir /mosquitto/config/certs && \ + cd /mosquitto/config/certs && \ + openssl genrsa -out ca.key 2048 && \ + openssl req -x509 -new -nodes -key ca.key -days 3650 -out ca.crt -subj '/CN=My Root' && \ + openssl req -new -nodes -out server.csr -newkey rsa:2048 -keyout server.key -subj '/CN=Mosquitto' && \ + openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650 && \ + c_rehash . && \ + chown -R mosquitto:mosquitto /mosquitto && \ + chmod 600 /mosquitto/config/certs/* + +EXPOSE 1883 +EXPOSE 8883 \ No newline at end of file diff --git a/README.md b/README.md index ab340b9..0a4121e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ Tools to help configure the Meross devices for purpose of utilising our =18 +For Node.js >=21 you need to prepend commands with `NODE_OPTIONS='--insecure-http-parser'`. This is because the responses from some (if not all) versions of the Meross firmware incorrectly terminate headers with LF instead of CRLF. [CVE-2022-32214](https://nvd.nist.gov/vuln/detail/CVE-2022-32214) ## Home Assistant diff --git a/VERSION b/VERSION deleted file mode 100644 index 492b167..0000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.0.12 \ No newline at end of file diff --git a/certs/ca.crt b/certs/ca.crt deleted file mode 100644 index ffec438..0000000 --- a/certs/ca.crt +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIUPH3VrxuvmxuP1sgIWlqi9dGMSuQwDQYJKoZIhvcNAQEL -BQAwcjELMAkGA1UEBhMCVUsxEzARBgNVBAgMCkdsb3VjZXN0ZXIxEzARBgNVBAcM -Ckdsb3VjZXN0ZXIxCzAJBgNVBAoMAkNBMQswCQYDVQQLDAJDQTEfMB0GA1UEAwwW -Um9icy1NYWNCb29rLVByby5sb2NhbDAeFw0yMDEwMDkxNTE2MDNaFw0yNTEwMDkx -NTE2MDNaMHIxCzAJBgNVBAYTAlVLMRMwEQYDVQQIDApHbG91Y2VzdGVyMRMwEQYD -VQQHDApHbG91Y2VzdGVyMQswCQYDVQQKDAJDQTELMAkGA1UECwwCQ0ExHzAdBgNV -BAMMFlJvYnMtTWFjQm9vay1Qcm8ubG9jYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDH/V1EuumONBJtXzsqsrfZ0cyHfXl2GrdmBszvw6ehBIQITegD -R8C8h1U1igjeyzdckTQsAw+BwVu9mwpUXI3xmYhFDgnxM5FkUvBkPMvTLEBT4nFR -YbWDOniW0C8TWNpxjD7qPm7OhMlL8nWjtn3xNt6vVvvgWLBo9d3W37fcQYALmf9n -K5mhx+8UUtBUU/mMjKjHGCkidzZQVnkaFyLSL7P0eAZOySxmQ8LgT6+cwkF/neIA -oyLCVeQQfB7e5Bw26uAMfOCPXubS8d8bjW+CPtCCWT9l5F5I7Ris7nVm1Oj+gO/a -/Ob2HlpaNygbacLPHjYQRcKnYvL3EIGplJCNAgMBAAGjUzBRMB0GA1UdDgQWBBTl -zbEWkyopzNw84h3nw6AgCgbN6TAfBgNVHSMEGDAWgBTlzbEWkyopzNw84h3nw6Ag -CgbN6TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBpZ5laeRqz -uMHiLJhp/4IXwi+qkbFFk2TC18Yx3NMwvnGA7WMMb74130XL9X/6+PO4XdMP3VAn -D+lxTJV6V4Iyq84URaH0+pwj1FAfBjwaYJ8YszAFeWcMCEbtNSxEOk1cvZSWwf1A -5I0/FEsjYoOKBFq11lbWqY8+ukfFihAMBcjFebcKH6J42Zu0x0CmPwOSQ0/dwJUj -tVSa2GUlPr9TJ78mRUeEXKQf+f+MUpSTJpg5DzoL2gMJMpJkMQzTsLlMGYAo9gYy -tvpfIcGHidepGaSowddm7F7A6c8n2ZadyE8edxv30mY9XVCM5SXC44HcOl4cQ8oB -3Q0OVM0oGLa7 ------END CERTIFICATE----- diff --git a/certs/server.crt b/certs/server.crt deleted file mode 100644 index 179b278..0000000 --- a/certs/server.crt +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDeDCCAmACFCaTPe44FcR397h+CxtRrqlGU+YOMA0GCSqGSIb3DQEBCwUAMHIx -CzAJBgNVBAYTAlVLMRMwEQYDVQQIDApHbG91Y2VzdGVyMRMwEQYDVQQHDApHbG91 -Y2VzdGVyMQswCQYDVQQKDAJDQTELMAkGA1UECwwCQ0ExHzAdBgNVBAMMFlJvYnMt -TWFjQm9vay1Qcm8ubG9jYWwwHhcNMjAxMDA5MTUxNzEyWhcNMjExMDA0MTUxNzEy -WjB/MQswCQYDVQQGEwJVSzEYMBYGA1UECAwPR2xvdWNlc3RlcnNoaXJlMRMwEQYD -VQQHDApHbG91Y2VzdGVyMQ8wDQYDVQQKDAZTZXJ2ZXIxDzANBgNVBAsMBlNlcnZl -cjEfMB0GA1UEAwwWUm9icy1NYWNCb29rLVByby5sb2NhbDCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBANATy1RzkNjmsWh9x3S8HfiqSc63pYWvrkPJyX8W -goj8YnaA066Eht30zmTDZ/13YhFweqxV2Oi1gbfRRTHMVUmdRuz5ToekDGBpSUiO -dwj4kQKp/RrezNir4lYzm7tA5yJ++TOBDlK0WaQHURu2jfz2tnBTim6LL8drv9Rm -xOgi0tzamqXaGIgHjQ26jH2Cf/u3ZbpPe+hVap2fdkj2M0ZUyU0jwS0CWDfNrntU -V2IaCeNOuV0VkSNYgagFlOjAPa3sHjbIevEGBtmRYHMjY8W50J7hzClcN2q6ZPWD -CJpE2efvqwarfE9I4GfkLRsIxUfbVVDkXnyYbs95yKlrC98CAwEAATANBgkqhkiG -9w0BAQsFAAOCAQEAqZ7Z58MI+847kZDsBQWWK9tKXOnBZFjuUqM/MbnKfy684GeZ -yX5RdZGa+qzcW781J+4XLhkcp/OSNzZn9R93jzxyv4/LsUCX9Ctk5gthcElRkA0h -lPfzbcW0X+JgOS6WQmHwIizmoKrPWfCnXRe3texTUS+OJul2RYNqLZVZ4qEkwiur -F5/j0xYtv9CkYwixMfgo3ZLRh76NwDsGz/9UFubSeB985lDNSIj8SxpaOHPVysjM -IP0WMyIDIVOPwlJ+miKkd1kMjDsOhB2zCBXKd7kuq0AkDSzJsE9XJneGVK419KZR -EIbn+AXfETN6t4/EtyRN6xUxbYmibSNT2Z3Vww== ------END CERTIFICATE----- diff --git a/lib/api.js b/lib/api.js index 67f52c7..b119828 100644 --- a/lib/api.js +++ b/lib/api.js @@ -1,422 +1,451 @@ -'use strict' +'use strict'; -if (typeof (URL) === 'undefined') { - var URL = class URL { - constructor(url) { - return require('url').parse(url) - } - } -} +const { URL } = require('url'); -const util = require('util') -const uuid4 = require('uuid4') -const md5 = require('md5') -const term = require('terminal-kit').terminal -const axios = require('axios') -const crypto = require('crypto') +const util = require('util'); +const uuid = require('uuid'); +const md5 = require('md5'); +const term = require('terminal-kit').terminal; +const axios = require('axios'); +const crypto = require('crypto'); -const axiosInstanace = axios.create(); -axiosInstanace.defaults.timeout = 10000; +const axiosInstance = axios.create(); +axiosInstance.defaults.timeout = 10000; const cleanServerUrl = (server) => { - server = /mqtts?:\/\//.test(server) ? server : 'mqtt://' + server // add protocol - server = /:(?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])/.test(server) ? server : (server + ':' + (server.indexOf('mqtts://') > -1 ? 8883 : 1883)) + server = /mqtts?:\/\//.test(server) ? server : 'mqtt://' + server; // add protocol + server = + /:(?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])/.test( + server, + ) + ? server + : server + ':' + (server.indexOf('mqtts://') > -1 ? 8883 : 1883); - return server -} + return server; +}; -const serverRegex = /((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])):(?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])$/ - -const base64Encode = str => Buffer.from(str).toString('base64') -const base64Decode = str => Buffer.from(str, 'base64').toString('utf8') +const base64Encode = (str) => Buffer.from(str).toString('base64'); +const base64Decode = (str) => Buffer.from(str, 'base64').toString('utf8'); const tableOptions = { - hasBorder: true, - borderChars: 'light', - contentHasMarkup: true, - fit: true, - width: 95, - firstColumnTextAttr: { color: 'yellow' } -} + hasBorder: true, + borderChars: 'light', + contentHasMarkup: true, + fit: true, + width: 95, + firstColumnTextAttr: { color: 'yellow' }, +}; -const percentToColor = percent => percent > .7 ? '^G' : (percent > .5 ? '^Y' : (percent > .30 ? '^y' : '^r')) +const percentToColor = (percent) => + percent > 0.7 ? '^G' : percent > 0.5 ? '^Y' : percent > 0.3 ? '^y' : '^r'; const bar = (percent, width) => { - const partials = ['▏', '▎', '▍', '▌', '▋', '▊', '▉'] - let ticks = percent * width - if (ticks < 0) { - ticks = 0 - } - let filled = Math.floor(ticks) - let open = bar.width - filled - 1 - return (percentToColor(percent) + '▉').repeat(filled) + partials[Math.floor((ticks - filled) * partials.length)] + ' '.repeat(open) -} + const partials = ['▏', '▎', '▍', '▌', '▋', '▊', '▉']; + let ticks = percent * width; + if (ticks < 0) { + ticks = 0; + } + let filled = Math.floor(ticks); + let open = bar.width - filled - 1; + return ( + (percentToColor(percent) + '▉').repeat(filled) + + partials[Math.floor((ticks - filled) * partials.length)] + + ' '.repeat(open) + ); +}; const filterUndefined = (obj) => { - for (const key in obj) { - if (undefined === obj[key]) { - delete obj[key] - } + for (const key in obj) { + if (undefined === obj[key]) { + delete obj[key]; } + } - return obj -} + return obj; +}; function logRequest(request) { - let url = new URL(request.url); - console.log(`> ${request.method.toUpperCase()} ${url.path}`) - console.log(`> Host: ${url.host}`) - - let headers = {} - headers = Object.assign(headers, request.headers.common); - headers = Object.assign(headers, request.headers[request.method]); - headers = Object.assign(headers, Object.fromEntries( - Object.entries(request.headers).filter( - ([header]) => !['common', 'delete', 'get', 'head', 'post', 'put', 'patch'].includes(header) - ) - )); + const url = new URL(request.url, 'http://unknown'); + const method = request.method ? request.method.toUpperCase() : 'GET'; + + console.log(`> ${method} ${url.path}`); + console.log(`> Host: ${url.host}`); + + if (request.headers) { + let headers = { + ...request.headers.common, + ...request.headers[method], + ...Object.fromEntries( + Object.entries(request?.headers).filter(([header]) => !['common', 'delete', 'get', 'head', 'post', 'put', 'patch'].includes(header) + )), + }; + for (let [header, value] of Object.entries(headers)) { - console.log(`> ${header}: ${value}`) + console.log(`> ${header}: ${value}`); } + } - console.log('>') - console.log(util.inspect(request.data, { showHidden: false, depth: null })) - console.log('') + console.log('>'); + console.log(util.inspect(request.data, { showHidden: false, depth: null })); + console.log(''); } function logResponse(response) { - console.log(`< ${response.status} ${response.statusText}`) - for (const [header, value] of Object.entries(response.headers)) { - console.log(`< ${header}: ${value}`) - } - console.log('<') - console.log(util.inspect(response.data, { showHidden: false, depth: null })) - console.log('') + console.log(`< ${response.status} ${response.statusText}`); + for (const [header, value] of Object.entries(response.headers)) { + console.log(`< ${header}: ${value}`); + } + console.log('<'); + console.log(util.inspect(response.data, { showHidden: false, depth: null })); + console.log(''); } function handleRequestError(error, verbose) { - if (verbose) { - if (error.code === 'ECONNRESET' || error.code === 'ECONNABORTED') { - let hint = ''; - if (error.config.url === 'http://10.10.10.1/config') { - hint = "\nAre you connected to the device's Access Point?"; - } - console.error('Error', 'Unable to connect to device' + hint); - process.exit(); - } else if (error.response) { - logResponse(error.response) - } else if (error.request) { - logRequest(error.request) - } else { - console.error('Error', error.message); - } + if (error.code === 'HPE_CR_EXPECTED') { + console.error(`Please append NODE_OPTIONS='--insecure-parser' to your command.`); + process.exit(1); + } + + if (error.code === 'ECONNRESET' || error.code === 'ECONNABORTED') { + let hint = ''; + if (error.config.url === 'http://10.10.10.1/config') { + hint = "\nAre you connected to the device's Access Point?"; + } + console.error('Error', 'Unable to connect to device' + hint); + process.exit(1); + } + + if (verbose) { + if (error.response) { + logResponse(error.response); + } else if (error.request) { + logRequest(error.request); } else { - console.error('Error', 'Unable to connect to device'); + console.error('Error', error.message); } + } else { + console.error('Error', 'Unable to connect to device'); + } } module.exports = class API { - constructor(host, key, userId, verbose = false) { - this.host = host - this.key = key - this.userId = userId - this.verbose = verbose - - axiosInstanace.interceptors.request.use(request => { - if (verbose) { - logRequest(request) - } - return request - }) - - axiosInstanace.interceptors.response.use(response => { - if (verbose) { - logResponse(response) - } - return response - }) + constructor(host, key, userId, verbose = false) { + this.host = host; + this.key = key; + this.userId = userId; + this.verbose = verbose; + + axiosInstance.interceptors.request.use((request) => { + if (verbose) { + logRequest(request); + } + return request; + }); + + axiosInstance.interceptors.response.use((response) => { + if (verbose) { + logResponse(response); + } + return response; + }); + } + + signPacket(packet) { + const messageId = md5(uuid.v4()); + const timestamp = Math.floor(Date.now() / 1000); + const signature = md5(messageId + this.key + timestamp); + + packet.header.messageId = messageId; + packet.header.timestamp = timestamp; + packet.header.sign = signature; + + return packet; + } + + async deviceInformation() { + const data = await this.deviceInformationData(); + + const system = data.system; + const digest = data.digest; + const hw = system.hardware; + const fw = system.firmware; + + let rows = [ + [ + 'Device', + `${hw.type} ${hw.subType} ${hw.chipType} (hardware:${hw.version} firmware:${fw.version})`, + ], + ['UUID', hw.uuid], + ['Mac address', hw.macAddress], + ['IP address', fw.innerIp], + ]; + + if (fw.server) { + rows.push(['Current MQTT broker', `${fw.server}:${fw.port}`]); } - signPacket(packet) { - const messageId = md5(uuid4()) - const timestamp = Math.floor(Date.now() / 1000) - const signature = md5(messageId + this.key + timestamp) - - packet.header.messageId = messageId - packet.header.timestamp = timestamp - packet.header.sign = signature - - return packet - } - - async deviceInformation() { - const data = await this.deviceInformationData() - - const system = data.system - const digest = data.digest - const hw = system.hardware - const fw = system.firmware - - let rows = [ - ['Device', `${hw.type} ${hw.subType} ${hw.chipType} (hardware:${hw.version} firmware:${fw.version})`], - ['UUID', hw.uuid], - ['Mac address', hw.macAddress], - ['IP address', fw.innerIp], - ]; - - if (fw.server) { - rows.push( - ['Current MQTT broker', `${fw.server}:${fw.port}`] - ) + rows.push( + [ + 'Credentials', + `User: ^C${hw.macAddress}\nPassword: ^C${this.calculateDevicePassword( + hw.macAddress, + fw.userId, + )}`, + ], + [ + 'MQTT topics', + `Publishes to: ^C/appliance/${hw.uuid}/publish\nSubscribes to: ^C/appliance/${hw.uuid}/subscribe`, + ], + ); + + term.table(rows, tableOptions); + } + + async deviceInformationData() { + const packet = this.signPacket({ + header: { + from: '', + method: 'GET', + namespace: 'Appliance.System.All', + }, + payload: {}, + }); + + try { + const response = await axiosInstance.post( + `http://${this.host}/config`, + packet, + { + headers: { + 'Content-Type': 'application/json', + }, + }, + ); + + const data = response.data; + + if ('error' in data.payload) { + let { code, message } = data.payload.error; + + switch (code) { + case 5001: + console.error('Incorrect shared key provided.'); + break; } - rows.push( - ['Credentials', `User: ^C${hw.macAddress}\nPassword: ^C${this.calculateDevicePassword(hw.macAddress, fw.userId)}`], - ['MQTT topics', `Publishes to: ^C/appliance/${hw.uuid}/publish\nSubscribes to: ^C/appliance/${hw.uuid}/subscribe`] - ) + return; + } - term.table( - rows, - tableOptions - ) + return data.payload.all; + } catch (error) { + handleRequestError(error, this.verbose); } - - async deviceInformationData() { - const packet = this.signPacket({ - 'header': { - 'from': '', - 'method': 'GET', - 'namespace': 'Appliance.System.All' - }, - 'payload': {} - }) - - try { - const response = await axiosInstanace.post( - `http://${this.host}/config`, - packet, - { - headers: { - 'Content-Type': 'application/json' - }, - } - ) - - const data = response.data; - - if ('error' in data.payload) { - let { code, message } = data.payload.error; - - switch (code) { - case 5001: - console.error('Incorrect shared key provided.') - break; - } - - return - } - - return data.payload.all - } catch (error) { - handleRequestError(error, this.verbose) + } + + async deviceWifiList() { + const packet = this.signPacket({ + header: { + from: '', + method: 'GET', + namespace: 'Appliance.Config.WifiList', + }, + payload: {}, + }); + + try { + let spinner = await term.spinner({ + animation: 'dotSpinner', + rightPadding: ' ', + }); + term('Getting WIFI list…\n'); + + const response = await axiosInstance.post( + `http://${this.host}/config`, + packet, + { + headers: { + 'Content-Type': 'application/json', + }, + }, + ); + + spinner.animate(false); + + const data = response.data; + + if ('error' in data.payload) { + let { code, message } = data.payload.error; + + switch (code) { + case 5001: + console.error('Incorrect shared key provided.'); + break; } - } - async deviceWifiList() { - const packet = this.signPacket({ - 'header': { - 'from': '', - 'method': 'GET', - 'namespace': 'Appliance.Config.WifiList' - }, - 'payload': {} - }) - - try { - let spinner = await term.spinner({ animation: 'dotSpinner', rightPadding: ' ' }) - term('Getting WIFI list…\n') - - const response = await axiosInstanace.post( - `http://${this.host}/config`, - packet, - { - headers: { - 'Content-Type': 'application/json' - }, - } - ) - - - spinner.animate(false) - - const data = response.data; - - if ('error' in data.payload) { - let { code, message } = data.payload.error; - - switch (code) { - case 5001: - console.error('Incorrect shared key provided.') - break; - } - - return - } + return; + } - const wifiList = data.payload.wifiList + const wifiList = data.payload.wifiList; - let rows = [ - ['WIFI', 'Signal strength'], - ]; + let rows = [['WIFI', 'Signal strength']]; - for (const ap of wifiList) { - const decodedSsid = base64Decode(ap.ssid); - rows.push([ - `${decodedSsid ? decodedSsid : ''}\n^B${ap.bssid}^ ^+^YCh:^ ${ap.channel} ^+^YEncryption:^ ${ap.encryption} ^+^YCipher:^ ${ap.cipher}`, - bar((ap.signal / 100), 20) - ]) - } + for (const ap of wifiList) { + const decodedSsid = base64Decode(ap.ssid); + rows.push([ + `${decodedSsid ? decodedSsid : ''}\n^B${ap.bssid}^ ^+^YCh:^ ${ap.channel + } ^+^YEncryption:^ ${ap.encryption} ^+^YCipher:^ ${ap.cipher}`, + bar(ap.signal / 100, 20), + ]); + } - let thisTableOptions = tableOptions - thisTableOptions.firstColumnTextAttr = { color: 'cyan' } - thisTableOptions.firstRowTextAttr = { color: 'yellow' } + let thisTableOptions = tableOptions; + thisTableOptions.firstColumnTextAttr = { color: 'cyan' }; + thisTableOptions.firstRowTextAttr = { color: 'yellow' }; - term.table( - rows, - tableOptions - ) - } catch (error) { - handleRequestError(error, this.verbose) - } + term.table(rows, tableOptions); + } catch (error) { + handleRequestError(error, this.verbose); } - - async configureMqttServers(mqtt) { - const servers = mqtt.map((server) => { - server = cleanServerUrl(server) - - const url = new URL(server) - return { - host: url.hostname, - port: url.port + '' - } - }).slice(0, 2) - - // make sure we set a failover server - if (servers.length == 1) { - servers.push(servers[0]); - } - - let rows = []; - for (let s = 0; s < servers.length; s++) { - let server = servers[s]; - rows.push([ - `${s > 0 ? 'Failover' : 'Primary'} MQTT broker`, - `${server.host}:${server.port}` - ]) - } - - term.table(rows, tableOptions) - - const packet = this.signPacket({ - 'header': { - 'from': '', - 'method': 'SET', - 'namespace': 'Appliance.Config.Key' - }, - 'payload': { - 'key': { - 'userId': this.userId + '', - 'key': this.key + '', - 'gateway': ((servers) => { - const gateway = servers[0] - - if (servers.length > 1) { - gateway.secondHost = servers[1].host - gateway.secondPort = servers[1].port - } - - gateway.redirect = 1; - - return gateway - })(servers) - } - } - }) - - try { - const response = await axiosInstanace.post( - `http://${this.host}/config`, - packet, - { - headers: { - 'Content-Type': 'application/json' - }, - } - ) - } catch (error) { - handleRequestError(error, this.verbose) - } + } + + async configureMqttServers(mqtt) { + const servers = mqtt + .map((server) => { + server = cleanServerUrl(server); + + const url = new URL(server); + return { + host: url.hostname, + port: url.port + '', + }; + }) + .slice(0, 2); + + // make sure we set a failover server + if (servers.length == 1) { + servers.push(servers[0]); } - async configureWifiCredentials(credentials, useWifiX = null) { - const ssid = base64Encode(credentials.ssid) - const namespace = useWifiX ? 'Appliance.Config.WifiX' : 'Appliance.Config.Wifi' - const password = useWifiX ? await this.encryptPassword(credentials.password) : base64Encode(credentials.password) - - const packet = this.signPacket({ - 'header': { - 'from': '', - 'method': 'SET', - 'namespace': namespace - }, - 'payload': { - 'wifi': { - ...filterUndefined(credentials), - ssid, - password, - } - } - }) - - try { - const response = await axiosInstanace.post( - `http://${this.host}/config`, - packet, - { - headers: { - 'Content-Type': 'application/json' - }, - } - ) - } catch (error) { - handleRequestError(error, this.verbose) - } + let rows = []; + for (let s = 0; s < servers.length; s++) { + let server = servers[s]; + rows.push([ + `${s > 0 ? 'Failover' : 'Primary'} MQTT broker`, + `${server.host}:${server.port}`, + ]); } - async encryptPassword(password) { - const data = await this.deviceInformationData(); - - return this.calculateWifiXPassword(password, - data.system.hardware.type, - data.system.hardware.uuid, - data.system.hardware.macAddress) - } + term.table(rows, tableOptions); + + const packet = this.signPacket({ + header: { + from: '', + method: 'SET', + namespace: 'Appliance.Config.Key', + }, + payload: { + key: { + userId: this.userId + '', + key: this.key + '', + gateway: ((servers) => { + const gateway = servers[0]; + + if (servers.length > 1) { + gateway.secondHost = servers[1].host; + gateway.secondPort = servers[1].port; + } - calculateDevicePassword(macAddress, userId = 0) { - return `${userId}_${md5(macAddress + '' + this.key)}` + gateway.redirect = 1; + + return gateway; + })(servers), + }, + }, + }); + + try { + const response = await axiosInstance.post( + `http://${this.host}/config`, + packet, + { + headers: { + 'Content-Type': 'application/json', + }, + }, + ); + } catch (error) { + handleRequestError(error, this.verbose); } - - calculateWifiXPassword(password, type, uuid, macAddress) { - const key = Buffer.from(md5(type + uuid + macAddress).toString('hex'), 'utf8') - const iv = Buffer.from('0000000000000000', 'utf8') - const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); - - const count = Math.ceil(password.length / 16) * 16; - const padded = password.padEnd(count, '\0') - - let encrypted = cipher.update(padded, 'utf8', 'base64'); - encrypted += cipher.final('base64') - - return encrypted + } + + async configureWifiCredentials(credentials, useWifiX = null) { + const ssid = base64Encode(credentials.ssid); + const namespace = useWifiX + ? 'Appliance.Config.WifiX' + : 'Appliance.Config.Wifi'; + const password = useWifiX + ? await this.encryptPassword(credentials.password) + : base64Encode(credentials.password); + + const packet = this.signPacket({ + header: { + from: '', + method: 'SET', + namespace: namespace, + }, + payload: { + wifi: { + ...filterUndefined(credentials), + ssid, + password, + }, + }, + }); + + try { + const response = await axiosInstance.post( + `http://${this.host}/config`, + packet, + { + headers: { + 'Content-Type': 'application/json', + }, + }, + ); + } catch (error) { + handleRequestError(error, this.verbose); } -} + } + + async encryptPassword(password) { + const data = await this.deviceInformationData(); + + return this.calculateWifiXPassword( + password, + data.system.hardware.type, + data.system.hardware.uuid, + data.system.hardware.macAddress, + ); + } + + calculateDevicePassword(macAddress, userId = 0) { + return `${userId}_${md5(macAddress + '' + this.key)}`; + } + + calculateWifiXPassword(password, type, uuid, macAddress) { + const key = Buffer.from( + md5(type + uuid + macAddress).toString('hex'), + 'utf8', + ); + const iv = Buffer.from('0000000000000000', 'utf8'); + const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); + + const count = Math.ceil(password.length / 16) * 16; + const padded = password.padEnd(count, '\0'); + + let encrypted = cipher.update(padded, 'utf8', 'base64'); + encrypted += cipher.final('base64'); + + return encrypted; + } +}; diff --git a/mosquitto/basic.conf b/mosquitto/basic.conf index 19c4d30..f4dbc98 100644 --- a/mosquitto/basic.conf +++ b/mosquitto/basic.conf @@ -2,14 +2,14 @@ log_type all log_dest stdout use_username_as_clientid true -require_certificate false - -allow_anonymous true listener 8883 # replace with your CA Root -cafile ../certs/ca.crt +cafile /mosquitto/config/certs/ca.crt # replace with your server certificate and key paths -certfile ../certs/server.crt -keyfile ../certs/server.key +keyfile /mosquitto/config/certs/server.key +certfile /mosquitto/config/certs/server.crt + +allow_anonymous true +require_certificate false \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b1acc2d..4a54b93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,26 +1,25 @@ { "name": "meross", - "version": "1.0.12", + "version": "1.0.16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "meross", - "version": "1.0.12", + "version": "1.0.16", "license": "ISC", "dependencies": { - "axios": "^0.21.1", + "axios": "^1.7.9", "commander": "^7.2", - "got": "^13.0.0", "md5": "^2.2.1", "terminal-kit": "^3.0.1", - "uuid4": "^2.0.2" + "uuid": "^11.0.5" }, "bin": { "meross": "bin/meross" }, "engines": { - "node": ">=18.0.0" + "node": "^18.12 || ^20.9.0 || ^22.11" } }, "node_modules/@cronvel/get-pixels": { @@ -36,64 +35,19 @@ "pngjs": "^6.0.0" } }, - "node_modules/@sindresorhus/is": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", - "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", - "dependencies": { - "defer-to-connect": "^2.0.1" - }, - "engines": { - "node": ">=14.16" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", - "integrity": "sha512-V46MYLFp08Wf2mmaBhvgjStM3tPa+2GAdy/iqoX+noX1//zje2x4XmrIU0cAwyClATsTmahbtoQ2EwP7I5WSiA==" + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/cacheable-lookup": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", - "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", - "engines": { - "node": ">=14.16" - } - }, - "node_modules/cacheable-request": { - "version": "10.2.14", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", - "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", - "dependencies": { - "@types/http-cache-semantics": "^4.0.2", - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.3", - "mimic-response": "^4.0.0", - "normalize-url": "^8.0.0", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=14.16" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/charenc": { @@ -109,6 +63,17 @@ "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz", "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -133,49 +98,25 @@ "uniq": "^1.0.0" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "engines": { - "node": ">=10" + "node": ">=0.4.0" } }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -185,64 +126,17 @@ } } }, - "node_modules/form-data-encoder": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", - "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", - "engines": { - "node": ">= 14.17" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", - "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==", + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dependencies": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^10.2.8", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" - }, - "node_modules/http2-wrapper": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", - "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - }, - "engines": { - "node": ">=10.19.0" + "node": ">= 6" } }, "node_modules/iota-array": { @@ -260,19 +154,6 @@ "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==" }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dependencies": { - "json-buffer": "3.0.1" - } - }, "node_modules/lazyness": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/lazyness/-/lazyness-1.2.0.tgz", @@ -281,17 +162,6 @@ "node": ">=6.0.0" } }, - "node_modules/lowercase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -302,15 +172,23 @@ "is-buffer": "~1.1.6" } }, - "node_modules/mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.6" } }, "node_modules/ndarray": { @@ -347,30 +225,11 @@ "node": ">=v0.6.5" } }, - "node_modules/normalize-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", - "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/omggif": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==" }, - "node_modules/p-cancelable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", - "engines": { - "node": ">=12.20" - } - }, "node_modules/pngjs": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", @@ -379,35 +238,10 @@ "node": ">=12.13.0" } }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" - }, - "node_modules/responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", - "dependencies": { - "lowercase-keys": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/setimmediate": { "version": "1.0.5", @@ -464,10 +298,18 @@ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", "integrity": "sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==" }, - "node_modules/uuid4": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid4/-/uuid4-2.0.3.tgz", - "integrity": "sha512-CTpAkEVXMNJl2ojgtpLXHgz23dh8z81u6/HEPiQFOvBc/c2pde6TVHmH4uwY0d/GLF3tb7+VDAj4+2eJaQSdZQ==" + "node_modules/uuid": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz", + "integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } } } } diff --git a/package.json b/package.json index 4cef242..6230f3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meross", - "version": "1.0.15", + "version": "1.0.16", "description": "Utility to configure Meross devices for local MQTT", "keywords": [ "smarthome", @@ -18,14 +18,13 @@ "repository": "https://github.com/bytespider/Meross/tree/master", "license": "ISC", "dependencies": { - "axios": "^0.21.1", + "axios": "^1.7.9", "commander": "^7.2", - "got": "^13.0.0", "md5": "^2.2.1", "terminal-kit": "^3.0.1", - "uuid4": "^2.0.2" + "uuid": "^11.0.5" }, "engines": { - "node": ">=18.0.0" + "node": "^18.12 || ^20.9.0 || >22.11" } -} \ No newline at end of file +}