#!/usr/bin/python # Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from Crypto.Cipher import AES import random import requests import socket import struct import threading import time from . import lakeside_pb2 key = bytearray([0x24, 0x4E, 0x6D, 0x8A, 0x56, 0xAC, 0x87, 0x91, 0x24, 0x43, 0x2D, 0x8B, 0x6C, 0xBC, 0xA2, 0xC4]) iv = bytearray([0x77, 0x24, 0x56, 0xF2, 0xA7, 0x66, 0x4C, 0xF3, 0x39, 0x2C, 0x35, 0x97, 0xE9, 0x3E, 0x57, 0x47]) def get_devices(username, password): devices = []; client_id = "eufyhome-app" client_secret = "GQCpr9dSp3uQpsOMgJ4xQ" payload = {'client_id':client_id, 'client_Secret':client_secret, 'email':username, 'password':password} r = requests.post("https://home-api.eufylife.com/v1/user/email/login", json=payload) token = r.json()['access_token'] headers = {'token': token, 'category': 'Home'} r = requests.get("https://home-api.eufylife.com/v1/device/list/devices-and-groups", headers=headers) info = r.json() for item in info['items']: if item['device'] is not None: devices.append({ 'address': item['device']['wifi']['lan_ip_addr'], 'code': item['device']['local_code'], 'type': item['device']['product']['product_code'], 'name': item['device']['alias_name'], 'id': item['device']['id'], }) return devices class device: def __init__(self, address, code, kind=None): self.address = address self.code = code self.kind = kind self.keepalive = None def connect(self): self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s.connect((self.address, 55556)) self.update() if self.keepalive is None: self.keepalive = threading.Thread(target=self.ping, args=()) self.keepalive.daemon = True self.keepalive.start() def send_packet(self, packet, response): cipher = AES.new(bytes(key), AES.MODE_CBC, bytes(iv)) raw_packet = packet.SerializeToString() for i in range(16 - (len(raw_packet) % 16)): raw_packet += b'\0' encrypted_packet = cipher.encrypt(raw_packet) try: self.s.send(encrypted_packet) except: self.connect() self.s.send(encrypted_packet) if response: data = self.s.recv(1024) if (len(data) == 0): self.connect() self.s.send(encrypted_packet) data = self.s.recv(1024) cipher = AES.new(bytes(key), AES.MODE_CBC, bytes(iv)) decrypted_packet = cipher.decrypt(data) length = struct.unpack("