package payment import ( "backend/internal/dto" "errors" "strings" ) // 证书 / 私钥上传处理:校验 PEM 可解析 → 0600 落地到仓库外目录 → 更新配置行。 // Logan.Li // maxUploadBytes 单个上传文件大小上限(PEM 文本,64KB 足够) // Logan.Li const maxUploadBytes = 64 * 1024 // Upload 处理一次证书/密钥上传 // Logan.Li func (s *ConfigService) Upload(kind, filename string, content []byte) (*dto.PaymentUploadResponse, error) { if !IsValidUploadKind(kind) { return nil, errors.New("不支持的上传类型(可选:wechat_cert / wechat_key / wechat_platform_cert / alipay_private_key / alipay_public_key)") } if len(content) == 0 { return nil, errors.New("上传文件为空") } if len(content) > maxUploadBytes { return nil, errors.New("文件过大(上限 64KB)") } row, err := s.loadRow() if err != nil { return nil, err } var certSerial, note string // 1) 内容校验(解析失败直接拒绝入库) // Logan.Li switch kind { case UploadKindWechatCert, UploadKindWechatPlatformCert: cert, perr := ParseCertificatePEM(content) if perr != nil { return nil, errors.New("证书文件校验失败:" + perr.Error()) } certSerial = CertSerialHex(cert) case UploadKindWechatKey: normalized := NormalizePEM(string(content), "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----") if _, perr := ParseRSAPrivateKey([]byte(normalized)); perr != nil { return nil, errors.New("商户 API 私钥校验失败:" + perr.Error()) } content = []byte(normalized) case UploadKindAlipayPrivateKey: normalized := NormalizePEM(string(content), "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----") if _, perr := ParseRSAPrivateKey([]byte(normalized)); perr != nil { return nil, errors.New("应用私钥校验失败:" + perr.Error()) } content = []byte(normalized) case UploadKindAlipayPublicKey: normalized := NormalizePEM(string(content), "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----") if _, perr := ParseRSAPublicKey([]byte(normalized)); perr != nil { return nil, errors.New("支付宝公钥校验失败:" + perr.Error()) } content = []byte(normalized) } // 2) 落地文件(0600,仓库外目录) // Logan.Li path, err := WriteSecretFile(kind, content) if err != nil { return nil, err } // 3) 更新配置行指向新文件 // Logan.Li switch kind { case UploadKindWechatCert: row.WechatCertPath = path if strings.TrimSpace(row.WechatSerialNo) == "" && certSerial != "" { row.WechatSerialNo = certSerial note = "已自动回填证书序列号" } else if certSerial != "" && !strings.EqualFold(strings.TrimSpace(row.WechatSerialNo), certSerial) { note = "注意:填写的序列号与证书实际序列号不一致(证书:" + certSerial + "),请核对" } case UploadKindWechatKey: row.WechatKeyPath = path case UploadKindWechatPlatformCert: row.WechatPlatformCertPath = path case UploadKindAlipayPrivateKey: row.AlipayPrivateKeyPath = path row.AlipayPrivateKeyEnc = "" // 上传后清掉旧的粘贴值,避免来源歧义 // Logan.Li case UploadKindAlipayPublicKey: row.AlipayPublicKeyPath = path row.AlipayPublicKeyEnc = "" } if err := s.db.Save(row).Error; err != nil { return nil, errors.New("保存上传记录失败") } msg := "上传成功:" + filename if note != "" { msg += "(" + note + ")" } return &dto.PaymentUploadResponse{ Kind: kind, File: BuildFileInfo(path, IsCertKind(kind)), Message: msg, }, nil }