[SSL证书]实现对ACME任务的增删改查

This commit is contained in:
GoEdgeLab
2020-11-25 21:19:22 +08:00
parent 12f348a592
commit 29cbabebf5
22 changed files with 862 additions and 180 deletions

View File

@@ -0,0 +1,175 @@
package models
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
)
const (
ACMETaskStateEnabled = 1 // 已启用
ACMETaskStateDisabled = 0 // 已禁用
)
type ACMETaskDAO dbs.DAO
func NewACMETaskDAO() *ACMETaskDAO {
return dbs.NewDAO(&ACMETaskDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeACMETasks",
Model: new(ACMETask),
PkName: "id",
},
}).(*ACMETaskDAO)
}
var SharedACMETaskDAO *ACMETaskDAO
func init() {
dbs.OnReady(func() {
SharedACMETaskDAO = NewACMETaskDAO()
})
}
// 启用条目
func (this *ACMETaskDAO) EnableACMETask(id int64) error {
_, err := this.Query().
Pk(id).
Set("state", ACMETaskStateEnabled).
Update()
return err
}
// 禁用条目
func (this *ACMETaskDAO) DisableACMETask(id int64) error {
_, err := this.Query().
Pk(id).
Set("state", ACMETaskStateDisabled).
Update()
return err
}
// 查找启用中的条目
func (this *ACMETaskDAO) FindEnabledACMETask(id int64) (*ACMETask, error) {
result, err := this.Query().
Pk(id).
Attr("state", ACMETaskStateEnabled).
Find()
if result == nil {
return nil, err
}
return result.(*ACMETask), err
}
// 计算某个ACME用户相关的任务数量
func (this *ACMETaskDAO) CountACMETasksWithACMEUserId(acmeUserId int64) (int64, error) {
return this.Query().
State(ACMETaskStateEnabled).
Attr("acmeUserId", acmeUserId).
Count()
}
// 计算某个DNS服务商相关的任务数量
func (this *ACMETaskDAO) CountACMETasksWithDNSProviderId(dnsProviderId int64) (int64, error) {
return this.Query().
State(ACMETaskStateEnabled).
Attr("dnsProviderId", dnsProviderId).
Count()
}
// 停止某个证书相关任务
func (this *ACMETaskDAO) DisableAllTasksWithCertId(certId int64) error {
_, err := this.Query().
Attr("certId", certId).
Set("state", ACMETaskStateDisabled).
Update()
return err
}
// 计算所有任务数量
func (this *ACMETaskDAO) CountAllEnabledACMETasks(adminId int64, userId int64) (int64, error) {
return NewQuery(this, adminId, userId).
State(ACMETaskStateEnabled).
Count()
}
// 列出单页任务
func (this *ACMETaskDAO) ListEnabledACMETasks(adminId int64, userId int64, offset int64, size int64) (result []*ACMETask, err error) {
_, err = NewQuery(this, adminId, userId).
State(ACMETaskStateEnabled).
DescPk().
Offset(offset).
Limit(size).
Slice(&result).
FindAll()
return
}
// 创建任务
func (this *ACMETaskDAO) CreateACMETask(adminId int64, userId int64, acmeUserId int64, dnsProviderId int64, dnsDomain string, domains []string, autoRenew bool) (int64, error) {
op := NewACMETaskOperator()
op.AdminId = adminId
op.UserId = userId
op.AcmeUserId = acmeUserId
op.DnsProviderId = dnsProviderId
op.DnsDomain = dnsDomain
if len(domains) > 0 {
domainsJSON, err := json.Marshal(domains)
if err != nil {
return 0, err
}
op.Domains = domainsJSON
} else {
op.Domains = "[]"
}
op.AutoRenew = autoRenew
op.IsOn = true
op.State = ACMETaskStateEnabled
op.IsOk = false
_, err := this.Save(op)
if err != nil {
return 0, err
}
return types.Int64(op.Id), nil
}
// 修改任务
func (this *ACMETaskDAO) UpdateACMETask(acmeTaskId int64, acmeUserId int64, dnsProviderId int64, dnsDomain string, domains []string, autoRenew bool) error {
if acmeTaskId <= 0 {
return errors.New("invalid acmeTaskId")
}
op := NewACMETaskOperator()
op.Id = acmeTaskId
op.AcmeUserId = acmeUserId
op.DnsProviderId = dnsProviderId
op.DnsDomain = dnsDomain
if len(domains) > 0 {
domainsJSON, err := json.Marshal(domains)
if err != nil {
return err
}
op.Domains = domainsJSON
} else {
op.Domains = "[]"
}
op.AutoRenew = autoRenew
_, err := this.Save(op)
return err
}
// 检查权限
func (this *ACMETaskDAO) CheckACMETask(adminId int64, userId int64, acmeTaskId int64) (bool, error) {
return NewQuery(this, adminId, userId).
State(ACMETaskStateEnabled).
Pk(acmeTaskId).
Exist()
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,28 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
)
type ACMETaskLogDAO dbs.DAO
func NewACMETaskLogDAO() *ACMETaskLogDAO {
return dbs.NewDAO(&ACMETaskLogDAO{
DAOObject: dbs.DAOObject{
DB: Tea.Env,
Table: "edgeACMETaskLogs",
Model: new(ACMETaskLog),
PkName: "id",
},
}).(*ACMETaskLogDAO)
}
var SharedACMETaskLogDAO *ACMETaskLogDAO
func init() {
dbs.OnReady(func() {
SharedACMETaskLogDAO = NewACMETaskLogDAO()
})
}

View File

@@ -0,0 +1,5 @@
package models
import (
_ "github.com/go-sql-driver/mysql"
)

View File

@@ -0,0 +1,22 @@
package models
// ACME任务运行日志
type ACMETaskLog struct {
Id uint64 `field:"id"` // ID
TaskId uint64 `field:"taskId"` // 任务ID
IsOk uint8 `field:"isOk"` // 是否成功
Error string `field:"error"` // 错误信息
CreatedAt uint64 `field:"createdAt"` // 运行时间
}
type ACMETaskLogOperator struct {
Id interface{} // ID
TaskId interface{} // 任务ID
IsOk interface{} // 是否成功
Error interface{} // 错误信息
CreatedAt interface{} // 运行时间
}
func NewACMETaskLogOperator() *ACMETaskLogOperator {
return &ACMETaskLogOperator{}
}

View File

@@ -0,0 +1 @@
package models

View File

@@ -0,0 +1,38 @@
package models
// ACME任务
type ACMETask struct {
Id uint64 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
IsOn uint8 `field:"isOn"` // 是否启用
AcmeUserId uint32 `field:"acmeUserId"` // ACME用户ID
DnsDomain string `field:"dnsDomain"` // DNS主域名
DnsProviderId uint64 `field:"dnsProviderId"` // DNS服务商
Domains string `field:"domains"` // 证书域名
CreatedAt uint64 `field:"createdAt"` // 创建时间
State uint8 `field:"state"` // 状态
IsOk uint8 `field:"isOk"` // 最后运行是否正常
CertId uint64 `field:"certId"` // 生成的证书ID
AutoRenew uint8 `field:"autoRenew"` // 是否自动更新
}
type ACMETaskOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
IsOn interface{} // 是否启用
AcmeUserId interface{} // ACME用户ID
DnsDomain interface{} // DNS主域名
DnsProviderId interface{} // DNS服务商
Domains interface{} // 证书域名
CreatedAt interface{} // 创建时间
State interface{} // 状态
IsOk interface{} // 最后运行是否正常
CertId interface{} // 生成的证书ID
AutoRenew interface{} // 是否自动更新
}
func NewACMETaskOperator() *ACMETaskOperator {
return &ACMETaskOperator{}
}

View File

@@ -0,0 +1,20 @@
package models
import (
"encoding/json"
"github.com/iwind/TeaGo/logs"
)
// 将域名解析成字符串数组
func (this *ACMETask) DecodeDomains() []string {
if len(this.Domains) == 0 || this.Domains == "null" {
return nil
}
result := []string{}
err := json.Unmarshal([]byte(this.Domains), &result)
if err != nil {
logs.Error(err)
return nil
}
return result
}

View File

@@ -144,6 +144,28 @@ func (this *ACMEUserDAO) ListACMEUsers(adminId int64, userId int64, offset int64
return
}
// 查找所有用户
func (this *ACMEUserDAO) FindAllACMEUsers(adminId int64, userId int64) (result []*ACMEUser, err error) {
// 防止没有传入条件导致返回的数据过多
if adminId <= 0 && userId <= 0 {
return nil, errors.New("'adminId' or 'userId' should not be empty")
}
query := this.Query()
if adminId > 0 {
query.Attr("adminId", adminId)
}
if userId > 0 {
query.Attr("userId", userId)
}
_, err = query.
State(ACMEUserStateEnabled).
Slice(&result).
DescPk().
FindAll()
return
}
// 检查用户权限
func (this *ACMEUserDAO) CheckACMEUser(acmeUserId int64, adminId int64, userId int64) (bool, error) {
if acmeUserId <= 0 {

View File

@@ -66,8 +66,10 @@ func (this *DNSProviderDAO) FindEnabledDNSProvider(id int64) (*DNSProvider, erro
}
// 创建服务商
func (this *DNSProviderDAO) CreateDNSProvider(providerType string, name string, apiParamsJSON []byte) (int64, error) {
func (this *DNSProviderDAO) CreateDNSProvider(adminId int64, userId int64, providerType string, name string, apiParamsJSON []byte) (int64, error) {
op := NewDNSProviderOperator()
op.AdminId = adminId
op.UserId = userId
op.Type = providerType
op.Name = name
if len(apiParamsJSON) > 0 {
@@ -104,15 +106,15 @@ func (this *DNSProviderDAO) UpdateDNSProvider(dnsProviderId int64, name string,
}
// 计算服务商数量
func (this *DNSProviderDAO) CountAllEnabledDNSProviders() (int64, error) {
return this.Query().
func (this *DNSProviderDAO) CountAllEnabledDNSProviders(adminId int64, userId int64) (int64, error) {
return NewQuery(this, adminId, userId).
State(DNSProviderStateEnabled).
Count()
}
// 列出单页服务商
func (this *DNSProviderDAO) ListEnabledDNSProviders(offset int64, size int64) (result []*DNSProvider, err error) {
_, err = this.Query().
func (this *DNSProviderDAO) ListEnabledDNSProviders(adminId int64, userId int64, offset int64, size int64) (result []*DNSProvider, err error) {
_, err = NewQuery(this, adminId, userId).
State(DNSProviderStateEnabled).
Offset(offset).
Limit(size).
@@ -122,6 +124,16 @@ func (this *DNSProviderDAO) ListEnabledDNSProviders(offset int64, size int64) (r
return
}
// 列出所有服务商
func (this *DNSProviderDAO) FindAllEnabledDNSProviders(adminId int64, userId int64) (result []*DNSProvider, err error) {
_, err = NewQuery(this, adminId, userId).
State(DNSProviderStateEnabled).
DescPk().
Slice(&result).
FindAll()
return
}
// 查询某个类型下的所有服务商
func (this *DNSProviderDAO) FindAllEnabledDNSProvidersWithType(providerType string) (result []*DNSProvider, err error) {
_, err = this.Query().

View File

@@ -269,49 +269,3 @@ func (this *SSLCertDAO) ListCertIds(isCA bool, isAvailable bool, isExpired bool,
}
return result, nil
}
// 计算所有某个管理员/用户下所有的ACME用户生成的证书数量
func (this *SSLCertDAO) CountAllSSLCertsWithACME(adminId int64, userId int64) (int64, error) {
query := this.Query()
if adminId > 0 {
query.Attr("adminId", adminId)
}
if userId > 0 {
query.Attr("userId", userId)
}
return query.
State(SSLCertStateEnabled).
Where("acmeUserId>0").
Count()
}
// 列出某个管理员/用户下所有的ACME用户生成的证书Ids
func (this *SSLCertDAO) ListSSLCertIdsWithACME(adminId int64, userId int64, offset int64, size int64) (certIds []int64, err error) {
query := this.Query()
if adminId > 0 {
query.Attr("adminId", adminId)
}
if userId > 0 {
query.Attr("userId", userId)
}
ones, err := query.
ResultPk().
State(SSLCertStateEnabled).
Where("acmeUserId>0").
Offset(offset).
Limit(size).
DescPk().
FindAll()
for _, one := range ones {
certIds = append(certIds, int64(one.(*SSLCert).Id))
}
return
}
// 计算某个ACME用户生成的证书数量
func (this *SSLCertDAO) CountSSLCertsWithACMEUserId(acmeUserId int64) (int64, error) {
return this.Query().
State(SSLCertStateEnabled).
Attr("acmeUserId", acmeUserId).
Count()
}

View File

@@ -2,51 +2,49 @@ package models
// SSL证书
type SSLCert struct {
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
UpdatedAt uint64 `field:"updatedAt"` // 修改时间
IsOn uint8 `field:"isOn"` // 是否启用
Name string `field:"name"` // 证书名
Description string `field:"description"` // 描述
CertData string `field:"certData"` // 证书内容
KeyData string `field:"keyData"` // 密钥内容
ServerName string `field:"serverName"` // 证书使用的主机名
IsCA uint8 `field:"isCA"` // 是否为CA证书
GroupIds string `field:"groupIds"` // 证书分组
TimeBeginAt uint64 `field:"timeBeginAt"` // 开始时间
TimeEndAt uint64 `field:"timeEndAt"` // 结束时间
DnsNames string `field:"dnsNames"` // DNS名称列表
CommonNames string `field:"commonNames"` // 发行单位列表
IsACME uint8 `field:"isACME"` // 是否为ACME自动生成的
AcmeUserId uint64 `field:"acmeUserId"` // ACME用户ID
AcmeAutoRenew uint8 `field:"acmeAutoRenew"` // ACME生成后是否自动更新
Id uint32 `field:"id"` // ID
AdminId uint32 `field:"adminId"` // 管理员ID
UserId uint32 `field:"userId"` // 用户ID
State uint8 `field:"state"` // 状态
CreatedAt uint64 `field:"createdAt"` // 创建时间
UpdatedAt uint64 `field:"updatedAt"` // 修改时间
IsOn uint8 `field:"isOn"` // 是否启用
Name string `field:"name"` // 证书名
Description string `field:"description"` // 描述
CertData string `field:"certData"` // 证书内容
KeyData string `field:"keyData"` // 密钥内容
ServerName string `field:"serverName"` // 证书使用的主机名
IsCA uint8 `field:"isCA"` // 是否为CA证书
GroupIds string `field:"groupIds"` // 证书分组
TimeBeginAt uint64 `field:"timeBeginAt"` // 开始时间
TimeEndAt uint64 `field:"timeEndAt"` // 结束时间
DnsNames string `field:"dnsNames"` // DNS名称列表
CommonNames string `field:"commonNames"` // 发行单位列表
IsACME uint8 `field:"isACME"` // 是否为ACME自动生成的
AcmeTaskId uint64 `field:"acmeTaskId"` // ACME任务ID
}
type SSLCertOperator struct {
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
State interface{} // 状态
CreatedAt interface{} // 创建时间
UpdatedAt interface{} // 修改时间
IsOn interface{} // 是否启用
Name interface{} // 证书名
Description interface{} // 描述
CertData interface{} // 证书内容
KeyData interface{} // 密钥内容
ServerName interface{} // 证书使用的主机名
IsCA interface{} // 是否为CA证书
GroupIds interface{} // 证书分组
TimeBeginAt interface{} // 开始时间
TimeEndAt interface{} // 结束时间
DnsNames interface{} // DNS名称列表
CommonNames interface{} // 发行单位列表
IsACME interface{} // 是否为ACME自动生成的
AcmeUserId interface{} // ACME用户ID
AcmeAutoRenew interface{} // ACME生成后是否自动更新
Id interface{} // ID
AdminId interface{} // 管理员ID
UserId interface{} // 用户ID
State interface{} // 状态
CreatedAt interface{} // 创建时间
UpdatedAt interface{} // 修改时间
IsOn interface{} // 是否启用
Name interface{} // 证书名
Description interface{} // 描述
CertData interface{} // 证书内容
KeyData interface{} // 密钥内容
ServerName interface{} // 证书使用的主机名
IsCA interface{} // 是否为CA证书
GroupIds interface{} // 证书分组
TimeBeginAt interface{} // 开始时间
TimeEndAt interface{} // 结束时间
DnsNames interface{} // DNS名称列表
CommonNames interface{} // 发行单位列表
IsACME interface{} // 是否为ACME自动生成的
AcmeTaskId interface{} // ACME任务ID
}
func NewSSLCertOperator() *SSLCertOperator {

View File

@@ -1,5 +1,7 @@
package models
import "github.com/iwind/TeaGo/dbs"
// 处理JSON字节Slice
func JSONBytes(data []byte) []byte {
if len(data) == 0 {
@@ -12,3 +14,15 @@ func JSONBytes(data []byte) []byte {
func IsNotNull(data string) bool {
return len(data) > 0 && data != "null"
}
// 构造Query
func NewQuery(dao dbs.DAOWrapper, adminId int64, userId int64) *dbs.Query {
query := dao.Object().Query()
if adminId > 0 {
query.Attr("adminId", adminId)
}
if userId > 0 {
query.Attr("userId", userId)
}
return query
}