SecKatie / ha-wyzeapi

Home Assistant Integration for Wyze devices.
748 stars 113 forks source link

[Feature Request] Two-Factor Authentication #39

Closed IIAIronWolf closed 3 years ago

IIAIronWolf commented 4 years ago

Currently, as you stated in the README, this integration does not support two-factor authentication. Would use this integration if two factor was an option, but do not wish to lower the security of my Wyze system in order to make this work as it is currently written.

jfarmer08 commented 4 years ago

I have the required documents to make this happen. So we should see something soon.

IIAIronWolf commented 4 years ago

Awesome! Thanks for the update!

SecKatie commented 4 years ago

Sweet @jfarmer08 this would be awesome

imhotep commented 4 years ago

Yes, this would be great!

jfarmer08 commented 4 years ago

If anyone has the knowledge of HA Development and would like to help please let me know.

CoryBailly commented 3 years ago

Any update on this?

bed428 commented 3 years ago

Any update on this?

It wouldn't be as big of a deal if Wyze had login alerts, devices logged in, security logs, etc. Sucks having to disable 2FA though with none of the previous protections in place. I'm hoping the Wyze comes out with some of those features.

SecKatie commented 3 years ago

This is not coming anytime soon. There is not a reliable way to refresh the access token at the moment so every time the access token expired which is every 3 or so days you would have to login again and enter a new 2fa code.

This is not a workable solution but once there is a way to use the refresh token then the plan is to provide a way through the UI to provide the 2fa code and be notified when it is required next

KevinVoell commented 3 years ago

@JoshuaMulliken I have the functionality to refresh the access token using the refresh token as well as a having 2FA working on my project. Is there something I can help with on this? I only know enough python to be dangerous, I'm a C++/C# guy, but maybe I can help.

danielntamasi commented 3 years ago

@JoshuaMulliken

I have the functionality to refresh the access token using the refresh token as well as a having 2FA working on my project. Is there something I can help with on this? I only know enough python to be dangerous, I'm a C++/C# guy, but maybe I can help.

it would be so great if we could make our Wyze account safe again :)

atjshop commented 3 years ago

@JoshuaMulliken I have the functionality to refresh the access token using the refresh token as well as a having 2FA working on my project. Is there something I can help with on this? I only know enough python to be dangerous, I'm a C++/C# guy, but maybe I can help.

It should be possible since I know "tinycam" app on Android can do 2FA for wyze.

Do you have a link/document for this? If you can post, maybe someone else good at python can create PR.

SecKatie commented 3 years ago

@KevinVoell Any secrets you can share would be much appreciated!

KevinVoell commented 3 years ago

Sorry, meant to keep circling back on this, but...

Anyway, here is what I have for 2FA.

If attempting to login using username/password for an account that has 2FA enabled, the access and refresh token in the response will both be null, but the mfa_options will be populated.

MFA Options

The value in mfa_options will vary depending on how the user has setup mfa. I believe there are 4 possible values that can be there: PrimaryPhone BackupPhone TotpVerificationCode TotpRecoveryCode

Depending on the value of mfa_options, the mfa_details will contain different values.

SMS PrimaryPhone BackupPhone

For a mfa_options that contains "PrimaryPhone" or "BackupPhone" the response from login will look like this:

{
  "access_token": null,
  "refresh_token": null,
  "user_id": "d0dd2254418447c8a0f12804dc68d778",
  "mfa_options": [
    "PrimaryPhone"
  ],
  "mfa_details": {
    "phone_numbers": {
      "primary_phone": {
        "country_code": "+1",
        "number": "5555551212"
      },
      "backup_phone": {
        "country_code": "+1",
        "number": "5555551213"
      }
    },
    "totp_apps": []
  },
  "sms_session_id": "23c85121-34d2-40b6-9b60-65fa390fdb39"
}

TotpVerificationCode TotpRecoveryCode

For a request that contains TotpVerificationCode or TotpRecoveryCode the response will look like this:

{
  "access_token": null,
  "refresh_token": null,
  "user_id": "d0dd2254418447c8a0f12804dc68d778",
  "mfa_options": [
    "TotpVerificationCode",
    "TotpRecoveryCode"
  ],
  "mfa_details": {
    "phone_numbers": null,
    "totp_apps": [
      {
        "app_id": "d2d26372-7451-4152-bf65-6ddce1b68229",
        "app_nickname": "Wyze"
      }
    ]
  },
  "sms_session_id": ""
}

TOTP APP

For a Totp app 2FA, you just need to prompt the user to enter their 2FA code and make one additional POST request to: https://auth-prod.api.wyze.com/user/login

With the following body:

{
    "email": "user@user.com",
    "password": "01ecb9dca3544b7286223b671e1c4c3b",
    "verification_id": "d2d26372-7451-4152-bf65-6ddce1b68229",
    "mfa_type": "TotpVerificationCode",
    "verification_code": "123456"
}

email: Users email password: Users triple MD5 encoded password (same one sent with normal login) verfication_id: The Totp app_id or sms_session_id from the login response above mfa_type: The value from mfa_options from the login response above verification_code: The mfa code the user entered

SMS

For sms 2fa, there is an additional step to have wyze send the code to the SMS number.

Perform a POST with an empty body to: https://auth-prod.api.wyze.com/user/login/sendSmsCode?mfaPhoneType=Primary&sessionId=23c85121-34d2-40b6-9b60-65fa390fdb39&userId=d0dd2254418447c8a0f12804dc68d778

mfaPhoneType: This will be either 'Primary' or 'Backup' sessionId: This will be the sms_session_id returned from the first login attempt userId: This is the id (not email) of the user retuned in the first login attempt

If this POST is successful, it will return a 200 with a body containing a session id.

{
    "session_id": "770a3d0e-256b-49fe-8e02-d2f5cf22acc6"
}

After POSTing to the sendSmsCode and the user enters the code, you make one additional POST to: https://auth-prod.api.wyze.com/user/login

with this body:

{
    "email": "user@user.com",
    "password": "01ecb9dca3544b7286223b671e1c4c3b",
    "verification_id": "770a3d0e-256b-49fe-8e02-d2f5cf22acc6",
    "mfa_type": "PrimaryPhone",
    "verification_code": "123456"
}

email: Users email password: Users triple MD5 encoded password (same one sent with normal login) verfication_id: The session_id returned from the sendSmsCode POST above mfa_type: The value from mfa_options from the login response above verification_code: The mfa code the user entered

Response

If everything is correct, you will get a response containing the access and refresh token:

{
    "access_token": "gdjhdjhdjhdlkagjhfg;fshgfjghfdohfhjhfdsjhgf",
    "refresh_token": "lhjkhdfdhdkjhfd;fhjdasfhdfhdhfdjkhflad",
    "user_id": "d0dd2254418447c8a0f12804dc68d778",
    "mfa_options": null,
    "mfa_details": null,
    "sms_session_id": null
}

Notes

There is a timeout for SMS, which i believe is 30 seconds, if the user doesn't submit their sms code before then you need to call the sendSmsCode again to push another code to the user

I haven't actually tested the BackupPhone sms, since I don't have 2 phones I can try with. But I believe it should work the same as primary phone.

The headers sent with each POST is the same as a normal login: Host: auth-prod.api.wyze.com Content-Type: application/json X-API-Key: WMXHY... User-Agent: wyze_ios_2.21.35 Accept-Language: en-US;q=1 Phone-Id: 7e54fc95-a4a8-4b9b-a721-45ad536d82a5

KevinVoell commented 3 years ago

@JoshuaMulliken just went back and reread this thread, did you actually need the 2fa process, the refresh token process, or both?

SecKatie commented 3 years ago

Refresh token info would also be useful @KevinVoell thank you so much for the info on the 2FA process!!

KevinVoell commented 3 years ago

@JoshuaMulliken Sure thing, here are my notes on using the refresh token.

The login user response contains the access token and the refresh token. Store the refresh token along with the access token and the current time. Store the current time since access tokens are only valid for 60 hours and check if a refresh is needed before performing the POST. Also catch 401 responses and perform a refresh of the access token and retry the POST again.

To refresh the access token, make a POST to: https://api.wyzecam.com/app/user/refresh_token

With the following body:

{
    "phone_id": "e9b000d1-5a1a-40cf-815f-166cd5fbf226",
    "app_name": "com.hyalai.WyzeCam",
    "app_version": "2.18.41",
    "sc": "9f2757...8876429f3c",
    "sv": "41267de2...2658f88d7",
    "phone_system_type": "1",
    "app_ver": "wyze_ios_2.21.35",
    "ts": "1617733423",
    "refresh_token": "lvtx.eq...=="
}

If successful it will return this response:

{
    "ts": 1624754112349,
    "code": "1",
    "msg": "",
    "data": {
        "access_token": "lvtx.y2ou...RO/w==",
        "refresh_token": "lvtx.biVbrXzT7ne...Q=="
    }
}

Store both the new access tokens and the new refresh token, along with the current time (for same reason stated above).

Notes

Access tokens are valid for 60 hours Refresh tokens are valid for 16000 hours

Refresh tokens can't be reused, so once a refresh token is used, the new one returned should be stored and used next time a new access token is needed.

If an updated access token cannot be acquired, then the user will need to login again.

SecKatie commented 3 years ago

@KevinVoell thank you so much!

SecKatie commented 3 years ago

I implemented the refresh token process! Thank you @KevinVoell!

gdreelin commented 3 years ago

I would think working with Wyze to add HA as a linked app like Alexa or Google would get around the 2FA. Those folks at Wyze are great to work with and should be able to make this happen since their products are about the only ones that do not integrate into HA by now.

SecKatie commented 3 years ago

@gdreelin I would love to see someone from their team reach out to me! I cannot imagine that they are unaware of our work over here

gdreelin commented 3 years ago

@gdreelin I would love to see someone from their team reach out to me! I cannot imagine that they are unaware of our work over here

I will reach out to them since I am on the betatesting team to see if we can get some help.

gdreelin commented 3 years ago

I just contacted their support team and gave them your contact email so hopefully they will get in touch with you soon. Hope that helps love to see this working.

SecKatie commented 3 years ago

Someone from their security team reached out so either we will be getting major help or a cease and desist lol

gdreelin commented 3 years ago

Someone from their security team reached out so either we will be getting major help or a cease and desist lol

Well maybe it was a good thing.... Lol It would be the security section to help with 2FA and more.

gdreelin commented 3 years ago

@JoshuaMulliken I am glad to see they are working with you on getting some of the issues fixed. I knew talking to the beta team would stir up some interest. They are a great company and care about their customers. Ring use to be like until it was Bezoized for profit. LOL.

SecKatie commented 3 years ago

@gdreelin Yes thank you for your help on that. I would have prefered to be contacted before the incident so we could adjust ahead of time but the collaboration has been really positive so far @yoinx helping with the 2FA implementation so more to come soon!

gdreelin commented 3 years ago

@JoshuaMulliken oh sorry I thought I told I would reach out to them for some help, my bad!!

SecKatie commented 3 years ago

@gdreelin They did but only after the rate limiting incident. Not your fault at all! You helped be they got my contact info!

gdreelin commented 3 years ago

Oh oops... well seems they would want to fix that since they are about the only company not connected to HA somehow.. lol

JoeSchubert commented 3 years ago

Sorry all... I know it's been like 2 weeks since I was tagged in here. Just wanted to tag the PR for this that I'm working on. I'm having a little trouble with the last two commits... Essentially, since we're potentially using 2fa we could end up with a bad login if the tokens corrupt/expire/etc. Granted, the refresh tokens should stay good for something like 2 years, so in theory it should never really happen. The last 2 commits in this wrap the API calls so that if they get a bad access token error it clears the wyze integration entry. This isn't really ideal because it completely clears the integration.

If someone is pretty decent with Home Assistant's way of doing things, I could use some tips on how to prompt the user to reconfigure through the config flow or something. (If anyone is looking to do testing, you'll need the PR I have open in wyzeapy as well for it to work as well... Not the easiest thing to do with HA though)

https://github.com/JoshuaMulliken/ha-wyzeapi/pull/244

JoeSchubert commented 3 years ago

This has been merged into the current beta.

SecKatie commented 3 years ago

Implemented in Stable!