82 lines
1.8 KiB
Go
82 lines
1.8 KiB
Go
package protocol
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
)
|
|
|
|
// RequestFingerprint 计算第 7.3 节发送请求指纹(十六进制小写 SHA-256)。
|
|
// 字段:to.kind、to.id、body.enc、content_type、解码后正文、meta(键排序)、
|
|
// send_at_ms、delay_ms、offline.keep、offline.ttl_seconds、receipt。
|
|
// 不含 talk_password 与 rid。meta 键顺序不影响结果。
|
|
// receipt / offline 使用文档默认值后的有效值;缺省的 send_at_ms、delay_ms 不写入对应槽位。
|
|
func RequestFingerprint(s *Send) (string, error) {
|
|
raw, err := DecodeBody(s.Body)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
metaJSON, err := MetaCanonicalJSON(s.Meta)
|
|
if err != nil {
|
|
return "", badRequest("invalid meta")
|
|
}
|
|
|
|
h := sha256.New()
|
|
writeStr(h, s.To.Kind)
|
|
writeStr(h, s.To.ID)
|
|
writeStr(h, s.Body.Enc)
|
|
writeStr(h, EffectiveContentType(s.Body))
|
|
writeBytes(h, raw)
|
|
writeBytes(h, metaJSON)
|
|
|
|
writeOptInt64(h, s.SendAtMs)
|
|
writeOptInt64(h, s.DelayMs)
|
|
|
|
keep := EffectiveOfflineKeep(s)
|
|
writeBool(h, keep)
|
|
ttl := EffectiveOfflineTTL(s)
|
|
writeInt64(h, ttl)
|
|
writeBool(h, EffectiveReceipt(s))
|
|
|
|
sum := h.Sum(nil)
|
|
return hex.EncodeToString(sum), nil
|
|
}
|
|
|
|
type hashWriter interface {
|
|
Write(p []byte) (int, error)
|
|
}
|
|
|
|
func writeStr(h hashWriter, s string) {
|
|
writeBytes(h, []byte(s))
|
|
}
|
|
|
|
func writeBytes(h hashWriter, b []byte) {
|
|
var lenBuf [8]byte
|
|
binary.BigEndian.PutUint64(lenBuf[:], uint64(len(b)))
|
|
_, _ = h.Write(lenBuf[:])
|
|
_, _ = h.Write(b)
|
|
}
|
|
|
|
func writeBool(h hashWriter, v bool) {
|
|
if v {
|
|
_, _ = h.Write([]byte{1})
|
|
} else {
|
|
_, _ = h.Write([]byte{0})
|
|
}
|
|
}
|
|
|
|
func writeInt64(h hashWriter, v int64) {
|
|
var buf [8]byte
|
|
binary.BigEndian.PutUint64(buf[:], uint64(v))
|
|
_, _ = h.Write(buf[:])
|
|
}
|
|
|
|
func writeOptInt64(h hashWriter, v *int64) {
|
|
if v == nil {
|
|
_, _ = h.Write([]byte{0})
|
|
return
|
|
}
|
|
_, _ = h.Write([]byte{1})
|
|
writeInt64(h, *v)
|
|
}
|