From 30d60a72aded583025ec706c3a39b795aa4b3e6e Mon Sep 17 00:00:00 2001 From: sepehr Date: Mon, 26 Aug 2024 11:22:04 +0330 Subject: [PATCH] Improved login errors, Added user disable option, Fix groups selection in tasks, Improved Auto updater, Fixed sorting of scan reports, Some pro feature --- py/api/api_account.py | 18 +++++++++++------- py/api/api_dev.py | 5 ++++- py/api/api_scanner.py | 2 +- py/api/api_user_tasks.py | 5 +++-- py/bgtasks.py | 29 +++++++++++++++++++++++++---- py/libs/account.py | 2 -- py/libs/db/db_groups.py | 5 +++++ py/libs/db/db_user_tasks.py | 3 ++- py/libs/util.py | 10 +++++++--- py/mules/radius.py | 23 ++++++++++++++++++----- py/mules/updater.py | 35 ++++++++++++++++++++++++++++++++++- py/task_run.py | 16 +++++----------- 12 files changed, 115 insertions(+), 38 deletions(-) diff --git a/py/api/api_account.py b/py/api/api_account.py index f4a62a8..c34f74f 100644 --- a/py/api/api_account.py +++ b/py/api/api_account.py @@ -11,7 +11,7 @@ from libs.util import ISPRO from libs.db import db,db_permissions,db_user_group_perm,db_groups,db_sysconfig,db_syslog import json -from libs import webutil,account +from libs import utilpro, webutil,account from libs.webutil import app, login_required, get_myself , buildResponse from libs.mschap3.mschap import nt_password_hash @@ -29,19 +29,18 @@ def login(): password = input.get('password') if not username or not password: - return webutil.warn_reply("Missing input") + return buildResponse({"status":"failed", "err":"Wrong user/pass"}, 200) u = db.get_user_by_username(username) - if not u or not account.check_password(u.password, password): + if not u or not account.check_password(u.password, password) or u.role=='disabled': # error try: - db_syslog.add_syslog_event(u.id, "User login","Failed login",webutil.get_ip(),webutil.get_agent(),json.dumps({"username":username})) + db_syslog.add_syslog_event(u.id, "User login","Failed login",webutil.get_ip(),webutil.get_agent(),json.dumps({"username":username,'reason':'wrong password'})) except: pass - return webutil.warn_reply("Invalid login credentials") + return buildResponse({"status":"failed", "err":"Wrong user/pass"}, 200) else: # success - account.build_session(u, is_permanent=input.get('remember', True)) tz=db_sysconfig.get_sysconfig('timezone') # log.info("LOGIN OK agent={}".format(webutil.get_agent())) res={ @@ -56,6 +55,11 @@ def login(): "tz":tz, "perms":json.loads(u.adminperms) } + if ISPRO: + prores=utilpro.do_login(res,input) + if prores: + return buildResponse(prores, 200) + account.build_session(u, is_permanent=input.get('remember', True)) db_syslog.add_syslog_event(u.id, "User login","Successful login",webutil.get_ip(),webutil.get_agent(),json.dumps({"username":username})) return buildResponse(res, 200) @@ -248,7 +252,7 @@ def user_edit(): if lname: u.last_name = lname - if role: + if role and str(u.id) != "37cc36e0-afec-4545-9219-94655805868b": u.role = role if adminperms and str(u.id) != "37cc36e0-afec-4545-9219-94655805868b": u.adminperms= json.dumps(adminperms) diff --git a/py/api/api_dev.py b/py/api/api_dev.py index c0c2fc4..8a16a46 100644 --- a/py/api/api_dev.py +++ b/py/api/api_dev.py @@ -77,7 +77,10 @@ def get_editform(): if not dev: return buildResponse({'status': 'failed'}, 200, error="Wrong Data") res['user_name']=util.decrypt_data(dev['user_name']) - res['password']=util.decrypt_data(dev['password']) + if ISPRO: + res['password']="Password is Hidden" + else: + res['password']=util.decrypt_data(dev['password']) res['ip']=dev['ip'] res['peer_ip']=dev['peer_ip'] res['name']=dev['name'] diff --git a/py/api/api_scanner.py b/py/api/api_scanner.py index 65cc40d..b070a37 100644 --- a/py/api/api_scanner.py +++ b/py/api/api_scanner.py @@ -45,7 +45,7 @@ def scan_resutls(): input = request.json tasks=db_tasks.TaskResults #Get tasks that is task_type is ip-scan - tasks=tasks.select().where(tasks.task_type=='ip-scan') + tasks=tasks.select().where(tasks.task_type=='ip-scan').order_by(tasks.id.desc()) tasks=list(tasks.dicts()) #Get task results return buildResponse({'status': True,'data':tasks},200) diff --git a/py/api/api_user_tasks.py b/py/api/api_user_tasks.py index a42a42a..403910d 100644 --- a/py/api/api_user_tasks.py +++ b/py/api/api_user_tasks.py @@ -46,6 +46,7 @@ def user_tasks_list(): clauses.append(utaks.task_type == task_type) if not ISPRO: clauses.append(utaks.task_type != 'firmware') + clauses.append(utaks.task_type != 'vault') clauses.append(utaks.task_type != 'snipet_exec') expr="" logs = [] @@ -89,7 +90,7 @@ def user_tasks_create(): data={ 'name':name, 'description':description, - 'snippetid':int(snippetid) if snippetid else 0, + 'snippetid':int(snippetid) if snippetid else None, 'cron':cron, 'desc_cron': get_description(cron), 'action': action, @@ -163,7 +164,7 @@ def user_tasks_edit(): data={ 'name':name, 'description':description, - 'snippetid':int(snippetid) if snippetid else 0, + 'snippetid':int(snippetid) if snippetid else None, 'cron':cron, 'desc_cron': get_description(cron), 'action': action, diff --git a/py/bgtasks.py b/py/bgtasks.py index c9aae28..cc86ec3 100644 --- a/py/bgtasks.py +++ b/py/bgtasks.py @@ -21,6 +21,12 @@ from libs.check_routeros.routeros_check.resource import RouterOSCheckResource from typing import Dict import json import datetime +try: + from libs import utilpro + ISPRO=True +except ImportError: + ISPRO=False + pass sensor_pile = queue.LifoQueue() other_sensor_pile = queue.LifoQueue() @@ -429,10 +435,6 @@ def scan_with_ip(*args, **kwargs): task.save() return True - - - - @spool(pass_arguments=True) def exec_snipet(*args, **kwargs): task=db_tasks.exec_snipet_status() @@ -488,3 +490,22 @@ def exec_snipet(*args, **kwargs): task.status=0 task.save() return False + +@spool(pass_arguments=True) +def exec_vault(*args, **kwargs): + Tasks=db_tasks.Tasks + task=Tasks.select().where(Tasks.signal == 170).get() + if not task.status: + try: + task.status=1 + task.save() + utask=kwargs.get('utask',False) + res=utilpro.run_vault_task(utask) + except Exception as e: + log.error(e) + task.status=0 + task.save() + return False + task.status=0 + task.save() + return False diff --git a/py/libs/account.py b/py/libs/account.py index 9d36f0c..d560cb6 100644 --- a/py/libs/account.py +++ b/py/libs/account.py @@ -6,7 +6,6 @@ # Author: Tomi.Mickelsson@iki.fi modified by sepehr.ha@gmail.com import re -from shutil import ExecError from flask import session from passlib.context import CryptContext import json @@ -25,7 +24,6 @@ def build_session(user_obj, is_permanent=True): assert user_obj assert user_obj.id - log.error(session) # make sure session is empty session.clear() session['userid'] = user_obj.id diff --git a/py/libs/db/db_groups.py b/py/libs/db/db_groups.py index d9b632b..c4fa0ce 100644 --- a/py/libs/db/db_groups.py +++ b/py/libs/db/db_groups.py @@ -107,6 +107,11 @@ def devs2(groupid): .order_by(Devices.name)) def get_devs_of_groups(group_ids): try: + group_ids=[group.id for group in group_ids] + if 1 in group_ids: + return list(Devices + .select() + .order_by(Devices.name)) return list(Devices .select() .join(DevGroupRel, on=DevGroupRel.device_id) diff --git a/py/libs/db/db_user_tasks.py b/py/libs/db/db_user_tasks.py index c00a605..6a6c5e6 100644 --- a/py/libs/db/db_user_tasks.py +++ b/py/libs/db/db_user_tasks.py @@ -92,9 +92,10 @@ def get_task_devices(task,return_devs=True): try: group_ids.append(mem.group_id) except DoesNotExist as err: + log.error(err) pass if return_devs: - devs=get_devs_of_groups(group_ids) + devs=get_devs_of_groups(group_ids) else: devs=group_ids else: diff --git a/py/libs/util.py b/py/libs/util.py index 4b0b2ab..41bebab 100644 --- a/py/libs/util.py +++ b/py/libs/util.py @@ -1106,13 +1106,17 @@ def sizeof_fmt(num, suffix="B"): num /= 1024.0 return f"{num:.1f}Yi{suffix}" -def get_local_users(opts): +def get_local_users(opts,router=False,full=False): try: - router=RouterOSCheckResource(opts) + if not router: + router=RouterOSCheckResource(opts) call = router.api.path( "/user" ) - results=[a['name'] for a in tuple(call)] + if not full: + results=[a['name'] for a in tuple(call)] + else: + results=tuple(call) return results except Exception as e: log.error(e) diff --git a/py/mules/radius.py b/py/mules/radius.py index 1970ed7..78a53b7 100644 --- a/py/mules/radius.py +++ b/py/mules/radius.py @@ -26,6 +26,12 @@ try: asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) except: pass +try: + from libs import utilpro + ISPRO=True +except ImportError: + ISPRO=False + pass log = logging.getLogger("Radius") @@ -103,17 +109,17 @@ class RadServer(ServerAsync): if not dev: self.send_auth_reject(protocol,pkt,addr) return + u = db.get_user_by_username(username) - if not u: + if not u or u.role=='disabled': self.send_auth_reject(protocol,pkt,addr) db_AA.Auth.add_log(dev.id, 'failed', username , userip , by=None,sessionid=None,timestamp=tz,message="User Not Exist") return else: #get user permision related to device - if not dev: self.send_auth_reject(protocol, pkt, addr) - db_AA.Auth.add_log(dev.id, 'failed', username, userip, by=None, sessionid=None, timestamp=tz, message="Device Not Exist") + db_AA.Auth.add_log(dev.id, 'failed', u.username, userip, by=None, sessionid=None, timestamp=tz, message="Device Not Exist") return force_perms=True if db_sysconfig.get_sysconfig('force_perms')=="True" else False if force_perms: @@ -128,9 +134,16 @@ class RadServer(ServerAsync): res2=FourcePermToRouter(dev,perm) if not res2: self.send_auth_reject(protocol,pkt,addr) - db_AA.Auth.add_log(dev.id, 'failed', username , userip , by=None,sessionid=None,timestamp=tz,message="Unable to verify group") + db_AA.Auth.add_log(dev.id, 'failed', u.username , userip , by=None,sessionid=None,timestamp=tz,message="Unable to verify group") return nthash=u.hash + if(ISPRO): + nthash = utilpro.GetNThash(u) + respro=utilpro.verfyRadius(u,userip) + if not respro: + db_AA.Auth.add_log(dev.id, 'failed', u.username , userip , by=None,sessionid=None,timestamp=tz,message="IP not allowed: {}".format(userip)) + self.send_auth_reject(protocol, pkt, addr) + return if force_perms: reply=self.verifyMsChapV2(pkt,"password",perm[0].perm_id.name,nthash) else: @@ -138,7 +151,7 @@ class RadServer(ServerAsync): if reply: protocol.send_response(reply, addr) return - db_AA.Auth.add_log(dev.id, 'failed', username , userip , by=None,sessionid=None,timestamp=tz,message="Wrong Password") + db_AA.Auth.add_log(dev.id, 'failed', u.username , userip , by=None,sessionid=None,timestamp=tz,message="Wrong Password") self.send_auth_reject(protocol,pkt,addr) except Exception as e: print(e) diff --git a/py/mules/updater.py b/py/mules/updater.py index ab1d3a9..5d79e5e 100644 --- a/py/mules/updater.py +++ b/py/mules/updater.py @@ -17,6 +17,20 @@ import hashlib import zipfile import subprocess 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(): @@ -66,8 +80,27 @@ def extract_zip_reload(filename,dst): (output, err) = p.communicate() #This makes the wait possible p_status = p.wait() - #touch server reload file /app/reload + #install requirments + try: + from libs import utilpro + ISPRO=True + 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) + 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() diff --git a/py/task_run.py b/py/task_run.py index 09e05c1..75c2f35 100644 --- a/py/task_run.py +++ b/py/task_run.py @@ -77,16 +77,6 @@ if __name__ == '__main__': devices=[] devices=db_user_tasks.get_task_devices(utask) - # if task.selection_type == "devices": - # devids=task.dev_ids.split(",") - # devices=list(db_device.get_devices_by_id2(devids)) - # else: - # for group in task.dev_groups.split(","): - # if not group.isdigit(): - # continue - # devices=db_groups.devs2(group) - - # task=utaks.select().where(utaks.id == taksid).get() if utask.task_type == "backup": log.error("TASK TYPE BACKUP") res=backup_devs(devices=devices) @@ -102,6 +92,10 @@ if __name__ == '__main__': if not ISPRO: exit() res=utilpro.run_firmware_task(utask) - + elif utask.task_type == "vault": + log.error("vault") + if not ISPRO: + exit() + res=utilpro.run_vault_task(utask) #log.error(res) #[{'id': 3, 'state': False}, {'id': 1, 'state': False}, {'id': 2, 'state': True}]