nfarina / homebridge-kevo

Kevo support for Homebridge: https://github.com/nfarina/homebridge
21 stars 18 forks source link

mykevo now has captcha #17

Closed b3nj1 closed 2 years ago

b3nj1 commented 5 years ago

The plugin stopped working this morning. When I log in to mykevo manually, I'm presented with a captcha. I'm afraid this may mean the death of this means of getting Kevo Plus to work. The plugin reports this:

Jun 06 09:04:52 raspberrypi homebridge[21315]: [06/06/2019, 09:04:52] [HK Front Door] Error submitting login page: Error: Bad status code 200 Jun 06 09:04:52 raspberrypi homebridge[21315]: [06/06/2019, 09:04:52] [HK Front Door] There was a problem logging into Kevo. Check your username and password.

Any hope of a fix?

Thanks, Benjamin

pmeisel123 commented 5 years ago

yeah just saw this too. There are application for other systems that are going to break too. Hopefully kēvo will provide an api. Still surprise they don’t have one already

bondjw07 commented 5 years ago

I’m having the same problem. Hasn’t worked for days, logged into my pi to find “Error submitting login page: Error: bad status code 422”

thenoid commented 5 years ago

Guessing this is related :(

[7/11/2019, 5:21:59 AM] TypeError: Cannot read property 'statusCode' of undefined
    at KevoAccessory.<anonymous> (/homebridge/node_modules/homebridge-kevo/index.js:66:18)
    at self.callback (/homebridge/node_modules/request/request.js:185:22)
    at Request.emit (events.js:189:13)
    at Request.onRequestError (/homebridge/node_modules/request/request.js:881:8)
    at ClientRequest.emit (events.js:189:13)
    at TLSSocket.socketErrorListener (_http_client.js:392:9)
    at TLSSocket.emit (events.js:189:13)
    at emitErrorNT (internal/streams/destroy.js:82:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
    at process._tickCallback (internal/process/next_tick.js:63:19)
[7/11/2019, 5:21:59 AM] TypeError: Cannot read property 'statusCode' of undefined
    at KevoAccessory.<anonymous> (/homebridge/node_modules/homebridge-kevo/index.js:66:18)
    at self.callback (/homebridge/node_modules/request/request.js:185:22)
    at Request.emit (events.js:189:13)
    at Request.onRequestError (/homebridge/node_modules/request/request.js:881:8)
    at ClientRequest.emit (events.js:189:13)
    at TLSSocket.socketErrorListener (_http_client.js:392:9)
    at TLSSocket.emit (events.js:189:13)
    at emitErrorNT (internal/streams/destroy.js:82:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
    at process._tickCallback (internal/process/next_tick.js:63:19)
fashionimage commented 5 years ago

Hello this started for me this afternoon, this is what mine is showing ... it is also causing home bridge to shut itself down

TypeError: Cannot read property 'statusCode' of undefined at KevoAccessory. (/usr/local/lib/node_modules/homebridge-kevo/index.js:66:17) at self.callback (/usr/local/lib/node_modules/homebridge-kevo/node_modules/request/request.js:185:22) at emitOne (events.js:115:13) at Request.emit (events.js:210:7) at Request.onRequestError (/usr/local/lib/node_modules/homebridge-kevo/node_modules/request/request.js:881:8) at emitOne (events.js:115:13) at ClientRequest.emit (events.js:210:7) at TLSSocket.socketErrorListener (_http_client.js:401:9) at emitOne (events.js:115:13) at TLSSocket.emit (events.js:210:7) [2019-7-10 21:33:15] Got SIGTERM, shutting down Homebridge..

JKaya commented 5 years ago

Same here... stopped working <12 hours ago with the same TLS socket error:

TypeError: Cannot read property 'statusCode' of undefined at KevoAccessory.<anonymous> (/usr/lib/node_modules/homebridge-kevo/index.js:66:18) at self.callback (/usr/lib/node_modules/homebridge-kevo/node_modules/request/request.js:185:22) at Request.emit (events.js:193:13) at Request.onRequestError (/usr/lib/node_modules/homebridge-kevo/node_modules/request/request.js:881:8) at ClientRequest.emit (events.js:193:13) at TLSSocket.socketErrorListener (_http_client.js:397:9) at TLSSocket.emit (events.js:193:13) at emitErrorNT (internal/streams/destroy.js:91:8) at emitErrorAndCloseNT (internal/streams/destroy.js:59:3) at processTicksAndRejections (internal/process/task_queues.js:81:17) [7/11/2019, 2:45:24 PM] Got SIGTERM, shutting downHomebridge...`

msaraceno commented 5 years ago

ditto on that [2019-7-11 06:59:37] Loading 1 accessories... [2019-7-11 06:59:37] [Front Door] Initializing Kevo accessory... [2019-7-11 06:59:39] TypeError: Cannot read property 'statusCode' of undefined at KevoAccessory. (/opt/node/lib/node_modules/homebridge-kevo/index.js:66:18) at self.callback (/opt/node/lib/node_modules/homebridge-kevo/node_modules/request/request.js:186:22) at emitOne (events.js:116:13) at Request.emit (events.js:211:7) at Request.onRequestError (/opt/node/lib/node_modules/homebridge-kevo/node_modules/request/request.js:878:8) at emitOne (events.js:116:13) at ClientRequest.emit (events.js:211:7) at TLSSocket.socketErrorListener (_http_client.js:387:9) at emitOne (events.js:116:13) at TLSSocket.emit (events.js:211:7) at emitErrorNT (internal/streams/destroy.js:64:8) at _combinedTickCallback (internal/process/next_tick.js:138:11) at process._tickCallback (internal/process/next_tick.js:180:9) [2019-7-11 06:59:39] Got SIGTERM, shutting down Homebridge...

fashionimage commented 5 years ago

I am new to this coding thing so I am asking all of the more experienced users here .. And that this probably sounds easier than it is but ..

Is there any way to just be able to modify the plug in so it can mark the checkbox of the captcha when logging into the site?

Thanks

JKaya commented 5 years ago

Well, seeing as captcha is designed and implemented specifically to prevent that I would say no;)

fashionimage commented 5 years ago

@JKaya Ok Thanks! That's what I was afraid of. So is all hope lost in ever getting this lock to work with homekit and Siri again.

pmeisel123 commented 5 years ago

Call kevo and complain. If enough people do it, maybe they will actually build a real api. Or more likely sell an add on to replace homebridge.

What’s really annoying me is they released a new lock with apple HomeKit built in right around the time they started adding the captcha. Now it could be a coincidence, or the new product making them be more secure, but it could be there way of pushing the new lock

fashionimage commented 5 years ago

@pmeisel123 I just called Kwikset to voice my concern and complain the rep also transferred me to an upper tier technical support and I had a conversation with them as well ... everyone here does need to call and wait on hold the hold time is bad!! I was on hold for 10min before someone answered ... but if you explain to the Kēvo rep and then get them to get you to a higher tech support they will listen ... and also please everyone here go to the kwikset portal on their website and voice a concern there and they may do something ... but we have to all make some noise for either full support or a Siri shortcut which could be added to the my Kēvo app From my understanding from the two Reps I talked to they will listen. If enough people make noise! .. so all of you please call and please go to the portal Here is the Kwikset number 1-800-327-5625 I believe here is the portal https://www.kwikset.com/Customer-Support/Product-FAQs/New-Case.aspx

msaraceno commented 5 years ago

I called in and opened a ticket as well, they said give the engineers a few weeks to look into it and I could call back on the case to see if there was any movement. Hopefully they can address or give us a true API to consume.

notasausage commented 5 years ago

I just started getting the same Cannot read property 'statusCode' of undefined at KevoAccessory. error as everyone else here as well. I'll make a call to Kwikset support tomorrow or Monday to voice my concerns as well, this is frustrating.

In the meantime, I've made a copy of my Homebridge config.json file and removed the part dealing with Kevo so that Homebridge can run properly:

    "accessories": [
        {
            "accessory": "Kevo",
            "name": "Front Door Lock",
            "username": "patrick@******.com",
            "password": "*******",
            "lock_id": "*****-*******-*******"
        }
    ],
bondjw07 commented 5 years ago

I just gave up on them doing this the right way and bough the Schlage with HomeKit built in. It’s soooooo much faster and more reliable than the Kēvo setup was. Still holding out hope here though for the Kēvo for another door.

fashionimage commented 5 years ago

@msaraceno Thank You for calling, @notasausage Please call and voice your concern and try to get to a level 2 tech support person and voice your concern there too, when I spoke to the tech person they said they would get it over to the app dev team ... so again the more people that call in and voice a concern the better...

fashionimage commented 5 years ago

@bondjw07 I have put a premis on my front door but my kevo I had hooked up to my security gate/screendoor ... I'm going to try and put this on I just ordered it the Vocolinc Smart lock with HomeKit should be here tomorrow it has the Kwikset type of keys so I'm hoping to re-key it and at $129 I wish it would've been available when I bought my Premis ... https://www.amazon.com/VOCOlinc-HomeKit-Bluetooth-Touchscreen-Deadbolt/dp/B07HMT5G5V/ref=sr_1_1?keywords=vocolinc+lock&qid=1562995958&s=gateway&sr=8-1

alixyz commented 5 years ago

As of Thursday night, the error disappeared for me and it’s been working.

fab301s commented 5 years ago

Yep, working for me now too. Thanks for the heads up!

JKaya commented 5 years ago

Working here too... as the web page still prompts for captcha they probably had a web developer filter the HTTP header for whatever User-Agent Homebridge/NPM declares and setup an exception.. awesome;)

pmeisel123 commented 5 years ago

If there is a way for automatic script to bypass the captcha, doesn't that defeat the purpose of a captcha?

Either way it is cool that it is working for people. I tried to log in remotely to my raspberry pi that runs homebridge, but apparently it went offline sometime last night, I will test this when I get home tonight.

Working here too... as the web page still prompts for captcha they probably had a web developer filter the HTTP header for whatever User-Agent Homebridge/NPM declares and setup an exception.. awesome;)

msaraceno commented 5 years ago

Patience got the better of me and I broke down and updated to a Premis lock this past Monday. The good thing is they were able to address the issue.

pmeisel123 commented 5 years ago

Works for me now, guess telling people to call in and complain worked. Good job everyone!

thomasqbrady commented 5 years ago

I've updated homebridge and homebridge-kevo and restarted, but I still get the bad status code 200 error. My account had been locked, but I called and got it unlocked, and I'm able to log in through mykevo.com. Was there something else I was supposed to do?

pmeisel123 commented 5 years ago

I've updated homebridge and homebridge-kevo and restarted, but I still get the bad status code 200 error. My account had been locked, but I called and got it unlocked, and I'm able to log in through mykevo.com. Was there something else I was supposed to do?

@thomasqbrady For browsers 200 status codes means everything worked. My guess you are getting a different error later.

FYI there was no update the homebridge-kevo. The fix was on kevo's website

Couple of suggestions: 1) This is just a general suggestion, this won't fix your problem: Create a second account on kevo for homebridge to use. This way if there is ever a glitch with homebridge, your main account won't get locked (note when the captcha problem started happening, homebridge-kevo kept trying to log in over and over, eventually locking the account). Make sure you can log in to mykevo.com with the new account. 2) look in your logs for 500 requests. I have seen issues where mykevo.com often fails to respond, if you are seeing those, you can probably wait and try again later.
3) If you are still having problem try posting your log here (with a few lines before and after the issue). Note: before posting make sure now username/passwords/api keys are in the logs (replace the with ***** before pasting it here)

thomasqbrady commented 5 years ago

That's the weird thing. I don't get 500s… I get 200s (which shouldn't be a "bad" status code, right?).

[7/28/2019, 11:15:58 PM] [Back Door] Error submitting login page: Error: Bad status code 200 at KevoAccessory.<anonymous> (/usr/local/lib/node_modules/homebridge-kevo/index.js:101:24) at Request.self.callback (/usr/local/lib/node_modules/homebridge-kevo/node_modules/request/request.js:185:22) at Request.emit (events.js:203:13) at Request.<anonymous> (/usr/local/lib/node_modules/homebridge-kevo/node_modules/request/request.js:1161:10) at Request.emit (events.js:203:13) at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/homebridge-kevo/node_modules/request/request.js:1083:12) at Object.onceWrapper (events.js:291:20) at IncomingMessage.emit (events.js:208:15) at endReadableNT (_stream_readable.js:1154:12) at processTicksAndRejections (internal/process/task_queues.js:77:11)

pmeisel123 commented 5 years ago

hmm, interesting. Apparently you are getting a 200 after login, when you should get a redirect (302) after login.

If you login is invalid they return a 200 instead of a 401. The bad news is that the captcha causes this problem. The good news is I suspect/hope you made a really simple easy to make mistake. When you account was locked I am betting they made you change your password, but since homebridge-kevo was broken you didn’t update your password stored in the config.json file.

thomasqbrady commented 5 years ago

I did update the password, unfortunately, so that’s not it.

How is this login happening? Are you using something like phantom to simulate a browser session? If so, could this be a cache issue (cookies or even HTML/javascript that’s cached)?

pmeisel123 commented 5 years ago

It uses node.js to make an ajax call. It does store cookies in memory, but only after you are logged in, and that is all cleared after you restart homebridge.

You can try going to /usr/local/lib/node_modules/homebridge-kevo/index.js (line 101) and add a console.log to have it print your user name and password. Maybe it is using a different config.json?

you can also have it log the html of the page. Then you can look at the source and see the error. It might be that you are an exception who is still getting screwed by that captcha. With out seeing the response it is hard to tell if it is a username/password error vs a captcha error

b3nj1 commented 5 years ago

@thomasqbrady, did it ever start working for you? It does not work for me still, but I'm able to login with the same user/password in Safari.

thomasqbrady commented 5 years ago

It did not. I did figure out that I had a typo in the username in my config file, but having fixed that doesn't seem to have improved things much. I have two locks. When the first one attempts to log in I get a "Bad status code 422." The second lock still gets the 200 "error" (in quotes because 200 is not an error—it's "OK").

thomasqbrady commented 5 years ago

It's back to a 200 on both now. Here's the log of what I get in the body: <html> <head> <link href="/assets/favicon-ef174cf86a7628199db2d22a4cb7b24abaa15df90138bff23a1cb7593a682bf7.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" /> <title>Kēvo</title> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0"> <meta name="apple-itunes-app" content="app-id=685604951"> <meta name="msapplication-config" content="none"/> <script src="https://use.typekit.net/ldp6jth.js"></script> <script>try{Typekit.load({ async: true });}catch(e){}</script> <link data-turbolinks-track="true" href="/assets/application-spectrum-86b782e77da1d8bf2f5d9b65256cb8d59b55416623148e1f302f2b1c432d081f.css" media="all" rel="stylesheet" /> <script data-turbolinks-track="true" src="/assets/application-spectrum-d3f30e0bd409bf03c62c0baebc31c79c9494faa09abf23f0a8951635f383c87a.js"></script> <script src="/assets/vendor/modernizr-de01d10b1f02bef5d15bef25c7e9959c21002760baece04fe957295974908523.js"></script> <meta content="authenticity_token" name="csrf-param" /> <meta content="au1DLxut/8XieM4mhKLMYpo6R25Nbm6YJ2+jpqu/hBA=" name="csrf-token" /> <link rel="apple-touch-icon-precomposed" sizes="144x144" href="/assets/apple_touch_icon/144-a82492147ff9a0c28bd6fc11974f5fa3ef71c855404f658a9ace2787d6b5d817.png"> <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/assets/apple_touch_icon/114-57258f56c827791876f869ecbdbd01dedd96aa19f8acde2e7278107c9a7e8828.png"> <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/assets/apple_touch_icon/72-f36c7ccd4c4d1c2e83069a318bbeaea274877d1257e552a4dad666e677e4368f.png"> <link rel="apple-touch-icon-precomposed" sizes="57x57" href="/assets/apple_touch_icon/57-44f7feef1c0454e614ed608f99210416fd083bd78f98410ae437a9ec6864d6ca.png"> </head> <body> <!-- Navbar Menu --> <div class="off-canvas-wrap"> <div class="inner-wrap"> <nav class="spectrum-nav-bar" data-no-turbolink> <section class="middle spectrum-nav-bar-section"> <center> <a href="https://www.mykevo.com/login"><img alt="Kevo" class="logo" src="/assets/kevo-logo-dc5ec5204b42388bd93f7062fdf619360524e265f73db24c727d204d29dd8f72.png" /></a> </center> </section> </nav> </div> </div> <!-- End of Navbar Menu --> ` <div class="row form-container main-container" data-equalizer>` ` <div class="large-8 medium-10 large-offset-0 medium-offset-1 columns login-panel" data-equalizer-watch>` ` <div class="row">` ` <div id="error_explanation" class="large-8 medium-10 large-offset-2 medium-offset-1 columns">` ` <div class="error-messages row">` ` <div data-alert class="alert-box alert small-12 columns">` ` <div>reCAPTCHA verification failed, please try again.</div>` ` <a href="#" class="close">&times;</a>` ` </div>` ` </div>` ` </div>` ` </div>` ` <div class="row panel-liner">` ` <form accept-charset="UTF-8" action="https://www.mykevo.com/signin" class="login-form large-8 medium-10 large-offset-2 medium-offset-1 columns" id="new_user_243509be-4751-4a56-a811-ee4058db3e1e" method="post"><div style="display:none"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="au1DLxut/8XieM4mhKLMYpo6R25Nbm6YJ2+jpqu/hBA=" /></div>` ` <h1 class="header">Sign-in</h1>` ` <h5>New Kevo owners please <a href="https://www.mykevo.com/registration">create an account</a>.</h5>` ` <br>` ` <div class="row">` ` <div class="large-10 small-12 columns">` ` <input class="special-input" id="user_username" name="user[username]" placeholder="Email" type="text" value="thomasqbrady@gmail.com" />` ` </div>` ` </div>` ` <div class="row">` ` <div class="large-10 small-12 columns">` ` <input class="special-input" id="user_password" name="user[password]" placeholder="Password" type="password" />` ` </div>` ` </div>` <br> <script src="https://www.recaptcha.net/recaptcha/api.js" async defer ></script> <div data-sitekey="6LeoV6cUAAAAAE9l2rpB-OTcfmS3wKkgkDgzHoTk" class="g-recaptcha "></div> <noscript> <div> <div style="width: 302px; height: 422px; position: relative;"> <div style="width: 302px; height: 422px; position: absolute;"> <iframe src="https://www.recaptcha.net/recaptcha/api/fallback?k=6LeoV6cUAAAAAE9l2rpB-OTcfmS3wKkgkDgzHoTk" name="ReCAPTCHA" style="width: 302px; height: 422px; border-style: none; border: 0; overflow: hidden;"> </iframe> </div> </div> <div style="width: 300px; height: 60px; border-style: none; bottom: 12px; left: 25px; margin: 0px; padding: 0px; right: 25px; background: #f9f9f9; border: 1px solid #c1c1c1; border-radius: 3px;"> <textarea id="g-recaptcha-response" name="g-recaptcha-response" class="g-recaptcha-response" style="width: 250px; height: 40px; border: 1px solid #c1c1c1; margin: 10px 25px; padding: 0px; resize: none;"> </textarea> </div> </div> </noscript> ` <br>` <div class="row"> <div class="small-5 columns"> <input class="button expand" name="commit" type="submit" value="LOGIN" /> </div> <div class="small-5 columns end forgot-password"> <a class="text-center" href="https://www.mykevo.com/forgot_password">Forgot Password</a> </div> </div> <p class="cookies-message"> Note: A browser that supports cookies is required. </p> </form> </div> <div class="row sub-footer"> <div class="large-8 medium-10 large-offset-2 medium-offset-1 columns"> <h6><strong>New to Kevo?</strong> Learn more at <a class="blue-link" href="http://www.baldwinhardware.com/evolved">Baldwin</a>, <a class="blue-link" href="http://www.kwikset.com/kevo/">Kwikset</a>, or <a class="blue-link" href="http://www.weiserlock.com/en/kevo/">Weiser</a>.</h6> </div> </div> </div> <div class="large-4 medium-10 large-offset-0 medium-offset-1 columns end support-panel" data-equalizer-watch> <div class="row panel-liner"> <div class="large-8 medium-5 small-10 large-offset-2 medium-offset-1 small-offset-1 columns"> <h2 class="subheader"> <img alt="Support" class="i-button" src="/assets/spectrum/i-c4d54d8ac58531654c909dd327f13549338b9d9306da1f5e58f0977fffb21cb3.png" /> Support </h2> <h6 class="subheader"> Watch how-to videos and get instant answers on popular topics. Select a brand below. </h6> </div> <div class="large-8 medium-5 small-10 large-offset-2 small-offset-1 columns end"> <a href="http://www.baldwinhardware.com/evolved/support"><img alt="Baldwin Support" class="support-button" src="/assets/spectrum/baldwin-0b70851686d1b867fc92fcebb6e3d4645ddae96e5cde27edf20b50ad51b193c4.png" /></a> <a href="http://www.kwikset.com/kevo/support"><img alt="Kwikset Support" class="support-button" src="/assets/spectrum/kwikset-a8d43263d2c01691cf32a216e96b0b103232d64c22d3bb650f0cfb44d3531266.png" /></a> <a href="http://www.weiserlock.com/en/kevo/support"><img alt="Weiser Support" class="support-button" src="/assets/spectrum/weiser-27504e02517d68cb308de8c8cc051d0a942231f1f1c4c676cbb0392b10fa5060.png" /></a> </div> </div> </div> <div class="small-12 columns"> <div class="row"> <br> <div class="large-4 small-12 large-centered columns"> <div class="row"> <div class="small-12 columns"> <a href="http://www.unikey.com/"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 772.09 330.26" class="powered-by-unikey" alt="Powered By UniKey"> <title>Asset 1</title> <g id="Layer_2" data-name="Layer 2"> <g id="Layer_1-2" data-name="Layer 1"> <path id="Symetrical_-_Cut" data-name="Symetrical - Cut" d="M644.9,95.51l-40.35,54-28.72-54H410l-44.44,59H353.91l9.62-78.34H304.24S264.1.44,165.51.44,0,82,0,167.11,70.81,330.26,165.51,330.26s137-73.12,137-73.12h38.92L350.29,184l9.18-.15,32.76,61.77H530.29l3.57-29-68.59.08H424.68l-24.09-45.54,34.85-46.43L542,124.42l37.56,70.42-6.37,50.76h38.45l6.47-52.73,73.36-97.35ZM165.51,290.59A125.24,125.24,0,1,1,290.75,165.35,125.24,125.24,0,0,1,165.51,290.59Z"></path> <g id="UNI_-_2_3_Spacing" data-name="UNI - 2/3 Spacing"> <path d="M66.61,177.87l6-49.07H93.13l-5.58,46.49c-.95,7.17,4.8,10.66,12.19,10.64,10.88,0,14.73-4.66,15.77-16.07l5.14-41.06,20.16.16L134.75,177c-2.32,20.59-18.89,27.38-38.12,27.38C77,203.94,64.82,192.21,66.61,177.87Z"></path> <path d="M154.43,128.81h20.35l24,38.32,4.58-38.33h20.38L214.58,203h-18l-25.47-40.71L166,203H145.32Z"></path> <path d="M237.5,128.8h20.66l-9,74.23H228.44Z"></path> </g> <polygon points="431.92 154.49 538.38 154.49 534.75 183.98 428.42 184.07 431.92 154.49"></polygon> <path d="M736,71.92V91.66h-4.85V71.92h-7V67.7h18.82v4.22Zm31.66,19.74V74.71l-6.9,14.49H757.6l-6.84-14.49V91.66H746.3v-24h5.59l7.3,15.23,7.3-15.23h5.59v24Z"></path> <path d="M339.17.16c9.23,0,14.53,4.56,14.53,12.54,0,8.29-5.3,13.12-14.53,13.12h-8.45V36.88h-6.19V.16Zm-8.45,20.09h8.18c5.67,0,8.87-2.41,8.87-7.4,0-4.83-3.2-7.13-8.87-7.13h-8.18Z"></path> <path d="M401,18.52c0,10.49-8.5,18.62-19.46,18.62S362,29,362,18.52,370.55,0,381.51,0,401,8,401,18.52Zm-32.63,0a13.16,13.16,0,0,0,13.22,13.06,13,13,0,1,0-13.22-13.06Z"></path> <path d="M443.74,36.88,435,8.24l-8.81,28.64h-6.4L407.64.16h6.66L423.22,30,432.09.21l6.09-.05L447.09,30,456,.16h6.4L450.08,36.88Z"></path> <path d="M478.11,5.72v9.91H496v5.56H478.11V31.32h20.67v5.56H471.92V.16h26.23V5.72Z"></path> <path d="M528.16,25.76c-.53.05-1.1.05-1.68.05h-8.71V36.88h-6.19V.16h14.9c9.39,0,14.8,4.56,14.8,12.54,0,5.88-2.73,10-7.61,11.91l8.24,12.28h-7Zm-1.68-5.51c5.67,0,8.92-2.41,8.92-7.4,0-4.83-3.25-7.13-8.92-7.13h-8.71V20.25Z"></path> <path d="M561,5.72v9.91H578.9v5.56H561V31.32h20.67v5.56H554.77V.16H581V5.72Z"></path> <path d="M609.49.16c11,0,19,7.71,19,18.36s-8,18.36-19.15,18.36h-14.9V.16Zm-8.86,31.16h9a12.31,12.31,0,0,0,12.59-12.75A12.52,12.52,0,0,0,609.39,5.72h-8.76Z"></path> <path d="M675.08.16c7.61,0,12.33,3.46,12.33,9.18A8,8,0,0,1,681,17.52a8.91,8.91,0,0,1,7.87,9.29c0,6.3-5.09,10.07-13.38,10.07H659.13V.16Zm-9.76,15.21h9.44c3.94,0,6.3-1.84,6.3-4.93s-2.36-4.77-6.3-4.77h-9.44Zm0,16h9.44c4.83,0,7.71-1.89,7.71-5.35,0-3.26-2.89-5.19-7.71-5.19h-9.44Z"></path> <path d="M716.48,36.88h-6.14v-12L696.65.16h6.24L713.38,18,723.67.16H730l-13.48,24.5Z"></path> </g> </g> </svg> </a> </div> </div> <div class="row"> <div class="small-12 columns"> <h6 class="text-center subheader copyright">Copyright © 2019 Spectrum Brands, Inc., All rights reserved.</h6> </div> </div> <br> </div> </div> </div> </div> ` <script>` ` (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){` ` (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),` ` m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)` ` })(window,document,'script','//www.google-analytics.com/analytics.js','ga');` ga('create', 'UA-45276467-1', 'mykevo.com'); ga('send', 'pageview'); ` var app_messages = {` ` errors: {` ` send_command: "There was an error sending the *TYPE* command for *NAME*.",` ` too_many_failures: "Too many failed attempts to process *TYPE* command for *NAME*",` ` too_many_attempts: "Too many attempts to process *TYPE* command for *NAME*"` ` },` ` successes: {` ` command_complete: "*NAME* was successfully *TYPE*ed."` ` }` ` }` var batch_job_ids = []; ` var log = function(message){ return false; } `

chickenandpork commented 5 years ago

Kevo, Kwikset are currently owned by Spectrum Brands, Madison WI USA. Feel free to hit up their support site, but maybe more effectively, https://twitter.com/KwiksetCorp to ask about a pseudo-random crypto hash as an API token to connect and manipulate locks via an API. If we ask for the same thing, across many media, and offer to help (in the US: 1099 $1 consultant willing to sign NDAs) they might accept some modernization of their system.

pmeisel123 commented 5 years ago

Just started seeing this error again. What’s interesting when I signed into mykevo.com on my phone with the same account I stopped seeing this issue.
When I logged out I started happening again

I’m currently waiting to see what happens if I login and just timeout

pmeisel123 commented 5 years ago

Made some changes, things seem to be working better now: I was seeing some weird issues, which might be related to multiple browsers making requests at the exact same time with the same login. (also their reset password doesn't seem to work too well)

Some suggestions:

pmeisel123 commented 5 years ago

Good News/Annoying News/Bad News/Question

Good News: Through some manual testing, I have figure out why this has started working.

Annoying News Part I: You do in fact have to login with a computer or a phone with the same account before homebridge can login (I believe it has to be from the same network but I have not cofirmed). I would recommend once a week opening an incognito window, login in to mykevo.com with the hombridge account, and then close the incognito session

Annoying News Part II: Homebridge will always get the "fail to login" from mykevo.com, but if you have logged in with a browser recently (and have not logged out), it will work as if the login passed. I don't think this can be avoided (though we could update the homebridge code to ignore this error)

Bad News Part I: If an account fails login too many time kevo will lock the account, I think homebridge "fail to login" counts as a bad login. It is probable that if you log in to the mykevo website with the account that homebridge uses, will reset the "fail to login" count.

Bad News Part II: This is a bug not a feature. This is all working because of a really minor security bug on mykevo.com. It is one of those bugs that could easily be made a feature, or easily fixed. Either option will probably take less than an hour of coding. Sadly even though this bug can not be used to hack into someone else's account, it is still safest for kevo to fix this

Question: I'm currently debating if I should report this to kevo. While I don't want them to fix this, I hope that if I report this, with my proposed solution (not making the captcha required if the account is already logged in from the same network), they will make this a feature instead of a bug. I am also on other forums for making programs use kevo (they have also been following my instruction to call kevo and complain about the captcha, and request an API), and if I post about this bug in too many forums, sooner or later kevo will find out about this bug anyway, and then they might fix it, instead of using my proposed solution. So, should I report this to kevo or wait until they find it on their own

JKaya commented 5 years ago

Another option would be to copy the cookie contents from the desktop PC to homebridge however that would require additional development to this module (not much though as I believe it already implements session cookies)

pmeisel123 commented 5 years ago

Another option would be to copy the cookie contents from the desktop PC to homebridge however that would require additional development to this module (not much though as I believe it already implements session cookies)

That could be tricky, because you would regularly need to copy the cookies over. One thing I left out of my above note (I just updated it), is that sessions do timeout. You should log in with a browser at least once a week to prevent issues. There is probably a good way to copy cookies automatically from your browser into homebridge, though I don't know it. Though you are right that is probably the long term solution

kbosscawen commented 4 years ago

Have there been any non-workaround updates to this since last September? I'm new to Homebridge, and am having this problem.

pmeisel123 commented 4 years ago

Have there been any non-workaround updates to this since last September? I'm new to Homebridge, and am having this problem. @kbosscawen not that I know of. I don't think anyone is really working on this project. I'm also not sure if there would be a work around. Kevo doesn't have an api so the app needs to login via the website, and the point of a captcha is to prevent accessing a website via code.

Honestly I still surprised the work around work at all. Though while it does I just login via the website every few weeks. It should work as long as you don't log out from the website (just close the browser window/tab). BTW my original note said you needed to be logged in from the same network that isn't true.

The real problem is if you fail the captcha too many times you account gets locked. It looks like now if you disable homebridge for a few minutes, then login via the website, your account will be unlocked.

YouCanNotBeSerious commented 3 years ago

Is the workaround of logging in via browser still the way to make this work? thx

fab301s commented 3 years ago

Is the workaround of logging in via browser still the way to make this work? thx

I haven't found a way to make that work

pmeisel123 commented 3 years ago

Is the workaround of logging in via browser still the way to make this work? thx

Yes. I’ve found as long as you don’t log out from the browser it works.
Though I have found that at times it takes a few seconds for commands to go through.

I’ve also tweaked the code of my local copy to retry a few times after failure. I’ll post my changes when I have a chance

fab301s commented 3 years ago

I’ve also tweaked the code of my local copy to retry a few times after failure. I’ll post my changes when I have a chance

Would you be able to share your code changes please @pmeisel123

SemoTech commented 3 years ago

I’ve also tweaked the code of my local copy to retry a few times after failure. I’ll post my changes when I have a chance

Would you be able to share your code changes please @pmeisel123

2nd!

Tiger519 commented 2 years ago

@pmeisel123 @fab301s @SemoTech I actually have a fork that does a retry as well, unfortunately it has been years since I looked at it and I'm not even confident it still works. I just installed homebridge on a new RPi image so I no longer have the changes I did on my local. I may try to pick this back up but any work you have done @pmeisel123 would be great to see.

fab301s commented 2 years ago

@Tiger519, I'm getting an Unexpected status code 401, rather than a Bad status code 200

pmeisel123 commented 2 years ago

For the error make sure to login to kevo with your browser, and then close the browser window without logging out. Also I recommend having a kevo account per kevo lock. homebridge-kevo treats each lock separately, and logs in for each lock. Kevo doesn't always handle multiple concurrent request from the same account well. Making each accessory use a different username gets around this problem.

I did try to make a platform version of this code, that would do one call to get the status of all the devices, but my knowledge of writting a homebridge app from scratch is very limited, and I quickly got stuck. And then the raspberry pi I was building it on got water damaged, and I lost my code.

--

For my tweaks to the code, it has been a while since I have worked on this. But this is my index.js file now. I can't remember if I modified any other file

The big change was adding KevoAccessory.prototype.multirequest and then using that all over the code

var request = require('request').defaults({jar: true/*, proxy:"http://localhost:8888", strictSSL:false*/}); // use cookies
var cheerio = require('cheerio');
var Service, Characteristic;

module.exports = function(homebridge) {
    Service = homebridge.hap.Service;
    Characteristic = homebridge.hap.Characteristic;

    homebridge.registerAccessory("homebridge-kevo", "Kevo", KevoAccessory);
}

var lockOrder = 0;
var lockEventSpacing = 15000;
var lockEventsOccurring = 0;

function KevoAccessory(log, config) {
    this.log = log;
    this.name = config["name"];
    this.username = config["username"];
    this.password = config["password"];
    this.lockId = config["lock_id"];
    this.lockOrder = lockOrder++;

    this.service = new Service.LockMechanism(this.name);

    this.service
        .getCharacteristic(Characteristic.LockCurrentState)
        .on('get', this.getState.bind(this));

    this.service
        .getCharacteristic(Characteristic.LockTargetState)
        .on('get', this.getState.bind(this));
    this.service
        .getCharacteristic(Characteristic.LockTargetState)
        .on('set', this.setState.bind(this));

    this._setup();
}

KevoAccessory.prototype.multirequest = function(uri, options, callback, count) {
    if (!count) {
    count = 0;
    }

    var platform = this;
    if (typeof options === 'function') {
    callback = options;
    options = {};
    }

    return request(uri, options, function (err, response, body) {
    if (response.statusCode == 500 && count < 5) {
        platform.log('Got a 500 response trying again');
        return platform.multirequest(uri, options, callback, ++count);
    } else {
        if(callback) {
        return callback(err, response, body);
        }
    }
    });
}

KevoAccessory.prototype.multipost = function(uri, options, callback, count) {
    if (!count) {
    count = 0;
    }

    var platform = this;
    if (typeof options === 'function') {
    callback = options;
    options = {};
    }

    return request.post(uri, options, function (err, response, body) {
    if (response.statusCode == 500 && count < 5) {
        platform.log('Got a 500 response trying again');
        return platform.multipost(uri, options, callback, ++count);
    } else {
        if(callback) {
        return callback(err, response, body);
        }
    }
    });
}

KevoAccessory.prototype._setup = function() {
    this._login(function(err) {
    if (err) {
        this.log("There was a problem logging into Kevo. Check your username and password.");
        return;
    }
    else {
        this._checkLockExists(function(err) {});
    }
    }.bind(this));
}

KevoAccessory.prototype._login = function(callback) {
    var url = "https://www.mykevo.com/login";

    var followRedirect = function(response) {
    if (response.headers.location === "https://www.mykevo.com/user/locks") {
        this.log("Already logged in.");
        callback(null);
        return false; // don't follow this redirect, we're done
    }

    return true; // ok redirect, sure
    }.bind(this);

    this.multirequest(url, {followRedirect:followRedirect}, function (err, response, body) {
    if (response.statusCode == 302) return; // we cancelled a redirect above

    if (!err && response.statusCode == 200 && response.headers['content-type'].indexOf("text/html") == 0) {

        var form = {
        "user[username]": this.username,
        "user[password]": this.password,
        "commit": "Sign In"
        };

        // the response is an HTML login page. Suck out the hidden input fields so we can simulate a form submit
        var $ = cheerio.load(body);
        var action = $('form').attr('action');

        $('input[type=hidden]').each(function(i, input) {
        var name = $(input).attr('name');
        var value = $(input).val();
        form[name] = value;
        });

        if (!action) {
        this.log("Couldn't find form action.");
        this.log(body);
        callback(err);
        return;
        }

        // Submit the login page
        this.multipost(action, {form:form}, function(err, response, body) {
        // we expect a redirect response
        if (!err && response.statusCode == 302) {
            this.log("Login successful.");
            callback(null);
        }
        else {
            err = err || new Error("Bad status code " + response.statusCode);
            this.log("Error submitting login page: %s", err);
            callback(err);
        }
        }.bind(this));

    }
    else {
        err = err || new Error("Invalid response code " + response.statusCode)
        this.log("Error requesting login page: %s", err);
        callback(err);
    }
    }.bind(this));
}

KevoAccessory.prototype._checkLockExists = function(callback) {
    var url = "https://www.mykevo.com/user/locks";

    this.multirequest(url, function(err, response, body) {
    if (!err && response.statusCode == 200) {
        var $ = cheerio.load(body);
        var seenLockIds = [];

        // pull out all elements with "data-lock-id" defined
        $('*[data-lock-id]').each(function(i, elem) {
        var lockId = $(elem).attr('data-lock-id');

        if (this.lockId == null && seenLockIds.indexOf(lockId) < 0) {
            seenLockIds.push(lockId);
        }
        else if (lockId == this.lockId) {
            callback(null);
            return;
        }
        }.bind(this));

        if (this.lockId == null) {
        this.log("No lock ID specified, list of possible lock IDs: ");
        this.log(seenLockIds);
        }
        else {
        err = new Error("Could not locate lock with ID: %s", this.lockId);
        callback(err);
        }
    }
    else {
        err = err || new Error("Invalid status code " + response.statusCode);
        this.log("Error fetching lock: %s", err);
        callback(err);
    }
    }.bind(this));
}

KevoAccessory.prototype._getLockStatus = function(callback) {
    var url = "https://www.mykevo.com/user/remote_locks/command/lock.json";
    var qs = {
    arguments: this.lockId
    };
    this.multirequest(url, {qs:qs}, function(err, response, body) {

    if (!err && response.statusCode == 200) {
        var json = JSON.parse(body);
        var state = json.bolt_state; // "Unlocked" or "Locked" or maybe "Processing" or "Confirming"
        callback(null, state);
    }
    else {
        err = err || new Error("Invalid status code " + response.statusCode);
        this.log("Error getting lock status: %s", err);
        callback(err);
    }

    }.bind(this));
}

KevoAccessory.prototype._setLockStatus = function(status, callback) {
    var url;

    if (status === "Locked") {
    url = "https://www.mykevo.com/user/remote_locks/command/remote_lock.json";
    }
    else if (status === "Unlocked") {
    url = "https://www.mykevo.com/user/remote_locks/command/remote_unlock.json";
    }
    else {
    this.log("Invalid lock status %s", status);
    callback(new Error("Invalid lock status"));
    return;
    }

    var qs = {
    arguments: this.lockId
    };

    this.multirequest(url, {qs:qs}, function(err, response, body) {

    if (!err && response.statusCode == 200) {
        var json = JSON.parse(body);

        if (json.status_code !== 201) {
        callback(new Error("Unexpected status_code " + json.status_code));
        return;
        }

        // success!
        callback(null);
    }
    else {
        err = err || new Error("Invalid status code " + response.statusCode);
        this.log("Error setting lock status: %s", err);
        callback(err);
    }

    }.bind(this));
}

KevoAccessory.prototype.getState = function(callback, state) {
    if (!this.lockId) {
    this.log("Lock has no ID assigned; can't get current state.");
    return;
    }

    this.log("Getting current state...");

    this._login(function(err) {
    if (err) {
        callback(err);
        return;
    }

    this._getLockStatus(function(err, status) {

        this.log("Lock status is %s", status);
        if (status === "Locked") {
        callback(null, true); // success, locked
        }
        else if (status === "Unlocked") {
        callback(null, false); // success, unlocked
        }
        else {
        err = new Error("Invalid lock status '"+status+"'");
        this.log("Error getting state: %s", err);
        callback(err);
        }

    }.bind(this));
    }.bind(this));
}

KevoAccessory.prototype.setState = function(state, callback) {
    if (!this.lockId) {
    this.log("Lock has no ID assigned; can't set current state");
    return;
    }

    var kevoStatus = (state == Characteristic.LockTargetState.SECURED) ? "Locked" : "Unlocked";

    this._login(function(err) {
    if (err) {
        callback(err);
        return;
    }

    var lockStatusCallback = function(err) {
        if (err) {
        this.log("Error setting state: %s", err);
        callback(err);
        lockEventsOccurring--;
        return;
        }

        // we succeeded, so update the "current" state as well
        var currentState = (state == Characteristic.LockTargetState.SECURED) ?
        Characteristic.LockCurrentState.SECURED : Characteristic.LockCurrentState.UNSECURED;
        this.service
            .setCharacteristic(Characteristic.LockCurrentState, currentState);

        // success
        lockEventsOccurring--;
        callback(null);

    }.bind(this);

    if (lockEventsOccurring > 0) {
        lockEventsOccurring++;
        setTimeout(function() {
        this.log("Setting status to %s", kevoStatus);
        this._setLockStatus(kevoStatus, lockStatusCallback);
        }.bind(this), this.lockOrder * lockEventSpacing);
    }
    else {
        lockEventsOccurring++;
        this.log("Setting status to %s", kevoStatus);
        this._setLockStatus(kevoStatus, lockStatusCallback);
    }

    }.bind(this));

}

KevoAccessory.prototype.getServices = function() {
    return [this.service];
}
Tiger519 commented 2 years ago

@Tiger519, I'm getting an Unexpected status code 401, rather than a Bad status code 200

You're still getting a 401? That's definitely an authentication issue. I'll try to look into this a bit when I have time.

SemoTech commented 2 years ago

This is what I get if I enable the plugin (v0.0.3):

[8/20/2022, 5:43:29 PM] [Office Door] Error submitting login page: Error: Bad status code 200 at KevoAccessory.<anonymous> (/homebridge/node_modules/homebridge-kevo/index.js:101:24) at Request.self.callback (/homebridge/node_modules/homebridge-kevo/node_modules/request/request.js:185:22) at Request.emit (node:events:527:28) at Request.<anonymous> (/homebridge/node_modules/homebridge-kevo/node_modules/request/request.js:1154:10) at Request.emit (node:events:527:28) at IncomingMessage.<anonymous> (/homebridge/node_modules/homebridge-kevo/node_modules/request/request.js:1076:12) at Object.onceWrapper (node:events:641:28) at IncomingMessage.emit (node:events:539:35) at endReadableNT (node:internal/streams/readable:1345:12) at processTicksAndRejections (node:internal/process/task_queues:83:21) [8/20/2022, 5:43:29 PM] [Office Door] There was a problem logging into Kevo. Check your username and password. [8/20/2022, 5:43:44 PM] [Office Door] Getting current state... [8/20/2022, 5:43:44 PM] [Office Door] Getting current state... [8/20/2022, 5:43:44 PM] [Office Door] Already logged in. [8/20/2022, 5:43:44 PM] [Office Door] Already logged in. [8/20/2022, 5:43:45 PM] [Office Door] Lock status is Unlocked [8/20/2022, 5:43:45 PM] [Office Door] Lock status is Unlocked

Lock is most certainly Locked! I had to disable the plugin as it is not working...