This commit is contained in:
parent
62ed09f765
commit
87cd28f30c
@ -11,6 +11,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -26,6 +27,13 @@ type aliDNSRecord struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
type aliDNSListedRecord struct {
|
||||
ID string `json:"RecordId"`
|
||||
Name string `json:"RR"`
|
||||
Type string `json:"Type"`
|
||||
Value string `json:"Value"`
|
||||
}
|
||||
|
||||
// 每次签发独立记录创建结果,清理时只删除本实例创建且内容未被修改的记录。
|
||||
type aliDNSChallenge struct {
|
||||
mu sync.Mutex
|
||||
@ -121,17 +129,11 @@ func (provider *aliDNSChallenge) CleanUp(domain, token, keyAuth string) error {
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
var current struct {
|
||||
RecordID string `json:"RecordId"`
|
||||
Domain string `json:"DomainName"`
|
||||
Name string `json:"RR"`
|
||||
Type string `json:"Type"`
|
||||
Value string `json:"Value"`
|
||||
}
|
||||
if err := provider.call("DescribeDomainRecordInfo", url.Values{"RecordId": {created.ID}}, ¤t); err != nil {
|
||||
current, err := provider.findCreatedRecord(created)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if current.RecordID != created.ID || current.Domain != provider.zone || current.Name != created.Name || current.Type != "TXT" || current.Value != created.Value {
|
||||
if current.ID != created.ID || current.Name != created.Name || current.Type != "TXT" || current.Value != created.Value {
|
||||
return errors.New("DNS 挑战记录已被修改,保留记录并停止自动清理")
|
||||
}
|
||||
if err := provider.call("DeleteDomainRecord", url.Values{"RecordId": {created.ID}}, nil); err != nil {
|
||||
@ -141,6 +143,34 @@ func (provider *aliDNSChallenge) CleanUp(domain, token, keyAuth string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 使用指定托管区域的记录列表复核,不要求额外的跨区域单记录查询权限。
|
||||
func (provider *aliDNSChallenge) findCreatedRecord(created aliDNSRecord) (aliDNSListedRecord, error) {
|
||||
const pageSize = 500
|
||||
for page := 1; page <= 20; page++ {
|
||||
var response struct {
|
||||
Total int `json:"TotalCount"`
|
||||
Records struct {
|
||||
Record []aliDNSListedRecord `json:"Record"`
|
||||
} `json:"DomainRecords"`
|
||||
}
|
||||
if err := provider.call("DescribeDomainRecords", url.Values{
|
||||
"DomainName": {provider.zone}, "RRKeyWord": {created.Name}, "Type": {"TXT"},
|
||||
"PageSize": {strconv.Itoa(pageSize)}, "PageNumber": {strconv.Itoa(page)},
|
||||
}, &response); err != nil {
|
||||
return aliDNSListedRecord{}, err
|
||||
}
|
||||
for _, record := range response.Records.Record {
|
||||
if record.ID == created.ID {
|
||||
return record, nil
|
||||
}
|
||||
}
|
||||
if page*pageSize >= response.Total || len(response.Records.Record) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return aliDNSListedRecord{}, errors.New("无法核对本次 DNS 挑战记录,已停止自动清理")
|
||||
}
|
||||
|
||||
func aliDNSPercentEncode(value string) string {
|
||||
return strings.ReplaceAll(url.QueryEscape(value), "+", "%20")
|
||||
}
|
||||
|
||||
@ -33,12 +33,18 @@ func TestAutomaticDNSCleansOnlyOwnedUnchangedRecords(t *testing.T) {
|
||||
id = fmt.Sprint(adds)
|
||||
records[id] = aliDNSRecord{ID: id, Name: r.Form.Get("RR"), Value: r.Form.Get("Value")}
|
||||
_ = json.NewEncoder(w).Encode(map[string]string{"RecordId": id})
|
||||
case "DescribeDomainRecordInfo":
|
||||
record := records[id]
|
||||
if tamper {
|
||||
record.Value = "changed-by-user"
|
||||
case "DescribeDomainRecords":
|
||||
if r.Form.Get("DomainName") != "example.com" || r.Form.Get("Type") != "TXT" || r.Form.Get("PageNumber") == "" {
|
||||
t.Error("record lookup must be scoped to the configured zone")
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]string{"RecordId": id, "DomainName": "example.com", "RR": record.Name, "Type": "TXT", "Value": record.Value})
|
||||
listed := make([]aliDNSListedRecord, 0, len(records))
|
||||
for _, record := range records {
|
||||
if tamper {
|
||||
record.Value = "changed-by-user"
|
||||
}
|
||||
listed = append(listed, aliDNSListedRecord{ID: record.ID, Name: record.Name, Type: "TXT", Value: record.Value})
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"TotalCount": len(listed), "DomainRecords": map[string]any{"Record": listed}})
|
||||
case "DeleteDomainRecord":
|
||||
if failDelete {
|
||||
w.WriteHeader(503)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user