feat(all): split client tooling and add OAuth server login
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package stateio
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RequireExactJSONObject makes the persisted layout part of the current
|
||||
// storage contract. It rejects both missing and unknown fields rather than
|
||||
// allowing encoding/json to silently interpret an older or newer format.
|
||||
func RequireExactJSONObject(payload []byte, required ...string) error {
|
||||
var fields map[string]json.RawMessage
|
||||
if err := json.Unmarshal(payload, &fields); err != nil {
|
||||
return err
|
||||
}
|
||||
if fields == nil {
|
||||
return fmt.Errorf("state payload is not an object")
|
||||
}
|
||||
want := make(map[string]bool, len(required))
|
||||
for _, name := range required {
|
||||
if name == "" || want[name] {
|
||||
return fmt.Errorf("invalid required field %q", name)
|
||||
}
|
||||
want[name] = true
|
||||
}
|
||||
var missing, unknown []string
|
||||
for name := range want {
|
||||
if _, exists := fields[name]; !exists {
|
||||
missing = append(missing, name)
|
||||
}
|
||||
}
|
||||
for name := range fields {
|
||||
if !want[name] {
|
||||
unknown = append(unknown, name)
|
||||
}
|
||||
}
|
||||
if len(missing) == 0 && len(unknown) == 0 {
|
||||
return nil
|
||||
}
|
||||
sort.Strings(missing)
|
||||
sort.Strings(unknown)
|
||||
return fmt.Errorf("state fields mismatch: missing=[%s] unknown=[%s]", strings.Join(missing, ","), strings.Join(unknown, ","))
|
||||
}
|
||||
Reference in New Issue
Block a user