feat: deliver authenticated task APIs, SDK and P1 regression

This commit is contained in:
2026-09-17 07:41:32 +08:00
parent 4f2935e36f
commit 9701b7a071
37 changed files with 3169 additions and 67 deletions

View File

@@ -0,0 +1,194 @@
// Package jsonvalue 比较 JSON 的实际内容,不将 JSON 数值转换为浮点数。
package jsonvalue
import (
"bytes"
"encoding/json"
"errors"
"io"
"sort"
"strconv"
"strings"
"unicode/utf8"
)
// Canonical 生成内部 orbit-json-v1 摘要输入:对象键排序、重复键拒绝、
// 精确十进制数规范化。该格式不是对外 JSON 编码承诺,也不宣称实现 RFC 8785。
func Canonical(raw []byte) ([]byte, error) {
if !utf8.Valid(raw) {
return nil, errors.New("JSON must be valid UTF-8")
}
if err := validEscapes(raw); err != nil {
return nil, err
}
d := json.NewDecoder(bytes.NewReader(raw))
d.UseNumber()
b, err := value(d, 0)
if err != nil {
return nil, err
}
if _, err := d.Token(); err != io.EOF {
return nil, errors.New("exactly one JSON value required")
}
return b, nil
}
func value(d *json.Decoder, depth int) ([]byte, error) {
if depth > 32 {
return nil, errors.New("JSON nesting exceeds 32 levels")
}
t, err := d.Token()
if err != nil {
return nil, err
}
switch v := t.(type) {
case json.Delim:
switch v {
case '{':
fields := map[string][]byte{}
keys := []string{}
for d.More() {
token, err := d.Token()
if err != nil {
return nil, err
}
key, ok := token.(string)
if !ok {
return nil, errors.New("invalid object key")
}
if _, ok := fields[key]; ok {
return nil, errors.New("duplicate JSON object key")
}
b, err := value(d, depth+1)
if err != nil {
return nil, err
}
fields[key] = b
keys = append(keys, key)
}
if close, err := d.Token(); err != nil || close != json.Delim('}') {
return nil, errors.New("unterminated JSON object")
}
sort.Strings(keys)
var b bytes.Buffer
b.WriteByte('{')
for i, k := range keys {
if i > 0 {
b.WriteByte(',')
}
key, _ := json.Marshal(k)
b.Write(key)
b.WriteByte(':')
b.Write(fields[k])
}
b.WriteByte('}')
return b.Bytes(), nil
case '[':
var b bytes.Buffer
b.WriteByte('[')
n := 0
for d.More() {
v, err := value(d, depth+1)
if err != nil {
return nil, err
}
if n > 0 {
b.WriteByte(',')
}
b.Write(v)
n++
}
if close, err := d.Token(); err != nil || close != json.Delim(']') {
return nil, errors.New("unterminated JSON array")
}
b.WriteByte(']')
return b.Bytes(), nil
default:
return nil, errors.New("unexpected JSON delimiter")
}
case json.Number:
return number(string(v))
default:
return json.Marshal(v)
}
}
func number(s string) ([]byte, error) {
if len(s) > 256 {
return nil, errors.New("JSON number exceeds 256 characters")
}
// 仅用作有限范围检查;摘要始终由下面的十进制文本运算生成。
if _, err := strconv.ParseFloat(s, 64); err != nil {
return nil, errors.New("JSON number outside supported range")
}
negative := strings.HasPrefix(s, "-")
s = strings.TrimPrefix(s, "-")
exponent := 0
if i := strings.IndexAny(s, "eE"); i >= 0 {
var err error
exponent, err = strconv.Atoi(s[i+1:])
if err != nil || exponent < -308 || exponent > 308 {
return nil, errors.New("JSON exponent outside supported range")
}
s = s[:i]
}
if i := strings.IndexByte(s, '.'); i >= 0 {
exponent -= len(s) - i - 1
s = s[:i] + s[i+1:]
}
s = strings.TrimLeft(s, "0")
if s == "" {
return []byte("0"), nil
}
for strings.HasSuffix(s, "0") {
s = s[:len(s)-1]
exponent++
}
if exponent < -308 || exponent > 308 {
return nil, errors.New("normalized JSON exponent outside supported range")
}
if exponent+len(s)-1 > 308 {
return nil, errors.New("JSON number outside supported range")
}
if negative {
s = "-" + s
}
if exponent != 0 {
s += "e" + strconv.Itoa(exponent)
}
return []byte(s), nil
}
// encoding/json 会替换孤立 UTF-16 代理项;拒绝它们,避免两个不同输入被悄悄合并。
func validEscapes(raw []byte) error {
for i := 0; i < len(raw); i++ {
if raw[i] != '\\' {
continue
}
i++
if i >= len(raw) || raw[i] != 'u' {
continue
}
if i+4 >= len(raw) {
return errors.New("invalid unicode escape")
}
v, err := strconv.ParseUint(string(raw[i+1:i+5]), 16, 16)
if err != nil {
return err
}
i += 4
if v >= 0xdc00 && v <= 0xdfff {
return errors.New("unpaired unicode surrogate")
}
if v < 0xd800 || v > 0xdbff {
continue
}
if i+6 >= len(raw) || raw[i+1] != '\\' || raw[i+2] != 'u' {
return errors.New("unpaired unicode surrogate")
}
v, err = strconv.ParseUint(string(raw[i+3:i+7]), 16, 16)
if err != nil || v < 0xdc00 || v > 0xdfff {
return errors.New("unpaired unicode surrogate")
}
i += 6
}
return nil
}

View File

@@ -0,0 +1,38 @@
package jsonvalue
import "testing"
func TestCanonicalPreservesExactNumbers(t *testing.T) {
for _, pair := range [][2]string{
{`{"z":1.0,"a":9007199254740993}`, `{"a":9007199254740993,"z":1}`},
{`[0,-0,100,0.0001000]`, `[0,0,1e2,1e-4]`},
{`{"x":12345678901234567890.1234567890123456789}`, `{"x":123456789012345678901234567890123456789e-19}`},
{`"\ud83d\ude00"`, `"😀"`},
} {
got, err := Canonical([]byte(pair[0]))
if err != nil || string(got) != pair[1] {
t.Fatalf("%s => %s, %v", pair[0], got, err)
}
}
for _, raw := range []string{`{"a":1,"\u0061":2}`, `{"nested":{"x":1,"x":2}}`, `1 2`, `9e308`, `1e309`, `"\ud800"`, `"\udc00"`, `"\ud800\u1234"`, string([]byte{'"', 0xff, '"'})} {
if _, err := Canonical([]byte(raw)); err == nil {
t.Fatalf("accepted %q", raw)
}
}
}
func FuzzCanonical(f *testing.F) {
for _, s := range []string{`{"a":1.0}`, `[1,true,null]`, `"\ud83d\ude00"`, `0.0000000000000000001`} {
f.Add(s)
}
f.Fuzz(func(t *testing.T, s string) {
b, err := Canonical([]byte(s))
if err != nil {
return
}
again, err := Canonical(b)
if err != nil || string(again) != string(b) {
t.Fatalf("unstable canonical form %s %v", b, err)
}
})
}