mirror of
https://gitee.com/mirrors/AllinSSL.git
synced 2026-03-08 15:51:11 +08:00
Add files via upload
This commit is contained in:
94
backend/internal/cert/apply/account.go
Normal file
94
backend/internal/cert/apply/account.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/public"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MyUser struct {
|
||||
Email string
|
||||
Registration *registration.Resource
|
||||
key crypto.PrivateKey
|
||||
}
|
||||
|
||||
func (u *MyUser) GetEmail() string {
|
||||
return u.Email
|
||||
}
|
||||
|
||||
func (u *MyUser) GetRegistration() *registration.Resource {
|
||||
return u.Registration
|
||||
}
|
||||
|
||||
func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
|
||||
return u.key
|
||||
}
|
||||
|
||||
func SaveUserToDB(db *public.Sqlite, user *MyUser) error {
|
||||
keyBytes, err := x509.MarshalPKCS8PrivateKey(user.key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
regBytes := []byte("")
|
||||
if user.Registration != nil {
|
||||
regBytes, err = json.Marshal(user.Registration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pemBytes := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: keyBytes,
|
||||
})
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
_, err = db.Insert(map[string]interface{}{
|
||||
"email": user.Email,
|
||||
"private_key": string(pemBytes),
|
||||
"reg": regBytes,
|
||||
"create_time": now,
|
||||
"update_time": now,
|
||||
"type": "Let's Encrypt",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func LoadUserFromDB(db *public.Sqlite, email string) (*MyUser, error) {
|
||||
data, err := db.Where(`email=?`, []interface{}{email}).Select()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
regStr, ok := data[0]["reg"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid reg data")
|
||||
}
|
||||
regBytes := []byte(regStr)
|
||||
privPEM, ok := data[0]["private_key"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid private key data")
|
||||
}
|
||||
privateKey, err := public.ParsePrivateKey([]byte(privPEM))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var reg *registration.Resource
|
||||
if len(regBytes) > 0 {
|
||||
reg = ®istration.Resource{}
|
||||
if err := json.Unmarshal(regBytes, reg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &MyUser{
|
||||
Email: email,
|
||||
key: privateKey,
|
||||
Registration: reg,
|
||||
}, nil
|
||||
}
|
||||
245
backend/internal/cert/apply/apply.go
Normal file
245
backend/internal/cert/apply/apply.go
Normal file
@@ -0,0 +1,245 @@
|
||||
package apply
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/access"
|
||||
"ALLinSSL/backend/internal/cert"
|
||||
"ALLinSSL/backend/public"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
"github.com/go-acme/lego/v4/providers/dns/alidns"
|
||||
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetSqlite() (*public.Sqlite, error) {
|
||||
s, err := public.NewSqlite("data/data.db", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Connect()
|
||||
s.TableName = "_accounts"
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func GetDNSProvider(providerName string, creds map[string]string) (challenge.Provider, error) {
|
||||
switch providerName {
|
||||
case "tencentcloud":
|
||||
config := tencentcloud.NewDefaultConfig()
|
||||
config.SecretID = creds["secret_id"]
|
||||
config.SecretKey = creds["secret_key"]
|
||||
return tencentcloud.NewDNSProviderConfig(config)
|
||||
|
||||
// case "cloudflare":
|
||||
// config := cloudflare.NewDefaultConfig()
|
||||
// config.AuthToken = creds["CLOUDFLARE_API_TOKEN"]
|
||||
// return cloudflare.NewDNSProviderConfig(config)
|
||||
|
||||
case "aliyun":
|
||||
config := alidns.NewDefaultConfig()
|
||||
config.APIKey = creds["access_key"]
|
||||
config.SecretKey = creds["access_secret"]
|
||||
return alidns.NewDNSProviderConfig(config)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("不支持的 DNS Provider: %s", providerName)
|
||||
}
|
||||
}
|
||||
|
||||
func Apply(cfg map[string]any, logger *public.Logger) (map[string]any, error) {
|
||||
db, err := GetSqlite()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
email, ok := cfg["email"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("参数错误:email")
|
||||
}
|
||||
domains, ok := cfg["domains"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("参数错误:domains")
|
||||
}
|
||||
providerStr, ok := cfg["provider"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("参数错误:provider")
|
||||
}
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return nil, fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
|
||||
// 获取上次申请的证书
|
||||
runId, ok := cfg["_runId"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("参数错误:_runId")
|
||||
}
|
||||
if runId != "" {
|
||||
s, err := public.NewSqlite("data/data.db", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Connect()
|
||||
s.TableName = "workflow_history"
|
||||
defer s.Close()
|
||||
// 查询 workflowId
|
||||
wh, err := s.Where("id=?", []interface{}{runId}).Select()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(wh) > 0 {
|
||||
s.TableName = "cert"
|
||||
certs, err := s.Where("workflow_id=?", []interface{}{wh[0]["workflow_id"]}).Select()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(certs) > 0 {
|
||||
layout := "2006-01-02 15:04:05"
|
||||
var maxDays float64
|
||||
var maxItem map[string]any
|
||||
for i := range certs {
|
||||
endTimeStr, ok := certs[i]["end_time"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
endTime, _ := time.Parse(layout, endTimeStr)
|
||||
diff := endTime.Sub(time.Now()).Hours() / 24
|
||||
if diff > maxDays {
|
||||
maxDays = diff
|
||||
maxItem = certs[i]
|
||||
}
|
||||
}
|
||||
certObj := maxItem
|
||||
// 判断证书是否过期
|
||||
cfgEnd, ok := cfg["end_day"].(int)
|
||||
if !ok || cfgEnd <= 0 {
|
||||
cfgEnd = 30
|
||||
}
|
||||
|
||||
if int(maxDays) > cfgEnd {
|
||||
// 证书未过期,直接返回
|
||||
logger.Debug(fmt.Sprintf("上次证书申请成功,剩余天数:%d 大于%d天,已跳过申请复用此证书", int(maxDays), cfgEnd))
|
||||
return map[string]any{
|
||||
"cert": certObj["cert"],
|
||||
"key": certObj["key"],
|
||||
"issuerCert": certObj["issuer_cert"],
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Debug("正在申请证书,域名: " + domains)
|
||||
|
||||
user, err := LoadUserFromDB(db, email)
|
||||
if err != nil {
|
||||
logger.Debug("acme账号不存在,注册新账号")
|
||||
privateKey, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
user = &MyUser{
|
||||
Email: email,
|
||||
key: privateKey,
|
||||
}
|
||||
|
||||
config := lego.NewConfig(user)
|
||||
config.Certificate.KeyType = certcrypto.EC384
|
||||
|
||||
client, err := lego.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger.Debug("正在注册账号:" + email)
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.Registration = reg
|
||||
|
||||
err = SaveUserToDB(db, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger.Debug("账号注册并保存成功")
|
||||
}
|
||||
|
||||
// 初始化 ACME 客户端
|
||||
client, err := lego.NewClient(lego.NewConfig(user))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 获取 DNS 验证提供者
|
||||
providerData, err := access.GetAccess(providerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
providerConfigStr, ok := providerData["config"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("api配置错误")
|
||||
}
|
||||
// 解析 JSON 配置
|
||||
var providerConfig map[string]string
|
||||
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// DNS 验证
|
||||
provider, err := GetDNSProvider(providerStr, providerConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建 DNS provider 失败: %v", err)
|
||||
}
|
||||
|
||||
err = client.Challenge.SetDNS01Provider(provider,
|
||||
dns01.WrapPreCheck(func(domain, fqdn, value string, check dns01.PreCheckFunc) (bool, error) {
|
||||
// 跳过预检查
|
||||
return true, nil
|
||||
}),
|
||||
dns01.AddRecursiveNameservers([]string{
|
||||
"8.8.8.8:53",
|
||||
"1.1.1.1:53",
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// fmt.Println(strings.Split(domains, ","))
|
||||
request := certificate.ObtainRequest{
|
||||
Domains: strings.Split(domains, ","),
|
||||
Bundle: true,
|
||||
}
|
||||
certObj, err := client.Certificate.Obtain(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certStr := string(certObj.Certificate)
|
||||
keyStr := string(certObj.PrivateKey)
|
||||
issuerCertStr := string(certObj.IssuerCertificate)
|
||||
|
||||
// 保存证书和私钥
|
||||
data := map[string]any{
|
||||
"cert": certStr,
|
||||
"key": keyStr,
|
||||
"issuerCert": issuerCertStr,
|
||||
}
|
||||
|
||||
err = cert.SaveCert("workflow", keyStr, certStr, issuerCertStr, runId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
206
backend/internal/cert/cert.go
Normal file
206
backend/internal/cert/cert.go
Normal file
@@ -0,0 +1,206 @@
|
||||
package cert
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/public"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetSqlite() (*public.Sqlite, error) {
|
||||
s, err := public.NewSqlite("data/data.db", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Connect()
|
||||
s.TableName = "cert"
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func GetList(search string, p, limit int64) ([]map[string]any, int, error) {
|
||||
var data []map[string]any
|
||||
var count int64
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return data, 0, err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
var limits []int64
|
||||
if p >= 0 && limit >= 0 {
|
||||
limits = []int64{0, limit}
|
||||
if p > 1 {
|
||||
limits[0] = (p - 1) * limit
|
||||
limits[1] = p * limit
|
||||
}
|
||||
}
|
||||
|
||||
if search != "" {
|
||||
count, err = s.Where("domains like ?", []interface{}{"%" + search + "%"}).Count()
|
||||
data, err = s.Where("domains like ?", []interface{}{"%" + search + "%"}).Limit(limits).Order("create_time", "desc").Select()
|
||||
} else {
|
||||
count, err = s.Count()
|
||||
data, err = s.Order("create_time", "desc").Limit(limits).Select()
|
||||
}
|
||||
if err != nil {
|
||||
return data, 0, err
|
||||
}
|
||||
for _, v := range data {
|
||||
endtime, err := time.Parse("2006-01-02 15:04:05", v["end_time"].(string))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
v["end_day"] = strconv.FormatInt(int64(endtime.Sub(time.Now())/(24*time.Hour)), 10)
|
||||
}
|
||||
return data, int(count), nil
|
||||
}
|
||||
|
||||
func AddCert(source, key, cert, issuer, issuerCert, domains, sha256, historyId, startTime, endTime, endDay string) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
workflowId := ""
|
||||
if historyId != "" {
|
||||
s, err := public.NewSqlite("data/data.db", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Connect()
|
||||
s.TableName = "workflow_history"
|
||||
defer s.Close()
|
||||
// 查询 workflowId
|
||||
wh, err := s.Where("id=?", []interface{}{historyId}).Select()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(wh) > 0 {
|
||||
workflowId = wh[0]["workflow_id"].(string)
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now().Format("2006-01-02 15:04:05")
|
||||
_, err = s.Insert(map[string]any{
|
||||
"source": source,
|
||||
"key": key,
|
||||
"cert": cert,
|
||||
"issuer": issuer,
|
||||
"issuer_cert": issuerCert,
|
||||
"domains": domains,
|
||||
"sha256": sha256,
|
||||
"history_id": historyId,
|
||||
"workflow_id": workflowId,
|
||||
"create_time": now,
|
||||
"update_time": now,
|
||||
"start_time": startTime,
|
||||
"end_time": endTime,
|
||||
"end_day": endDay,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SaveCert(source, key, cert, issuerCert, historyId string) error {
|
||||
if err := public.ValidateSSLCertificate(cert, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certObj, err := public.ParseCertificate([]byte(cert))
|
||||
if err != nil {
|
||||
return fmt.Errorf("解析证书失败: %v", err)
|
||||
}
|
||||
// SHA256
|
||||
sha256, err := public.GetSHA256(cert)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取 SHA256 失败: %v", err)
|
||||
}
|
||||
if d, _ := GetCert(sha256); d != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
domainSet := make(map[string]bool)
|
||||
|
||||
if certObj.Subject.CommonName != "" {
|
||||
domainSet[certObj.Subject.CommonName] = true
|
||||
}
|
||||
for _, dns := range certObj.DNSNames {
|
||||
domainSet[dns] = true
|
||||
}
|
||||
|
||||
// 转成切片并拼接成逗号分隔的字符串
|
||||
var domains []string
|
||||
for domain := range domainSet {
|
||||
domains = append(domains, domain)
|
||||
}
|
||||
domainList := strings.Join(domains, ",")
|
||||
|
||||
// 提取 CA 名称(Issuer 的组织名)
|
||||
caName := "UNKNOWN"
|
||||
if len(certObj.Issuer.Organization) > 0 {
|
||||
caName = certObj.Issuer.Organization[0]
|
||||
} else if certObj.Issuer.CommonName != "" {
|
||||
caName = certObj.Issuer.CommonName
|
||||
}
|
||||
// 证书有效期
|
||||
startTime := certObj.NotBefore.Format("2006-01-02 15:04:05")
|
||||
endTime := certObj.NotAfter.Format("2006-01-02 15:04:05")
|
||||
endDay := fmt.Sprintf("%d", int(certObj.NotAfter.Sub(time.Now()).Hours()/24))
|
||||
|
||||
err = AddCert(source, key, cert, caName, issuerCert, domainList, sha256, historyId, startTime, endTime, endDay)
|
||||
if err != nil {
|
||||
return fmt.Errorf("保存证书失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func UploadCert(key, cert string) error {
|
||||
err := SaveCert("upload", key, cert, "", "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("保存证书失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DelCert(id string) error {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
_, err = s.Where("id=?", []interface{}{id}).Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetCert(id string) (map[string]string, error) {
|
||||
s, err := GetSqlite()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
res, err := s.Where("id=? or sha256=?", []interface{}{id, id}).Select()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(res) == 0 {
|
||||
return nil, fmt.Errorf("证书不存在")
|
||||
}
|
||||
|
||||
data := map[string]string{
|
||||
"domains": res[0]["domains"].(string),
|
||||
"cert": res[0]["cert"].(string),
|
||||
"key": res[0]["key"].(string),
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ========================================================
|
||||
31
backend/internal/cert/deploy/1p_test.go
Normal file
31
backend/internal/cert/deploy/1p_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package deploy
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSite(t *testing.T) {
|
||||
cfg := map[string]any{
|
||||
"site_id": "1",
|
||||
"provider_id": "22",
|
||||
"certificate": map[string]any{
|
||||
"key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAxIjmAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONh\nWhMT6W+cx0WMC80yCRm5JshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM\n4tz/Zh8a3kVyN4MtWDmV1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1\nz6qqEDcM8FtHoAXAdxQBkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9\ncMY1cCEBxpwQTJiJHbX9LcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MU\nS89+DsixFf3HL+iWjr6yVnQ/mAGVPQ+HD4pwmQIDAQABAoIBAALpcFb59MBZZHJ3\nui9RRi96ig6kPQoRjkjN83pjM+/h/bANMmUOQU5FHBKLwj5uhN5Dpk2fzAnIX2TE\nVgfyNGsYuWLsIM+m6EJfm7pXJwJDr3RCpm+6DIKr1U8TwlR2OhbDi6fOlfH66q79\n2Klq4SXsa0vgfllpTVCDtydFVjwAuQV7Cf6DGRjbNpN3DPLeOC1wYFimNZwudSK0\nf8grWpPFXw2TPaf3TgeBGxwL7GCTYSKT+Eq9USbhG4RArrM9oQt+h7rzaH2bFEdg\n7tOM4KIgV+aw8r0TsYisDG9dfiHfHr5vQnkmWgt/rxAOvHlJ7/64pBVuET1ZF0mB\nP6gu4Y0CgYEAzkwXvfnHI5qx9BVP6e9lGrpWrm0RxCKr2iCCwrOVALbX1yfKCb5L\nrP/jSERMuLt6bIKg/AoVu9ogCTGzntyHTbZXFGg/y5Xoul+1af2arQ1rGZ7A/Im7\nnteZePg2U6UiDRy07F94FF5aL/v97D4BffiSA+0atlgH6tpKyYfY6NsCgYEA8+Ku\nGQqX9kHDd5bbzPhLelNmHVnAjnMaHEhvzVtBA737F10Oqg9wyffqe/i/DvdUSx9r\nafKGUfzB2vVZjz//OpSQ8VhRzDTiyelKLsSTmzOokLBnwayyTxw85o9EDvTNrzfb\nYQbAjmAXWmnv5Xvx1KfvTaKFY3BmHsKYJDzwnJsCgYBK1SVjn2CSVMIqlTSI2nMl\nb+STnzLrn9wQ4uwr7nKlcK34+RD72dCfr67lfwkJldBB3lzBMHNT0jr+us26Waqn\nEPaji3Fgyz9BpAgtq3XZQl3QTFsbAGdTpkegrwEd9G/Wq8whVjw7v0Id193zPUbT\nSEDHNdITxPkSQx8P3bxcMwKBgQDO5EGk5KO9OFTFoqib3RbKku1RgM4lCefgjmKp\n5vvkXMohK8RA6BBahYHZ4U7TN2W+xMyueBsSekVJplFvgG7YFyhOVQovHb42Yz2X\nJxPA2bXp6HxchFBPZDkVrfuiZHIIbm4ghUXcgg/Nl4j3OIoSSNRtG63kiXlYJuRB\n+aB0eQKBgD79VrREpbOMS7HRlDTtfkDN94HY3T4MLErs26z/NLO/dC44tmBJGo2P\ngcQ+p7XxNjpWUnUbEiuz4R3Xgh6ULwuSseWtcQicolPHTkBjnc+6BEpyguZJ+FPZ\nGls3g3LxjGhdPlyd37CaWDvx/Jtjrd4Y9iGkGO2d9fXZD0Hg0ymX\n-----END RSA PRIVATE KEY-----",
|
||||
"cert": "-----BEGIN CERTIFICATE-----\nMIIG5DCCBMygAwIBAgIQBPQGlt81+4RKt3RAFXPvrjANBgkqhkiG9w0BAQsFADBb\nMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg\nSW5jLjElMCMGA1UEAxMcVHJ1c3RBc2lhIERWIFRMUyBSU0EgQ0EgMjAyNTAeFw0y\nNTA0MjIwMDAwMDBaFw0yNTA3MjAyMzU5NTlaMB8xHTAbBgNVBAMTFGFsbGluc3Ns\nLnphY2h5YW5nLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxIjm\nAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONhWhMT6W+cx0WMC80yCRm5\nJshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM4tz/Zh8a3kVyN4MtWDmV\n1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1z6qqEDcM8FtHoAXAdxQB\nkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9cMY1cCEBxpwQTJiJHbX9\nLcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MUS89+DsixFf3HL+iWjr6y\nVnQ/mAGVPQ+HD4pwmQIDAQABo4IC3jCCAtowHwYDVR0jBBgwFoAUtBIopbTAHZ8p\ncWk82RGWSnVpUMAwHQYDVR0OBBYEFHqqdlMVBlcadf7iJLJoLnLZ7h4tMB8GA1Ud\nEQQYMBaCFGFsbGluc3NsLnphY2h5YW5nLmNuMD4GA1UdIAQ3MDUwMwYGZ4EMAQIB\nMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNV\nHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHkGCCsG\nAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t\nMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vVHJ1c3RB\nc2lhRFZUTFNSU0FDQTIwMjUuY3J0MAwGA1UdEwEB/wQCMAAwggF9BgorBgEEAdZ5\nAgQCBIIBbQSCAWkBZwB2ABLxTjS9U3JMhAYZw48/ehP457Vih4icbTAFhOvlhiY6\nAAABll0w/o0AAAQDAEcwRQIgd24jCPm+fbHq3grMIxtvQhzkv7dvYPM/BGjPEsy1\nQ70CIQC5jXADjBh+dH50T+atn3lktBEqQhedOl6cAaP/XXmk6gB2AO08S9boBsKk\nogBX28sk4jgB31Ev7cSGxXAPIN23Pj/gAAABll0w/rUAAAQDAEcwRQIgU2GDVEH1\ns5i/RC1RhqvJjn72PAZOlDtJyLdg29vC9HECIQCj78GATYK5quitLxbn3HvD8BeT\noOz+3tacgyN6+TdvugB1AKRCxQZJYGFUjw/U6pz7ei0mRU2HqX8v30VZ9idPOoRU\nAAABll0w/sYAAAQDAEYwRAIgCvU/iBRPKoJLjmU4edBYObWAO/aJp2mWnfJ4ieAr\nrXsCIBsAppYu28h8YEOl0N9yEeF9G05IMxwkCjZKonQs2SKMMA0GCSqGSIb3DQEB\nCwUAA4ICAQB3wFou51Qvl4apMhencuQUnWF3UpYP49e0WQ72DVT3pYjYsozkSuqb\nQZcwMB6HDoHdFicxvQ/yxKyTu/nw3rXjUWYuSxXYd7lJcQ/R0tR00m6AFeinY4Aq\nq4QqoA+lriK1XqO5MomAL4FbSysT1ow/gaG9pYuXEdT4pr05I/NumjXdkwBRZOd4\nrhol2grKf3y37Qla5hUbbG3ab9nf/csJSWkCoESeXr3MB1oAU/aL9pGSagvMXSKQ\nsFs2cn2Fi8ZmJPJXIP114lgvFuFDO+C1yTNbHap/FufvAKGryfPDuPecCF6FSXej\n+bwg4/BNz5lcHbNo2XXjLgoPg4VE6mG/SQQZQEDBk5DowwMVMvh77t9RBNrHozah\nHGtQz2hCuIX7rZQYnSlvW8T75FhI/Sd+HEfU/iyTIELXBUjypnK2bOJL7+jE7f79\nuljhXlCcP52fGHCjexNBz5gIZr82KVxsfxKuZjfioPkhmWleVNMdMWYJRXu618E6\nNtNjUVsDCuMOOMNs1qScqxOT60MeDZLX+vnC93fdd/t2hLEAWWNNMkWeX2qLCE1q\nGarop9U1mJpiBWkW5cBiqnNIbhuV2fcwFIR8mVT5f1Qcw+WxE2nEjY2h75bKv8T5\n3RBngmaX8PcyLAP2s0/4UyzAnMYfioJBh37VpUYBrdriBkRds/AMZw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFnjCCBIagAwIBAgIQCSYyO0lk42hGFRLe8aXVLDANBgkqhkiG9w0BAQsFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\nMjAeFw0yNTAxMDgwMDAwMDBaFw0zNTAxMDcyMzU5NTlaMFsxCzAJBgNVBAYTAkNO\nMSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSUwIwYDVQQD\nExxUcnVzdEFzaWEgRFYgVExTIFJTQSBDQSAyMDI1MIICIjANBgkqhkiG9w0BAQEF\nAAOCAg8AMIICCgKCAgEA0fuEmuBIsN6ZZVq+gRobMorOGIilTCIfQrxNpR8FUZ9R\n/GfbiekbiIKphQXEZ7N1uBnn6tXUuZ32zl6jPkZpHzN/Bmgk1BWSIzVc0npMzrWq\n/hrbk5+KddXJdsNpeG1+Q8lc8uVMBrztnxaPb7Rh7yQCsMrcO4hgVaqLJWkVvEfW\nULtoCHQnNaj4IroG6VxQf1oArQ8bPbwpI02lieSahRa78FQuXdoGVeQcrkhtVjZs\nON98vq5fPWZX2LFv7e5J6P9IHbzvOl8yyQjv+2/IOwhNSkaXX3bI+//bqF9XW/p7\n+gsUmHiK5YsvLjmXcvDmoDEGrXMzgX31Zl2nJ+umpRbLjwP8rxYIUsKoEwEdFoto\nAid59UEBJyw/GibwXQ5xTyKD/N6C8SFkr1+myOo4oe1UB+YgvRu6qSxIABo5kYdX\nFodLP4IgoVJdeUFs1Usa6bxYEO6EgMf5lCWt9hGZszvXYZwvyZGq3ogNXM7eKyi2\n20WzJXYMmi9TYFq2Fa95aZe4wki6YhDhhOO1g0sjITGVaB73G+JOCI9yJhv6+REN\nD40ZpboUHE8JNgMVWbG1isAMVCXqiADgXtuC+tmJWPEH9cR6OuJLEpwOzPfgAbnn\n2MRu7Tsdr8jPjTPbD0FxblX1ydW3RG30vwLF5lkTTRkHG9epMgpPMdYP7nY/08MC\nAwEAAaOCAVYwggFSMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLQSKKW0\nwB2fKXFpPNkRlkp1aVDAMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485\nMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\ndgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy\ndC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E\naWdpQ2VydEdsb2JhbFJvb3RHMi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov\nL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDARBgNV\nHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBAJ4a3svh316GY2+Z7EYx\nmBIsOwjJSnyoEfzx2T699ctLLrvuzS79Mg3pPjxSLlUgyM8UzrFc5tgVU3dZ1sFQ\nI4RM+ysJdvIAX/7Yx1QbooVdKhkdi9X7QN7yVkjqwM3fY3WfQkRTzhIkM7mYIQbR\nr+y2Vkju61BLqh7OCRpPMiudjEpP1kEtRyGs2g0aQpEIqKBzxgitCXSayO1hoO6/\n71ts801OzYlqYW9OQQQ2GCJyFbD6XHDjdpn+bWUxTKWaMY0qedSCbHE3Kl2QEF0C\nynZ7SbC03yR+gKZQDeTXrNP1kk5Qhe7jSXgw+nhbspe0q/M1ZcNCz+sPxeOwdCcC\ngJE=\n-----END CERTIFICATE-----",
|
||||
"issuer": "cert-issuer",
|
||||
},
|
||||
}
|
||||
err := Deploy1panelSite(cfg)
|
||||
println(err)
|
||||
}
|
||||
|
||||
func TestP(t *testing.T) {
|
||||
cfg := map[string]any{
|
||||
"site_id": "1",
|
||||
"provider_id": "22",
|
||||
"certificate": map[string]any{
|
||||
"key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAxIjmAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONh\nWhMT6W+cx0WMC80yCRm5JshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM\n4tz/Zh8a3kVyN4MtWDmV1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1\nz6qqEDcM8FtHoAXAdxQBkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9\ncMY1cCEBxpwQTJiJHbX9LcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MU\nS89+DsixFf3HL+iWjr6yVnQ/mAGVPQ+HD4pwmQIDAQABAoIBAALpcFb59MBZZHJ3\nui9RRi96ig6kPQoRjkjN83pjM+/h/bANMmUOQU5FHBKLwj5uhN5Dpk2fzAnIX2TE\nVgfyNGsYuWLsIM+m6EJfm7pXJwJDr3RCpm+6DIKr1U8TwlR2OhbDi6fOlfH66q79\n2Klq4SXsa0vgfllpTVCDtydFVjwAuQV7Cf6DGRjbNpN3DPLeOC1wYFimNZwudSK0\nf8grWpPFXw2TPaf3TgeBGxwL7GCTYSKT+Eq9USbhG4RArrM9oQt+h7rzaH2bFEdg\n7tOM4KIgV+aw8r0TsYisDG9dfiHfHr5vQnkmWgt/rxAOvHlJ7/64pBVuET1ZF0mB\nP6gu4Y0CgYEAzkwXvfnHI5qx9BVP6e9lGrpWrm0RxCKr2iCCwrOVALbX1yfKCb5L\nrP/jSERMuLt6bIKg/AoVu9ogCTGzntyHTbZXFGg/y5Xoul+1af2arQ1rGZ7A/Im7\nnteZePg2U6UiDRy07F94FF5aL/v97D4BffiSA+0atlgH6tpKyYfY6NsCgYEA8+Ku\nGQqX9kHDd5bbzPhLelNmHVnAjnMaHEhvzVtBA737F10Oqg9wyffqe/i/DvdUSx9r\nafKGUfzB2vVZjz//OpSQ8VhRzDTiyelKLsSTmzOokLBnwayyTxw85o9EDvTNrzfb\nYQbAjmAXWmnv5Xvx1KfvTaKFY3BmHsKYJDzwnJsCgYBK1SVjn2CSVMIqlTSI2nMl\nb+STnzLrn9wQ4uwr7nKlcK34+RD72dCfr67lfwkJldBB3lzBMHNT0jr+us26Waqn\nEPaji3Fgyz9BpAgtq3XZQl3QTFsbAGdTpkegrwEd9G/Wq8whVjw7v0Id193zPUbT\nSEDHNdITxPkSQx8P3bxcMwKBgQDO5EGk5KO9OFTFoqib3RbKku1RgM4lCefgjmKp\n5vvkXMohK8RA6BBahYHZ4U7TN2W+xMyueBsSekVJplFvgG7YFyhOVQovHb42Yz2X\nJxPA2bXp6HxchFBPZDkVrfuiZHIIbm4ghUXcgg/Nl4j3OIoSSNRtG63kiXlYJuRB\n+aB0eQKBgD79VrREpbOMS7HRlDTtfkDN94HY3T4MLErs26z/NLO/dC44tmBJGo2P\ngcQ+p7XxNjpWUnUbEiuz4R3Xgh6ULwuSseWtcQicolPHTkBjnc+6BEpyguZJ+FPZ\nGls3g3LxjGhdPlyd37CaWDvx/Jtjrd4Y9iGkGO2d9fXZD0Hg0ymX\n-----END RSA PRIVATE KEY-----",
|
||||
"cert": "-----BEGIN CERTIFICATE-----\nMIIG5DCCBMygAwIBAgIQBPQGlt81+4RKt3RAFXPvrjANBgkqhkiG9w0BAQsFADBb\nMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg\nSW5jLjElMCMGA1UEAxMcVHJ1c3RBc2lhIERWIFRMUyBSU0EgQ0EgMjAyNTAeFw0y\nNTA0MjIwMDAwMDBaFw0yNTA3MjAyMzU5NTlaMB8xHTAbBgNVBAMTFGFsbGluc3Ns\nLnphY2h5YW5nLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxIjm\nAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONhWhMT6W+cx0WMC80yCRm5\nJshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM4tz/Zh8a3kVyN4MtWDmV\n1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1z6qqEDcM8FtHoAXAdxQB\nkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9cMY1cCEBxpwQTJiJHbX9\nLcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MUS89+DsixFf3HL+iWjr6y\nVnQ/mAGVPQ+HD4pwmQIDAQABo4IC3jCCAtowHwYDVR0jBBgwFoAUtBIopbTAHZ8p\ncWk82RGWSnVpUMAwHQYDVR0OBBYEFHqqdlMVBlcadf7iJLJoLnLZ7h4tMB8GA1Ud\nEQQYMBaCFGFsbGluc3NsLnphY2h5YW5nLmNuMD4GA1UdIAQ3MDUwMwYGZ4EMAQIB\nMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNV\nHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHkGCCsG\nAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t\nMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vVHJ1c3RB\nc2lhRFZUTFNSU0FDQTIwMjUuY3J0MAwGA1UdEwEB/wQCMAAwggF9BgorBgEEAdZ5\nAgQCBIIBbQSCAWkBZwB2ABLxTjS9U3JMhAYZw48/ehP457Vih4icbTAFhOvlhiY6\nAAABll0w/o0AAAQDAEcwRQIgd24jCPm+fbHq3grMIxtvQhzkv7dvYPM/BGjPEsy1\nQ70CIQC5jXADjBh+dH50T+atn3lktBEqQhedOl6cAaP/XXmk6gB2AO08S9boBsKk\nogBX28sk4jgB31Ev7cSGxXAPIN23Pj/gAAABll0w/rUAAAQDAEcwRQIgU2GDVEH1\ns5i/RC1RhqvJjn72PAZOlDtJyLdg29vC9HECIQCj78GATYK5quitLxbn3HvD8BeT\noOz+3tacgyN6+TdvugB1AKRCxQZJYGFUjw/U6pz7ei0mRU2HqX8v30VZ9idPOoRU\nAAABll0w/sYAAAQDAEYwRAIgCvU/iBRPKoJLjmU4edBYObWAO/aJp2mWnfJ4ieAr\nrXsCIBsAppYu28h8YEOl0N9yEeF9G05IMxwkCjZKonQs2SKMMA0GCSqGSIb3DQEB\nCwUAA4ICAQB3wFou51Qvl4apMhencuQUnWF3UpYP49e0WQ72DVT3pYjYsozkSuqb\nQZcwMB6HDoHdFicxvQ/yxKyTu/nw3rXjUWYuSxXYd7lJcQ/R0tR00m6AFeinY4Aq\nq4QqoA+lriK1XqO5MomAL4FbSysT1ow/gaG9pYuXEdT4pr05I/NumjXdkwBRZOd4\nrhol2grKf3y37Qla5hUbbG3ab9nf/csJSWkCoESeXr3MB1oAU/aL9pGSagvMXSKQ\nsFs2cn2Fi8ZmJPJXIP114lgvFuFDO+C1yTNbHap/FufvAKGryfPDuPecCF6FSXej\n+bwg4/BNz5lcHbNo2XXjLgoPg4VE6mG/SQQZQEDBk5DowwMVMvh77t9RBNrHozah\nHGtQz2hCuIX7rZQYnSlvW8T75FhI/Sd+HEfU/iyTIELXBUjypnK2bOJL7+jE7f79\nuljhXlCcP52fGHCjexNBz5gIZr82KVxsfxKuZjfioPkhmWleVNMdMWYJRXu618E6\nNtNjUVsDCuMOOMNs1qScqxOT60MeDZLX+vnC93fdd/t2hLEAWWNNMkWeX2qLCE1q\nGarop9U1mJpiBWkW5cBiqnNIbhuV2fcwFIR8mVT5f1Qcw+WxE2nEjY2h75bKv8T5\n3RBngmaX8PcyLAP2s0/4UyzAnMYfioJBh37VpUYBrdriBkRds/AMZw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFnjCCBIagAwIBAgIQCSYyO0lk42hGFRLe8aXVLDANBgkqhkiG9w0BAQsFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\nMjAeFw0yNTAxMDgwMDAwMDBaFw0zNTAxMDcyMzU5NTlaMFsxCzAJBgNVBAYTAkNO\nMSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSUwIwYDVQQD\nExxUcnVzdEFzaWEgRFYgVExTIFJTQSBDQSAyMDI1MIICIjANBgkqhkiG9w0BAQEF\nAAOCAg8AMIICCgKCAgEA0fuEmuBIsN6ZZVq+gRobMorOGIilTCIfQrxNpR8FUZ9R\n/GfbiekbiIKphQXEZ7N1uBnn6tXUuZ32zl6jPkZpHzN/Bmgk1BWSIzVc0npMzrWq\n/hrbk5+KddXJdsNpeG1+Q8lc8uVMBrztnxaPb7Rh7yQCsMrcO4hgVaqLJWkVvEfW\nULtoCHQnNaj4IroG6VxQf1oArQ8bPbwpI02lieSahRa78FQuXdoGVeQcrkhtVjZs\nON98vq5fPWZX2LFv7e5J6P9IHbzvOl8yyQjv+2/IOwhNSkaXX3bI+//bqF9XW/p7\n+gsUmHiK5YsvLjmXcvDmoDEGrXMzgX31Zl2nJ+umpRbLjwP8rxYIUsKoEwEdFoto\nAid59UEBJyw/GibwXQ5xTyKD/N6C8SFkr1+myOo4oe1UB+YgvRu6qSxIABo5kYdX\nFodLP4IgoVJdeUFs1Usa6bxYEO6EgMf5lCWt9hGZszvXYZwvyZGq3ogNXM7eKyi2\n20WzJXYMmi9TYFq2Fa95aZe4wki6YhDhhOO1g0sjITGVaB73G+JOCI9yJhv6+REN\nD40ZpboUHE8JNgMVWbG1isAMVCXqiADgXtuC+tmJWPEH9cR6OuJLEpwOzPfgAbnn\n2MRu7Tsdr8jPjTPbD0FxblX1ydW3RG30vwLF5lkTTRkHG9epMgpPMdYP7nY/08MC\nAwEAAaOCAVYwggFSMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLQSKKW0\nwB2fKXFpPNkRlkp1aVDAMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485\nMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\ndgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy\ndC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E\naWdpQ2VydEdsb2JhbFJvb3RHMi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov\nL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDARBgNV\nHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBAJ4a3svh316GY2+Z7EYx\nmBIsOwjJSnyoEfzx2T699ctLLrvuzS79Mg3pPjxSLlUgyM8UzrFc5tgVU3dZ1sFQ\nI4RM+ysJdvIAX/7Yx1QbooVdKhkdi9X7QN7yVkjqwM3fY3WfQkRTzhIkM7mYIQbR\nr+y2Vkju61BLqh7OCRpPMiudjEpP1kEtRyGs2g0aQpEIqKBzxgitCXSayO1hoO6/\n71ts801OzYlqYW9OQQQ2GCJyFbD6XHDjdpn+bWUxTKWaMY0qedSCbHE3Kl2QEF0C\nynZ7SbC03yR+gKZQDeTXrNP1kk5Qhe7jSXgw+nhbspe0q/M1ZcNCz+sPxeOwdCcC\ngJE=\n-----END CERTIFICATE-----",
|
||||
"issuer": "cert-issuer",
|
||||
},
|
||||
}
|
||||
err := Deploy1panel(cfg)
|
||||
println(err)
|
||||
}
|
||||
223
backend/internal/cert/deploy/1panel.go
Normal file
223
backend/internal/cert/deploy/1panel.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/access"
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func generateToken(timestamp string, apiKey string) string {
|
||||
tokenMd5 := md5.Sum([]byte("1panel" + apiKey + timestamp))
|
||||
tokenMd5Hex := hex.EncodeToString(tokenMd5[:])
|
||||
return tokenMd5Hex
|
||||
}
|
||||
|
||||
// method provider_id url data
|
||||
|
||||
func Request1panel(data *map[string]any, method, providerID, requestUrl string) (map[string]any, error) {
|
||||
providerData, err := access.GetAccess(providerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
providerConfigStr, ok := providerData["config"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("api配置错误")
|
||||
}
|
||||
// 解析 JSON 配置
|
||||
var providerConfig map[string]string
|
||||
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
timestamp := fmt.Sprintf("%d", time.Now().Unix())
|
||||
token := generateToken(timestamp, providerConfig["api_key"])
|
||||
|
||||
// data, requestUrl, method := GetDeploy1PBody(cfg, Type)
|
||||
if requestUrl == "" || data == nil {
|
||||
return nil, fmt.Errorf("不支持的部署类型")
|
||||
}
|
||||
|
||||
// 编码为 JSON
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if providerConfig["url"][len(providerConfig["url"])-1:] != "/" {
|
||||
providerConfig["url"] += "/"
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, providerConfig["url"]+requestUrl, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36")
|
||||
req.Header.Set("1Panel-Timestamp", timestamp)
|
||||
req.Header.Set("1Panel-Token", token)
|
||||
|
||||
// 自定义 Transport,跳过 SSL 证书验证
|
||||
ignoreSsl := false
|
||||
if providerConfig["ignore_ssl"] == "1" {
|
||||
ignoreSsl = true
|
||||
}
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: tr}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
return nil, fmt.Errorf("请求1panel失败: %v", err)
|
||||
}
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var res map[string]interface{}
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("证书部署失败: %v", err)
|
||||
}
|
||||
code, ok := res["code"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("证书部署失败")
|
||||
}
|
||||
if code != 200 {
|
||||
msg, ok := res["msg"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("证书部署失败")
|
||||
}
|
||||
return nil, fmt.Errorf("证书部署失败: %s", msg)
|
||||
}
|
||||
return res, nil
|
||||
|
||||
}
|
||||
|
||||
func Deploy1panel(cfg map[string]any) error {
|
||||
cert, ok := cfg["certificate"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书不存在")
|
||||
}
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
// 设置证书
|
||||
keyPem, ok := cert["key"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:key")
|
||||
}
|
||||
certPem, ok := cert["cert"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:cert")
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"cert": certPem,
|
||||
"key": keyPem,
|
||||
"ssl": "enable",
|
||||
"sslType": "import-paste",
|
||||
}
|
||||
_, err := Request1panel(&data, "POST", providerID, "api/v1/settings/ssl/update")
|
||||
if err != nil {
|
||||
return fmt.Errorf("证书部署失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Deploy1panelSite(cfg map[string]any) error {
|
||||
cert, ok := cfg["certificate"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书不存在")
|
||||
}
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
siteId, ok := cfg["site_id"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:site_id")
|
||||
}
|
||||
// 设置证书
|
||||
keyPem, ok := cert["key"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:key")
|
||||
}
|
||||
certPem, ok := cert["cert"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:cert")
|
||||
}
|
||||
// 获取网站参数
|
||||
siteData, err := Request1panel(&map[string]any{}, "GET", providerID, fmt.Sprintf("api/v1/websites/%s/https", siteId))
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取网站参数失败: %v", err)
|
||||
}
|
||||
//
|
||||
websiteId, err := strconv.Atoi(siteId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取网站参数失败: %v", err)
|
||||
}
|
||||
|
||||
siteData, ok = siteData["data"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("获取网站参数失败: data")
|
||||
}
|
||||
SSLProtocol, ok := siteData["ssl_protocol"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("获取网站参数失败: data.ssl_protocol")
|
||||
}
|
||||
algorithm, ok := siteData["algorithm"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("获取网站参数失败: data.algorithm")
|
||||
}
|
||||
enable, ok := siteData["enable"].(bool)
|
||||
if !ok {
|
||||
return fmt.Errorf("获取网站参数失败: data.enable")
|
||||
}
|
||||
hsts, ok := siteData["hsts"].(bool)
|
||||
if !ok {
|
||||
return fmt.Errorf("获取网站参数失败: data.hsts")
|
||||
}
|
||||
httpConfig, ok := siteData["http_config"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("获取网站参数失败: data.http_config")
|
||||
}
|
||||
|
||||
data := map[string]any{
|
||||
"SSLProtocol": SSLProtocol,
|
||||
// "acmeAccountId": siteData["SSL"].(map[string]any)["acmeAccountId"].(float64),
|
||||
"algorithm": algorithm,
|
||||
"certificate": certPem,
|
||||
"privateKey": keyPem,
|
||||
// "certificatePath": "",
|
||||
// "privateKeyPath": "",
|
||||
"enable": enable,
|
||||
"hsts": hsts,
|
||||
"httpConfig": httpConfig,
|
||||
// "importType": "paste",
|
||||
"type": "manual",
|
||||
"websiteId": websiteId,
|
||||
}
|
||||
_, err = Request1panel(&data, "POST", providerID, fmt.Sprintf("api/v1/websites/%s/https", siteId))
|
||||
return nil
|
||||
}
|
||||
41
backend/internal/cert/deploy/ali_test.go
Normal file
41
backend/internal/cert/deploy/ali_test.go
Normal file
File diff suppressed because one or more lines are too long
186
backend/internal/cert/deploy/aliyun.go
Normal file
186
backend/internal/cert/deploy/aliyun.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/access"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
aliyuncdn "github.com/alibabacloud-go/cdn-20180510/v6/client"
|
||||
aliyunopenapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
)
|
||||
|
||||
func ClientAliCdn(accessKey, accessSecret string) (_result *aliyuncdn.Client, err error) {
|
||||
config := &aliyunopenapi.Config{
|
||||
AccessKeyId: tea.String(accessKey),
|
||||
AccessKeySecret: tea.String(accessSecret),
|
||||
Endpoint: tea.String("cdn.aliyuncs.com"),
|
||||
}
|
||||
client, err := aliyuncdn.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func DeployAliCdn(cfg map[string]any) error {
|
||||
cert, ok := cfg["certificate"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书不存在")
|
||||
}
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
//
|
||||
providerData, err := access.GetAccess(providerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerConfigStr, ok := providerData["config"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("api配置错误")
|
||||
}
|
||||
// 解析 JSON 配置
|
||||
var providerConfig map[string]string
|
||||
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := ClientAliCdn(providerConfig["access_key"], providerConfig["access_secret"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domain, ok := cfg["domain"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:domain")
|
||||
}
|
||||
// 设置证书
|
||||
keyPem, ok := cert["key"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:key")
|
||||
}
|
||||
certPem, ok := cert["cert"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:cert")
|
||||
}
|
||||
|
||||
setCdnDomainSSLCertificateRequest := &aliyuncdn.SetCdnDomainSSLCertificateRequest{
|
||||
DomainName: tea.String(domain),
|
||||
SSLProtocol: tea.String("on"),
|
||||
SSLPub: tea.String(strings.TrimSpace(certPem)),
|
||||
SSLPri: tea.String(strings.TrimSpace(keyPem)),
|
||||
}
|
||||
_, err = client.SetCdnDomainSSLCertificate(setCdnDomainSSLCertificateRequest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ClientOss(accessKeyId, accessKeySecret, region string) (*oss.Client, error) {
|
||||
// 接入点一览 https://api.aliyun.com/product/Oss
|
||||
var endpoint string
|
||||
switch region {
|
||||
case "":
|
||||
endpoint = "oss.aliyuncs.com"
|
||||
case
|
||||
"cn-hzjbp",
|
||||
"cn-hzjbp-a",
|
||||
"cn-hzjbp-b":
|
||||
endpoint = "oss-cn-hzjbp-a-internal.aliyuncs.com"
|
||||
case
|
||||
"cn-shanghai-finance-1",
|
||||
"cn-shenzhen-finance-1",
|
||||
"cn-beijing-finance-1",
|
||||
"cn-north-2-gov-1":
|
||||
endpoint = fmt.Sprintf("oss-%s-internal.aliyuncs.com", region)
|
||||
default:
|
||||
endpoint = fmt.Sprintf("oss-%s.aliyuncs.com", region)
|
||||
}
|
||||
|
||||
client, err := oss.New(endpoint, accessKeyId, accessKeySecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func DeployOss(cfg map[string]any) error {
|
||||
cert, ok := cfg["certificate"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书不存在")
|
||||
}
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
//
|
||||
providerData, err := access.GetAccess(providerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerConfigStr, ok := providerData["config"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("api配置错误")
|
||||
}
|
||||
// 解析 JSON 配置
|
||||
var providerConfig map[string]string
|
||||
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
region, ok := cfg["region"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:region")
|
||||
}
|
||||
|
||||
client, err := ClientOss(providerConfig["access_key"], providerConfig["access_secret"], region)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domain, ok := cfg["domain"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:domain")
|
||||
}
|
||||
bucket, ok := cfg["domain"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:bucket")
|
||||
}
|
||||
// 设置证书
|
||||
keyPem, ok := cert["key"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:key")
|
||||
}
|
||||
certPem, ok := cert["cert"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:cert")
|
||||
}
|
||||
|
||||
putBucketCnameWithCertificateRequest := oss.PutBucketCname{
|
||||
Cname: domain,
|
||||
CertificateConfiguration: &oss.CertificateConfiguration{
|
||||
Certificate: certPem,
|
||||
PrivateKey: keyPem,
|
||||
Force: true,
|
||||
},
|
||||
}
|
||||
err = client.PutBucketCnameWithCertificate(bucket, putBucketCnameWithCertificateRequest)
|
||||
return err
|
||||
}
|
||||
31
backend/internal/cert/deploy/bt_test.go
Normal file
31
backend/internal/cert/deploy/bt_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package deploy
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestBTSite(t *testing.T) {
|
||||
cfg := map[string]any{
|
||||
"siteName": "abcd.cn",
|
||||
"provider_id": "19",
|
||||
"certificate": map[string]any{
|
||||
"key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAxIjmAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONh\nWhMT6W+cx0WMC80yCRm5JshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM\n4tz/Zh8a3kVyN4MtWDmV1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1\nz6qqEDcM8FtHoAXAdxQBkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9\ncMY1cCEBxpwQTJiJHbX9LcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MU\nS89+DsixFf3HL+iWjr6yVnQ/mAGVPQ+HD4pwmQIDAQABAoIBAALpcFb59MBZZHJ3\nui9RRi96ig6kPQoRjkjN83pjM+/h/bANMmUOQU5FHBKLwj5uhN5Dpk2fzAnIX2TE\nVgfyNGsYuWLsIM+m6EJfm7pXJwJDr3RCpm+6DIKr1U8TwlR2OhbDi6fOlfH66q79\n2Klq4SXsa0vgfllpTVCDtydFVjwAuQV7Cf6DGRjbNpN3DPLeOC1wYFimNZwudSK0\nf8grWpPFXw2TPaf3TgeBGxwL7GCTYSKT+Eq9USbhG4RArrM9oQt+h7rzaH2bFEdg\n7tOM4KIgV+aw8r0TsYisDG9dfiHfHr5vQnkmWgt/rxAOvHlJ7/64pBVuET1ZF0mB\nP6gu4Y0CgYEAzkwXvfnHI5qx9BVP6e9lGrpWrm0RxCKr2iCCwrOVALbX1yfKCb5L\nrP/jSERMuLt6bIKg/AoVu9ogCTGzntyHTbZXFGg/y5Xoul+1af2arQ1rGZ7A/Im7\nnteZePg2U6UiDRy07F94FF5aL/v97D4BffiSA+0atlgH6tpKyYfY6NsCgYEA8+Ku\nGQqX9kHDd5bbzPhLelNmHVnAjnMaHEhvzVtBA737F10Oqg9wyffqe/i/DvdUSx9r\nafKGUfzB2vVZjz//OpSQ8VhRzDTiyelKLsSTmzOokLBnwayyTxw85o9EDvTNrzfb\nYQbAjmAXWmnv5Xvx1KfvTaKFY3BmHsKYJDzwnJsCgYBK1SVjn2CSVMIqlTSI2nMl\nb+STnzLrn9wQ4uwr7nKlcK34+RD72dCfr67lfwkJldBB3lzBMHNT0jr+us26Waqn\nEPaji3Fgyz9BpAgtq3XZQl3QTFsbAGdTpkegrwEd9G/Wq8whVjw7v0Id193zPUbT\nSEDHNdITxPkSQx8P3bxcMwKBgQDO5EGk5KO9OFTFoqib3RbKku1RgM4lCefgjmKp\n5vvkXMohK8RA6BBahYHZ4U7TN2W+xMyueBsSekVJplFvgG7YFyhOVQovHb42Yz2X\nJxPA2bXp6HxchFBPZDkVrfuiZHIIbm4ghUXcgg/Nl4j3OIoSSNRtG63kiXlYJuRB\n+aB0eQKBgD79VrREpbOMS7HRlDTtfkDN94HY3T4MLErs26z/NLO/dC44tmBJGo2P\ngcQ+p7XxNjpWUnUbEiuz4R3Xgh6ULwuSseWtcQicolPHTkBjnc+6BEpyguZJ+FPZ\nGls3g3LxjGhdPlyd37CaWDvx/Jtjrd4Y9iGkGO2d9fXZD0Hg0ymX\n-----END RSA PRIVATE KEY-----",
|
||||
"cert": "-----BEGIN CERTIFICATE-----\nMIIG5DCCBMygAwIBAgIQBPQGlt81+4RKt3RAFXPvrjANBgkqhkiG9w0BAQsFADBb\nMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg\nSW5jLjElMCMGA1UEAxMcVHJ1c3RBc2lhIERWIFRMUyBSU0EgQ0EgMjAyNTAeFw0y\nNTA0MjIwMDAwMDBaFw0yNTA3MjAyMzU5NTlaMB8xHTAbBgNVBAMTFGFsbGluc3Ns\nLnphY2h5YW5nLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxIjm\nAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONhWhMT6W+cx0WMC80yCRm5\nJshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM4tz/Zh8a3kVyN4MtWDmV\n1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1z6qqEDcM8FtHoAXAdxQB\nkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9cMY1cCEBxpwQTJiJHbX9\nLcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MUS89+DsixFf3HL+iWjr6y\nVnQ/mAGVPQ+HD4pwmQIDAQABo4IC3jCCAtowHwYDVR0jBBgwFoAUtBIopbTAHZ8p\ncWk82RGWSnVpUMAwHQYDVR0OBBYEFHqqdlMVBlcadf7iJLJoLnLZ7h4tMB8GA1Ud\nEQQYMBaCFGFsbGluc3NsLnphY2h5YW5nLmNuMD4GA1UdIAQ3MDUwMwYGZ4EMAQIB\nMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNV\nHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHkGCCsG\nAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t\nMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vVHJ1c3RB\nc2lhRFZUTFNSU0FDQTIwMjUuY3J0MAwGA1UdEwEB/wQCMAAwggF9BgorBgEEAdZ5\nAgQCBIIBbQSCAWkBZwB2ABLxTjS9U3JMhAYZw48/ehP457Vih4icbTAFhOvlhiY6\nAAABll0w/o0AAAQDAEcwRQIgd24jCPm+fbHq3grMIxtvQhzkv7dvYPM/BGjPEsy1\nQ70CIQC5jXADjBh+dH50T+atn3lktBEqQhedOl6cAaP/XXmk6gB2AO08S9boBsKk\nogBX28sk4jgB31Ev7cSGxXAPIN23Pj/gAAABll0w/rUAAAQDAEcwRQIgU2GDVEH1\ns5i/RC1RhqvJjn72PAZOlDtJyLdg29vC9HECIQCj78GATYK5quitLxbn3HvD8BeT\noOz+3tacgyN6+TdvugB1AKRCxQZJYGFUjw/U6pz7ei0mRU2HqX8v30VZ9idPOoRU\nAAABll0w/sYAAAQDAEYwRAIgCvU/iBRPKoJLjmU4edBYObWAO/aJp2mWnfJ4ieAr\nrXsCIBsAppYu28h8YEOl0N9yEeF9G05IMxwkCjZKonQs2SKMMA0GCSqGSIb3DQEB\nCwUAA4ICAQB3wFou51Qvl4apMhencuQUnWF3UpYP49e0WQ72DVT3pYjYsozkSuqb\nQZcwMB6HDoHdFicxvQ/yxKyTu/nw3rXjUWYuSxXYd7lJcQ/R0tR00m6AFeinY4Aq\nq4QqoA+lriK1XqO5MomAL4FbSysT1ow/gaG9pYuXEdT4pr05I/NumjXdkwBRZOd4\nrhol2grKf3y37Qla5hUbbG3ab9nf/csJSWkCoESeXr3MB1oAU/aL9pGSagvMXSKQ\nsFs2cn2Fi8ZmJPJXIP114lgvFuFDO+C1yTNbHap/FufvAKGryfPDuPecCF6FSXej\n+bwg4/BNz5lcHbNo2XXjLgoPg4VE6mG/SQQZQEDBk5DowwMVMvh77t9RBNrHozah\nHGtQz2hCuIX7rZQYnSlvW8T75FhI/Sd+HEfU/iyTIELXBUjypnK2bOJL7+jE7f79\nuljhXlCcP52fGHCjexNBz5gIZr82KVxsfxKuZjfioPkhmWleVNMdMWYJRXu618E6\nNtNjUVsDCuMOOMNs1qScqxOT60MeDZLX+vnC93fdd/t2hLEAWWNNMkWeX2qLCE1q\nGarop9U1mJpiBWkW5cBiqnNIbhuV2fcwFIR8mVT5f1Qcw+WxE2nEjY2h75bKv8T5\n3RBngmaX8PcyLAP2s0/4UyzAnMYfioJBh37VpUYBrdriBkRds/AMZw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFnjCCBIagAwIBAgIQCSYyO0lk42hGFRLe8aXVLDANBgkqhkiG9w0BAQsFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\nMjAeFw0yNTAxMDgwMDAwMDBaFw0zNTAxMDcyMzU5NTlaMFsxCzAJBgNVBAYTAkNO\nMSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSUwIwYDVQQD\nExxUcnVzdEFzaWEgRFYgVExTIFJTQSBDQSAyMDI1MIICIjANBgkqhkiG9w0BAQEF\nAAOCAg8AMIICCgKCAgEA0fuEmuBIsN6ZZVq+gRobMorOGIilTCIfQrxNpR8FUZ9R\n/GfbiekbiIKphQXEZ7N1uBnn6tXUuZ32zl6jPkZpHzN/Bmgk1BWSIzVc0npMzrWq\n/hrbk5+KddXJdsNpeG1+Q8lc8uVMBrztnxaPb7Rh7yQCsMrcO4hgVaqLJWkVvEfW\nULtoCHQnNaj4IroG6VxQf1oArQ8bPbwpI02lieSahRa78FQuXdoGVeQcrkhtVjZs\nON98vq5fPWZX2LFv7e5J6P9IHbzvOl8yyQjv+2/IOwhNSkaXX3bI+//bqF9XW/p7\n+gsUmHiK5YsvLjmXcvDmoDEGrXMzgX31Zl2nJ+umpRbLjwP8rxYIUsKoEwEdFoto\nAid59UEBJyw/GibwXQ5xTyKD/N6C8SFkr1+myOo4oe1UB+YgvRu6qSxIABo5kYdX\nFodLP4IgoVJdeUFs1Usa6bxYEO6EgMf5lCWt9hGZszvXYZwvyZGq3ogNXM7eKyi2\n20WzJXYMmi9TYFq2Fa95aZe4wki6YhDhhOO1g0sjITGVaB73G+JOCI9yJhv6+REN\nD40ZpboUHE8JNgMVWbG1isAMVCXqiADgXtuC+tmJWPEH9cR6OuJLEpwOzPfgAbnn\n2MRu7Tsdr8jPjTPbD0FxblX1ydW3RG30vwLF5lkTTRkHG9epMgpPMdYP7nY/08MC\nAwEAAaOCAVYwggFSMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLQSKKW0\nwB2fKXFpPNkRlkp1aVDAMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485\nMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\ndgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy\ndC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E\naWdpQ2VydEdsb2JhbFJvb3RHMi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov\nL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDARBgNV\nHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBAJ4a3svh316GY2+Z7EYx\nmBIsOwjJSnyoEfzx2T699ctLLrvuzS79Mg3pPjxSLlUgyM8UzrFc5tgVU3dZ1sFQ\nI4RM+ysJdvIAX/7Yx1QbooVdKhkdi9X7QN7yVkjqwM3fY3WfQkRTzhIkM7mYIQbR\nr+y2Vkju61BLqh7OCRpPMiudjEpP1kEtRyGs2g0aQpEIqKBzxgitCXSayO1hoO6/\n71ts801OzYlqYW9OQQQ2GCJyFbD6XHDjdpn+bWUxTKWaMY0qedSCbHE3Kl2QEF0C\nynZ7SbC03yR+gKZQDeTXrNP1kk5Qhe7jSXgw+nhbspe0q/M1ZcNCz+sPxeOwdCcC\ngJE=\n-----END CERTIFICATE-----",
|
||||
"issuer": "cert-issuer",
|
||||
},
|
||||
}
|
||||
err := DeployBtSite(cfg)
|
||||
println(err)
|
||||
}
|
||||
|
||||
func TestBTP(t *testing.T) {
|
||||
cfg := map[string]any{
|
||||
"site_id": "1",
|
||||
"provider_id": "19",
|
||||
"certificate": map[string]any{
|
||||
"key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAxIjmAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONh\nWhMT6W+cx0WMC80yCRm5JshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM\n4tz/Zh8a3kVyN4MtWDmV1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1\nz6qqEDcM8FtHoAXAdxQBkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9\ncMY1cCEBxpwQTJiJHbX9LcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MU\nS89+DsixFf3HL+iWjr6yVnQ/mAGVPQ+HD4pwmQIDAQABAoIBAALpcFb59MBZZHJ3\nui9RRi96ig6kPQoRjkjN83pjM+/h/bANMmUOQU5FHBKLwj5uhN5Dpk2fzAnIX2TE\nVgfyNGsYuWLsIM+m6EJfm7pXJwJDr3RCpm+6DIKr1U8TwlR2OhbDi6fOlfH66q79\n2Klq4SXsa0vgfllpTVCDtydFVjwAuQV7Cf6DGRjbNpN3DPLeOC1wYFimNZwudSK0\nf8grWpPFXw2TPaf3TgeBGxwL7GCTYSKT+Eq9USbhG4RArrM9oQt+h7rzaH2bFEdg\n7tOM4KIgV+aw8r0TsYisDG9dfiHfHr5vQnkmWgt/rxAOvHlJ7/64pBVuET1ZF0mB\nP6gu4Y0CgYEAzkwXvfnHI5qx9BVP6e9lGrpWrm0RxCKr2iCCwrOVALbX1yfKCb5L\nrP/jSERMuLt6bIKg/AoVu9ogCTGzntyHTbZXFGg/y5Xoul+1af2arQ1rGZ7A/Im7\nnteZePg2U6UiDRy07F94FF5aL/v97D4BffiSA+0atlgH6tpKyYfY6NsCgYEA8+Ku\nGQqX9kHDd5bbzPhLelNmHVnAjnMaHEhvzVtBA737F10Oqg9wyffqe/i/DvdUSx9r\nafKGUfzB2vVZjz//OpSQ8VhRzDTiyelKLsSTmzOokLBnwayyTxw85o9EDvTNrzfb\nYQbAjmAXWmnv5Xvx1KfvTaKFY3BmHsKYJDzwnJsCgYBK1SVjn2CSVMIqlTSI2nMl\nb+STnzLrn9wQ4uwr7nKlcK34+RD72dCfr67lfwkJldBB3lzBMHNT0jr+us26Waqn\nEPaji3Fgyz9BpAgtq3XZQl3QTFsbAGdTpkegrwEd9G/Wq8whVjw7v0Id193zPUbT\nSEDHNdITxPkSQx8P3bxcMwKBgQDO5EGk5KO9OFTFoqib3RbKku1RgM4lCefgjmKp\n5vvkXMohK8RA6BBahYHZ4U7TN2W+xMyueBsSekVJplFvgG7YFyhOVQovHb42Yz2X\nJxPA2bXp6HxchFBPZDkVrfuiZHIIbm4ghUXcgg/Nl4j3OIoSSNRtG63kiXlYJuRB\n+aB0eQKBgD79VrREpbOMS7HRlDTtfkDN94HY3T4MLErs26z/NLO/dC44tmBJGo2P\ngcQ+p7XxNjpWUnUbEiuz4R3Xgh6ULwuSseWtcQicolPHTkBjnc+6BEpyguZJ+FPZ\nGls3g3LxjGhdPlyd37CaWDvx/Jtjrd4Y9iGkGO2d9fXZD0Hg0ymX\n-----END RSA PRIVATE KEY-----",
|
||||
"cert": "-----BEGIN CERTIFICATE-----\nMIIG5DCCBMygAwIBAgIQBPQGlt81+4RKt3RAFXPvrjANBgkqhkiG9w0BAQsFADBb\nMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg\nSW5jLjElMCMGA1UEAxMcVHJ1c3RBc2lhIERWIFRMUyBSU0EgQ0EgMjAyNTAeFw0y\nNTA0MjIwMDAwMDBaFw0yNTA3MjAyMzU5NTlaMB8xHTAbBgNVBAMTFGFsbGluc3Ns\nLnphY2h5YW5nLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxIjm\nAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONhWhMT6W+cx0WMC80yCRm5\nJshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM4tz/Zh8a3kVyN4MtWDmV\n1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1z6qqEDcM8FtHoAXAdxQB\nkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9cMY1cCEBxpwQTJiJHbX9\nLcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MUS89+DsixFf3HL+iWjr6y\nVnQ/mAGVPQ+HD4pwmQIDAQABo4IC3jCCAtowHwYDVR0jBBgwFoAUtBIopbTAHZ8p\ncWk82RGWSnVpUMAwHQYDVR0OBBYEFHqqdlMVBlcadf7iJLJoLnLZ7h4tMB8GA1Ud\nEQQYMBaCFGFsbGluc3NsLnphY2h5YW5nLmNuMD4GA1UdIAQ3MDUwMwYGZ4EMAQIB\nMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNV\nHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHkGCCsG\nAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t\nMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vVHJ1c3RB\nc2lhRFZUTFNSU0FDQTIwMjUuY3J0MAwGA1UdEwEB/wQCMAAwggF9BgorBgEEAdZ5\nAgQCBIIBbQSCAWkBZwB2ABLxTjS9U3JMhAYZw48/ehP457Vih4icbTAFhOvlhiY6\nAAABll0w/o0AAAQDAEcwRQIgd24jCPm+fbHq3grMIxtvQhzkv7dvYPM/BGjPEsy1\nQ70CIQC5jXADjBh+dH50T+atn3lktBEqQhedOl6cAaP/XXmk6gB2AO08S9boBsKk\nogBX28sk4jgB31Ev7cSGxXAPIN23Pj/gAAABll0w/rUAAAQDAEcwRQIgU2GDVEH1\ns5i/RC1RhqvJjn72PAZOlDtJyLdg29vC9HECIQCj78GATYK5quitLxbn3HvD8BeT\noOz+3tacgyN6+TdvugB1AKRCxQZJYGFUjw/U6pz7ei0mRU2HqX8v30VZ9idPOoRU\nAAABll0w/sYAAAQDAEYwRAIgCvU/iBRPKoJLjmU4edBYObWAO/aJp2mWnfJ4ieAr\nrXsCIBsAppYu28h8YEOl0N9yEeF9G05IMxwkCjZKonQs2SKMMA0GCSqGSIb3DQEB\nCwUAA4ICAQB3wFou51Qvl4apMhencuQUnWF3UpYP49e0WQ72DVT3pYjYsozkSuqb\nQZcwMB6HDoHdFicxvQ/yxKyTu/nw3rXjUWYuSxXYd7lJcQ/R0tR00m6AFeinY4Aq\nq4QqoA+lriK1XqO5MomAL4FbSysT1ow/gaG9pYuXEdT4pr05I/NumjXdkwBRZOd4\nrhol2grKf3y37Qla5hUbbG3ab9nf/csJSWkCoESeXr3MB1oAU/aL9pGSagvMXSKQ\nsFs2cn2Fi8ZmJPJXIP114lgvFuFDO+C1yTNbHap/FufvAKGryfPDuPecCF6FSXej\n+bwg4/BNz5lcHbNo2XXjLgoPg4VE6mG/SQQZQEDBk5DowwMVMvh77t9RBNrHozah\nHGtQz2hCuIX7rZQYnSlvW8T75FhI/Sd+HEfU/iyTIELXBUjypnK2bOJL7+jE7f79\nuljhXlCcP52fGHCjexNBz5gIZr82KVxsfxKuZjfioPkhmWleVNMdMWYJRXu618E6\nNtNjUVsDCuMOOMNs1qScqxOT60MeDZLX+vnC93fdd/t2hLEAWWNNMkWeX2qLCE1q\nGarop9U1mJpiBWkW5cBiqnNIbhuV2fcwFIR8mVT5f1Qcw+WxE2nEjY2h75bKv8T5\n3RBngmaX8PcyLAP2s0/4UyzAnMYfioJBh37VpUYBrdriBkRds/AMZw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFnjCCBIagAwIBAgIQCSYyO0lk42hGFRLe8aXVLDANBgkqhkiG9w0BAQsFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\nMjAeFw0yNTAxMDgwMDAwMDBaFw0zNTAxMDcyMzU5NTlaMFsxCzAJBgNVBAYTAkNO\nMSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSUwIwYDVQQD\nExxUcnVzdEFzaWEgRFYgVExTIFJTQSBDQSAyMDI1MIICIjANBgkqhkiG9w0BAQEF\nAAOCAg8AMIICCgKCAgEA0fuEmuBIsN6ZZVq+gRobMorOGIilTCIfQrxNpR8FUZ9R\n/GfbiekbiIKphQXEZ7N1uBnn6tXUuZ32zl6jPkZpHzN/Bmgk1BWSIzVc0npMzrWq\n/hrbk5+KddXJdsNpeG1+Q8lc8uVMBrztnxaPb7Rh7yQCsMrcO4hgVaqLJWkVvEfW\nULtoCHQnNaj4IroG6VxQf1oArQ8bPbwpI02lieSahRa78FQuXdoGVeQcrkhtVjZs\nON98vq5fPWZX2LFv7e5J6P9IHbzvOl8yyQjv+2/IOwhNSkaXX3bI+//bqF9XW/p7\n+gsUmHiK5YsvLjmXcvDmoDEGrXMzgX31Zl2nJ+umpRbLjwP8rxYIUsKoEwEdFoto\nAid59UEBJyw/GibwXQ5xTyKD/N6C8SFkr1+myOo4oe1UB+YgvRu6qSxIABo5kYdX\nFodLP4IgoVJdeUFs1Usa6bxYEO6EgMf5lCWt9hGZszvXYZwvyZGq3ogNXM7eKyi2\n20WzJXYMmi9TYFq2Fa95aZe4wki6YhDhhOO1g0sjITGVaB73G+JOCI9yJhv6+REN\nD40ZpboUHE8JNgMVWbG1isAMVCXqiADgXtuC+tmJWPEH9cR6OuJLEpwOzPfgAbnn\n2MRu7Tsdr8jPjTPbD0FxblX1ydW3RG30vwLF5lkTTRkHG9epMgpPMdYP7nY/08MC\nAwEAAaOCAVYwggFSMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLQSKKW0\nwB2fKXFpPNkRlkp1aVDAMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485\nMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\ndgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy\ndC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E\naWdpQ2VydEdsb2JhbFJvb3RHMi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov\nL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDARBgNV\nHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBAJ4a3svh316GY2+Z7EYx\nmBIsOwjJSnyoEfzx2T699ctLLrvuzS79Mg3pPjxSLlUgyM8UzrFc5tgVU3dZ1sFQ\nI4RM+ysJdvIAX/7Yx1QbooVdKhkdi9X7QN7yVkjqwM3fY3WfQkRTzhIkM7mYIQbR\nr+y2Vkju61BLqh7OCRpPMiudjEpP1kEtRyGs2g0aQpEIqKBzxgitCXSayO1hoO6/\n71ts801OzYlqYW9OQQQ2GCJyFbD6XHDjdpn+bWUxTKWaMY0qedSCbHE3Kl2QEF0C\nynZ7SbC03yR+gKZQDeTXrNP1kk5Qhe7jSXgw+nhbspe0q/M1ZcNCz+sPxeOwdCcC\ngJE=\n-----END CERTIFICATE-----",
|
||||
"issuer": "cert-issuer",
|
||||
},
|
||||
}
|
||||
err := DeployBt(cfg)
|
||||
println(err)
|
||||
}
|
||||
158
backend/internal/cert/deploy/btpanel.go
Normal file
158
backend/internal/cert/deploy/btpanel.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/access"
|
||||
"crypto/md5"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func generateSignature(timestamp, apiKey string) string {
|
||||
keyMd5 := md5.Sum([]byte(apiKey))
|
||||
keyMd5Hex := strings.ToLower(hex.EncodeToString(keyMd5[:]))
|
||||
|
||||
signMd5 := md5.Sum([]byte(timestamp + keyMd5Hex))
|
||||
signMd5Hex := strings.ToLower(hex.EncodeToString(signMd5[:]))
|
||||
return signMd5Hex
|
||||
}
|
||||
|
||||
func RequestBt(data *url.Values, method, providerID, requestUrl string) (map[string]any, error) {
|
||||
providerData, err := access.GetAccess(providerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
providerConfigStr, ok := providerData["config"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("api配置错误")
|
||||
}
|
||||
// 解析 JSON 配置
|
||||
var providerConfig map[string]string
|
||||
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
timestamp := time.Now().Unix()
|
||||
token := generateSignature(fmt.Sprintf("%d", timestamp), providerConfig["api_key"])
|
||||
if providerConfig["url"][len(providerConfig["url"])-1:] != "/" {
|
||||
providerConfig["url"] += "/"
|
||||
}
|
||||
|
||||
data.Set("request_time", fmt.Sprintf("%d", timestamp))
|
||||
data.Set("request_token", token)
|
||||
|
||||
req, err := http.NewRequest(method, providerConfig["url"]+requestUrl, strings.NewReader(data.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36")
|
||||
// 自定义 Transport,跳过 SSL 证书验证
|
||||
ignoreSsl := false
|
||||
if providerConfig["ignore_ssl"] == "1" {
|
||||
ignoreSsl = true
|
||||
}
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: ignoreSsl},
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: tr}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
// fmt.Println(err)
|
||||
return nil, fmt.Errorf("请求BT失败: %v", err)
|
||||
}
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
|
||||
var res map[string]interface{}
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("返回值解析失败: %v", err)
|
||||
}
|
||||
|
||||
if res["status"] != nil && !res["status"].(bool) {
|
||||
return nil, fmt.Errorf("请求出错: %s", res["msg"].(string))
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func DeployBt(cfg map[string]any) error {
|
||||
cert, ok := cfg["certificate"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书不存在")
|
||||
}
|
||||
// 设置证书
|
||||
keyPem, ok := cert["key"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:key")
|
||||
}
|
||||
certPem, ok := cert["cert"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:cert")
|
||||
}
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
data := url.Values{}
|
||||
data.Set("cert_type", "1")
|
||||
data.Set("privateKey", keyPem)
|
||||
data.Set("certPem", certPem)
|
||||
_, err := RequestBt(&data, "POST", providerID, "/config?action=SetPanelSSL")
|
||||
if err != nil {
|
||||
return fmt.Errorf("证书部署失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeployBtSite(cfg map[string]any) error {
|
||||
cert, ok := cfg["certificate"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书不存在")
|
||||
}
|
||||
// 设置证书
|
||||
keyPem, ok := cert["key"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:key")
|
||||
}
|
||||
certPem, ok := cert["cert"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:cert")
|
||||
}
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
siteName, ok := cfg["siteName"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:siteName")
|
||||
}
|
||||
data := url.Values{}
|
||||
data.Set("key", keyPem)
|
||||
data.Set("csr", certPem)
|
||||
data.Set("siteName", siteName)
|
||||
_, err := RequestBt(&data, "POST", providerID, "/site?action=SetSSL")
|
||||
if err != nil {
|
||||
return fmt.Errorf("证书部署失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
45
backend/internal/cert/deploy/deploy.go
Normal file
45
backend/internal/cert/deploy/deploy.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/public"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func Deploy(cfg map[string]any, logger *public.Logger) error {
|
||||
providerName, ok := cfg["provider"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("provider is not string")
|
||||
}
|
||||
switch providerName {
|
||||
case "btpanel":
|
||||
logger.Debug("部署到宝塔面板...")
|
||||
return DeployBt(cfg)
|
||||
case "btpanel-site":
|
||||
logger.Debug("部署到宝塔面板网站...")
|
||||
return DeployBtSite(cfg)
|
||||
case "tencentcloud-cdn":
|
||||
cfg["resource_type"] = "cdn"
|
||||
logger.Debug("部署到腾讯云CDN...")
|
||||
return DeployToTX(cfg)
|
||||
case "tencentcloud-cos":
|
||||
cfg["resource_type"] = "cos"
|
||||
logger.Debug("部署到腾讯云COS...")
|
||||
return DeployToTX(cfg)
|
||||
case "1panel":
|
||||
logger.Debug("部署到1Panel...")
|
||||
return Deploy1panel(cfg)
|
||||
case "1panel-site":
|
||||
logger.Debug("部署到1Panel网站...")
|
||||
return Deploy1panelSite(cfg)
|
||||
case "ssh":
|
||||
logger.Debug("使用ssh部署到指定路径...")
|
||||
return DeploySSH(cfg)
|
||||
case "aliyun-cdn":
|
||||
logger.Debug("部署到阿里云CDN...")
|
||||
return DeployAliCdn(cfg)
|
||||
// case "aliyun-oss":
|
||||
|
||||
default:
|
||||
return fmt.Errorf("不支持的部署: %s", providerName)
|
||||
}
|
||||
}
|
||||
163
backend/internal/cert/deploy/ssh.go
Normal file
163
backend/internal/cert/deploy/ssh.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/access"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"path"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type SSHConfig struct {
|
||||
User string
|
||||
Password string // 可选
|
||||
PrivateKey string // 可选
|
||||
Host string
|
||||
Port string
|
||||
}
|
||||
|
||||
type RemoteFile struct {
|
||||
Path string
|
||||
Content string
|
||||
}
|
||||
|
||||
func buildAuthMethods(password, privateKey string) ([]ssh.AuthMethod, error) {
|
||||
var methods []ssh.AuthMethod
|
||||
|
||||
if privateKey != "" {
|
||||
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse private key: %v", err)
|
||||
}
|
||||
methods = append(methods, ssh.PublicKeys(signer))
|
||||
}
|
||||
|
||||
if password != "" {
|
||||
methods = append(methods, ssh.Password(password))
|
||||
}
|
||||
|
||||
if len(methods) == 0 {
|
||||
return nil, fmt.Errorf("no authentication methods provided")
|
||||
}
|
||||
|
||||
return methods, nil
|
||||
}
|
||||
|
||||
func writeMultipleFilesViaSSH(config SSHConfig, files []RemoteFile, preCmd, postCmd string) error {
|
||||
addr := fmt.Sprintf("%s:%s", config.Host, config.Port)
|
||||
|
||||
authMethods, err := buildAuthMethods(config.Password, config.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: config.User,
|
||||
Auth: authMethods,
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
|
||||
client, err := ssh.Dial("tcp", addr, sshConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to dial: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
return fmt.Errorf("会话创建失败: %v", err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
var script bytes.Buffer
|
||||
|
||||
if preCmd != "" {
|
||||
script.WriteString(preCmd + " && ")
|
||||
}
|
||||
|
||||
for i, file := range files {
|
||||
if i > 0 {
|
||||
script.WriteString(" && ")
|
||||
}
|
||||
|
||||
dirCmd := fmt.Sprintf("mkdir -p $(dirname %q)", file.Path)
|
||||
writeCmd := fmt.Sprintf("printf %%s '%s' > %s", file.Content, file.Path)
|
||||
|
||||
script.WriteString(dirCmd + " && " + writeCmd)
|
||||
}
|
||||
|
||||
if postCmd != "" {
|
||||
script.WriteString(" && " + postCmd)
|
||||
}
|
||||
|
||||
cmd := script.String()
|
||||
|
||||
if err := session.Run(cmd); err != nil {
|
||||
return fmt.Errorf("运行出错: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeploySSH(cfg map[string]any) error {
|
||||
cert, ok := cfg["certificate"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书不存在")
|
||||
}
|
||||
// 设置证书
|
||||
keyPem, ok := cert["key"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:key")
|
||||
}
|
||||
certPem, ok := cert["cert"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:cert")
|
||||
}
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
dir, ok := cfg["path"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:path")
|
||||
}
|
||||
beforeCmd, ok := cfg["beforeCmd"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:beforeCmd")
|
||||
}
|
||||
afterCmd, ok := cfg["afterCmd"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:afterCmd")
|
||||
}
|
||||
providerData, err := access.GetAccess(providerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerConfigStr, ok := providerData["config"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("api配置错误")
|
||||
}
|
||||
// 解析 JSON 配置
|
||||
var providerConfig SSHConfig
|
||||
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 自动创建多级目录
|
||||
files := []RemoteFile{
|
||||
{Path: path.Join(dir, "cert.pem"), Content: certPem},
|
||||
{Path: path.Join(dir, "key.pem"), Content: keyPem},
|
||||
}
|
||||
err = writeMultipleFilesViaSSH(providerConfig, files, beforeCmd, afterCmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("SSH 部署失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
22
backend/internal/cert/deploy/ssh_test.go
Normal file
22
backend/internal/cert/deploy/ssh_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package deploy
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSSH(t *testing.T) {
|
||||
cfg := map[string]any{
|
||||
"path": "/www/ccccc",
|
||||
"beforeCmd": "touch /www/ccccc/xxxxx.txt",
|
||||
"afterCmd": "touch /www/ccccc/cccccc.txt",
|
||||
"provider_id": "23",
|
||||
"certificate": map[string]any{
|
||||
"key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAxIjmAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONh\nWhMT6W+cx0WMC80yCRm5JshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM\n4tz/Zh8a3kVyN4MtWDmV1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1\nz6qqEDcM8FtHoAXAdxQBkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9\ncMY1cCEBxpwQTJiJHbX9LcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MU\nS89+DsixFf3HL+iWjr6yVnQ/mAGVPQ+HD4pwmQIDAQABAoIBAALpcFb59MBZZHJ3\nui9RRi96ig6kPQoRjkjN83pjM+/h/bANMmUOQU5FHBKLwj5uhN5Dpk2fzAnIX2TE\nVgfyNGsYuWLsIM+m6EJfm7pXJwJDr3RCpm+6DIKr1U8TwlR2OhbDi6fOlfH66q79\n2Klq4SXsa0vgfllpTVCDtydFVjwAuQV7Cf6DGRjbNpN3DPLeOC1wYFimNZwudSK0\nf8grWpPFXw2TPaf3TgeBGxwL7GCTYSKT+Eq9USbhG4RArrM9oQt+h7rzaH2bFEdg\n7tOM4KIgV+aw8r0TsYisDG9dfiHfHr5vQnkmWgt/rxAOvHlJ7/64pBVuET1ZF0mB\nP6gu4Y0CgYEAzkwXvfnHI5qx9BVP6e9lGrpWrm0RxCKr2iCCwrOVALbX1yfKCb5L\nrP/jSERMuLt6bIKg/AoVu9ogCTGzntyHTbZXFGg/y5Xoul+1af2arQ1rGZ7A/Im7\nnteZePg2U6UiDRy07F94FF5aL/v97D4BffiSA+0atlgH6tpKyYfY6NsCgYEA8+Ku\nGQqX9kHDd5bbzPhLelNmHVnAjnMaHEhvzVtBA737F10Oqg9wyffqe/i/DvdUSx9r\nafKGUfzB2vVZjz//OpSQ8VhRzDTiyelKLsSTmzOokLBnwayyTxw85o9EDvTNrzfb\nYQbAjmAXWmnv5Xvx1KfvTaKFY3BmHsKYJDzwnJsCgYBK1SVjn2CSVMIqlTSI2nMl\nb+STnzLrn9wQ4uwr7nKlcK34+RD72dCfr67lfwkJldBB3lzBMHNT0jr+us26Waqn\nEPaji3Fgyz9BpAgtq3XZQl3QTFsbAGdTpkegrwEd9G/Wq8whVjw7v0Id193zPUbT\nSEDHNdITxPkSQx8P3bxcMwKBgQDO5EGk5KO9OFTFoqib3RbKku1RgM4lCefgjmKp\n5vvkXMohK8RA6BBahYHZ4U7TN2W+xMyueBsSekVJplFvgG7YFyhOVQovHb42Yz2X\nJxPA2bXp6HxchFBPZDkVrfuiZHIIbm4ghUXcgg/Nl4j3OIoSSNRtG63kiXlYJuRB\n+aB0eQKBgD79VrREpbOMS7HRlDTtfkDN94HY3T4MLErs26z/NLO/dC44tmBJGo2P\ngcQ+p7XxNjpWUnUbEiuz4R3Xgh6ULwuSseWtcQicolPHTkBjnc+6BEpyguZJ+FPZ\nGls3g3LxjGhdPlyd37CaWDvx/Jtjrd4Y9iGkGO2d9fXZD0Hg0ymX\n-----END RSA PRIVATE KEY-----",
|
||||
"cert": "-----BEGIN CERTIFICATE-----\nMIIG5DCCBMygAwIBAgIQBPQGlt81+4RKt3RAFXPvrjANBgkqhkiG9w0BAQsFADBb\nMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg\nSW5jLjElMCMGA1UEAxMcVHJ1c3RBc2lhIERWIFRMUyBSU0EgQ0EgMjAyNTAeFw0y\nNTA0MjIwMDAwMDBaFw0yNTA3MjAyMzU5NTlaMB8xHTAbBgNVBAMTFGFsbGluc3Ns\nLnphY2h5YW5nLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxIjm\nAi/paC2OmG7nOqZ+OJx7spDrx7yZiWvn1XgLW/5ODONhWhMT6W+cx0WMC80yCRm5\nJshIIMzmMxN03pRD1h4u1fPNUnJmGtthRZIm3aU7TlSM4tz/Zh8a3kVyN4MtWDmV\n1/1MV8H0YBtT6K2gxZ7Fz/YKhVATdh8Fy+1qEz3gSrw1z6qqEDcM8FtHoAXAdxQB\nkS8xu34SIriwZiN2YlrtL8Qy73j4XiJLh2cc/NPp+mW9cMY1cCEBxpwQTJiJHbX9\nLcEqYgOkkhWIijW2dYlCLaLsnvJw0TCRd6PooR8XK7MUS89+DsixFf3HL+iWjr6y\nVnQ/mAGVPQ+HD4pwmQIDAQABo4IC3jCCAtowHwYDVR0jBBgwFoAUtBIopbTAHZ8p\ncWk82RGWSnVpUMAwHQYDVR0OBBYEFHqqdlMVBlcadf7iJLJoLnLZ7h4tMB8GA1Ud\nEQQYMBaCFGFsbGluc3NsLnphY2h5YW5nLmNuMD4GA1UdIAQ3MDUwMwYGZ4EMAQIB\nMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNV\nHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHkGCCsG\nAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t\nMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vVHJ1c3RB\nc2lhRFZUTFNSU0FDQTIwMjUuY3J0MAwGA1UdEwEB/wQCMAAwggF9BgorBgEEAdZ5\nAgQCBIIBbQSCAWkBZwB2ABLxTjS9U3JMhAYZw48/ehP457Vih4icbTAFhOvlhiY6\nAAABll0w/o0AAAQDAEcwRQIgd24jCPm+fbHq3grMIxtvQhzkv7dvYPM/BGjPEsy1\nQ70CIQC5jXADjBh+dH50T+atn3lktBEqQhedOl6cAaP/XXmk6gB2AO08S9boBsKk\nogBX28sk4jgB31Ev7cSGxXAPIN23Pj/gAAABll0w/rUAAAQDAEcwRQIgU2GDVEH1\ns5i/RC1RhqvJjn72PAZOlDtJyLdg29vC9HECIQCj78GATYK5quitLxbn3HvD8BeT\noOz+3tacgyN6+TdvugB1AKRCxQZJYGFUjw/U6pz7ei0mRU2HqX8v30VZ9idPOoRU\nAAABll0w/sYAAAQDAEYwRAIgCvU/iBRPKoJLjmU4edBYObWAO/aJp2mWnfJ4ieAr\nrXsCIBsAppYu28h8YEOl0N9yEeF9G05IMxwkCjZKonQs2SKMMA0GCSqGSIb3DQEB\nCwUAA4ICAQB3wFou51Qvl4apMhencuQUnWF3UpYP49e0WQ72DVT3pYjYsozkSuqb\nQZcwMB6HDoHdFicxvQ/yxKyTu/nw3rXjUWYuSxXYd7lJcQ/R0tR00m6AFeinY4Aq\nq4QqoA+lriK1XqO5MomAL4FbSysT1ow/gaG9pYuXEdT4pr05I/NumjXdkwBRZOd4\nrhol2grKf3y37Qla5hUbbG3ab9nf/csJSWkCoESeXr3MB1oAU/aL9pGSagvMXSKQ\nsFs2cn2Fi8ZmJPJXIP114lgvFuFDO+C1yTNbHap/FufvAKGryfPDuPecCF6FSXej\n+bwg4/BNz5lcHbNo2XXjLgoPg4VE6mG/SQQZQEDBk5DowwMVMvh77t9RBNrHozah\nHGtQz2hCuIX7rZQYnSlvW8T75FhI/Sd+HEfU/iyTIELXBUjypnK2bOJL7+jE7f79\nuljhXlCcP52fGHCjexNBz5gIZr82KVxsfxKuZjfioPkhmWleVNMdMWYJRXu618E6\nNtNjUVsDCuMOOMNs1qScqxOT60MeDZLX+vnC93fdd/t2hLEAWWNNMkWeX2qLCE1q\nGarop9U1mJpiBWkW5cBiqnNIbhuV2fcwFIR8mVT5f1Qcw+WxE2nEjY2h75bKv8T5\n3RBngmaX8PcyLAP2s0/4UyzAnMYfioJBh37VpUYBrdriBkRds/AMZw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFnjCCBIagAwIBAgIQCSYyO0lk42hGFRLe8aXVLDANBgkqhkiG9w0BAQsFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\nMjAeFw0yNTAxMDgwMDAwMDBaFw0zNTAxMDcyMzU5NTlaMFsxCzAJBgNVBAYTAkNO\nMSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSUwIwYDVQQD\nExxUcnVzdEFzaWEgRFYgVExTIFJTQSBDQSAyMDI1MIICIjANBgkqhkiG9w0BAQEF\nAAOCAg8AMIICCgKCAgEA0fuEmuBIsN6ZZVq+gRobMorOGIilTCIfQrxNpR8FUZ9R\n/GfbiekbiIKphQXEZ7N1uBnn6tXUuZ32zl6jPkZpHzN/Bmgk1BWSIzVc0npMzrWq\n/hrbk5+KddXJdsNpeG1+Q8lc8uVMBrztnxaPb7Rh7yQCsMrcO4hgVaqLJWkVvEfW\nULtoCHQnNaj4IroG6VxQf1oArQ8bPbwpI02lieSahRa78FQuXdoGVeQcrkhtVjZs\nON98vq5fPWZX2LFv7e5J6P9IHbzvOl8yyQjv+2/IOwhNSkaXX3bI+//bqF9XW/p7\n+gsUmHiK5YsvLjmXcvDmoDEGrXMzgX31Zl2nJ+umpRbLjwP8rxYIUsKoEwEdFoto\nAid59UEBJyw/GibwXQ5xTyKD/N6C8SFkr1+myOo4oe1UB+YgvRu6qSxIABo5kYdX\nFodLP4IgoVJdeUFs1Usa6bxYEO6EgMf5lCWt9hGZszvXYZwvyZGq3ogNXM7eKyi2\n20WzJXYMmi9TYFq2Fa95aZe4wki6YhDhhOO1g0sjITGVaB73G+JOCI9yJhv6+REN\nD40ZpboUHE8JNgMVWbG1isAMVCXqiADgXtuC+tmJWPEH9cR6OuJLEpwOzPfgAbnn\n2MRu7Tsdr8jPjTPbD0FxblX1ydW3RG30vwLF5lkTTRkHG9epMgpPMdYP7nY/08MC\nAwEAAaOCAVYwggFSMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLQSKKW0\nwB2fKXFpPNkRlkp1aVDAMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485\nMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\ndgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy\ndC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E\naWdpQ2VydEdsb2JhbFJvb3RHMi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov\nL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDARBgNV\nHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBAJ4a3svh316GY2+Z7EYx\nmBIsOwjJSnyoEfzx2T699ctLLrvuzS79Mg3pPjxSLlUgyM8UzrFc5tgVU3dZ1sFQ\nI4RM+ysJdvIAX/7Yx1QbooVdKhkdi9X7QN7yVkjqwM3fY3WfQkRTzhIkM7mYIQbR\nr+y2Vkju61BLqh7OCRpPMiudjEpP1kEtRyGs2g0aQpEIqKBzxgitCXSayO1hoO6/\n71ts801OzYlqYW9OQQQ2GCJyFbD6XHDjdpn+bWUxTKWaMY0qedSCbHE3Kl2QEF0C\nynZ7SbC03yR+gKZQDeTXrNP1kk5Qhe7jSXgw+nhbspe0q/M1ZcNCz+sPxeOwdCcC\ngJE=\n-----END CERTIFICATE-----",
|
||||
"issuer": "cert-issuer",
|
||||
},
|
||||
}
|
||||
err := DeploySSH(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("DeploySSH failed: %v", err)
|
||||
}
|
||||
// println(err.Error())
|
||||
}
|
||||
134
backend/internal/cert/deploy/tencentcloud.go
Normal file
134
backend/internal/cert/deploy/tencentcloud.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"ALLinSSL/backend/internal/access"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||
ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ClientTencentcloud(SecretId, SecretKey, region string) *ssl.Client {
|
||||
credential := common.NewCredential(
|
||||
SecretId,
|
||||
SecretKey,
|
||||
)
|
||||
// 实例化一个client选项,可选的,没有特殊需求可以跳过
|
||||
cpf := profile.NewClientProfile()
|
||||
cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com"
|
||||
// 实例化要请求产品的client对象,clientProfile是可选的
|
||||
client, _ := ssl.NewClient(credential, region, cpf)
|
||||
return client
|
||||
}
|
||||
|
||||
func UploadToTX(client *ssl.Client, key, cert string) (string, error) {
|
||||
request := ssl.NewUploadCertificateRequest()
|
||||
request.CertificatePublicKey = common.StringPtr(cert)
|
||||
request.CertificatePrivateKey = common.StringPtr(key)
|
||||
// 返回的resp是一个UploadCertificateResponse的实例,与请求对象对应
|
||||
response, err := client.UploadCertificate(request)
|
||||
if _, ok := err.(*errors.TencentCloudSDKError); ok {
|
||||
return "", err
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return *response.Response.CertificateId, nil
|
||||
}
|
||||
|
||||
func DeployToTX(cfg map[string]any) error {
|
||||
cert, ok := cfg["certificate"].(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书不存在")
|
||||
}
|
||||
keyPem, ok := cert["key"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:key")
|
||||
}
|
||||
certPem, ok := cert["cert"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("证书错误:cert")
|
||||
}
|
||||
|
||||
var providerID string
|
||||
switch v := cfg["provider_id"].(type) {
|
||||
case float64:
|
||||
providerID = strconv.Itoa(int(v))
|
||||
case string:
|
||||
providerID = v
|
||||
default:
|
||||
return fmt.Errorf("参数错误:provider_id")
|
||||
}
|
||||
//
|
||||
providerData, err := access.GetAccess(providerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerConfigStr, ok := providerData["config"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("api配置错误")
|
||||
}
|
||||
// 解析 JSON 配置
|
||||
var providerConfig map[string]string
|
||||
err = json.Unmarshal([]byte(providerConfigStr), &providerConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
region := ""
|
||||
if r, ok := cfg["region"].(string); ok {
|
||||
region = r
|
||||
}
|
||||
client := ClientTencentcloud(providerConfig["secret_id"], providerConfig["secret_key"], region)
|
||||
|
||||
// 上传证书
|
||||
certificateId, err := UploadToTX(client, strings.TrimSpace(keyPem), strings.TrimSpace(certPem))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// fmt.Println(certificateId)
|
||||
|
||||
request := ssl.NewDeployCertificateInstanceRequest()
|
||||
|
||||
request.CertificateId = common.StringPtr(certificateId)
|
||||
if cfg["resource_type"] == "cdn" {
|
||||
domain, ok := cfg["domain"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:domain")
|
||||
}
|
||||
request.InstanceIdList = common.StringPtrs([]string{domain})
|
||||
request.ResourceType = common.StringPtr("cdn")
|
||||
}
|
||||
if cfg["resource_type"] == "cos" {
|
||||
// fmt.Println(fmt.Sprintf("%s|%s|%s", cfg["region"].(string), cfg["bucket"].(string), cfg["domain"].(string)))
|
||||
domain, ok := cfg["domain"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:domain")
|
||||
}
|
||||
region, ok := cfg["region"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:region")
|
||||
}
|
||||
bucket, ok := cfg["domain"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("参数错误:bucket")
|
||||
}
|
||||
request.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s|%s|%s", region, bucket, domain)})
|
||||
// request.InstanceIdList = common.StringPtrs([]string{"ap-guangzhou#allinssl-1253163109#allinssl.zachyang.cn"})
|
||||
request.ResourceType = common.StringPtr("cos")
|
||||
}
|
||||
|
||||
// 返回的resp是一个DeployCertificateInstanceResponse的实例,与请求对象对应
|
||||
response, err := client.DeployCertificateInstance(request)
|
||||
if _, ok := err.(*errors.TencentCloudSDKError); ok {
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(response.Response.DeployRecordId)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user