You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
345 lines
9.6 KiB
Python
345 lines
9.6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
|
|
import xmir_base
|
|
from gateway import *
|
|
|
|
cwd = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
gw = Gateway()
|
|
|
|
FN_lua = f'tmp/XQFeatures.lua'
|
|
fn_lua = '/tmp/XQFeatures.lua'
|
|
FN_patch = f'tmp/unlockf_patch.sh'
|
|
fn_patch = '/tmp/unlockf_patch.sh'
|
|
FN_install = f'tmp/unlockf_install.sh'
|
|
fn_install = '/tmp/unlockf_install.sh'
|
|
FN_uninstall = f'tmp/unlockf_uninstall.sh'
|
|
fn_uninstall = '/tmp/unlockf_uninstall.sh'
|
|
|
|
os.makedirs('tmp', exist_ok = True)
|
|
|
|
DEF_FEATURES = {
|
|
"system": {
|
|
"shutdown": "0",
|
|
"downloadlogs": "0",
|
|
"i18n": "0",
|
|
"infileupload": "1",
|
|
"task": "0",
|
|
"upnp": "1",
|
|
"new_update": "1",
|
|
"multiwan": "0", # def: 0 # misc.features.multiwan
|
|
"support_1000_dhcp": "1",
|
|
"ipv6_wired": "0",
|
|
"ipv6_wired_v2": "1",
|
|
"plugin_install": "0", # def: 0
|
|
"GdprPrivacy": "1",
|
|
"international": "1",
|
|
"ipv6oversea": "0",
|
|
"set_router_location": "0",
|
|
"upgraded_light_color": "1",
|
|
"change_time": "0", # def: 0
|
|
"newRouterPwd": "1",
|
|
"https": "1",
|
|
"ipv6_passthrough_relay": "1",
|
|
"vpn_init": "1",
|
|
"mesh_bhtype_mode": "0",
|
|
"ipmaccheck": "0",
|
|
"map_e": "1",
|
|
"dslite": "1",
|
|
"map_e_ocn": "1",
|
|
},
|
|
"wifi": {
|
|
"wifi24": "1",
|
|
"wifi50": "1",
|
|
"wifiguest": "1",
|
|
"wifimerge": "1",
|
|
"wifi_mu_mimo": "0",
|
|
"twt": "1",
|
|
"mlo": "1",
|
|
"mlo_vap": "1",
|
|
"split5g": "0",
|
|
"silence_switch": "0",
|
|
"wifi_access_ctl": "0", # misc.features.supportWifiAccessCtl # wifiaccess.cfg.enable
|
|
"iot_dev": "0", # misc.features.iot_dev
|
|
"easymesh_switch": "0",
|
|
},
|
|
"apmode": {
|
|
"wifiapmode": "1", # misc.features.supportWifiAp
|
|
"lanapmode": "1",
|
|
},
|
|
"netmode": {
|
|
"elink": "1",
|
|
"net2.5G": "0",
|
|
"net10G": "0",
|
|
},
|
|
"apps": {
|
|
"apptc": "0",
|
|
"qos": "1",
|
|
"dhcpMsg": "1",
|
|
"upnp": "1",
|
|
"nfc": "0",
|
|
"wanLan": "1",
|
|
"mipctlv2": "0",
|
|
"lanPort": "1",
|
|
"xqdatacenter": "1",
|
|
"baidupan": "0",
|
|
"timemachine": "0",
|
|
"storage": "0",
|
|
"samba": "0",
|
|
"docker": "0",
|
|
"swapmask": "3", # 0..7
|
|
"ports_custom": "1",
|
|
"LED_control": "1", # 0..7
|
|
"firewall": "0",
|
|
"local_gw_security": "0",
|
|
"download": "0",
|
|
"temp_control": "0",
|
|
"sec_center": "0", # 0..2
|
|
"sfp": "0",
|
|
"game_port": "0", # def: 0 # misc.features.game # misc.wireless.wl_if_count=3
|
|
"lan_lag": "1",
|
|
"telnet": "0",
|
|
},
|
|
"hardware": {
|
|
"usb": "0",
|
|
"usb_deploy": "0",
|
|
"disk": "0",
|
|
}
|
|
}
|
|
|
|
FEATURES = DEF_FEATURES.copy()
|
|
patched_features = { }
|
|
|
|
def patch_feature(node_name, fname, value, cfg_patch = None):
|
|
FEATURES[node_name][fname] = value
|
|
pname = f'{node_name}.{fname}'
|
|
if pname not in patched_features:
|
|
patched_features[pname] = [ ]
|
|
if cfg_patch:
|
|
patched_features[pname].extend(cfg_patch)
|
|
|
|
####################################################################################
|
|
# Edit me please
|
|
patch_feature('system', 'i18n', "1")
|
|
patch_feature('system', 'multiwan', "1", [ "misc.features.multiwan=1" ] )
|
|
patch_feature('system', 'plugin_install', "1")
|
|
patch_feature('system', 'change_time', "1")
|
|
patch_feature('wifi', 'wifi_access_ctl', "1", [ "misc.features.supportWifiAccessCtl=1", "wifiaccess.cfg.enable=1" ] )
|
|
# patch_feature('apps', 'game_port', "1", [ "misc.features.game=1" ] )
|
|
# patch_feature('apps', '__w3__', "1", [ "misc.wireless.wl_if_count=3" ] )
|
|
patch_feature('apps', 'baidupan', "1")
|
|
#
|
|
####################################################################################
|
|
|
|
lua_table = [ ]
|
|
lua_table.append('FEATURES = {')
|
|
|
|
def parse_feature(depth, elem_dict):
|
|
prefix = ' ' * depth if depth >= 1 else ''
|
|
for key, elem in elem_dict.items():
|
|
if isinstance(elem, dict):
|
|
lua_table.append(prefix + f'["{key}"] = ' + '{')
|
|
parse_feature(depth + 1, elem)
|
|
else:
|
|
if isinstance(elem, int) or isinstance(elem, float):
|
|
value = f'{elem}'
|
|
else:
|
|
value = f'"{elem}"'
|
|
lua_table.append(prefix + f'["{key}"] = {value},')
|
|
if key == list(elem_dict)[-1]:
|
|
lua_table.append(prefix + f'["__end__"] = "0"')
|
|
prefix_new = ' ' * (depth - 1) if depth >= 2 else ''
|
|
lua_table.append(prefix_new + '},')
|
|
|
|
parse_feature(1, FEATURES)
|
|
lua_table[-1] = ' }'
|
|
lua_table.append('}')
|
|
|
|
XQFeatures = '''#!/usr/bin/lua
|
|
module "xiaoqiang.XQFeatures"
|
|
'''
|
|
XQFeatures += '\n' + '\n'.join(lua_table) + '\n'
|
|
with open(FN_lua, 'w', newline = '\n') as file:
|
|
file.write(XQFeatures)
|
|
|
|
unlockf_patch = '''#!/bin/sh
|
|
INST_FLAG_FN=/tmp/unlockf_patch.log
|
|
|
|
[ -e "$INST_FLAG_FN" ] && return 0
|
|
|
|
DIR_PATCH=/etc/crontabs/patches
|
|
DIR_BACKUP=$DIR_PATCH/unlockf_backup
|
|
|
|
TARGET_DIR=/usr/lib/lua/xiaoqiang
|
|
MIRROR_DIR=/tmp/_usr_lib_lua_xiaoqiang
|
|
SYNCOBJECT=$MIRROR_DIR.sync
|
|
|
|
if [ ! -f $DIR_PATCH/XQFeatures.lua ; then
|
|
return 0
|
|
fi
|
|
|
|
for i in $(seq 1 45); do
|
|
mkdir $SYNCOBJECT &> /dev/null && break
|
|
sleep 1
|
|
done
|
|
if ! mount | grep -q " on $TARGET_DIR" ; then
|
|
mkdir -p $MIRROR_DIR
|
|
cp -rf $TARGET_DIR/* $MIRROR_DIR/
|
|
mount --bind $MIRROR_DIR $TARGET_DIR
|
|
fi
|
|
|
|
if [ ! -f $MIRROR_DIR/XQFeatures.lua ]; then
|
|
rm -rf $SYNCOBJECT
|
|
return 1 # error
|
|
fi
|
|
|
|
# replace XQFeatures.lua
|
|
cp -f $DIR_PATCH/XQFeatures.lua $MIRROR_DIR/XQFeatures.lua
|
|
|
|
rm -rf $SYNCOBJECT
|
|
|
|
### patch misc config ###
|
|
|
|
uci set misc.features.xmir_unlockf=1
|
|
uci commit misc
|
|
|
|
echo "unlockf enabled" > /tmp/unlockf_patch.log
|
|
'''
|
|
misc_patch = ''
|
|
for keyname, value in patched_features.items():
|
|
vlist = value if isinstance(value, list) else [ value ]
|
|
for val in vlist:
|
|
if val:
|
|
cfg_fn = val.split('.')[0]
|
|
misc_patch += f'uci set {val}' + '\n'
|
|
misc_patch += f'uci commit {cfg_fn}' + '\n'
|
|
|
|
unlockf_patch = unlockf_patch.replace('### patch misc config ###', misc_patch)
|
|
|
|
with open(FN_patch, 'w', newline = '\n') as file:
|
|
file.write(unlockf_patch)
|
|
|
|
unlockf_install = '''#!/bin/sh
|
|
INST_FLAG_FN=/tmp/unlockf_patch.log
|
|
|
|
DIR_PATCH=/etc/crontabs/patches
|
|
DIR_BACKUP=$DIR_PATCH/unlockf_backup
|
|
|
|
TARGET_DIR=/usr/lib/lua/xiaoqiang
|
|
MIRROR_DIR=/tmp/_usr_lib_lua_xiaoqiang
|
|
SYNCOBJECT=$MIRROR_DIR.sync
|
|
|
|
if [ ! -f /tmp/XQFeatures.lua ]; then
|
|
return 1
|
|
fi
|
|
|
|
if [ ! -d $DIR_PATCH ]; then
|
|
mkdir -p $DIR_PATCH
|
|
chown root $DIR_PATCH
|
|
chmod 0755 $DIR_PATCH
|
|
fi
|
|
|
|
CLEAN_INSTALL=0
|
|
if [ ! -d $DIR_BACKUP ]; then
|
|
CLEAN_INSTALL=1
|
|
mkdir -p $DIR_BACKUP
|
|
if [ -f $DIR_BACKUP/misc ]; then
|
|
cp -f /etc/config/misc $DIR_BACKUP/misc
|
|
fi
|
|
fi
|
|
if [ $CLEAN_INSTALL = 1 ]; then
|
|
NEED_RESTORE_MNT=0
|
|
if mount | grep -q " on $TARGET_DIR" ; then
|
|
umount -l $TARGET_DIR
|
|
NEED_RESTORE_MNT=1
|
|
fi
|
|
if [ ! -f $DIR_BACKUP/XQFeatures.lua ]; then
|
|
cp -f $TARGET_DIR/XQFeatures.lua $DIR_BACKUP/XQFeatures.lua
|
|
fi
|
|
[ $NEED_RESTORE_MNT = 1 ] && mount --bind $MIRROR_DIR $TARGET_DIR
|
|
fi
|
|
|
|
mv -f /tmp/XQFeatures.lua $DIR_PATCH/
|
|
mv -f /tmp/unlockf_patch.sh $DIR_PATCH/
|
|
chmod +x $DIR_PATCH/unlockf_patch.sh
|
|
|
|
uci set firewall.auto_unlockf_patch=include
|
|
uci set firewall.auto_unlockf_patch.type='script'
|
|
uci set firewall.auto_unlockf_patch.path="$DIR_PATCH/unlockf_patch.sh"
|
|
uci set firewall.auto_unlockf_patch.enabled='1'
|
|
uci commit firewall
|
|
|
|
rm -f $INST_FLAG_FN
|
|
|
|
# run patch
|
|
$DIR_PATCH/unlockf_patch.sh
|
|
|
|
luci-reload
|
|
rm -f /tmp/luci-indexcache
|
|
luci-reload
|
|
'''
|
|
with open(FN_install, 'w', newline = '\n') as file:
|
|
file.write(unlockf_install)
|
|
|
|
unlockf_uninstall = '''#!/bin/sh
|
|
INST_FLAG_FN=/tmp/unlockf_patch.log
|
|
|
|
DIR_PATCH=/etc/crontabs/patches
|
|
DIR_BACKUP=$DIR_PATCH/unlockf_backup
|
|
|
|
TARGET_DIR=/usr/lib/lua/xiaoqiang
|
|
MIRROR_DIR=/tmp/_usr_lib_lua_xiaoqiang
|
|
SYNCOBJECT=$MIRROR_DIR.sync
|
|
|
|
if [ -d $DIR_BACKUP ]; then
|
|
if [ -d $MIRROR_DIR ]; then
|
|
cp -f $DIR_BACKUP/XQFeatures.lua $MIRROR_DIR/XQFeatures.lua
|
|
fi
|
|
cp -f $DIR_BACKUP/misc /etc/config/misc
|
|
fi
|
|
|
|
uci delete firewall.auto_unlockf_patch
|
|
uci commit firewall
|
|
|
|
rm -rf $DIR_BACKUP
|
|
rm -f $DIR_PATCH/unlockf_patch.sh
|
|
rm -f $DIR_PATCH/XQFeatures.lua
|
|
rm -f $INST_FLAG_FN
|
|
rm -rf $SYNCOBJECT
|
|
|
|
luci-reload
|
|
rm -f /tmp/luci-indexcache
|
|
luci-reload
|
|
'''
|
|
with open(FN_uninstall, 'w', newline = '\n') as file:
|
|
file.write(unlockf_uninstall)
|
|
|
|
action = 'install'
|
|
if len(sys.argv) > 1:
|
|
if sys.argv[1].startswith('u') or sys.argv[1].startswith('r'):
|
|
action = 'uninstall'
|
|
|
|
if action == 'install':
|
|
gw.upload(FN_lua, fn_lua)
|
|
gw.upload(FN_patch, fn_patch)
|
|
gw.upload(FN_install, fn_install)
|
|
|
|
gw.upload(FN_uninstall, fn_uninstall)
|
|
|
|
print("All files uploaded!")
|
|
|
|
print("Run scripts...")
|
|
run_script = fn_install if action == 'install' else fn_uninstall
|
|
gw.run_cmd(f"chmod +x {run_script} ; {run_script}", timeout = 17)
|
|
|
|
time.sleep(1.5)
|
|
|
|
gw.run_cmd(f"rm -f {fn_lua} ; rm -f {fn_patch} ; rm -f {fn_install} ; rm -f {fn_uninstall}")
|
|
|
|
print("Ready! The UnlockFeatures patch installed.")
|