mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-13 17:24:44 +08:00
feat: 增加手动域名解析
This commit is contained in:
parent
3ccac92df6
commit
bd082d4e08
@ -38,9 +38,10 @@ type WebsiteDNSReq struct {
|
||||
}
|
||||
|
||||
type WebsiteDNSRes struct {
|
||||
Key string `json:"resolve"`
|
||||
Value string `json:"value"`
|
||||
Type string `json:"type"`
|
||||
Key string `json:"resolve"`
|
||||
Value string `json:"value"`
|
||||
Domain string `json:"domain"`
|
||||
Err string `json:"err"`
|
||||
}
|
||||
|
||||
type WebsiteSSLRenew struct {
|
||||
|
@ -168,24 +168,29 @@ func (w WebSiteSSLService) Renew(sslId uint) error {
|
||||
return websiteSSLRepo.Save(websiteSSL)
|
||||
}
|
||||
|
||||
func (w WebSiteSSLService) GetDNSResolve(req dto.WebsiteDNSReq) (dto.WebsiteDNSRes, error) {
|
||||
func (w WebSiteSSLService) GetDNSResolve(req dto.WebsiteDNSReq) ([]dto.WebsiteDNSRes, error) {
|
||||
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(req.AcmeAccountID))
|
||||
if err != nil {
|
||||
return dto.WebsiteDNSRes{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := ssl.NewPrivateKeyClient(acmeAccount.Email, acmeAccount.PrivateKey)
|
||||
if err != nil {
|
||||
return dto.WebsiteDNSRes{}, err
|
||||
return nil, err
|
||||
}
|
||||
re, err := client.UseManualDns(req.Domains)
|
||||
resolves, err := client.GetDNSResolve(req.Domains)
|
||||
if err != nil {
|
||||
return dto.WebsiteDNSRes{}, err
|
||||
return nil, err
|
||||
}
|
||||
var res []dto.WebsiteDNSRes
|
||||
for k, v := range resolves {
|
||||
res = append(res, dto.WebsiteDNSRes{
|
||||
Domain: k,
|
||||
Key: v.Key,
|
||||
Value: v.Value,
|
||||
Err: v.Err,
|
||||
})
|
||||
}
|
||||
var res dto.WebsiteDNSRes
|
||||
res.Key = re.Key
|
||||
res.Value = re.Value
|
||||
res.Type = "TXT"
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
@ -1,27 +1,27 @@
|
||||
-----BEGIN privateKey-----
|
||||
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
|
||||
-----END privateKey-----
|
||||
|
@ -3,6 +3,8 @@ package ssl
|
||||
import (
|
||||
"crypto"
|
||||
"encoding/json"
|
||||
"github.com/go-acme/lego/v4/acme"
|
||||
"github.com/go-acme/lego/v4/acme/api"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
@ -166,6 +168,7 @@ func (c *AcmeClient) RenewSSL(certUrl string) (certificate.Resource, error) {
|
||||
type Resolve struct {
|
||||
Key string
|
||||
Value string
|
||||
Err string
|
||||
}
|
||||
|
||||
type manualDnsProvider struct {
|
||||
@ -173,11 +176,6 @@ type manualDnsProvider struct {
|
||||
}
|
||||
|
||||
func (p *manualDnsProvider) Present(domain, token, keyAuth string) error {
|
||||
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||
p.Resolve = &Resolve{
|
||||
Key: fqdn,
|
||||
Value: value,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -185,6 +183,60 @@ func (p *manualDnsProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *AcmeClient) GetDNSResolve() {
|
||||
func (c *AcmeClient) GetDNSResolve(domains []string) (map[string]Resolve, error) {
|
||||
core, err := api.New(c.Config.HTTPClient, c.Config.UserAgent, c.Config.CADirURL, c.User.Registration.URI, c.User.Key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
order, err := core.Orders.New(domains)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resolves := make(map[string]Resolve)
|
||||
resc, errc := make(chan acme.Authorization), make(chan domainError)
|
||||
for _, authzURL := range order.Authorizations {
|
||||
|
||||
go func(authzURL string) {
|
||||
authz, err := core.Authorizations.Get(authzURL)
|
||||
if err != nil {
|
||||
errc <- domainError{Domain: authz.Identifier.Value, Error: err}
|
||||
return
|
||||
}
|
||||
resc <- authz
|
||||
}(authzURL)
|
||||
|
||||
}
|
||||
|
||||
var responses []acme.Authorization
|
||||
for i := 0; i < len(order.Authorizations); i++ {
|
||||
select {
|
||||
case res := <-resc:
|
||||
responses = append(responses, res)
|
||||
case err := <-errc:
|
||||
resolves[err.Domain] = Resolve{Err: err.Error.Error()}
|
||||
}
|
||||
}
|
||||
close(resc)
|
||||
close(errc)
|
||||
|
||||
for _, auth := range responses {
|
||||
domain := challenge.GetTargetedDomain(auth)
|
||||
chlng, err := challenge.FindChallenge(challenge.DNS01, auth)
|
||||
if err != nil {
|
||||
resolves[domain] = Resolve{Err: err.Error()}
|
||||
continue
|
||||
}
|
||||
keyAuth, err := core.GetKeyAuthorization(chlng.Token)
|
||||
if err != nil {
|
||||
resolves[domain] = Resolve{Err: err.Error()}
|
||||
continue
|
||||
}
|
||||
fqdn, value := dns01.GetRecord(domain, keyAuth)
|
||||
resolves[domain] = Resolve{
|
||||
Key: fqdn,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
return resolves, nil
|
||||
}
|
||||
|
29
backend/utils/ssl/obtain_err.go
Normal file
29
backend/utils/ssl/obtain_err.go
Normal file
@ -0,0 +1,29 @@
|
||||
package ssl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type obtainError map[string]error
|
||||
|
||||
func (e obtainError) Error() string {
|
||||
buffer := bytes.NewBufferString("error: one or more domains had a problem:\n")
|
||||
|
||||
var domains []string
|
||||
for domain := range e {
|
||||
domains = append(domains, domain)
|
||||
}
|
||||
sort.Strings(domains)
|
||||
|
||||
for _, domain := range domains {
|
||||
buffer.WriteString(fmt.Sprintf("[%s] %s\n", domain, e[domain]))
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
type domainError struct {
|
||||
Domain string
|
||||
Error error
|
||||
}
|
@ -160,9 +160,10 @@ export namespace WebSite {
|
||||
}
|
||||
|
||||
export interface DNSResolve {
|
||||
key: string;
|
||||
resolve: string;
|
||||
value: string;
|
||||
type: string;
|
||||
domain: string;
|
||||
err: string;
|
||||
}
|
||||
|
||||
export interface SSLReq {
|
||||
|
@ -120,7 +120,7 @@ export const RenewSSL = (req: WebSite.SSLRenew) => {
|
||||
};
|
||||
|
||||
export const GetDnsResolve = (req: WebSite.DNSResolveReq) => {
|
||||
return http.post<WebSite.DNSResolve>(`/websites/ssl/resolve`, req);
|
||||
return http.post<WebSite.DNSResolve[]>(`/websites/ssl/resolve`, req);
|
||||
};
|
||||
|
||||
export const GetHTTPSConfig = (id: number) => {
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<el-dialog v-model="open" :title="$t('commons.button.create')" width="30%" :before-close="handleClose">
|
||||
<el-dialog v-model="open" :title="$t('commons.button.create')" width="60%" :before-close="handleClose">
|
||||
<el-form
|
||||
ref="sslForm"
|
||||
label-position="right"
|
||||
:model="ssl"
|
||||
label-width="125px"
|
||||
label-width="100px"
|
||||
:rules="rules"
|
||||
v-loading="loading"
|
||||
>
|
||||
@ -41,18 +41,21 @@
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item :label="$t('website.domain')" prop="domains">
|
||||
<el-checkbox-group v-model="ssl.domains">
|
||||
<el-checkbox v-for="domain in domains" :key="domain.domain" :label="domain.domain"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item> -->
|
||||
<!-- <el-form-item>
|
||||
<div>
|
||||
<span>解析域名: {{ dnsResolve.key }}</span>
|
||||
<span>记录值: {{ dnsResolve.value }}</span>
|
||||
<span>类型: {{ dnsResolve.type }}</span>
|
||||
<el-form-item v-if="dnsResolve.length > 0">
|
||||
<div v-for="(re, index) in dnsResolve" :key="index">
|
||||
<el-descriptions direction="vertical" :column="4" border>
|
||||
<el-descriptions-item label="域名">{{ re.domain }}</el-descriptions-item>
|
||||
<div v-if="re.err != ''">
|
||||
<el-descriptions-item label="错误">{{ re.err }}</el-descriptions-item>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-descriptions-item label="解析域名">{{ re.resolve }}</el-descriptions-item>
|
||||
<el-descriptions-item label="记录值">{{ re.value }}</el-descriptions-item>
|
||||
<el-descriptions-item label="类型">TXT</el-descriptions-item>
|
||||
</div>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-form-item> -->
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
@ -67,7 +70,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { WebSite } from '@/api/interface/website';
|
||||
import { CreateSSL, SearchAcmeAccount, SearchDnsAccount } from '@/api/modules/website';
|
||||
import { CreateSSL, GetDnsResolve, SearchAcmeAccount, SearchDnsAccount } from '@/api/modules/website';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
@ -112,11 +115,7 @@ let ssl = ref({
|
||||
acmeAccountId: 0,
|
||||
dnsAccountId: 0,
|
||||
});
|
||||
// let dnsResolve = ref<WebSite.DNSResolve>({
|
||||
// key: '',
|
||||
// value: '',
|
||||
// type: '',
|
||||
// });
|
||||
let dnsResolve = ref<WebSite.DNSResolve[]>([]);
|
||||
let hasResolve = ref(false);
|
||||
|
||||
const em = defineEmits(['close']);
|
||||
@ -166,14 +165,16 @@ const getDnsAccounts = async () => {
|
||||
// domains.value = (await GetWebsite(id)).data.domains || [];
|
||||
// };
|
||||
|
||||
// const getDnsResolve = async (acmeAccountId: number, domains: string[]) => {
|
||||
// hasResolve.value = false;
|
||||
// const res = await GetDnsResolve({ acmeAccountId: acmeAccountId, domains: domains });
|
||||
// if (res.data) {
|
||||
// dnsResolve.value = res.data;
|
||||
// hasResolve.value = true;
|
||||
// }
|
||||
// };
|
||||
const getDnsResolve = async (acmeAccountId: number, domains: string[]) => {
|
||||
hasResolve.value = false;
|
||||
loading.value = true;
|
||||
const res = await GetDnsResolve({ acmeAccountId: acmeAccountId, domains: domains });
|
||||
if (res.data) {
|
||||
dnsResolve.value = res.data;
|
||||
hasResolve.value = true;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
@ -192,7 +193,12 @@ const submit = async (formEl: FormInstance | undefined) => {
|
||||
loading.value = false;
|
||||
});
|
||||
} else {
|
||||
// getDnsResolve(ssl.value.acmeAccountId, ssl.value.domains);
|
||||
let domains = [ssl.value.primaryDomain];
|
||||
if (ssl.value.otherDomains != '') {
|
||||
let otherDomains = ssl.value.otherDomains.split('\n');
|
||||
domains = domains.concat(otherDomains);
|
||||
}
|
||||
getDnsResolve(ssl.value.acmeAccountId, domains);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user