diff --git a/.gitignore b/.gitignore index 57137dd..cd0d513 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules/* example/node_modules/* example/scratch/* -.env \ No newline at end of file +.env +example/.env diff --git a/example/.env b/example/.env new file mode 100644 index 0000000..a7934ba --- /dev/null +++ b/example/.env @@ -0,0 +1,8 @@ +USERNAME="allenfarmer1@gmail.com" +PASSWORD="Honda!@5125" +KEY_ID="9e842a21-8f2e-4895-852b-ca8d301eae12" +API_KEY="6yANO0rh8bDTNSTjotSrmOl6oDIM2XbbQAF1qjodmpl4GBaAFLDp72DfVS1I" +PERSIST_PATH="./scratch" +LOG_LEVEL="debug" +API_LOG_ENABLED=true +LOCAL_DEV=true \ No newline at end of file diff --git a/example/index.js b/example/index.js index 22278d4..b63727d 100644 --- a/example/index.js +++ b/example/index.js @@ -1,3 +1,5 @@ +require('dotenv').config() + let WyzeAPI = null; if (process.env.LOCAL_DEV) { WyzeAPI = require('../src/index'); // Local Debug @@ -35,6 +37,6 @@ async function deviceListCheck() { (async () => { - // await deviceListCheck(); + await deviceListCheck(); // await loginCheck(4); })() diff --git a/example/package-lock.json b/example/package-lock.json index 315c5b7..58acad6 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "@ptkdev/logger": "1.8.0", "axios": "^0.27.2", - "wyze-api": "1.1.0" + "dotenv": "^16.4.1", + "wyze-api": "^1.1.1" } }, "node_modules/@ptkdev/logger": { @@ -195,6 +196,17 @@ "node": ">= 8.0.0" } }, + "node_modules/dotenv": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", + "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -701,16 +713,25 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/wyze-api": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/wyze-api/-/wyze-api-1.1.0.tgz", - "integrity": "sha512-gPkru2x2xS57Rk+5vmVP9S/vuVOSWhZV6b0nzh55oMeI938CqB1D6pU6g+ohDmFfV36zjtpsYNQjvA8/wFTKdw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wyze-api/-/wyze-api-1.1.2.tgz", + "integrity": "sha512-q0a0V0aO4DxE3DOc7ul3hlxYIsNKeFCwouPtdVfOju6zf8ELVv4pSF5Rao8KkB4AzIhmt7B9Znx5M1F2b6PUNQ==", "funding": [ { "type": "paypal", "url": "https://paypal.me/AllenFarmer" + }, + { + "type": "venmo", + "url": "https://venmo.com/u/Allen-Farmer" + }, + { + "type": "cashApp", + "url": "https://cash.app/$Jfamer08" } ], "dependencies": { + "@ptkdev/logger": "1.8.0", "axios": "1.5.0", "base64-js": "1.5.1", "colorsys": "^1.0.22", @@ -868,6 +889,11 @@ "resolved": "https://registry.npmjs.org/digest-header/-/digest-header-1.1.0.tgz", "integrity": "sha512-glXVh42vz40yZb9Cq2oMOt70FIoWiv+vxNvdKdU8CwjLad25qHM3trLxhl9bVjdr6WaslIXhWpn0NO8T/67Qjg==" }, + "dotenv": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", + "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==" + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -1230,10 +1256,11 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "wyze-api": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/wyze-api/-/wyze-api-1.1.0.tgz", - "integrity": "sha512-gPkru2x2xS57Rk+5vmVP9S/vuVOSWhZV6b0nzh55oMeI938CqB1D6pU6g+ohDmFfV36zjtpsYNQjvA8/wFTKdw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wyze-api/-/wyze-api-1.1.2.tgz", + "integrity": "sha512-q0a0V0aO4DxE3DOc7ul3hlxYIsNKeFCwouPtdVfOju6zf8ELVv4pSF5Rao8KkB4AzIhmt7B9Znx5M1F2b6PUNQ==", "requires": { + "@ptkdev/logger": "1.8.0", "axios": "1.5.0", "base64-js": "1.5.1", "colorsys": "^1.0.22", diff --git a/example/package.json b/example/package.json index 805e52a..6ba29a8 100644 --- a/example/package.json +++ b/example/package.json @@ -20,8 +20,9 @@ "author": "Allen Farmer", "license": "MIT", "dependencies": { - "axios": "^0.27.2", "@ptkdev/logger": "1.8.0", + "axios": "^0.27.2", + "dotenv": "^16.4.1", "wyze-api": "^1.1.1" } } diff --git a/package.json b/package.json index 5dc493b..965bbca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wyze-api", - "version": "1.1.2", + "version": "1.1.3", "description": "An unoficial API wrapper for Wyze products.", "homepage": "https://github.com/jfarmer08/wyze-api", "main": "./src/index.js", diff --git a/src/index.js b/src/index.js index 082fc2c..927aed0 100644 --- a/src/index.js +++ b/src/index.js @@ -3,11 +3,11 @@ const fs = require("fs").promises; const path = require("path"); const getUuid = require("uuid-by-string"); -const payloadFactory = require('./payloadFactory'); -const crypto = require('./crypto'); -const constants = require('./constants'); -const util = require('./util'); -const { time } = require('console'); +const payloadFactory = require("./payloadFactory"); +const crypto = require("./crypto"); +const constants = require("./constants"); +const util = require("./util"); +const { time } = require("console"); module.exports = class WyzeAPI { constructor(options, log) { @@ -145,13 +145,19 @@ module.exports = class WyzeAPI { throw e; } if (result.data.msg) { - if (result.data.msg == "DeviceIsOffline" || result.data.msg == "SUCCESS") { return result } else - throw new Error(result.data.msg) - } else { return result } + if ( + result.data.msg == "DeviceIsOffline" || + result.data.msg == "SUCCESS" + ) { + return result; + } else throw new Error(result.data.msg); + } else { + return result; + } } _performLoginRequest(data = {}) { - let url = "user/login"; + let url = "api/user/login"; data = { email: this.username, password: util.createPassword(this.password), @@ -160,44 +166,43 @@ module.exports = class WyzeAPI { const config = { baseURL: this.authBaseUrl, - headers: { "x-api-key": this.authApiKey, "User-Agent": this.userAgent }, - }; - - if (this.apiKey && this.keyId) { - url = "api/user/login"; - config.headers = { + headers: { + "x-api-key": this.authApiKey, apikey: this.apiKey, keyid: this.keyId, "User-Agent": this.userAgent, - }; - } + }, + }; return this._performRequest(url, data, config); } async login() { - let result = await this._performLoginRequest(); - - // Do we need to perform a 2-factor login? - if (!result.data.access_token && result.data.mfa_details) { - if (!this.mfaCode) { + let result; + // Do we need apiKey or keyId? + if (this.apiKey == null) { + throw new Error( + 'ApiKey Required, Please provide the "apiKey" parameter in config.json' + ); + } else if (this.keyId == null) { + throw new Error( + 'KeyId Required, Please provide the "keyid" parameter in config.json' + ); + } else { + result = await this._performLoginRequest(); + if ( + result.data.description == + "Invalid credentials, please check username, password, keyid or apikey" + ) { throw new Error( - 'Your account has 2-factor auth enabled. Please provide the "mfaCode" parameter in config.json.' + "Invalid credentials, please check username, password, keyid or apikey" ); + } else { + if (this.apiLogEnabled) + this.log.debug("Successfully logged into Wyze API"); + await this._updateTokens(result.data); } - - const data = { - mfa_type: "TotpVerificationCode", - verification_id: result.data.mfa_details.totp_apps[0].app_id, - verification_code: this.mfaCode, - }; - - result = await this._performLoginRequest(data); } - - await this._updateTokens(result.data); - - if (this.apiLogEnabled) this.log.debug("Successfully logged into Wyze API"); } async maybeLogin() { @@ -208,20 +213,35 @@ module.exports = class WyzeAPI { if (!this.access_token) { let now = new Date().getTime(); // check if the last login attempt occurred too recently - if (this.apiLogEnabled) this.log.debug("Last login " + this.lastLoginAttempt + " debounce " + this.loginAttemptDebounceMilliseconds + " now " + now); + if (this.apiLogEnabled) + this.log.debug( + "Last login " + + this.lastLoginAttempt + + " debounce " + + this.loginAttemptDebounceMilliseconds + + " now " + + now + ); if (this.lastLoginAttempt + this.loginAttemptDebounceMilliseconds < now) { // reset loginAttemptDebounceMilliseconds if last attempted login occurred more than 12 hours ago if (this.lastLoginAttempt - now > 60 * 1000 * 60 * 12) { this.loginAttemptDebounceMilliseconds = 1000; } else { // max debounce of 5 minutes - this.loginAttemptDebounceMilliseconds = Math.min(this.loginAttemptDebounceMilliseconds * 2, 1000 * 60 * 5); + this.loginAttemptDebounceMilliseconds = Math.min( + this.loginAttemptDebounceMilliseconds * 2, + 1000 * 60 * 5 + ); } this.lastLoginAttempt = now; await this.login(); } else { - this.log.warning("Attempting to login before debounce has cleared, waiting " + this.loginAttemptDebounceMilliseconds / 1000 + " seconds"); + this.log.warning( + "Attempting to login before debounce has cleared, waiting " + + this.loginAttemptDebounceMilliseconds / 1000 + + " seconds" + ); var waitTime = 0; while (waitTime < this.loginAttemptDebounceMilliseconds) { @@ -234,7 +254,10 @@ module.exports = class WyzeAPI { if (!this.access_token) { this.lastLoginAttempt = now; - this.loginAttemptDebounceMilliseconds = Math.min(this.loginAttemptDebounceMilliseconds * 2, 1000 * 60 * 5); + this.loginAttemptDebounceMilliseconds = Math.min( + this.loginAttemptDebounceMilliseconds * 2, + 1000 * 60 * 5 + ); await this.login(); } }