v8.0: Add port scanner functionality and refactor codebase

Integrated port scanner endpoints to manage and retrieve scanner configurations. Removed unused imports and redundant code blocks across multiple files for better performance and readability. Simplified error handling and consolidated port scanner settings operations.
pull/399/head
Aidaho 2024-08-19 11:49:19 +03:00
parent a1ed81b0a2
commit 89022e59be
12 changed files with 219 additions and 65 deletions

View File

@ -46,7 +46,6 @@ Web interface (user-friendly web GUI, alerting, monitoring and secure) for manag
35. Mobile-ready design
36. [SMON](https://roxy-wi.org/services/smon) (Check: Ping, TCP/UDP, HTTP(s), SSL expiry, HTTP body answer, DNS records, Status pages)
37. Backup HAProxy, Nginx, Apache and Keepalived config files through Roxy-WI
38. Managing OpenVPN3 as a client via Roxy-WI

View File

@ -14,6 +14,7 @@ from app.views.user.views import UserView, UserGroupView, UserRoles
from app.views.udp.views import UDPListener, UDPListeners, UDPListenerActionView
from app.views.channel.views import ChannelView, ChannelsView
from app.views.tools.views import CheckerView
from app.views.tools.port_scanner_views import PortScannerView, PortScannerPortsView
from app.views.admin.views import SettingsView
from app.modules.roxywi.class_models import LoginRequest
import app.modules.roxywi.auth as roxywi_auth
@ -67,6 +68,10 @@ bp.add_url_rule('/server/<server_id>/ip', view_func=ServerIPView.as_view('server
bp.add_url_rule('/server/<int:server_id>/ip', view_func=ServerIPView.as_view('server_ip'), methods=['GET'])
register_api(CredView, 'cred', '/server/cred', 'cred_id')
bp.add_url_rule('/server/creds', view_func=CredsView.as_view('creds'), methods=['GET'])
bp.add_url_rule('/server/portscanner/<server_id>', view_func=PortScannerView.as_view('port_scanner_ip'), methods=['GET', 'POST'])
bp.add_url_rule('/server/portscanner/<int:server_id>', view_func=PortScannerView.as_view('port_scanner'), methods=['GET', 'POST'])
bp.add_url_rule('/server/portscanner/<server_id>/ports', view_func=PortScannerPortsView.as_view('port_scanner_ports_ip'), methods=['GET'])
bp.add_url_rule('/server/portscanner/<int:server_id>/ports', view_func=PortScannerPortsView.as_view('port_scanner_ports'), methods=['GET'])
bp.add_url_rule('/servers', view_func=ServersView.as_view('servers'), methods=['GET'])
register_api(ServerGroupView, 'group', '/group', 'group_id')

View File

@ -7,6 +7,7 @@ import app.modules.roxywi.common as roxywi_common
from app.modules.roxywi.class_models import ServerRequest, GroupQuery, CredRequest, ChannelRequest
from app.middleware import get_user_params
class SupportClass:
def __init__(self, is_id=True):
self.is_id = is_id

View File

@ -1,6 +1,7 @@
from app.modules.db.db_model import connect, fn, PortScannerPorts, PortScannerSettings, PortScannerHistory
from app.modules.db.db_model import fn, PortScannerPorts, PortScannerSettings, PortScannerHistory
from app.modules.db.common import out_error
import app.modules.roxy_wi_tools as roxy_wi_tools
from app.modules.roxywi.exception import RoxywiResourceNotFound
def delete_port_scanner_settings(server_id):
@ -25,14 +26,20 @@ def select_port_scanner_settings(user_group):
return query_res
def select_port_scanner_settings_for_service():
query = PortScannerSettings.select()
def get_port_scanner_settings(server_id: int) -> PortScannerSettings:
try:
query_res = query.execute()
return PortScannerSettings.get(PortScannerSettings.server_id == server_id)
except PortScannerSettings.DoesNotExist:
raise RoxywiResourceNotFound
except Exception as e:
return out_error(e)
def select_port_scanner_settings_for_service():
try:
return PortScannerSettings.select().execute()
except Exception as e:
out_error(e)
else:
return query_res
def insert_port_scanner_port(serv, user_group_id, port, service_name):
@ -48,17 +55,10 @@ def insert_port_scanner_port(serv, user_group_id, port, service_name):
def select_ports(serv):
conn = connect()
cursor = conn.cursor()
sql = """select port from port_scanner_ports where serv = '%s' """ % serv
try:
cursor.execute(sql)
return PortScannerPorts.select(PortScannerPorts.port).where(PortScannerPorts.serv == serv).execute()
except Exception as e:
out_error(e)
else:
conn.close()
return cursor.fetchall()
def select_port_name(serv, port):
@ -74,9 +74,8 @@ def select_port_name(serv, port):
def delete_ports(serv):
query = PortScannerPorts.delete().where(PortScannerPorts.serv == serv)
try:
query.execute()
PortScannerPorts.delete().where(PortScannerPorts.serv == serv).execute()
except Exception as e:
out_error(e)
@ -96,23 +95,11 @@ def insert_port_scanner_settings(server_id, user_group_id, enabled, notify, hist
try:
PortScannerSettings.insert(
server_id=server_id, user_group_id=user_group_id, enabled=enabled, notify=notify, history=history
).execute()
return True
except Exception:
return False
def update_port_scanner_settings(server_id, user_group_id, enabled, notify, history):
query = PortScannerSettings.update(
user_group_id=user_group_id, enabled=enabled, notify=notify, history=history
).where(PortScannerSettings.server_id == server_id)
try:
query.execute()
).on_conflict('replace').execute()
except Exception as e:
out_error(e)
def select_count_opened_ports(serv):
query = PortScannerPorts.select(
PortScannerPorts.date, fn.Count(PortScannerPorts.port).alias('count')
@ -140,10 +127,7 @@ def delete_portscanner_history(keep_interval: int):
def select_port_scanner_history(serv):
query = PortScannerHistory.select().where(PortScannerHistory.serv == serv)
try:
query_res = query.execute()
return PortScannerHistory.select().where(PortScannerHistory.serv == serv).execute()
except Exception as e:
out_error(e)
else:
return query_res

View File

@ -111,12 +111,9 @@ def is_system_info(server_id):
def select_os_info(server_id):
try:
query_res = SystemInfo.get(SystemInfo.server_id == server_id).os_info
return SystemInfo.get(SystemInfo.server_id == server_id).os_info
except Exception as e:
out_error(e)
return
else:
return query_res
def update_firewall(serv):

View File

@ -4,7 +4,7 @@ from typing import Optional, Annotated, Union, Literal, Any, Dict, List
from shlex import quote
from pydantic_core import CoreSchema, core_schema
from pydantic import BaseModel, Base64Str, StringConstraints, IPvAnyAddress, AnyUrl, root_validator, GetCoreSchemaHandler
from pydantic import BaseModel, Base64Str, StringConstraints, IPvAnyAddress, GetCoreSchemaHandler
DomainName = Annotated[str, StringConstraints(pattern=r"^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z0-9-]{0,61}[a-z0-9]$")]
@ -263,3 +263,9 @@ class GitBackupRequest(BaseModel):
time: Optional[EscapedString] = 'weekly'
cred_id: Optional[int] = None
description: Optional[EscapedString] = None
class PortScannerRequest(BaseModel):
enabled: Optional[bool] = 1
history: Optional[bool] = 1
notify: Optional[bool] = 1

View File

@ -5,7 +5,7 @@ import pdpyras
import requests
import telebot
from telebot import apihelper
from flask import render_template, request, abort, g
from flask import render_template, abort, g
import app.modules.db.sql as sql
import app.modules.db.user as user_sql
@ -220,8 +220,7 @@ def slack_send_mess(mess, level, **kwargs):
channel_name = slack.chanel_name
if proxy is not None and proxy != '' and proxy != 'None':
proxies = dict(https=proxy, http=proxy)
client = WebClient(token=slack_token, proxies=proxies)
client = WebClient(token=slack_token, proxy=proxy)
else:
client = WebClient(token=slack_token)
@ -331,12 +330,7 @@ def mm_send_mess(mess, level, server_ip=None, service_id=None, alert_type=None,
def check_rabbit_alert() -> None:
try:
user_group_id = request.cookies.get('group')
except Exception as e:
raise Exception(f'Cannot get user group {e}')
try:
json_for_sending = {"user_group": user_group_id, "message": 'info: Test message'}
json_for_sending = {"user_group": g.user_params['group_id'], "message": 'info: Test message'}
send_message_to_rabbit(json.dumps(json_for_sending))
except Exception as e:
raise Exception(f'Cannot send message {e}')

View File

@ -5,7 +5,6 @@ from flask_jwt_extended import jwt_required
from app import scheduler
from app.routes.admin import bp
import app.modules.db.sql as sql
import app.modules.db.cred as cred_sql
import app.modules.db.user as user_sql
import app.modules.db.group as group_sql
import app.modules.db.server as server_sql

View File

@ -42,6 +42,7 @@ def load_channels():
@bp.post('/check')
@get_user_params()
def check_sender():
json_data = request.get_json()
sender = json_data.get('sender')

View File

@ -5,7 +5,6 @@ from app.routes.portscanner import bp
from app.middleware import get_user_params
import app.modules.db.server as server_sql
import app.modules.db.portscanner as ps_sql
import app.modules.common.common as common
import app.modules.server.server as server_mod
import app.modules.roxywi.common as roxywi_common
import app.modules.tools.common as tools_common
@ -60,22 +59,17 @@ def portscanner_history(server_ip):
@bp.post('/settings')
def change_settings_portscanner():
server_id = common.checkAjaxInput(request.form.get('server_id'))
enabled = common.checkAjaxInput(request.form.get('enabled'))
notify = common.checkAjaxInput(request.form.get('notify'))
history = common.checkAjaxInput(request.form.get('history'))
user_group_id = [server[3] for server in server_sql.select_servers(id=server_id)]
server_id = int(request.form.get('server_id'))
enabled = int(request.form.get('enabled'))
notify = int(request.form.get('notify'))
history = int(request.form.get('history'))
server = server_sql.get_server_by_id(server_id)
try:
if ps_sql.insert_port_scanner_settings(server_id, user_group_id[0], enabled, notify, history):
return 'ok'
else:
if ps_sql.update_port_scanner_settings(server_id, user_group_id[0], enabled, notify, history):
ps_sql.insert_port_scanner_settings(server_id, server.group_id, enabled, notify, history)
return 'ok'
except Exception as e:
return f'error: Cannot save settings: {e}'
else:
return 'ok'
@bp.post('/scan')

View File

@ -12,9 +12,7 @@ import app.modules.roxywi.common as roxywi_common
import app.modules.server.server as server_mod
from app.middleware import get_user_params, page_for_admin, check_group
from app.modules.roxywi.exception import RoxywiResourceNotFound
from app.modules.roxywi.class_models import (
BaseResponse, IdResponse, IdDataResponse, ServerRequest, GroupQuery, GroupRequest, CredRequest, CredUploadRequest
)
from app.modules.roxywi.class_models import BaseResponse, IdResponse, IdDataResponse, ServerRequest, GroupQuery, GroupRequest
from app.modules.common.common_classes import SupportClass

View File

@ -0,0 +1,176 @@
from typing import Union
from ansible.module_utils.common.text.converters import jsonify
from flask.views import MethodView
from flask_pydantic import validate
from flask_jwt_extended import jwt_required
from playhouse.shortcuts import model_to_dict
import app.modules.db.server as server_sql
import app.modules.db.portscanner as ps_sql
import app.modules.roxywi.common as roxywi_common
from app.middleware import get_user_params, page_for_admin, check_group
from app.modules.roxywi.class_models import PortScannerRequest, BaseResponse
from app.modules.db.db_model import PortScannerSettings, PortScannerHistory
from app.modules.common.common_classes import SupportClass
class PortScannerView(MethodView):
methods = ['GET', 'POST']
decorators = [jwt_required(), get_user_params(), page_for_admin(level=3), check_group()]
@staticmethod
def get(server_id: Union[int, str]):
"""
Port scanner operations for managing and retrieving scanner configurations.
---
tags:
- Port Scanner
parameters:
- in: path
name: server_id
type: integer
required: true
description: ID or IP address of the server.
responses:
200:
description: A JSON object containing the port scanner settings.
schema:
type: object
properties:
enabled:
type: boolean
description: Indicates if the port scanner is enabled.
history:
type: boolean
description: Indicates if the port scanner keeps a history.
notify:
type: boolean
description: Indicates if notifications are enabled for the port scanner.
404:
description: Server not found.
500:
description: An error occurred while retrieving the port scanner settings.
"""
try:
server_id = SupportClass().return_server_ip_or_id(server_id)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find server')
try:
ps_settings = ps_sql.get_port_scanner_settings(server_id)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get Portscanner settings')
return jsonify(model_to_dict(ps_settings, recurse=False, exclude=[PortScannerSettings.user_group_id]))
@validate(body=PortScannerRequest)
def post(self, server_id: Union[int, str], body: PortScannerRequest):
"""
Updates the port scanner settings for a specific server.
---
tags:
- Port Scanner
parameters:
- in: path
name: server_id
type: integer
required: true
description: The ID or IP of the server
- in: body
name: body
required: true
schema:
type: object
properties:
enabled:
type: boolean
description: Indicates if the port scanner is enabled
history:
type: boolean
description: Indicates if the port scanner keeps a history
notify:
type: boolean
description: Indicates if notifications are enabled for the port scanner
responses:
201:
description: Successfully updated the port scanner settings
default:
description: Unexpected error
"""
try:
server_id = SupportClass().return_server_ip_or_id(server_id)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find server')
try:
server = server_sql.get_server_by_id(server_id)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find server')
try:
ps_sql.insert_port_scanner_settings(server_id, server.group_id, body.enabled, body.notify, body.history)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot insert Portscanner settings')
return BaseResponse().model_dump(), 201
class PortScannerPortsView(MethodView):
methods = ['GET']
decorators = [jwt_required(), get_user_params(), page_for_admin(level=3), check_group()]
@staticmethod
def get(server_id: Union[int, str]):
"""
Port scanner ports information retrieval for a specific server.
---
description: Retrieves the list of open ports and their details for a specific server.
tags:
- Port Scanner
parameters:
- in: path
name: server_id
type: integer
required: true
description: ID or IP address of the server.
responses:
200:
description: A JSON array containing details of open ports.
schema:
type: array
items:
type: object
properties:
port:
type: integer
description: The port number.
status:
type: string
description: The status of the port, e.g., "opened".
service_name:
type: string
description: The name of the service running on the port.
date:
type: string
format: date-time
description: The date and time when the port was last checked.
404:
description: Server not found.
500:
description: An error occurred while retrieving the port scanner information.
"""
try:
server_ip = SupportClass(False).return_server_ip_or_id(server_id)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find server')
try:
ports = ps_sql.select_port_scanner_history(server_ip)
ports_list = []
for port in ports:
ports_list.append(model_to_dict(port, exclude=[PortScannerHistory.serv]))
return jsonify(ports_list)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get Portscanner history')