245 lines
6.6 KiB
Go
245 lines
6.6 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"math/big"
|
|
"strconv"
|
|
"time"
|
|
|
|
"next-terminal/server/common"
|
|
"next-terminal/server/common/maps"
|
|
"next-terminal/server/model"
|
|
"next-terminal/server/repository"
|
|
"next-terminal/server/utils"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
type CertificateApi struct{}
|
|
|
|
func (api CertificateApi) AllEndpoint(c echo.Context) error {
|
|
items, err := repository.CertificateRepository.FindAll(context.TODO())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return Success(c, items)
|
|
}
|
|
|
|
func (api CertificateApi) PagingEndpoint(c echo.Context) error {
|
|
pageIndex, _ := strconv.Atoi(c.QueryParam("pageIndex"))
|
|
pageSize, _ := strconv.Atoi(c.QueryParam("pageSize"))
|
|
keyword := c.QueryParam("keyword")
|
|
|
|
items, total, err := repository.CertificateRepository.Find(context.TODO(), pageIndex, pageSize, keyword)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return Success(c, maps.Map{
|
|
"total": total,
|
|
"items": items,
|
|
})
|
|
}
|
|
|
|
func parseCertificate(certPEM string) (commonName, subject, issuer string, notBefore, notAfter time.Time, err error) {
|
|
block, _ := pem.Decode([]byte(certPEM))
|
|
if block == nil {
|
|
return "", "", "", time.Time{}, time.Time{}, nil
|
|
}
|
|
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
return "", "", "", time.Time{}, time.Time{}, err
|
|
}
|
|
|
|
commonName = cert.Subject.CommonName
|
|
if commonName == "" && len(cert.Subject.Names) > 0 {
|
|
commonName = cert.Subject.Names[0].Value.(string)
|
|
}
|
|
|
|
subject = cert.Subject.String()
|
|
issuer = cert.Issuer.String()
|
|
notBefore = cert.NotBefore
|
|
notAfter = cert.NotAfter
|
|
|
|
return commonName, subject, issuer, notBefore, notAfter, nil
|
|
}
|
|
|
|
func generateSelfSignedCertificate(commonName string) (certPEM, keyPEM string, notBefore, notAfter time.Time, err error) {
|
|
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return "", "", time.Time{}, time.Time{}, err
|
|
}
|
|
|
|
notBefore = time.Now()
|
|
notAfter = notBefore.Add(365 * 24 * time.Hour)
|
|
|
|
serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
|
|
if err != nil {
|
|
return "", "", time.Time{}, time.Time{}, err
|
|
}
|
|
|
|
template := x509.Certificate{
|
|
SerialNumber: serialNumber,
|
|
Subject: pkix.Name{
|
|
CommonName: commonName,
|
|
},
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
BasicConstraintsValid: true,
|
|
}
|
|
|
|
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
|
if err != nil {
|
|
return "", "", time.Time{}, time.Time{}, err
|
|
}
|
|
|
|
certPEM = string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}))
|
|
keyPEM = string(pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}))
|
|
|
|
return certPEM, keyPEM, notBefore, notAfter, nil
|
|
}
|
|
|
|
func (api CertificateApi) CreateEndpoint(c echo.Context) error {
|
|
var req struct {
|
|
CommonName string `json:"commonName"`
|
|
Certificate string `json:"certificate"`
|
|
PrivateKey string `json:"privateKey"`
|
|
Type string `json:"type"`
|
|
RequireClientAuth bool `json:"requireClientAuth"`
|
|
}
|
|
if err := c.Bind(&req); err != nil {
|
|
return err
|
|
}
|
|
|
|
item := &model.Certificate{
|
|
ID: utils.UUID(),
|
|
CommonName: req.CommonName,
|
|
Certificate: req.Certificate,
|
|
PrivateKey: req.PrivateKey,
|
|
Type: req.Type,
|
|
RequireClientAuth: req.RequireClientAuth,
|
|
IssuedStatus: "success",
|
|
Created: common.NowJsonTime(),
|
|
UpdatedAt: common.NowJsonTime(),
|
|
}
|
|
|
|
if item.Type == "" {
|
|
item.Type = "imported"
|
|
}
|
|
|
|
if req.Type == "self-signed" && req.Certificate == "" {
|
|
certPEM, keyPEM, notBefore, notAfter, err := generateSelfSignedCertificate(req.CommonName)
|
|
if err == nil {
|
|
item.Certificate = certPEM
|
|
item.PrivateKey = keyPEM
|
|
item.NotBefore = common.NewJsonTime(notBefore)
|
|
item.NotAfter = common.NewJsonTime(notAfter)
|
|
item.Subject = "CN=" + req.CommonName
|
|
item.Issuer = "CN=" + req.CommonName
|
|
}
|
|
} else if req.Certificate != "" {
|
|
commonName, subject, issuer, notBefore, notAfter, err := parseCertificate(req.Certificate)
|
|
if err == nil {
|
|
if item.CommonName == "" {
|
|
item.CommonName = commonName
|
|
}
|
|
item.Subject = subject
|
|
item.Issuer = issuer
|
|
item.NotBefore = common.NewJsonTime(notBefore)
|
|
item.NotAfter = common.NewJsonTime(notAfter)
|
|
}
|
|
}
|
|
|
|
if err := repository.CertificateRepository.Create(context.TODO(), item); err != nil {
|
|
return err
|
|
}
|
|
return Success(c, "")
|
|
}
|
|
|
|
func (api CertificateApi) UpdateEndpoint(c echo.Context) error {
|
|
id := c.Param("id")
|
|
var req struct {
|
|
CommonName string `json:"commonName"`
|
|
Certificate string `json:"certificate"`
|
|
PrivateKey string `json:"privateKey"`
|
|
RequireClientAuth bool `json:"requireClientAuth"`
|
|
}
|
|
if err := c.Bind(&req); err != nil {
|
|
return err
|
|
}
|
|
|
|
item := &model.Certificate{
|
|
ID: id,
|
|
CommonName: req.CommonName,
|
|
Certificate: req.Certificate,
|
|
PrivateKey: req.PrivateKey,
|
|
RequireClientAuth: req.RequireClientAuth,
|
|
UpdatedAt: common.NowJsonTime(),
|
|
}
|
|
|
|
if req.Certificate != "" {
|
|
commonName, subject, issuer, notBefore, notAfter, err := parseCertificate(req.Certificate)
|
|
if err == nil {
|
|
if item.CommonName == "" {
|
|
item.CommonName = commonName
|
|
}
|
|
item.Subject = subject
|
|
item.Issuer = issuer
|
|
item.NotBefore = common.NewJsonTime(notBefore)
|
|
item.NotAfter = common.NewJsonTime(notAfter)
|
|
}
|
|
}
|
|
|
|
if err := repository.CertificateRepository.UpdateById(context.TODO(), item, id); err != nil {
|
|
return err
|
|
}
|
|
return Success(c, nil)
|
|
}
|
|
|
|
func (api CertificateApi) DeleteEndpoint(c echo.Context) error {
|
|
id := c.Param("id")
|
|
if err := repository.CertificateRepository.DeleteById(context.TODO(), id); err != nil {
|
|
return err
|
|
}
|
|
return Success(c, nil)
|
|
}
|
|
|
|
func (api CertificateApi) GetEndpoint(c echo.Context) error {
|
|
id := c.Param("id")
|
|
item, err := repository.CertificateRepository.FindById(context.TODO(), id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return Success(c, item)
|
|
}
|
|
|
|
func (api CertificateApi) UpdateDefaultEndpoint(c echo.Context) error {
|
|
id := c.Param("id")
|
|
|
|
err := repository.CertificateRepository.UpdateById(context.TODO(), &model.Certificate{IsDefault: false}, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return Success(c, nil)
|
|
}
|
|
|
|
func (api CertificateApi) DownloadEndpoint(c echo.Context) error {
|
|
return Success(c, nil)
|
|
}
|
|
|
|
func (api CertificateApi) RenewEndpoint(c echo.Context) error {
|
|
return Success(c, maps.Map{
|
|
"success": true,
|
|
"warning": false,
|
|
"error": "",
|
|
})
|
|
}
|