1
0
Fork 0
mirror of https://codeberg.org/vanous/huafetcher synced 2024-05-05 20:16:19 +02:00

initial commit

This commit is contained in:
vanous 2020-11-24 23:12:25 +01:00
parent fb57ce94fe
commit 7b449719f4
8 changed files with 965 additions and 0 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.buildozer
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/

View File

@ -1,2 +1,25 @@
# huafetcher
Kivy GUI for huami-token. Works on desktop and as Android apk. Downloads key and aGPS data, unzips it into `/storage/emulated/0`
[huami-token](https://github.com/argrento/huami-token): all credits to the original author
## Install
Install [Buildozer](https://github.com/kivy/buildozer/) and [Kivy](https://github.com/kivy/kivy)
pip install buildozer
pip install kivy
or
pip install -r requirements.txt
## Run
python main.py
## make Android apk
buildozer -v android debug deploy run

BIN
data/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

80
data/icon.svg Normal file
View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 24 24"
fill="white"
width="18px"
height="18px"
version="1.1"
id="svg6"
sodipodi:docname="icon.svg"
inkscape:export-filename="/tmp/icon.png"
inkscape:export-xdpi="2730.6699"
inkscape:export-ydpi="2730.6699"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1042"
id="namedview8"
showgrid="false"
inkscape:zoom="40.833333"
inkscape:cx="9"
inkscape:cy="9"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<path
d="M0 0h24v24H0V0z"
fill="none"
id="path2"
inkscape:export-filename="/tmp/icon.png"
inkscape:export-xdpi="2730.6699"
inkscape:export-ydpi="2730.6699" />
<path
d="M14.31 2l.41 2.48C13.87 4.17 12.96 4 12 4c-.95 0-1.87.17-2.71.47L9.7 2h4.61m.41 17.52L14.31 22H9.7l-.41-2.47c.84.3 1.76.47 2.71.47.96 0 1.87-.17 2.72-.48M16 0H8l-.95 5.73C5.19 7.19 4 9.45 4 12s1.19 4.81 3.05 6.27L8 24h8l.96-5.73C18.81 16.81 20 14.54 20 12s-1.19-4.81-3.04-6.27L16 0zm-4 18c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6z"
id="path4"
inkscape:export-filename="/tmp/icon.png"
inkscape:export-xdpi="2730.6699"
inkscape:export-ydpi="2730.6699"
style="stroke:#000000;stroke-opacity:1;stroke-width:0.2;stroke-miterlimit:4;stroke-dasharray:none" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.88889px;line-height:124%;font-family:Sans;-inkscape-font-specification:Sans;letter-spacing:0px;word-spacing:0px;fill:#fffffc;fill-opacity:1;stroke:#000000;stroke-width:0.26666667;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
x="7.1302075"
y="15.376737"
id="text839"><tspan
sodipodi:role="line"
id="tspan837"
x="7.1302075"
y="15.376737"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.88889px;font-family:Sans;-inkscape-font-specification:Sans;fill:#fffffc;fill-opacity:1;stroke-width:0.26666667;stroke:#000000;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none">hf</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

193
huami_token.py Normal file
View File

@ -0,0 +1,193 @@
#!/usr/bin/env python3
import json
import uuid
import random
import shutil
import urllib
import requests
import urls
class HuamiAmazfit:
def __init__(self, method="amazfit", email=None, password=None):
#if method == 'amazfit' and (not email or not password):
# raise ValueError("For Amazfit method E-Mail and Password can not be null.")
self.method = method
self.email = email
self.password = password
self.access_token = None
self.country_code = None
self.app_token = None
self.login_token = None
self.user_id = None
self.result = None
self.r = str(uuid.uuid4())
# IMEI or something unique
self.device_id = "02:00:00:%02x:%02x:%02x" % (random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255))
def __str__(self):
return f"{self.email} {self.password} {self.method} {self.access_token}"
def parse_token(self, token_url):
parsed_token_url = urllib.parse.urlparse(token_url)
token_url_parameters = urllib.parse.parse_qs(parsed_token_url.query)
if 'code' not in token_url_parameters:
return
self.access_token = token_url_parameters['code']
self.country_code = 'US'
def get_access_token(self):
print(f"Getting access token with {self.method} login method...")
if self.method == 'xiaomi':
login_url = urls.URLS["login_xiaomi"]
elif self.method == 'amazfit':
auth_url = urls.URLS['tokens_amazfit'].format(user_email=urllib.parse.quote(self.email))
data = urls.PAYLOADS['tokens_amazfit']
data['password'] = self.password
response = requests.post(auth_url, data=data, allow_redirects=False)
response.raise_for_status()
# 'Location' parameter contains url with login status
redirect_url = urllib.parse.urlparse(response.headers.get('Location'))
redirect_url_parameters = urllib.parse.parse_qs(redirect_url.query)
if 'error' in redirect_url_parameters:
raise ValueError(f"Wrong E-mail or Password. Error: {redirect_url_parameters['error']}")
if 'access' not in redirect_url_parameters:
raise ValueError("No 'access' parameter in login url.")
if 'country_code' not in redirect_url_parameters:
raise ValueError("No 'country_code' parameter in login url.")
self.access_token = redirect_url_parameters['access']
self.country_code = redirect_url_parameters['country_code']
def login(self, external_token=None):
print("Logging in...")
if external_token:
self.access_token = external_token
login_url = urls.URLS['login_amazfit']
data = urls.PAYLOADS['login_amazfit']
data['country_code'] = self.country_code
data['device_id'] = self.device_id
data['third_name'] = 'huami' if self.method == 'amazfit' else 'mi-watch'
data['code'] = self.access_token
data['grant_type'] = 'access_token' if self.method == 'amazfit' else 'request_token'
response = requests.post(login_url, data=data, allow_redirects=False)
response.raise_for_status()
login_result = response.json()
if 'error_code' in login_result:
raise ValueError(f"Login error. Error: {login_result['error_code']}")
if 'token_info' not in login_result:
raise ValueError("No 'token_info' parameter in login data.")
else:
token_info = login_result['token_info']
if 'app_token' not in token_info:
raise ValueError("No 'app_token' parameter in login data.")
self.app_token = token_info['app_token']
if 'login_token' not in token_info:
raise ValueError("No 'login_token' parameter in login data.")
self.login_token = token_info['login_token']
if 'user_id' not in token_info:
raise ValueError("No 'user_id' parameter in login data.")
self.user_id = token_info['user_id']
print("Logged in! User id: {}".format(self.user_id))
return True
def get_wearable_auth_keys(self):
print("Getting linked wearables...")
print(self.user_id)
devices_url = urls.URLS['devices'].format(user_id=urllib.parse.quote(self.user_id))
headers = urls.PAYLOADS['devices']
headers['apptoken'] = self.app_token
response = requests.get(devices_url, headers=headers)
response.raise_for_status()
device_request = response.json()
if 'items' not in device_request:
raise ValueError("No 'items' parameter in devices data.")
devices = device_request['items']
devices_dict = {}
for idx, wearable in enumerate(devices):
if 'macAddress' not in wearable:
raise ValueError("No 'macAddress' parameter in device data.")
mac_address = wearable['macAddress']
if 'additionalInfo' not in wearable:
raise ValueError("No 'additionalInfo' parameter in device data.")
device_info = json.loads(wearable['additionalInfo'])
if 'auth_key' not in device_info:
raise ValueError("No 'auth_key' parameter in device data.")
key_str = device_info['auth_key']
auth_key = '0x' + (key_str if key_str != '' else '00')
devices_dict[f'{mac_address}'] = auth_key
return devices_dict
def get_gps_data(self):
agps_packs = ["AGPS_ALM", "AGPSZIP"]
agps_file_names = ["cep_alm_pak.zip", "cep_7days.zip"]
agps_link = urls.URLS['agps']
headers = urls.PAYLOADS['agps']
headers['apptoken'] = self.app_token
for idx, agps_pack_name in enumerate(agps_packs):
print("Downloading {}...".format(agps_pack_name))
response = requests.get(agps_link.format(pack_name=agps_pack_name), headers=headers)
response.raise_for_status()
agps_result = response.json()[0]
if 'fileUrl' not in agps_result:
raise ValueError("No 'fileUrl' parameter in files request.")
with requests.get(agps_result['fileUrl'], stream=True) as r:
with open(agps_file_names[idx], 'wb') as f:
shutil.copyfileobj(r.raw, f)
def logout(self):
logout_url = urls.URLS['logout']
data = urls.PAYLOADS['logout']
data['login_token'] = self.login_token
response = requests.post(logout_url, data=data)
logout_result = response.json()
if logout_result['result'] == 'ok':
print("\nLogged out.")
else:
print("\nError logging out.")

394
main.py Normal file
View File

@ -0,0 +1,394 @@
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.utils import platform
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from functools import partial
from kivy.clock import Clock
from kivy.logger import Logger
from kivy.uix.dropdown import DropDown
from huami_token import HuamiAmazfit
import urls as urls
from kivy.core.clipboard import Clipboard
from kivy.storage.jsonstore import JsonStore
DEBUG=False
DEBUG=True
def debug_print(*xargs):
if DEBUG:
print(*xargs)
SPACING=2
Builder.load_string('''
<MyInputy>:
font_size: 30
halign: 'left'
color: 1,1,1,1
bcolor: .1, 0, .6, 0
canvas.before:
Color:
rgba: root.bcolor
Rectangle:
size: (self.width -2, self.height -2)
pos: (self.x+1,self.y +1)
<MyLabel>:
font_size: 30
halign: 'center'
bcolor: .7, .7, .7, 1
canvas.before:
Color:
rgba: root.bcolor
Rectangle:
size: self.size
pos: self.pos
<MyLeftLabel>:
font_size: 30
halign: 'left'
bcolor: .7, .7, .7, 1
canvas.before:
Color:
rgba: root.bcolor
Rectangle:
size: self.size
pos: self.pos
<MyButton>:
font_size: 30
bcolor: .7, .7, .7, 1
background_color: .1, 0, .5, 0
canvas.before:
Color:
rgba: root.bcolor
Rectangle:
size: self.size
pos: self.pos
''')
class MyLabel(Label):
pass
class MyLeftLabel(Label):
pass
class MyButton(Button):
pass
class MyInput(TextInput):
pass
class Main(App):
def build(self):
self.huamidevice=HuamiAmazfit()
self.store = JsonStore('credentials.json')
screen_layout = BoxLayout(orientation="vertical", spacing=SPACING)
buttons_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
rows_layout = BoxLayout(orientation="vertical", spacing=SPACING)
self.instructions_label=MyLeftLabel(text='Huafetcher')
rows_layout.add_widget(self.instructions_label)
dropdown = DropDown()
xiaomi_button = MyButton(text='Xiaomi', size_hint_y=None, height=150)
xiaomi_button.bind(on_press=lambda a:self.set_login_method('xiaomi'))
xiaomi_button.bind(on_release=lambda btn: dropdown.select(btn.text))
amazfit_button = MyButton(text='Amazfit', size_hint_y=None, height=150)
amazfit_button.bind(on_press=lambda a:self.set_login_method('amazfit'))
amazfit_button.bind(on_release=lambda btn: dropdown.select(btn.text))
dropdown.add_widget(xiaomi_button)
dropdown.add_widget(amazfit_button)
dropdown_button = MyButton(text='Login method')
dropdown_button.bind(on_release=dropdown.open)
#dropdown_button.bind(on_press=lambda x: setattr(dropdown_button,'text','Select'))
dropdown.bind(on_select=lambda instance, x: setattr(dropdown_button, 'text', x))
get_token_button = MyButton(text='Get token')
get_token_button.bind(on_press=self.on_press_button_gettoken)
fetch_key_button = MyButton(text='Fetch key')
fetch_key_button.bind(on_press=self.on_press_button_fetch_key)
fetch_agps_button = MyButton(text='Fetch aGPS')
fetch_agps_button.bind(on_press=self.on_press_button_agps)
share_agps_button = MyButton(text='Share aGPS')
share_agps_button.bind(on_press=self.on_press_button_share_agps)
buttons_layout.add_widget(get_token_button)
#buttons_layout.add_widget(login_button)
buttons_layout.add_widget(fetch_key_button)
buttons_layout.add_widget(fetch_agps_button)
#sharing doesn't work
#buttons_layout.add_widget(share_agps_button)
paste_token_input_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
paste_token_input_label=MyLabel(text='URL result')
self.paste_token_input = MyInput(text='',
multiline=False,
)
self.paste_token_input.bind(text=self.set_token)
paste_button1=MyButton(text='Paste', size_hint=(.3, 1))
paste_button1.bind(on_press=lambda instance: self.on_press_paste(self.paste_token_input) )
paste_token_input_layout.add_widget(paste_token_input_label)
paste_token_input_layout.add_widget(paste_button1)
paste_token_input_layout.add_widget(self.paste_token_input)
credentials_email_label=MyButton(text='Email' , size_hint=(.7, 1))
self.credentials_email_input = MyInput(text='',
multiline=False,
)
self.credentials_email_input.bind(text=lambda instance,x: setattr(self.huamidevice,'email',x))
credentials_email_label.bind(on_press=self.on_press_paste_email)
paste_button2=MyButton(text='Paste', size_hint=(.3, 1))
paste_button2.bind(on_press=lambda instance: self.on_press_paste(self.credentials_email_input) )
save_button1=MyButton(text='Save', size_hint=(.3, 1))
#load_button1.bind(on_press=lambda instance: )
save_button1.bind(on_press=lambda instance: self.on_press_save(self.credentials_email_input, 'email') )
self.credentials_email_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
self.credentials_email_layout.add_widget(credentials_email_label)
#credentials_email_layout.add_widget(load_button1)
self.credentials_email_layout.add_widget(save_button1)
self.credentials_email_layout.add_widget(paste_button2)
self.credentials_email_layout.add_widget(self.credentials_email_input)
credentials_password_label=MyLabel(text='Password', size_hint=(.7, 1))
self.credentials_password_input = MyInput(text='',
multiline=False,
)
self.credentials_password_input.bind(text=lambda instance,x: setattr(self.huamidevice,'password',x))
credentials_password_label.bind(on_press=self.on_press_paste_password)
paste_button3=MyButton(text='Paste', size_hint=(.3, 1))
paste_button3.bind(on_press=lambda instance: self.on_press_paste(self.credentials_password_input) )
save_button2=MyButton(text='Save', size_hint=(.3, 1))
save_button2.bind(on_press=lambda instance: self.on_press_save(self.credentials_password_input, 'password') )
self.credentials_password_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
self.credentials_password_layout.add_widget(credentials_password_label)
self.credentials_password_layout.add_widget(save_button2)
self.credentials_password_layout.add_widget(paste_button3)
self.credentials_password_layout.add_widget(self.credentials_password_input)
rows_layout.add_widget(dropdown_button)
rows_layout.add_widget(self.credentials_email_layout)
rows_layout.add_widget(self.credentials_password_layout)
rows_layout.add_widget(paste_token_input_layout)
result_value_label=MyButton(text='Found key')
self.result_value_value=TextInput()
copy_button4=MyButton(text='Copy', size_hint=(.3, 1))
copy_button4.bind(on_press=lambda instance: self.on_press_copy(self.result_value_value) )
result_value_layout = BoxLayout(orientation="horizontal", spacing=SPACING)
result_value_layout.add_widget(result_value_label)
result_value_layout.add_widget(copy_button4)
result_value_layout.add_widget(self.result_value_value)
result_value_label.bind(on_press=self.on_press_copy_result)
rows_layout.add_widget(result_value_layout)
rows_layout.add_widget(buttons_layout)
screen_layout.add_widget(rows_layout)
self.on_press_load(self.credentials_email_input, 'email')
self.on_press_load(self.credentials_password_input, 'password')
self.set_login_method('xiaomi')
dropdown_button.text='Xiaomi'
return screen_layout
def hide_widget(self, wid, dohide=True):
debug_print(dohide)
if hasattr(wid, 'saved_attrs'):
debug_print(wid.saved_attrs)
if not dohide:
wid.height, wid.size_hint_y, wid.opacity, wid.disabled = wid.saved_attrs
del wid.saved_attrs
elif dohide:
wid.saved_attrs = wid.height, wid.size_hint_y, wid.opacity, wid.disabled
wid.height, wid.size_hint_y, wid.opacity, wid.disabled = 0, None, 0, True
def set_login_method(self,method):
debug_print(method)
self.huamidevice.method=method
if method == 'xiaomi':
self.hide_widget(self.credentials_email_layout, dohide=True)
self.hide_widget(self.credentials_password_layout, dohide=True)
else:
self.hide_widget(self.credentials_email_layout, dohide=False)
self.hide_widget(self.credentials_password_layout, dohide=False)
def set_token(self, instance, text):
debug_print("got", text)
debug_print(self.huamidevice)
self.huamidevice.parse_token(text)
debug_print(self.huamidevice)
def on_press_button_gettoken(self, instance):
debug_print('You pressed the button login!')
debug_print(self.huamidevice)
self.instructions_label.text="log in and paste url here"
if self.huamidevice.method == 'xiaomi':
login_url = urls.URLS["login_xiaomi"]
if ( platform != 'android' ):
import webbrowser
webbrowser.open(login_url, new = 2)
else:
from jnius import autoclass
from jnius import cast
PythonActivity = autoclass('org.kivy.android.PythonActivity')
Intent = autoclass('android.content.Intent')
Uri = autoclass('android.net.Uri')
intent = Intent()
intent.setAction(Intent.ACTION_VIEW)
intent.setData(Uri.parse(login_url))
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
currentActivity.startActivity(intent)
self.huamidevice.get_access_token()
def on_press_button_fetch_key(self, instance):
debug_print('You pressed the button fetch!')
debug_print(self.huamidevice)
self.instructions_label.text="signing in"
if (self.huamidevice.login()):
self.instructions_label.text="Signed in as: {}, getting data".format(self.huamidevice.user_id)
device_keys = self.huamidevice.get_wearable_auth_keys()
self.instructions_label.text="Done"
self.result_value_value.text=""
for device_key in device_keys:
debug_print(f"{device_key} {device_keys[device_key]}")
self.result_value_value.text=f"{device_keys[device_key]}"
#Clock.schedule_once(partial(self.doit), 1)
def on_press_paste_token(self, instance):
self.paste_token_input.text=Clipboard.paste()
def on_press_paste_email(self, instance):
self.credentials_email_input.text=Clipboard.paste()
def on_press_paste_password(self, instance):
self.credentials_password_input.text=Clipboard.paste()
def on_press_copy_result(self, instance):
Clipboard.copy(self.result_value_value.text)
def on_press_paste(self, instance):
instance.text=Clipboard.paste()
def on_press_copy(self, instance):
Clipboard.copy(instance.text)
def on_press_load(self, instance, key):
if self.store.exists(key):
instance.text=self.store.get(key)["value"]
def on_press_save(self, instance, key):
self.store.put(key, value=instance.text)
def on_press_button_agps(self, instance):
import zipfile
debug_print('You pressed the button agps!')
debug_print(self.huamidevice)
self.instructions_label.text="signing in"
if (self.huamidevice.login()):
self.instructions_label.text="Signed in as: {}, getting data".format(self.huamidevice.user_id)
self.huamidevice.get_gps_data()
agps_file_names = ["cep_alm_pak.zip"]
if ( platform == 'android' ):
import shutil
import os
from jnius import autoclass
from jnius import cast
Environment = autoclass('android.os.Environment')
File = autoclass('java.io.File')
data_dir = Environment.getExternalStorageDirectory().getPath()
debug_print(data_dir)
for filename in agps_file_names:
sdpathfile = os.path.join(data_dir, filename)
shutil.copyfile(filename, sdpathfile)
with zipfile.ZipFile(filename, "r") as zip_f:
#zip_f.extractall()
zip_f.extractall(data_dir)
self.instructions_label.text="Done"
#Clock.schedule_once(partial(self.doit), 1)
def on_press_button_share_agps(self, instance):
#not working because android broke it
if ( platform == 'android' ):
import os
from jnius import autoclass
from jnius import cast
Environment = autoclass('android.os.Environment')
File = autoclass('java.io.File')
data_dir = Environment.getExternalStorageDirectory().getPath()
PythonActivity = autoclass('org.kivy.android.PythonActivity')
Intent = autoclass('android.content.Intent')
Uri = autoclass('android.net.Uri')
intent = Intent()
intent.setAction(Intent.ACTION_VIEW)
data_dir = getattr(self, 'user_data_dir')
file_target=File(os.path.join(data_dir, "cep_pak.bin"))
#target=Uri.parse(os.path.join("file:///", data_dir, "cep_pak.bin"))
target=Uri.fromFile(file_target)
#intent.setData(Uri.parse(os.path.join("file:///", data_dir, "cep_pak.bin")))
#intent.setType("application/octet-stream")
intent.setDataAndType(target, "application/octet-stream")
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
currentActivity.startActivity(intent)
#intent = Intent()
#intent.setAction(Intent.ACTION_VIEW)
#intent.setData(Uri.parse("gps_alm.bin"))
#currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
#currentActivity.startActivity(intent)
#def doit(self, *kargs):
def openweb(url):
debug_print("open ", url)
if __name__ == '__main__':
app = Main()
app.run()

221
requirements.txt Normal file
View File

@ -0,0 +1,221 @@
aiofile==1.4.3
aiofiles==0.4.0
aiohttp==3.5.4
aiohttp-cors==0.7.0
aiosqlite==0.8.0
altgraph==0.16.1
appdirs==1.4.4
argon2-cffi==20.1.0
arrow==0.17.0
asciimatics==1.11.0
asn1crypto==0.24.0
astral==1.9.2
async-timeout==3.0.1
atomicwrites==1.3.0
attrs==18.2.0
backcall==0.2.0
bcrypt==3.1.5
beautifulsoup4==4.6.3
binaryornot==0.4.4
bleach==3.1.5
boltons==18.0.1
boto3==1.9.106
botocore==1.12.106
briefcase==0.3.3
brython==3.6.2
bs4==0.0.1
buildozer==1.2.0
cachetools==4.1.0
certifi==2018.11.29
cffi==1.12.2
chardet==3.0.4
cli-helpers==2.1.0
click==7.1.2
colorama==0.4.3
colosseum==0.2.0
commonmark==0.9.1
configobj==5.0.6
cookiecutter==1.7.2
cryptography==2.9
cycler==0.10.0
Cython==0.29.21
dateparser==0.7.0
decorator==4.4.2
defusedxml==0.6.0
distlib==0.3.1
distro==1.4.0
docutils==0.14
ecdsa==0.16.0
entrypoints==0.3
enum34==1.1.10
envs==1.3
et-xmlfile==1.0.1
face==0.1.0
feedparser==6.0.2
filelock==3.0.12
Flask==0.12.2
Flask-SQLAlchemy==2.3.2
future==0.18.2
gbulb==0.6.1
gitdb==4.0.5
GitPython==3.1.11
glom==18.4.0
gTTS-token==1.1.3
h11==0.9.0
h2==3.2.0
home-assistant-frontend==20190220.0
homeassistant==0.88.2
hpack==3.0.0
humanize==0.5.1
hyperframe==5.2.0
idna==2.7
ifaddr==0.1.6
importlib-metadata==1.6.0
ipykernel==5.3.4
ipython==7.18.1
ipython-genutils==0.2.0
ipywidgets==7.5.1
iso8601==0.1.12
itsdangerous==0.24
jdcal==1.4.1
jedi==0.17.2
Jinja2==2.10
jinja2-time==0.2.0
jmespath==0.9.4
joblib==0.16.0
jsonschema==3.2.0
jupyter==1.0.0
jupyter-client==6.1.7
jupyter-console==6.2.0
jupyter-core==4.6.3
Kivy==1.11.1
Kivy-Garden==0.1.4
kiwisolver==1.0.1
litecli==1.4.1
Logbook==1.5.3
lxml==4.2.5
macholib==1.11
MarkupSafe==1.0
matplotlib==3.0.0
matrix-nio==0.10.0
mistune==0.8.4
MouseInfo==0.1.2
multidict==4.4.2
mutagen==1.42.0
nbconvert==5.6.1
nbformat==5.0.7
netdisco==2.3.0
notebook==6.1.3
Nuitka==0.6.3.1
numpy==1.15.2
opencv-python==4.1.2.30
openpyxl==3.0.3
packaging==20.4
paho-mqtt==1.4.0
pandas==0.24.0
pandocfilters==1.4.2
parso==0.7.1
patsy==0.5.1
peewee==3.13.2
pefile==2018.8.8
pep517==0.6.0
pexpect==4.8.0
pickleshare==0.7.5
Pillow==6.2.1
ply==3.11
poyo==0.5.0
prometheus-client==0.8.0
prompt-toolkit==3.0.7
ptyprocess==0.6.0
PyAutoGUI==0.9.48
pycairo==1.20.0
pycparser==2.19
pycryptodome==3.3.1
pyfiglet==0.8.post1
pygal==2.4.0
PyGetWindow==0.0.8
Pygments==2.6.1
PyGObject==3.38.0
pyjsparser==2.7.1
PyJWT==1.6.4
PyMsgBox==1.0.6
pyodbc==4.0.24
pyOpenSSL==19.1.0
pyotp==2.2.6
pyparsing==2.2.2
pyperclip==1.7.0
PyQRCode==1.2.1
PyRect==0.1.4
pyrsistent==0.16.0
PyScreeze==0.1.25
pyserial==3.4
python-dateutil==2.7.3
python-jose-cryptodome==1.3.2
python-magic==0.4.15
python-olm==3.1.3
python-slugify==4.0.1
python-xlib==0.23
python3-xlib==0.15
pytoml==0.1.21
PyTweening==1.0.3
pytz==2018.9
PyYAML==3.13
pyzmq==19.0.2
qtconsole==4.7.6
QtPy==1.9.0
regex==2019.2.7
requests==2.25.0
rich==9.0.1
ruamel.yaml==0.15.88
s3transfer==0.2.0
scikit-learn==0.23.2
scipy==1.2.0
selenium==3.141.0
Send2Trash==1.5.0
serial==0.0.97
sgmllib3k==1.0.0
sh==1.14.1
simplegeneric==0.8.1
six==1.15.0
sklearn==0.0
slimit==0.8.1
smmap==3.0.4
SQLAlchemy==1.2.2
sqlparse==0.3.1
statsmodels==0.12.0
tabulate==0.8.7
terminado==0.8.3
terminaltables==3.1.0
testpath==0.4.4
text-unidecode==1.3
threadpoolctl==2.1.0
toga-core==0.3.0.dev25
toga-gtk==0.3.0.dev25
toml==0.10.2
tornado==6.0.4
traitlets==4.3.3
travertino==0.1.3
typing-extensions==3.7.4.3
tzlocal==1.5.1
ua-parser==0.8.0
Unidecode==1.0.23
unpaddedbase64==1.1.0
urllib3==1.23
urwid==2.1.0
user-agents==1.1.0
virtualenv==20.1.0
voluptuous==0.11.5
voluptuous-serialize==2.0.0
warrant==0.6.1
wcwidth==0.2.5
webcolors==1.11.1
webencodings==0.5.1
Werkzeug==0.16.0
widgetsnbextension==3.5.1
xlib==0.21
xlrd==1.2.0
xmltodict==0.11.0
yarl==1.2.6
yattag==1.10.0
zeroconf==0.21.3
zipp==3.1.0

53
urls.py Normal file
View File

@ -0,0 +1,53 @@
URLS = {
'login_xiaomi': 'https://account.xiaomi.com/oauth2/authorize?skip_confirm=false&'
'client_id=2882303761517383915&pt=0&scope=1+6000+16001+20000&'
'redirect_uri=https%3A%2F%2Fhm.xiaomi.com%2Fwatch.do&_locale=en_US&response_type=code',
'tokens_amazfit': 'https://api-user.huami.com/registrations/{user_email}/tokens',
'login_amazfit': 'https://account.huami.com/v2/client/login',
'devices': 'https://api-mifit-us2.huami.com/users/{user_id}/devices',
'agps': 'https://api-mifit-us2.huami.com/apps/com.huami.midong/fileTypes/{pack_name}/files',
'data_short': 'https://api-mifit-us2.huami.com/users/{user_id}/deviceTypes/4/data',
'logout': 'https://account-us2.huami.com/v1/client/logout'
}
PAYLOADS = {
'login_xiaomi': None,
'tokens_amazfit': {
'state': 'REDIRECTION',
'client_id': 'HuaMi',
'password': None,
'redirect_uri': 'https://s3-us-west-2.amazonws.com/hm-registration/successsignin.html',
'region': 'us-west-2',
'token': 'access',
'country_code': 'US'
},
'login_amazfit': {
'dn': 'account.huami.com,api-user.huami.com,app-analytics.huami.com,api-watch.huami.com,'
'api-analytics.huami.com,api-mifit.huami.com',
'app_version': '4.3.0-play',
'source': 'com.huami.watch.hmwatchmanager',
'country_code': None,
'device_id': None,
'third_name': None,
'lang': 'en',
'device_model': 'android_phone',
'allow_registration': 'false',
'app_name': 'com.huami.midong',
'code': None,
'grant_type': None
},
'devices': {
'apptoken': None
},
'agps': {
'apptoken': None
},
'data_short': {
'apptoken': None,
'startDay': None,
'endDay': None
},
'logout': {
'login_token': None
},
}