mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-23 08:02:24 +02:00
1. Added Domains menu to manage Domains and SSL Certificates 2. Added Add Site automatic record creation when adding websites (Only supported by IPv4) 3. Added Vietnamese language 4. Added Indonesian language 5. Added HTTPS Protection function for Website (disables automatic HTTP to HTTPS redirection when enabled) 6. Added Mail Marketing -- Automation trigger tasks 7. Added Mail Marketing -- Groups Import, Export, Merge 8. Added Mail Marketing -- Subscribers to support paste import 9. Added Mail Marketing -- Template Import Export Duplicate 10. Added Mail server -- Other Settings add timed Auto Responder 11. Added Mail Marketing -- Suspend List to detect abnormal mailboxes 12. Added Mail Marketing -- Marketing Task to export error mail logs 13. Added Mail Domain -- SSL certificate expiration alert 14. Optimized Webmail management to display based on domain additions 15. Optimize Website Interface Button Integration 16. Optimize the response speed of WP Toolkit interface
895 lines
32 KiB
Python
895 lines
32 KiB
Python
# coding: utf-8
|
|
# ------------------------------
|
|
# 域名管理
|
|
# ------------------------------
|
|
import json
|
|
import os.path
|
|
import shutil
|
|
import threading
|
|
import time
|
|
from datetime import datetime
|
|
|
|
import public
|
|
from BTPanel import cache
|
|
from panelDnsapi import extract_zone
|
|
from panel_site_v2 import panelSite
|
|
from public.aaModel import Q
|
|
from public.validate import Param
|
|
from .config import DNS_MAP, UseFor, DnsTask
|
|
from .model import (
|
|
DnsDomainProvider,
|
|
DnsDomainRecord,
|
|
DnsDomainSSL,
|
|
DnsDomainTask,
|
|
)
|
|
from .service import (
|
|
init_dns_process,
|
|
SyncService,
|
|
DomainValid,
|
|
make_suer_alarm_task,
|
|
make_suer_renew_task,
|
|
)
|
|
|
|
|
|
# noinspection PyUnusedLocal
|
|
class DomainObject:
|
|
date_format = "%Y-%m-%d"
|
|
vhost = os.path.join(public.get_panel_path(), "vhost")
|
|
sender_task = os.path.join(
|
|
public.get_panel_path(), "data/mod_push_data/sender.json"
|
|
)
|
|
|
|
def __init__(self):
|
|
self.supports = list(DNS_MAP.keys())
|
|
|
|
@staticmethod
|
|
def _end_time(data_str: str) -> int:
|
|
if not data_str:
|
|
return 0
|
|
today = datetime.today().date()
|
|
end_date = datetime.strptime(data_str, DomainObject.date_format).date()
|
|
return (end_date - today).days if today <= end_date else 0
|
|
|
|
@staticmethod
|
|
def _hide_account(data: dict, key: str = "api_user") -> dict:
|
|
if len(data.get(key, "")) > 0:
|
|
data[key] = data[key][:len(data[key]) // 2] + "***"
|
|
return data
|
|
|
|
@staticmethod
|
|
def _add_ssl_info(data: dict) -> dict:
|
|
new_domains = []
|
|
domains = data.get("domains", [])
|
|
for domain in domains:
|
|
ssl_obj = DnsDomainSSL.objects.filter(
|
|
Q(provider_id=data.get("id", 0)) & (Q(subject=domain) | Q(subject=f"*.{domain}"))
|
|
).order_by("-create_time").first()
|
|
if not ssl_obj:
|
|
ssl_info = {
|
|
"id": 0,
|
|
"end_time": -1,
|
|
"end_date": "-",
|
|
"alarm": 0,
|
|
"auto_renew": 0,
|
|
}
|
|
else:
|
|
ssl_info = {
|
|
"id": ssl_obj.id,
|
|
"end_time": DomainObject._end_time(ssl_obj.not_after),
|
|
"end_date": ssl_obj.not_after,
|
|
"alarm": ssl_obj.alarm,
|
|
"auto_renew": ssl_obj.auto_renew,
|
|
}
|
|
new_domains.append(
|
|
{"name": domain, "ssl_info": ssl_info}
|
|
)
|
|
data["domains"] = new_domains
|
|
return data
|
|
|
|
@staticmethod
|
|
def _add_task_info(data: dict, task_name: str = None) -> dict:
|
|
# 初始化, 申请任意域名, 续签, 同步
|
|
tasks_obj = DnsDomainTask.objects.filter(
|
|
provider_id=data.get("id", 0), task_status__lt=100
|
|
)
|
|
if task_name:
|
|
tasks_obj.filter(task_name=task_name)
|
|
|
|
data["task"] = tasks_obj.order_by("-create_time").as_list()
|
|
return data
|
|
|
|
def get_dns_support(self, get):
|
|
return public.success_v2(self.supports)
|
|
|
|
# =========== 托管商 ===========
|
|
def sync_dns_info(self, get):
|
|
"""
|
|
对账号立即同步域名信息
|
|
"""
|
|
target_id = get.id if hasattr(get, "id") else None
|
|
running = SyncService().get_lock()
|
|
if running is False:
|
|
task = threading.Thread(target=SyncService(target_id).process)
|
|
task.start()
|
|
return public.success_v2("success")
|
|
|
|
def list_dns_api(self, get):
|
|
"""
|
|
dns api 列表
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("p").Integer(),
|
|
Param("limit").Integer(),
|
|
Param("pid").Integer(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
|
|
# clear task
|
|
try:
|
|
one_hours = 1000 * 60 * 60
|
|
out_time = round(time.time() * 1000) - one_hours
|
|
DnsDomainTask.objects.filter(create_time__lte=out_time).delete()
|
|
except Exception:
|
|
pass
|
|
|
|
page = int(getattr(get, "p", 1))
|
|
limit = int(getattr(get, "limit", 100))
|
|
obj = DnsDomainProvider.objects.all()
|
|
if hasattr(get, "pid"):
|
|
obj = DnsDomainProvider.objects.filter(id=get.pid)
|
|
total = obj.count()
|
|
result = obj.limit(limit).offset((page - 1) * limit).as_list()
|
|
for r in result:
|
|
r = self._hide_account(r)
|
|
r = self._add_ssl_info(r)
|
|
r = self._add_task_info(r)
|
|
return public.success_v2({"data": result, "total": total})
|
|
|
|
def create_dns_api(self, get):
|
|
try:
|
|
get.validate([
|
|
Param("name").String().Require(),
|
|
Param("api_user").String().Require(),
|
|
Param("api_key").String().Require(),
|
|
Param("permission").String(),
|
|
Param("alias").String().Require(),
|
|
Param("status").Integer(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
if "*" in get.api_user:
|
|
return public.fail_v2("'*' Symbols that are not allowed")
|
|
if hasattr(get, "status"):
|
|
get.status = int(get.status)
|
|
if get.name not in self.supports:
|
|
return public.fail_v2(f"Provider not support! Support DNS provider :{self.supports}")
|
|
if get.name == "CloudFlareDns":
|
|
if not hasattr(get, "permission") or get.permission not in ["limit", "global"]:
|
|
return public.fail_v2("CloudFlareDns Permission must be 'limit' or 'global'!")
|
|
else:
|
|
get.permission = "-"
|
|
try:
|
|
dns_obj = DnsDomainProvider(**get.get_items()).save()
|
|
if dns_obj:
|
|
init_task = threading.Thread(
|
|
target=init_dns_process, args=(dns_obj.as_dict(),)
|
|
)
|
|
init_task.start()
|
|
else:
|
|
return public.fail_v2("Please Upgrade PRO Version!")
|
|
except Exception as ex:
|
|
import traceback
|
|
public.print_log(traceback.format_exc())
|
|
return public.fail_v2(str(ex))
|
|
return public.success_v2("Save Successfully!")
|
|
|
|
def delete_dns_api(self, get):
|
|
try:
|
|
get.validate([
|
|
Param("id").Integer().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
DnsDomainRecord.objects.filter(provider_id=int(get.id)).delete()
|
|
DnsDomainProvider.objects.filter(id=int(get.id)).delete()
|
|
return public.success_v2("Delete Successfully!")
|
|
|
|
def edit_dns_api(self, get):
|
|
if not hasattr(get, "id"):
|
|
return public.fail_v2("id is required")
|
|
if hasattr(get, "status"):
|
|
get.status = int(get.status)
|
|
if hasattr(get, "name") and get.name == "CloudFlareDns":
|
|
if not hasattr(get, "permission") or get.permission not in ["limit", "global"]:
|
|
return public.fail_v2("CloudFlareDns Permission must be 'limit' or 'global'")
|
|
if hasattr(get, "user") and "*" in get.api_user:
|
|
return public.fail_v2("'*' symbols that are not allowed")
|
|
|
|
try:
|
|
DnsDomainProvider.objects.filter(id=get.id).update(get.get_items())
|
|
except Exception as ex:
|
|
return public.fail_v2(str(ex))
|
|
return public.success_v2("Save Successfully!")
|
|
|
|
# =========== dns 记录 ===========
|
|
def list_dns_record(self, get):
|
|
try:
|
|
get.validate([
|
|
Param("p").Integer(),
|
|
Param("limit").Integer(),
|
|
Param("search_pid").Integer().Require(),
|
|
Param("domain").String(),
|
|
Param("search").String(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
page = int(getattr(get, "p", 1))
|
|
limit = int(getattr(get, "limit", 100))
|
|
pid = int(get.search_pid)
|
|
provider = DnsDomainProvider.objects.find_one(id=pid)
|
|
if not provider:
|
|
return public.fail_v2("Provider not found!")
|
|
if hasattr(get, "domain"):
|
|
domain_name = get.domain
|
|
else:
|
|
domain_name = provider.domains[0] if provider.domains else ""
|
|
|
|
cache_expire = False
|
|
key = f"aaDomain_{provider.id}_{domain_name}"
|
|
if cache: # 1min cache
|
|
cache_data = cache.get(key)
|
|
cache_expire = True if cache_data is None else False
|
|
if cache_expire: # refresh data
|
|
SyncService().records_process(
|
|
provider_obj=provider, all_domains=[domain_name]
|
|
)
|
|
cache.set(key, "1", 60)
|
|
|
|
if not hasattr(get, "search"):
|
|
obj = DnsDomainRecord.objects.filter(provider_id=pid, domain=domain_name)
|
|
else:
|
|
obj = DnsDomainRecord.objects.filter(
|
|
Q(provider_id=pid, domain=domain_name) & (
|
|
Q(record__like=get.search) | Q(record_value__like=get.search)
|
|
)
|
|
)
|
|
|
|
total = obj.count()
|
|
result = obj.limit(limit).offset((page - 1) * limit).as_list()
|
|
data = []
|
|
for r in result:
|
|
r = self._hide_account(r)
|
|
data.append(r)
|
|
data.sort(key=lambda x: (x["record_type"], x["record"]))
|
|
return public.success_v2({"data": data, "total": total})
|
|
|
|
def create_dns_record(self, get):
|
|
try:
|
|
get.validate([
|
|
Param("pid").Integer().Require(),
|
|
Param("domain").String().Require(),
|
|
Param("record").String().Require(),
|
|
Param("record_type").String().Require(),
|
|
Param("record_value").String().Require(),
|
|
Param("ttl").Integer().Require(),
|
|
Param("proxy").Integer(),
|
|
Param("ps").String(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
|
|
provider = DnsDomainProvider.objects.filter(id=int(get.pid)).first()
|
|
body = {
|
|
"provider_id": provider.id,
|
|
"provider_name": provider.name,
|
|
"api_user": provider.api_user,
|
|
"domain": get.domain,
|
|
"record": get.record,
|
|
"record_type": get.record_type,
|
|
"record_value": get.record_value,
|
|
"ttl": int(get.ttl),
|
|
"proxy": int(get.proxy),
|
|
}
|
|
if hasattr(get, "ps"):
|
|
body["ps"] = get.ps
|
|
response = provider.model_create_dns_record(body)
|
|
if not response.get("status"):
|
|
return public.fail_v2(response.get("msg"))
|
|
return public.success_v2("Save Successfully!")
|
|
|
|
def delete_dns_record(self, get):
|
|
try:
|
|
get.validate([
|
|
Param("id").Integer().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
record = DnsDomainRecord.objects.find_one(id=int(get.id))
|
|
if not record:
|
|
return public.fail_v2("DNS record Not Found!")
|
|
provider = DnsDomainProvider.objects.find_one(id=record.provider_id)
|
|
if not provider:
|
|
return public.fail_v2("DNS Provider Not Found!")
|
|
response = provider.model_delete_dns_record(int(get.id))
|
|
if not response.get("status"):
|
|
return public.fail_v2(response.get("msg"))
|
|
return public.success_v2("Delete Successfully!")
|
|
|
|
def edit_dns_record(self, get):
|
|
try:
|
|
get.validate([
|
|
Param("id").Integer().Require(),
|
|
Param("pid").Integer().Require(),
|
|
Param("domain").String().Require(),
|
|
Param("record").String().Require(),
|
|
Param("record_type").String().Require(),
|
|
Param("record_value").String().Require(),
|
|
Param("ttl").Integer().Require(),
|
|
Param("proxy").Integer().Require(),
|
|
Param("ps").String(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
pid = int(get.pid)
|
|
record_id = int(get.id)
|
|
ps = get.ps if hasattr(get, "ps") else ""
|
|
# check if change
|
|
real_change = False
|
|
provider = DnsDomainProvider.objects.find_one(id=pid)
|
|
if not provider:
|
|
return public.fail_v2("DNS Provider Not Found!")
|
|
target = DnsDomainRecord.objects.find_one(id=record_id)
|
|
if not target:
|
|
return public.fail_v2("DNS Record Not Found!")
|
|
new_body = {
|
|
"provider_id": provider.id,
|
|
"provider_name": provider.name,
|
|
"api_user": provider.api_user,
|
|
"domain": get.domain,
|
|
"record": get.record,
|
|
"record_type": get.record_type,
|
|
"record_value": get.record_value,
|
|
"ttl": int(get.ttl),
|
|
"proxy": int(get.proxy),
|
|
"ps": ps,
|
|
}
|
|
if any([
|
|
target.record != get.record,
|
|
target.record_type != get.record_type,
|
|
target.record_value != get.record_value,
|
|
target.ttl != int(get.ttl),
|
|
target.proxy != int(get.proxy),
|
|
]):
|
|
real_change = True
|
|
if not real_change:
|
|
DnsDomainRecord.objects.filter(id=record_id).update(new_body)
|
|
return public.success_v2("Update Successfully!")
|
|
# real change
|
|
try:
|
|
update = provider.model_edit_dns_record(record_id, new_body)
|
|
if update.get("status"):
|
|
return public.success_v2("Update Successfully!")
|
|
else:
|
|
return public.fail_v2(update.get("msg", "Update Failed..."))
|
|
except Exception as ex:
|
|
return public.fail_v2(str(ex))
|
|
|
|
# ========== 域名管理概况 SSL =======
|
|
def list_domain_details(self, get):
|
|
try:
|
|
get.validate([
|
|
Param("p").Integer(),
|
|
Param("limit").Integer(),
|
|
Param("id").Integer().Require(),
|
|
Param("domain").String(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
|
|
page = int(getattr(get, "p", 1))
|
|
limit = int(getattr(get, "limit", 100))
|
|
provider = DnsDomainProvider.objects.find_one(id=get.id)
|
|
if not provider:
|
|
return public.fail_v2("DNS Provider Not Found!")
|
|
data = self._add_ssl_info(provider.as_dict())
|
|
data = data.get("domains", [])
|
|
if hasattr(get, "domain"): # filter domain
|
|
data = [x for x in data if get.domain in x.get("name", "")]
|
|
|
|
for d in data:
|
|
d["records"] = DnsDomainRecord.objects.filter(
|
|
domain=d.get("name", ""), provider_id=int(get.id)
|
|
).count()
|
|
total = len(data)
|
|
start = (page - 1) * limit
|
|
end = start + limit
|
|
return public.success_v2({"data": data[start:end], "total": total})
|
|
|
|
# =========== SSL ============
|
|
def list_ssl_info(self, get):
|
|
"""
|
|
证书列表
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("p").Integer(),
|
|
Param("limit").String(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
page = int(getattr(get, "p", 1))
|
|
limit = int(getattr(get, "limit", 100))
|
|
ssl_obj = DnsDomainSSL.objects.all()
|
|
total = ssl_obj.count()
|
|
ssl_obj.limit(limit).offset((page - 1) * limit)
|
|
data = [
|
|
self._add_task_info(
|
|
data={
|
|
"hash": ssl.hash,
|
|
"provider": ssl.info.get("issuer_O", "unknown"),
|
|
"issuer": ssl.info.get("issuer", "unknown"),
|
|
"verify_domains": list(set(ssl.dns + [ssl.subject])),
|
|
"end_time": self._end_time(ssl.not_after),
|
|
"end_date": ssl.not_after,
|
|
"auto_renew": ssl.auto_renew,
|
|
"last_apply_time": ssl.create_time,
|
|
"cert": {
|
|
"csr": public.readFile(ssl.path + "/fullchain.pem"), # 证书
|
|
"key": public.readFile(ssl.path + "/privkey.pem"), # 密钥
|
|
},
|
|
"log": ssl.get_ssl_log(),
|
|
"use_for": ssl.user_for,
|
|
"alarm": ssl.alarm,
|
|
},
|
|
# task_name=DnsTask.apply_ssl.value,
|
|
) for ssl in ssl_obj
|
|
]
|
|
return public.success_v2({"data": data, "total": total})
|
|
|
|
def download_cert(self, get):
|
|
"""
|
|
下载
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("hash").String().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
file_path = "/www/server/panel/vhost" + f"/ssl_saved/{get.hash}"
|
|
if not os.path.exists(file_path):
|
|
return public.fail_v2("SSL Certificate Not Found!")
|
|
|
|
download_path = os.path.join(self.vhost, f"/ssl_saved/download")
|
|
if not os.path.exists(download_path):
|
|
os.makedirs(download_path)
|
|
|
|
output_path = os.path.join(download_path, f"{get.hash}")
|
|
if os.path.exists(f"{output_path}.zip"):
|
|
return public.success_v2(f"{output_path}.zip")
|
|
try:
|
|
shutil.make_archive(output_path, "zip", file_path)
|
|
except Exception as e:
|
|
return public.fail_v2(f"error: {str(e)}")
|
|
return public.success_v2(f"{output_path}.zip")
|
|
|
|
def renew_cert(self, get):
|
|
"""
|
|
续签
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("hash").String(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
|
|
if hasattr(get, "hash"):
|
|
ssl_obj = DnsDomainSSL.objects.filter(hash=get.hash)
|
|
else:
|
|
ts_month = 30 * 24 * 60 * 60 * 1000
|
|
ssl_obj = DnsDomainSSL.objects.filter(not_after_ts__lt=int(time.time() * 1000) + ts_month)
|
|
|
|
log = None
|
|
for ssl in ssl_obj:
|
|
provider = DnsDomainProvider.objects.find_one(id=ssl.provider_id)
|
|
if not provider:
|
|
return public.fail_v2("DNS Provider Not Found!")
|
|
log = provider.get_ssl_log(ssl.dns)
|
|
renew_task = threading.Thread(target=provider.model_apply_cert, args=(ssl.dns,))
|
|
renew_task.start()
|
|
|
|
if hasattr(get, "hash"):
|
|
return public.success_v2(log)
|
|
else:
|
|
return public.success_v2("Successfully Renewed!")
|
|
|
|
def apply_new_ssl(self, get):
|
|
"""
|
|
申请证书
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("domains").String().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
get.domains = json.loads(get.domains)
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
|
|
targets = []
|
|
provider = None
|
|
for d in get.domains:
|
|
if not targets:
|
|
root, _, _ = extract_zone(d)
|
|
provider = DnsDomainProvider.objects.find_one(domains__has_element=root)
|
|
if not provider:
|
|
return public.fail_v2(f"DNS Provider Not Found! for {root}")
|
|
targets = provider.domains
|
|
temp_root, _, _ = extract_zone(d)
|
|
if temp_root not in targets:
|
|
return public.fail_v2("domains do not belong to the same DNS Provider Account. Please verify.")
|
|
apply_domains = list(set(get.domains))
|
|
log = provider.get_ssl_log(apply_domains)
|
|
apply_task = threading.Thread(
|
|
target=provider.model_apply_cert, args=(apply_domains,)
|
|
)
|
|
apply_task.start()
|
|
return public.success_v2(log)
|
|
|
|
def upload_cert(self, get):
|
|
"""
|
|
上传证书
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("key").String().Require(),
|
|
Param("cert").String().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
from ssl_manage import SSLManger
|
|
try:
|
|
data = SSLManger().save_by_data(get.cert, get.key)
|
|
if data:
|
|
# 再次检测, 兼容被跳过的情况
|
|
ssl = DnsDomainSSL.objects.filter(hash=data.get("hash")).first()
|
|
if not ssl:
|
|
del data["id"]
|
|
del data["create_time"]
|
|
# 从auth中尝试匹配现有api
|
|
provider, account, token = data.get("auth_info").get("auth_to", "||").split("|")
|
|
p_obj = DnsDomainProvider.objects.filter(
|
|
name=provider, api_user=account, api_key=token
|
|
).first()
|
|
pid = p_obj.id if p_obj and provider != "" else 0
|
|
data["provider_id"] = pid
|
|
DnsDomainSSL(**data).save()
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.fail_v2(str(ex))
|
|
return public.success_v2("success")
|
|
|
|
def remove_cert(self, get):
|
|
"""
|
|
删除证书
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("hash").String().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
ssl_obj = DnsDomainSSL.objects.find_one(hash=get.hash)
|
|
if not ssl_obj:
|
|
return public.fail_v2("SSL Certificate Not Found!")
|
|
# vhost/ssl为site ssl证书存放目录
|
|
vpath = os.path.join(self.vhost, "ssl", ssl_obj.subject)
|
|
if os.path.exists(vpath):
|
|
public.ExecShell("rm -rf " + vpath)
|
|
|
|
try:
|
|
from ssl_manage import ssl_db as old_ssl_db
|
|
old_ssl_db.connection().where("hash=?", (get.hash,)).delete()
|
|
public.S("ssl_info").where("hash=?", (get.hash,)).delete()
|
|
ssl_obj.delete()
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.fail_v2(str(ex))
|
|
return public.success_v2("success")
|
|
|
|
def switch_auto_renew(self, get):
|
|
"""
|
|
自动续签开关
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("hash").String().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
|
|
ssl_obj = DnsDomainSSL.objects.find_one(hash=get.hash)
|
|
if not ssl_obj:
|
|
return public.fail_v2("SSL Certificate Not Found!")
|
|
if ssl_obj.auto_renew == 1:
|
|
ssl_obj.auto_renew = 0
|
|
else:
|
|
make_suer_renew_task() # make suer corn task
|
|
ssl_obj.auto_renew = 1
|
|
ssl_obj.save()
|
|
return public.success_v2("Setting Successfully!")
|
|
|
|
def switch_ssl_alarm(self, get):
|
|
"""
|
|
证书告警开关
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("hash").String().Require(),
|
|
Param("alarm").Integer().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
ssl_obj = DnsDomainSSL.objects.find_one(hash=get.hash)
|
|
if not ssl_obj:
|
|
return public.fail_v2("SSL Not Found!")
|
|
alarm = int(get.alarm)
|
|
if alarm == 1: # open
|
|
res, msg = make_suer_alarm_task() # make suer alarm task
|
|
if res:
|
|
ssl_obj.alarm = alarm
|
|
ssl_obj.save()
|
|
return public.success_v2("Setting Successfully!")
|
|
else:
|
|
return public.fail_v2(msg)
|
|
else: # close
|
|
ssl_obj.alarm = alarm
|
|
ssl_obj.save()
|
|
return public.success_v2("Setting Successfully!")
|
|
|
|
def cert_domain_list(self, get):
|
|
"""
|
|
证书管理列表
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("hash").String().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
|
|
ssl_obj = DnsDomainSSL.objects.find_one(hash=get.hash)
|
|
if not ssl_obj:
|
|
return public.fail_v2("SSL Certificate Not Found!")
|
|
sites = public.S("sites").field(
|
|
"id", "name", "path", "status", "type_id", "project_type",
|
|
).select()
|
|
for s in sites:
|
|
dns = ssl_obj.dns
|
|
for sub in dns:
|
|
if sub.startswith("*."):
|
|
sub = sub[2:]
|
|
if sub in s.get("name", ""):
|
|
s["match"] = 1
|
|
break
|
|
data = {
|
|
"sites": sites,
|
|
"mails": [],
|
|
"accounts": [],
|
|
}
|
|
return public.success_v2(data)
|
|
|
|
def cert_deploy_sites(self, get):
|
|
"""
|
|
部署到sites, 包含取消
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("hash").String().Require(),
|
|
Param("domains").String().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
try:
|
|
get.domains = json.loads(get.domains)
|
|
except json.decoder.JSONDecodeError as js_err:
|
|
public.print_log("error info: {}".format(js_err))
|
|
return public.return_message(-1, 0, str(js_err))
|
|
|
|
ssl_obj = DnsDomainSSL.objects.find_one(hash=get.hash)
|
|
if not ssl_obj:
|
|
return public.fail_v2("SSL Certificate Not Found!")
|
|
|
|
# 当前得域名
|
|
user_for = ssl_obj.user_for.get(UseFor.sites.value, [])
|
|
# 不同的元素
|
|
diff = list(set(user_for).symmetric_difference(set(get.domains)))
|
|
# 1, 需要移除的sites
|
|
for remove in [x for x in diff if x in set(user_for)]:
|
|
new_get = public.dict_obj()
|
|
new_get.siteName = remove
|
|
new_get.updateOf = 1
|
|
remove_res = panelSite().CloseSSLConf(new_get)
|
|
# 2, 移除diff之后, 部署
|
|
result = ssl_obj.deploy_sites(get.domains)
|
|
if result.get("status"):
|
|
return public.success_v2("Setup successfully!")
|
|
else:
|
|
return public.fail_v2(result.get("msg", "Deploy Faild..."))
|
|
|
|
# todo
|
|
def cert_deploy_mails(self, get):
|
|
# ssl_obj.user_for[UseFor.mails.value] = []
|
|
# ssl_obj.save()
|
|
pass
|
|
|
|
# todo
|
|
def cert_deploy_panel(self, get):
|
|
# ssl_obj.user_for[UseFor.panel.value] = []
|
|
# ssl_obj.save()
|
|
pass
|
|
|
|
# =========== add Site ===========
|
|
def add_site_check(self, get):
|
|
"""
|
|
检测域名支持服务
|
|
"""
|
|
try:
|
|
get.validate([
|
|
Param("domain").String().Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, str(ex))
|
|
result = {
|
|
"hash": "",
|
|
"domain": get.domain,
|
|
"support": [],
|
|
}
|
|
for ssl in DnsDomainSSL.objects.all():
|
|
if DomainValid.domain_valid(ssl, get.domain):
|
|
result = {
|
|
"hash": ssl.hash,
|
|
"domain": get.domain,
|
|
"support": ["auto", "ssl_cert"],
|
|
}
|
|
if bool("CloudFlareDns" in ssl.auth_info.get("auth_to", "")):
|
|
result.update({"cf_proxy": 1})
|
|
result["support"].append("cf_proxy")
|
|
return public.success_v2(result)
|
|
return public.success_v2(result)
|
|
|
|
|
|
def move_old_account():
|
|
old_dns_api = os.path.join(public.get_panel_path(), "config/dns_api.json")
|
|
read = public.readFile(old_dns_api)
|
|
once = os.path.join(public.get_panel_path(), "config/dns_api_once.pl")
|
|
if not os.path.exists(once):
|
|
public.writeFile(once, "0")
|
|
|
|
if public.readFile(once) != "0":
|
|
return
|
|
try:
|
|
dnsapi_config = json.loads(read) if read else []
|
|
except Exception:
|
|
return
|
|
for dns in dnsapi_config:
|
|
try:
|
|
if dns.get("name") == "CloudFlareDns":
|
|
dns_name = "CloudFlareDns"
|
|
key = ""
|
|
account = ""
|
|
for cf in dns.get("data", []):
|
|
if cf.get("key") == "SAVED_CF_MAIL" and cf.get("value") != "":
|
|
account = cf.get("value", "")
|
|
elif cf.get("key") == "SAVED_CF_KEY" and cf.get("value") != "":
|
|
key = cf.get("value")
|
|
if dns_name and key:
|
|
try:
|
|
exists = DnsDomainProvider.objects.filter(
|
|
name=dns_name, api_user=account, api_key=key
|
|
).first()
|
|
if not exists:
|
|
if os.path.exists('/www/server/panel/data/cf_limit_api.pl'):
|
|
limit = True
|
|
else:
|
|
limit = False
|
|
get = public.dict_obj()
|
|
get.name = dns_name
|
|
get.api_user = account
|
|
get.api_key = key
|
|
get.permission = "limit" if limit is True else "global"
|
|
DomainObject().create_dns_api(get)
|
|
except:
|
|
pass
|
|
elif dns.get("name") == "NameCheapDns":
|
|
dns_name = "NameCheapDns"
|
|
key = ""
|
|
account = ""
|
|
for nc in dns.get("data", []):
|
|
if nc.get("key") == "SAVED_NC_ACCOUNT" and nc.get("value") != "":
|
|
account = nc.get("value", "")
|
|
elif nc.get("key") == "SAVED_CX_APIKEY" and nc.get("value") != "":
|
|
key = nc.get("value")
|
|
if dns_name and key and account:
|
|
try:
|
|
exists = DnsDomainProvider.objects.filter(
|
|
name=dns_name, api_user=account, api_key=key
|
|
).first()
|
|
if not exists:
|
|
try:
|
|
get = public.dict_obj()
|
|
get.name = dns_name
|
|
get.api_user = account
|
|
get.api_key = key
|
|
DomainObject().create_dns_api(get)
|
|
except Exception:
|
|
import traceback
|
|
public.print_log(traceback.format_exc())
|
|
except:
|
|
pass
|
|
except Exception:
|
|
continue
|
|
public.writeFile(once, "1")
|
|
|
|
|
|
move_old_account()
|