- internal/{address,identity,protocol,tce,transport,verify} -> pkg/ so
external Go projects can import the verified core; invariant tests
updated for the new paths
- Config.TrustProxy: key rate limiting by X-Forwarded-For when the relay
sits behind a reverse proxy (off by default, header never trusted
otherwise)
- examples/service + examples/approve: complete passwordless login round
trip (mint request -> wallet approves -> local verify), run live in CI
- docs/SERVICE-GUIDE.md: the integration recipe
87 lines
3.3 KiB
Go
87 lines
3.3 KiB
Go
// Package transport defines the JSON wire form of TCE objects, as specified in
|
|
// PROTOCOL.md section 10. It is the only layer in the tree that speaks JSON:
|
|
// the codec packages (internal/tce, internal/protocol) never import
|
|
// encoding/json, because signatures are computed over the binary TCE bytes and
|
|
// never over JSON (non-negotiable #8).
|
|
//
|
|
// A verifier must decode the `tce` field, verify the signature over those exact
|
|
// bytes, and read any field it needs from those bytes. The `object` view is a
|
|
// convenience only and must never be trusted or re-encoded for verification.
|
|
package transport
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"git.n1ko.dev/Niko/niko_trust/pkg/protocol"
|
|
"git.n1ko.dev/Niko/niko_trust/pkg/tce"
|
|
)
|
|
|
|
// Envelope is the JSON transport form of one signed object.
|
|
//
|
|
// `tce` and `signature` are authoritative (base64 standard, with padding).
|
|
// `object_id` is the lowercase hex of SHA-256(tce); a server must recompute it
|
|
// and ignore any supplied value. `object` is a decoded convenience view.
|
|
type Envelope struct {
|
|
TCE []byte `json:"tce"`
|
|
Signature []byte `json:"signature"`
|
|
Object json.RawMessage `json:"object,omitempty"`
|
|
ObjectID string `json:"object_id,omitempty"`
|
|
}
|
|
|
|
// ParseEnvelope decodes a JSON envelope.
|
|
func ParseEnvelope(b []byte) (*Envelope, error) {
|
|
var e Envelope
|
|
if err := json.Unmarshal(b, &e); err != nil {
|
|
return nil, fmt.Errorf("transport: bad envelope: %w", err)
|
|
}
|
|
return &e, nil
|
|
}
|
|
|
|
// Marshal returns the canonical JSON form of the envelope.
|
|
func (e *Envelope) Marshal() ([]byte, error) {
|
|
return json.Marshal(e)
|
|
}
|
|
|
|
// ContentID computes the content address of the envelope's TCE bytes (the
|
|
// authoritative object_id).
|
|
func (e *Envelope) ContentID() string {
|
|
return tce.ComputeID(e.TCE).String()
|
|
}
|
|
|
|
// BuildView decodes the TCE bytes and produces the `object` convenience view,
|
|
// returning the object type name.
|
|
func (e *Envelope) BuildView() (objectType string, view json.RawMessage, err error) {
|
|
return BuildView(e.TCE)
|
|
}
|
|
|
|
// Verify performs structural decode and signature verification of the
|
|
// envelope, returning the object type name and a verify error if any. Callers
|
|
// must treat a non-nil error as total rejection. The signature is checked over
|
|
// the exact TCE bytes.
|
|
func (e *Envelope) Verify() (objectType string, err error) {
|
|
typ, obj, decErr := DecodeObject(e.TCE)
|
|
if decErr != nil {
|
|
return "", decErr
|
|
}
|
|
switch obj.(type) {
|
|
case *protocol.Identity:
|
|
_, err = protocol.VerifyIdentity(e.TCE, e.Signature)
|
|
case *protocol.Claim:
|
|
_, err = protocol.VerifyClaim(e.TCE, e.Signature)
|
|
case *protocol.Revocation:
|
|
_, err = protocol.VerifyRevocation(e.TCE, e.Signature)
|
|
case *protocol.ApprovalRequest:
|
|
_, err = protocol.VerifyApprovalRequest(e.TCE, e.Signature)
|
|
case *protocol.ApprovalResponse:
|
|
// A response is only meaningful bound to its request; callers verify it
|
|
// through VerifyApprovalResponse with the request. Standalone we only
|
|
// confirm the response itself is structurally signed.
|
|
_, err = protocol.VerifyApprovalResponseStandalone(e.TCE, e.Signature)
|
|
case *protocol.AuthAssertion:
|
|
// Audience is bound by the server from request context; standalone we
|
|
// cannot check it, so we only confirm the assertion is signed.
|
|
_, err = protocol.VerifyAuthAssertionSignature(e.TCE, e.Signature)
|
|
}
|
|
return typ, err
|
|
}
|