119 lines
2.6 KiB
Go
119 lines
2.6 KiB
Go
package globals
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/rand"
|
|
"encoding/base32"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
PermitEndpoint = "/api/permit"
|
|
)
|
|
|
|
var Proxy *ProxyClient
|
|
|
|
type ProxyClient struct {
|
|
}
|
|
|
|
func initProxy() {
|
|
Proxy = &ProxyClient{}
|
|
}
|
|
|
|
type ProxyPermitConfig struct {
|
|
Id int32 `json:"id"`
|
|
Whitelists *[]string `json:"whitelists,omitempty"`
|
|
Username *string `json:"username,omitempty"`
|
|
Password *string `json:"password,omitempty"`
|
|
Expire time.Time `json:"expire"`
|
|
}
|
|
|
|
func (p *ProxyClient) Permit(host string, secret string, config []*ProxyPermitConfig) error {
|
|
|
|
// 请求体加密
|
|
body, err := encrypt(config, secret)
|
|
if err != nil {
|
|
return fmt.Errorf("加密请求失败: %w", err)
|
|
}
|
|
|
|
resp, err := http.Post(
|
|
fmt.Sprintf("http://%s:8848%s", host, PermitEndpoint),
|
|
"application/json",
|
|
strings.NewReader(body),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("配置端口许可失败: %s", resp.Status)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func encrypt(req []*ProxyPermitConfig, secretStr string) (string, error) {
|
|
var encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
|
|
|
|
// 创建 AES 密钥
|
|
secret, err := encoding.DecodeString(secretStr)
|
|
if err != nil {
|
|
return "", fmt.Errorf("解码 AES 密钥字符串失败: %w", err)
|
|
}
|
|
|
|
block, err := aes.NewCipher(secret)
|
|
if err != nil {
|
|
return "", fmt.Errorf("创建 AES 密钥失败: %w", err)
|
|
}
|
|
|
|
gcm, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
return "", fmt.Errorf("创建 AES GCM 失败: %w", err)
|
|
}
|
|
|
|
// 加密内容
|
|
bytes, err := json.Marshal(req)
|
|
if err != nil {
|
|
return "", fmt.Errorf("配置参数序列化失败: %w", err)
|
|
}
|
|
|
|
nonceBytes := make([]byte, gcm.NonceSize())
|
|
if _, err := rand.Read(nonceBytes); err != nil {
|
|
return "", fmt.Errorf("生成随机数失败: %w", err)
|
|
}
|
|
nonce := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(nonceBytes)
|
|
|
|
timestamp := time.Now().UnixMilli()
|
|
aad := fmt.Sprintf("%s:%d", nonce, timestamp)
|
|
|
|
ciphertext := gcm.Seal(nil, nonceBytes, bytes, []byte(aad))
|
|
encoded := base64.StdEncoding.EncodeToString(ciphertext)
|
|
|
|
// 生成请求体
|
|
encrypted := EncryptReq{
|
|
Content: encoded,
|
|
Nonce: nonce,
|
|
Timestamp: timestamp,
|
|
}
|
|
|
|
body, err := json.Marshal(encrypted)
|
|
if err != nil {
|
|
return "", fmt.Errorf("请求参数序列化失败: %w", err)
|
|
}
|
|
|
|
return string(body), nil
|
|
}
|
|
|
|
type EncryptReq struct {
|
|
Content string `json:"content"`
|
|
Nonce string `json:"nonce"`
|
|
Timestamp int64 `json:"timestamp"`
|
|
}
|