diff --git a/tunnelrpc/pogs/connectionrpc.go b/tunnelrpc/pogs/connectionrpc.go index eb1e9dac..971f5393 100644 --- a/tunnelrpc/pogs/connectionrpc.go +++ b/tunnelrpc/pogs/connectionrpc.go @@ -14,7 +14,7 @@ import ( ) type RegistrationServer interface { - RegisterConnection(ctx context.Context, auth []byte, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) + RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) UnregisterConnection(ctx context.Context) } @@ -32,6 +32,11 @@ type ConnectionOptions struct { CompressionQuality uint8 } +type TunnelAuth struct { + AccountTag string + TunnelSecret []byte +} + func (p *ConnectionOptions) MarshalCapnproto(s tunnelrpc.ConnectionOptions) error { return pogs.Insert(tunnelrpc.ConnectionOptions_TypeID, s.Struct, p) } @@ -40,6 +45,14 @@ func (p *ConnectionOptions) UnmarshalCapnproto(s tunnelrpc.ConnectionOptions) er return pogs.Extract(p, tunnelrpc.ConnectionOptions_TypeID, s.Struct) } +func (a *TunnelAuth) MarshalCapnproto(s tunnelrpc.TunnelAuth) error { + return pogs.Insert(tunnelrpc.TunnelAuth_TypeID, s.Struct, a) +} + +func (a *TunnelAuth) UnmarshalCapnproto(s tunnelrpc.TunnelAuth) error { + return pogs.Extract(a, tunnelrpc.TunnelAuth_TypeID, s.Struct) +} + type ConnectionDetails struct { UUID uuid.UUID Location string @@ -92,6 +105,11 @@ func (i TunnelServer_PogsImpl) RegisterConnection(p tunnelrpc.RegistrationServer if err != nil { return err } + var pogsAuth TunnelAuth + err = pogsAuth.UnmarshalCapnproto(auth) + if err != nil { + return err + } uuidBytes, err := p.Params.TunnelId() if err != nil { return err @@ -111,7 +129,7 @@ func (i TunnelServer_PogsImpl) RegisterConnection(p tunnelrpc.RegistrationServer return err } - connDetails, callError := i.impl.RegisterConnection(p.Ctx, auth, tunnelID, connIndex, &pogsOptions) + connDetails, callError := i.impl.RegisterConnection(p.Ctx, pogsAuth, tunnelID, connIndex, &pogsOptions) resp, err := p.Results.NewResult() if err != nil { @@ -140,10 +158,17 @@ func (i TunnelServer_PogsImpl) UnregisterConnection(p tunnelrpc.RegistrationServ return nil } -func (c TunnelServer_PogsClient) RegisterConnection(ctx context.Context, auth []byte, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) { +func (c TunnelServer_PogsClient) RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) { client := tunnelrpc.TunnelServer{Client: c.Client} promise := client.RegisterConnection(ctx, func(p tunnelrpc.RegistrationServer_registerConnection_Params) error { - err := p.SetAuth(auth) + tunnelAuth, err := p.NewAuth() + if err != nil { + return err + } + if err = auth.MarshalCapnproto(tunnelAuth); err != nil { + return err + } + err = p.SetAuth(tunnelAuth) if err != nil { return err } diff --git a/tunnelrpc/pogs/connectionrpc_test.go b/tunnelrpc/pogs/connectionrpc_test.go index f520c2e1..b4e7ee7f 100644 --- a/tunnelrpc/pogs/connectionrpc_test.go +++ b/tunnelrpc/pogs/connectionrpc_test.go @@ -16,6 +16,8 @@ import ( "github.com/cloudflare/cloudflared/tunnelrpc" ) +const testAccountTag = "abc123" + func TestMarshalConnectionOptions(t *testing.T) { clientID := uuid.New() orig := ConnectionOptions{ @@ -47,6 +49,7 @@ func TestMarshalConnectionOptions(t *testing.T) { func TestConnectionRegistrationRPC(t *testing.T) { p1, p2 := net.Pipe() + t1, t2 := rpc.StreamTransport(p1), rpc.StreamTransport(p2) // Server-side @@ -84,9 +87,14 @@ func TestConnectionRegistrationRPC(t *testing.T) { testImpl.details = &expectedDetails testImpl.err = nil + auth := TunnelAuth{ + AccountTag: testAccountTag, + TunnelSecret: []byte{1, 2, 3, 4}, + } + // success tunnelID := uuid.New() - details, err := client.Register(ctx, []byte{1, 2, 3}, tunnelID, 2, options) + details, err := client.RegisterConnection(ctx, auth, tunnelID, 2, options) assert.NoError(t, err) assert.Equal(t, expectedDetails, *details) @@ -94,15 +102,15 @@ func TestConnectionRegistrationRPC(t *testing.T) { testImpl.details = nil testImpl.err = errors.New("internal") - _, err = client.Register(ctx, []byte{1, 2, 3}, tunnelID, 2, options) + _, err = client.RegisterConnection(ctx, auth, tunnelID, 2, options) assert.EqualError(t, err, "internal") // retriable error testImpl.details = nil - const delay = 27*time.Second + const delay = 27 * time.Second testImpl.err = RetryErrorAfter(errors.New("retryable"), delay) - _, err = client.Register(ctx, []byte{1, 2, 3}, tunnelID, 2, options) + _, err = client.RegisterConnection(ctx, auth, tunnelID, 2, options) assert.EqualError(t, err, "retryable") re, ok := err.(*RetryableError) @@ -117,7 +125,10 @@ type testConnectionRegistrationServer struct { err error } -func (t testConnectionRegistrationServer) Register(ctx context.Context, auth []byte, tunnelUUID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) { +func (t *testConnectionRegistrationServer) RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) { + if auth.AccountTag != testAccountTag { + panic("bad account tag: " + auth.AccountTag) + } if t.err != nil { return nil, t.err } diff --git a/tunnelrpc/pogs/support_test.go b/tunnelrpc/pogs/support_test.go index 8aa459c4..bd54329a 100644 --- a/tunnelrpc/pogs/support_test.go +++ b/tunnelrpc/pogs/support_test.go @@ -11,12 +11,12 @@ import ( // mocks for specific unit tests without having to implement every method type mockTunnelServerBase struct{} -func (mockTunnelServerBase) Register(ctx context.Context, auth []byte, tunnelUUID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) { - panic("unexpected call to Register") +func (mockTunnelServerBase) RegisterConnection(ctx context.Context, auth TunnelAuth, tunnelID uuid.UUID, connIndex byte, options *ConnectionOptions) (*ConnectionDetails, error) { + panic("unexpected call to RegisterConnection") } -func (mockTunnelServerBase) Unregister(ctx context.Context) { - panic("unexpected call to Unregister") +func (mockTunnelServerBase) UnregisterConnection(ctx context.Context) { + panic("unexpected call to UnregisterConnection") } func (mockTunnelServerBase) RegisterTunnel(ctx context.Context, originCert []byte, hostname string, options *RegistrationOptions) *TunnelRegistration { diff --git a/tunnelrpc/tunnelrpc.capnp b/tunnelrpc/tunnelrpc.capnp index af9b890c..1342df23 100644 --- a/tunnelrpc/tunnelrpc.capnp +++ b/tunnelrpc/tunnelrpc.capnp @@ -121,8 +121,13 @@ struct ConnectionDetails { locationName @1 :Text; } +struct TunnelAuth { + accountTag @0 :Text; + tunnelSecret @1 :Data; +} + interface RegistrationServer { - registerConnection @0 (auth :Data, tunnelId :Data, connIndex :UInt8, options :ConnectionOptions) -> (result :ConnectionResponse); + registerConnection @0 (auth :TunnelAuth, tunnelId :Data, connIndex :UInt8, options :ConnectionOptions) -> (result :ConnectionResponse); unregisterConnection @1 () -> (); } diff --git a/tunnelrpc/tunnelrpc.capnp.go b/tunnelrpc/tunnelrpc.capnp.go index de429999..b3b644dd 100644 --- a/tunnelrpc/tunnelrpc.capnp.go +++ b/tunnelrpc/tunnelrpc.capnp.go @@ -1484,6 +1484,90 @@ func (p ConnectionDetails_Promise) Struct() (ConnectionDetails, error) { return ConnectionDetails{s}, err } +type TunnelAuth struct{ capnp.Struct } + +// TunnelAuth_TypeID is the unique identifier for the type TunnelAuth. +const TunnelAuth_TypeID = 0x9496331ab9cd463f + +func NewTunnelAuth(s *capnp.Segment) (TunnelAuth, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}) + return TunnelAuth{st}, err +} + +func NewRootTunnelAuth(s *capnp.Segment) (TunnelAuth, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}) + return TunnelAuth{st}, err +} + +func ReadRootTunnelAuth(msg *capnp.Message) (TunnelAuth, error) { + root, err := msg.RootPtr() + return TunnelAuth{root.Struct()}, err +} + +func (s TunnelAuth) String() string { + str, _ := text.Marshal(0x9496331ab9cd463f, s.Struct) + return str +} + +func (s TunnelAuth) AccountTag() (string, error) { + p, err := s.Struct.Ptr(0) + return p.Text(), err +} + +func (s TunnelAuth) HasAccountTag() bool { + p, err := s.Struct.Ptr(0) + return p.IsValid() || err != nil +} + +func (s TunnelAuth) AccountTagBytes() ([]byte, error) { + p, err := s.Struct.Ptr(0) + return p.TextBytes(), err +} + +func (s TunnelAuth) SetAccountTag(v string) error { + return s.Struct.SetText(0, v) +} + +func (s TunnelAuth) TunnelSecret() ([]byte, error) { + p, err := s.Struct.Ptr(1) + return []byte(p.Data()), err +} + +func (s TunnelAuth) HasTunnelSecret() bool { + p, err := s.Struct.Ptr(1) + return p.IsValid() || err != nil +} + +func (s TunnelAuth) SetTunnelSecret(v []byte) error { + return s.Struct.SetData(1, v) +} + +// TunnelAuth_List is a list of TunnelAuth. +type TunnelAuth_List struct{ capnp.List } + +// NewTunnelAuth creates a new list of TunnelAuth. +func NewTunnelAuth_List(s *capnp.Segment, sz int32) (TunnelAuth_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}, sz) + return TunnelAuth_List{l}, err +} + +func (s TunnelAuth_List) At(i int) TunnelAuth { return TunnelAuth{s.List.Struct(i)} } + +func (s TunnelAuth_List) Set(i int, v TunnelAuth) error { return s.List.SetStruct(i, v.Struct) } + +func (s TunnelAuth_List) String() string { + str, _ := text.MarshalList(0x9496331ab9cd463f, s.List) + return str +} + +// TunnelAuth_Promise is a wrapper for a TunnelAuth promised by a client call. +type TunnelAuth_Promise struct{ *capnp.Pipeline } + +func (p TunnelAuth_Promise) Struct() (TunnelAuth, error) { + s, err := p.Pipeline.Struct() + return TunnelAuth{s}, err +} + type RegistrationServer struct{ Client capnp.Client } // RegistrationServer_TypeID is the unique identifier for the type RegistrationServer. @@ -1618,9 +1702,9 @@ func (s RegistrationServer_registerConnection_Params) String() string { return str } -func (s RegistrationServer_registerConnection_Params) Auth() ([]byte, error) { +func (s RegistrationServer_registerConnection_Params) Auth() (TunnelAuth, error) { p, err := s.Struct.Ptr(0) - return []byte(p.Data()), err + return TunnelAuth{Struct: p.Struct()}, err } func (s RegistrationServer_registerConnection_Params) HasAuth() bool { @@ -1628,8 +1712,19 @@ func (s RegistrationServer_registerConnection_Params) HasAuth() bool { return p.IsValid() || err != nil } -func (s RegistrationServer_registerConnection_Params) SetAuth(v []byte) error { - return s.Struct.SetData(0, v) +func (s RegistrationServer_registerConnection_Params) SetAuth(v TunnelAuth) error { + return s.Struct.SetPtr(0, v.Struct.ToPtr()) +} + +// NewAuth sets the auth field to a newly +// allocated TunnelAuth struct, preferring placement in s's segment. +func (s RegistrationServer_registerConnection_Params) NewAuth() (TunnelAuth, error) { + ss, err := NewTunnelAuth(s.Struct.Segment()) + if err != nil { + return TunnelAuth{}, err + } + err = s.Struct.SetPtr(0, ss.Struct.ToPtr()) + return ss, err } func (s RegistrationServer_registerConnection_Params) TunnelId() ([]byte, error) { @@ -1709,6 +1804,10 @@ func (p RegistrationServer_registerConnection_Params_Promise) Struct() (Registra return RegistrationServer_registerConnection_Params{s}, err } +func (p RegistrationServer_registerConnection_Params_Promise) Auth() TunnelAuth_Promise { + return TunnelAuth_Promise{Pipeline: p.Pipeline.GetPipeline(0)} +} + func (p RegistrationServer_registerConnection_Params_Promise) Options() ConnectionOptions_Promise { return ConnectionOptions_Promise{Pipeline: p.Pipeline.GetPipeline(2)} } @@ -3264,177 +3363,181 @@ func (p TunnelServer_reconnectTunnel_Results_Promise) Result() TunnelRegistratio return TunnelRegistration_Promise{Pipeline: p.Pipeline.GetPipeline(0)} } -const schema_db8274f9144abc7e = "x\xda\xccY\x7fp\x14\xe5\xf9\x7f\x9e}\xef\xb2\x17H" + - "\xbc[\xf6\x88\x98\xd1o\xbee`\xac\xd1\xa81\xa5\x83" + - "T\x9b\x04\x035\x91\x1f\xd9\x1ct\x1cE\xc7\xcd\xddK" + - "\xb2\xe9\xdd\xee\xb9\xbb\x17\x13\x0a\x82\x11\xaa8\xfe\x16\xaa" + - "Ri\x15\xc7v\xb0\xb5J\xd5i\xed\xe8T\xdaZ\xed" + - "hU\x1c\xe8\x80\xd2i+\xd2V\x06k\x8bv\x1c:" + - "\xeav\x9e\xdd\xdb\x1f\xb9\x84$h\xff\xe8\x7f7\xcf>" + - "\xef\xf3>\xbf\x9f\xcf\xfb\xdc\xf9i\xb1Mh\x8e?>" + - "\x0d@Y\x1b\xafrx\xe3\x1bk\x1e\x9c\xfb\xab\x11P" + - "\xea\x11\x9d\xeb\x9f\xedJ\x1f\xb7G\xde\x828\x13\x01Z" + - ".\x8e\xafAY\x89\x8b\x00\xf2\xd2\xf8_\x01\x9d\xcb\xa4" + - "\xf3\xaeL\xbf\xfe\xea\x8d \xd5G\x99c\xc4\xdc\\\xd5" + - "\x88r{\x151_\\E\xcc\x17\x15^\xdb\xf1\xe5\xad" + - "/o\x04\xa9^\x08\x99\x01[\xce\x12\xd7\xa0|\xb1H" + - "\x9c\x17\x8a\xcb\x01\x9d\x0f\xb6\xcc\xfa\xe1C\xaf\xbe\xb4\x09" + - "\xa43\x11\xcaw+\xe2\x9b\x08(s\xf1q@g\xf6" + - "\xe0\xdck~\xf9\xc2\x93\xf7\x82\xd2\x84\xe8\x1c\xec={" + - "\x1f\xdb\xfe\xe8[\xb0\x12E\x14\x00Z\xe2\x89\x1d\xc4;" + - "3q\x1d\xa0\xf3\xda9\xcf\xfe\xfc\xce'o\xfa\x0e(" + - "g\"\x02\xb8\xba\x0d'\xfeM\x0c\xb7%Z\x01\x9d-" + - "\xfb\x9f[V\xb8k\xdb\x0e\xef6\xf7\xfb\xd3\x09A\x80" + - "\x98\xb3\xb1\xf3\xa3\xc2\xca\x873\x0f\x97\xf5 \xc3[v" + - "&\x8e!`\xcbs\x89\x06\x04t\xe6\xbdyx\xf9\xd2" + - "\x9f\xac\xfeA\xe4\xec\x81\xea5t\xf6\xb1\xff\xbb\xacz" + - "\xe8\xf0\xe2'@j\xf2\xbf\xec\xab\xee\xa1/\xb1\xab\xd8" + - "\xa7\xea}\xbfx\xaa\xd2\xc5\x02\xf1\xec\xa9\xeeE\xf9p" + - "5\xf9\xe2\xcf\xd5\xe4\xb5[vo;;\xf1\xbd\x0f\x9e" + - "\xaep\xb1\xcb\xfc\xc2\xb4^\x94\x0fL#\xe6}\xd3\xc8" + - "\xd6\x99\x9dx\xf0\xf9\xe6\xd8O\xa3\x8e\x9b7\xfd\x08\xd9" + - "\xda9\x9d\x1cw\xc6{\x0bk\xf5\xf7G\x9e\xaf\x90\xe6" + - "2\xbe;\xbd\x0b\xe5O\xa6\x93\xb4\xe3.s\xd7\x95\xf7" + - "\xdc\x1d?|\xcf\x8b\xa4h$b\xf1\x04qo\xad1" + - "Q\xdeYC?\x1f\xa99\x95\x01:\xf5O|\xe5\xc7" + - "\x0bs\x07^\x1eGSyn\xea\x98\xdc\x9c\xa2_M" + - ")R\xf4P\xd3\xaeo\xbe{\xdb\x9e\xbdeE\x91\xc4" + - "lN\xb9A\xd9\x9e\xa2\xa0\x041\xadp\x92\xcb\xf9\\" + - "j\x00\xe5=\xae\xb8\xdf\xb9\xdc\xc2a\xf5\xb4\x0d\xbf\xff" + - "\xea\xc1H\x18\xf6\xa4\xdeF\x889\xcb\xbe~\xe5@\xf5" + - "\xbaC\x87\xa2\x17\xbd\x90r=r\xc0=\xfa\xf7\xef\x1f" + - "\xb9\xe3h!\xf7\x177\x95|\x9f\x1dO-\x10\x00e" + - "I\xa2\x08\x9c\xdaP\xbbh\xf6\xfe\xee#^$=\x11" + - "\xefI\x0b\x89!>\x83D\xcc\xbb\xa6\x9d\xaf\x9a\x7f\xf9" + - "\x11\x90\xea\xd9\xa8\xc4\x9e;c\x01\xca\xf3f\xb8\xd50" + - "\xe3&\x94;\xe5S\x01\x9c\xdb\xaf\xefX~\xe1\xec\xdd" + - "\xc7\xa2*](SV\xc9Ke\x92\xb7z\xfe\xd1\xaf" + - "\xcd\xbd\xfd7\xc7*\x1c\xe92\x16\xe4F\x94\xd7\xc9d" + - "\xfa01\xbf\xbf\xf8\xbb{\xeb\x93\xf5\x1fV\xb8\x89\xca" + - "\xaee\xbb<\x80\xf2.\xe2myL~\x91\xd2\xf5[" + - "o]=\xf4\xc6\x8d\x1f\xfc\xab2\xa2\xae\xe8\x87f\xf6" + - "\xa0\xfc\xf4L\x12\xbdk&\xc5\xff\xde\x15\x7f[\x7ft" + - "k\xddGc\xecR\xea\x06P\xe6u\xc4\xa9\xd6\xdd$" + - "\xef\xa6_\xce\xeb\xe2\xc3\xcd\x1d\xeb_>\x1eI\xf8\x9d" + - "u]\x94\xf0\xdf\x16\x1f8\xb4\xe1\x8fW\x7f\x1c5\xf8" + - "\x91\xba\xb7\xc9\xe0g\xea\xc8\xe0\xb5\xef\xdf\x7f\xe9\x1d\xab" + - "~\xf4i\xb4\x8a\xeaF\xe8\xa8]\xd2u\x9e7\x8b\xb1" + - "\xecy\xfe\xcf\xec\xb9Y\xb5\xa8\x17\x17\xb4\x97\xec~\xae" + - "\xdbZV\xb5y\x0fo\xb5\x8a\x86n\xf1nD%\xc5" + - "b\x001\x04\x90\xd4\x01\x00\xe5\x1a\x86J^@\x091" + - "M\x01\x964\"\xf63Tl\x01%AHS\xc7\x90" + - "\xae\x9d\x0d\xa0\xe4\x19*C\x02\"K#\x03\x90Jw" + - "\x03(C\x0c\x95\x8d\x02:En\x16T\x9d\xeb\x90\xb4" + - "\x17\x99&\xd6\x80\x805\x80\x8e\xc9msX\xed\xcdC" + - "\x92G\xc8\xe2\xc0u6\xd6\x82\x80\xb5\x80N\xbfQ2" + - "\xad\x95\xba\x8dZ\xbe\x87\xaf6\xb9\x85\xfdX\x05\x02V" + - "\x01\x06\xe6\xb1\xb1\xe6]\x92\xd7\xb8n';\xf5\xd5F" + - "\x85Q]\xe3\x19\xd5U6jc\xc4\xa8\x1b\x16RS" + - "g\xa8\xdc,\xa0\xc4\xcaVmj\x04P60Tn" + - "\x15\xd0\xc9\xba\x97t\xe6\x00 \xd0w5W\xed\x92\xc9" + - "-\xa2\x9d\x02\xd8\xcd\xd05\xeb\x14\xc0\xf5\x83\xdc\xb44" + - "C\xf7\xcdL\xaaf\xb6?p\xc5\x04\xa1Z4\xa4Y" + - "\xb6\xa6\xf7\xadp\xe9\xad\xddF^\xcb\x0e\x93U5\xae" + - "\x9eg,\x00@\x94f^\x01\x80\x82$-\x04h\xd5" + - "\xfat\xc3\xe4NN\xb3\xb2\x86\xaes`Y{}\xaf" + - "\x9aW\xf5,\x0f.\xaa\x1a{\x91wA\x86\x9b\x83\xdc" + - "\x10\xb9\x15RI\xc5\x0e\xad\x8f\x03\xb3>o" + - "\x9a%&\xf1\x87\xd1k\x19yn\xf3\x0e\x9e\xcd\xab\xa6" + - "jk\x83\xdc\xfb^NF?\xa8\x13\x09\xecq#B" + - "\x87\x0d}L\x98\xc2\xa4.\x87\x0a\xad\x89\xbaE\xc8\xbe" + - "\xbchk\xa2\xa1[\x15\x0dp\x01\x80\xb2\x8a\xa1\xd2\x1f" + - "\x89\x0e7\x01\x94\x1cC\xa5( \x96\x83S\x18\x09\x9b" + - "\xba\xc4\xb0\xdc\xd5\xb7\x85\xb1m\xf5\xfa\x1f\xa6B [" + - "\xf6\x9dW\xe5K\x0ch\xc8\xaa\xf9\xceb\x10\x01\x93\x17" + - "\xf3j\x96/\xc2rG\x03D\x10\x10\xdd\x80\x15\x8a&" + - "\xb7,\xd4\x0c])\xa9y\x8d\xd9\xc3c\xfa\xfc\x84\xd6" + - "R=\x8aZ\xde\xb56\x11X{VcX\xeb\x81\xb5" + - "M4\xc3\xcea\xa8\xcc\x170Y*i\xb9@\xc1\xbc" + - "\x91u\x83\x00\xc9ej\x81\x8fi\xceU\x93\xd6\xc6\xa8" + - "\xca\xeaV\x93ni\xfc/u\xcd\x89\xa1\x00\x99\x0e\xee" + - "h\x09U\xa6jnc\xa8,\x89\xa8\xdcyA\xc4\x0e" + - "_\xe5\xa5\xbd\xa1\x1d\xe27\xf8\xb0\xafU\x03/P\xa7" + - "\xf4\x9dY6\xa6\x1d\xc4\xcbB\x9e\x89\xf4\x8bV\xc7\xf2" + - "b\x83k!\xe98\xdf\xd7Q\x1e\xc6.\x80\xcc\x102" + - "\xccl\xc4PM\xf9\x06\\\x08\x90YK\xf4\x9b1\xd4" + - "T\xde\x84\xf5\x00\x99\x0dD\xbf\x15\x03\xc8\"o\xc6G" + - "\x012\xb7\x12\xf9>b\x8f1\xb7\xf9\xc8[]\xf1[" + - "\x88\xfe \xd1\xe3\xb14\xc6\x01\xe4\xed\xd8\x08\x90\xb9\x8f" + - "\xe8O\x11\xbdJHc\x15\xe1?\x1c\x00\xc8" + - "+\xc0\xe9\xe1\x0d\x9f\xa7\x81\x8c\x13\\\xef\x9e\xe0\xdd\x1e" + - "\x91K\x98\xad\x86\xa12K\x98\x14\xa6\xc5Nd\x85\x9f" + - "\xb4I:L\xf2\xff?\x90\xbf\x87`\xce+\x0c\x95\xfd" + - "\x91\"\xdcG\xc4\xd7\x19*\x07#0\xe7\x00U\xe6~" + - "\x86\xca\x87\xe1\xb2\xe3\x9f\xb7\x00(\x1f2\xec\x89\xc0\x06" + - "\xe9\x13b\xfc\x98\x86\xab\x0b\x1a\xd0\x03\x0dq\xbc\x1b " + - "\x93\xa0\xa1\x9bvAC\xcc\x03\x0d\x12\xf6\x02dRD" + - "?=\x0a\x1aN\xc3+\x002\xb3\x88>\x07\x05\x14y" + - "dQR2CX\x957\xfa\x96h\xfa\xb8\x93\xc8\xdf" + - "\xbe\xa0\xbdX\xd5\xf2%\x93C8\x08\xcbM\xa2#2" + - "\x9b\xbd\xb5L\xfbjJ\xbf\x0c%O\x0e-\x14A@" + - "\xf1\xe4\xde[S\x9a\x13\x8bL\xd3@\xb3\x02r^\x10" + - "B\xce\x00q\x12r\xbe\x94\xa1\xb2\x82B\xd1\xe6\x85B" + - "\xe9\x0dArCV-Y|\x8c\x0d\xc0\xb8\x19\xbc\x91" + - "\xad~\xa3\x94\xcf\xf5p\x10ms\xb8\xc2\x05\x93B\xcf" + - "\x0cO\xfa\x1d'\xe1v\x1c\x7f\xf7\x89\xfe\x8aSj\xde" + - "\x06\x82\xd4D\x1d\xc7_\xe7\xa1\xbf\xc8\x96\xbe\xf0(\x08" + - "\xd2\x19a\x03@\xdf\x07\xcc\xd0G\x97\xbc\xf7\xc1\xcd\xd1" + - "6\xecF\xfco\xbc\x1c\xbd\xa1s\x12\x95>j\xfdC" + - "m\\\x9c\xca\xb4\x0c\xfe\xff\xa8\xa8\xf4\xea\xcf\xfb\x88\xf6" + - "\x07\xc9\x7f\x02\x00\x00\xff\xffU\xcf\xfa\xff" +const schema_db8274f9144abc7e = "x\xda\xccYkl\x1c\xd5\xf5?g\xee\xaeg\xfdb" + + "=\x99M\x9cX\xf0\xf7\xbfQ\"\x8a!\x80\xe3R\x85" + + "\x14j;\xd8)6yx\xbcq\xc5#A\x8cwo" + + "\xecqwg63\xb3\xc6N\x13\x92\x98\xa4\x10Dy" + + "\x84\x84G\x0a-\x04\xa9UiiI\xa1j\xa9\xa8J" + + "\xfa\x82\x8agP\xa8\x02\xa4jKH[\xa2P\xda@" + + "\x85\xa8\x80\xa9\xce\xcc\xce\xc3kc;\xd0\x0f\xfd\xb6:" + + "s\xee\xbd\xe7}~\xe7\xec\xf9\xcb\xc56\xa19.V" + + "\x03([\xe3\x15\x0eozi\xe3\xfd\x0b\x7f5\x06J" + + "\x03\xa2s\xdd\x13\xdd\xa9\xf7\xed\xb1\xd7 \xceD\x80\x16" + + "-\xbe\x11\xe5\xcdq\x11@\x1e\x8d\xff\x15\xd0\xb9L:" + + "\xef\xaa\xd4\x8b\xcf_\x0fRC\x949F\xcc\xeb*\x9a" + + "P\xceW\x10\xb3VA\xcc\x17\xe5_\xd8\xf7\xf9=\xcf" + + "l\x07\xa9A\x08\x99\x01[\xfa\xc4\x8d(k\"qr" + + "q5\xa0\xf3\xce\xee\xb9\xdf{\xe0\xf9\xa7w\x80t&" + + "B\xe9\xed\xcd\xe2\xab\x08(\xdf.\xfe\x10\xd0i]\xfe" + + "\xdc\xe3\x0d-w\xee.{W \xc6\xe6D\x13\xca\xed" + + "\x09\xba\xed\xe2\xc4\xb5\x80\xce\xfc\xe1\x85\xd7\xfc\xf27\x8f" + + "\xde\x05\xca\"D\xe7H\xff\xd9/\xb3\xfb\x1ez\x0d\xfa" + + "PD\x01\xa0\xe5\x81\xc4>\xbax\xbf\xcb\xfb\xc29O" + + "\xfc\xec\xb6Go\xf8\x06(g\"\x02\xb8\x8a\xcc\xae\xfc" + + "71\x9cU\xd9\x0a\xe8\xec>\xfc\xf3U\xf9\xdb\xf7\xee" + + "\xf3Ds\xbf+\x95\x82\x001g{\xd7{\xf9\xbe\x07" + + "\xd3\x0f\x96\x84&+\xb5tV\x9eD\xc0\x96+*\x1b" + + "\x11\xd0\xb9\xe0\xd5c\xabW\xfeh\xfdw\"g\x8bU" + + "\x1b\xe9\xec\xc3\xffwY\xe5\xc8\xb1\xe5\x8f\x80\xb4\xc8\xff" + + "\xb2\xa1\xaa\x97\xbe\xc4\xd6\xb1\x8f\xd4\xbb\x7f\xf1X\xb9?" + + "\\U\xf3U\xfd(o\xab\"U7W\x91\x89o:" + + "\xb0\xf7\xec\xc4\xb7\xde\xf9\xf1dvQ\xab\xfbQ.V" + + "\x13\xf3\x86j\xd2uv\x17\x1ey\xb29\xf6\x93\xa8\x95" + + "\x0fV\x1f']\x8fU\x93\x95\xcfxkY\xad\xfe\xf6" + + "\xd8\x93e\xb7\xb9\x8c;j\xbaQ\xbe\xa7\x86n\xdbS" + + "C\xcc\xddW\xdd\xb1+~\xec\x8e\xa7H\xd0\x88{\xe3" + + "\x09\xd7'\xb5&\xca\x9d\xb5\xf4\xb3\xbd\xb6\x9e\x01:\x0d" + + "\x8f|\xe1\x07\xcb\xb2\xaf<3\x89\xa4\xf2\x81\xba\x93\xf2" + + "su\xf4\xebwu$\xe8\xd1E\xfb\xbf\xfa\xe6\xd7\x0f" + + "\x1e*\x09\x8at\xcdB\xc9u\xca\x85\x129%\xf0i" + + "\x99\x91\\\xce+\xa4!\x94\xf3\x92\x1b\x87.\xb7pL" + + "\x9d\xb7\xf5\xf7_<\x12qC^z\x1d!\xe6\xac\xfa" + + "\xf2UC\x95\x9b\x8f\x1e\x8d>\xa4J\xaeE\x8a\xee\xd1" + + "\xbf\x7f\xfb\xf8\xad'\xf2\xd9\xbf\xb8\xa1\xe4\xdbl\x8f\xb4" + + "T\x00\x94\x1f\x96\xc8\x03\xf5\x8d\xb5\x9d\xf3\x0f\xf7\x1c\xf7" + + "<\xe9]\xb1s\xd62bx`\x16]q\xc15\xed" + + "|\xed\x92\xcb\x8f\x83\xd4\xc0\xc6e\xc1\x81YKQ>" + + "8\x8b\x0e<7\xeb\x06\x94\x8f\xc9\xf5\x00\xce-\xd7u" + + "\xac\xbep\xfe\x81\x93Q\x91^\x96)\xaa\xe47e\xba" + + "o\xfd\x92\x13_Zx\xcboO\x96\x19\xd2e\xacL" + + "5\xa1\xb6l]" + + "\xcds\xb2Y\xc9\x1e[\x8c\x82\xad\x19\xba\x85ua\x1d" + + "\x05\xc4\xba\xa9\xbd\xee)\x90\xa4\xd8&\xfb$\x02i\xcf" + + "\"i?\xcbP\xf9\\D\xdaf\x0a\xe5\xf3\x19*\x17" + + "\x09\xe8\xa8\x99\x8cQ\xd4\xed5\xc0\xd4\x812\xa7\xa49" + + "$3&\x0f\xe5\xf5\x9f\x8dO\x12wd\xef\x0c\x89\xde" + + "\xcb\xbd\x9c:\xd7\xe4\x96X\xcc\xd9$M\x8d\xe3x\xe2" + + ",\x06P\x160T\xce\x17\xb0\x16?r\xa0Y67=\xf2\x82V\xf2t\xdeR" + + "b\x81\xe9j\xf7\x02(u\x0c\x95\xd3\x05t\x06L5" + + "\xc3{\xb8\x89\x9a\x91]\xa5\xeaF\x9a\xf1\x0c\xc6A\xc0" + + "x\xe4\xd1\xd3N\xf5\xd1^n\x15s\xb6\x05\xc1\xa9\xa9" + + "\xcf\x9b\xbcd\x84\xd2\xf1\x9eFO\xe6T \xf3\xe6\xf9" + + "a\xed\x09\xdc\xbd\xad?L\xdd 8wR`\xdc\xc8" + + "P\xd9\x1dI\xf2\xdb)\x8coc\xa8\xdc+\xa0\x14\x8b" + + "\xa50\x06 \xddCa\xbc\x9b\xa1r\xbf0\xbeB\xf1" + + "a\xae\xdb\x1d\xda\x00\x88\xdc\x0a\xa9$b\x876\xc0\x81" + + "Y\x9f6\xd0\x13\xd3\xd8\xc3\xe8\xb7\x8c\x1c\xb7y\x07\xcf" + + "\xe4TS\xb5\xb5a\xee}/\x05\xa3\xef\xd4\xa9.\xec" + + "u=B\x87\x0d}\x82\x9b\xc2\xa0.\xb9\x0a\xad\xa9\xea" + + "U\xc8\xbe\xba`k\xa2\xa1[e%x)\x80\xb2\x96" + + "\xa12\x18\xf1\x0e7\x01\x94,C\xa5 \x96\x9c\x93" + + "\x1f\x0b\xdb\x8a\xc4\xb0\xd4W\xf6\x86\xbem\xf5*0\xd6" + + "\x85\xb8\xbbd;\xaf\xce\xac0\xa01\xa3\xe6\xba\x0a\x81" + + "\x07L^\xc8\xa9\x19\xde\x89\xa5\x9a\x0a\x88 \xba\x0e" + + "\xcb\x17LnY\xa8\x19\xbaRTs\x1a\xb3G't" + + "\x9a)\xb5\xa5|\x14\xb5\x9cUVz\x9a\xc2\\\x0f\xb4" + + "]D\xa5\xe7\x1c\x86\xca\x12\x01\x93\xc5\xa2\x96\x0d\x04\xcc" + + "\x19\x19\xd7\x09\x90\\\xa5\xe6\xf9\x84\xf6P1mn\x8c" + + "\xcb\xac\x1e5\xe9\xa6\xc6\xffR\xdd\x9e\x1a\x8c\x90\xea\xe0" + + "6\xb7Pd\xca\xe66\x86\xca\x8a\x88\xc8]\x8b#z" + + "\xf8\"\xaf\xec\x0f\xf5\x10\xbf\xc2G}\xa9\x1ay\x9e*" + + "\xa5o\xcc\x922\xed ^\x16\xf2L%_4;V" + + "\x17\x1a]\x0dI\xc6%\xbe\x8c\xf2(v\x03\xa4G\x90" + + "az;\x86b\xca\xdbp\x19@z\x13\xd1o\xc4P" + + "Ry\x076\x00\xa4\xb7\x12\xfdf\x0c@\x93\xbc\x13\x1f" + + "\x02H\xdfL\xe4\xbb\x89=\xc6\xdc\xe2#\xefq\xaf\xdf" + + "M\xf4\xfb\x89\x1e\x8f\xa50\x0e \xdf\x87M\x00\xe9\xbb" + + "\x89\xfe\x18\xd1+\x84\x14V\x00\xc8\xfbq\x08 \xfd\x08" + + "\xd1\x9f \xba\x18O\x11n\x94\x1fG\x13 \xfdS\xa2" + + "\xff\x9a\xe8\x89\xb9)L\xd0\x80\xe1\xd2\x9f$\xfa\xb3D" + + "\xaf\x9c\x97\xc2J\x1a7p\x0c \xfd4\xd1\x0f\x11\xbd" + + "\x0aSX\x05 \x1f\xc4\xbd\x00\xe9CD\xff\x13\xd1\xab" + + "+RX\x0d \xff\xc1\x95\xe70\xd1\xdf zM," + + "\x855\x00\xf2\x9fq\x1f@\xfa\x0d\xa2\xff\x83\xe8\xb5b" + + "\x0ak\x01\xe4\xb7\\\xbdN\x10=!\x94!*?\xa2" + + "\xca`\x133\xac\xc0e\xbc\x94\xc5\xe8\x85{\x8f\x91$" + + "h\x84\xc9p\xb2\x06\xc4$\xa0S0\x8c\xdc\xaa\xf1\x91" + + "\x9a\xb4\xd5\x01\xcb\x87hu\xe1\xf8\x05H\xc4\xa0\xcfB" + + "\xd2\xd0\xbb\xb2A!(\xaf+\xbe$\x9a\xd5^\xb4\x8d" + + "b\x01\x1a\xb3\xaa\xcd\xb3AU1\x8b\xfar\xd3\xc8\xaf" + + "An\xe65]\xcdMSo*A\xc0J(\x95\x04" + + "\xffn\xbd\x98\xef1\xf9\xb0\x86F\xd1j\xb7m\x9e\x17" + + "\x0b\xb6\x15H\xf4\xf1\x803\x88h\xa1<\xa2\x1b\x0bK" + + "\xd7\xa8\x033\xa9S\x8bC\xdc\x94\xd4#\x05\xa9qX" + + "\xcd\x15?Iy\x1a\xdf\xba{[\xbd\xd6\x1f\xc5\x1b\xd4" + + "\x1d\x12\x0c\x95\x94\x80\xad\xa6\xd7n\xea\xfc9m\xfaR" + + "2\x1e\x80%\xfd\xa9\xc6\xbd\x1f#\xab\x0fzG(\xdd" + + "?c\xf1\x07\xb8\xed\xfd\xa2\xb9\x82@\xb1\x18m\xab\xa7" + + "v\xba\x97[\xc9\x99\xa8\x1e\xce\xb3e\xca\x8b3\xea\xe2" + + "\x93\xf4p\x1f\xe3E:r\xd3d\x1d\xb9{\x92\x8e\xdc" + + "\x1b\xed\xc8B\xa9#S\xa3(0T6\x09\x98\xa4\xb1" + + "\x01\xeb\xc2}\xd48\xa1\xc7\x8fJ\x14\x0a]z\x96\x03" + + "\x8e\xf8\xd1\x1ci\x1f\xc1\x9egz443\xb5}\x94" + + "9\xad\xc1\x83\xe5\xc9L\x07\x8eV\xefQ\x8a\xb3\xb9," + + "\x0e\x10,\x92\xd0_VH\xfb7\x82 }W\xc4p" + + "\xd9\x82\xfenE\xba\xcf\x04A\xda#\xa2\x10,\xdb\xd0" + + "_\xaaI;o\x02A\xda!\"\x0bve\xe8\x8f\xfb" + + "\xcd\xa3U\x08\x82\xb4Y\xc4X\xb0\x1fD\x7fY m" + + "\x18\x02A\xd2D\x8c\x07k8\xf4\xb7F\xd2\xba1\x10" + + "\xa4>\xd1\xf1\x8d\x04\xad\x9e\x1em\xe8\xf81\x0a\x8dn" + + "\x94\xb6\xa1\xe3\xc3@\xf4A\x05@\x1b:>\xe6d\x1f" + + "\x07:].\x7f\x86\x84$M\x91m\x04\xbf\xbc\xfc\xc7" + + "R\x01\x806Tb\x18\xd9\x95\x00|R\xa8\xd3\xcb\x1b" + + "?M)\x99\xc4\xb9\xde;\xc1\x0e!r/\xa1\xb7\x1a" + + "\x86\xca\\aZ\xc0\x16\xfb8-\xfc\xa0M\xd2a\xba" + + "\xff\xff\x83\xfb\x0f\x12\xe0y\x96\xa1r8\x92\x8e/\x13" + + "\xf1E\x86\xca\x91\x08\xe0y\x85r\xf40C\xe5\xddp" + + "\xf1\xf2\xcf\x9b\x00\x94w\x19\xf6F\x00\x84\xf4!1~" + + "@m\xd6\x85\x0f\xe8\xc1\x878\xee\x02H'\xa8\xfd\xa6" + + "\\\xf8\x10\xf3\xe0\x83\x84\xfd\x00\xe9:\xa2\x9f\x1e\x85\x0f" + + "\xf3\xf0J\x80\xf4\\\xa2/@\x01E\x1eY\xda\x14\xcd" + + "\x10`\xe5\x8c\x81\x15\x9a>iO\xf27Ah/W" + + "\xb5\\\xd1\xe4\x10\xb6\xc4R\x91\xe8\x88tioE\xd4" + + "\xbe\x9e\xc2/M\xc1\x93E\x0bE\x10P<\xb5\xc9k" + + "F\x1d\xa3\xd34\x0d4\xcb\xc0\xe7\xe2\x10|\x06\xd8\x93" + + "0\xf4\xa5\x0c\x955\xe4\x8a6\xcf\x15J\x7f\x08\x97\x1b" + + "3j\xd1\xe2\x13t\x00\xc6\xcd`Z\xb6\x06\x8db." + + "\xdb\xcbA\xb4\xcd\xd12\x13L\x0bB\xd3<\xe9W\x9c" + + "\x84[q\xfc=,\xfa\xebV\xa9y/\x08\xd2\"\xaa" + + "8\xfej\x11\xfd\xa5\xba\xf4\x99\x87@\x90\xce\x08\x0b\x00" + + "\xfa6`\x86>>\xe5\xbd\x0fn\x8c\xb6a\x0f\xe2\x7f" + + "c\x86\xf4\xda\xcf)d\xfa\xb8U\x14\x95qq&}" + + "3\xf8\xe3\xa6,\xd3+?\xed8\xed7\x92\xff\x04\x00" + + "\x00\xff\xff\xed\xc3%H" func init() { schemas.Register(schema_db8274f9144abc7e, @@ -3442,6 +3545,7 @@ func init() { 0x83ced0145b2f114b, 0x84cb9536a2cf6d3c, 0x85c8cea1ab1894f3, + 0x9496331ab9cd463f, 0x97b3c5c260257622, 0x9b87b390babc2ccf, 0xa29a916d4ebdd894,