"""Description: Used for control shadowsocks, for example: add account, del account, flow usage stats. The method ``start_shadowsocks`` integrates shadowsocks into sspymgr and it will start a shadowsocks server in a separate thread. ``ssAddr`` can be used to make sure that shadowsocks server and adapter communicate with the same address, either unix socks file, either socket. Author: BriFuture Date: 2019/03/19 """ __version__ = "0.0.6" from sspymgr import convertFlowToByte, getRandomCode, Manager, createLogger from sspymgr.core import User, WebguiSetting, UserType logger = createLogger('sscontroller', stream=False, logger_prefix="[Core SSController]") from .database import Account, AccountFlow from .adapter import SSController import sys def ssAddr(addr2str = False): """Get universal address for communicating with shadowsocks server """ if sys.platform.startswith( 'linux' ): mgr_addr = '/var/run/sspymgr.sock' else: mgr_addr = ('127.0.0.1', 6001) # some problem in unix sock file, using tcp mode always currently mgr_addr = ('127.0.0.1', 6001)
# -*- coding: utf-8 -*- """Description: This module is used to provide email feature to all other sub modules so that they can send email by a simple api. Author: BriFuture Modified: 2019/03/17 12:35 """ __version__ = '0.1.2' from sspymgr import DB, createLogger from datetime import datetime logger = createLogger('email', stream=False) class Email(DB.Model): __tablename__ = 'email' id = DB.Column(DB.Integer, primary_key=True, autoincrement=True) to = DB.Column(DB.String(255), nullable=False) content = DB.Column(DB.Text) time = DB.Column(DB.DateTime, default=datetime.now) subject = DB.Column(DB.String(255)) ip = DB.Column(DB.String(255)) type = DB.Column(DB.String(255)) remark = DB.Column(DB.String(255)) session = DB.Column(DB.String(255)) def to_dict(self): di = {
# -*- coding: utf-8 -*- from sspymgr import createLogger logger = createLogger( "plugin_sscontroller", stream=False, logger_prefix="[Plugin sscontroller]") from sspymgr import getRandomCode from datetime import datetime, timedelta app = None from .flow_stats import AccountsChecker from .flow_stats import FlowStats import threading def run_threaded(job_func): job_thread = threading.Thread(target=job_func) job_thread.start() def scheduleTasks(schedule): recorder = FlowStats(app.m_db) app.m_sscontroller.setStats(recorder.recordFlow) # schedule.every(10).seconds.do(run_threaded, recorder.record5minToDb) schedule.every().minute.at(":57").do(run_threaded, recorder.record5minToDb) schedule.every().day.at("23:59").do(run_threaded, recorder.record1dayToDb) accChecker = AccountsChecker(app) schedule.every().minutes.do(accChecker.checkAllAccounts) logger.debug("Tasks scheduled done") from sspymgr.core import WebguiSetting from sspymgr.sscontroller import availiable_port
# -*- coding: utf-8 -*- """Description: This module is used for communicate with shadowsocks server, it contains basic protocol which defines how to communicate with shadowsocks server. Also contains a controller class to provide convenient methods for other modules. Author: BriFuture Detail: 2019/03/17 12:31 """ from sspymgr import createLogger logger = createLogger('sscontroller') def _ping(): """Return a tuple that is made up of a message that need to be sent to shadowsocks server and the expected response from shadowsocks server """ return b'ping', b'pong' def _add_port(port, password, method): """Return a tuple that contains 4 elements First: is the message that should be sent to shadowsocks server; Second: is the expected response from shadowsocks server; Third: is a bool type value which indicates whether it is account-add operation. Fourth: is the port passed in. """ cmd = 'add: {{ "server_port": {:d}, "password": "******", "method": "{:s}" }}'.format(port, password, method) return cmd.encode( 'ascii' ), b'ok', True, port def _remove_port(port): """Return a tuple that contains 4 elements, the same as ``_add_port``
# -*- coding: utf-8 -*- from sspymgr import DB, createLogger logger = createLogger("plugin_annoucement", stream=False, logger_prefix="[Plugin announcement]") from datetime import datetime class Announcement(DB.Model): """公告数据模型 """ __tablename__ = 'announcement' id = DB.Column(DB.Integer, primary_key=True) title = DB.Column(DB.String(255), nullable=False) variant = DB.Column(DB.String(32)) # primary, success, warn content = DB.Column(DB.BLOB) createtime = DB.Column(DB.DateTime, default=datetime.now) top = DB.Column(DB.Integer, default=0) def to_dict(self): content = self.content.decode( 'utf-8') if self.content is not None else '' di = { 'id': self.id, 'title': self.title, 'variant': self.variant, 'content': content, 'createTime': self.createtime.timestamp(), 'top': self.top,
# -*- coding: utf-8 -*- from sspymgr import DB, \ createLogger, getRandomCode, formatTime logger = createLogger("plugin_order", stream=False, logger_prefix="[Plugin Order]") from datetime import datetime, timedelta from sqlalchemy.sql import text class Product(DB.Model): __tablename__ = 'product' id = DB.Column(DB.Integer, primary_key=True, autoincrement=True) # name = DB.Column( DB.String( 255 ) ) type = DB.Column(DB.Integer) # 0 or none stands by enabled flow = DB.Column(DB.Integer) # unit: Mn price = DB.Column(DB.Float) # unit: ¥ enable = DB.Column(DB.Boolean, default=True) duration = DB.Column(DB.Integer) # unit: seconds buffer_period = DB.Column(DB.Integer) # unit: seconds @staticmethod def add_type(price: float, flow: int, duration: timedelta, buffer_period: timedelta): dseconds = duration.total_seconds() bseconds = buffer_period.total_seconds() ot = Product( price=price, flow=flow, duration=dseconds, buffer_period=bseconds) return ot def to_dict(self):
annotations or text are mixed in many parts, so one of the jobs TODO is to rewrite all of them in English and then use ``gettext`` module to translate them into Chinses. Author: BriFuture Date: 2019/03/18 21:51 """ from sspymgr import DB, createLogger from sspymgr import getRandomCode, convertFlowToByte from flask import session, request, jsonify from datetime import datetime, timedelta import hashlib logger = createLogger("core_user", stream=False, logger_prefix="[Plugin User]") class User(DB.Model): """The life cycle of an webserver user is not clear now. So the user type may be confusing. TODO reconstruct this model """ __tablename__ = 'user' id = DB.Column(DB.Integer, primary_key=True, autoincrement=True) type = DB.Column(DB.String(255)) salt = DB.Column(DB.String(8), nullable=False) email = DB.Column(DB.String(255), nullable=False) group = DB.Column(DB.Integer, default=0) level = DB.Column(DB.Integer, default=1) comment = DB.Column(DB.String(255), default='') password = DB.Column(DB.String(255), nullable=False)
# -*- coding: utf-8 -*- """Description: This module stores the settings of webserver provided by sspymgr into database. The original purpose of this module is to store as much information as possible into a single table, But it is proved that it's much better to store settings with simple and enumerable types, such as String and Number (most common). It will take some time to review this module and make some improvements. Author: BriFuture Date: 2019/03/18 21:42 """ from sspymgr import DB, createLogger from sqlalchemy.sql import text from base64 import b64decode logger = createLogger('core_settings', stream=False, logger_prefix="[Plugin Settings]") db = None class WebguiSetting(DB.Model): """ TODO reconstruct this model Type (can be ignored, just used as utility): String: Value type by default, should be processed by other logic Image: Value are encoded with base64 format Number: Treat value as number( use float builtin function), Boolean: are stored in number with only two candicates (0 or 1) Json: Value are encoded with json format Hidden: Not visible for even manager """