package secretbox import ( "fmt" "gorm.io/gorm" ) // MigratePlaintext 启动时把历史明文机密一次性加密回写(幂等,可重跑)。 // 只处理非空且无 enc:v1: 前缀的值;双节点各自执行,密文经节点同步后 // 在相同 OPSLIC_MASTER_KEY 下均可解密。 // Logan.Li func MigratePlaintext(db *gorm.DB) error { if !Ready() { return fmt.Errorf("secretbox: 主密钥未装载,拒绝执行机密迁移") } // payment_gateway_configs: 主键为 gateway(字符串) // Logan.Li var gwRows []struct { Gateway string SecretKey string WebhookSecret string } if err := db.Raw(`SELECT gateway, secret_key, webhook_secret FROM payment_gateway_configs WHERE (secret_key <> '' AND secret_key NOT LIKE ?) OR (webhook_secret <> '' AND webhook_secret NOT LIKE ?)`, Prefix+"%", Prefix+"%"). Scan(&gwRows).Error; err != nil { return fmt.Errorf("扫描 payment_gateway_configs: %w", err) } for _, r := range gwRows { encSecret, err := Encrypt(r.SecretKey) if err != nil { return fmt.Errorf("加密 %s.secret_key: %w", r.Gateway, err) } encWebhook, err := Encrypt(r.WebhookSecret) if err != nil { return fmt.Errorf("加密 %s.webhook_secret: %w", r.Gateway, err) } if err := db.Exec(`UPDATE payment_gateway_configs SET secret_key = ?, webhook_secret = ? WHERE gateway = ?`, encSecret, encWebhook, r.Gateway).Error; err != nil { return fmt.Errorf("回写 %s: %w", r.Gateway, err) } } // peer_nodes: 主键为 id(整型) // Logan.Li var peerRows []struct { ID uint SharedKey string } if err := db.Raw(`SELECT id, shared_key FROM peer_nodes WHERE shared_key <> '' AND shared_key NOT LIKE ?`, Prefix+"%"). Scan(&peerRows).Error; err != nil { return fmt.Errorf("扫描 peer_nodes: %w", err) } for _, r := range peerRows { enc, err := Encrypt(r.SharedKey) if err != nil { return fmt.Errorf("加密 peer_nodes.%d: %w", r.ID, err) } if err := db.Exec(`UPDATE peer_nodes SET shared_key = ? WHERE id = ?`, enc, r.ID).Error; err != nil { return fmt.Errorf("回写 peer_nodes.%d: %w", r.ID, err) } } return nil }