mirror of https://github.com/allinssl/allinssl
262 lines
6.2 KiB
Go
262 lines
6.2 KiB
Go
package apply
|
||
|
||
import (
|
||
"ALLinSSL/backend/public"
|
||
"crypto"
|
||
"crypto/ecdsa"
|
||
"crypto/elliptic"
|
||
"crypto/rand"
|
||
"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, Type string) 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")
|
||
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{}{
|
||
"email": user.Email,
|
||
"private_key": string(pemBytes),
|
||
"reg": regBytes,
|
||
"create_time": now,
|
||
"update_time": now,
|
||
"type": Type,
|
||
})
|
||
}
|
||
return err
|
||
}
|
||
|
||
func GetAcmeUser(email string, logger *public.Logger, accData map[string]any) (user *MyUser) {
|
||
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 {
|
||
return nil, err
|
||
}
|
||
if len(data) == 0 {
|
||
return nil, fmt.Errorf("user not found")
|
||
}
|
||
return data[0], nil
|
||
}
|
||
|
||
func AddAccount(email, ca, Kid, HmacEncoded, CADirURL string) error {
|
||
db, err := GetSqlite()
|
||
if err != nil {
|
||
return fmt.Errorf("failed to get sqlite: %w", err)
|
||
}
|
||
now := time.Now().Format("2006-01-02 15:04:05")
|
||
if (ca == "sslcom" || ca == "google") && (Kid == "" || HmacEncoded == "") {
|
||
return fmt.Errorf("Kid and HmacEncoded are required for %s CA", ca)
|
||
} else if ca == "custom" && CADirURL == "" {
|
||
return fmt.Errorf("CADirURL is required for custom CA")
|
||
}
|
||
account := map[string]interface{}{
|
||
"email": email,
|
||
"type": ca,
|
||
"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 DelAccount(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{}, int, error) {
|
||
db, err := GetSqlite()
|
||
if err != nil {
|
||
return nil, 0, 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
|
||
}
|
||
}
|
||
if search != "" {
|
||
whereSql += " and (email like ? or type like ?)"
|
||
whereArgs = append(whereArgs, "%"+search+"%", "%"+search+"%")
|
||
}
|
||
if ca != "" {
|
||
if ca == "custom" {
|
||
whereSql += `and type not in ('Let's Encrypt','buypass', 'google', 'sslcom', 'zerossl')`
|
||
} else {
|
||
if ca == "letsencrypt" {
|
||
ca = "Let's Encrypt"
|
||
}
|
||
whereSql += " and type=?"
|
||
whereArgs = append(whereArgs, ca)
|
||
}
|
||
}
|
||
count, err := db.Where(whereSql, whereArgs).Count()
|
||
data, err := db.Where(whereSql, whereArgs).Limit(limits).Select()
|
||
if err != nil {
|
||
return nil, 0, fmt.Errorf("failed to get account list: %w", err)
|
||
}
|
||
for i := range data {
|
||
if data[i]["type"] == "Let's Encrypt" {
|
||
data[i]["type"] = "letsencrypt"
|
||
}
|
||
data[i]["ca"] = data[i]["type"]
|
||
delete(data[i], "private_key")
|
||
delete(data[i], "reg")
|
||
delete(data[i], "type")
|
||
}
|
||
|
||
return data, int(count), nil
|
||
}
|
||
|
||
func GetCaList() ([]string, int, error) {
|
||
db, err := GetSqlite()
|
||
if err != nil {
|
||
return nil, 0, fmt.Errorf("failed to get sqlite: %w", err)
|
||
}
|
||
data, err := db.Field([]string{"type"}).GroupBy("type").Select()
|
||
if err != nil {
|
||
return nil, 0, fmt.Errorf("failed to get CA list: %w", err)
|
||
}
|
||
caList := []string{"letsencrypt", "buypass", "zerossl"}
|
||
for i := range data {
|
||
if data[i]["type"] == "Let's Encrypt" {
|
||
data[i]["type"] = "letsencrypt"
|
||
}
|
||
if !containsString(caList, data[i]["type"].(string)) {
|
||
caList = append(caList, data[i]["type"].(string))
|
||
}
|
||
}
|
||
count := len(caList)
|
||
return caList, count, nil
|
||
}
|
||
|
||
func containsString(slice []string, target string) bool {
|
||
for _, v := range slice {
|
||
if v == target {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|