diff --git a/plugins/mail/conf/postfixadmin.sql b/plugins/mail/conf/postfixadmin.sql deleted file mode 100644 index dc984f2f4..000000000 --- a/plugins/mail/conf/postfixadmin.sql +++ /dev/null @@ -1,42 +0,0 @@ -CREATE TABLE IF NOT EXISTS `domain` ( - `domain` varchar(255) NOT NULL, - `a_record` TEXT DEFAULT "", - `created` datetime NOT NULL, - `active` tinyint(1) NOT NULL DEFAULT 1, - PRIMARY KEY (`domain`) -); - -CREATE TABLE IF NOT EXISTS `mailbox` ( - `username` varchar(255) NOT NULL, - `password` varchar(255) NOT NULL, - `password_encode` varchar(255) NOT NULL, - `full_name` varchar(255) NOT NULL, - `is_admin` tinyint(1) NOT NULL DEFAULT 0, - `maildir` varchar(255) NOT NULL, - `quota` bigint(20) NOT NULL DEFAULT 0, - `local_part` varchar(255) NOT NULL, - `domain` varchar(255) NOT NULL, - `created` datetime NOT NULL, - `modified` datetime NOT NULL, - `active` tinyint(1) NOT NULL DEFAULT 1, - PRIMARY KEY (`username`) -); - -CREATE TABLE IF NOT EXISTS `alias` ( - `address` varchar(255) NOT NULL, - `goto` text NOT NULL, - `domain` varchar(255) NOT NULL, - `created` datetime NOT NULL, - `modified` datetime NOT NULL, - `active` tinyint(1) NOT NULL DEFAULT 1, - PRIMARY KEY (`address`) -); - -CREATE TABLE IF NOT EXISTS `alias_domain` ( - `alias_domain` varchar(255) NOT NULL, - `target_domain` varchar(255) NOT NULL, - `created` datetime NOT NULL, - `modified` datetime NOT NULL, - `active` tinyint(1) NOT NULL DEFAULT 1, - PRIMARY KEY (`alias_domain`) -); \ No newline at end of file diff --git a/plugins/mail/ico.png b/plugins/mail/ico.png deleted file mode 100755 index fd5d7fad1..000000000 Binary files a/plugins/mail/ico.png and /dev/null differ diff --git a/plugins/mail/index.html b/plugins/mail/index.html deleted file mode 100755 index 27292c55a..000000000 --- a/plugins/mail/index.html +++ /dev/null @@ -1,1027 +0,0 @@ - - -
-
- -
-
-

域名列表

-

邮件秘抄

-

邮件中继

-

邮件转发

-

邮件备份

-

收件箱

-

垃圾箱

-

已发送

-

发送邮件

-

服务状态

-

日志

-
-
-
- -
- - - -
- - - - - - - - - - - - - - - -
邮箱域名MX记录A记录SPF记录DKIM记录DMARC记录CatchAllSSL操作
-
-
-
    -
  • 添加域名后,需要添加MX记录(用于邮箱服务)和TXT记录(用于邮箱反垃圾服务)才能正常使用邮箱服务。
  • -
  • 提示: 部分云厂商(如:阿里云,腾讯云)默认关闭25端口,需联系厂商开通25端口后才能正常使用邮局服务
  • -
  • 该自建邮局版本为基础版本,仅提供基础功能,更多功能请耐心等候开发进度。
  • -
-
- - - - - - - - - - - - - - - - - - - - -
-
-
-
- \ No newline at end of file diff --git a/plugins/mail/index.py b/plugins/mail/index.py deleted file mode 100755 index be1122a12..000000000 --- a/plugins/mail/index.py +++ /dev/null @@ -1,489 +0,0 @@ -# coding:utf-8 - -import sys -import io -import os -import time -import re -import socket - -from datetime import datetime - -try: - import dns.resolver -except: - if os.path.exists(os.getcwd() + '/bin'): - mw.mw(os.getcwd() + '/bin/pip install dnspython') - else: - mw.execShell('pip install dnspython') - import dns.resolver - - -sys.path.append(os.getcwd() + "/class/core") - -import mw -app_debug = False -if mw.isAppleSystem(): - app_debug = True - -import mail_init as mi - - -class App: - __setupPath = '/www/server/mail' - __session_conf = __setupPath + '/session.json' - - _check_time = 86400 - - def __init__(self): - self.__setupPath = self.getServerDir() - self._session = self.__get_session() - - def getArgs(self): - args = sys.argv[3:] - tmp = {} - args_len = len(args) - - if args_len == 1: - t = args[0].strip('{').strip('}') - t = t.split(':') - tmp[t[0]] = t[1] - elif args_len > 1: - for i in range(len(args)): - t = args[i].split(':') - tmp[t[0]] = t[1] - - return tmp - - def check_mail_sys(self): - args = self.getArgs() - - if os.path.exists('/etc/postfix/sqlite_virtual_domains_maps.cf'): - mw.execShell( - '/sbin/postconf -e "message_size_limit = 102400000"') - # 修改postfix mydestination配置项 - result = mw.readFile(self.postfix_main_cf) - if not result: - return mw.returnJson(False, "找不到postfix配置文件") - result = re.search(r"\n*mydestination\s*=(.+)", result) - if not result: - return mw.returnJson(False, "postfix配置文件中找不到mydestination配置项") - result = result.group(1) - if 'localhost' in result or '$myhostname' in result or '$mydomain' in result: - mw.execShell( - '/sbin/postconf -e "mydestination =" && systemctl restart postfix') - # 修改dovecot配置 - dovecot_conf = public.readFile("/etc/dovecot/dovecot.conf") - if not dovecot_conf or not re.search(r"\n*protocol\s*imap", dovecot_conf): - return mw.returnJson(False, '配置dovecot失败') - # 修复之前版本未安装opendkim的问题 - # if not (os.path.exists("/usr/sbin/opendkim") and os.path.exists("/etc/opendkim.conf") and os.path.exists("/etc/opendkim")): - # if not self.setup_opendkim(): - # return public.returnMsg(False, 'Failed to configure opendkim 1') - - return mw.returnJson(True, '邮局系统已经存在,重装之前请先卸载!') - else: - return mw.returnJson(False, '之前没有安装过邮局系统,请放心安装!') - - def __get_session(self): - session = mw.readFile(self.__session_conf) - if session: - session = json.loads(session) - else: - session = {} - return session - - def __get_dkim_value(self, domain): - ''' - 解析/etc/opendkim/keys/domain/default.txt得到域名要设置的dkim记录值 - :param domain: - :return: - ''' - if not os.path.exists("/www/server/dkim/{}".format(domain)): - os.makedirs("/www/server/dkim/{}".format(domain)) - rspamd_pub_file = '/www/server/dkim/{}/default.pub'.format(domain) - opendkim_pub_file = '/etc/opendkim/keys/{0}/default.txt'.format(domain) - if os.path.exists(opendkim_pub_file) and not os.path.exists(rspamd_pub_file): - opendkim_pub = mw.readFile(opendkim_pub_file) - mw.writeFile(rspamd_pub_file, opendkim_pub) - - rspamd_pri_file = '/www/server/dkim/{}/default.private'.format( - domain) - opendkim_pri_file = '/etc/opendkim/keys/{}/default.private'.format( - domain) - opendkim_pri = mw.readFile(opendkim_pri_file) - mw.writeFile(rspamd_pri_file, opendkim_pri) - - if not os.path.exists(rspamd_pub_file): - return '' - file_body = mw.readFile(rspamd_pub_file).replace( - ' ', '').replace('\n', '').split('"') - value = file_body[1] + file_body[3] - return value - - def __check_mx(self, domain): - ''' - 检测域名是否有mx记录 - :param domain: - :return: - ''' - a_record = self.M('domain').where( - 'domain=?', (domain,)).field('a_record').find()['a_record'] - key = '{0}:{1}'.format(domain, 'MX') - now = int(time.time()) - try: - value = "" - if key in self._session and self._session[key]["status"] != 0: - v_time = now - int(self._session[key]["v_time"]) - if v_time < self._check_time: - value = self._session[key]["value"] - if '' == value: - resolver = dns.resolver.Resolver() - resolver.timeout = 1 - try: - result = resolver.resolve(domain, 'MX') - except: - result = resolver.query(domain, 'MX') - - value = str(result[0].exchange).strip('.') - if not a_record: - a_record = value - self.M('domain').where('domain=?', (domain,)).save( - 'a_record', (a_record,)) - if value == a_record: - self._session[key] = {"status": 1, - "v_time": now, "value": value} - return True - self._session[key] = {"status": 0, "v_time": now, "value": value} - return False - except: - # print(public.get_error_info()) - self._session[key] = {"status": 0, "v_time": now, - "value": "None of DNS query names exist:{}".format(domain)} - return False - - def __check_spf(self, domain): - ''' - 检测域名是否有spf记录 - :param domain: - :return: - ''' - key = '{0}:{1}'.format(domain, 'TXT') - now = int(time.time()) - try: - value = "" - if key in self._session and self._session[key]["status"] != 0: - v_time = now - int(self._session[key]["v_time"]) - if v_time < self._check_time: - value = self._session[key]["value"] - if '' == value: - resolver = dns.resolver.Resolver() - resolver.timeout = 1 - # try: - result = resolver.resolve(domain, 'TXT') - # except: - # result = resolver.query(domain, 'TXT') - - for i in result.response.answer: - for j in i.items: - value += str(j).strip() - if 'v=spf1' in value.lower(): - self._session[key] = {"status": 1, - "v_time": now, "value": value} - return True - self._session[key] = {"status": 0, "v_time": now, "value": value} - return False - except: - # print(public.get_error_info()) - self._session[key] = {"status": 0, "v_time": now, - "value": "None of DNS query spf exist:{}".format(domain)} - return False - - def __check_dkim(self, domain): - ''' - 检测域名是否有dkim记录 - :param domain: - :return: - ''' - origin_domain = domain - domain = 'default._domainkey.{0}'.format(domain) - key = '{0}:{1}'.format(domain, 'TXT') - now = int(time.time()) - try: - value = "" - if key in self._session and self._session[key]["status"] != 0: - v_time = now - int(self._session[key]["v_time"]) - if v_time < self._check_time: - value = self._session[key]["value"] - if '' == value: - resolver = dns.resolver.Resolver() - resolver.timeout = 1 - result = resolver.resolve(domain, 'TXT') - for i in result.response.answer: - for j in i.items: - value += str(j).strip() - new_v = self._get_dkim_value(origin_domain) - if new_v and new_v in value: - self._session[key] = {"status": 1, - "v_time": now, "value": value} - return True - self._session[key] = {"status": 0, "v_time": now, "value": value} - return False - except: - # print(public.get_error_info()) - self._session[key] = {"status": 0, "v_time": now, - "value": "None of DNS query names exist:{}".format(domain)} - return False - - def __check_dmarc(self, domain): - ''' - 检测域名是否有dmarc记录 - :param domain: - :return: - ''' - domain = '_dmarc.{0}'.format(domain) - key = '{0}:{1}'.format(domain, 'TXT') - now = int(time.time()) - try: - value = "" - if key in self._session and self._session[key]["status"] != 0: - v_time = now - int(self._session[key]["v_time"]) - if v_time < self._check_time: - value = self._session[key]["value"] - if '' == value: - resolver = dns.resolver.Resolver() - resolver.timeout = 1 - - result = resolver.resolve(domain, 'TXT') - - for i in result.response.answer: - for j in i.items: - value += str(j).strip() - if 'v=dmarc1' in value.lower(): - self._session[key] = {"status": 1, - "v_time": now, "value": value} - return True - self._session[key] = {"status": 0, "v_time": now, "value": value} - return False - except: - # print(public.get_error_info()) - self._session[key] = {"status": 0, "v_time": now, - "value": "None of DNS query names exist:{}".format(domain)} - return False - - def __gevent_jobs(self, domain, a_record): - from gevent import monkey - # monkey.patch_all() - import gevent - gevent.joinall([ - gevent.spawn(self.__check_mx, domain), - gevent.spawn(self.__check_spf, domain), - gevent.spawn(self.__check_dkim, domain), - gevent.spawn(self.__check_dmarc, domain), - gevent.spawn(self.__check_a, a_record), - ]) - - return True - - def getInitDFile(self): - if app_debug: - return '/tmp/' + getPluginName() - return '/etc/init.d/' + getPluginName() - - def getPluginName(self): - return 'mail' - - def getPluginDir(self): - return mw.getPluginDir() + '/' + self.getPluginName() - - def getServerDir(self): - return mw.getServerDir() + '/' + self.getPluginName() - - def M(self, dbname='domain'): - file = self.getServerDir() + '/postfixadmin.db' - name = 'mail' - if not os.path.exists(file): - conn = mw.M(dbname).dbPos(self.getServerDir(), name) - csql = mw.readFile(self.getPluginDir() + '/conf/postfixadmin.sql') - csql_list = csql.split(';') - for index in range(len(csql_list)): - conn.execute(csql_list[index], ()) - else: - # 现有run - # conn = mw.M(dbname).dbPos(getServerDir(), name) - # csql = mw.readFile(getPluginDir() + '/conf/mysql.sql') - # csql_list = csql.split(';') - # for index in range(len(csql_list)): - # conn.execute(csql_list[index], ()) - conn = mw.M(dbname).dbPos(self.getServerDir(), name) - return conn - - def status(self): - return 'start' - - def get_domains(self): - args = self.getArgs() - - p = int(args['p']) if 'p' in args else 1 - rows = int(args['size']) if 'size' in args else 10 - callback = args['callback'] if 'callback' in args else '' - count = self.M('domain').count() - - data = {} - # 获取分页数据 - _page = {} - _page['count'] = count - _page['p'] = p - _page['row'] = rows - _page['tojs'] = callback - data['page'] = mw.getPage(_page) - - start_pos = (_page['p'] - 1) * _page['row'] - - data_list = self.M('domain').order('created desc').limit( - str(start_pos) + ',' + str(_page['row'])).field('domain,a_record,created,active').select() - - # print(data) - # print(data_list) - - return mw.returnJson(True, 'ok', {'data': data_list, 'page': data['page']}) - - def runLog(self): - path = '/var/log/maillog' - # if "ubuntu" in: - # path = '/var/log/mail.log' - return path - - def add_domain(self): - args = self.getArgs() - - if 'domain' not in args: - return mw.returnJson(False, '请传入域名') - - domain = args['domain'] - a_record = args['a_record'] - - if not a_record.endswith(domain): - return mw.returnJson(False, 'A记录 [{}] 不属于该域名'.format(a_record)) - - if not mw.isDebugMode(): - check = self.__check_a(a_record) - if not check[0]: - return mw.returnJson(False, 'A记录解析失败
域名:{}
IP:{}'.format(a_record, check[1]['value'])) - - if self.M('domain').where("domain=?", (domain,)).count() > 0: - return mw.returnJson(False, '该域名已存在') - - cur_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - try: - self.M('domain').add('domain,a_record,created', - (domain, a_record, cur_time)) - except: - return mw.returnJson(False, '邮局没有初始化成功!
' - '请尝试重新初始化,
' - '如果以下端口没访问将无法初始化
port 25 [outbound direction]
' - '你可以尝试执行以下命令测试端口是否开启:

[ telnet gmail-smtp-in.l.google.com 25 ]
') - - # 在虚拟用户家目录创建对应域名的目录 - if os.path.exists('/www/vmail'): - if not os.path.exists('/www/vmail/{0}'.format(domain)): - os.makedirs('/www/vmail/{0}'.format(domain)) - mw.execShell('chown -R vmail:mail /www/vmail/{0}'.format(domain)) - return mw.returnJson(False, 'OK') - - def __check_a(self, hostname): - key = '{0}:{1}'.format(hostname, 'A') - now = int(time.time()) - - value = "" - error_ip = "" - - ipaddress = mw.getLocalIp() - if not ipaddress: - return False, {"status": 0, "v_time": now, "value": error_ip} - - try: - resolver = dns.resolver.Resolver() - resolver.timeout = 1 - try: - result = resolver.resolve(hostname, 'A') - except: - result = resolver.query(hostname, 'A') - - for i in result.response.answer: - for j in i.items: - error_ip = j - if str(j).strip() in ipaddress: - value = str(j).strip() - - if value: - return True, {"status": 1, "v_time": now, "value": value} - return False, {"status": 0, "v_time": now, "value": error_ip} - except Exception as e: - raise e - return False, {"status": 0, "v_time": now, "value": error_ip} - - def flush_domain_record(self): - ''' - 手动刷新域名记录 - domain all/specify.com - :param args: - :return: - ''' - args = self.getArgs() - - if args['domain'] == 'all': - data_list = self.M('domain').order('created desc').field( - 'domain,a_record,created,active').select() - for item in data_list: - # try: - # if os.path.exists("/usr/bin/rspamd"): - # self.set_rspamd_dkim_key(item['domain']) - # if os.path.exists("/usr/sbin/opendkim"): - # self._gen_dkim_key(item['domain']) - # except: - # return mw.returnJson(False, '请检查Rspamd服务器是否已经启动!') - self.__gevent_jobs(item['domain'], item['a_record']) - # else: - # try: - # if os.path.exists("/usr/bin/rspamd"): - # self.set_rspamd_dkim_key(args.domain) - # if os.path.exists("/usr/sbin/opendkim"): - # self._gen_dkim_key(args.domain) - # except: - # return mw.returnJson(False, '请检查Rspamd服务器是否已经启动!') - # self._gevent_jobs(args['domain'], None) # 不需要验证A记录 - - # mw.writeFile(self._session_conf, json.dumps(self._session)) - - return mw.returnJson(True, '刷新成功!') - - def check_mail_env(self): - data = mi.mail_init().check_env() - return mw.returnJson(True, 'ok', data) - - def change_hostname(self): - ''' - mac - sudo scutil --set HostName mac_hostname.vm - ''' - args = self.getArgs() - hostname = args['hostname'] - rep_domain = "^(?=^.{3,255}$)[a-zA-Z0-9\_\-][a-zA-Z0-9\_\-]{0,62}(\.[a-zA-Z0-9\_\-][a-zA-Z0-9\_\-]{0,62})+$" - if not re.search(rep_domain, hostname): - return mw.returnJson(False, "请输入完整域名,例如 mail.bt.com),") - mw.execShell('hostnamectl set-hostname --static {}'.format(hostname)) - h = socket.gethostname() - if h == hostname: - return mw.returnJson(True, "设置成功!") - return mw.returnJson(False, "设置失败!") - - -if __name__ == "__main__": - func = sys.argv[1] - classApp = App() - try: - data = eval("classApp." + func + "()") - print(data) - except Exception as e: - print('error:' + str(e)) diff --git a/plugins/mail/info.json b/plugins/mail/info.json deleted file mode 100755 index 222e411ca..000000000 --- a/plugins/mail/info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "sort": 7, - "ps": "简单邮件服务[DEV]", - "name": "mail", - "title": "邮件服务", - "shell": "install.sh", - "versions":["1.0"], - "updates":["1.0"], - "tip": "soft", - "checks": "server/mail", - "path": "server/mail", - "display": 1, - "author": "midoks", - "date": "2022-09-13", - "home": "https://github.com/midoks/mdserver-web", - "type": 0, - "pid": "5" -} \ No newline at end of file diff --git a/plugins/mail/install.sh b/plugins/mail/install.sh deleted file mode 100755 index 83537d0d2..000000000 --- a/plugins/mail/install.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin -export PATH - -curPath=`pwd` -rootPath=$(dirname "$curPath") -rootPath=$(dirname "$rootPath") -serverPath=$(dirname "$rootPath") - -install_tmp=${rootPath}/tmp/mw_install.pl - -pip install dnspython - -if [ -f ${rootPath}/bin/activate ];then - source ${rootPath}/bin/activate - pip install dnspython -fi - - -action=$1 -type=$2 - -if [ "${2}" == "" ];then - echo '缺少安装脚本...' > $install_tmp - exit 0 -fi - -if [ ! -d $curPath/versions/$2 ];then - echo '缺少安装脚本2...' > $install_tmp - exit 0 -fi - -sh -x $curPath/versions/$2/install.sh $1 diff --git a/plugins/mail/js/mail.js b/plugins/mail/js/mail.js deleted file mode 100755 index b83c597ac..000000000 --- a/plugins/mail/js/mail.js +++ /dev/null @@ -1,626 +0,0 @@ -var mail = { - plugin_name: 'mail', - post_env_list:['HostName','Postfix-Version','Postfix-install','Sqlite-support','Dovecot-install','Redis-install','Redis-Passwd','Rspamd-install','SElinux'], - post_env_text:['主机名','Postfix版本','Postfix安装','Sqlite支持','Dovecot安装','Redis安装','Redis密码','Rspamd','SElinux'], - init: function () { - var _this = this; - - this.event(); - - $('.layui-layer-page').hide(); - - setTimeout(function () { - var win = $(window), - layer = $('.layui-layer-page'); - layer.show(); - layer.css({ - 'width':'1080px', - 'top':((win.height()-layer.height())/2)+'px', - 'left':((win.width()-1000)/2)+'px', - 'zIndex':'999' - }); - $('.layui-layer-shade').css('zIndex', '998'); - }, 200); - - - _this.check_mail_sys({ - tips: '正在检查邮局服务是否正常,请稍后....', - hostname: '' - }, function (res) { - console.log("aaaa",res); - if (res.status == false && res.msg == '之前没有安装过邮局系统,请放心安装!') { - layer.confirm('当前未设置邮局服务,是否现在设置?', { - icon: 0, - title: '邮局初始化', - btn: ['设置', '取消'], //按钮 - cancel: function () { - layer.closeAll(); - } - }, function (index) { - _this.check_post_env('setup_mail_sys'); - }, function () { - layer.closeAll(); - }); - } else { - // _this.create_domain_list(); - $('.tasklist .tab-nav span:first').click(); // 初始化 - _this.loadScript('/static/ckeditor/ckeditor.js', function () { - CKEDITOR.replace('editor1', { - customConfig: '/static/ckeditor/config.js?v1.0' - }) - }); - } - }); - - // _this.create_domain_list(); - }, - event: function () { - var _this = this; - - $('.bt-w-main .bt-w-menu p').click(function () { - var index = $(this).index(); - $(this).addClass('on').siblings().removeClass('on'); - $('.soft-man-con .task_block').eq(index).show().siblings().hide(); - console.log(index); - - - switch (index) { - case 0: - _this.create_domain_list(); - // _this.get_mailSSL_status(function (res) { - // $('#certificateSSL').prop("checked", res); - // }); - break; - } - }); - - - - - console.log(_this); - }, - - // 编辑添加邮箱用户视图-方法 - edit_domain_view: function (type, obj) { - var _this = this; - if (obj == undefined) { - obj = { - domain: '', - company_name: '', - admin_name: '', - admin_phone: '' - } - } - - layer.open({ - type: 1, - title: type ? '添加邮箱域名' : '编辑邮箱域名', - area: '500px', - closeBtn: 1, - btn: [type ? '提交' : '保存', '取消'], - content: "
\ -
\ - 邮箱域名\ -
\ - \ -
\ -
\ -
\ - A记录\ -
\ - \ -
\ -
\ -
\ - \ -
\ -
", - yes: function (index, layers) { - var array = [ - ['domain', '邮箱域名不能为空!', 'a_record', 'A记录值不能为空!'] - ], - _form = {}, - tel_reg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/; - for (var i = 0; i < array.length; i++) { - if ($('[name="' + array[i][0] + '"]').val() == '') { - layer.msg(array[i][1], { - icon: 2 - }); - return false; - } else if (array[i][0] == 'admin_phone' && !tel_reg.test($('[name="' + array[i] - [0] + '"]').val())) { - layer.msg('管理手机号码格式错误,请重试!', { - icon: 2 - }); - return false; - } - _form[array[i][0]] = $('[name="' + array[i][0] + '"]').val(); - _form[array[i][2]] = $('[name="' + array[i][2] + '"]').val(); - } - if (type) { - _this.add_domain(_form, function (res) { - console.log(res); - _this.create_domain_list({ - page: 1, - size: 10 - }, function (res) { - var rdata = res.msg.data, - hostname = rdata; - for (var i = 0; i < rdata.length; i++) { - if (rdata[i].domain == _form['domain']) hostname = - rdata[i]['domain'] - } - layer.close(index); - }); - }); - } else { - _form['active'] = obj.active; - _this.update_domain(_form, function (res) { - _this.create_domain_list({ - page: 1, - size: 10 - }, function (res) { - layer.msg(res.msg, { - icon: 1 - }); - layer.close(index); - }); - }); - } - } - }) - }, - - // 添加域名_请求 - add_domain: function (obj, callback) { - this.send({ - tips: '正在添加域名,请稍候...', - method: 'add_domain', - data: { - domain: obj.domain, - a_record: obj.a_record, - company_name: obj.company_name, - admin_name: obj.admin_name, - admin_phone: obj.admin_phone - }, - success: function (res) { - if (callback) callback(res); - } - }); - }, - // 获取域名列表_请求 - get_domain_list: function (obj, callback) { - this.send({ - tips: '正在获取域名列表,请稍候....', - method: 'get_domains', - data: { - p: obj.page, - size: obj.size - }, - success: function (res) { - if (callback) callback(res); - } - }) - }, - - flush_domain_record: function(obj,callback){ - var _this = this; - this.send({ - tips: obj == 'all'?'正在刷新所有域名记录,刷新时间视域名数量而定,请稍后...':'Refresh domain record, please wait...', - method: 'flush_domain_record', - data: { - domain: obj - }, - success: function (res) { - console.log(res); - if(res.status) _this.create_domain_list(); - if (callback) callback(res); - } - }); - }, - - // 创建域名列表-方法 - create_domain_list: function (obj, callback) { - if (obj == undefined) obj = { - page: 1, - size: 10 - } - var _this = this; - this.get_domain_list(obj, function (res) { - console.log(res); - var _tbody = '', - rdata = res.data.data; - _this.domain_list = rdata - if (rdata.length > 0) { - for (var i = 0; i < rdata.length; i++) { - _tbody += '\ - ' + rdata[i].domain + '\ - ' + (rdata[i].mx_status ? - '
已设置
' : - '
未设置记录值
') + '\ - ' + (rdata[i].a_status ? - '
已设置
' : - '
未设置记录值
') + '\ - ' + (rdata[i].spf_status ? - '
已设置
' : - '
未设置记录值
') + '\ - ' + (rdata[i].dkim_status ? - '
已设置
' : - '
未设置记录值
') + '\ - ' + (rdata[i].dmarc_status ? - '
已设置
' : - '
未设置记录值
') + '\ -
\ - '+(rdata[i].ssl_status?('到期时间: '+rdata[i].ssl_info.notAfter):'添加证书')+'\ - ' + (rdata[i].mx_status ? ( - '用户管理') : ( - '添加记录值')) + ' | \ - 删除\ - \ - '; - }; - } - $('#domain_list').html(_tbody); - $('#domain_page').html(res.page); - $('#domain_page a').click(function (e) { - _this.create_domain_list({ - page: $(this).attr('href').split('p=')[1], - size: 10 - }) - e.stopPropagation(); - e.preventDefault(); - }) - $('#flush_domain_record').unbind().on('click',function(e){ - _this.flush_domain_record('all',function(res){ - layer.msg(res.msg, { icon: res.status ? 1 : 2 }); - }); - }) - $('.add_certificate').unbind().on('click',function(){ - var index = $(this).attr('data-index') - _this.open_certificate_view(rdata[index].ssl_status, rdata[index].domain, rdata[index].ssl_info.dns, index) - }) - $('.catch_all').click(function (e) { - e.preventDefault(); - var _catch = $(this), - _status = $(this).prop('checked'), - _html = _status ? '
邮件转寄
' : '确认关闭此功能?', - loadT = layer.confirm(_html, {title:'CatchAll设置', closeBtn: 2, area: '500'},function(){ - var _email = _status ? $(".catchall").val() : '', - loadS = bt.load(); - _this.enable_catchall({domain:_catch.attr('id'), email: _email},function(res){ - loadS.close(); - if(res.status) _catch.prop('checked', _status); - layer.msg(res.msg, { icon: res.status ? 1 : 2 }); - loadT.close(); - }) - }); - }); - if (callback) callback(res); - }); - }, - - // 获取邮箱服务是否正常_请求 - check_mail_sys: function (obj, callback) { - this.send({ - tips: obj.tips, - method: 'check_mail_sys', - data: { - hostname: obj.hostname - }, - check: true, - success: function (res) { - if (callback) callback(res); - } - }) - }, - - // 检查邮箱环境 - check_mail_env:function(callback){ - this.send({ - tips: '正在检查邮局环境,请稍候...', - method: 'check_mail_env', - success: function (res) { - if (callback) callback(res); - } - }) - }, - - //检查邮局环境 - check_post_env:function (name) { - var _this = this; - var layerE = layer.open({ - skin:"", - type: 1, - closeBtn:1, - title:'检查邮局环境', - area: ['600px','520px'], //宽高 - btn: ['提交','取消','刷新列表'], - content:'\ -
\ -
\ -
\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
环境详情操作
\ -
\ -
\ - \ -
', - success:function(index){ - _this.create_post_env_table(); - }, - cancel:function(){ - layer.closeAll(); - }, - yes:function(){ - if($('#checkPostEnv').find('.set_mail_key').length > 0){ - layer.msg('请修复好所有的异常再提交'); - }else{ - switch (name){ - case 'setup_mail_sys': - _this.setup_mail_sys({tips:'正在初始化邮局...'},function(res){ - layer.close(layerE) - layer.msg(res.msg,{icon:res.status?1:2}); - _this.create_domain_list(); - }); - break; - case 'change_to_rspamd': - _this.change_to_rspamd(function(res){ - layer.close(layerE) - layer.msg(res.msg,{icon:res.status?1:2}); - _this.create_server_status_table() - }) - break; - } - } - }, - btn3: function(index, layero){ - _this.create_post_env_table(); - return false; - }, - btn2: function(index, layero){ - name == 'change_to_rspamd'?layer.close(layerE):layer.closeAll(); - }, - - }) - }, - - //创建邮局环境列表 - create_post_env_table:function (callback){ - var _this = this; - _this.check_mail_env(function(rdata){ - var res = rdata.data; - $('#checkPostEnv tbody').empty(); - $.each(_this.post_env_list,function(index,item){ - var list = []; - var noOperList = ['Redis-install', 'Redis-Passwd', 'SElinux']; - if(res[item].msg && noOperList.includes(item)){ - $('#checkPostEnv tbody').append($(''+_this.post_env_text[index] +''+(res[item].status?"就绪":(res[item].msg.toString().length>30?res[item].msg.toString().substring(0,30)+'...':res[item].msg.toString()))+'无操作')) - }else{ - $('#checkPostEnv tbody').append($(``+_this.post_env_text[index] +`${(res[item].status?"就绪":(res[item].msg !=''?(res[item].msg.toString().length>30?res[item].msg.toString().substring(0,30)+'...':res[item].msg.toString()):"异常"))}${(res[item].status?"无操作":"修复")}`)) - } - $('#checkPostEnv .divtable').removeClass('mtb10'); - }); - }); - - $('#checkPostEnv').unbind().on('click','a',function(){ - var key = $(this).attr('data-keys'); - var confirmA = layer.confirm('是否修复邮局环境?', { - title: '修复邮局环境', - icon: 3, - closeBtn:2, - btn: ['确定', '取消'], - },function(index, layero){ - _this.repair_mail_env(key); - }); - }) - if(callback) callback() - }, - - //修复邮局环境 - repair_mail_env: function (key) { - var _this = this,_key; - switch(key) { - case 'Postfix-Version': - case 'Postfix-install': - case 'Sqlite-support': - _key = 'repair_postfix'; - break; - case 'Rspamd-install': - _key = 'install_rspamd'; - break; - case 'Dovecot-install': - _key = 'repair_dovecot'; - break; - case 'HostName': - _key = 'repair_host_name'; - break; - } - if (key == 'HostName'){ - this.repair_host_name(); - return; - } - - this.send({ - tips: '正在修复' + key + ',请稍候...', - method: _key, - success: function (res) { - layer.msg(res.msg, { icon: res.status?1:2 }); - _this.create_post_env_table(); - } - }) - }, - - // 修复hostname - repair_host_name: function () { - var _this = this; - layer.open({ - type: 1, - shift: 5, - closeBtn: 1, - shadeClose: false, - title: '修复【主机名】', - btn: ['确定', '取消'], - area: "400px", - content: '\ -
\ -
\ - 域名\ -
\ - \ -
\ -
\ - \ -
', - success: function ($layer, index) { - }, - yes: function(index){ - var hostname = $('input[name="hostname"]').val().trim(); - if (hostname === '') { - layer.msg('请输入你的完整域名', { icon: 2, closeBtn: true }); - return - } - _this.change_hostname({ - hostname: hostname, - }, function (res) { - layer.close(index); - _this.create_post_env_table(); - layer.msg(res.msg, { icon: res.status ? 1 : 5 }); - }); - } - }); - }, - - // 一键修复主机名 - change_hostname: function(data, callback){ - this.send({ - tips: '正在获取修复主机名, 请稍候...', - method: 'change_hostname', - data: data, - success: function (res) { - if (callback) callback(res); - } - }); - }, - - str2Obj:function(str){ - var data = {}; - kv = str.split('&'); - for(i in kv){ - v = kv[i].split('='); - data[v[0]] = v[1]; - } - return data; - }, - - send:function(info){ - var tips = info['tips']; - var method = info['method']; - var args = info['data']; - var callback = info['success']; - - var loadT = layer.msg(tips, { icon: 16, time: 0, shade: 0.3 }); - - var data = {}; - data['name'] = 'mail'; - data['func'] = method; - data['version'] = $('.plugin_version').attr('version'); - - if (typeof(args) == 'string'){ - data['args'] = JSON.stringify(this.str2Obj(args)); - } else { - data['args'] = JSON.stringify(args); - } - - $.post('/plugins/run', data, function(res) { - layer.close(loadT); - if (!res.status){ - layer.msg(res.msg,{icon:2,time:10000}); - return; - } - - var ret_data = $.parseJSON(res.data); - console.log("send:",ret_data); - // if (!ret_data.status){ - // layer.msg(ret_data.msg,{icon:2,time:2000}); - // return; - // } - - // console.log("send2:",ret_data); - - if(typeof(callback) == 'function'){ - callback(ret_data); - } - },'json'); - }, - postCallback:function(info){ - var tips = info['tips']; - var method = info['method']; - var args = info['data']; - var callback = info['success']; - - var loadT = layer.msg(tips, { icon: 16, time: 0, shade: 0.3 }); - - var data = {}; - data['name'] = 'mail'; - data['func'] = method; - data['version'] = $('.plugin_version').attr('version'); - - if (typeof(args) == 'string'){ - data['args'] = JSON.stringify(this.str2Obj(args)); - } else { - data['args'] = JSON.stringify(args); - } - - $.post('/plugins/callback', data, function(res) { - - layer.close(loadT); - if (!res.status){ - layer.msg(res.msg,{icon:2,time:10000}); - return; - } - - var ret_data = $.parseJSON(res.data); - if (!ret_data.status){ - layer.msg(ret_data.msg,{icon:2,time:2000}); - return; - } - - if(typeof(callback) == 'function'){ - callback(res); - } - },'json'); - } -} diff --git a/plugins/mail/mail_init.py b/plugins/mail/mail_init.py deleted file mode 100644 index 413e71ae3..000000000 --- a/plugins/mail/mail_init.py +++ /dev/null @@ -1,69 +0,0 @@ -# coding:utf-8 - -import sys -import io -import os -import time -import re - - -sys.path.append(os.getcwd() + "/class/core") - -import mw -app_debug = False -if mw.isAppleSystem(): - app_debug = True - - -class mail_init: - - def __init__(self): - self.logfile = '/tmp/mail_init.log' - - def check_env(self): - data = {} - data['HostName'] = self.check_hostname() - data['Postfix-install'] = {"status": True, "msg": "Postfix已经安装"} if os.path.exists( - '/usr/sbin/postfix') else {"status": False, "msg": "Postfix未安装,请点击修复按钮"} - data['Dovecot-install'] = {"status": True, "msg": "Deovecot已经安装"} if os.path.exists( - '/usr/sbin/dovecot') else {"status": False, "msg": "Dovecot未安装,请点击修复按钮"} - data['Postfix-Version'] = self.check_postfix_ver() - data['Redis-install'] = {"status": True, "msg": "Redis已经安装"} if os.path.exists( - mw.getServerDir() + '/redis/bin/redis-server') else {"status": False, "msg": "请到软件商店内安装Redis"} - data['Redis-Passwd'] = self.check_redis_passwd(data['Redis-install']) - data['Rspamd-install'] = {"status": True, "msg": "Rspamd已经安装"} if os.path.exists( - '/usr/bin/rspamd') else {"status": False, "msg": "Rspamd未安装,请点击修复按钮"} - data['Sqlite-support'] = self.check_sqlite() - data['SElinux'] = {"status": True, "msg": "SElinux已经禁用"} if not 'enforcing' in mw.execShell( - 'getenforce')[0].lower() else {"status": False, "msg": "请先禁用SElinux"} - return data - - def check_hostname(self): - import socket - rep = '^(?!:\/\/)(?=.{1,255}$)((.{1,63}\.){1,127}(?![0-9]*$)[a-z0-9-]+\.?)$' - hostname = socket.gethostname() - if re.search(rep, hostname): - return mw.returnData(True, 'success') - return mw.returnData(False, '你的主机名 ({}) 不合规定, 需要是完整域名' - '你可以通过以下命令修复你的主机名 ' - '在ssh终端执行 \'hostnamectl set-hostname --static mail.example.com\''.format(hostname)) - - def check_postfix_ver(self): - postfix_version = mw.execShell( - r"postconf mail_version|sed -r 's/.* ([0-9\.]+)$/\1/'")[0].strip() - if postfix_version.startswith('3'): - return mw.returnData(True, postfix_version) - else: - return mw.returnData(False, "当前版本不支持或Postfix没有安装成功:{}".format(postfix_version)) - - def check_redis_passwd(self, redis_install): - redis_conf = mw.readFile(mw.getServerDir() + '/redis/redis.conf') - if redis_install['status']: - if re.search('\n\s*requirepass', redis_conf): - return mw.returnData(True, "Redis已经设置密码") - return mw.returnData(False, "请到Redis管理器设置密码!") - - def check_sqlite(self): - if not mw.execShell('postconf -m | grep sqlite')[0].strip(): - return mw.returnData(False, "Postfix不支持Sqlite") - return mw.returnData(True, "Postfix已支持Sqlite") diff --git a/plugins/mail/versions/1.0/install.sh b/plugins/mail/versions/1.0/install.sh deleted file mode 100755 index 337d17960..000000000 --- a/plugins/mail/versions/1.0/install.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/bash -PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin -export PATH - -curPath=`pwd` -rootPath=$(dirname "$curPath") -rootPath=$(dirname "$rootPath") -serverPath=$(dirname "$rootPath") - -install_tmp=${rootPath}/tmp/mw_install.pl -VERSION=$2 - -cpu_arch=`arch` -if [[ $cpu_arch != "x86_64" ]];then - echo 'Does not support non-x86 system installation' - exit 0 -fi - -# if [ -f "/usr/bin/apt-get" ];then -# systemver='ubuntu' -# elif [ -f "/etc/redhat-release" ];then -# systemver=`cat /etc/redhat-release|sed -r 's/.* ([0-9]+)\..*/\1/'` -# postfixver=`postconf mail_version|sed -r 's/.* ([0-9\.]+)$/\1/'` -# else -# echo 'Unsupported system version' -# exit 0 -# fi - -## curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash -## debug: -## cd /www/server/mdserver-web/plugins/mail && bash install.sh install 1.0 - -bash ${rootPath}/scripts/getos.sh -OSNAME=`cat ${rootPath}/data/osname.pl` -OSNAME_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'` - - -Install_debain(){ - hostname=`hostname` - # 安装postfix和postfix-sqlite - debconf-set-selections <<< "postfix postfix/mailname string ${hostname}" - debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Internet Site'" - apt install postfix -y - apt install postfix-sqlite -y - apt install sqlite -y - - # 安装dovecot和dovecot-sieve - apt install dovecot-core dovecot-pop3d dovecot-imapd dovecot-lmtpd dovecot-sqlite dovecot-sieve -y - - apt install rspamd -y - - apt install cyrus-sasl-plain -y -} - -Uninstall_debain(){ - apt remove postfix postfix-sqlite -y && rm -rf /etc/postfix - dpkg -P postfix postfix-sqlite - apt remove dovecot-core dovecot-imapd dovecot-lmtpd dovecot-pop3d dovecot-sqlite dovecot-sieve -y - dpkg -P dovecot-core dovecot-imapd dovecot-lmtpd dovecot-pop3d dovecot-sqlite dovecot-sieve - apt remove opendkim opendkim-tools -y - dpkg -P opendkim opendkim-tools - apt remove rspamd -y - dpkg -P rspamd -} - -Install_ubuntu(){ - Install_debain -} - -Uninstall_ubuntu(){ - Uninstall_debain -} - -Install_App() -{ - echo '正在安装脚本文件...' > $install_tmp - mkdir -p $serverPath/source - - runScript=$curPath/install_$OSNAME.sh - - if [[ -f $runScript ]]; then - sh -x $runScript install - elif [[ $OSNAME = "debian" ]]; then - Install_debain - else - Install_ubuntu - fi - - if [ ! -f /etc/dovecot/conf.d/90-sieve.conf ];then - if [ -f "/usr/bin/apt-get" ];then - apt install dovecot-sieve -y - else - rm -rf /etc/dovecot_back - cp -a /etc/dovecot /etc/dovecot_back - yum remove dovecot -y - yum install dovecot-pigeonhole -y - if [ ! -f /usr/sbin/dovecot ]; then - yum install dovecot -y - fi - \cp -a /etc/dovecot_back/* /etc/dovecot - chown -R vmail:dovecot /etc/dovecot - chmod -R o-rwx /etc/dovecot - - systemctl enable dovecot - systemctl restart dovecot - fi - fi - - filesize=`ls -l /etc/dovecot/dh.pem | awk '{print $5}'` - echo $filesize - - if [ ! -f "/etc/dovecot/dh.pem" ] || [ $filesize -lt 300 ]; then - openssl dhparam 2048 > /etc/dovecot/dh.pem - fi - - mkdir -p $serverPath/mail - echo '1.0' > $serverPath/mail/version.pl - echo '安装完成' > $install_tmp -} - -Uninstall_App() -{ - runScript=$curPath/install_$OSNAME.sh - if [[ -f $runScript ]]; then - sh -x $runScript uninstall - elif [[ $OSNAME = "debian" ]]; then - Uninstall_debain - else - Uninstall_ubuntu - fi - - if [ -f $serverPath/mail/initd/mail ];then - $serverPath/mail/initd/mail stop - fi - - rm -rf /etc/postfix - rm -rf /etc/dovecot - rm -rf /etc/opendkim - rm -rf /usr/share/rspamd/www/rspamd - echo "Uninstall_Mail" > $install_tmp -} - -action=$1 -if [ "${1}" == 'install' ];then - Install_App -else - Uninstall_App -fi diff --git a/plugins/mail/versions/1.0/install_centos.sh b/plugins/mail/versions/1.0/install_centos.sh deleted file mode 100644 index e30a78a16..000000000 --- a/plugins/mail/versions/1.0/install_centos.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash -PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin -export PATH - -curPath=`pwd` -rootPath=$(dirname "$curPath") -rootPath=$(dirname "$rootPath") -serverPath=$(dirname "$rootPath") - -cpu_arch=`arch` -if [[ $cpu_arch != "x86_64" ]];then - echo 'Does not support non-x86 system installation' - exit 0 -fi - - -OSNAME_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'` - -Install_centos8() -{ - yum install epel-release -y - # 卸载系统自带的postfix - if [[ $cpu_arch = "x86_64" && $postfixver != "3.4.9" ]];then - yum remove postfix -y - rm -rf /etc/postfix - fi - # 安装postfix和postfix-sqlite - yum localinstall $pluginPath/rpm/postfix3-3.4.9-1.gf.el8.x86_64.rpm -y - yum localinstall $pluginPath/rpm/postfix3-sqlite-3.4.9-1.gf.el8.x86_64.rpm -y - if [[ ! -f "/usr/sbin/postfix" ]]; then - yum install postfix -y - yum install postfix-sqlite -y - fi - # 安装dovecot和dovecot-sieve - yum install dovecot-pigeonhole -y - if [[ ! -f "/usr/sbin/dovecot" ]]; then - yum install dovecot -y - fi - # 安装opendkim -# 安装rspamd - - install_rspamd - yum install cyrus-sasl-plain -y -} - -Install_centos7() { - - yum install epel-release -y - # 卸载系统自带的postfix - if [[ $cpu_arch = "x86_64" && $postfixver != "3.4.7" ]];then - yum remove postfix -y - rm -rf /etc/postfix - fi - # 安装postfix和postfix-sqlite - yum localinstall $pluginPath/rpm/postfix3-3.4.7-1.gf.el7.x86_64.rpm -y - yum localinstall $pluginPath/rpm/postfix3-sqlite-3.4.7-1.gf.el7.x86_64.rpm -y - if [[ ! -f "/usr/sbin/postfix" ]]; then - yum install postfix -y - yum install postfix-sqlite -y - fi - # 安装dovecot和dovecot-sieve - yum install dovecot-pigeonhole -y - if [[ ! -f "/usr/sbin/dovecot" ]]; then - yum install dovecot -y - fi - #安装rspamd - install_rspamd - yum install cyrus-sasl-plain -y - -} - -install_rspamd() { - if [[ $OSNAME_ID = "7" ]];then - wget -O /etc/yum.repos.d/rspamd.repo https://rspamd.com/rpm-stable/centos-7/rspamd.repo - rpm --import https://rspamd.com/rpm-stable/gpg.key - yum makecache - yum install rspamd -y - elif [ $OSNAME_ID = "8" ]; then - wget -O /etc/yum.repos.d/rspamd.repo https://rspamd.com/rpm-stable/centos-8/rspamd.repo - rpm --import https://rspamd.com/rpm-stable/gpg.key - yum makecache - yum install rspamd -y - else - CODENAME=`lsb_release -c -s` - mkdir -p /etc/apt/keyrings - wget -O- https://rspamd.com/apt-stable/gpg.key | gpg --dearmor | tee /etc/apt/keyrings/rspamd.gpg > /dev/null - echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ $CODENAME main" | tee /etc/apt/sources.list.d/rspamd.list - echo "deb-src [arch=amd64 signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ $CODENAME main" | tee -a /etc/apt/sources.list.d/rspamd.list - apt-get update - export DEBIAN_FRONTEND=noninteractive - apt-get --no-install-recommends install rspamd -y - fi -} - -Install_App() { - if [ "$OSNAME_ID" == "7" ];then - Install_centos7 - elif [ "$OSNAME_ID" == "8" ];then - Install_centos8 - fi -} - -Uninstall_App() -{ - yum remove postfix -y - yum remove dovecot -y - yum remove opendkim -y - yum remove rspamd -y - yum remove dovecot-pigeonhole -y -} - - -action=$1 -if [ "${1}" == 'install' ];then - Install_App -else - Uninstall_App -fi \ No newline at end of file