MikroWizard.mikroman/py/mules/updater.py
sepehr 70dc0ddc55 Bugs:
Fixed Firmware download from the Mikrotik website when there are multiple npk available
Fixed Mikrowizard system permission error when it is set to None
Fixed user device group permissions
Some minor UI improvements
Fix IP scan for one IP scan / Fix not scanning the last IP in the range
Fix manual snippet execution not working when device groups are selected
Some minor bug fixes and improvements

New:
Show background tasks and be able to stop them while running in the background (like an IP scanner)
Add support for manual MikroWizard update dashboard/settings page
update to version 1.0.5

Enhancement:
Show permission error in some pages when the  user doesn't have permission for that page/action
show better charts/graphs in the dashboard and device interface details
show more info on the dashboard about update and version information and license
2025-01-02 20:12:00 +03:00

203 lines
6.8 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
# updater.py: independent worker process for updating MikroWizard to latest version
# MikroWizard.com , Mikrotik router management solution
# Author: sepehr.ha@gmail.com
import time
import datetime
from libs import util
from pathlib import Path
from libs.db import db_sysconfig
import requests
import logging
import os
import hashlib
import zipfile
import subprocess
import json
log = logging.getLogger("Updater_mule")
import pip
def import_or_install(package):
try:
__import__(package)
except ImportError:
pip.main(['install', package])
def install_package(package):
try:
pip.main(['install', package])
except Exception as e:
log.error(e)
def set_get_install_date():
install_date=False
try:
install_date=db_sysconfig.get_sysconfig('install_date')
except:
pass
if not install_date:
install_date=datetime.datetime.now()
db_sysconfig.set_sysconfig('install_date',install_date.strftime("%Y-%m-%d %H:%M:%S"))
install_date=install_date.strftime("%Y-%m-%d %H:%M:%S")
return install_date
# Example usage
def check_sha256(filename, expect):
"""Check if the file with the name "filename" matches the SHA-256 sum
in "expect"."""
h = hashlib.sha256()
# This will raise an exception if the file doesn't exist. Catching
# and handling it is left as an exercise for the reader.
try:
with open(filename, 'rb') as fh:
# Read and hash the file in 4K chunks. Reading the whole
# file at once might consume a lot of memory if it is
# large.
while True:
data = fh.read(4096)
if len(data) == 0:
break
else:
h.update(data)
return expect == h.hexdigest()
except Exception as e:
return False
def extract_zip_reload(filename,dst):
return True
"""Extract the contents of the zip file "filename" to the directory
"dst". Then reload the updated modules."""
with zipfile.ZipFile(filename, 'r') as zip_ref:
zip_ref.extractall(dst)
# run db migrate
dir ="/app/"
cmd = "cd {}; PYTHONPATH={}py PYSRV_CONFIG_PATH={} python3 scripts/dbmigrate.py".format(dir, dir, "/conf/server-conf.json")
p = subprocess.Popen(cmd, shell=True)
(output, err) = p.communicate()
#This makes the wait possible
p_status = p.wait()
#install requirments
try:
proreqs="/app/py/pro-reqs.txt"
with open(proreqs, "r") as f:
for line in f:
import_or_install(line.strip())
log.info("Installed {}".format(line.strip()))
time.sleep(1)
time.sleep(3)
except ImportError:
pass
reqs="/app/reqs.txt"
with open(reqs, "r") as f:
for line in f:
try:
install_package(line.strip())
except:
pass
os.remove(filename)
#touch server reload file /app/reload
Path('/app/reload').touch()
def main():
while True:
try:
from libs import utilpro
ISPRO=True
except ImportError:
ISPRO=False
pass
next_hour = (time.time() // 3600 + 1) * 3600
sleep_time = next_hour - time.time()
# Code to be executed every hour
print("Running hourly Update checker ...")
interfaces = util.get_ethernet_wifi_interfaces()
hwid = util.generate_serial_number(interfaces)
update_mode=db_sysconfig.get_sysconfig('update_mode')
update_mode=json.loads(update_mode)
if update_mode['mode']=='manual':
if not update_mode['update_back']:
hwid=hwid+"MANUAL"
else:
update_mode['update_back']=False
db_sysconfig.set_sysconfig('update_mode',json.dumps(update_mode))
username=False
try:
username = db_sysconfig.get_sysconfig('username')
except:
log.error("No username found")
# util.send_mikrowizard_request(params)
if not username or username.strip()=="":
log.error("No username found")
time.sleep(300)
continue
install_date=set_get_install_date()
from _version import __version__
#convert install_date string "%Y-%m-%d %H:%M:%S" to datetime
install_date = datetime.datetime.strptime(install_date, "%Y-%m-%d %H:%M:%S").strftime("%Y%m%d")
# convert install_date from "%Y-%m-%d %H:%M:%S" to ""%Y%m%d"" and append to serial_number
hwid += "-"+install_date
params={
"serial_number": hwid,
"username": username.strip(),
"version": __version__,
"ISPRO":ISPRO
}
res=False
url="https://mikrowizard.com/wp-json/mikrowizard/v1/get_update"
# send post request to server mikrowizard.com with params in json
try:
response = requests.post(url, json=params)
res = response
except:
time.sleep(sleep_time)
continue
# get response from server
try:
if res and res.status_code == 200:
res=res.json()
if 'token' in res:
params={
"token":res['token'],
"file_name":res['filename'],
"username":username.strip()
}
log.info("Update available/Downloading...")
else:
time.sleep(sleep_time)
continue
except Exception as e:
log.error(e)
# check if filename exist in /app/ and checksum is same then dont continue
if check_sha256("/app/"+res['filename'], res['sha256']):
log.error("Checksum match, File exist")
extract_zip_reload("/app/"+res['filename'],"/app/")
time.sleep(sleep_time)
continue
download_url="https://mikrowizard.com/wp-json/mikrowizard/v1/download_update"
# send post request to server mikrowizard.com with params in json
r = requests.post(download_url,json=params,stream=True)
if "invalid" in r.text or r.text=='false':
log.error("Invalid response")
time.sleep(sleep_time)
continue
with open("/app/"+res['filename'], 'wb') as fd:
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
if check_sha256("/app/"+res['filename'], res['sha256']):
log.error("Update downloaded : "+"/app/"+res['filename'])
extract_zip_reload("/app/"+res['filename'],"/app/")
else:
log.error("Checksum not match")
os.remove("/app/"+res['filename'])
time.sleep(sleep_time)
if __name__ == '__main__':
main()