♻️ refactor(handlers): status 与 review 页面模板化

- HTML 提取至 templates/status.html、templates/review.html(go:embed 内嵌)
- status.go 1022→271 行、review.go 1281→438 行,动态数据全部经 html/template 按上下文自动转义
- 评论循环/作者徽章/贴纸/图片条件渲染翻译为模板 range/if;emojiMap 以 template.JS 注入
- 与旧版渲染输出实测对比:22 条评论结构完全一致;差异仅为 JS 上下文安全转义(& 等)与 html/template 剥除 CSS 注释,均无功能影响
- 其余文件为 gofmt 顺手格式化
This commit is contained in:
chenxin committed 2026-09-30 00:25:09 +08:00
1 parent ad6d28fd85
commit 5bcc8a962e
29 files changed
+1267 -2893

No files matched your search

+184 -185
View File
@@ -1,185 +1,184 @@
package fqapi
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"math/big"
)
// CM 加密管理器
type CM struct {
bigC *big.Int // 大素数C
bigB int64 // 底数B
arryD []byte // 固定密钥
thisD [2]*big.Int // 密钥对(私钥, 公钥)
thisC []byte // 随机IV
}
// NewCM 创建新的CM实例
func NewCM() *CM {
// 大素数C
bigCStr := "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"
bigC := new(big.Int)
bigC.SetString(bigCStr, 10)
// 固定密钥(base64解码)
arryD, _ := base64.StdEncoding.DecodeString("rCXGfd2POMGzeiNIgo4iLg==")
return &CM{
bigC: bigC,
bigB: 2,
arryD: arryD,
}
}
// generateKeyPair 生成密钥对
func (cm *CM) generateKeyPair() [2]*big.Int {
// 生成随机私钥
randomBytes := make([]byte, 32)
rand.Read(randomBytes)
x := new(big.Int).SetBytes(randomBytes)
x = x.Mod(x, new(big.Int).Sub(cm.bigC, big.NewInt(1)))
// 计算公钥: y = b^x mod c
y := new(big.Int).Exp(big.NewInt(cm.bigB), x, cm.bigC)
cm.thisD = [2]*big.Int{x, y}
return cm.thisD
}
// pairToBytes 将公钥转换为字节数组
func (cm *CM) pairToBytes(keyPair [2]*big.Int) []byte {
return keyPair[1].Bytes()
}
// randIV 生成随机IV
func (cm *CM) randIV() []byte {
iv := make([]byte, 16)
rand.Read(iv)
return iv
}
// encodeAES AES-CBC加密
func (cm *CM) encodeAES(key, iv, data []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
// PKCS7填充
padding := aes.BlockSize - len(data)%aes.BlockSize
padText := make([]byte, padding)
for i := range padText {
padText[i] = byte(padding)
}
paddedData := append(data, padText...)
ciphertext := make([]byte, len(paddedData))
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, paddedData)
return ciphertext, nil
}
// decodeAES AES-CBC解密
func (cm *CM) decodeAES(key, iv, data []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
mode := cipher.NewCBCDecrypter(block, iv)
decrypted := make([]byte, len(data))
mode.CryptBlocks(decrypted, data)
// 移除PKCS7填充
padding := int(decrypted[len(decrypted)-1])
if padding > len(decrypted) || padding > aes.BlockSize {
return nil, fmt.Errorf("无效的填充")
}
return decrypted[:len(decrypted)-padding], nil
}
// ClientHandshake 客户端握手,生成请求头y
func (cm *CM) ClientHandshake() string {
keyPair := cm.generateKeyPair()
cm.thisC = cm.randIV()
publicKeyBytes := cm.pairToBytes(keyPair)
encrypted, _ := cm.encodeAES(cm.arryD, cm.thisC, publicKeyBytes)
combined := append(cm.thisC, encrypted...)
return base64.StdEncoding.EncodeToString(combined)
}
// decryptF 解密函数
func (cm *CM) decryptF(peerPublicKey []byte, keyPair [2]*big.Int, iv, data []byte) ([]byte, error) {
x := keyPair[0]
// 计算共享密钥: shared_secret = peer_public_key^x mod c
peerPubInt := new(big.Int).SetBytes(peerPublicKey)
sharedSecret := new(big.Int).Exp(peerPubInt, x, cm.bigC)
key := sharedSecret.Bytes()
// 确保key长度为32字节
if len(key) < 32 {
// 前面补0
paddedKey := make([]byte, 32)
copy(paddedKey[32-len(key):], key)
key = paddedKey
} else if len(key) > 32 {
key = key[:32]
}
return cm.decodeAES(key, iv, data)
}
// Decrypt 解密响应内容
func (cm *CM) Decrypt(c, y, content string) (string, error) {
// c 应该为 "1" 表示启用加密
// y 是服务器返回的公钥
// content 是加密的内容
if c != "1" || y == "" {
return content, nil
}
// 解码content
contentDecoded, err := base64.StdEncoding.DecodeString(content)
if err != nil {
return "", err
}
if len(contentDecoded) < 16 {
return "", fmt.Errorf("内容太短")
}
// 提取IV和数据
iv := contentDecoded[:16]
data := contentDecoded[16:]
// 解码服务器公钥
peerPublicKey, err := base64.StdEncoding.DecodeString(y)
if err != nil {
return "", err
}
// 检查密钥对是否已初始化
if cm.thisD[0] == nil {
return "", fmt.Errorf("密钥对未初始化")
}
// 解密
decrypted, err := cm.decryptF(peerPublicKey, cm.thisD, iv, data)
if err != nil {
return "", err
}
return string(decrypted), nil
}
package fqapi
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"math/big"
)
// CM 加密管理器
type CM struct {
bigC *big.Int // 大素数C
bigB int64 // 底数B
arryD []byte // 固定密钥
thisD [2]*big.Int // 密钥对(私钥, 公钥)
thisC []byte // 随机IV
}
// NewCM 创建新的CM实例
func NewCM() *CM {
// 大素数C
bigCStr := "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"
bigC := new(big.Int)
bigC.SetString(bigCStr, 10)
// 固定密钥(base64解码)
arryD, _ := base64.StdEncoding.DecodeString("rCXGfd2POMGzeiNIgo4iLg==")
return &CM{
bigC: bigC,
bigB: 2,
arryD: arryD,
}
}
// generateKeyPair 生成密钥对
func (cm *CM) generateKeyPair() [2]*big.Int {
// 生成随机私钥
randomBytes := make([]byte, 32)
rand.Read(randomBytes)
x := new(big.Int).SetBytes(randomBytes)
x = x.Mod(x, new(big.Int).Sub(cm.bigC, big.NewInt(1)))
// 计算公钥: y = b^x mod c
y := new(big.Int).Exp(big.NewInt(cm.bigB), x, cm.bigC)
cm.thisD = [2]*big.Int{x, y}
return cm.thisD
}
// pairToBytes 将公钥转换为字节数组
func (cm *CM) pairToBytes(keyPair [2]*big.Int) []byte {
return keyPair[1].Bytes()
}
// randIV 生成随机IV
func (cm *CM) randIV() []byte {
iv := make([]byte, 16)
rand.Read(iv)
return iv
}
// encodeAES AES-CBC加密
func (cm *CM) encodeAES(key, iv, data []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
// PKCS7填充
padding := aes.BlockSize - len(data)%aes.BlockSize
padText := make([]byte, padding)
for i := range padText {
padText[i] = byte(padding)
}
paddedData := append(data, padText...)
ciphertext := make([]byte, len(paddedData))
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, paddedData)
return ciphertext, nil
}
// decodeAES AES-CBC解密
func (cm *CM) decodeAES(key, iv, data []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
mode := cipher.NewCBCDecrypter(block, iv)
decrypted := make([]byte, len(data))
mode.CryptBlocks(decrypted, data)
// 移除PKCS7填充
padding := int(decrypted[len(decrypted)-1])
if padding > len(decrypted) || padding > aes.BlockSize {
return nil, fmt.Errorf("无效的填充")
}
return decrypted[:len(decrypted)-padding], nil
}
// ClientHandshake 客户端握手,生成请求头y
func (cm *CM) ClientHandshake() string {
keyPair := cm.generateKeyPair()
cm.thisC = cm.randIV()
publicKeyBytes := cm.pairToBytes(keyPair)
encrypted, _ := cm.encodeAES(cm.arryD, cm.thisC, publicKeyBytes)
combined := append(cm.thisC, encrypted...)
return base64.StdEncoding.EncodeToString(combined)
}
// decryptF 解密函数
func (cm *CM) decryptF(peerPublicKey []byte, keyPair [2]*big.Int, iv, data []byte) ([]byte, error) {
x := keyPair[0]
// 计算共享密钥: shared_secret = peer_public_key^x mod c
peerPubInt := new(big.Int).SetBytes(peerPublicKey)
sharedSecret := new(big.Int).Exp(peerPubInt, x, cm.bigC)
key := sharedSecret.Bytes()
// 确保key长度为32字节
if len(key) < 32 {
// 前面补0
paddedKey := make([]byte, 32)
copy(paddedKey[32-len(key):], key)
key = paddedKey
} else if len(key) > 32 {
key = key[:32]
}
return cm.decodeAES(key, iv, data)
}
// Decrypt 解密响应内容
func (cm *CM) Decrypt(c, y, content string) (string, error) {
// c 应该为 "1" 表示启用加密
// y 是服务器返回的公钥
// content 是加密的内容
if c != "1" || y == "" {
return content, nil
}
// 解码content
contentDecoded, err := base64.StdEncoding.DecodeString(content)
if err != nil {
return "", err
}
if len(contentDecoded) < 16 {
return "", fmt.Errorf("内容太短")
}
// 提取IV和数据
iv := contentDecoded[:16]
data := contentDecoded[16:]
// 解码服务器公钥
peerPublicKey, err := base64.StdEncoding.DecodeString(y)
if err != nil {
return "", err
}
// 检查密钥对是否已初始化
if cm.thisD[0] == nil {
return "", fmt.Errorf("密钥对未初始化")
}
// 解密
decrypted, err := cm.decryptF(peerPublicKey, cm.thisD, iv, data)
if err != nil {
return "", err
}
return string(decrypted), nil
}