Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wlan_guide_settings api #219

Merged
merged 6 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions examples/initial_setup_e5576-320.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from argparse import ArgumentParser

from huawei_lte_api.Client import Client
from huawei_lte_api.Connection import Connection
from time import sleep

parser = ArgumentParser()
parser.add_argument('--password', type=str)
parser.add_argument('--newpassword', type=str)
parser.add_argument('--ssid', type=str)
parser.add_argument('--wpapassword', type=str)
args = parser.parse_args()

original_password = args.password
new_password = args.newpassword

wifi_ssid = args.ssid
wifi_password = args.wpapassword

url = 'http://192.168.8.1/'
with Connection(url, password=original_password) as connection:
client = Client(connection)

locale = "en-us"
print("Set language to " + locale)
print(client.language.set_current_language(locale))

print("Accept privacy policy")
print(client.app.accept_privacypolicy(approve=True))

print("Set autoupdate config")
print(client.online_update.set_autoupdate_config(autoupdate=True))

print("Set basic information")
print(client.device.set_basic_information())

print(f"Set wlan ({wifi_ssid}/{wifi_password}) and account settings (admin/{new_password})")
resp = client.wlan.set_wlan_guide_settings(
ssid=wifi_ssid, wpa_psk=wifi_password, current_password=original_password, new_password=new_password
)
print(resp)

print("Admin password changed, reconnect...")
sleep(10)
failing = True
while failing:
try:
with Connection(url, password=new_password) as connection:
print("Get basic information")
status = client.monitoring.status()
if status["ConnectionStatus"] == "901":
failing = False
else:
sleep(60)
except Exception as e:
print("Failed with exception: " + str(e) + ", sleeping 60s")
sleep(60)

with Connection(url, password=new_password) as connection:
client = Client(connection)

print("Set basic information")
print(client.device.set_basic_information())

# restart wifi to see effect of the new ssid
# see toggle_wifi.py



5 changes: 3 additions & 2 deletions huawei_lte_api/Session.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def wrapped(*args: Any, **kw: Any) -> T:
args[0].reload()
return fn(*args, **kw)


return wrapped


Expand Down Expand Up @@ -253,8 +254,6 @@ def _post(self,
)
response.raise_for_status()

response_data = cast(str, self._check_response_status(self._process_response_data(response)))

if refresh_csrf:
self.request_verification_tokens = []

Expand All @@ -267,6 +266,8 @@ def _post(self,
else:
_LOGGER.debug('Failed to get CSRF from POST response headers')

response_data = cast(str, self._check_response_status(self._process_response_data(response)))

return response_data

def post_file(self,
Expand Down
21 changes: 20 additions & 1 deletion huawei_lte_api/api/App.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from huawei_lte_api.ApiGroup import ApiGroup
from huawei_lte_api.Session import GetResponseType
from huawei_lte_api.Session import GetResponseType, SetResponseType
from huawei_lte_api.exceptions import ResponseErrorException


class App(ApiGroup):
Expand All @@ -8,3 +9,21 @@ def operatorinfo(self, lang: str = 'en_us') -> GetResponseType:

def privacypolicy(self, lang: str = 'en_us') -> GetResponseType:
return self._session.get('app/privacypolicy', {'lang': lang})

def accept_privacypolicy(self, approve: bool = False) -> SetResponseType:
response = self._session.post_get('app/privacypolicy',
{
"data": {
"Approve": "2" if approve else "0",
"Liscence": "0" # deliberate typo
}
},
is_json=True)
error_code = response["errcode"]
if error_code == 0:
return "OK"

raise ResponseErrorException(
message="Unexpected response: " + str(response),
code=int(error_code)
)
6 changes: 6 additions & 0 deletions huawei_lte_api/api/Device.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ def device_feature_switch(self) -> GetResponseType:
def basic_information(self) -> GetResponseType:
return self._session.get('device/basic_information')

def set_basic_information(self, restore_default_status: bool = False) -> SetResponseType:
return self._session.post_set('device/basic_information',
{
"restore_default_status": 1 if restore_default_status else 0
})

def basicinformation(self) -> GetResponseType:
return self._session.get('device/basicinformation')

Expand Down
4 changes: 4 additions & 0 deletions huawei_lte_api/api/OnlineUpdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,9 @@ def configuration(self) -> GetResponseType:
def autoupdate_config(self) -> GetResponseType:
return self._session.get('online-update/autoupdate-config')

def set_autoupdate_config(self, autoupdate: bool) -> SetResponseType:
return self._session.post_set('online-update/autoupdate-config',
{"auto_update": int(autoupdate is True), "ui_download": 0})

def redirect_cancel(self) -> GetResponseType:
return self._session.get('online-update/redirect_cancel')
68 changes: 42 additions & 26 deletions huawei_lte_api/api/User.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,39 @@ class User(ApiGroup):
def state_login(self) -> GetResponseType:
return self._session.get('user/state-login')

def _login(self, username: str, password: Optional[str], password_type: PasswordTypeEnum = PasswordTypeEnum.BASE_64) -> bool:
def _state_login_with_retry(self) -> GetResponseType:
tries = 5
for i in range(tries):
try:
state_login = self.state_login()
return state_login
except requests.exceptions.ConnectionError:
# Some models reportedly close the connection if we attempt to access login state too soon after
# setting up the session etc. In that case, retry a few times. The error is reported to be
# ConnectionError: (
# 'Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
if i == tries - 1:
raise
time.sleep((i + 1) / 10)

raise ResponseErrorException(message="Tries exhausted", code=0)

def _encode_password(self, username: str, password: Optional[str], password_type: PasswordTypeEnum = PasswordTypeEnum.BASE_64) -> bytes:
if not password:
password_encoded = b''
else:
if password_type == PasswordTypeEnum.SHA256:
concentrated = b''.join([
username.encode('UTF-8'),
base64.b64encode(hashlib.sha256(password.encode('UTF-8')).hexdigest().encode('ascii')),
self._session.request_verification_tokens[0].encode('UTF-8')
])
password_encoded = base64.b64encode(hashlib.sha256(concentrated).hexdigest().encode('ascii'))
else:
password_encoded = base64.b64encode(password.encode('UTF-8'))
return b''

if password_type == PasswordTypeEnum.SHA256:
concentrated = b''.join([
username.encode('UTF-8'),
base64.b64encode(hashlib.sha256(password.encode('UTF-8')).hexdigest().encode('ascii')),
self._session.request_verification_tokens[0].encode('UTF-8')
])
return base64.b64encode(hashlib.sha256(concentrated).hexdigest().encode('ascii'))

return base64.b64encode(password.encode('UTF-8'))

def _login(self, username: str, password: Optional[str], password_type: PasswordTypeEnum = PasswordTypeEnum.BASE_64) -> bool:
password_encoded = self._encode_password(username, password, password_type)
try:
result = self._session.post_set('user/login', {
'Username': username,
Expand Down Expand Up @@ -96,20 +115,11 @@ def _login(self, username: str, password: Optional[str], password_type: Password
def login(self, username: str = DEFAULT_USERNAME, password: Optional[str] = None, force_new_login: bool = False) -> bool:
if username == '': # <= 1.6.4 backwards compatibility
username = DEFAULT_USERNAME
tries = 5
for i in range(tries):
try:
state_login = self.state_login()
except requests.exceptions.ConnectionError:
# Some models reportedly close the connection if we attempt to access login state too soon after
# setting up the session etc. In that case, retry a few times. The error is reported to be
# ConnectionError: (
# 'Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
if i == tries - 1:
raise
time.sleep((i + 1) / 10)
except ResponseErrorNotSupportedException:
return True

try:
state_login = self._state_login_with_retry()
except ResponseErrorNotSupportedException:
return True

if LoginStateEnum(int(state_login['State'])) == LoginStateEnum.LOGGED_IN and not force_new_login:
return True
Expand All @@ -130,6 +140,12 @@ def password(self) -> GetResponseType:
def pwd(self) -> GetResponseType:
return self._session.get('user/pwd')

def set_pwd(self) -> SetResponseType:
return self._session.post_set('user/pwd', {
"module": "wlan",
"nonce": "aaaaaaa"
})

def set_remind(self, remind_state: str) -> SetResponseType:
return self._session.post_set('user/remind', {
'remindstate': remind_state
Expand Down
28 changes: 28 additions & 0 deletions huawei_lte_api/api/WLan.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,5 +257,33 @@ def wifi_network_switch(self, status: bool, criteria: Optional[dict] = None) ->
def wlandbho(self) -> GetResponseType:
return self._session.get('wlan/wlandbho')

def wlan_guide_settings(self) -> GetResponseType:
return self._session.get('wlan/wlan-guide-settings')

def set_wlan_guide_settings(self, ssid: str, wpa_psk: str, current_password: str, new_password: str) -> SetResponseType:
ssids = self.wlan_guide_settings()["Ssids"]["Ssid"]
new_ssid = ssids[0] if len(ssids) > 0 else {"Index": "0"}
new_ssid["WifiSsid"] = ssid
new_ssid["WifiWpapsk"] = wpa_psk

self._session.reload()

data = {
"Ssids": {
"Ssid": [new_ssid]
},
"rebootInfo": {
"isReboot": 0
},
"accountInfo": {
"currentpassword": current_password,
"newpassword": new_password,
"confirmpwd": new_password}
}
return self._session.post_set('wlan/wlan-guide-settings',
data,
refresh_csrf=True,
is_encrypted=True)

def wlanintelligent(self) -> GetResponseType:
return self._session.get('wlan/wlanintelligent')
2 changes: 1 addition & 1 deletion huawei_lte_api/enums/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ class ResponseCodeEnum(enum.IntEnum):
ERROR_VOICE_BUSY = 120001 # Unused
ERROR_WRONG_TOKEN = 125001 # Unused
ERROR_SYSTEM_CSRF = 125002
ERROR_WRONG_SESSION_TOKEN = 125003 # Unused
ERROR_WRONG_SESSION_TOKEN = 125003
Loading