修改默认登录超时为24小时

申请证书支持自定义acme
zerossl修改eab非必填
pull/236/head
v-me-50 2025-06-12 19:51:31 +08:00
parent d8f4ee0e80
commit 884c8407b5
3 changed files with 270 additions and 83 deletions

View File

@ -3,6 +3,9 @@ package apply
import ( import (
"ALLinSSL/backend/public" "ALLinSSL/backend/public"
"crypto" "crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509" "crypto/x509"
"encoding/json" "encoding/json"
"encoding/pem" "encoding/pem"
@ -47,6 +50,17 @@ func SaveUserToDB(db *public.Sqlite, user *MyUser, Type string) error {
Bytes: keyBytes, Bytes: keyBytes,
}) })
now := time.Now().Format("2006-01-02 15:04:05") now := time.Now().Format("2006-01-02 15:04:05")
data, err := db.Where(`email=? and type=?`, []interface{}{user.Email, Type}).Select()
if err != nil {
return err
}
if len(data) > 0 {
_, err = db.Update(map[string]interface{}{
"private_key": string(pemBytes),
"reg": regBytes,
"update_time": now,
})
} else {
_, err = db.Insert(map[string]interface{}{ _, err = db.Insert(map[string]interface{}{
"email": user.Email, "email": user.Email,
"private_key": string(pemBytes), "private_key": string(pemBytes),
@ -55,40 +69,139 @@ func SaveUserToDB(db *public.Sqlite, user *MyUser, Type string) error {
"update_time": now, "update_time": now,
"type": Type, "type": Type,
}) })
}
return err return err
} }
func LoadUserFromDB(db *public.Sqlite, email string, Type string) (*MyUser, error) { func GetAcmeUser(email string, logger *public.Logger, accData map[string]any) (user *MyUser) {
data, err := db.Where(`email=? and type=?`, []interface{}{email, Type}).Select() privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
user = &MyUser{
Email: email,
key: privateKey,
}
if accData == nil {
return
}
reg, ok := accData["reg"].(string)
if !ok || reg == "" {
logger.Debug("acme账号未注册注册新账号")
return
}
key, ok := accData["private_key"].(string)
if !ok || key == "" {
logger.Debug("acme账号私钥不存在注册新账号")
return
}
var Registration registration.Resource
localKey, err1 := public.ParsePrivateKey([]byte(key))
if err1 != nil {
logger.Debug("acme账号私钥解析失败", err1)
return
}
err2 := json.Unmarshal([]byte(reg), &Registration)
if err2 != nil {
return
}
logger.Debug("acme账号私钥和注册信息解析成功")
user.key = localKey
user.Registration = &Registration
return
}
func GetAccount(db *public.Sqlite, email, ca string) (map[string]interface{}, error) {
data, err := db.Where(`email=? and type=?`, []interface{}{email, ca}).Select()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(data) == 0 { if len(data) == 0 {
return nil, fmt.Errorf("user not found") return nil, fmt.Errorf("user not found")
} }
regStr, ok := data[0]["reg"].(string) return data[0], nil
if !ok {
return nil, fmt.Errorf("invalid reg data")
} }
regBytes := []byte(regStr)
privPEM, ok := data[0]["private_key"].(string) func AddAccount(email, ca, Kid, HmacEncoded, CADirURL string) error {
if !ok { db, err := GetSqlite()
return nil, fmt.Errorf("invalid private key data")
}
privateKey, err := public.ParsePrivateKey([]byte(privPEM))
if err != nil { if err != nil {
return nil, err return fmt.Errorf("failed to get sqlite: %w", err)
} }
var reg *registration.Resource now := time.Now().Format("2006-01-02 15:04:05")
if len(regBytes) > 0 { account := map[string]interface{}{
reg = &registration.Resource{} "email": email,
if err := json.Unmarshal(regBytes, reg); err != nil { "type": ca,
return nil, err "Kid": Kid,
"HmacEncoded": HmacEncoded,
"CADirURL": CADirURL,
"create_time": now,
"update_time": now,
}
_, err = db.Insert(account)
if err != nil {
return fmt.Errorf("failed to insert account: %w", err)
}
return nil
}
func UpdateAccount(id, email, ca, Kid, HmacEncoded, CADirURL string) error {
db, err := GetSqlite()
if err != nil {
return fmt.Errorf("failed to get sqlite: %w", err)
}
account := map[string]interface{}{
"email": email,
"type": ca,
"Kid": Kid,
"HmacEncoded": HmacEncoded,
"CADirURL": CADirURL,
"update_time": time.Now().Format("2006-01-02 15:04:05"),
}
_, err = db.Where("id=?", []any{id}).Update(account)
if err != nil {
return fmt.Errorf("failed to update account: %w", err)
}
return nil
}
func DeleteAccount(id string) error {
db, err := GetSqlite()
if err != nil {
return fmt.Errorf("failed to get sqlite: %w", err)
}
_, err = db.Where("id=?", []any{id}).Delete()
if err != nil {
return fmt.Errorf("failed to delete account: %w", err)
}
return nil
}
func GetAccountList(search, ca string, p, limit int64) ([]map[string]interface{}, error) {
db, err := GetSqlite()
if err != nil {
return nil, fmt.Errorf("failed to get sqlite: %w", err)
}
whereSql := "1=1"
var whereArgs []any
limits := []int64{0, 100}
if p >= 0 && limit >= 0 {
limits = []int64{0, limit}
if p > 1 {
limits[0] = (p - 1) * limit
limits[1] = limit
} }
} }
return &MyUser{ if search != "" {
Email: email, whereSql += " and (email like ? or type like ?)"
key: privateKey, whereArgs = append(whereArgs, "%"+search+"%", "%"+search+"%")
Registration: reg, }
}, nil if ca != "" {
if ca == "custom" {
whereSql += `and type not in ('Let's Encrypt','buypass', 'google', 'sslcom', 'zerossl')`
} else {
whereSql += " and type=?"
whereArgs = append(whereArgs, ca)
}
}
return db.Where(whereSql, whereArgs).Limit(limits).Select()
} }

View File

@ -5,9 +5,6 @@ import (
"ALLinSSL/backend/internal/cert" "ALLinSSL/backend/internal/cert"
"ALLinSSL/backend/internal/cert/apply/lego/jdcloud" "ALLinSSL/backend/internal/cert/apply/lego/jdcloud"
"ALLinSSL/backend/public" "ALLinSSL/backend/public"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/json" "encoding/json"
"fmt" "fmt"
azcorecloud "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" azcorecloud "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
@ -67,7 +64,7 @@ func GetSqlite() (*public.Sqlite, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
s.TableName = "_accounts" s.TableName = "accounts"
return s, nil return s, nil
} }
@ -200,7 +197,62 @@ func GetDNSProvider(providerName string, creds map[string]string, httpClient *ht
} }
} }
func GetAcmeClient(db *public.Sqlite, email, algorithm, eabId, ca string, httpClient *http.Client, logger *public.Logger) (*lego.Client, error) { func GetZeroSSLEabFromEmail(email string, httpClient *http.Client) (map[string]any, error) {
APIPath := "https://api.zerossl.com/acme/eab-credentials-email"
data := map[string]any{
"email": email,
}
jsonData, err := json.Marshal(data)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", APIPath, strings.NewReader(string(jsonData)))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
if httpClient == nil {
httpClient = &http.Client{}
}
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("获取ZeroSSL EAB信息失败状态码%d", resp.StatusCode)
}
var result map[string]any
err = json.NewDecoder(resp.Body).Decode(&result)
if err != nil {
return nil, fmt.Errorf("解析ZeroSSL EAB信息失败%v", err)
}
if result["eab_kid"] == nil || result["eab_hmac_key"] == nil {
return nil, fmt.Errorf("ZeroSSL EAB信息不完整缺少kid或hmacEncoded")
}
return map[string]any{
"Kid": result["eab_kid"],
"HmacEncoded": result["eab_hmac_key"],
}, nil
}
func getEABFromAccData(accData map[string]any, eabData *map[string]any) bool {
if accData == nil {
return false
}
kid := accData["Kid"]
hmac := accData["HmacEncoded"]
if kid != nil && hmac != nil {
*eabData = map[string]any{
"Kid": kid,
"HmacEncoded": hmac,
}
return true
}
return false
}
func GetAcmeClient(email, algorithm, eabId, ca string, httpClient *http.Client, logger *public.Logger) (*lego.Client, error) {
var ( var (
eabData map[string]any eabData map[string]any
err error err error
@ -229,28 +281,45 @@ func GetAcmeClient(db *public.Sqlite, email, algorithm, eabId, ca string, httpCl
return nil, fmt.Errorf("HmacEncoded不能为空") return nil, fmt.Errorf("HmacEncoded不能为空")
} }
ca = eabData["ca"].(string) ca = eabData["ca"].(string)
if ca == "sslcom" {
switch algorithm[0] {
case 'R', 'r':
ca = "sslcom-rsa"
case 'E', 'e':
ca = "sslcom-ecc"
}
}
} }
user, err := LoadUserFromDB(db, email, ca) CADirURL := CADirURLMap[ca]
if ca == "sslcom" {
if algorithm == "EC256" || algorithm == "EC384" {
CADirURL = CADirURLMap["sslcom-ecc"]
} else {
CADirURL = CADirURLMap["sslcom-rsa"]
}
}
db, err := GetSqlite()
var accData map[string]any
if err != nil { if err != nil {
logger.Debug("acme账号不存在注册新账号") logger.Debug("获取数据库连接失败", err)
privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if ca != "Let's Encrypt" && ca != "zerossl" && ca != "buypass" {
user = &MyUser{ return nil, fmt.Errorf("当前CA【%s】 需要从数据库获取预设账号但是连接数据库失败请稍后重试err:%w", ca, err)
Email: email, }
key: privateKey, } else {
defer db.Close()
accData, err = GetAccount(db, email, ca)
if err != nil || accData == nil {
logger.Debug("获取acme账号信息失败")
if ca != "Let's Encrypt" && ca != "zerossl" && ca != "buypass" {
return nil, fmt.Errorf("未找到%s账号信息请先在账号管理中添加%s账号, email:%s", ca, ca, email)
} }
} }
if CADirURL == "" {
accCADirURL, ok := accData["CADirURL"].(string)
if !ok || accCADirURL == "" {
logger.Debug("未找到此CA的请求地址")
return nil, fmt.Errorf("未找到CA【%s】请求地址请先在账号管理中检查%s账号, email:%s", ca, ca, email)
}
CADirURL = accCADirURL
}
}
user := GetAcmeUser(email, logger, accData)
config := lego.NewConfig(user) config := lego.NewConfig(user)
config.Certificate.KeyType = AlgorithmMap[algorithm] config.Certificate.KeyType = AlgorithmMap[algorithm]
config.CADirURL = CADirURLMap[ca] config.CADirURL = CADirURL
if httpClient != nil { if httpClient != nil {
config.HTTPClient = httpClient config.HTTPClient = httpClient
} }
@ -260,6 +329,20 @@ func GetAcmeClient(db *public.Sqlite, email, algorithm, eabId, ca string, httpCl
} }
if user.Registration == nil { if user.Registration == nil {
logger.Debug("正在注册账号:" + email) logger.Debug("正在注册账号:" + email)
if eabData == nil {
// 走新的逻辑eab已合并到账号中
if !getEABFromAccData(accData, &eabData) {
switch ca {
case "zerossl":
eabData, err = GetZeroSSLEabFromEmail(email, httpClient)
if err != nil {
return nil, fmt.Errorf("获取ZeroSSL EAB信息失败: %v", err)
}
case "sslcom", "google":
return nil, fmt.Errorf("未找到EAB信息请在账号管理中添加%s账号", ca)
}
}
}
var reg *registration.Resource var reg *registration.Resource
if eabData != nil { if eabData != nil {
Kid := eabData["Kid"].(string) Kid := eabData["Kid"].(string)
@ -279,7 +362,7 @@ func GetAcmeClient(db *public.Sqlite, email, algorithm, eabId, ca string, httpCl
err = SaveUserToDB(db, user, ca) err = SaveUserToDB(db, user, ca)
if err != nil { if err != nil {
return nil, err logger.Debug("acme账号注册成功但保存到数据库失败", err)
} }
logger.Debug("acme账号注册并保存成功") logger.Debug("acme账号注册并保存成功")
} }
@ -350,12 +433,7 @@ func GetCert(runId string, domainArr []string, endDay int, logger *public.Logger
func Apply(cfg map[string]any, logger *public.Logger) (map[string]any, error) { func Apply(cfg map[string]any, logger *public.Logger) (map[string]any, error) {
log.Logger = logger.GetLogger() log.Logger = logger.GetLogger()
db, err := GetSqlite() var err error
if err != nil {
return nil, err
}
defer db.Close()
email, ok := cfg["email"].(string) email, ok := cfg["email"].(string)
if !ok { if !ok {
return nil, fmt.Errorf("参数错误email") return nil, fmt.Errorf("参数错误email")
@ -575,7 +653,7 @@ func Apply(cfg map[string]any, logger *public.Logger) (map[string]any, error) {
logger.Debug("正在申请证书,域名: " + domains) logger.Debug("正在申请证书,域名: " + domains)
os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", strconv.FormatBool(closeCname)) os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", strconv.FormatBool(closeCname))
// 创建 ACME 客户端 // 创建 ACME 客户端
client, err := GetAcmeClient(db, email, algorithm, eabId, ca, httpClient, logger) client, err := GetAcmeClient(email, algorithm, eabId, ca, httpClient, logger)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -278,7 +278,7 @@ func init() {
Isql := fmt.Sprintf( Isql := fmt.Sprintf(
`INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('log_path', 'logs/ALLinSSL.log', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); `INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('log_path', 'logs/ALLinSSL.log', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'workflow_log_path', 'logs/workflows/', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'workflow_log_path', 'logs/workflows/', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'timeout', '3600', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'timeout', '86400', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'https', '0', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ( 'https', '0', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('session_key', '%s', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('session_key', '%s', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('secure', '/%s', '2025-04-15 15:58', '2025-04-15 15:58', 1, null); INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES ('secure', '/%s', '2025-04-15 15:58', '2025-04-15 15:58', 1, null);
@ -304,34 +304,30 @@ INSERT INTO settings (key, value, create_time, update_time, active, type) VALUES
_, err = dbAcc.Exec(` _, err = dbAcc.Exec(`
PRAGMA journal_mode=WAL; PRAGMA journal_mode=WAL;
create table IF NOT EXISTS _accounts create table if not exists accounts
( (
id integer not null id integer not null
constraint _accounts_pk constraint _accounts_pk
primary key autoincrement, primary key autoincrement,
private_key TEXT not null, private_key TEXT ,
reg TEXT not null, reg TEXT ,
email TEXT not null, email TEXT not null,
type TEXT not null,
Kid TEXT ,
HmacEncoded TEXT ,
CADirURL TEXT ,
create_time TEXT, create_time TEXT,
update_time TEXT, update_time TEXT
type TEXT
); );
create table IF NOT EXISTS _eab
(
id integer not null
constraint _eab_pk
primary key autoincrement,
name TEXT,
Kid TEXT not null,
HmacEncoded TEXT not null,
ca TEXT not null,
create_time TEXT,
update_time TEXT,
mail TEXT not null
);
`) `)
insertSql := `
insert into accounts (id, private_key, reg, email, create_time, update_time, type, Kid, HmacEncoded)
select a.id, a.private_key, a.reg, a.email, a.create_time, a.update_time, case when a.type like 'sslcom%' then 'sslcom' else a.type end, b.Kid,b.HmacEncoded
from _accounts a
left join _eab b
on a.email = b.mail and a.type like b.ca||'%';
`
insertDefaultData(dbAcc, "accounts", insertSql)
} }
func insertDefaultData(db *sql.DB, table, insertSQL string) { func insertDefaultData(db *sql.DB, table, insertSQL string) {