├── .idea
├── .gitignore
├── AMEN-GoEdge-User.iml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── API
├── HTTPWebService.py
├── MetricStatService.py
├── OriginService.py
├── ReverseProxyService.py
├── SSLCertService.py
├── SSLPolicyService.py
├── ServerService.py
├── UserService.py
└── __init__.py
├── Config
└── Config_initialization.json
├── Controller
├── ConfigService.py
├── HTTPAccessLogService.py
├── HTTPWebService.py
├── MetricStatService.py
├── OriginService.py
├── SSLCertService.py
├── SSLPolicyService.py
├── ServerService.py
├── UserService.py
└── Verification.py
├── ErrCode
└── __init__.py
├── LICENSE
├── README.md
├── Sql
└── __init__.py
├── Utils
├── __init__.py
├── cert.py
└── tencent.py
├── edge_code.sql
├── main.py
├── requirements.txt
└── test_main.http
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # 默认忽略的文件
2 | /shelf/
3 | /workspace.xml
4 | # 基于编辑器的 HTTP 客户端请求
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/AMEN-GoEdge-User.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/API/HTTPWebService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import json
3 | import traceback
4 |
5 | from API import Api
6 | from API import ServerService
7 |
8 |
9 | class HTTPWebService(Api):
10 | def updateHTTPWebRedirectToHTTPS(self, ServerService: ServerService, serverId:int, httpWebId: int, isOn: bool, status: bool):
11 | """
12 |
13 | :param ServerService:
14 | :param httpWebId: webid
15 | :param isOn: 启用禁用
16 | :param status: bool位=为301否则302
17 | :return:
18 | """
19 | ServerConfig = ServerService.findEnabledServerConfig(serverId)
20 | if not ServerConfig[0]:
21 | if ServerConfig[1] is None:
22 | return [False, None]
23 | else:
24 | return [False, ServerConfig[1]]
25 | try:
26 | Config = ServerConfig[1]
27 | Config = json.loads(base64.b64decode(Config).decode())
28 | redirectToHTTPSJson: dict = Config['web']['redirectToHTTPS']
29 | if redirectToHTTPSJson is None:
30 | status_i = 301
31 | isOn = False
32 | redirectToHTTPSJson = {"host": "", "port": 0, "isPrior": False, "onlyDomains": None, "exceptDomains": None}
33 | if status:
34 | status_i = 301
35 | else:
36 | status_i = 302
37 | redirectToHTTPSJson.update({
38 | "isOn": isOn,
39 | "status": status_i
40 | })
41 | redirectToHTTPSJson_bytes = base64.b64encode(json.dumps(redirectToHTTPSJson).encode('utf-8')).decode(
42 | "utf-8")
43 | except:
44 | return [False, None]
45 | submit = {
46 | "httpWebId": httpWebId,
47 | "redirectToHTTPSJSON": redirectToHTTPSJson_bytes
48 | }
49 | res = self.post(self.Host + "/HTTPWebService/updateHTTPWebRedirectToHTTPS", json=submit)
50 | try:
51 | if res.json()['code'] == 200:
52 | return [True, "ok"]
53 | else:
54 | return [False, res.json()['message']]
55 | except:
56 | return [False, None]
57 |
--------------------------------------------------------------------------------
/API/MetricStatService.py:
--------------------------------------------------------------------------------
1 | from API import Api
2 |
3 |
4 | class MetricStatService(Api):
5 | def listMetricStats(self):
6 | res = self.post(self.Host + "/MetricStatService/listMetricStats", json={
7 | "metricItemId": 1,
8 | "offset":0,
9 | "size":80
10 | })
11 | print(res.content.decode())
12 |
--------------------------------------------------------------------------------
/API/OriginService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import json
3 | import traceback
4 |
5 | from API import Api, ReverseProxyService
6 |
7 |
8 | class OriginService(Api):
9 | def findEnabledOrigin(self, originId: int):
10 | submit = {
11 | "originId": originId
12 | }
13 | # findEnabledOrigin是简要信息
14 | # {"code":200,"data":{"Origin":{"id":2,"isOn":true,"addr":{"protocol":"http","host":"webserver1.ymqq.top","portRange":"8800"}}},"message":"ok"}
15 | # findEnabledOriginConfig是复杂信息,data.originJSON是base64编码
16 | res = self.post(self.Host + "/OriginService/findEnabledOriginConfig", json=submit)
17 | try:
18 | if res.json()['code'] == 200:
19 | if 'originJSON' in res.json()['data']:
20 | return [True, res.json()['data']['originJSON']]
21 | else:
22 | return [True, None]
23 | else:
24 | return [False, res.json()['message']]
25 | except:
26 | return [False, None]
27 |
28 | def updateOrigin(self, originJson: dict):
29 | submit = originJson
30 | submit_v1 = {}
31 | try:
32 | submit['connTimeout']['count'] = int(submit['connTimeout']['count'])
33 | submit['readTimeout']['count'] = int(submit['readTimeout']['count'])
34 | submit['idleTimeout']['count'] = int(submit['idleTimeout']['count'])
35 | connTimeoutJSON = base64.b64encode(json.dumps(submit['connTimeout']).encode('utf-8')).decode("utf-8")
36 | readTimeoutJSON = base64.b64encode(json.dumps(submit['readTimeout']).encode('utf-8')).decode("utf-8")
37 | idleTimeoutJSON = base64.b64encode(json.dumps({"unit": "second", "count": 0}).encode('utf-8')).decode("utf-8") # submit['idleTimeout']
38 | # certRefJSON = base64.b64encode(json.dumps(submit['certRef']).encode('utf-8')).decode("utf-8")
39 | if submit['certRef']['certId'] == 0:
40 | certRefJSON = ""
41 | else:
42 | certRefJSON = base64.b64encode(('{"isOn": true, "certId": '+str(submit['certRef']['certId'])+'}').encode('utf-8')).decode("utf-8")
43 |
44 | submit_v1['originId'] = submit['id']
45 | submit_v1['connTimeoutJSON'] = connTimeoutJSON # 连接时间
46 | submit_v1['readTimeoutJSON'] = readTimeoutJSON # 读取时间
47 | submit_v1['idleTimeoutJSON'] = idleTimeoutJSON # 闲置超时 idleTimeoutJSON
48 | submit_v1['name'] = submit['name'] # 名
49 |
50 | submit['addr']['maxPort'] = 0
51 | submit['addr']['minPort'] = 0
52 | submit_v1['addr'] = submit['addr'] # 源站信息 host portRange protocol 【maxPort minPort】这两个保持默认0
53 |
54 | submit_v1[
55 | 'description'] = "AMEN-GoEdge-User创建的源站,不可删除,请通过AMEN-GoEdge-User删除,否则AMEN-GoEdge-User异常" # 备注submit['description']
56 | submit_v1['weight'] = int(submit['weight']) # 权重
57 | submit_v1['isOn'] = submit['isOn'] # 是否启用
58 | submit_v1['maxConns'] = 0 # 最大连接数submit['maxConns']
59 | submit_v1['maxIdleConns'] = 0 # 最大空闲超时时间submit['idleConns']
60 | submit_v1['domains'] = [] # 专属域名
61 | submit_v1['certRefJSON'] = certRefJSON # 源站https
62 | submit_v1['followPort'] = False # 端口跟随submit['followPort']
63 | submit_v1['host'] = "" # 回源主机名submit['requestHost']
64 | except:
65 | traceback.print_exc()
66 | return [False, "提交数据错误"]
67 | res = self.post(self.Host + "/OriginService/updateOrigin", json=submit_v1)
68 | try:
69 | if res.json()['code'] == 200:
70 | if 'originJSON' in res.json()['data']:
71 | return [True, res.json()['data']['originJSON']]
72 | else:
73 | return [True, None]
74 | else:
75 | return [False, res.json()['message']]
76 | except:
77 | return [False, None]
78 |
79 | def deleteOrigin(self, reverseProxyId: int, GoEdgeApi: ReverseProxyService, originId: int, originJson: dict,
80 | Primary: bool = False):
81 | """
82 | 通过源数据+删除主备字段+将要删除id叠合后触发更新源站信息
83 | :param reverseProxyId:
84 | :param GoEdgeApi:
85 | :param originId:
86 | :param originJson:
87 | :param Primary:
88 | :return:
89 | """
90 | isOk = False
91 | for i, v in enumerate(originJson):
92 | if v['originId'] == originId:
93 | isOk = True
94 | break
95 | if not isOk:
96 | return [False, '未找到此源站信息']
97 | originJson.pop(i)
98 | return GoEdgeApi.updateReverseProxOrigins(reverseProxyId=reverseProxyId, originsJSON=originJson,
99 | Primary=Primary)
100 |
101 | def createOrigin(self, originJson: dict):
102 | submit = originJson
103 | submit_v1 = {}
104 | try:
105 | submit['connTimeout']['count'] = int(submit['connTimeout']['count'])
106 | submit['readTimeout']['count'] = int(submit['readTimeout']['count'])
107 | # submit['idleTimeout']['count'] = int(submit['idleTimeout']['count'])
108 | submit['connTimeout']['unit'] = "second"
109 | submit['readTimeout']['unit'] = "second"
110 | # submit['idleTimeout'] = {}
111 | # submit['idleTimeout']['unit'] = "second"
112 | connTimeoutJSON = base64.b64encode(json.dumps(submit['connTimeout']).encode('utf-8')).decode("utf-8")
113 | readTimeoutJSON = base64.b64encode(json.dumps(submit['readTimeout']).encode('utf-8')).decode("utf-8")
114 | # idleTimeoutJSON = base64.b64encode(json.dumps(submit['idleTimeout']).encode('utf-8')).decode("utf-8")
115 | idleTimeoutJSON = base64.b64encode(json.dumps({"unit": "second", "count": 0}).encode('utf-8')).decode(
116 | "utf-8")
117 |
118 | certRefJSON = base64.b64encode(json.dumps(None).encode('utf-8')).decode("utf-8")
119 |
120 | submit_v1['name'] = ""
121 |
122 | submit_v1['addr'] = submit['addr']
123 | submit_v1['addr']['minPort'] = 0
124 | submit_v1['addr']['maxPort'] = 0
125 |
126 | submit_v1['description'] = ""
127 |
128 | submit_v1['weight'] = int(submit['weight'])
129 |
130 | submit_v1['isOn'] = True
131 |
132 | submit_v1['connTimeoutJSON'] = connTimeoutJSON
133 | submit_v1['readTimeoutJSON'] = readTimeoutJSON
134 | submit_v1['idleTimeoutJSON'] = idleTimeoutJSON
135 |
136 | submit_v1['maxConns'] = 0
137 |
138 | submit_v1['maxIdleConns'] = 0
139 |
140 | submit_v1['domains'] = []
141 |
142 | submit_v1['certRefJSON'] = certRefJSON
143 |
144 | submit_v1['host'] = submit['host']
145 |
146 | submit_v1['followPort'] = False
147 | except:
148 | traceback.print_exc()
149 | return [False, "提交数据错误"]
150 | res = self.post(self.Host + "/OriginService/createOrigin", json=submit_v1)
151 | try:
152 | if res.json()['code'] == 200:
153 | if 'originId' in res.json()['data']:
154 | return [True, res.json()['data']['originId']]
155 | else:
156 | return [True, None]
157 | else:
158 | return [False, res.json()['message']]
159 | except:
160 | return [False, None]
161 |
--------------------------------------------------------------------------------
/API/ReverseProxyService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import json
3 |
4 | from API import Api
5 |
6 |
7 | class ReverseProxyService(Api):
8 | def updateReverseProxOrigins(self, reverseProxyId: int, originsJSON: dict, Primary: bool = False):
9 | """
10 | 修改源站信息,不是源站配置,是网站服务器->源站信息->源站配置。做新增,新增数据为:源数据+新数据,源数据由上层传递,本函数不做查询源数据
11 | :param reverseProxyId:
12 | :param originsJSON:
13 | :param Primary:
14 | :return:
15 | """
16 | originsJSON_bytes = base64.b64encode(json.dumps(originsJSON).encode('utf-8')).decode("utf-8")
17 | submit = {
18 | "reverseProxyId": reverseProxyId,
19 | "originsJSON": originsJSON_bytes
20 | }
21 | if Primary:
22 | res = self.post(self.Host + "/ReverseProxyService/updateReverseProxyPrimaryOrigins", json=submit)
23 | else:
24 | res = self.post(self.Host + "/ReverseProxyService/updateReverseProxyBackupOrigins", json=submit)
25 | try:
26 | if res.json()['code'] == 200:
27 | return [True,"ok"]
28 | else:
29 | return [True, res.json()['message']]
30 | except:
31 | return [False,None]
32 |
--------------------------------------------------------------------------------
/API/SSLCertService.py:
--------------------------------------------------------------------------------
1 | import base64
2 |
3 | from API import Api
4 |
5 |
6 | class SSLCertService(Api):
7 | def listSSLCerts(self, userId: int, offset: int, size: int, keyword: str = None):
8 | if keyword is None:
9 | submit = {
10 | "userId": userId,
11 | "offset": offset,
12 | "size": size
13 | }
14 | else:
15 | submit = {
16 | "userId": userId,
17 | "offset": offset,
18 | "size": size,
19 | "keyword": keyword
20 | }
21 | res = self.post(self.Host + "/SSLCertService/listSSLCerts", json=submit)
22 | try:
23 | if res.json()['code'] == 200:
24 | if "sslCertsJSON" in res.json()['data']:
25 | return [True, res.json()['data']['sslCertsJSON']]
26 | else:
27 | return [True, 'W10=']
28 | else:
29 | return [False, res.json()['message']]
30 | except:
31 | return [False, None]
32 |
33 | def createSSLCert(self, name: str, isCA: bool, certData: str, keyData: str,timeBeginAt:int,timeEndAt:int,dnsNames:list,issuer_type:str,issuer_author:str):
34 | """
35 | certData keyData base64编码
36 | :param issuer_author:
37 | :param issuer_type:
38 | :param dnsNames:
39 | :param timeEndAt:
40 | :param timeBeginAt:
41 | :param name:
42 | :param isCA:
43 | :param certData:
44 | :param keyData:
45 | :return:
46 | """
47 | # certData_bytes = base64.b64encode(certData.encode('utf-8')).decode("utf-8")
48 | # keyData_bytes = base64.b64encode(keyData.encode('utf-8')).decode("utf-8")
49 | # print(certData_bytes)
50 | submit = {
51 | "isOn": True,
52 | "name": name,
53 | "serverName": "",
54 | "isCA": isCA,
55 | "certData": certData,
56 | "keyData": keyData,
57 | "timeBeginAt": timeBeginAt,
58 | "timeEndAt": timeEndAt,
59 | "dnsNames": dnsNames,
60 | "commonNames": [issuer_type, issuer_author],
61 | "description": "AMEN-GoEdge-User创建的HTTPS证书,用户为:AMEN,不可删除,请通过AMEN-GoEdge-User删除,否则AMEN-GoEdge-User异常"
62 | }
63 | res = self.post(self.Host + "/SSLCertService/createSSLCert", json=submit)
64 | try:
65 | if res.json()['code'] == 200:
66 | if "sslCertId" in res.json()['data']:
67 | return [True,res.json()['data']['sslCertId']]
68 | else:
69 | return [False,res.json()['message']]
70 | else:
71 | return [False,res.json()['message']]
72 | except:
73 | return [False,None]
74 |
75 | def countSSLCerts(self, userId: int, keyword: str = None):
76 | if keyword is None:
77 | submit = {
78 | "userId": userId
79 | }
80 | else:
81 | submit = {
82 | "userId": userId,
83 | "keyword": keyword
84 | }
85 | res = self.post(self.Host + "/SSLCertService/countSSLCerts", json=submit)
86 | try:
87 | if res.json()['code'] == 200:
88 | if "count" in res.json()['data']:
89 | return [True, res.json()['data']['count']]
90 | else:
91 | return [True, 0]
92 | else:
93 | return [False, res.json()['message']]
94 | except:
95 | return [False, None]
96 |
97 | def deleteSSLCert(self,sslCertId:int):
98 | submit = {
99 | "sslCertId":sslCertId
100 | }
101 | res = self.post(self.Host + "/SSLCertService/deleteSSLCert", json=submit)
102 | try:
103 | if res.json()['code'] == 200:
104 | return [True, "ok"]
105 | else:
106 | return [False, res.json()['message']]
107 | except:
108 | return [False, None]
109 |
110 | def countAllEnabledServersWithSSLCertId(self,sslCertId:int):
111 | """计算使用某个SSL证书的服务数量"""
112 | submit = {
113 | "sslCertId":sslCertId
114 | }
115 | res = self.post(self.Host+"/ServerService/countAllEnabledServersWithSSLCertId",json=submit)
116 | try:
117 | if res.json()['code'] == 200:
118 | if "count" in res.json()['data']:
119 | return [True, res.json()['data']['count']]
120 | else:
121 | return [True, 0]
122 | else:
123 | return [False, res.json()['message']]
124 | except:
125 | return [False, None]
126 |
127 |
--------------------------------------------------------------------------------
/API/SSLPolicyService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import json
3 |
4 | from API import Api
5 |
6 |
7 | class SSLPolicyService(Api):
8 | def updateSSLPolicy(self, sslPolicyId: int, ocsp: bool, sslID: int, hsts: dict, http2Enabled: bool,
9 | minVersion: str):
10 | if "isOn" not in hsts or "maxAge" not in hsts or "preload" not in hsts or "includeSubDomains" not in hsts:
11 | return [False, None]
12 | try:
13 | hstsV2 = {}
14 | hstsV2['isOn'] = hsts['isOn']
15 | hstsV2['maxAge'] = int(hsts['maxAge'])
16 | hstsV2['preload'] = hsts['preload']
17 | hstsV2['includeSubDomains'] = hsts['includeSubDomains']
18 | hstsV2['domains'] = []
19 | hsts_bytes = base64.b64encode(json.dumps(hstsV2).encode('utf-8')).decode('utf-8')
20 | if sslID <= 0:
21 | ssl = base64.b64encode('[]'.encode('utf-8')).decode('utf-8')
22 | else:
23 | ssl = base64.b64encode(('[{"isOn": true, "certId": '+str(sslID)+'}]').encode('utf-8')).decode('utf-8')
24 | except:
25 | return [False,None]
26 | submit = {
27 | "sslPolicyId": sslPolicyId,
28 | "http2Enabled": http2Enabled,
29 | "sslCertsJSON": ssl,
30 | "hstsJSON": hsts_bytes,
31 | "ocspIsOn": ocsp,
32 | "minVersion": minVersion
33 | }
34 | res = self.post(self.Host + "/SSLPolicyService/updateSSLPolicy", json=submit)
35 | try:
36 | if res.json()['code'] == 200:
37 | return [True, "ok"]
38 | else:
39 | return [False, res.json()['message']]
40 | except:
41 | return [False, None]
42 |
--------------------------------------------------------------------------------
/API/ServerService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import json
3 | import traceback
4 |
5 | import Sql
6 | from API import Api, ReverseProxyService
7 |
8 |
9 | class ServerService(Api):
10 | def createServer(self, ClusterId: int, userId: int, name: str, domain: str):
11 | id_info = self.createReverseProxy() # 创建反向代理
12 | if not id_info[0]:
13 | # 创建失败
14 | return [False, id_info[1]]
15 | # 创建成功
16 | reverse_id = id_info[1]
17 | reverse_json = json.dumps(
18 | {"isOn": True, "isPrior": False, "reverseProxyId": int(reverse_id)}
19 | )
20 | reverse_json = base64.b64encode(reverse_json.encode('utf-8')).decode("utf-8")
21 | # 创建ssl配置
22 | ssl_info = self.createSSLPolicy()
23 | if not ssl_info[0]:
24 | # 创建失败
25 | return [False, ssl_info[1]]
26 | ssl_id = ssl_info[1]
27 |
28 | # 查询是否存在domain
29 | # if not self.finddomain(ESql, domain):
30 | # return [False, "域名 {} 已经被其他服务所占用,不能重复使用".format(domain)]
31 | domainList = self.finddomain(ClusterId, [domain])
32 |
33 | if domainList is None:
34 | return [False, None]
35 | if domain in domainList:
36 | return [False, "域名 {} 已经被其他服务所占用,不能重复使用,如果确保域名是自己的,请带上域名所有权和所有权本人有效证件提交给本站管理员/客服处理".format(domain)]
37 | server_json = json.dumps(
38 | [{"name": domain, "type": "full"}]
39 | )
40 | server_json = base64.b64encode(server_json.encode('utf-8')).decode("utf-8")
41 | http_json = json.dumps(
42 | {"isOn": True, "listen": [{"host": "", "maxPort": 0, "minPort": 0, "protocol": "http", "portRange": "80"}]}
43 | )
44 | http_json = base64.b64encode(http_json.encode('utf-8')).decode("utf-8")
45 | https_json = json.dumps(
46 | {"isOn": False,
47 | "listen": [{"host": "", "maxPort": 443, "minPort": 443, "protocol": "https", "portRange": "443"}],
48 | "sslPolicy": None, "sslPolicyRef": {"isOn":True,"sslPolicyId":int(ssl_id)}}
49 | )
50 | https_json = base64.b64encode(https_json.encode('utf-8')).decode("utf-8")
51 | submit = {
52 | "userId": userId,
53 | "name": name,
54 | "type": "httpProxy",
55 | # httpProxy:CDN加速 分发全部
56 | # httpWeb:HTTP Web服务 分发静态
57 | # tcpProxy:TCP反向代理 tcp反代
58 | # udpProxy:UDP反向代理 udp反代
59 | # 先只做分发全部
60 | "description": "AMEN-GoEdge-User创建的网站服务,不可删除,请通过AMEN-GoEdge-User删除,否则AMEN-GoEdge-User异常",
61 | "serverNamesJON": server_json,
62 | "httpJSON": http_json,
63 | "httpsJSON": https_json,
64 | "reverseProxyJSON": reverse_json
65 | }
66 | res = self.post(self.Host + "/ServerService/createServer", json=submit)
67 | try:
68 | if res is None:
69 | return [False, None]
70 | if res.json()['code'] != 200:
71 | return [False, res.json()['message']]
72 | self.findAndInitServerWebConfig(res.json()['data']['serverId']) # 初始化web
73 | return [True, res.json()['data']['serverId']]
74 | except:
75 | traceback.print_exc()
76 | return [False, None]
77 |
78 | def finddomain(self, ClusterId: int, domain: list):
79 | # 查询是否已存在此域名,返回id x
80 | # 同样没有此接口,遍历数据库
81 | # row = ESql.fetch("""select * from `edgeServers` WHERE `plainServerNames` like '"qqq.com"' limit 1""")
82 | # if row is None:
83 | # return None
84 | # return row['id']
85 | submit = {
86 | "nodeClusterId": ClusterId,
87 | "serverNames": domain
88 | }
89 | res = self.post(self.Host + "/ServerService/checkServerNameDuplicationInNodeCluster", json=submit)
90 | try:
91 | if "duplicatedServerNames" in res.json()['data']:
92 | return res.json()['data']['duplicatedServerNames']
93 | else:
94 | return []
95 | except:
96 | return None
97 |
98 | def findAllUserServers(self, userId: int):
99 | # 防止越权,用usertoken
100 | submit = {
101 | "userId": userId
102 | }
103 | res = self.post(self.Host + "/ServerService/findAllUserServers", json=submit)
104 | try:
105 | if res.json()['code'] == 200:
106 | if "servers" in res.json()['data']:
107 | return [True, res.json()['data']['servers']]
108 | else:
109 | return [True, []]
110 | else:
111 | return [False, res.json()['message']]
112 | except:
113 | return [False, None]
114 |
115 | def updateServerIsOn(self, serverId: int, isOn: bool):
116 | submit = {
117 | "serverId": serverId,
118 | "isOn": isOn
119 | }
120 | res = self.post(self.Host + "/ServerService/updateServerIsOn", json=submit)
121 | try:
122 | if res.json()['code'] == 200:
123 | return [True, 'ok']
124 | else:
125 | return [False, res.json()['message']]
126 | except:
127 | return [False, None]
128 |
129 | def findEnabledServerConfig(self, serverId: int):
130 | submit = {
131 | "serverId": serverId
132 | }
133 | res = self.post(self.Host + "/ServerService/findEnabledServerConfig", json=submit)
134 | try:
135 | if res.json()['code'] == 200:
136 | if 'serverJSON' in res.json()['data']:
137 | # base64.b64decode(res.json()['data']['serverJSON'])
138 | return [True, res.json()['data']['serverJSON']]
139 | else:
140 | return [True, "e30="]
141 | else:
142 | return [False, res.json()['message']]
143 | except:
144 | return [False, None]
145 |
146 | def findEnabledServer(self, serverId: int):
147 | submit = {
148 | "serverId": serverId
149 | }
150 | res = self.post(self.Host + "/ServerService/findEnabledServer", json=submit)
151 | try:
152 | if res.json()['code'] == 200:
153 | if 'server' in res.json()['data']:
154 | return [True, res.json()['data']['server']]
155 | else:
156 | return [True, {}]
157 | else:
158 | return [False, res.json()['message']]
159 | except:
160 | return [False, None]
161 |
162 | def deleteServer(self, serverId: int):
163 | submit = {
164 | "serverId": serverId
165 | }
166 | res = self.post(self.Host + "/ServerService/deleteServer", json=submit)
167 | try:
168 | if res.json()['code'] == 200:
169 | return [True, "ok"]
170 | else:
171 | return [False, res.json()['message']]
172 | except:
173 | return [False, None]
174 |
175 | def updateServerReverseProxy(self, serverId: int, reverseProxyJSON: dict):
176 | # 这种方式不安全,换
177 | # reverseProxyJSON_bytes = base64.b64encode(json.dumps(reverseProxyJSON).encode('utf-8')).decode("utf-8")
178 | # reverseProxyJSON_bytes = base64.b64encode(json.dumps(reverseProxyJSON).encode('utf-8')).decode("utf-8")
179 | ServerConfig = self.findEnabledServerConfig(serverId)
180 | if not ServerConfig[0]:
181 | if ServerConfig[1] is None:
182 | return [False, None]
183 | else:
184 | return [False, ServerConfig[1]]
185 | try:
186 | Config = ServerConfig[1]
187 | Config = json.loads(base64.b64decode(Config).decode())
188 | reverseProxy = Config['reverseProxyRef']
189 | reverseProxy['isOn'] = reverseProxyJSON['isOn']
190 | reverseProxyJSON_bytes = base64.b64encode(json.dumps(reverseProxy).encode('utf-8')).decode("utf-8")
191 | except:
192 | return [False, None]
193 | submit = {
194 | "serverId": serverId,
195 | "reverseProxyJSON": reverseProxyJSON_bytes
196 | }
197 | res = self.post(self.Host + "/ServerService/updateServerReverseProxy", json=submit)
198 | try:
199 | if res.json()['code'] == 200:
200 | return [True, "ok"]
201 | else:
202 | return [False, res.json()['message']]
203 | except:
204 | return [False, None]
205 |
206 | def updateServerHTTPS(self, serverId: int, isOn: bool):
207 | ServerConfig = self.findEnabledServerConfig(serverId)
208 | if not ServerConfig[0]:
209 | if ServerConfig[1] is None:
210 | return [False, None]
211 | else:
212 | return [False, ServerConfig[1]]
213 | try:
214 | Config = ServerConfig[1]
215 | Config = json.loads(base64.b64decode(Config).decode())
216 | https = Config['https']
217 | https['isOn'] = isOn
218 | httpsJSON_bytes = base64.b64encode(json.dumps(https).encode('utf-8')).decode("utf-8")
219 | except:
220 | return [False, None]
221 | submit = {
222 | "serverId": serverId,
223 | "httpsJSON": httpsJSON_bytes
224 | }
225 | res = self.post(self.Host + "/ServerService/updateServerHTTPS", json=submit)
226 | try:
227 | if res.json()['code'] == 200:
228 | return [True, "ok"]
229 | else:
230 | return [False, res.json()['message']]
231 | except:
232 | return [False, None]
233 |
234 | def updateServerHTTP(self, serverId: int, isOn: bool):
235 | ServerConfig = self.findEnabledServerConfig(serverId)
236 | if not ServerConfig[0]:
237 | if ServerConfig[1] is None:
238 | return [False, None]
239 | else:
240 | return [False, ServerConfig[1]]
241 | try:
242 | Config = ServerConfig[1]
243 | Config = json.loads(base64.b64decode(Config).decode())
244 | https = Config['http']
245 | https['isOn'] = isOn
246 | httpsJSON_bytes = base64.b64encode(json.dumps(https).encode('utf-8')).decode("utf-8")
247 | except:
248 | return [False, None]
249 | submit = {
250 | "serverId": serverId,
251 | "httpJSON": httpsJSON_bytes
252 | }
253 | res = self.post(self.Host + "/ServerService/updateServerHTTP", json=submit)
254 | try:
255 | if res.json()['code'] == 200:
256 | return [True, "ok"]
257 | else:
258 | return [False, res.json()['message']]
259 | except:
260 | return [False, None]
261 |
262 | def findAndInitServerWebConfig(self, serverId: int):
263 | # 初始化web设置
264 | submit = {
265 | "serverId": serverId
266 | }
267 | res = self.post(self.Host + "/ServerService/findAndInitServerWebConfig", json=submit)
268 | try:
269 | if res.json()['code'] == 200:
270 | return [True, "ok"]
271 | else:
272 | return [False, res.json()['message']]
273 | except:
274 | return [False, None]
275 |
276 | def createReverseProxy(self):
277 | # 创建反向代理,返回id
278 | # submit = {
279 | # "reverseProxyId": reverseProxyId,
280 | # "originsJSON": originsJSON_bytes
281 | # }
282 | res = self.post(self.Host + "/ReverseProxyService/createReverseProxy")
283 | print(res.json())
284 | try:
285 | if res.json()['code'] == 200:
286 | return [True, res.json()['data']['reverseProxyId']]
287 | else:
288 | return [True, res.json()['message']]
289 | except:
290 | return [False, None]
291 |
292 | def createSSLPolicy(self):
293 | # 创建ssl配置
294 | hsts_json = json.dumps(
295 | {"isOn": False, "maxAge": 2592000, "domains": [], "preload": False, "includeSubDomains": False}
296 | )
297 | hsts_json = base64.b64encode(hsts_json.encode('utf-8')).decode("utf-8")
298 | submit = {
299 | "minVersion": "TLS 1.0",
300 | "http2Enabled": False,
301 | "hstsJSON": hsts_json,
302 | "clientAuthType": 0,
303 | "ocspIsOn": False,
304 | "cipherSuitesIsOn": False,
305 | "clientCACertsJSON": None,
306 | "sslCertsJSON": None
307 | }
308 | res = self.post(self.Host + "/SSLPolicyService/createSSLPolicy", json=submit)
309 | try:
310 | if res.json()['code'] == 200:
311 | return [True, res.json()['data']['sslPolicyId']]
312 | else:
313 | return [True, res.json()['message']]
314 | except:
315 | return [False, None]
316 |
--------------------------------------------------------------------------------
/API/UserService.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import json
3 |
4 | import requests
5 |
6 | import Sql
7 | import Utils
8 | from API import Api
9 |
10 |
11 | class UserService(Api):
12 | def registerUser(self, username, password, mobile, email, fullname, ip, source):
13 | """注册用户"""
14 | submit = {
15 | "username": username,
16 | "password": password,
17 | "mobile": mobile,
18 | "email": email,
19 | "fullname": fullname,
20 | "ip": ip
21 | }
22 | res = self.post(self.Host + "/UserService/registerUser", json=submit)
23 | return res.json()
24 |
25 | def createUser(self, username, password, mobile, email, fullname, ip, source, tel, nodeClusterId):
26 | submit = {
27 | "username": username,
28 | "password": password,
29 | "mobile": mobile,
30 | "email": email,
31 | "fullname": fullname,
32 | "remark": "AMEN-GoEdge-User创建的用户,不可删除,请通过AMEN-GoEdge-User删除,否则AMEN-GoEdge-User异常",
33 | "nodeClusterId": nodeClusterId,
34 | "tel": tel
35 | }
36 | res = self.post(self.Host + "/UserService/createUser", json=submit)
37 | if res is None:
38 | return None
39 | return res.json()
40 |
41 | def loginUser(self, Emysql: Sql.Sql, username: str, password: str):
42 | # 登陆服务官方没有开,自己写,数据库的密码就是md5(原始密码)
43 | # submit = {
44 | # "username": username,
45 | # "password": password,
46 | # }
47 | # # res = requests.post(self.Host + "/UserService/loginUser",json=submit)
48 | # res = self.post(self.Host + "/UserService/loginUser", json=submit)
49 | # # print(res.content.decode())
50 | # return res.json()
51 | # md = hashlib.md5(password.encode())
52 |
53 | userinfo = Emysql.fetch_where("edgeUsers", {
54 | "username": username,
55 | # "password": md.hexdigest(),
56 | # "serversEnabled":1,
57 | "state": 1
58 | })
59 | # isOn字段无用
60 | # state=0被删除
61 | # serversEnabled=0被禁用
62 | if userinfo is not None:
63 | # 查找AccessKey
64 | userinfov2: dict = self.findAllEnabledUserAccessKeys(userinfo['id'])
65 | if userinfov2 is None:
66 | # 生成key
67 | keyinfo = self.createUserAccessKey(Emysql, userinfo['id'])
68 | if not keyinfo[0]:
69 | # 生成失败
70 | return None
71 | # 生成成功
72 | userinfov2 = {'uniqueId': keyinfo[1], 'secret': keyinfo[2]}
73 | elif userinfov2 == "0":
74 | # 异常
75 | return None
76 | # userinfov2 = json.loads(userinfov2)
77 | userinfov3 = {
78 | "uniqueId": userinfov2['uniqueId'],
79 | "secret": userinfov2['secret']
80 | }
81 | userinfo.update(userinfov3)
82 | return userinfo
83 | else:
84 | return None
85 |
86 | def createUserAccessKey(self, ESql: Sql.Sql, userid: int):
87 | # 理由为None,内部出错
88 | submit = {
89 | "userId": userid,
90 | "description": "AMEN-GoEdge-User创建的Key,不可删除,请通过AMEN-GoEdge-User删除,否则AMEN-GoEdge-User异常"
91 | }
92 | res = self.post(self.Host + "/UserAccessKeyService/createUserAccessKey", json=submit)
93 | if res is None:
94 | return [False, None]
95 | keyinfo = None
96 | try:
97 | if res.json()['code'] != 200:
98 | msg = "code为:{}".format(res.json()['code'])
99 | if "message" in res.json():
100 | msg = res.json()['message']
101 | return [False, msg]
102 | keyId = res.json()['data']['userAccessKeyId']
103 | # 根据keyId查找,无此接口通过数据库查找
104 | keyinfo = ESql.fetch_where("edgeUserAccessKeys", {
105 | "id": keyId
106 | })
107 | except:
108 | return [False, None]
109 | if keyinfo is None:
110 | return [False, None]
111 | else:
112 | return [True, keyinfo['uniqueId'], keyinfo['secret']]
113 |
114 | def findAllEnabledUserAccessKeys(self, userid: int):
115 | submit = {
116 | "userId": userid,
117 | }
118 | res = self.post(self.Host + "/UserAccessKeyService/findAllEnabledUserAccessKeys", json=submit)
119 | try:
120 | if res is not None:
121 | if len(res.json()['data']['userAccessKeys']) == 0:
122 | return None
123 | else:
124 | return res.json()['data']['userAccessKeys'][0]
125 | else:
126 | return "0"
127 | except:
128 | return None
129 |
130 | def token_find_userid(self, ESql: Sql.Sql, UserToken: str):
131 | userinfo_token = ESql.fetch_where("edgeAPIAccessTokens", {
132 | "token": UserToken
133 | })
134 | if userinfo_token is None:
135 | return None
136 | return userinfo_token['userId']
137 |
--------------------------------------------------------------------------------
/API/__init__.py:
--------------------------------------------------------------------------------
1 | import json
2 | import traceback
3 |
4 | import requests
5 |
6 |
7 | class Api:
8 | def __init__(self, Host, Id, Key, Token=None):
9 | self.Token = Token
10 | self.Host = Host
11 | self.Id = Id
12 | self.Key = Key
13 | self.header = {
14 | "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36",
15 | "Content-Type": "application/json",
16 | "AMEN": "YMWLGZS"
17 | }
18 | session = requests.session()
19 | session.headers['X-Edge-Access-Token'] = Token
20 | session.headers['AMEN'] = "YMWLGZS"
21 | # session.headers['Content-Type'] = "application/json"
22 | session.headers[
23 | 'User-Agent'] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36"
24 | session.keep_alive = False
25 | self.Session = session
26 |
27 | def get(self, url, headers):
28 | try:
29 | return self.Session.get(url, headers=headers)
30 | except:
31 | return None
32 |
33 | def post(self, url, json=None, headers=None):
34 | try:
35 | return self.Session.post(url, json=json, headers=headers)
36 | except:
37 | traceback.print_exc()
38 | return None
39 |
40 | def getToken(self, type: str = "admin", accessKeyId: str = None, accessKey: str = None):
41 | if accessKey is None or accessKeyId is None:
42 | submit = {
43 | "type": "admin",
44 | "accessKeyId": self.Id,
45 | "accessKey": self.Key
46 | }
47 | else:
48 | submit = {
49 | "type": type,
50 | "accessKeyId": accessKeyId,
51 | "accessKey": accessKey
52 | }
53 | try:
54 | res = requests.post(self.Host + "/APIAccessTokenService/getAPIAccessToken", data=json.dumps(submit),
55 | headers=self.header)
56 | if res.json()['message'] != "ok":
57 | return None
58 | return [res.json()['data']['token'], res.json()['data']['expiresAt']]
59 | except:
60 | # traceback.print_exc()
61 | return None
62 |
63 | def listHTTPAccessLogs(self):
64 | """列出单页访问日志"""
65 | submit = {
66 | "serverId": 2,
67 | "day": "20221121",
68 | "size": 100,
69 | "reverse": True
70 | }
71 | # submit = {
72 | # "node": 1
73 | # }
74 | # res = self.post(self.Host + "/HTTPAccessLogService/listHTTPAccessLogs", json=submit)
75 | res = self.post(self.Host + "/DBService/findAllDBTables")
76 | print(res.text)
77 | # text = res.content.decode()
78 | # return json.loads(text)
79 | return ""
80 |
--------------------------------------------------------------------------------
/Config/Config_initialization.json:
--------------------------------------------------------------------------------
1 | {
2 | "Config": {
3 | "whetherVerificationCodeIsEnabl": false
4 | },
5 | "mysql": {
6 | "host": "127.0.0.1",
7 | "port": 3306,
8 | "user": "goedge",
9 | "password": "goedge",
10 | "database": "goedge"
11 | },
12 | "EdgeAdmin_mysql": {
13 | "host": "",
14 | "port": 8001,
15 | "user": "",
16 | "password": "",
17 | "database": ""
18 | },
19 | "Verification": {
20 | "type": 0,
21 | "host": "",
22 | "port": 465,
23 | "ssl": true,
24 | "user": "",
25 | "password": "",
26 | "title": "AMEN-GoEdge-User",
27 | "frequentTime": 60
28 | },
29 | "API": {
30 | "HOST": "",
31 | "AccessKey ID": "",
32 | "AccessKey Key": "",
33 | "nodeClusterId": 1
34 | },
35 | "Token": "",
36 | "expiresAt": 0,
37 | "adminId": 2
38 | }
--------------------------------------------------------------------------------
/Controller/ConfigService.py:
--------------------------------------------------------------------------------
1 | import API.UserService as UserService
2 | import Sql
3 | import Utils
4 | from fastapi import APIRouter, Path, Body, Depends, Request, Cookie
5 |
6 | from API import ServerService, ReverseProxyService
7 |
8 | app = APIRouter(prefix="/ConfigService", tags=['获取本站配置'])
9 |
10 |
11 | @app.get("/get")
12 | async def get():
13 | allConfig = Utils.read_config()
14 | Config = allConfig['Config']
15 | ConfigV2 = allConfig['Verification']['title']
16 | C = {}
17 | C.update(Config)
18 | C.update({
19 | "title": ConfigV2
20 | })
21 | C.update({
22 | "nodeClusterId": allConfig['API']['nodeClusterId']
23 | })
24 | return C
25 |
--------------------------------------------------------------------------------
/Controller/HTTPAccessLogService.py:
--------------------------------------------------------------------------------
1 |
2 | import API
3 | import Utils
4 | from fastapi import APIRouter, Path
5 |
6 | app = APIRouter(prefix="/HTTPAccessLogService", tags=['访问日志相关服务'])
7 |
8 |
9 | @app.get("/listHTTPAccessLogs")
10 | async def listHTTPAccessLogs():
11 | config = Utils.read_config()
12 | api = config['API']
13 | if config['Token'] == "" or config['Token'] is None:
14 | return {"code": 401, "msg": "server is abnormal"}
15 | GoEdge_Api = API.Api(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], config['Token'])
16 | return GoEdge_Api.listHTTPAccessLogs()
17 |
--------------------------------------------------------------------------------
/Controller/HTTPWebService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import json
3 |
4 | from fastapi import APIRouter, Depends, Cookie, Body
5 | import API.ServerService as ServerService
6 | import API.UserService as UserService
7 | import Utils
8 | from API import HTTPWebService
9 |
10 | app = APIRouter(prefix="/HTTPWebService", tags=['WEB服务'])
11 |
12 | @app.post("/updateHTTPWebRedirectToHTTPS")
13 | async def updateHTTPWebRedirectToHTTPS(UserToken: str = Cookie(None),
14 | httpWebId: int = Body(None),
15 | serverId: int = Body(None),
16 | isOn: bool = Body(None),
17 | status: bool = Body(None),
18 | commons: dict = Depends(Utils.init)):
19 | if isOn is None or httpWebId is None or status is None or serverId is None:
20 | return Utils.message(201)
21 | # 此时全部是用户token
22 | config = commons[0]
23 | api = config['API']
24 | GoEdge_Api = HTTPWebService.HTTPWebService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
25 | GoEdge_Api2 = ServerService.ServerService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
26 | info = GoEdge_Api.updateHTTPWebRedirectToHTTPS(ServerService=GoEdge_Api2,serverId=serverId,httpWebId=httpWebId,isOn=isOn,status=status)
27 | if not info[0]:
28 | if info[1] is None:
29 | return Utils.message(402)
30 | else:
31 | return Utils.message(389, message=info[1])
32 | return Utils.message(200)
33 |
34 |
--------------------------------------------------------------------------------
/Controller/MetricStatService.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import json
3 | import re
4 | import time
5 | import API.MetricStatService as MetricStatService
6 | import API.UserService as UserService
7 | import API.SSLCertService as SSLCertService
8 | import Sql
9 | import Utils
10 | import API.ServerService as ServerService
11 | import API.OriginService as OriginService
12 | import API.ReverseProxyService as ReverseProxyService
13 | from Utils.tencent import Tencent
14 | from fastapi import APIRouter, Path, Body, Depends, Request, Response, Cookie
15 |
16 | # from main import Data_Config
17 | app = APIRouter(prefix="/MetricStatService", tags=['指标'])
18 |
19 |
20 | @app.get("/listMetricStats", tags=['读取'])
21 | async def listMetricStats(UserToken: str = Cookie(None),
22 | commons: dict = Depends(Utils.init)):
23 | config = commons[0]
24 | ESql = commons[2]
25 | UserToken = "YMJwls2Xj7JU7zBjGzlk6qjoZKj6ERkiicHx0TfgQgUcD5ntwQeJcuEziS6wNUAp1F2MkKbkdrAvx7AQYpcTgZOmrNLu2X2zt3ARPMA4OgL4nnsOORHlGJvAd3ak6MxN"
26 | if ESql is None:
27 | return Utils.message(393)
28 | api = config['API']
29 | # GoEdge_Api = MetricStatService.MetricStatService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], config['Token'])
30 | # GoEdge_Api.listMetricStats()
31 | # GoEdge_Api = OriginService.OriginService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
32 | # GoEdge_Api = ReverseProxyService.ReverseProxyService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
33 | # GoEdge_Api = OriginService.OriginService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], config['Token'])
34 | GoEdge_Api2 = SSLCertService.SSLCertService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], config['Token'])
35 | # GoEdge_Api = SSLCertService.SSLCertService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'],
36 | # UserToken)
37 | # serverInfo = GoEdge_Api.findEnabledOrigin(2)
38 | a = """
39 | [{"isOn": false, "originId": 2}]
40 | """
41 | # GoEdge_Api.updateReverseProxOrigins(2,json.loads(a),True)
42 | # GoEdge_Api.listSSLCerts(1,0,5)
43 | # GoEdge_Api2.listSSLCerts()
44 | GoEdge_Api2.countAllEnabledServersWithSSLCertId(2)
45 | return 1
--------------------------------------------------------------------------------
/Controller/OriginService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import hashlib
3 | import json
4 | import re
5 | import time
6 |
7 | import API.UserService as UserService
8 | import API.ReverseProxyService as ReverseProxyService
9 | import Sql
10 | import Utils
11 | from API import OriginService as OriginService, ServerService, SSLPolicyService
12 | from Utils.tencent import Tencent
13 | from fastapi import APIRouter, Path, Body, Depends, Request, Response, Cookie
14 |
15 | # from main import Data_Config
16 | app = APIRouter(prefix="/OriginService", tags=['源站管理服务'])
17 |
18 |
19 | @app.post("/updateOrigin", tags=['修改源站'])
20 | async def updateOrigin(
21 | UserToken: str = Cookie(None),
22 | OriginJson: str = Body(None),
23 | isOn: bool = Body(None),
24 | commons: dict = Depends(Utils.init)):
25 | # 单参数时错误,需要加一个
26 | config = commons[0]
27 | api = config['API']
28 | if OriginJson is None:
29 | return Utils.message(201)
30 | GoEdge_Api = OriginService.OriginService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
31 | OriginJson_bytes = json.loads(base64.b64decode(OriginJson).decode("utf-8"))
32 | originInfo = GoEdge_Api.updateOrigin(OriginJson_bytes)
33 | if not originInfo[0]:
34 | if originInfo[1] is None:
35 | return Utils.message(402)
36 | else:
37 | return Utils.message(389, message=originInfo[1])
38 | return Utils.message(200)
39 |
40 |
41 | @app.post("/findEnabledOrigin", tags=['获取源站配置'])
42 | async def findEnabledOrigin(
43 | UserToken: str = Cookie(None),
44 | originId: int = Body(None),
45 | isOn: bool = Body(None),
46 | commons: dict = Depends(Utils.init)):
47 | # 源站配置base64传入解码后再传入类工具,类工具再编码
48 | # 单int参数需要带其他类型参数,否则异常,fastapibug
49 | config = commons[0]
50 | api = config['API']
51 | GoEdge_Api = OriginService.OriginService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
52 | if originId is None:
53 | return Utils.message(201)
54 | originInfo = GoEdge_Api.findEnabledOrigin(originId)
55 | if not originInfo[0]:
56 | if originInfo[1] is None:
57 | return Utils.message(402)
58 | else:
59 | return Utils.message(389, message=originInfo[1])
60 | return Utils.message(200, data=originInfo[1])
61 |
62 |
63 | @app.post("/deleteOrigin")
64 | async def deleteOrigin(
65 | UserToken: str = Cookie(None),
66 | originId: int = Body(None),
67 | reverseProxyId: int = Body(None),
68 | isOn: bool = Body(None),
69 | originJson: str = Body(None),
70 | commons: dict = Depends(Utils.init)):
71 | # isOn是否主源站,originJson primaryOrigins等字段更新,通过这个字段进行引导源站
72 | config = commons[0]
73 | api = config['API']
74 | GoEdge_Api = OriginService.OriginService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
75 | GoEdge_Api2 = ReverseProxyService.ReverseProxyService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'],
76 | UserToken)
77 | if originId is None:
78 | return Utils.message(201)
79 | if reverseProxyId is None:
80 | return Utils.message(201)
81 | if isOn is None:
82 | return Utils.message(201)
83 | if originJson is None:
84 | return Utils.message(201)
85 | OriginJson_bytes = json.loads(base64.b64decode(originJson).decode("utf-8"))
86 | ReverseProxOriginsInfo = GoEdge_Api.deleteOrigin(reverseProxyId=reverseProxyId, GoEdgeApi=GoEdge_Api2,
87 | originId=originId, originJson=OriginJson_bytes, Primary=isOn)
88 | if not ReverseProxOriginsInfo[0]:
89 | if ReverseProxOriginsInfo[1] is None:
90 | return Utils.message(402)
91 | else:
92 | return Utils.message(389, message=ReverseProxOriginsInfo[1])
93 | return Utils.message(200)
94 |
95 |
96 | @app.post("/createOrigin")
97 | async def createOrigin(
98 | UserToken: str = Cookie(None),
99 | reverseProxyId: int = Body(None),
100 | originJson: str = Body(None),
101 | isOn: bool = Body(None),
102 | commons: dict = Depends(Utils.init)):
103 | # 单int参数需要带其他类型参数,否则异常,fastapibug
104 | # isOn为是否主源站,true主,false备
105 | config = commons[0]
106 | api = config['API']
107 | GoEdge_Api = OriginService.OriginService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
108 | if originJson is None:
109 | return Utils.message(201)
110 | if isOn is None:
111 | return Utils.message(201)
112 | if reverseProxyId is None:
113 | return Utils.message(201)
114 | OriginJson_bytes = json.loads(base64.b64decode(originJson).decode("utf-8"))
115 | originInfo = GoEdge_Api.createOrigin(OriginJson_bytes)
116 |
117 | if not originInfo[0]:
118 | if originInfo[1] is None:
119 | return Utils.message(402)
120 | else:
121 | return Utils.message(389, message=originInfo[1])
122 | # 创建成功,放入反代理
123 | sourceData = OriginJson_bytes['sourceData']
124 | GoEdge_Api2 = ReverseProxyService.ReverseProxyService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'],
125 | UserToken)
126 | if originInfo[1] is None:
127 | return Utils.message(402)
128 | sourceData.append({"isOn": True, "originId": originInfo[1]})
129 | ReverseProxOriginsInfo = GoEdge_Api2.updateReverseProxOrigins(reverseProxyId=reverseProxyId, originsJSON=sourceData,
130 | Primary=isOn)
131 | if not ReverseProxOriginsInfo[0]:
132 | if ReverseProxOriginsInfo[1] is None:
133 | return Utils.message(402)
134 | else:
135 | return Utils.message(389, message=ReverseProxOriginsInfo[1])
136 | return Utils.message(200)
137 |
138 |
139 | @app.post("/updateOriginSSL")
140 | async def updateOriginSSL(
141 | UserToken: str = Cookie(None),
142 | serverId: int = Body(None),
143 | certId: int = Body(None),
144 | commons: dict = Depends(Utils.init)):
145 | config = commons[0]
146 | api = config['API']
147 | GoEdge_Api = SSLPolicyService.SSLPolicyService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
148 | GoEdge_Api2 = ServerService.ServerService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
149 | serverInfo = GoEdge_Api2.findEnabledServerConfig(serverId)
150 | if not serverInfo[0]:
151 | if serverInfo[1] is None:
152 | return Utils.message(402)
153 | else:
154 | return Utils.message(389, message=serverInfo[1])
155 | serverInfoConfig = json.loads(base64.b64decode(serverInfo[1]).decode('utf-8'))
156 | sslPolicyId = serverInfoConfig['https']['sslPolicyRef']['sslPolicyId']
157 | hsts = serverInfoConfig['https']['sslPolicy']['hsts']
158 | http2Enabled = serverInfoConfig['https']['sslPolicy']['http2Enabled']
159 | ocspIsOn = serverInfoConfig['https']['sslPolicy']['ocspIsOn']
160 | minVersion = serverInfoConfig['https']['sslPolicy']['minVersion']
161 | if hsts is None:
162 | hsts = {
163 | "isOn":False,
164 | "maxAge":1,
165 | "preload":False,
166 | "includeSubDomains":False
167 | }
168 | sslInfo = GoEdge_Api.updateSSLPolicy(sslPolicyId=sslPolicyId,ocsp=ocspIsOn,sslID=certId,hsts=hsts,http2Enabled=http2Enabled,minVersion=minVersion)
169 | if not sslInfo[0]:
170 | if sslInfo[1] is None:
171 | return Utils.message(402)
172 | else:
173 | return Utils.message(389, message=sslInfo[1])
174 | return Utils.message(200)
175 |
176 |
--------------------------------------------------------------------------------
/Controller/SSLCertService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import datetime
3 | import json
4 | import time
5 |
6 | from OpenSSL import crypto
7 | from cryptography import x509
8 | import cryptography
9 | from cryptography.hazmat.backends import default_backend
10 |
11 | from fastapi import APIRouter, Depends, Cookie, Body
12 | import API.ServerService as ServerService
13 | import API.UserService as UserService
14 | import API.SSLCertService as SSLCertService
15 | import Utils
16 |
17 | app = APIRouter(prefix="/SSLCertService", tags=['SSL服务'])
18 |
19 |
20 | # 将userid放进cookie httponly中
21 |
22 | @app.post("/createSSLCert")
23 | async def createSSLCert(UserToken: str = Cookie(None),
24 | name: str = Body(None),
25 | isCA: bool = Body(None),
26 | certData: str = Body(None),
27 | keyData: str = Body(None),
28 | commons: dict = Depends(Utils.init)):
29 | # 此时全部是用户token
30 | config = commons[0]
31 | ESql = commons[2]
32 | if ESql is None:
33 | return Utils.message(393)
34 | if name is None:
35 | return Utils.message(201)
36 | if isCA is None:
37 | return Utils.message(201)
38 | if certData is None:
39 | return Utils.message(201)
40 | # if keyData is None:
41 | # return Utils.message(201)
42 | api = config['API']
43 | GoEdge_Api = SSLCertService.SSLCertService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
44 |
45 | c = base64.b64decode(certData)
46 | try:
47 | cert1 = crypto.load_certificate(crypto.FILETYPE_PEM, c)
48 | # cert.get_issuer().CN 颁发机构
49 | # cert.get_subject().CN 获得通用名称
50 | # cert.get_serial_number() 证书SN
51 | # cert.subject_name_hash()证书hash
52 | # cert.get_notBefore() 证书生效 b'20221006000000Z'
53 | # cert.get_notBefore() 证书失效 b'20230104235959Z'
54 | # print(cert.get_subject())
55 | cert2 = x509.load_pem_x509_certificate(c, default_backend())
56 | ski = cert2.extensions.get_extension_for_oid(x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
57 | DNSNameS = ski.value.get_values_for_type(cryptography.x509.DNSName)
58 | issuer_type = cert1.get_issuer().CN
59 | issuer_author = cert1.get_issuer().O
60 | Atime = int(datetime.datetime.strptime(cert1.get_notBefore().decode()[0:-1], '%Y%m%d%H%M%S').timestamp())
61 | Etime = int(datetime.datetime.strptime(cert1.get_notAfter().decode()[0:-1], '%Y%m%d%H%M%S').timestamp())
62 | except:
63 | return Utils.message(389, message="证书不正确")
64 | SSLinfo = GoEdge_Api.createSSLCert(name=name, isCA=isCA, certData=certData, keyData=keyData, timeBeginAt=Atime,
65 | timeEndAt=Etime, dnsNames=DNSNameS, issuer_type=issuer_type,
66 | issuer_author=issuer_author)
67 | if not SSLinfo[0]:
68 | if SSLinfo[1] is None:
69 | return Utils.message(402)
70 | else:
71 | return Utils.message(389, message=SSLinfo[1])
72 | return Utils.message(200)
73 |
74 |
75 | @app.post("/listSSLCerts")
76 | async def listSSLCerts(UserToken: str = Cookie(None),
77 | UserId: int = Cookie(None),
78 | offset: int = Body(),
79 | size: int = Body(),
80 | keyword: str = Body(None),
81 | commons: dict = Depends(Utils.init)):
82 | config = commons[0]
83 | api = config['API']
84 | GoEdge_Api = SSLCertService.SSLCertService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
85 | listSSL = GoEdge_Api.listSSLCerts(UserId, offset, size, keyword)
86 | countSSL = GoEdge_Api.countSSLCerts(UserId, keyword)
87 | if not countSSL[0]:
88 | if countSSL[1] is None:
89 | return Utils.message(402)
90 | else:
91 | return Utils.message(389, message=countSSL[1])
92 | if not listSSL[0]:
93 | if listSSL[1] is None:
94 | return Utils.message(402)
95 | else:
96 | return Utils.message(389, message=listSSL[1])
97 | try:
98 | listSSL_V2 = json.loads(base64.b64decode(listSSL[1]).decode())
99 | for i,v in enumerate(listSSL_V2):
100 | countInfo = GoEdge_Api.countAllEnabledServersWithSSLCertId(int(v['id']))
101 | if not countInfo[0]:
102 | if countInfo[1] is None:
103 | return Utils.message(402)
104 | else:
105 | return Utils.message(389, message=countInfo[1])
106 | listSSL_V2[i]['count'] = countInfo[1]
107 | listSSL_V2 = base64.b64encode(json.dumps(listSSL_V2).encode('utf-8')).decode("utf-8")
108 | except:
109 | return Utils.message(402)
110 | ret = {
111 | "count": countSSL[1],
112 | "data": listSSL_V2
113 | }
114 | return Utils.message(200, data=ret)
115 |
116 |
117 | @app.post("/deleteSSLCert")
118 | async def deleteSSLCert(UserToken: str = Cookie(None),
119 | sslCertId: int = Body(None),
120 | isOn: bool = Body(None),
121 | commons: dict = Depends(Utils.init)):
122 | config = commons[0]
123 | api = config['API']
124 | if sslCertId is None:
125 | return Utils.message(201)
126 | GoEdge_Api = SSLCertService.SSLCertService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
127 | sslInfo = GoEdge_Api.deleteSSLCert(sslCertId)
128 | if not sslInfo[0]:
129 | if sslInfo[1] is None:
130 | return Utils.message(402)
131 | else:
132 | return Utils.message(389, message=sslInfo[1])
133 | return Utils.message(200)
134 |
--------------------------------------------------------------------------------
/Controller/SSLPolicyService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import json
3 |
4 | from fastapi import APIRouter, Depends, Cookie, Body
5 | import API.ServerService as ServerService
6 | import API.UserService as UserService
7 | import Utils
8 | from API import SSLPolicyService
9 |
10 | app = APIRouter(prefix="/SSLPolicyService", tags=['SSL服务'])
11 |
12 | @app.post("/updateSSLPolicy")
13 | async def updateSSLPolicy(UserToken: str = Cookie(None),
14 | sslPolicyId: int = Body(None),
15 | ocsp: bool = Body(None),
16 | sslID: int = Body(None),
17 | hsts: str = Body(None),
18 | minVersion: str = Body(None),
19 | http2Enabled: bool = Body(None),
20 | commons: dict = Depends(Utils.init)):
21 | try:
22 | hsts_bytes = json.loads(base64.b64decode(hsts).decode())
23 | except:
24 | return Utils.message(402)
25 | if sslPolicyId is None or ocsp is None or sslID is None or http2Enabled is None or minVersion is None or hsts is None:
26 | return Utils.message(201)
27 | # 此时全部是用户token
28 | config = commons[0]
29 | api = config['API']
30 | GoEdge_Api = SSLPolicyService.SSLPolicyService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
31 | info = GoEdge_Api.updateSSLPolicy(sslPolicyId=sslPolicyId,ocsp=ocsp,sslID=sslID,hsts=hsts_bytes,http2Enabled=http2Enabled,minVersion=minVersion)
32 | if not info[0]:
33 | if info[1] is None:
34 | return Utils.message(402)
35 | else:
36 | return Utils.message(389, message=info[1])
37 | return Utils.message(200)
38 |
39 |
--------------------------------------------------------------------------------
/Controller/ServerService.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import json
3 |
4 | from fastapi import APIRouter, Depends, Cookie, Body
5 | import API.ServerService as ServerService
6 | import API.UserService as UserService
7 | import Utils
8 |
9 | app = APIRouter(prefix="/ServerService", tags=['网站服务'])
10 |
11 |
12 | # 将userid放进cookie httponly中
13 |
14 | @app.post("/createServer")
15 | async def createServer(UserToken: str = Cookie(None),
16 | UserId: int = Cookie(None),
17 | clusterId: int = Body(),
18 | domian: str = Body(),
19 | name: str = Body(),
20 | commons: dict = Depends(Utils.init)):
21 | # 此时全部是用户token
22 | config = commons[0]
23 | ESql = commons[2]
24 | if ESql is None:
25 | return Utils.message(393)
26 | api = config['API']
27 | # 用户管理还是需要管理token的
28 | GoEdge_Api = UserService.UserService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], config['Token'])
29 | # userId = GoEdge_Api.token_find_userid(ESql, UserToken)
30 | # if userId is None:
31 | # return Utils.message(388)
32 | if clusterId != api['nodeClusterId']:
33 | return Utils.message(387)
34 | GoEdge_Api = ServerService.ServerService(api['HOST'], None, None, UserToken)
35 | info = GoEdge_Api.createServer(clusterId, userId=UserId, name=name, domain=domian)
36 | if not info[0]:
37 | if info[1] is None:
38 | return Utils.message(402)
39 | else:
40 | return Utils.message(389, message=info[1])
41 | return Utils.message(200, info[1])
42 |
43 |
44 | @app.get("/findAllUserServers")
45 | async def findAllUserServers(UserToken: str = Cookie(None),
46 | UserId: int = Cookie(None),
47 | commons: dict = Depends(Utils.init)
48 | ):
49 | # 此时全部是用户token
50 | config = commons[0]
51 | ESql = commons[2]
52 | api = config['API']
53 | GoEdge_Api = ServerService.ServerService(api['HOST'], None, None, UserToken)
54 | # GoEdge_UserService = UserService.UserService(api['HOST'], None, None, UserToken)
55 | # userId = GoEdge_UserService.token_find_userid(ESql, UserToken)
56 | domainList = GoEdge_Api.findAllUserServers(UserId)
57 | if not domainList[0]:
58 | if domainList[1] is None:
59 | return Utils.message(402)
60 | else:
61 | return Utils.message(389, message=domainList[1])
62 | return Utils.message(200, domainList[1])
63 |
64 |
65 | @app.post("/updateServerIsOn")
66 | async def updateServerIsOn(UserToken: str = Cookie(None),
67 | UserId: int = Cookie(None),
68 | serverId: int = Body(None),
69 | isOn: bool = Body(None),
70 | commons: dict = Depends(Utils.init)):
71 | # 此时全部是用户token
72 | config = commons[0]
73 | ESql = commons[2]
74 | api = config['API']
75 | GoEdge_Api = ServerService.ServerService(api['HOST'], None, None, UserToken)
76 | updateServer = GoEdge_Api.updateServerIsOn(serverId, isOn)
77 | if not updateServer[0]:
78 | if updateServer[1] is None:
79 | return Utils.message(402)
80 | else:
81 | return Utils.message(389, message=updateServer[1])
82 | return Utils.message(200)
83 |
84 |
85 | @app.post("/findEnabledServerConfig")
86 | async def findEnabledServerConfig(UserToken: str = Cookie(None),
87 | serverId: int = Body(None),
88 | isOn: bool = Body(None),
89 | commons: dict = Depends(Utils.init)):
90 | # 单独int参数时需要带上其他类型参数,不然类型错误,fastapibug
91 | config = commons[0]
92 | api = config['API']
93 | GoEdge_Api = ServerService.ServerService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
94 | if serverId is None:
95 | return Utils.message(201)
96 | serverInfo = GoEdge_Api.findEnabledServerConfig(serverId)
97 | if not serverInfo[0]:
98 | if serverInfo[1] is None:
99 | return Utils.message(402)
100 | else:
101 | return Utils.message(389, message=serverInfo[1])
102 | return Utils.message(200, serverInfo[1])
103 |
104 |
105 | @app.post("/deleteServer")
106 | async def deleteServer(UserToken: str = Cookie(None),
107 | serverId: int = Body(None),
108 | isOn: bool = Body(None),
109 | commons: dict = Depends(Utils.init)):
110 | # 单独int参数时需要带上其他类型参数,不然类型错误,fastapibug
111 | config = commons[0]
112 | api = config['API']
113 | GoEdge_Api = ServerService.ServerService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
114 | if serverId is None:
115 | return Utils.message(201)
116 | # 检查是否被禁用,无禁用不可删除
117 | ServerInfo1 = GoEdge_Api.findEnabledServer(serverId)
118 | if not ServerInfo1[0]:
119 | if ServerInfo1[1] is None:
120 | return Utils.message(402)
121 | else:
122 | return Utils.message(389, message=ServerInfo1[1])
123 | if ServerInfo1[1] == {}:
124 | return Utils.message(402)
125 | if "isOn" in ServerInfo1[1] and ServerInfo1[1]['isOn']:
126 | return Utils.message(386)
127 | serverInfo = GoEdge_Api.deleteServer(serverId)
128 | if not serverInfo[0]:
129 | if serverInfo[1] is None:
130 | return Utils.message(402)
131 | else:
132 | return Utils.message(389, message=serverInfo[1])
133 | return Utils.message(200)
134 |
135 |
136 | @app.post("/updateServerReverseProxy")
137 | async def updateServerReverseProxy(UserToken: str = Cookie(None),
138 | serverId: int = Body(None),
139 | reverseProxyJSON: str = Body(None),
140 | commons: dict = Depends(Utils.init)):
141 | # 源站配置base64传入解码后再传入类工具,类工具再编码
142 | config = commons[0]
143 | api = config['API']
144 | GoEdge_Api = ServerService.ServerService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
145 | if serverId is None:
146 | return Utils.message(201)
147 | reverseProxyJSON_bytes = json.loads(base64.b64decode(reverseProxyJSON).decode("utf-8"))
148 | serverInfo = GoEdge_Api.updateServerReverseProxy(serverId, reverseProxyJSON_bytes)
149 | if not serverInfo[0]:
150 | if serverInfo[1] is None:
151 | return Utils.message(402)
152 | else:
153 | return Utils.message(389, message=serverInfo[1])
154 | return Utils.message(200)
155 |
156 |
157 | @app.post("/updateServerHTTPS")
158 | async def updateServerHTTPS(UserToken: str = Cookie(None),
159 | serverId: int = Body(None),
160 | isOn: bool = Body(None),
161 | commons: dict = Depends(Utils.init)):
162 | if isOn is None or serverId is None:
163 | return Utils.message(201)
164 | config = commons[0]
165 | api = config['API']
166 | GoEdge_Api = ServerService.ServerService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
167 | HTTPSinfo = GoEdge_Api.updateServerHTTPS(serverId, isOn)
168 | if not HTTPSinfo[0]:
169 | if HTTPSinfo[1] is None:
170 | return Utils.message(402)
171 | else:
172 | return Utils.message(389, message=HTTPSinfo[1])
173 | return Utils.message(200)
174 |
175 | @app.post("/updateServerHTTP")
176 | async def updateServerHTTP(UserToken: str = Cookie(None),
177 | serverId: int = Body(None),
178 | isOn: bool = Body(None),
179 | commons: dict = Depends(Utils.init)):
180 | if isOn is None or serverId is None:
181 | return Utils.message(201)
182 | config = commons[0]
183 | api = config['API']
184 | GoEdge_Api = ServerService.ServerService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], UserToken)
185 | HTTPSinfo = GoEdge_Api.updateServerHTTP(serverId, isOn)
186 | if not HTTPSinfo[0]:
187 | if HTTPSinfo[1] is None:
188 | return Utils.message(402)
189 | else:
190 | return Utils.message(389, message=HTTPSinfo[1])
191 | return Utils.message(200)
192 |
--------------------------------------------------------------------------------
/Controller/UserService.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import json
3 | import re
4 | import time
5 |
6 | import API.UserService as UserService
7 | import Sql
8 | import Utils
9 | from Utils.tencent import Tencent
10 | from fastapi import APIRouter, Path, Body, Depends, Request, Response, Cookie
11 |
12 | # from main import Data_Config
13 | app = APIRouter(prefix="/UserService", tags=['用户相关服务'])
14 |
15 |
16 | @app.post("/registerUser", tags=['注册用户'])
17 | async def registerUser(request1: Request,
18 | username: str = Body(
19 | description='必须是正确的手机号或邮箱,且必填'),
20 | # username: str = Body(regex=r"^[a-zA-Z][a-zA-Z0-9_]{4,15}$", min_length=5,
21 | # max_length=13, description='用户必填,最小5个字符,最大13个字符,且只能大写/小写字母,数字和特殊符号'),
22 | password: str = Body(regex=r"^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])).*$", min_length=5,
23 | max_length=13, description='密码必填,最小5个字符,最大13个字符,且只能大写/小写字母,数字和特殊符号'),
24 | # mobile: str = Body(
25 | # regex='^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\d{8}$',
26 | # description='必须是正确的手机号,且必填'),
27 | # 先暂时参数邮箱保留,后期手机验证码写上后,根据用户名决定不填,手机注册邮箱空,手机号存在。邮箱注册手机空,邮箱号存在
28 | # email: str = Body(regex=r'([\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+)', description='必须正确的邮箱,且必填'),
29 | code: str = Body(),
30 | ticket: str = Body(None),
31 | randstr: str = Body(None),
32 | commons: dict = Depends(Utils.init)):
33 | # 初始化
34 | email = None
35 | mobile = None
36 | # 用户名用手机或邮箱
37 | ret = re.match('^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\d{8}$', username)
38 | type = 0 # 0是邮箱 1是手机
39 | if not ret:
40 | ret = re.match(r'([\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+)', username)
41 | if not ret:
42 | return Utils.message(395)
43 | else:
44 | email = username
45 | type = 0
46 | else:
47 | mobile = username
48 | type = 1
49 | if type == 1:
50 | return Utils.message(202)
51 |
52 | config = commons[0]
53 | ip = request1.client.host
54 | # 验证腾讯滑块验证码
55 | if config['Config']['whetherVerificationCodeIsEnabl']:
56 | if ticket is None or randstr is None:
57 | return Utils.message(396)
58 | T = Tencent()
59 | flag = T.check_ticket(ticket, randstr)
60 | if flag == -1:
61 | return Utils.message(394)
62 | if flag == 0:
63 | return Utils.message(396)
64 | # 滑块结束
65 | api = config['API']
66 | Verification = config['Verification']
67 | # 连接数据库查询验证码
68 | VSql: Sql.Sql = commons[1]
69 | if VSql is None:
70 | return Utils.message(401)
71 | code_db = VSql.fetch_where("edge_code", {
72 | "number": email
73 | }, additionalContent="order by `timeStamp` desc")
74 | # 查询验证码是否过期
75 | millis = int(round(time.time() * 1000))
76 | if code_db is not None:
77 | if millis - int(code_db['timeStamp']) > Verification['frequentTime'] * 1000:
78 | return Utils.message(397)
79 | else:
80 | # 查询验证码是否正确
81 | if code.lower() != str(code_db['code']).lower():
82 | return Utils.message(397)
83 | else:
84 | return Utils.message(397)
85 |
86 | # 验证成功,删除此验证码
87 | VSql.delete("edge_code", {
88 | "id": code_db['id']
89 | })
90 | GoEdge_Api = UserService.UserService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], config['Token'])
91 | # res = GoEdge_Api.createUser(username, password, mobile, email, username, ip, None, mobile, 1)
92 | res = GoEdge_Api.createUser(username, password, mobile, email, username, ip, None, mobile, api['nodeClusterId'])
93 | if res is None:
94 | return Utils.message(402)
95 | return res
96 |
97 |
98 | @app.post("/loginUser")
99 | async def loginUser(
100 | response: Response,
101 | username: str = Body(),
102 | password: str = Body(),
103 | ticket: str = Body(None),
104 | randstr: str = Body(None),
105 | commons: dict = Depends(Utils.init)):
106 | config = commons[0]
107 | # 判断参数
108 | if username is None or username == "" or password is None or password == "":
109 | return Utils.message(390)
110 | # 验证腾讯滑块验证码
111 | if config['Config']['whetherVerificationCodeIsEnabl']:
112 | if ticket is None or randstr is None:
113 | return Utils.message(396)
114 | T = Tencent()
115 | flag = T.check_ticket(ticket, randstr)
116 | if flag == -1:
117 | return Utils.message(394)
118 | if flag == 0:
119 | return Utils.message(396)
120 | # 滑块结束
121 | api = config['API']
122 | ESql = commons[2]
123 | if ESql is None:
124 | return Utils.message(393)
125 | GoEdge_Api = UserService.UserService(api['HOST'], api['AccessKey ID'], api['AccessKey Key'], config['Token'])
126 | res = GoEdge_Api.loginUser(ESql, username, password)
127 | if res is None:
128 | return Utils.message(392)
129 | md = hashlib.md5(password.encode())
130 | if res['password'] != md.hexdigest():
131 | return Utils.message(390)
132 | if res['serversEnabled'] == 0:
133 | return Utils.message(391)
134 | # 获取成功,获取token
135 | userToken = GoEdge_Api.getToken("user", res['uniqueId'], res['secret'])
136 | if userToken is None:
137 | return Utils.message(402)
138 | # 置入cookie
139 | # 置入cookie
140 | # response.set_cookie(key="UserToken",value=userToken[0])
141 | response.set_cookie(key="UserToken", value=userToken[0], max_age=userToken[1], httponly=True)
142 | response.set_cookie(key="UserId", value=res['id'], max_age=userToken[1], httponly=True)
143 | return Utils.message(200, {
144 | "Token": userToken[0],
145 | "Time": userToken[1]
146 | })
147 |
148 | @app.post("/logout")
149 | async def logout(response: Response,
150 | UserToken: str = Cookie(None),
151 | UserId: int = Cookie(None), ):
152 | response.delete_cookie(key="UserToken", httponly=True)
153 | response.delete_cookie(key="UserId", httponly=True)
154 |
155 | return Utils.message(200)
156 |
--------------------------------------------------------------------------------
/Controller/Verification.py:
--------------------------------------------------------------------------------
1 | import re
2 | import time
3 |
4 | from email.header import Header
5 | from email.mime.text import MIMEText
6 |
7 |
8 | import Utils
9 | from fastapi import APIRouter, Path, Depends, Body
10 | import smtplib
11 |
12 | from Utils.tencent import Tencent
13 |
14 | app = APIRouter(prefix="/Verification", tags=['验证服务'])
15 |
16 |
17 | @app.post("/getcode")
18 | async def getcode(number: str = Body(description='必须正确的邮箱,且必填'),
19 | # 注册必须滑块,不可关闭
20 | ticket: str = Body(),
21 | randstr: str = Body(),
22 | commons: dict = Depends(Utils.init)):
23 | # if type != 0 and type != 1:
24 | # return Utils.message(201)
25 | # if type == 1:
26 | # return Utils.message(202)
27 |
28 | # 用户名用手机或邮箱
29 | ret = re.match('^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\d{8}$', number)
30 | type = 0 # 0是邮箱 1是手机
31 | if not ret:
32 | ret = re.match(r'([\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+)', number)
33 | if not ret:
34 | return Utils.message(395)
35 | else:
36 | type = 0
37 | else:
38 | type = 1
39 | if type == 1:
40 | return Utils.message(202)
41 | # 参数正确,开始滑块
42 |
43 | # 验证腾讯滑块验证码
44 | T = Tencent()
45 | flag = T.check_ticket(ticket, randstr)
46 | if flag == -1:
47 | return Utils.message(394)
48 | if flag == 0:
49 | return Utils.message(396)
50 | # 滑块结束
51 |
52 | # 查询数据库寻找title,暂时查询不到,用配置文件替代
53 | config = commons[0]
54 | Verification = config['Verification']
55 | mysql = config['mysql']
56 | host = Verification['host']
57 | port = Verification['port']
58 | uer_name = Verification['user']
59 | password = Verification['password']
60 | # 写入验证码
61 | yzm = Utils.generate_random_str(6)
62 | # VSql = Sql.Sql(mysql['host'], mysql['port'], mysql['user'], mysql['password'], mysql['database'])
63 | VSql = commons[1]
64 | if VSql is None:
65 | return Utils.message(401)
66 | millis = int(round(time.time() * 1000))
67 | toBeWritten = {
68 | "type": 0,
69 | "number": number,
70 | "code": yzm,
71 | "timeStamp": str(millis)
72 | }
73 | # 先查询是否频繁
74 | code_db = VSql.fetch_where("edge_code", {
75 | "number": number
76 | }, additionalContent="order by `timeStamp` desc")
77 | if code_db is not None:
78 | if millis - int(code_db['timeStamp']) < Verification['frequentTime'] * 1000:
79 | return Utils.message(398)
80 |
81 | flag = VSql.insert("edge_code", toBeWritten)
82 | if not flag:
83 | return Utils.message(4012)
84 | msg = "标题不是验证码。\n您正在注册 {} 的验证码,验证码为:{}".format(Verification['title'], yzm)
85 | msg = MIMEText(msg, 'plain', 'utf-8')
86 | # 放入邮件主题 随机标题,防止拦截,特别是qq邮箱
87 | msg['Subject'] = Header("{}注册验证码 {}".format(Verification['title'], Utils.generate_random_str(6)), 'utf-8')
88 |
89 | # 放入发件人
90 | msg['From'] = uer_name
91 |
92 | try:
93 | '''2、创建 SMTP 对象
94 | SMTP 协议是由源服务器到目的地服务器传送邮件的一组规则。(可简单理解为:我们需要通过SMTP指定一个服务器,这样才能把邮件送到另一个服务器)'''
95 |
96 | if Verification['ssl']:
97 | smtpObj = smtplib.SMTP_SSL(host, port)
98 | else:
99 | smtpObj = smtplib.SMTP(host, port)
100 | '''3、连接(connect)指定服务器'''
101 | smtpObj.connect(host, port)
102 | '''4、登录,需要:登录邮箱和授权码'''
103 | smtpObj.login(uer_name, password)
104 | '''5、发邮件。
105 | 参数:发件人,收件人和邮件内容
106 | msg.as_string()是一个字符串类型:as_string()是将发送的信息msg变为字符串类型。
107 | '''
108 | smtpObj.sendmail(uer_name, number, msg.as_string())
109 | '''6、退出'''
110 | smtpObj.quit()
111 | except:
112 | # traceback.print_exc()
113 | # 邮箱发送失败。删除记录
114 | VSql.delete("edge_code", toBeWritten)
115 | return Utils.message(399)
116 | return Utils.message(200)
117 |
118 |
--------------------------------------------------------------------------------
/ErrCode/__init__.py:
--------------------------------------------------------------------------------
1 | ErrCode = {
2 | # 无400,402要么是管理员token错误,要么是api接口错误,要么是程序错误
3 | "200": "ok",
4 | "201": "参数错误,漏写参数或参数值不正确",
5 | "202": "该功能可能未开启",
6 | "399": "邮箱连接失败,发送失败",
7 | "398": "请勿频繁发送验证码",
8 | "397": "验证码错误或失效",
9 | "396": "滑块错误或未滑块",
10 | "394": "滑块接口失效",
11 | "395": "用户名必须是手机号或邮箱",
12 | "393": "EdgeAdmin_mysql数据库连接失败,请通知网站管理员查看日志",
13 | "392": "用户不存在",
14 | "391": "用户已被封禁",
15 | "390": "账号密码错误",
16 | "389": "自定义出错",
17 | "388": "你还没有登陆或登录态失效,请重新登陆",
18 | "387": "此套餐不属于你或暂不支持此套餐",
19 | "386": "服务器未禁用,不可删除",
20 | "401": "数据库连接失败,请通知网站管理员查看日志",
21 | "402": "一般是你操作的对象不属于你,你没有权限。或内部处理错误,请联系客服咨询",
22 | "4012": "数据库连接失败或数据库语句执行失败,请通知网站管理员查看日志"
23 | }
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 AMEN
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AMEN-GoEdge-User后端
2 |
3 | ## 这是什么项目?
4 | 这是 GoEdge CDN的用户端
5 |
6 | ## 为什么要创作,GoEdge没有用户端吗?
7 | 有,但是是商业版才可用,也就是需要💴
8 |
9 | ## 有哪些功能
10 | 1.注册
11 | 2.登录
12 | 3.验证码
13 | 4.网站管理
14 | 5.添加/删除网站
15 | 6.https设置(http2/强制https/https证书/hsts/开关http|s/ocps/tls)
16 | 7.源站管理(支持端口/支持域名/支持ip/支持https/支持https证书/添加/删除)
17 | 8.证书管理(一键绑定/添加/删除)
18 |
19 | ## 后续会增加功能吗?
20 | 会的,会逐渐加上:waf规则自定义/webp/缓存/防盗链/Websocket/地区限制/URL跳转/网站统计(流量/请求数)/拦截日志
21 |
22 | ## 只有后端,没有前端吗?
23 | 有的,项目在 https://github.com/2331892928/AMEN-GoEdge-User_frontEnd
24 |
25 | ## 如何升级?
26 | 后期会给升级方法,基本覆盖即可
27 |
28 | ## 如何安装后端?
29 | ### 导入sql
30 | 将此项目根目录下的 edge_code.sql导入即可
31 | ### GoEdgeAdmin设置
32 | 1.系统设置->高级设置->API节点->主节点详情->修改节点->更多选项->是否开启HTTP API端口(开启)->HTTP API监听端口(自行设置)->启用当前节点(打开)
33 | 2.系统用户->随便一个->详情->accesskeys—>按需创建添加,记住即可后边用
34 | ### 填写配置文件
35 | 没有配置文件?
36 | 将项目运行一遍,即可在项目根目录下的Config文件夹里
37 | 配置文件名:Config.json
38 | 配置解释:
39 | ```json
40 | {
41 | "Config": {
42 | "whetherVerificationCodeIsEnabl": false # 是否开启腾讯验证码,验证码界面有:
43 | # 注册/登录/发送验证码。关闭后只有以下生效:发送验证码
44 | },
45 | "mysql": {# 本项目sql配置
46 | "host": "127.0.0.1", # mysql主机名
47 | "port": 3306,# mysql端口
48 | "user": "goedge",# mysql用户
49 | "password": "goedge",# mysql密码
50 | "database": "goedge"# mysql数据库
51 | },
52 | "EdgeAdmin_mysql": { # GoEdgeAdmin的数据库
53 | "host": "",
54 | "port": 8001,
55 | "user": "",
56 | "password": "",
57 | "database": ""
58 | },
59 | "Verification": { # 发送验证码配置,邮箱配置
60 | "type": 0,
61 | "host": "", # 邮箱主机名
62 | "port": 465, #邮箱端口
63 | "ssl": true, #邮箱是否启用ssl
64 | "user": "", #邮箱用户名
65 | "password": "", #邮箱密码
66 | "title": "AMEN-GoEdge-User", #邮箱主题/网站主题
67 | "frequentTime": 60 # 验证码多久失效/内频繁 秒单位,如60秒:
68 | # 60秒内生效,60秒内不可再次发送否则频繁
69 | },
70 | "API": { # 安装第二步GoEdgeAdmin设置的内容 nodeClusterId为注册用户默认绑定的集群id
71 | "HOST": "",
72 | "AccessKey ID": "",
73 | "AccessKey Key": "",
74 | "nodeClusterId": 1
75 | },
76 | # 以下为系统运行临时配置,不可动
77 | "Token": "",
78 | "expiresAt": 0,
79 | "adminId": 2
80 | }
81 | ```
82 | ### 宝塔安装示例
83 | > 什么是宝塔?bt.cn
84 | > 软件商店搜索 python项目管理器 进行安装
85 | > 软件商店搜索 进程守护 进行安装
86 | > 打开 python项目管理器
87 | > 添加项目
88 | > 版本管理,安装python3.7.9等待
89 | > 添加项目 框架python
90 | > 启动方式 gunicorn
91 | > 项目路径 不解释
92 | > 日志目录 不解释
93 | > 启动文件 选择项目路径下的main.py
94 | > 端口随意
95 | > 权限看你的项目文件夹权限不解释
96 | > 安装模块依赖勾上,守护进程开机启动看自己
97 | > 确定 等待
98 | > 启动完毕,关闭项目
99 | > 配置
100 | > 修改worker_class节点为 'uvicorn.workers.UvicornWorker'
101 | > 保存 运行
102 | > 产生配置文件 关闭项目
103 | > 修改配置文件
104 | > 启动项目,启动成功,若失败,请提交issues进行咨询或查看日志自行研究
--------------------------------------------------------------------------------
/Sql/__init__.py:
--------------------------------------------------------------------------------
1 | import traceback
2 |
3 | import pymysql
4 | from pymysql import cursors
5 |
6 |
7 | class Sql:
8 | def __init__(self, host, port, user, password, database):
9 | # 链接服务端
10 | try:
11 | self.connect = pymysql.connect(
12 | host=host, # MySQL服务端的IP地址
13 | port=port, # MySQL默认PORT地址(端口号)
14 | user=user, # 用户名
15 | password=password, # 密码,也可以简写为passwd
16 | database=database, # 库名称,也可以简写为db
17 | charset='utf8', # 字符编码
18 | cursorclass=cursors.DictCursor
19 | )
20 | except:
21 | self.connect = None
22 | if self.connect is None:
23 | self.cursor = None
24 | else:
25 | self.cursor = self.connect.cursor()
26 |
27 | def fj(self, args: dict):
28 | # 分解
29 | keys = ""
30 | values = ""
31 | for i in args:
32 | # 分解Key
33 | if keys == "":
34 | keys = "(`" + i + "`"
35 | else:
36 | keys = keys + ",`" + i + "`"
37 | # 分解value
38 | if values == "":
39 | values = "(" + str(args[i])
40 | else:
41 | if isinstance(args[i], int):
42 | values = values + "," + str(args[i])
43 | elif isinstance(args[i], float):
44 | values = values + "," + str(args[i])
45 | elif isinstance(args[i], str):
46 | values = values + ",'" + args[i] + "'"
47 | else:
48 | return None
49 | if keys != "":
50 | keys = keys + ")"
51 | if values != "":
52 | values = values + ")"
53 | return [keys, values]
54 |
55 | def fj_where(self, args: dict, separator: str = "and"):
56 | prepare = ""
57 | value = ""
58 | for i in args:
59 | if isinstance(args[i], int):
60 | value = str(args[i])
61 | elif isinstance(args[i], float):
62 | values = str(args[i])
63 | elif isinstance(args[i], str):
64 | value = "'" + args[i] + "'"
65 | else:
66 | return None
67 | if value == "":
68 | return None
69 | if prepare == "":
70 | prepare = "`" + i + "`" + "=" + value
71 | else:
72 | prepare = prepare + " " + separator + " `" + i + "`" + "=" + value
73 | return prepare
74 |
75 | def query(self, sql: str):
76 | try:
77 | affect_rows = self.cursor.execute(sql)
78 | res = self.cursor.fetchall() # 获取所有数据
79 | return res
80 | except:
81 | return None
82 |
83 | def execute(self, sql: str):
84 | # self.connect.query(sql)
85 | try:
86 | return self.cursor.execute(sql)
87 | except:
88 | # traceback.print_exc()
89 | return None
90 |
91 | def fetchall(self, tableName: str):
92 | sql = "select * from `{}`".format(tableName)
93 | return self.query(sql)
94 |
95 | def fetchall_where(self, tableName: str, args, separator: str = "and", additionalContent: str = None):
96 | prepare = self.fj_where(args, separator)
97 | sql = """select * from `{}` where {}""".format(tableName, prepare)
98 | if additionalContent is not None:
99 | sql = sql + " " + additionalContent
100 | return self.query(sql)
101 |
102 | def fetch_where(self, tableName: str, args, separator: str = "and", additionalContent: str = None):
103 | prepare = self.fj_where(args, separator)
104 | sql = """select * from `{}` where {}""".format(tableName, prepare)
105 | if additionalContent is not None:
106 | sql = sql + " " + additionalContent
107 | res = self.query(sql)
108 | if res is None or len(res) == 0:
109 | return None
110 | return res[0]
111 |
112 | def fetch(self, tableName: str):
113 | sql = "select * from `{}`".format(tableName)
114 | res = self.query(sql)
115 | if res is None or len(res) == 0:
116 | return None
117 | return res[0]
118 |
119 | def insert(self, tableName: str, args: dict):
120 | res = self.fj(args)
121 | keys = res[0]
122 | values = res[1]
123 | sql = """insert into `{}` {} values {}""".format(tableName, keys, values)
124 | affect_rows = self.execute(sql)
125 | if affect_rows is None:
126 | return False
127 | else:
128 | return True
129 |
130 | def delete(self, tableName: str, args: dict, separator: str = "and"):
131 | prepare = self.fj_where(args, separator)
132 | sql = """delete from `{}` where {}""".format(tableName, prepare)
133 | affect_rows = self.execute(sql)
134 | if affect_rows is None:
135 | return False
136 | else:
137 | return True
138 |
--------------------------------------------------------------------------------
/Utils/__init__.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import random
4 | import shutil
5 | import time
6 |
7 | import API
8 | import ErrCode
9 | import Sql
10 |
11 |
12 | def read_config():
13 | """"读取配置"""
14 | # 检查配置文件是否存在,不存在创建一个
15 | if not os.path.exists('./Config/Config.json'):
16 | shutil.copy('./Config/Config_initialization.json', './Config/Config.json')
17 | with open("Config/Config.json") as json_file:
18 | config = json.load(json_file)
19 | return config
20 |
21 |
22 | def update_config(config):
23 | """"更新配置"""
24 | with open("Config/Config.json", 'w') as json_file:
25 | json.dump(config, json_file, indent=4)
26 | return None
27 |
28 |
29 | def verify_token():
30 | # 查询token是否过期
31 | config = read_config()
32 | api = config['API']
33 | GoEdge_Api = API.Api(api['HOST'], api['AccessKey ID'], api['AccessKey Key'])
34 | if config['Token'] == "" or config['Token'] is None:
35 | # 生成Token
36 | token = GoEdge_Api.getToken()
37 | if token is not None:
38 | token = {
39 | "Token": token[0],
40 | "expiresAt": token[1]
41 | }
42 |
43 | else:
44 | token = {
45 | "Token": "",
46 | "expiresAt": 0
47 | }
48 | config = read_config()
49 | config.update(token)
50 | update_config(config)
51 | # 是否过期
52 | # 给两分钟宽限期
53 | if config['expiresAt'] - 120 < time.time():
54 | token = GoEdge_Api.getToken()
55 | if token is not None:
56 | token = {
57 | "Token": token[0],
58 | "expiresAt": token[1]
59 | }
60 |
61 | else:
62 | token = {
63 | "Token": "",
64 | "expiresAt": 0
65 | }
66 | config = read_config()
67 | config.update(token)
68 | update_config(config)
69 |
70 |
71 | async def init():
72 | """读取配置文件,连接数据库等初始化操作"""
73 | # 连接数据库
74 | config = read_config()
75 | mysql = config['mysql']
76 | Emysql = config['EdgeAdmin_mysql']
77 | VSql = Sql.Sql(mysql['host'], mysql['port'], mysql['user'], mysql['password'], mysql['database'])
78 | ESql = Sql.Sql(Emysql['host'], Emysql['port'], Emysql['user'], Emysql['password'], Emysql['database'])
79 | return [config, VSql, ESql]
80 |
81 |
82 | def generate_random_str(randomlength=16):
83 | """
84 | 生成一个指定长度的随机字符串
85 | """
86 | random_str = ''
87 | base_str = 'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789'
88 | length = len(base_str) - 1
89 | for i in range(randomlength):
90 | random_str += base_str[random.randint(0, length)]
91 | return random_str
92 |
93 |
94 | def message(code: int, data=None, message: str = "unknown"):
95 | """返回json,message只有400code或ErrCode没有相应的时候才有用"""
96 | if data is None:
97 | data = {}
98 | if code == 400 or code == 389:
99 | msg = message
100 | else:
101 | msg = ErrCode.ErrCode[str(code)]
102 | res = {
103 | "code": code,
104 | "data": data,
105 | "message": msg
106 | }
107 | return res
108 |
--------------------------------------------------------------------------------
/Utils/cert.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2331892928/AMEN-GoEdge-User_backEnd/2afa05f98d2263e716feb8d1e71aa7aaecfbaf0b/Utils/cert.py
--------------------------------------------------------------------------------
/Utils/tencent.py:
--------------------------------------------------------------------------------
1 | import json
2 | import random
3 | import urllib
4 | from urllib import parse
5 |
6 | import requests
7 |
8 |
9 | class Tencent:
10 | def __init__(self):
11 | pass
12 |
13 | def check_ticket(self, ticket: str, randstr: str):
14 | url = 'https://cgi.urlsec.qq.com/index.php?m=check&a=gw_check&callback=url_query&url=https%3A%2F%2Fwww.qq.com' \
15 | '%2F' + str(
16 | random.randint(
17 | 111111, 999999)) + '&ticket=' + urllib.parse.quote(ticket) + '&randstr=' + urllib.parse.quote(randstr)
18 | try:
19 | res = requests.get(url, headers={
20 | "Accept": "application/json",
21 | "Accept-Language": "zh-CN,zh;q=0.8",
22 | "Connection": "close",
23 | "referer": "https://urlsec.qq.com/check.html",
24 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
25 | "Chrome/86.0.4240.198 Safari/537.36",
26 | })
27 | # print(res.content.decode())
28 | arr = self.jsonp_decode(res.content.decode())
29 | arr = json.loads(arr)
30 | if arr['reCode'] == 0: # 验证通过
31 | return 1
32 | elif arr['reCode'] == -109: # 验证码错误
33 | return 0
34 | else: # 接口已失效
35 | return -1
36 | except: # 接口已失效
37 | return -1
38 |
39 | def jsonp_decode(self, jsonp: str):
40 | jsonp = jsonp.lstrip()
41 | jsonp = jsonp.rstrip()
42 | if jsonp[0:1] != "[" and jsonp[0:1] != "{":
43 | begin = jsonp.find("(")
44 |
45 | if begin != -1:
46 | end = jsonp.find(")")
47 | if end != -1:
48 | jsonp = jsonp[begin + 1:end]
49 | return jsonp
50 |
--------------------------------------------------------------------------------
/edge_code.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Navicat Premium Data Transfer
3 |
4 | Source Server : localhost
5 | Source Server Type : MySQL
6 | Source Server Version : 50726
7 | Source Host : localhost:3306
8 | Source Schema : goedge
9 |
10 | Target Server Type : MySQL
11 | Target Server Version : 50726
12 | File Encoding : 65001
13 |
14 | Date: 30/11/2022 19:37:04
15 | */
16 |
17 | SET NAMES utf8mb4;
18 | SET FOREIGN_KEY_CHECKS = 0;
19 |
20 | -- ----------------------------
21 | -- Table structure for edge_code
22 | -- ----------------------------
23 | DROP TABLE IF EXISTS `edge_code`;
24 | CREATE TABLE `edge_code` (
25 | `id` int(11) NOT NULL AUTO_INCREMENT,
26 | `type` int(11) NOT NULL,
27 | `number` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
28 | `code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
29 | `timeStamp` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
30 | PRIMARY KEY (`id`) USING BTREE
31 | ) ENGINE = MyISAM AUTO_INCREMENT = 52 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
32 |
33 | SET FOREIGN_KEY_CHECKS = 1;
34 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import os
2 | import shutil
3 | import sys
4 | import time
5 | from fastapi import FastAPI, Request, Depends, Cookie, HTTPException
6 | import requests
7 |
8 | import Sql
9 | import Utils
10 | import API
11 | from Controller.HTTPAccessLogService import app as HTTPAccessLogService
12 | from Controller.UserService import app as UserService
13 | from Controller.Verification import app as Verification
14 | from Controller.ConfigService import app as ConfigService
15 | from Controller.ServerService import app as ServerService
16 | from Controller.MetricStatService import app as MetricStatService
17 | from Controller.OriginService import app as OriginService
18 | from Controller.SSLCertService import app as SSLCertService
19 | from Controller.SSLPolicyService import app as SSLPolicyService
20 | from Controller.HTTPWebService import app as HTTPWebService
21 |
22 |
23 | def userInit(UserToken: str = Cookie(None),
24 | UserId: int = Cookie(None),
25 | commons: dict = Depends(Utils.init)):
26 | # 查询cookie是否过期 或 非法Token
27 | # print(UserToken)
28 | # 没有API验证是否正确,读取数据库,虽然每个接口都有输出token错误,提前做好
29 | if UserToken is None:
30 | raise HTTPException(status_code=388, detail=Utils.message(388))
31 | ESql: Sql.Sql = commons[2]
32 | if ESql is None:
33 | raise HTTPException(status_code=393, detail=Utils.message(393))
34 | userinfo_token = ESql.fetch_where("edgeAPIAccessTokens", {
35 | "token": UserToken
36 | })
37 | if userinfo_token is None:
38 | raise HTTPException(status_code=388, detail=Utils.message(388))
39 | if int(userinfo_token['expiredAt']) < time.time():
40 | # 过期了
41 | raise HTTPException(status_code=388, detail=Utils.message(388))
42 | # 查询userid是否有效
43 | if userinfo_token['userId'] != UserId:
44 | raise HTTPException(status_code=388, detail=Utils.message(388))
45 |
46 |
47 | # 添加全局依赖
48 | app = FastAPI(dependencies=[Depends(Utils.verify_token)], docs_url=None, redoc_url=None)
49 | # app.mount()
50 | # 挂载
51 |
52 | app.include_router(HTTPAccessLogService)
53 | app.include_router(UserService)
54 | app.include_router(Verification)
55 | app.include_router(ConfigService)
56 | app.include_router(ServerService, dependencies=[Depends(userInit)])
57 | app.include_router(OriginService, dependencies=[Depends(userInit)])
58 | app.include_router(SSLCertService, dependencies=[Depends(userInit)])
59 | app.include_router(SSLPolicyService, dependencies=[Depends(userInit)])
60 | app.include_router(HTTPWebService, dependencies=[Depends(userInit)])
61 | app.include_router(MetricStatService)
62 |
63 |
64 | @app.on_event('startup')
65 | def init_data():
66 | # 检查配置文件是否存在,不存在创建一个
67 | if not os.path.exists('./Config/Config.json'):
68 | shutil.copy('./Config/Config_initialization.json', './Config/Config.json')
69 | # 查询adminId,根据acceskeyid 和key查找
70 | config = Utils.read_config()
71 | mysql = config['mysql']
72 | API_Config = config['API']
73 | Emysql = config['EdgeAdmin_mysql']
74 | ESql = Sql.Sql(Emysql['host'], Emysql['port'], Emysql['user'], Emysql['password'], Emysql['database'])
75 | user_info = ESql.fetch_where("edgeUserAccessKeys", {
76 | "uniqueId": API_Config['AccessKey ID'],
77 | "secret": API_Config['AccessKey Key'],
78 | "state": 1
79 | })
80 | if user_info is None:
81 | raise "id 和 key错误"
82 | else:
83 | # 写入adminId
84 | update = {
85 | "adminId": user_info["adminId"]
86 | }
87 | config.update(update)
88 | Utils.update_config(config)
89 | print("AMEN-GoEdge-User后端启动完毕!")
90 |
91 |
92 | @app.on_event('shutdown')
93 | def shutdown():
94 | print("shutdown")
95 |
96 |
97 | if __name__ == "__main__":
98 | pass
99 | #import uvicorn
100 |
101 | #uvicorn.run(app='main:app', host="0.0.0.0", port=8002, reload=True, debug=True)
102 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | traceback
2 | json
3 | requests
4 | base64
5 | hashlib
6 | pyOpenSSL
7 | smtplib
8 | pymysql
9 | urllib
10 | random
11 | time
12 | fastapi
13 | uvicorn
--------------------------------------------------------------------------------
/test_main.http:
--------------------------------------------------------------------------------
1 | # Test your FastAPI endpoints
2 |
3 | GET http://127.0.0.1:8000/
4 | Accept: application/json
5 |
6 | ###
7 |
8 | GET http://127.0.0.1:8000/hello/User
9 | Accept: application/json
10 |
11 | ###
12 |
--------------------------------------------------------------------------------