|
@@ -10,13 +10,14 @@ import (
|
|
|
"github.com/spf13/viper"
|
|
|
"io"
|
|
|
"net/http"
|
|
|
- "strings"
|
|
|
+ "net/url"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
type AoDunService interface {
|
|
|
- AddDomainWhiteList(ctx context.Context, req []string) error
|
|
|
- DelDomainWhiteList(ctx context.Context, req []string) error
|
|
|
+ DomainWhiteList(ctx context.Context, domain string, ip string, apiType string) error
|
|
|
+ AddWhiteStaticList(ctx context.Context, req []v1.IpInfo) error
|
|
|
+ DelWhiteStaticList(ctx context.Context, req v1.DeleteIp) error
|
|
|
}
|
|
|
func NewAoDunService(
|
|
|
service *Service,
|
|
@@ -29,6 +30,9 @@ func NewAoDunService(
|
|
|
clientID: conf.GetString("aodun.clientID"),
|
|
|
username: conf.GetString("aodun.username"),
|
|
|
password: conf.GetString("aodun.password"),
|
|
|
+ domainUserName: conf.GetString("domainWhite.username"),
|
|
|
+ domainPassword: conf.GetString("domainWhite.password"),
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -38,12 +42,10 @@ type aoDunService struct {
|
|
|
clientID string
|
|
|
username string
|
|
|
password string
|
|
|
+ domainUserName string
|
|
|
+ domainPassword string
|
|
|
}
|
|
|
|
|
|
-func (s *aoDunService) DeleteDomainWhiteList(ctx context.Context, req []string) error {
|
|
|
- //TODO implement me
|
|
|
- panic("implement me")
|
|
|
-}
|
|
|
|
|
|
func (s *aoDunService) sendFormData(ctx context.Context,apiUrl string,tokenType string,token string,formData map[string]interface{}) ([]byte,error) {
|
|
|
URL := s.Url + apiUrl
|
|
@@ -87,6 +89,54 @@ func (s *aoDunService) sendFormData(ctx context.Context,apiUrl string,tokenType
|
|
|
}
|
|
|
|
|
|
|
|
|
+func (s *aoDunService) sendDomainFormData(ctx context.Context,domain string,ip string,apiType string) ([]byte,error) {
|
|
|
+ var URL string
|
|
|
+ if apiType == "add" {
|
|
|
+ URL = "http://zapi.zzybgp.com/api/user/do_main"
|
|
|
+ } else {
|
|
|
+ URL = "http://zapi.zzybgp.com/api/user/do_main/delete"
|
|
|
+ }
|
|
|
+ formData := url.Values{}
|
|
|
+ formData.Set("username", s.domainUserName)
|
|
|
+ formData.Set("password", s.domainPassword)
|
|
|
+ formData.Add("do_main_list[name][]", domain)
|
|
|
+ formData.Add("do_main_list[ip][]", ip)
|
|
|
+ encodedData := formData.Encode()
|
|
|
+
|
|
|
+ req, err := http.NewRequest("POST", URL, bytes.NewBuffer([]byte(encodedData)))
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("创建 HTTP 请求失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置请求头 Content-Type 为 "application/x-www-form-urlencoded"
|
|
|
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
+
|
|
|
+
|
|
|
+ tr := &http.Transport{
|
|
|
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // <--- 关键修改:忽略 SSL 验证
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 使用 HTTP 客户端发送请求
|
|
|
+ client := &http.Client{
|
|
|
+ Transport: tr,
|
|
|
+ Timeout: 15 * time.Second, // 设置一个合理的超时时间,例如15秒
|
|
|
+ }
|
|
|
+ resp, err := client.Do(req)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("发送 HTTP 请求失败: %w", err)
|
|
|
+ }
|
|
|
+ // defer 确保在函数返回前关闭响应体,防止资源泄露
|
|
|
+ defer resp.Body.Close()
|
|
|
+
|
|
|
+ // 6. 读取响应体内容
|
|
|
+ body, err := io.ReadAll(resp.Body)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("读取响应体失败: %w", err)
|
|
|
+ }
|
|
|
+ return body, nil
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
func (s *aoDunService) GetToken(ctx context.Context) (string,string,error) {
|
|
|
|
|
|
formData := map[string]interface{}{
|
|
@@ -151,110 +201,77 @@ func (s *aoDunService) AddWhiteStaticList(ctx context.Context,req []v1.IpInfo) e
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-//func (s *aoDunService) GetWhiteStaticList(ctx context.Context,ip string) (int,error) {
|
|
|
-// tokenType,token, err := s.GetToken(ctx)
|
|
|
-// if err != nil {
|
|
|
-// return 0, err
|
|
|
-// }
|
|
|
-//
|
|
|
-// formData := map[string]interface{}{
|
|
|
-// "action" : "get",
|
|
|
-// "bwflag" : "white",
|
|
|
-// "page" : 1,
|
|
|
-// "ids": ip,
|
|
|
-// }
|
|
|
-//
|
|
|
-// resBody, err := s.sendFormData(ctx,"/v1.0/firewall/static_bw_list",tokenType,token,formData)
|
|
|
-// if err != nil {
|
|
|
-// return nil, err
|
|
|
-// }
|
|
|
-// // 7. 将响应体 JSON 数据反序列化到 ResponsePayload 结构体
|
|
|
-// var res IpResponse // 使用我们定义的 IpResponse 结构体
|
|
|
-// if err := json.Unmarshal(resBody, &res); err != nil {
|
|
|
-// // 如果反序列化失败,说明响应格式不符合预期
|
|
|
-// return 0, fmt.Errorf("反序列化响应 JSON 失败 (内容: %s): %w", string(resBody), err)
|
|
|
-// }
|
|
|
-//
|
|
|
-// // 2. 检查 API 返回的 code,这是处理业务失败的关键
|
|
|
-// if res.Code != 0 {
|
|
|
-// // API 返回了错误码,例如 IP 不存在、参数错误等
|
|
|
-// return 0, fmt.Errorf("API 错误: code %d, msg '%s'", res.Code, res.Msg)
|
|
|
-// }
|
|
|
-//
|
|
|
-// // 3. 检查 data 数组是否为空
|
|
|
-// // 即使 code 为 0,也可能因为没有匹配的数据而返回一个空数组
|
|
|
-// if len(res.Data) == 0 {
|
|
|
-// return 0, fmt.Errorf("API 调用成功,但未找到与 IP '%s' 相关的记录", ip)
|
|
|
-// }
|
|
|
-//
|
|
|
-// // 4. 获取 ID 并返回
|
|
|
-// // 假设我们总是取返回结果中的第一个元素的 ID
|
|
|
-// id := res.Data[0].ID
|
|
|
-// return id, nil // 成功!返回获取到的 id 和 nil 错误
|
|
|
-//}
|
|
|
-
|
|
|
-func (s *aoDunService) DelWhiteStaticList(ctx context.Context, req v1.DeleteIp) error {
|
|
|
- tokenType, token, err := s.GetToken(ctx)
|
|
|
+func (s *aoDunService) GetWhiteStaticList(ctx context.Context,ip string) (int,error) {
|
|
|
+ tokenType,token, err := s.GetToken(ctx)
|
|
|
if err != nil {
|
|
|
- return err
|
|
|
+ return 0, err
|
|
|
}
|
|
|
|
|
|
formData := map[string]interface{}{
|
|
|
- "action": "del",
|
|
|
- "bwflag": "white",
|
|
|
- "flag": 0,
|
|
|
- "ids": req.Ids,
|
|
|
+ "action" : "get",
|
|
|
+ "bwflag" : "white",
|
|
|
+ "page" : 1,
|
|
|
+ "ids": ip,
|
|
|
}
|
|
|
|
|
|
- resBody, err := s.sendFormData(ctx, "/v1.0/firewall/static_bw_list", tokenType, token, formData)
|
|
|
+ resBody, err := s.sendFormData(ctx,"/v1.0/firewall/static_bw_list",tokenType,token,formData)
|
|
|
if err != nil {
|
|
|
- return err
|
|
|
+ return 0, err
|
|
|
}
|
|
|
- var res v1.IpResponse
|
|
|
+ // 7. 将响应体 JSON 数据反序列化到 ResponsePayload 结构体
|
|
|
+ var res v1.IpGetResponse // 使用我们定义的 IpResponse 结构体
|
|
|
if err := json.Unmarshal(resBody, &res); err != nil {
|
|
|
- return fmt.Errorf("反序列化响应 JSON 失败 ( 内容: %s): %w", string(resBody), err)
|
|
|
+ // 如果反序列化失败,说明响应格式不符合预期
|
|
|
+ return 0, fmt.Errorf("反序列化响应 JSON 失败 (内容: %s): %w", string(resBody), err)
|
|
|
}
|
|
|
+
|
|
|
+ // 2. 检查 API 返回的 code,这是处理业务失败的关键
|
|
|
if res.Code != 0 {
|
|
|
- return fmt.Errorf("API 错误: code %d, msg '%s'", res.Code, res.Msg)
|
|
|
+ // API 返回了错误码,例如 IP 不存在、参数错误等
|
|
|
+ return 0, fmt.Errorf("API 错误: code %d, msg '%s'", res.Code, res.Msg)
|
|
|
}
|
|
|
- return nil
|
|
|
+
|
|
|
+ // 3. 检查 data 数组是否为空
|
|
|
+ // 即使 code 为 0,也可能因为没有匹配的数据而返回一个空数组
|
|
|
+ if len(res.Data) == 0 {
|
|
|
+ return 0, fmt.Errorf("API 调用成功,但未找到与 IP '%s' 相关的记录", ip)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 获取 ID 并返回
|
|
|
+ // 假设我们总是取返回结果中的第一个元素的 ID
|
|
|
+ id := res.Data[0].ID
|
|
|
+ return id, nil // 成功!返回获取到的 id 和 nil 错误
|
|
|
}
|
|
|
|
|
|
-func (s *aoDunService) AddDomainWhiteList(ctx context.Context, req []string) error {
|
|
|
+func (s *aoDunService) DelWhiteStaticList(ctx context.Context, req v1.DeleteIp) error {
|
|
|
tokenType, token, err := s.GetToken(ctx)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
+
|
|
|
formData := map[string]interface{}{
|
|
|
- "domain": req,
|
|
|
+ "action": "del",
|
|
|
+ "bwflag": "white",
|
|
|
+ "flag": 0,
|
|
|
+ "ids": req.Ids,
|
|
|
}
|
|
|
- resBody, err := s.sendFormData(ctx, "/v1.0/firewall/addDomainWhiteList", tokenType, token, formData)
|
|
|
+
|
|
|
+ resBody, err := s.sendFormData(ctx, "/v1.0/firewall/static_bw_list", tokenType, token, formData)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- var res v1.DomainResponse
|
|
|
+ var res v1.IpResponse
|
|
|
if err := json.Unmarshal(resBody, &res); err != nil {
|
|
|
return fmt.Errorf("反序列化响应 JSON 失败 ( 内容: %s): %w", string(resBody), err)
|
|
|
}
|
|
|
if res.Code != 0 {
|
|
|
- if strings.Contains(string(res.Msg), "重复列表") {
|
|
|
- return nil
|
|
|
- }
|
|
|
return fmt.Errorf("API 错误: code %d, msg '%s'", res.Code, res.Msg)
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-func (s *aoDunService) DelDomainWhiteList(ctx context.Context, req []string) error {
|
|
|
- tokenType, token, err := s.GetToken(ctx)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- formData := map[string]interface{}{
|
|
|
- "type": 1,
|
|
|
- "domain": req,
|
|
|
- }
|
|
|
- resBody, err := s.sendFormData(ctx, "/v1.0/firewall/delDomainWhiteList", tokenType, token, formData)
|
|
|
+func (s *aoDunService) DomainWhiteList(ctx context.Context, domain string, ip string, apiType string) error {
|
|
|
+ resBody, err := s.sendDomainFormData(ctx,domain,ip,apiType)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
@@ -262,10 +279,10 @@ func (s *aoDunService) DelDomainWhiteList(ctx context.Context, req []string) err
|
|
|
if err := json.Unmarshal(resBody, &res); err != nil {
|
|
|
return fmt.Errorf("反序列化响应 JSON 失败 ( 内容: %s): %w", string(resBody), err)
|
|
|
}
|
|
|
- if res.Code != 0 {
|
|
|
- if strings.Contains(string(res.Msg), "重复列表") {
|
|
|
- return nil
|
|
|
- }
|
|
|
+ if res.Code != 200 && apiType == "add" {
|
|
|
+ return fmt.Errorf("API 错误: code %d, msg '%s'", res.Code, res.Msg)
|
|
|
+ }
|
|
|
+ if res.Code != 600 && apiType == "del" {
|
|
|
return fmt.Errorf("API 错误: code %d, msg '%s'", res.Code, res.Msg)
|
|
|
}
|
|
|
return nil
|