Merge branch 'main' into mac-compoatibility-enhancements

This commit is contained in:
Trammell Hudson
2023-12-04 20:08:16 +01:00
committed by GitHub
3 changed files with 262 additions and 263 deletions

View File

@@ -16,19 +16,20 @@ and should prevent most any random attacker on your network from being able to
## Setup
To avoid running into issues later with your default python installs, it's recommended to use a py virtual env for doing this. Go to your desired test directory, and:
```
pip3 -r requirements.txt
python3 -m venv venv
source venv/bin/activate
git clone https://github.com/osresearch/hcpy
cd hcpy
pip3 install -r requirements.txt
```
Install the Python dependencies; the `sslpsk` one is a little weird
and we might need to revisit it later.
### For Mac Users
To avoid running into issues later with your default python installs, it's recommended to use a py virtual env for doing this. Go to your desired test directory, and:
1. python3 -m venv venv
1. source venv/bin/activate
1. clone this repo
### For Mac Users
Installing `sslpsk` needs some extra steps:
1. The openssl package installed via brew: `brew install openssl`, and
@@ -39,7 +40,7 @@ Installing `sslpsk` needs some extra steps:
![laptop in a clothes washer with a display DoorState:Closed](images/doorclose.jpg)
```
```bash
hc-login $USERNAME $PASSWORD > config.json
```
@@ -55,10 +56,9 @@ the resulting configuration JSON file *should* be sufficient to
connect to the devices on your local network, assuming that
your mDNS or DNS server resolves the names correctly.
## Home Connect to MQTT
```
```bash
hc2mqtt config.json
```
@@ -82,7 +82,7 @@ library.
Example message published to `homeconnect/dishwasher`:
```
```json
{
"state": "Run",
"door": "Closed",
@@ -98,7 +98,7 @@ Example message published to `homeconnect/dishwasher`:
<details>
<summary>Full state information</summary>
```
```json
{
'AllowBackendConnection': False,
'BackendConnected': False,
@@ -163,8 +163,8 @@ Example message published to `homeconnect/dishwasher`:
'SilenceOnDemand': False
}
```
</details>
</details>
### Clothes washer
@@ -178,7 +178,7 @@ binary data over the websocket (type 0x82).
Example message published to `homeconnect/washer`:
```
```json
{
"state": "Ready",
"door": "Closed",
@@ -194,7 +194,7 @@ Example message published to `homeconnect/washer`:
<details>
<summary>Full state information</summary>
```
```json
{
'BackendConnected': False,
'CustomerEnergyManagerPaired': False,
@@ -256,8 +256,8 @@ Example message published to `homeconnect/washer`:
'SelectedProgram': 28718
}
```
</details>
</details>
### Coffee Machine
@@ -268,7 +268,7 @@ The coffee machine needs a better mapping to MQTT messages.
<details>
<summary>Full state information</summary>
```
```json
{
'LastSelectedBeverage': 8217,
'LocalControlActive': False,
@@ -361,8 +361,8 @@ The coffee machine needs a better mapping to MQTT messages.
'ProcessPhase': 'None'
}
```
</details>
</details>
## FRIDA tools

View File

@@ -4,7 +4,7 @@
# A really nice walk through of how it works is:
# https://auth0.com/docs/get-started/authentication-and-authorization-flow/call-your-api-using-the-authorization-code-flow-with-pkce
import requests
from urllib.parse import urlparse, parse_qs, urlencode
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
from lxml import html
import io
import re
@@ -13,6 +13,7 @@ import json
from time import time
from base64 import b64decode as base64_decode
from base64 import urlsafe_b64encode as base64url_encode
from bs4 import BeautifulSoup
from Crypto.Random import get_random_bytes
from Crypto.Hash import SHA256
from zipfile import ZipFile
@@ -124,44 +125,40 @@ while True:
r = session.get(preauth_url, allow_redirects=False)
if r.status_code == 200:
break
if r.status_code == 302 or r.status_code == 301:
if r.status_code > 300 and r.status_code < 400:
preauth_url = r.headers["location"]
# Make relative locations absolute
if not bool(urlparse(preauth_url).netloc):
preauth_url = singlekey_host + preauth_url
continue
print(f"2: {preauth_url=}: failed to fetch {r} {r.text}", file=sys.stderr)
exit(1)
# get the ReturnUrl from the response
query = parse_qs(urlparse(preauth_url).query)
return_url = query["ReturnUrl"][0]
return_url = query["returnUrl"][0]
debug(f"{return_url=}")
headers["RequestVerificationToken"] = r.cookies["X-CSRF-FORM-TOKEN"]
if "X-CSRF-FORM-TOKEN" in r.cookies:
headers["RequestVerificationToken"] = r.cookies["X-CSRF-FORM-TOKEN"]
session.headers.update(headers)
debug("--------")
valid_url = singlekey_host + '/auth/api/v1/authentication/UserExists'
auth_url = singlekey_host + '/auth/api/v1/authentication/login'
soup = BeautifulSoup(r.text, 'html.parser')
requestVerificationToken = soup.find('input', {'name': '__RequestVerificationToken'}).get('value')
r = session.post(preauth_url, data={"UserIdentifierInput.EmailInput.StringValue": email, "__RequestVerificationToken": requestVerificationToken }, allow_redirects=False)
r = session.post(valid_url, json={"username": email})
debug(f"{valid_url=}: {r} {r.text}")
password_url = r.headers['location']
if not bool(urlparse(password_url).netloc):
password_url = singlekey_host + password_url
r = session.get(password_url, allow_redirects=False)
soup = BeautifulSoup(r.text, 'html.parser')
requestVerificationToken = soup.find('input', {'name': '__RequestVerificationToken'}).get('value')
login_fields = {
"username": email,
"password": password,
"keepMeSignedIn": False,
"returnUrl": return_url,
}
r = session.post(password_url, data={"Password": password, "RememberMe": "false", "__RequestVerificationToken": requestVerificationToken }, allow_redirects=False)
r = session.post(auth_url, json=login_fields, allow_redirects=False)
if r.status_code != 200:
debug(f"auth failed: {auth_url=}, {login_fields=} {r} {r.text}")
exit(-1)
debug(f"{auth_url=}, {r} {r.text}")
return_url = json.loads(r.text)["returnUrl"]
if return_url.startswith("/"):
return_url = singlekey_host + return_url

View File

@@ -1,3 +1,5 @@
bs4
requests
pycryptodome
websocket-client
sslpsk