// Package vkpay verifies VK Mini Apps payment ("голоса") callback signatures. VK signs each // payment notification (get_item / order_status_change) and expects the receiving server to verify // it with the app's secret before acting. The signature is MD5 — mandated by VK's payment protocol, // not a security choice on our part — so this package uses crypto/md5 deliberately. package vkpay import ( "crypto/md5" "encoding/hex" "sort" "strings" ) // Verify reports whether params carry a valid VK payment signature under secret. VK computes the // signature as the MD5 of the sig-excluded parameters, sorted alphabetically by name and // concatenated as key=value with no separators, with the app secret appended. The comparison is // case-insensitive over the hex digest. func Verify(params map[string]string, secret string) bool { got := params["sig"] if got == "" || secret == "" { return false } keys := make([]string, 0, len(params)) for k := range params { if k == "sig" { continue } keys = append(keys, k) } sort.Strings(keys) var b strings.Builder for _, k := range keys { b.WriteString(k) b.WriteString("=") b.WriteString(params[k]) } b.WriteString(secret) sum := md5.Sum([]byte(b.String())) return strings.EqualFold(hex.EncodeToString(sum[:]), got) }