2020-09-30 17:46:43 +08:00
package models
import (
2022-03-18 20:21:24 +08:00
"bytes"
2020-09-30 17:46:43 +08:00
"encoding/json"
"errors"
2024-07-27 14:15:25 +08:00
"regexp"
"strings"
"time"
2022-03-27 12:22:47 +08:00
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
2021-11-11 14:16:42 +08:00
"github.com/TeaOSLab/EdgeAPI/internal/utils"
2023-03-18 22:18:13 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
2020-09-30 17:46:43 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
2020-11-27 09:57:21 +08:00
timeutil "github.com/iwind/TeaGo/utils/time"
2020-09-30 17:46:43 +08:00
)
const (
SSLCertStateEnabled = 1 // 已启用
SSLCertStateDisabled = 0 // 已禁用
)
type SSLCertDAO dbs . DAO
func NewSSLCertDAO ( ) * SSLCertDAO {
return dbs . NewDAO ( & SSLCertDAO {
DAOObject : dbs . DAOObject {
DB : Tea . Env ,
Table : "edgeSSLCerts" ,
Model : new ( SSLCert ) ,
PkName : "id" ,
} ,
} ) . ( * SSLCertDAO )
}
2020-10-13 20:05:13 +08:00
var SharedSSLCertDAO * SSLCertDAO
func init ( ) {
dbs . OnReady ( func ( ) {
SharedSSLCertDAO = NewSSLCertDAO ( )
} )
}
2020-09-30 17:46:43 +08:00
2021-08-22 11:35:33 +08:00
// Init 初始化
2020-10-01 16:01:17 +08:00
func ( this * SSLCertDAO ) Init ( ) {
2021-01-17 16:48:00 +08:00
_ = this . DAOObject . Init ( )
2020-10-01 16:01:17 +08:00
}
2021-08-22 11:35:33 +08:00
// EnableSSLCert 启用条目
2021-01-01 23:31:30 +08:00
func ( this * SSLCertDAO ) EnableSSLCert ( tx * dbs . Tx , id int64 ) error {
_ , err := this . Query ( tx ) .
2020-09-30 17:46:43 +08:00
Pk ( id ) .
Set ( "state" , SSLCertStateEnabled ) .
Update ( )
return err
}
2021-08-22 11:35:33 +08:00
// DisableSSLCert 禁用条目
2021-01-17 16:48:00 +08:00
func ( this * SSLCertDAO ) DisableSSLCert ( tx * dbs . Tx , certId int64 ) error {
2021-01-01 23:31:30 +08:00
_ , err := this . Query ( tx ) .
2021-01-17 16:48:00 +08:00
Pk ( certId ) .
2020-09-30 17:46:43 +08:00
Set ( "state" , SSLCertStateDisabled ) .
Update ( )
2021-01-17 16:48:00 +08:00
if err != nil {
return err
}
return this . NotifyUpdate ( tx , certId )
2020-09-30 17:46:43 +08:00
}
2021-08-22 11:35:33 +08:00
// FindEnabledSSLCert 查找启用中的条目
2021-01-01 23:31:30 +08:00
func ( this * SSLCertDAO ) FindEnabledSSLCert ( tx * dbs . Tx , id int64 ) ( * SSLCert , error ) {
result , err := this . Query ( tx ) .
2020-09-30 17:46:43 +08:00
Pk ( id ) .
Attr ( "state" , SSLCertStateEnabled ) .
Find ( )
if result == nil {
return nil , err
}
return result . ( * SSLCert ) , err
}
2021-08-22 11:35:33 +08:00
// FindSSLCertName 根据主键查找名称
2021-01-01 23:31:30 +08:00
func ( this * SSLCertDAO ) FindSSLCertName ( tx * dbs . Tx , id int64 ) ( string , error ) {
return this . Query ( tx ) .
2020-09-30 17:46:43 +08:00
Pk ( id ) .
Result ( "name" ) .
FindStringCol ( "" )
}
2021-08-22 11:35:33 +08:00
// CreateCert 创建证书
2021-01-01 23:31:30 +08:00
func ( this * SSLCertDAO ) CreateCert ( tx * dbs . Tx , adminId int64 , userId int64 , isOn bool , name string , description string , serverName string , isCA bool , certData [ ] byte , keyData [ ] byte , timeBeginAt int64 , timeEndAt int64 , dnsNames [ ] string , commonNames [ ] string ) ( int64 , error ) {
2022-07-24 09:56:27 +08:00
var op = NewSSLCertOperator ( )
2020-11-24 17:36:47 +08:00
op . AdminId = adminId
op . UserId = userId
2020-09-30 17:46:43 +08:00
op . State = SSLCertStateEnabled
op . IsOn = isOn
op . Name = name
op . Description = description
op . ServerName = serverName
op . IsCA = isCA
op . CertData = certData
op . KeyData = keyData
op . TimeBeginAt = timeBeginAt
op . TimeEndAt = timeEndAt
dnsNamesJSON , err := json . Marshal ( dnsNames )
if err != nil {
return 0 , err
}
op . DnsNames = dnsNamesJSON
commonNamesJSON , err := json . Marshal ( commonNames )
if err != nil {
return 0 , err
}
op . CommonNames = commonNamesJSON
2022-03-10 11:54:35 +08:00
op . OcspIsUpdated = false
2021-01-01 23:31:30 +08:00
err = this . Save ( tx , op )
2020-09-30 17:46:43 +08:00
if err != nil {
return 0 , err
}
return types . Int64 ( op . Id ) , nil
}
2021-08-22 11:35:33 +08:00
// UpdateCert 修改证书
2022-03-10 11:54:35 +08:00
func ( this * SSLCertDAO ) UpdateCert ( tx * dbs . Tx ,
certId int64 ,
isOn bool ,
name string ,
description string ,
serverName string ,
isCA bool ,
certData [ ] byte ,
keyData [ ] byte ,
timeBeginAt int64 ,
timeEndAt int64 ,
dnsNames [ ] string , commonNames [ ] string ) error {
2020-09-30 17:46:43 +08:00
if certId <= 0 {
return errors . New ( "invalid certId" )
}
2022-03-18 20:21:24 +08:00
oldOne , err := this . Query ( tx ) . Find ( )
if err != nil {
return err
}
if oldOne == nil {
return nil
}
var oldCert = oldOne . ( * SSLCert )
2022-09-23 09:28:19 +08:00
var dataIsChanged = ! bytes . Equal ( certData , oldCert . CertData ) || ! bytes . Equal ( keyData , oldCert . KeyData )
2022-03-18 20:21:24 +08:00
var op = NewSSLCertOperator ( )
2020-09-30 17:46:43 +08:00
op . Id = certId
op . IsOn = isOn
op . Name = name
op . Description = description
op . ServerName = serverName
op . IsCA = isCA
2020-10-02 17:22:32 +08:00
// cert和key均为有重新上传才会修改
if len ( certData ) > 0 {
op . CertData = certData
}
if len ( keyData ) > 0 {
op . KeyData = keyData
}
2020-09-30 17:46:43 +08:00
op . TimeBeginAt = timeBeginAt
op . TimeEndAt = timeEndAt
dnsNamesJSON , err := json . Marshal ( dnsNames )
if err != nil {
return err
}
op . DnsNames = dnsNamesJSON
commonNamesJSON , err := json . Marshal ( commonNames )
if err != nil {
return err
}
op . CommonNames = commonNamesJSON
2022-03-18 20:21:24 +08:00
// OCSP
if dataIsChanged {
op . OcspIsUpdated = 0
op . Ocsp = ""
op . OcspUpdatedAt = 0
op . OcspError = ""
op . OcspTries = 0
op . OcspExpiresAt = 0
}
2022-03-10 11:54:35 +08:00
2021-01-01 23:31:30 +08:00
err = this . Save ( tx , op )
2021-01-17 16:48:00 +08:00
if err != nil {
return err
}
return this . NotifyUpdate ( tx , certId )
2020-09-30 17:46:43 +08:00
}
2021-08-22 11:35:33 +08:00
// ComposeCertConfig 组合配置
2022-12-31 17:12:39 +08:00
// ignoreData 是否忽略证书数据,避免因为数据过大影响传输
2023-03-18 22:18:13 +08:00
func ( this * SSLCertDAO ) ComposeCertConfig ( tx * dbs . Tx , certId int64 , ignoreData bool , dataMap * shared . DataMap , cacheMap * utils . CacheMap ) ( * sslconfigs . SSLCertConfig , error ) {
2021-08-22 11:35:33 +08:00
if cacheMap == nil {
2021-11-11 14:16:42 +08:00
cacheMap = utils . NewCacheMap ( )
2021-08-22 11:35:33 +08:00
}
2022-11-05 14:39:40 +08:00
var cacheKey = this . Table + ":ComposeCertConfig:" + types . String ( certId )
2021-11-11 14:16:42 +08:00
var cache , _ = cacheMap . Get ( cacheKey )
2021-08-22 11:35:33 +08:00
if cache != nil {
return cache . ( * sslconfigs . SSLCertConfig ) , nil
}
2021-01-01 23:31:30 +08:00
cert , err := this . FindEnabledSSLCert ( tx , certId )
2020-09-30 17:46:43 +08:00
if err != nil {
return nil , err
}
if cert == nil {
return nil , nil
}
2022-12-31 17:12:39 +08:00
var config = & sslconfigs . SSLCertConfig { }
2020-09-30 17:46:43 +08:00
config . Id = int64 ( cert . Id )
2022-03-22 21:45:07 +08:00
config . IsOn = cert . IsOn
2022-03-22 22:11:32 +08:00
config . IsCA = cert . IsCA
config . IsACME = cert . IsACME
2020-09-30 17:46:43 +08:00
config . Name = cert . Name
config . Description = cert . Description
2022-12-31 17:12:39 +08:00
if ! ignoreData {
2023-03-18 22:18:13 +08:00
if dataMap != nil {
if len ( cert . CertData ) > 0 {
config . CertData = dataMap . Put ( cert . CertData )
}
if len ( cert . KeyData ) > 0 {
config . KeyData = dataMap . Put ( cert . KeyData )
}
} else {
config . CertData = cert . CertData
config . KeyData = cert . KeyData
}
2022-12-31 17:12:39 +08:00
}
2020-09-30 17:46:43 +08:00
config . ServerName = cert . ServerName
config . TimeBeginAt = int64 ( cert . TimeBeginAt )
config . TimeEndAt = int64 ( cert . TimeEndAt )
2022-03-18 20:21:24 +08:00
// OCSP
if int64 ( cert . OcspExpiresAt ) > time . Now ( ) . Unix ( ) {
2023-03-18 22:18:13 +08:00
if dataMap != nil {
if len ( cert . Ocsp ) > 0 {
config . OCSP = dataMap . Put ( cert . Ocsp )
}
} else {
config . OCSP = cert . Ocsp
}
2022-03-18 20:21:24 +08:00
config . OCSPExpiresAt = int64 ( cert . OcspExpiresAt )
}
2022-03-11 20:27:53 +08:00
config . OCSPError = cert . OcspError
2020-09-30 17:46:43 +08:00
if IsNotNull ( cert . DnsNames ) {
2022-12-31 17:12:39 +08:00
var dnsNames = [ ] string { }
2022-03-21 21:39:36 +08:00
err := json . Unmarshal ( cert . DnsNames , & dnsNames )
2020-09-30 17:46:43 +08:00
if err != nil {
return nil , err
}
config . DNSNames = dnsNames
}
2022-03-21 21:39:36 +08:00
if cert . CommonNames . IsNotNull ( ) {
2022-12-31 17:12:39 +08:00
var commonNames = [ ] string { }
2022-03-21 21:39:36 +08:00
err := json . Unmarshal ( cert . CommonNames , & commonNames )
2020-09-30 17:46:43 +08:00
if err != nil {
return nil , err
}
config . CommonNames = commonNames
}
2021-11-11 14:16:42 +08:00
if cacheMap != nil {
cacheMap . Put ( cacheKey , config )
}
2021-08-22 11:35:33 +08:00
2020-09-30 17:46:43 +08:00
return config , nil
}
2021-08-22 11:35:33 +08:00
// CountCerts 计算符合条件的证书数量
2023-10-09 15:54:00 +08:00
func ( this * SSLCertDAO ) CountCerts ( tx * dbs . Tx , isCA bool , isAvailable bool , isExpired bool , expiringDays int64 , keyword string , userId int64 , domains [ ] string , userOnly bool ) ( int64 , error ) {
2023-03-24 19:07:43 +08:00
var query = this . Query ( tx ) .
2020-09-30 17:46:43 +08:00
State ( SSLCertStateEnabled )
if isCA {
query . Attr ( "isCA" , true )
}
if isAvailable {
query . Where ( "timeBeginAt<=UNIX_TIMESTAMP() AND timeEndAt>=UNIX_TIMESTAMP()" )
}
if isExpired {
query . Where ( "timeEndAt<UNIX_TIMESTAMP()" )
}
if expiringDays > 0 {
query . Where ( "timeEndAt>UNIX_TIMESTAMP() AND timeEndAt<:expiredAt" ) .
Param ( "expiredAt" , time . Now ( ) . Unix ( ) + expiringDays * 86400 )
}
if len ( keyword ) > 0 {
query . Where ( "(name LIKE :keyword OR description LIKE :keyword OR dnsNames LIKE :keyword OR commonNames LIKE :keyword)" ) .
2022-03-27 12:22:47 +08:00
Param ( "keyword" , dbutils . QuoteLike ( keyword ) )
2020-09-30 17:46:43 +08:00
}
2020-12-18 21:18:53 +08:00
if userId > 0 {
query . Attr ( "userId" , userId )
} else {
2023-10-09 15:54:00 +08:00
if userOnly {
query . Gt ( "userId" , 0 )
} else {
// 只查询管理员上传的
query . Attr ( "userId" , 0 )
}
2020-12-18 21:18:53 +08:00
}
2023-03-24 19:07:43 +08:00
// 域名
err := this . buildDomainSearchingQuery ( query , domains )
if err != nil {
return 0 , err
}
2020-09-30 17:46:43 +08:00
return query . Count ( )
}
2021-08-22 11:35:33 +08:00
// ListCertIds 列出符合条件的证书
2023-10-09 15:54:00 +08:00
func ( this * SSLCertDAO ) ListCertIds ( tx * dbs . Tx , isCA bool , isAvailable bool , isExpired bool , expiringDays int64 , keyword string , userId int64 , domains [ ] string , userOnly bool , offset int64 , size int64 ) ( certIds [ ] int64 , err error ) {
2023-03-24 19:07:43 +08:00
var query = this . Query ( tx ) .
2020-09-30 17:46:43 +08:00
State ( SSLCertStateEnabled )
if isCA {
query . Attr ( "isCA" , true )
}
if isAvailable {
query . Where ( "timeBeginAt<=UNIX_TIMESTAMP() AND timeEndAt>=UNIX_TIMESTAMP()" )
}
if isExpired {
query . Where ( "timeEndAt<UNIX_TIMESTAMP()" )
}
if expiringDays > 0 {
query . Where ( "timeEndAt>UNIX_TIMESTAMP() AND timeEndAt<:expiredAt" ) .
Param ( "expiredAt" , time . Now ( ) . Unix ( ) + expiringDays * 86400 )
}
if len ( keyword ) > 0 {
query . Where ( "(name LIKE :keyword OR description LIKE :keyword OR dnsNames LIKE :keyword OR commonNames LIKE :keyword)" ) .
2022-03-27 12:22:47 +08:00
Param ( "keyword" , dbutils . QuoteLike ( keyword ) )
2020-09-30 17:46:43 +08:00
}
2020-12-18 21:18:53 +08:00
if userId > 0 {
query . Attr ( "userId" , userId )
} else {
2023-10-09 15:54:00 +08:00
if userOnly {
query . Gt ( "userId" , 0 )
} else {
// 只查询管理员上传的
query . Attr ( "userId" , 0 )
}
2020-12-18 21:18:53 +08:00
}
2020-09-30 17:46:43 +08:00
2023-03-24 19:07:43 +08:00
// 域名
err = this . buildDomainSearchingQuery ( query , domains )
if err != nil {
return nil , err
}
2020-09-30 17:46:43 +08:00
ones , err := query .
ResultPk ( ) .
DescPk ( ) .
Offset ( offset ) .
Limit ( size ) .
FindAll ( )
if err != nil {
return nil , err
}
2023-03-24 19:07:43 +08:00
var result = [ ] int64 { }
2020-09-30 17:46:43 +08:00
for _ , one := range ones {
result = append ( result , int64 ( one . ( * SSLCert ) . Id ) )
}
return result , nil
}
2020-11-26 16:39:06 +08:00
2021-08-22 11:35:33 +08:00
// UpdateCertACME 设置证书的ACME信息
2021-01-01 23:31:30 +08:00
func ( this * SSLCertDAO ) UpdateCertACME ( tx * dbs . Tx , certId int64 , acmeTaskId int64 ) error {
2020-11-26 16:39:06 +08:00
if certId <= 0 {
return errors . New ( "invalid certId" )
}
2022-07-24 09:56:27 +08:00
var op = NewSSLCertOperator ( )
2020-11-26 16:39:06 +08:00
op . Id = certId
op . AcmeTaskId = acmeTaskId
op . IsACME = true
2021-01-01 23:31:30 +08:00
err := this . Save ( tx , op )
2020-11-26 16:39:06 +08:00
return err
}
2020-11-27 09:57:21 +08:00
2021-08-22 11:35:33 +08:00
// FindAllExpiringCerts 查找需要自动更新的任务
2020-11-27 09:57:21 +08:00
// 这里我们只返回有限的字段以节省内存
2021-01-01 23:31:30 +08:00
func ( this * SSLCertDAO ) FindAllExpiringCerts ( tx * dbs . Tx , days int ) ( result [ ] * SSLCert , err error ) {
2020-11-27 09:57:21 +08:00
if days < 0 {
days = 0
}
2022-08-28 20:02:13 +08:00
var deltaSeconds = int64 ( days * 86400 )
2021-01-01 23:31:30 +08:00
_ , err = this . Query ( tx ) .
2020-11-27 09:57:21 +08:00
State ( SSLCertStateEnabled ) .
2023-04-08 09:15:03 +08:00
Attr ( "isOn" , true ) .
2020-11-27 09:57:21 +08:00
Where ( "FROM_UNIXTIME(timeEndAt, '%Y-%m-%d')=:day AND FROM_UNIXTIME(notifiedAt, '%Y-%m-%d')!=:today" ) .
Param ( "day" , timeutil . FormatTime ( "Y-m-d" , time . Now ( ) . Unix ( ) + deltaSeconds ) ) .
Param ( "today" , timeutil . Format ( "Y-m-d" ) ) .
Result ( "id" , "adminId" , "userId" , "timeEndAt" , "name" , "dnsNames" , "notifiedAt" , "acmeTaskId" ) .
Slice ( & result ) .
AscPk ( ) .
FindAll ( )
return
}
2021-08-22 11:35:33 +08:00
// UpdateCertNotifiedAt 设置当前证书事件通知时间
2021-01-01 23:31:30 +08:00
func ( this * SSLCertDAO ) UpdateCertNotifiedAt ( tx * dbs . Tx , certId int64 ) error {
_ , err := this . Query ( tx ) .
2020-11-27 09:57:21 +08:00
Pk ( certId ) .
Set ( "notifiedAt" , time . Now ( ) . Unix ( ) ) .
Update ( )
return err
}
2020-12-18 21:18:53 +08:00
2021-08-22 11:35:33 +08:00
// CheckUserCert 检查用户权限
2021-01-01 23:31:30 +08:00
func ( this * SSLCertDAO ) CheckUserCert ( tx * dbs . Tx , certId int64 , userId int64 ) error {
2020-12-18 21:18:53 +08:00
if certId <= 0 || userId <= 0 {
return errors . New ( "not found" )
}
2021-01-01 23:31:30 +08:00
ok , err := this . Query ( tx ) .
2020-12-18 21:18:53 +08:00
Pk ( certId ) .
Attr ( "userId" , userId ) .
State ( SSLCertStateEnabled ) .
Exist ( )
if err != nil {
return err
}
if ! ok {
return errors . New ( "not found" )
}
return nil
}
2021-01-17 16:48:00 +08:00
2023-10-09 15:54:00 +08:00
// FindCertUserId 查找证书所属用户ID
func ( this * SSLCertDAO ) FindCertUserId ( tx * dbs . Tx , certId int64 ) ( userId int64 , err error ) {
return this . Query ( tx ) .
Pk ( certId ) .
Result ( "userId" ) .
FindInt64Col ( 0 )
}
2022-12-21 17:07:02 +08:00
// UpdateCertUser 修改证书所属用户
func ( this * SSLCertDAO ) UpdateCertUser ( tx * dbs . Tx , certId int64 , userId int64 ) error {
if certId <= 0 || userId <= 0 {
return nil
}
return this . Query ( tx ) .
Pk ( certId ) .
Set ( "userId" , userId ) .
UpdateQuickly ( )
}
2022-03-10 11:54:35 +08:00
// ListCertsToUpdateOCSP 查找需要更新OCSP的证书
2022-03-18 20:21:24 +08:00
func ( this * SSLCertDAO ) ListCertsToUpdateOCSP ( tx * dbs . Tx , maxTries int , size int64 ) ( result [ ] * SSLCert , err error ) {
var nowTime = time . Now ( ) . Unix ( )
2022-03-18 18:28:28 +08:00
var query = this . Query ( tx ) .
2022-03-10 11:54:35 +08:00
State ( SSLCertStateEnabled ) .
2022-03-18 20:21:24 +08:00
Lt ( "ocspExpiresAt" , nowTime + 120 ) . // 提前 N 秒钟准备更新
Lt ( "ocspTries" , maxTries ) .
Lt ( "timeBeginAt" , nowTime ) .
Gt ( "timeEndAt" , nowTime )
2022-03-18 18:28:28 +08:00
// TODO 需要排除没有被server使用的policy, 或许可以增加一个字段记录policy最近使用时间
// 检查函数
var JSONArrayAggIsEnabled = false
_ , err = this . Object ( ) . Instance . Exec ( "SELECT JSON_ARRAYAGG('1')" )
if err == nil {
JSONArrayAggIsEnabled = true
}
if JSONArrayAggIsEnabled {
query . Where ( "JSON_CONTAINS((SELECT JSON_ARRAYAGG(JSON_EXTRACT(certs, '$[*].certId')) FROM edgeSSLPolicies WHERE state=1 AND ocspIsOn=1 AND certs IS NOT NULL), CAST(id AS CHAR))" )
} else {
query . Where ( "JSON_CONTAINS((SELECT REPLACE(GROUP_CONCAT(JSON_EXTRACT(certs, '$[*].certId')), '],[', ',') FROM edgeSSLPolicies WHERE state=1 AND ocspIsOn=1 AND certs IS NOT NULL), CAST(id AS CHAR))" )
}
2022-03-18 17:08:51 +08:00
2022-03-18 18:28:28 +08:00
_ , err = query .
2022-03-18 17:08:51 +08:00
Asc ( "ocspUpdatedAt" ) .
2022-03-10 11:54:35 +08:00
Limit ( size ) .
Slice ( & result ) .
FindAll ( )
return
}
2022-03-18 17:08:51 +08:00
// ListCertOCSPAfterVersion 列出某个版本后的OCSP
func ( this * SSLCertDAO ) ListCertOCSPAfterVersion ( tx * dbs . Tx , version int64 , size int64 ) ( result [ ] * SSLCert , err error ) {
// 不需要判断ocsp是否为空
_ , err = this . Query ( tx ) .
2022-03-18 20:21:24 +08:00
Result ( "id" , "ocsp" , "ocspUpdatedVersion" , "ocspExpiresAt" ) .
2022-03-18 17:08:51 +08:00
State ( SSLCertStateEnabled ) .
Attr ( "ocspIsUpdated" , 1 ) .
Gt ( "ocspUpdatedVersion" , version ) .
Asc ( "ocspUpdatedVersion" ) .
Limit ( size ) .
Slice ( & result ) .
FindAll ( )
return
}
// FindCertOCSPLatestVersion 获取OCSP最新版本
func ( this * SSLCertDAO ) FindCertOCSPLatestVersion ( tx * dbs . Tx ) ( int64 , error ) {
return this . Query ( tx ) .
Result ( "ocspUpdatedVersion" ) .
Desc ( "ocspUpdatedVersion" ) .
Limit ( 1 ) .
FindInt64Col ( 0 )
}
// PrepareCertOCSPUpdating 更新OCSP更新时间, 以便于准备更新, 相当于锁定
func ( this * SSLCertDAO ) PrepareCertOCSPUpdating ( tx * dbs . Tx , certId int64 ) error {
return this . Query ( tx ) .
Pk ( certId ) .
Set ( "ocspUpdatedAt" , time . Now ( ) . Unix ( ) ) .
UpdateQuickly ( )
}
// UpdateCertOCSP 修改OCSP
2022-03-18 20:21:24 +08:00
func ( this * SSLCertDAO ) UpdateCertOCSP ( tx * dbs . Tx , certId int64 , ocsp [ ] byte , expiresAt int64 , hasErr bool , errString string ) error {
if hasErr && len ( errString ) == 0 {
errString = "failed"
}
2022-03-18 17:08:51 +08:00
version , err := SharedSysLockerDAO . Increase ( tx , "SSL_CERT_OCSP_VERSION" , 1 )
if err != nil {
return err
}
2022-03-10 11:54:35 +08:00
if ocsp == nil {
ocsp = [ ] byte { }
}
// 限制长度
if len ( errString ) > 300 {
errString = errString [ : 300 ]
}
2022-03-18 20:21:24 +08:00
var query = this . Query ( tx ) .
2022-03-10 11:54:35 +08:00
Pk ( certId ) .
Set ( "ocsp" , ocsp ) .
Set ( "ocspError" , errString ) .
Set ( "ocspIsUpdated" , true ) .
2022-03-18 17:08:51 +08:00
Set ( "ocspUpdatedAt" , time . Now ( ) . Unix ( ) ) .
Set ( "ocspUpdatedVersion" , version ) .
2022-03-18 20:21:24 +08:00
Set ( "ocspExpiresAt" , expiresAt )
if hasErr {
query . Set ( "ocspTries" , dbs . SQL ( "ocspTries+1" ) )
} else {
query . Set ( "ocspTries" , 0 )
}
err = query . UpdateQuickly ( )
2022-03-10 11:54:35 +08:00
if err != nil {
return err
}
2022-03-18 17:08:51 +08:00
// 注意:这里不通知更新,避免频繁的更新导致服务不稳定
return nil
2022-03-10 11:54:35 +08:00
}
2022-03-11 20:27:53 +08:00
// CountAllSSLCertsWithOCSPError 计算有OCSP错误的证书数量
func ( this * SSLCertDAO ) CountAllSSLCertsWithOCSPError ( tx * dbs . Tx , keyword string ) ( int64 , error ) {
var query = this . Query ( tx )
if len ( keyword ) > 0 {
query . Where ( "(name LIKE :keyword OR description LIKE :keyword OR dnsNames LIKE :keyword OR commonNames LIKE :keyword OR ocspError LIKE :keyword)" ) .
2022-03-27 12:22:47 +08:00
Param ( "keyword" , dbutils . QuoteLike ( keyword ) )
2022-03-11 20:27:53 +08:00
}
return query .
State ( SSLCertStateEnabled ) .
Attr ( "ocspIsUpdated" , true ) .
Where ( "LENGTH(ocspError) > 0" ) .
Count ( )
}
// ListSSLCertsWithOCSPError 列出有OCSP错误的证书
func ( this * SSLCertDAO ) ListSSLCertsWithOCSPError ( tx * dbs . Tx , keyword string , offset int64 , size int64 ) ( result [ ] * SSLCert , err error ) {
var query = this . Query ( tx )
if len ( keyword ) > 0 {
query . Where ( "(name LIKE :keyword OR description LIKE :keyword OR dnsNames LIKE :keyword OR commonNames LIKE :keyword OR ocspError LIKE :keyword)" ) .
2022-03-27 12:22:47 +08:00
Param ( "keyword" , dbutils . QuoteLike ( keyword ) )
2022-03-11 20:27:53 +08:00
}
_ , err = query .
State ( SSLCertStateEnabled ) .
Attr ( "ocspIsUpdated" , true ) .
Where ( "LENGTH(ocspError) > 0" ) .
Offset ( offset ) .
Limit ( size ) .
DescPk ( ) .
Slice ( & result ) .
FindAll ( )
return
}
// IgnoreSSLCertsWithOCSPError 忽略一组OCSP证书错误
func ( this * SSLCertDAO ) IgnoreSSLCertsWithOCSPError ( tx * dbs . Tx , certIds [ ] int64 ) error {
for _ , certId := range certIds {
err := this . Query ( tx ) .
Pk ( certId ) .
Set ( "ocspError" , "" ) .
UpdateQuickly ( )
if err != nil {
return err
}
}
return nil
}
// ResetSSLCertsWithOCSPError 重置一组证书OCSP错误状态
func ( this * SSLCertDAO ) ResetSSLCertsWithOCSPError ( tx * dbs . Tx , certIds [ ] int64 ) error {
for _ , certId := range certIds {
err := this . Query ( tx ) .
Pk ( certId ) .
Set ( "ocspIsUpdated" , 0 ) .
2022-03-18 17:08:51 +08:00
Set ( "ocspUpdatedAt" , 0 ) .
2022-03-11 20:27:53 +08:00
Set ( "ocspError" , "" ) .
2022-03-18 20:21:24 +08:00
Set ( "ocspTries" , 0 ) .
2022-03-11 20:27:53 +08:00
UpdateQuickly ( )
if err != nil {
return err
}
}
return nil
}
// ResetAllSSLCertsWithOCSPError 重置所有证书OCSP错误状态
func ( this * SSLCertDAO ) ResetAllSSLCertsWithOCSPError ( tx * dbs . Tx ) error {
return this . Query ( tx ) .
State ( SSLCertStateEnabled ) .
Attr ( "ocspIsUpdated" , 1 ) .
Where ( "LENGTH(ocspError)>0" ) .
Set ( "ocspIsUpdated" , 0 ) .
2022-03-18 17:08:51 +08:00
Set ( "ocspUpdatedAt" , 0 ) .
2022-03-11 20:27:53 +08:00
Set ( "ocspError" , "" ) .
2022-03-18 20:21:24 +08:00
Set ( "ocspTries" , 0 ) .
2022-03-11 20:27:53 +08:00
UpdateQuickly ( )
}
2021-08-22 11:35:33 +08:00
// NotifyUpdate 通知更新
2021-01-17 16:48:00 +08:00
func ( this * SSLCertDAO ) NotifyUpdate ( tx * dbs . Tx , certId int64 ) error {
policyIds , err := SharedSSLPolicyDAO . FindAllEnabledPolicyIdsWithCertId ( tx , certId )
if err != nil {
return err
}
if len ( policyIds ) == 0 {
return nil
}
2022-11-05 14:39:40 +08:00
// 通知服务更新
2021-01-17 16:48:00 +08:00
serverIds , err := SharedServerDAO . FindAllEnabledServerIdsWithSSLPolicyIds ( tx , policyIds )
if err != nil {
return err
}
if len ( serverIds ) == 0 {
return nil
}
for _ , serverId := range serverIds {
err := SharedServerDAO . NotifyUpdate ( tx , serverId )
if err != nil {
return err
}
}
2022-11-05 14:39:40 +08:00
// TODO 通知用户节点、API节点、管理系统( 将来实现选择) 更新
2021-01-17 16:48:00 +08:00
return nil
}
2023-03-24 19:07:43 +08:00
// 构造通过域名搜索证书的查询对象
func ( this * SSLCertDAO ) buildDomainSearchingQuery ( query * dbs . Query , domains [ ] string ) error {
if len ( domains ) == 0 {
return nil
}
// 不要查询太多
const maxDomains = 10_000
if len ( domains ) > maxDomains {
domains = domains [ : maxDomains ]
}
// 加入通配符
var searchingDomains = [ ] string { }
var domainMap = map [ string ] bool { }
for _ , domain := range domains {
domainMap [ domain ] = true
}
2023-04-21 10:41:20 +08:00
var reg = regexp . MustCompile ( ` ^[\w*.-]+$ ` ) // 为了下面的SQL语句安全先不支持其他字符
2023-03-24 19:07:43 +08:00
for domain := range domainMap {
if ! reg . MatchString ( domain ) {
continue
}
searchingDomains = append ( searchingDomains , domain )
if strings . Count ( domain , "." ) >= 2 && ! strings . HasPrefix ( domain , "*." ) {
var wildcardDomain = "*" + domain [ strings . Index ( domain , "." ) : ]
if ! domainMap [ wildcardDomain ] {
domainMap [ wildcardDomain ] = true
searchingDomains = append ( searchingDomains , wildcardDomain )
}
}
}
// 检测 JSON_OVERLAPS() 函数是否可用
2023-08-08 16:46:17 +08:00
var canJSONOverlaps bool
2023-03-24 19:07:43 +08:00
_ , funcErr := this . Instance . FindCol ( 0 , "SELECT JSON_OVERLAPS('[1]', '[1]')" )
canJSONOverlaps = funcErr == nil
if canJSONOverlaps {
domainsJSON , err := json . Marshal ( searchingDomains )
if err != nil {
return err
}
query .
Where ( "JSON_OVERLAPS(dnsNames, JSON_UNQUOTE(:domainsJSON))" ) .
Param ( "domainsJSON" , string ( domainsJSON ) )
return nil
}
// 不支持JSON_OVERLAPS()的情形
query . Reuse ( false )
// TODO 需要判断是否超出max_allowed_packet
var sqlPieces = [ ] string { }
for _ , domain := range searchingDomains {
domainJSON , err := json . Marshal ( domain )
if err != nil {
return err
}
sqlPieces = append ( sqlPieces , "JSON_CONTAINS(dnsNames, '" + string ( domainJSON ) + "')" )
}
2023-04-21 10:41:20 +08:00
if len ( sqlPieces ) > 0 {
query . Where ( "(" + strings . Join ( sqlPieces , " OR " ) + ")" )
}
2023-03-24 19:07:43 +08:00
return nil
}