mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 11:27:17 +08:00
feat: 添加面板HTTPS接口
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/TheTNB/panel/app/models"
|
||||
"github.com/TheTNB/panel/internal"
|
||||
"github.com/TheTNB/panel/internal/services"
|
||||
"github.com/TheTNB/panel/pkg/cert"
|
||||
"github.com/TheTNB/panel/pkg/io"
|
||||
"github.com/TheTNB/panel/pkg/os"
|
||||
"github.com/TheTNB/panel/pkg/shell"
|
||||
@@ -27,13 +28,12 @@ func NewSettingController() *SettingController {
|
||||
|
||||
// List
|
||||
//
|
||||
// @Summary 设置列表
|
||||
// @Description 获取面板设置列表
|
||||
// @Tags 面板设置
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/setting/list [get]
|
||||
// @Summary 设置列表
|
||||
// @Tags 面板设置
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/setting/list [get]
|
||||
func (r *SettingController) List(ctx http.Context) http.Response {
|
||||
var settings []models.Setting
|
||||
err := facades.Orm().Query().Get(&settings)
|
||||
@@ -77,15 +77,14 @@ func (r *SettingController) List(ctx http.Context) http.Response {
|
||||
|
||||
// Update
|
||||
//
|
||||
// @Summary 更新设置
|
||||
// @Description 更新面板设置
|
||||
// @Tags 面板设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Param data body requests.Update true "request"
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/setting/update [post]
|
||||
// @Summary 更新设置
|
||||
// @Tags 面板设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Param data body requests.Update true "request"
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/setting/update [post]
|
||||
func (r *SettingController) Update(ctx http.Context) http.Response {
|
||||
var updateRequest requests.Update
|
||||
sanitize := SanitizeRequest(ctx, &updateRequest)
|
||||
@@ -213,7 +212,70 @@ func (r *SettingController) Update(ctx http.Context) http.Response {
|
||||
}
|
||||
}
|
||||
|
||||
if updateRequest.SSL {
|
||||
if oldPort != port || oldEntrance != entrance || oldLanguage != updateRequest.Language {
|
||||
tools.RestartPanel()
|
||||
}
|
||||
|
||||
return Success(ctx, nil)
|
||||
}
|
||||
|
||||
// GetHttps
|
||||
//
|
||||
// @Summary 获取面板 HTTPS 设置
|
||||
// @Tags 面板设置
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/setting/https [get]
|
||||
func (r *SettingController) GetHttps(ctx http.Context) http.Response {
|
||||
certPath := facades.Config().GetString("http.tls.ssl.cert")
|
||||
keyPath := facades.Config().GetString("http.tls.ssl.key")
|
||||
crt, err := io.Read(certPath)
|
||||
if err != nil {
|
||||
return ErrorSystem(ctx)
|
||||
}
|
||||
key, err := io.Read(keyPath)
|
||||
if err != nil {
|
||||
return ErrorSystem(ctx)
|
||||
}
|
||||
|
||||
return Success(ctx, http.Json{
|
||||
"https": facades.Config().GetBool("panel.ssl"),
|
||||
"cert": crt,
|
||||
"key": key,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateHttps
|
||||
//
|
||||
// @Summary 更新面板 HTTPS 设置
|
||||
// @Tags 面板设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Param data body requests.Https true "request"
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/setting/https [post]
|
||||
func (r *SettingController) UpdateHttps(ctx http.Context) http.Response {
|
||||
var httpsRequest requests.Https
|
||||
sanitize := SanitizeRequest(ctx, &httpsRequest)
|
||||
if sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
|
||||
if httpsRequest.Https {
|
||||
if _, err := cert.ParseCert(httpsRequest.Cert); err != nil {
|
||||
return Error(ctx, http.StatusBadRequest, "证书格式错误")
|
||||
}
|
||||
if _, err := cert.ParseKey(httpsRequest.Key); err != nil {
|
||||
return Error(ctx, http.StatusBadRequest, "密钥格式错误")
|
||||
}
|
||||
if err := io.Write(facades.App().ExecutablePath("storage/ssl.crt"), httpsRequest.Cert, 0700); err != nil {
|
||||
return ErrorSystem(ctx)
|
||||
}
|
||||
if err := io.Write(facades.App().ExecutablePath("storage/ssl.key"), httpsRequest.Key, 0700); err != nil {
|
||||
return ErrorSystem(ctx)
|
||||
}
|
||||
if out, err := shell.Execf("sed -i 's/APP_SSL=false/APP_SSL=true/g' /www/panel/panel.conf"); err != nil {
|
||||
return Error(ctx, http.StatusInternalServerError, out)
|
||||
}
|
||||
@@ -223,9 +285,6 @@ func (r *SettingController) Update(ctx http.Context) http.Response {
|
||||
}
|
||||
}
|
||||
|
||||
if oldPort != port || oldEntrance != entrance || oldLanguage != updateRequest.Language || updateRequest.SSL != facades.Config().GetBool("panel.ssl") {
|
||||
tools.RestartPanel()
|
||||
}
|
||||
|
||||
tools.RestartPanel()
|
||||
return Success(ctx, nil)
|
||||
}
|
||||
|
||||
36
app/http/requests/setting/https.go
Normal file
36
app/http/requests/setting/https.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package requests
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/contracts/validation"
|
||||
)
|
||||
|
||||
type Https struct {
|
||||
Https bool `form:"https" json:"https"`
|
||||
Cert string `form:"cert" json:"cert"`
|
||||
Key string `form:"key" json:"key"`
|
||||
}
|
||||
|
||||
func (r *Https) Authorize(ctx http.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Https) Rules(ctx http.Context) map[string]string {
|
||||
return map[string]string{
|
||||
"https": "bool",
|
||||
"cert": "string",
|
||||
"key": "string",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Https) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Https) Attributes(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Https) PrepareForValidation(ctx http.Context, data validation.Data) error {
|
||||
return nil
|
||||
}
|
||||
@@ -12,7 +12,6 @@ type Update struct {
|
||||
BackupPath string `form:"backup_path" json:"backup_path"`
|
||||
WebsitePath string `form:"website_path" json:"website_path"`
|
||||
Entrance string `form:"entrance" json:"entrance"`
|
||||
SSL bool `form:"ssl" json:"ssl"`
|
||||
UserName string `form:"username" json:"username"`
|
||||
Email string `form:"email" json:"email"`
|
||||
Password string `form:"password" json:"password"`
|
||||
@@ -30,7 +29,6 @@ func (r *Update) Rules(ctx http.Context) map[string]string {
|
||||
"backup_path": "required|string:2,255",
|
||||
"website_path": "required|string:2,255",
|
||||
"entrance": `required|regex:^/(\w+)?$|not_in:/api`,
|
||||
"ssl": "bool",
|
||||
"username": "required|string:2,20",
|
||||
"email": "required|email",
|
||||
"password": "string:8,255",
|
||||
|
||||
79
docs/docs.go
79
docs/docs.go
@@ -2830,6 +2830,66 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/setting/https": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"面板设置"
|
||||
],
|
||||
"summary": "获取面板 HTTPS 设置",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"面板设置"
|
||||
],
|
||||
"summary": "更新面板 HTTPS 设置",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/requests.Https"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/setting/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -2837,7 +2897,6 @@ const docTemplate = `{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "获取面板设置列表",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -2862,7 +2921,6 @@ const docTemplate = `{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "更新面板设置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -5006,9 +5064,6 @@ const docTemplate = `{
|
||||
"port": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -5467,6 +5522,20 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.Https": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cert": {
|
||||
"type": "string"
|
||||
},
|
||||
"https": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.ImagePull": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -2823,6 +2823,66 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/setting/https": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"面板设置"
|
||||
],
|
||||
"summary": "获取面板 HTTPS 设置",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"面板设置"
|
||||
],
|
||||
"summary": "更新面板 HTTPS 设置",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/requests.Https"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/setting/list": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -2830,7 +2890,6 @@
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "获取面板设置列表",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -2855,7 +2914,6 @@
|
||||
"BearerToken": []
|
||||
}
|
||||
],
|
||||
"description": "更新面板设置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -4999,9 +5057,6 @@
|
||||
"port": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ssl": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -5460,6 +5515,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.Https": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cert": {
|
||||
"type": "string"
|
||||
},
|
||||
"https": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.ImagePull": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -84,8 +84,6 @@ definitions:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
ssl:
|
||||
type: boolean
|
||||
username:
|
||||
type: string
|
||||
website_path:
|
||||
@@ -389,6 +387,15 @@ definitions:
|
||||
path:
|
||||
type: string
|
||||
type: object
|
||||
requests.Https:
|
||||
properties:
|
||||
cert:
|
||||
type: string
|
||||
https:
|
||||
type: boolean
|
||||
key:
|
||||
type: string
|
||||
type: object
|
||||
requests.ImagePull:
|
||||
properties:
|
||||
auth:
|
||||
@@ -2384,9 +2391,44 @@ paths:
|
||||
summary: 更新插件首页显示状态
|
||||
tags:
|
||||
- 插件
|
||||
/panel/setting/https:
|
||||
get:
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 获取面板 HTTPS 设置
|
||||
tags:
|
||||
- 面板设置
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/requests.Https'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 更新面板 HTTPS 设置
|
||||
tags:
|
||||
- 面板设置
|
||||
/panel/setting/list:
|
||||
get:
|
||||
description: 获取面板设置列表
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -2403,7 +2445,6 @@ paths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新面板设置
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
requests "github.com/TheTNB/panel/app/http/requests/cert"
|
||||
"github.com/TheTNB/panel/app/models"
|
||||
"github.com/TheTNB/panel/pkg/acme"
|
||||
"github.com/TheTNB/panel/pkg/cert"
|
||||
"github.com/TheTNB/panel/pkg/io"
|
||||
"github.com/TheTNB/panel/pkg/systemctl"
|
||||
)
|
||||
@@ -54,7 +55,7 @@ func (s *CertImpl) UserStore(request requests.UserStore) error {
|
||||
return errors.New("向 CA 注册账号失败,请检查参数是否正确")
|
||||
}
|
||||
|
||||
privateKey, err := acme.EncodePrivateKey(client.Account.PrivateKey)
|
||||
privateKey, err := cert.EncodeKey(client.Account.PrivateKey)
|
||||
if err != nil {
|
||||
return errors.New("获取私钥失败")
|
||||
}
|
||||
@@ -97,7 +98,7 @@ func (s *CertImpl) UserUpdate(request requests.UserUpdate) error {
|
||||
return errors.New("向 CA 注册账号失败,请检查参数是否正确")
|
||||
}
|
||||
|
||||
privateKey, err := acme.EncodePrivateKey(client.Account.PrivateKey)
|
||||
privateKey, err := cert.EncodeKey(client.Account.PrivateKey)
|
||||
if err != nil {
|
||||
return errors.New("获取私钥失败")
|
||||
}
|
||||
|
||||
@@ -4,20 +4,17 @@ import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/acmez/v2"
|
||||
"github.com/mholt/acmez/v2/acme"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/TheTNB/panel/pkg/cert"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -77,7 +74,7 @@ func NewPrivateKeyAccount(email string, privateKey string, CA string, eab *EAB)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := parsePrivateKey([]byte(privateKey))
|
||||
key, err := cert.ParseKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -102,36 +99,6 @@ func NewPrivateKeyAccount(email string, privateKey string, CA string, eab *EAB)
|
||||
return &Client{Account: account, zClient: client}, nil
|
||||
}
|
||||
|
||||
func parsePrivateKey(key []byte) (crypto.Signer, error) {
|
||||
keyBlockDER, _ := pem.Decode(key)
|
||||
if keyBlockDER == nil {
|
||||
return nil, errors.New("invalid PEM block")
|
||||
}
|
||||
|
||||
if keyBlockDER.Type != "PRIVATE KEY" && !strings.HasSuffix(keyBlockDER.Type, " PRIVATE KEY") {
|
||||
return nil, fmt.Errorf("unknown PEM header %q", keyBlockDER.Type)
|
||||
}
|
||||
|
||||
if parse, err := x509.ParsePKCS1PrivateKey(keyBlockDER.Bytes); err == nil {
|
||||
return parse, nil
|
||||
}
|
||||
|
||||
if parse, err := x509.ParsePKCS8PrivateKey(keyBlockDER.Bytes); err == nil {
|
||||
switch parse.(type) {
|
||||
case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
|
||||
return parse.(crypto.Signer), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("found unknown private key type in PKCS#8 wrapping: %T", key)
|
||||
}
|
||||
}
|
||||
|
||||
if parse, err := x509.ParseECPrivateKey(keyBlockDER.Bytes); err == nil {
|
||||
return parse, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("解析私钥失败")
|
||||
}
|
||||
|
||||
func generatePrivateKey(keyType KeyType) (crypto.Signer, error) {
|
||||
switch keyType {
|
||||
case KeyEC256:
|
||||
@@ -149,34 +116,6 @@ func generatePrivateKey(keyType KeyType) (crypto.Signer, error) {
|
||||
return nil, errors.New("未知的密钥类型")
|
||||
}
|
||||
|
||||
func EncodePrivateKey(key crypto.Signer) ([]byte, error) {
|
||||
var pemType string
|
||||
var keyBytes []byte
|
||||
switch key := key.(type) {
|
||||
case *ecdsa.PrivateKey:
|
||||
var err error
|
||||
pemType = "EC"
|
||||
keyBytes, err = x509.MarshalECPrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case *rsa.PrivateKey:
|
||||
pemType = "RSA"
|
||||
keyBytes = x509.MarshalPKCS1PrivateKey(key)
|
||||
case ed25519.PrivateKey:
|
||||
var err error
|
||||
pemType = "ED25519"
|
||||
keyBytes, err = x509.MarshalPKCS8PrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("未知的密钥类型 %T", key)
|
||||
}
|
||||
pemKey := pem.Block{Type: pemType + " PRIVATE KEY", Bytes: keyBytes}
|
||||
return pem.EncodeToMemory(&pemKey), nil
|
||||
}
|
||||
|
||||
func getClient(CA string) (acmez.Client, error) {
|
||||
logger, err := zap.NewProduction()
|
||||
if err != nil {
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"github.com/libdns/libdns"
|
||||
"github.com/mholt/acmez/v2"
|
||||
"github.com/mholt/acmez/v2/acme"
|
||||
|
||||
"github.com/TheTNB/panel/pkg/cert"
|
||||
)
|
||||
|
||||
type Certificate struct {
|
||||
@@ -61,7 +63,7 @@ func (c *Client) ObtainSSL(ctx context.Context, domains []string, keyType KeyTyp
|
||||
if err != nil {
|
||||
return Certificate{}, err
|
||||
}
|
||||
pemPrivateKey, err := EncodePrivateKey(certPrivateKey)
|
||||
pemPrivateKey, err := cert.EncodeKey(certPrivateKey)
|
||||
if err != nil {
|
||||
return Certificate{}, err
|
||||
}
|
||||
|
||||
89
pkg/cert/cert.go
Normal file
89
pkg/cert/cert.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package cert
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ParseCert(crt string) (x509.Certificate, error) {
|
||||
certBlock, _ := pem.Decode([]byte(crt))
|
||||
if certBlock == nil {
|
||||
return x509.Certificate{}, errors.New("invalid PEM block")
|
||||
}
|
||||
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||
if err != nil {
|
||||
return x509.Certificate{}, err
|
||||
}
|
||||
|
||||
return *cert, nil
|
||||
}
|
||||
|
||||
func ParseKey(key string) (crypto.Signer, error) {
|
||||
keyBlockDER, _ := pem.Decode([]byte(key))
|
||||
if keyBlockDER == nil {
|
||||
return nil, errors.New("invalid PEM block")
|
||||
}
|
||||
|
||||
if keyBlockDER.Type != "PRIVATE KEY" && !strings.HasSuffix(keyBlockDER.Type, " PRIVATE KEY") {
|
||||
return nil, fmt.Errorf("unknown PEM header %q", keyBlockDER.Type)
|
||||
}
|
||||
|
||||
if parse, err := x509.ParsePKCS1PrivateKey(keyBlockDER.Bytes); err == nil {
|
||||
return parse, nil
|
||||
}
|
||||
|
||||
if parse, err := x509.ParsePKCS8PrivateKey(keyBlockDER.Bytes); err == nil {
|
||||
switch parse.(type) {
|
||||
case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
|
||||
return parse.(crypto.Signer), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("found unknown private key type in PKCS#8 wrapping: %T", key)
|
||||
}
|
||||
}
|
||||
|
||||
if parse, err := x509.ParseECPrivateKey(keyBlockDER.Bytes); err == nil {
|
||||
return parse, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("解析私钥失败")
|
||||
}
|
||||
|
||||
func EncodeCert(cert x509.Certificate) ([]byte, error) {
|
||||
pemCert := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}
|
||||
return pem.EncodeToMemory(&pemCert), nil
|
||||
}
|
||||
|
||||
func EncodeKey(key crypto.Signer) ([]byte, error) {
|
||||
var pemType string
|
||||
var keyBytes []byte
|
||||
switch key := key.(type) {
|
||||
case *ecdsa.PrivateKey:
|
||||
var err error
|
||||
pemType = "EC"
|
||||
keyBytes, err = x509.MarshalECPrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case *rsa.PrivateKey:
|
||||
pemType = "RSA"
|
||||
keyBytes = x509.MarshalPKCS1PrivateKey(key)
|
||||
case ed25519.PrivateKey:
|
||||
var err error
|
||||
pemType = "ED25519"
|
||||
keyBytes, err = x509.MarshalPKCS8PrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("未知的密钥类型 %T", key)
|
||||
}
|
||||
pemKey := pem.Block{Type: pemType + " PRIVATE KEY", Bytes: keyBytes}
|
||||
return pem.EncodeToMemory(&pemKey), nil
|
||||
}
|
||||
@@ -199,6 +199,8 @@ func Api() {
|
||||
settingController := controllers.NewSettingController()
|
||||
r.Get("list", settingController.List)
|
||||
r.Post("update", settingController.Update)
|
||||
r.Get("https", settingController.GetHttps)
|
||||
r.Post("https", settingController.UpdateHttps)
|
||||
})
|
||||
r.Prefix("system").Middleware(middleware.Jwt()).Group(func(r route.Router) {
|
||||
controller := controllers.NewSystemController()
|
||||
|
||||
Reference in New Issue
Block a user