diff --git a/README.md b/README.md index 677d463..ce9530c 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,11 @@ You can find **Full Project Documentation** [here][documentation_path] ## Mission `tenda-everest` is python package to manage Tenda Everest router. -This package was tested on **EVEREST EWR-F303** Wireless Router with **Tenda** firmware **V02.03.01.125** -(and similar). But this package may work on different routers with other firmwares. + +This package was tested on **EVEREST EWR-F303** Wireless Router with **Tenda** firmware **V02.03.01.125**. +It also works with **V12.01.01.33_multi** but may be with some problems. +It could work with other similar firmwares. +But this package may work on different routers with other firmwares. ![Everest ewr-f303 router picture](https://github.com/quillcraftsman/tenda-everest/blob/main/everest.jpeg) @@ -117,9 +120,27 @@ See more in [Full Documentation](https://quillcraftsman.github.io/tenda-everest/ ## Quickstart ```python -from tenda_everest import info +import pprint +import requests +from tenda_everest import login, get_info, MODULES, request_firmware + +host = 'http://192.168.0.1:8081' # There is device located + +session = login(requests, host) # connect to device and login + +firmware = request_firmware(host, session) # check router firmware +print(firmware) + +modules = ( # What do you want to know + MODULES.systemInfo, + MODULES.wanBasicCfg, + MODULES.wifiBasicCfg, + MODULES.softWare, +) + +info = get_info(host, session, modules, firmware=firmware) -print(info()) +pprint.pprint(info) ``` ### More examples in [Full Documentation][documentation_path] diff --git a/docs/about.rst b/docs/about.rst index 054ca8b..ea65735 100644 --- a/docs/about.rst +++ b/docs/about.rst @@ -15,8 +15,11 @@ Mission ------- **tenda-everest** is python package to manage Tenda Everest router. -This package was tested on **EVEREST EWR-F303** Wireless Router with **Tenda** firmware **V02.03.01.125** -(and similar). But this package may work on different routers with other firmwares. + +This package was tested on **EVEREST EWR-F303** Wireless Router with **Tenda** firmware **V02.03.01.125**. +It also works with **V12.01.01.33_multi** but may be with some problems. +It could work with other similar firmwares. +But this package may work on different routers with other firmwares. Open Source Project ------------------- diff --git a/quickstart/main.py b/quickstart/main.py index 0fa3e32..096b036 100644 --- a/quickstart/main.py +++ b/quickstart/main.py @@ -8,6 +8,24 @@ def main(): TendaEverest simple usage :return: """ - from tenda_everest import info # pylint: disable=import-outside-toplevel + import pprint # pylint: disable=import-outside-toplevel + import requests # pylint: disable=import-outside-toplevel + from tenda_everest import login, get_info, MODULES, request_firmware # pylint: disable=import-outside-toplevel - print(info()) + host = 'http://192.168.0.1:8081' # There is device located + + session = login(requests, host) # connect to device and login + + firmware = request_firmware(host, session) # check router firmware + print(firmware) + + modules = ( # What do you want to know + MODULES.systemInfo, + MODULES.wanBasicCfg, + MODULES.wifiBasicCfg, + MODULES.softWare, + ) + + info = get_info(host, session, modules, firmware=firmware) + + pprint.pprint(info) diff --git a/tenda_everest/__init__.py b/tenda_everest/__init__.py index c5b584c..70aebe9 100644 --- a/tenda_everest/__init__.py +++ b/tenda_everest/__init__.py @@ -1,4 +1,4 @@ """ TendaEverest package """ -from .main import info +from .main import login, get_info, MODULES, request_firmware diff --git a/tenda_everest/main.py b/tenda_everest/main.py index bf2932b..79d4c13 100644 --- a/tenda_everest/main.py +++ b/tenda_everest/main.py @@ -1,10 +1,160 @@ """ Main module """ +from enum import Enum, verify, UNIQUE, auto +DEFAULT_FIRMWARE = 'V02.03.01.125' -def info(): +def login(requests, host): """ Info """ - return 'First steps with TendaEverest' + session = requests.session() + + url = '/login/Auth' + + referer = f'{host}/login.html' + + headers = { + 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:130.0) ' + 'Gecko/20100101 Firefox/130.0', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,' + 'image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Connection': 'keep-alive', + 'Referer': referer + + } + + data = { + 'password': "YWRtaW4=" # admin coded in base64 + } + + request_url = f'{host}{url}' + + session.post( + url=request_url, + headers=headers, + data=data + ) + + return session + +# pylint:disable=invalid-name +@verify(UNIQUE) +class MODULES(Enum): + """ + Available modules + """ + systemInfo = auto() + wifiBasicCfg = auto() + wanBasicCfg = auto() + softWare = auto() + wifiBeamforming = auto() + onlineList = auto() + hasNewSoftVersion = auto() + portList = auto() + sysTime = auto() + wifiRelay = auto() + parentAccessCtrl = auto() + ipv6Status = auto() + LEDControl = auto() + ping = auto() + wifiTime = auto() + parentCtrlList = auto() + macFilter = auto() + internetStatus = auto() + IPTV = auto() + guestList = auto() + lan6Cfg = auto() + wan6BasicCfg = auto() + ipv6Enable = auto() + deviceStatistics = auto() + lanCfg = auto() + wanAdvCfg = auto() + productInfo = auto() + wpsModule = auto() + upnp = auto() + wifiAdvCfg = auto() + staticIPList = auto() + isWifiClients = auto() + localhost = auto() + wifiGuest = auto() + wifiWPS = auto() + remoteWeb = auto() + dmz = auto() + wifiPower = auto() + loginAuth = auto() + ddns = auto() + + +def get_request_urls(firmware=DEFAULT_FIRMWARE, modules=None): + """ + get different urls for request + """ + if firmware == 'V12.01.01.33_multi': + module_urls = { + MODULES.systemInfo: 'getStatus', + MODULES.wanBasicCfg: 'getWAN', + MODULES.wifiBasicCfg: 'getWifi', + MODULES.softWare: 'getSysTools', + } + result = [] + if modules: + for module in modules: + if module in module_urls: + result.append(module_urls[module]) + else: + result.append('getStatus') + else: + result.append('getStatus') + return result + + return ['getStatus'] + + +def get_info(host, session, modules=(MODULES.systemInfo,), firmware=DEFAULT_FIRMWARE): + """ + Get info using different modules + """ + available_modules = [module.name for module in modules] + modules_str = ','.join(list(available_modules)) + + request_urls = get_request_urls(firmware, modules) + + result = {} + for url_item in request_urls: + + url = f'/goform/{url_item}?modules={modules_str}' + + headers = { + 'User-Agent': + 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0', + 'Accept': '*/*', + 'Accept-Language': 'en-US,en;q=0.5', + } + + request_url = f'{host}{url}' + + cookies = { + 'bLanguage': 'en', + 'ecos_pw': 'ecos_pw=YWRtaW4=wdv:language=cn' # admin in base64 + } + + response = session.get( + url=request_url, + headers=headers, + cookies=cookies, + ) + + result.update(response.json()) + + return result + +def request_firmware(host, session): + """ + Request router current firmware + """ + info = get_info(host, session, modules=(MODULES.systemInfo,)) + return info['systemInfo']['softVersion'] diff --git a/tenda_everest/package.py b/tenda_everest/package.py index 7b58153..ef67aec 100644 --- a/tenda_everest/package.py +++ b/tenda_everest/package.py @@ -2,5 +2,5 @@ Package info """ name = 'tenda-everest' -version = '0.1.0' +version = '0.2.0' status = '3 - Alpha' \ No newline at end of file diff --git a/testing/test_tenda_everest/conftest.py b/testing/test_tenda_everest/conftest.py new file mode 100644 index 0000000..3dcb211 --- /dev/null +++ b/testing/test_tenda_everest/conftest.py @@ -0,0 +1,14 @@ +# import requests +import testing.test_tenda_everest.mocks as mocks +from pytest import fixture + + +@fixture +def requests_module(): + # return requests + return mocks + +@fixture +def host(): + return '9.9.9.9' + # return 'http://10.173.1.142:8081' diff --git a/testing/test_tenda_everest/mocks/__init__.py b/testing/test_tenda_everest/mocks/__init__.py new file mode 100644 index 0000000..9274a61 --- /dev/null +++ b/testing/test_tenda_everest/mocks/__init__.py @@ -0,0 +1,34 @@ +from tenda_everest import MODULES +from testing.test_tenda_everest.mocks.expected import expected_info + +class MockResponse: + + def __init__(self, url): + self.modules = self.get_modules(url) + + def json(self): + result = {} + for module in self.modules: + enum_module = MODULES[module] + value = expected_info[enum_module] + result.update(value) + + return result + + def get_modules(self, url): + host, params = url.split('?') + module, values = params.split('=') + modules = values.split(',') + return modules + + +class MockSession: + + def get(self, url, *args, **kwargs): + return MockResponse(url) + + def post(self, *args, **kwargs): + pass + +def session(): + return MockSession() diff --git a/testing/test_tenda_everest/mocks/expected.py b/testing/test_tenda_everest/mocks/expected.py new file mode 100644 index 0000000..bafb2af --- /dev/null +++ b/testing/test_tenda_everest/mocks/expected.py @@ -0,0 +1,63 @@ +from tenda_everest import MODULES + +hidden_mac = 'XX:XX:XX:XX:XX:XX' +hidden_dns = 'XX.XX.XXX.XXX' +hidden_key = '********' +hidden_user = 'user' +hidden_ssid = 'SSID' + +expected_systemInfo = { + 'systemInfo': { + 'lanIP': '192.168.0.1', + 'lanMask': '255.255.255.0', + 'macHost': hidden_mac, + 'softVersion': 'V02.03.01.125', + 'statusWanDns1': hidden_dns, + 'statusWanDns2': '1.1.1.1', + 'statusWanGaterway': '10.173.255.1', + 'statusWanIP': '10.173.1.142', + 'statusWanMAC': hidden_mac, + 'statusWanMask': '255.255.255.254', + 'wanConnectTime': '66039', + 'wanType': 'pppoe' + } +} + +expected_wanBasicCfg = { + 'wanBasicCfg': { + 'wanDns1': hidden_dns, + 'wanDns2': '1.1.1.1', + 'wanGateway': '10.173.255.1', + 'wanIP': '10.173.1.142', + 'wanMask': '255.255.255.254', + 'wanPPPoEPwd': hidden_key, + 'wanPPPoEUser': hidden_user, + 'wanType': 'pppoe' + } +} + +expected_wifiBasicCfg = { + 'wifiBasicCfg': { + 'HasDoubleBandUnity': 'true', + 'doubleBandUnityEnable': 'false', + 'wifiEn': 'true', + 'wifiEn_5G': 'true', + 'wifiHideSSID': 'false', + 'wifiHideSSID_5G': 'false', + 'wifiNoPwd': 'false', + 'wifiNoPwd_5G': 'false', + 'wifiPwd': hidden_key, + 'wifiPwd_5G': hidden_key, + 'wifiSSID': hidden_ssid, + 'wifiSSID_5G': hidden_ssid, + 'wifiSecurityMode': 'WPAWPA2/AES', + 'wifiSecurityMode_5G': 'WPAWPA2/AES', + 'wifiTotalEn': 'true' + } +} + +expected_info = { + MODULES.systemInfo: expected_systemInfo, + MODULES.wanBasicCfg: expected_wanBasicCfg, + MODULES.wifiBasicCfg: expected_wifiBasicCfg +} diff --git a/testing/test_tenda_everest/test_main.py b/testing/test_tenda_everest/test_main.py index ed56996..2bff0cf 100644 --- a/testing/test_tenda_everest/test_main.py +++ b/testing/test_tenda_everest/test_main.py @@ -1,13 +1,76 @@ """ Test main """ -from tenda_everest import info +from tenda_everest import login, get_info, request_firmware, MODULES +from tenda_everest.main import get_request_urls +from testing.test_tenda_everest.mocks.expected import expected_info -def test_info(): +def test_get_request_urls_default(): """ - Test info - :return: None + test default usage """ - info_expected_text = 'First steps with TendaEverest' - assert info() == info_expected_text + assert ['getStatus'] == get_request_urls() + +def test_get_request_urls_no_modules(): + """ + test when no modules + """ + urls = get_request_urls(firmware='V12.01.01.33_multi') + assert ['getStatus'] == urls + +def test_get_request_urls_multi(): + """ + Test for multi firmware + """ + modules = [ + MODULES.systemInfo, + MODULES.wifiBasicCfg, + MODULES.wanBasicCfg, + MODULES.dmz, # unknown, + MODULES.softWare, + ] + urls = get_request_urls(firmware='V12.01.01.33_multi', modules=modules) + + expected_result = [ + 'getStatus', + 'getWifi', + 'getWAN', + 'getStatus', + 'getSysTools', + ] + + assert urls == expected_result + + +def test_get_info(requests_module, host): + """ + Test for get_info + """ + # login + session = login(requests_module, host) + + # request_firmware + + firmware = request_firmware(host, session) + assert firmware == 'V02.03.01.125' + + info = get_info( + host, + session, + modules=( + MODULES.systemInfo, + MODULES.wanBasicCfg, + MODULES.wifiBasicCfg, + ) + ) + + expected_result = {} + expected_result.update(expected_info[MODULES.systemInfo]) + expected_result.update(expected_info[MODULES.wanBasicCfg]) + expected_result.update(expected_info[MODULES.wifiBasicCfg]) + + # del expected_result['systemInfo']['wanConnectTime'] + # del info['systemInfo']['wanConnectTime'] + + assert expected_result == info diff --git a/v12.01.01.33_multi.examples.txt b/v12.01.01.33_multi.examples.txt new file mode 100644 index 0000000..c164977 --- /dev/null +++ b/v12.01.01.33_multi.examples.txt @@ -0,0 +1,15 @@ +http://10.173.7.211:8081/goform/getHomePageInfo??random=0.37546801752695846&modules=loginAuth,wifiRelay +http://10.173.7.211:8081/goform/getStatus?random=0.008002568520880549&modules=internetStatus,deviceStatistics,systemInfo,wanAdvCfg +http://10.173.7.211:8081/goform/getWAN?0.6800180561540222=&modules=internetStatus +http://10.173.7.211:8081/goform/getWAN?random=0.13262705387122975&modules=lanCfg,wanBasicCfg,wanAdvCfg,internetStatus +http://10.173.7.211:8081/goform/getWifi?0.48748204191666955=&modules=wifiAdvCfg,wifiTime +http://10.173.7.211:8081/goform/getWifi?random=0.964325119634537&modules=wifiEn,wifiBasicCfg,wifiAdvCfg,wifiPower,wifiTime,wifiWPS +http://10.173.7.211:8081/goform/getQos?random=0.7227449516358969&modules=localhost,onlineList,blackList +http://10.173.7.211:8081/goform/getWifiRelay?random=0.2977282984888068&modules=wifiEn%2CwifiRelay +http://10.173.7.211:8081/goform/getQos??random=0.9122857382762711&modules=localhost,onlineList,blackList +http://10.173.7.211:8081/goform/getParentControl?random=0.6234278390597141&modules=parentCtrlList,parentAccessCtrl +http://10.173.7.211:8081/goform/getNAT?0.2765616824131101=&modules=ddns +http://10.173.7.211:8081/goform/getNAT?random=0.4009191262145818&modules=staticIPList,portList,ddns,dmz,upnp,lanCfg +http://10.173.7.211:8081/goform/getNAT?0.645456203545996=&modules=ddns +http://10.173.7.211:8081/goform/getSysTools?0.9006648912763681=&modules=sysTime +http://10.173.7.211:8081/goform/getSysTools?random=0.07916970103058285&modules=loginAuth,wanAdvCfg,lanCfg,softWare,wifiRelay,sysTime,remoteWeb,isWifiClients,systemInfo \ No newline at end of file