diff --git a/protocol/communities/community.go b/protocol/communities/community.go index 5a5c78d31..c610d2693 100644 --- a/protocol/communities/community.go +++ b/protocol/communities/community.go @@ -2204,3 +2204,24 @@ func (o *Community) DeclineRequestToJoin(dbRequest *RequestToJoin) error { return nil } + +func (o *Community) ValidateEvent(event *CommunityEvent, signer *ecdsa.PublicKey) error { + o.mutex.Lock() + defer o.mutex.Unlock() + + err := validateCommunityEvent(event) + if err != nil { + return err + } + + member := o.getMember(signer) + if member == nil { + return ErrMemberNotFound + } + + if !RolesAuthorizedToPerformEvent(member.Roles, event) { + return ErrNotAuthorized + } + + return nil +} diff --git a/protocol/communities/community_event.go b/protocol/communities/community_event.go index e4de01eac..fff13c633 100644 --- a/protocol/communities/community_event.go +++ b/protocol/communities/community_event.go @@ -233,13 +233,8 @@ func (o *Community) UpdateCommunityByEvents(communityEventMessage *CommunityEven } func (o *Community) updateCommunityDescriptionByEvents() error { - for i := range o.config.EventsData.Events { - communityEvent := &o.config.EventsData.Events[i] - err := validateCommunityEvent(communityEvent) - if err != nil { - return err - } - err = o.updateCommunityDescriptionByCommunityEvent(*communityEvent) + for _, event := range o.config.EventsData.Events { + err := o.updateCommunityDescriptionByCommunityEvent(event) if err != nil { return err } @@ -368,11 +363,6 @@ func (o *Community) addNewCommunityEvent(event *CommunityEvent) error { return err } - data, err := proto.Marshal(event.ToProtobuf()) - if err != nil { - return errors.New("converting CommunityEvent to protobuf failed") - } - // All events must be built on top of the control node CommunityDescription // If there were no events before, extract CommunityDescription from CommunityDescriptionProtocolMessage // and check the signature @@ -388,7 +378,11 @@ func (o *Community) addNewCommunityEvent(event *CommunityEvent) error { } } - event.RawPayload = data + event.Payload, err = proto.Marshal(event.ToProtobuf()) + if err != nil { + return err + } + o.config.EventsData.Events = append(o.config.EventsData.Events, *event) return nil diff --git a/protocol/communities/community_event_message.go b/protocol/communities/community_event_message.go index c37823805..7cc113fd4 100644 --- a/protocol/communities/community_event_message.go +++ b/protocol/communities/community_event_message.go @@ -23,7 +23,8 @@ type CommunityEvent struct { RejectedRequestsToJoin map[string]*protobuf.CommunityRequestToJoin `json:"rejectedRequestsToJoin,omitempty"` AcceptedRequestsToJoin map[string]*protobuf.CommunityRequestToJoin `json:"acceptedRequestsToJoin,omitempty"` TokenMetadata *protobuf.CommunityTokenMetadata `json:"tokenMetadata,omitempty"` - RawPayload []byte `json:"rawPayload"` + Payload []byte `json:"payload"` + Signature []byte `json:"signature"` } func (e *CommunityEvent) ToProtobuf() *protobuf.CommunityEvent { @@ -41,15 +42,13 @@ func (e *CommunityEvent) ToProtobuf() *protobuf.CommunityEvent { TokenMetadata: e.TokenMetadata, } } - -func CommunityEventFromProtobuf(raw []byte) (*CommunityEvent, error) { +func communityEventFromProtobuf(msg *protobuf.SignedCommunityEvent) (*CommunityEvent, error) { decodedEvent := protobuf.CommunityEvent{} - encodedEvent := raw - - err := proto.Unmarshal(encodedEvent, &decodedEvent) + err := proto.Unmarshal(msg.Payload, &decodedEvent) if err != nil { return nil, err } + return &CommunityEvent{ CommunityEventClock: decodedEvent.CommunityEventClock, Type: decodedEvent.Type, @@ -62,7 +61,8 @@ func CommunityEventFromProtobuf(raw []byte) (*CommunityEvent, error) { RejectedRequestsToJoin: decodedEvent.RejectedRequestsToJoin, AcceptedRequestsToJoin: decodedEvent.AcceptedRequestsToJoin, TokenMetadata: decodedEvent.TokenMetadata, - RawPayload: encodedEvent, + Payload: msg.Payload, + Signature: msg.Signature, }, nil } @@ -73,26 +73,39 @@ type CommunityEventsMessage struct { } func (m *CommunityEventsMessage) ToProtobuf() protobuf.CommunityEventsMessage { - rawEvents := communityEventsToBytes(m.Events) - - return protobuf.CommunityEventsMessage{ + result := protobuf.CommunityEventsMessage{ CommunityId: m.CommunityID, EventsBaseCommunityDescription: m.EventsBaseCommunityDescription, - Events: rawEvents, + SignedEvents: []*protobuf.SignedCommunityEvent{}, } + + for _, event := range m.Events { + signedEvent := &protobuf.SignedCommunityEvent{ + Signature: event.Signature, + Payload: event.Payload, + } + result.SignedEvents = append(result.SignedEvents, signedEvent) + } + + return result } -func CommunityEventsMessageFromProtobuf(raw *protobuf.CommunityEventsMessage) (*CommunityEventsMessage, error) { - events, err := communityEventsFromBytes(raw.Events) - if err != nil { - return nil, err +func CommunityEventsMessageFromProtobuf(msg *protobuf.CommunityEventsMessage) (*CommunityEventsMessage, error) { + result := &CommunityEventsMessage{ + CommunityID: msg.CommunityId, + EventsBaseCommunityDescription: msg.EventsBaseCommunityDescription, + Events: []CommunityEvent{}, } - return &CommunityEventsMessage{ - CommunityID: raw.CommunityId, - EventsBaseCommunityDescription: raw.EventsBaseCommunityDescription, - Events: events, - }, nil + for _, signedEvent := range msg.SignedEvents { + event, err := communityEventFromProtobuf(signedEvent) + if err != nil { + return nil, err + } + result.Events = append(result.Events, *event) + } + + return result, nil } func (m *CommunityEventsMessage) Marshal() ([]byte, error) { @@ -225,30 +238,7 @@ func validateCommunityEvent(communityEvent *CommunityEvent) error { } func isCommunityEventsEqual(left CommunityEvent, right CommunityEvent) bool { - return bytes.Equal(left.RawPayload, right.RawPayload) -} - -func communityEventsToBytes(communityEvents []CommunityEvent) [][]byte { - var rawEvents [][]byte - for _, e := range communityEvents { - var encodedEvent []byte - encodedEvent = append(encodedEvent, e.RawPayload...) - rawEvents = append(rawEvents, encodedEvent) - } - - return rawEvents -} - -func communityEventsFromBytes(rawEvents [][]byte) ([]CommunityEvent, error) { - var events []CommunityEvent - for _, e := range rawEvents { - verifiedEvent, err := CommunityEventFromProtobuf(e) - if err != nil { - return nil, err - } - events = append(events, *verifiedEvent) - } - return events, nil + return bytes.Equal(left.Payload, right.Payload) } func communityEventsToJSONEncodedBytes(communityEvents []CommunityEvent) ([]byte, error) { diff --git a/protocol/communities/manager.go b/protocol/communities/manager.go index 3ef38b85a..f64343624 100644 --- a/protocol/communities/manager.go +++ b/protocol/communities/manager.go @@ -1314,17 +1314,66 @@ func (m *Manager) handleCommunityDescriptionMessageCommon(community *Community, }, nil } +func (m *Manager) signEvents(community *Community) error { + for i := range community.config.EventsData.Events { + communityEvent := &community.config.EventsData.Events[i] + if communityEvent.Signature == nil || len(communityEvent.Signature) == 0 { + var err error + communityEvent.Signature, err = crypto.Sign(crypto.Keccak256(communityEvent.Payload), m.identity) + if err != nil { + return err + } + } + } + return nil +} + +func (m *Manager) validateAndFilterEvents(community *Community, events []CommunityEvent) []CommunityEvent { + validatedEvents := make([]CommunityEvent, 0, len(events)) + + validateEvent := func(event *CommunityEvent) error { + if event.Signature == nil || len(event.Signature) == 0 { + return errors.New("missing signature") + } + + signer, err := crypto.SigToPub( + crypto.Keccak256(event.Payload), + event.Signature, + ) + if err != nil { + return errors.New("failed to recover signer") + } + + err = community.ValidateEvent(event, signer) + if err != nil { + return err + } + + return nil + } + + for i := range events { + if err := validateEvent(&events[i]); err == nil { + validatedEvents = append(validatedEvents, events[i]) + } else { + m.logger.Warn("invalid community event", zap.Error(err)) + } + } + + return validatedEvents +} + func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message *protobuf.CommunityEventsMessage) (*CommunityResponse, error) { if signer == nil { return nil, errors.New("signer can't be nil") } - adminMessage, err := CommunityEventsMessageFromProtobuf(message) + eventsMessage, err := CommunityEventsMessageFromProtobuf(message) if err != nil { return nil, err } - community, err := m.persistence.GetByID(&m.identity.PublicKey, adminMessage.CommunityID) + community, err := m.persistence.GetByID(&m.identity.PublicKey, eventsMessage.CommunityID) if err != nil { return nil, err } @@ -1337,7 +1386,9 @@ func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message return nil, errors.New("user has not permissions to send events") } - changes, err := community.UpdateCommunityByEvents(adminMessage) + eventsMessage.Events = m.validateAndFilterEvents(community, eventsMessage.Events) + + changes, err := community.UpdateCommunityByEvents(eventsMessage) if err != nil { return nil, err } @@ -4235,7 +4286,11 @@ func (m *Manager) saveAndPublish(community *Community) error { m.publish(&Subscription{Community: community}) return nil } else if community.HasPermissionToSendCommunityEvents() { - err := m.persistence.SaveCommunityEvents(community) + err := m.signEvents(community) + if err != nil { + return err + } + err = m.persistence.SaveCommunityEvents(community) if err != nil { return err } diff --git a/protocol/communities/roles_authorization.go b/protocol/communities/roles_authorization.go new file mode 100644 index 000000000..e59eacb71 --- /dev/null +++ b/protocol/communities/roles_authorization.go @@ -0,0 +1,97 @@ +package communities + +import "github.com/status-im/status-go/protocol/protobuf" + +var adminAuthorizedEventTypes = []protobuf.CommunityEvent_EventType{ + protobuf.CommunityEvent_COMMUNITY_EDIT, + protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE, + protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE, + protobuf.CommunityEvent_COMMUNITY_CATEGORY_CREATE, + protobuf.CommunityEvent_COMMUNITY_CATEGORY_DELETE, + protobuf.CommunityEvent_COMMUNITY_CATEGORY_EDIT, + protobuf.CommunityEvent_COMMUNITY_CHANNEL_CREATE, + protobuf.CommunityEvent_COMMUNITY_CHANNEL_DELETE, + protobuf.CommunityEvent_COMMUNITY_CHANNEL_EDIT, + protobuf.CommunityEvent_COMMUNITY_CATEGORY_REORDER, + protobuf.CommunityEvent_COMMUNITY_CHANNEL_REORDER, + protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT, + protobuf.CommunityEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT, + protobuf.CommunityEvent_COMMUNITY_MEMBER_KICK, + protobuf.CommunityEvent_COMMUNITY_MEMBER_BAN, + protobuf.CommunityEvent_COMMUNITY_MEMBER_UNBAN, +} + +var tokenMasterAuthorizedEventTypes = append(adminAuthorizedEventTypes, []protobuf.CommunityEvent_EventType{ + protobuf.CommunityEvent_COMMUNITY_TOKEN_ADD, +}...) + +var ownerAuthorizedEventTypes = tokenMasterAuthorizedEventTypes + +var rolesToAuthorizedEventTypes = map[protobuf.CommunityMember_Roles][]protobuf.CommunityEvent_EventType{ + protobuf.CommunityMember_ROLE_NONE: []protobuf.CommunityEvent_EventType{}, + protobuf.CommunityMember_ROLE_OWNER: ownerAuthorizedEventTypes, + protobuf.CommunityMember_ROLE_MANAGE_USERS: []protobuf.CommunityEvent_EventType{}, + protobuf.CommunityMember_ROLE_MODERATE_CONTENT: []protobuf.CommunityEvent_EventType{}, + protobuf.CommunityMember_ROLE_ADMIN: adminAuthorizedEventTypes, + protobuf.CommunityMember_ROLE_TOKEN_MASTER: tokenMasterAuthorizedEventTypes, +} + +var adminAuthorizedPermissionTypes = []protobuf.CommunityTokenPermission_Type{ + protobuf.CommunityTokenPermission_BECOME_MEMBER, + protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL, + protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL, +} + +var tokenMasterAuthorizedPermissionTypes = append(adminAuthorizedPermissionTypes, []protobuf.CommunityTokenPermission_Type{ + protobuf.CommunityTokenPermission_BECOME_ADMIN, +}...) + +var ownerAuthorizedPermissionTypes = append(tokenMasterAuthorizedPermissionTypes, []protobuf.CommunityTokenPermission_Type{ + protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, +}...) + +var rolesToAuthorizedPermissionTypes = map[protobuf.CommunityMember_Roles][]protobuf.CommunityTokenPermission_Type{ + protobuf.CommunityMember_ROLE_NONE: []protobuf.CommunityTokenPermission_Type{}, + protobuf.CommunityMember_ROLE_OWNER: ownerAuthorizedPermissionTypes, + protobuf.CommunityMember_ROLE_MANAGE_USERS: []protobuf.CommunityTokenPermission_Type{}, + protobuf.CommunityMember_ROLE_MODERATE_CONTENT: []protobuf.CommunityTokenPermission_Type{}, + protobuf.CommunityMember_ROLE_ADMIN: adminAuthorizedPermissionTypes, + protobuf.CommunityMember_ROLE_TOKEN_MASTER: tokenMasterAuthorizedPermissionTypes, +} + +func canRolesPerformEvent(roles []protobuf.CommunityMember_Roles, eventType protobuf.CommunityEvent_EventType) bool { + for _, role := range roles { + authorizedEventTypes := rolesToAuthorizedEventTypes[role] + for _, authorizedEventType := range authorizedEventTypes { + if authorizedEventType == eventType { + return true + } + } + } + return false +} + +func canRolesModifyPermission(roles []protobuf.CommunityMember_Roles, permissionType protobuf.CommunityTokenPermission_Type) bool { + for _, role := range roles { + authorizedPermissionTypes := rolesToAuthorizedPermissionTypes[role] + for _, authorizedPermissionType := range authorizedPermissionTypes { + if authorizedPermissionType == permissionType { + return true + } + } + } + return false +} + +func RolesAuthorizedToPerformEvent(roles []protobuf.CommunityMember_Roles, event *CommunityEvent) bool { + if !canRolesPerformEvent(roles, event.Type) { + return false + } + + if event.Type == protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE || + event.Type == protobuf.CommunityEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE { + return canRolesModifyPermission(roles, event.TokenPermission.Type) + } + + return true +} diff --git a/protocol/protobuf/community_update.pb.go b/protocol/protobuf/community_update.pb.go index 65d7c135a..e01cdc271 100644 --- a/protocol/protobuf/community_update.pb.go +++ b/protocol/protobuf/community_update.pb.go @@ -417,6 +417,55 @@ func (m *ChannelData) GetChannel() *CommunityChat { return nil } +type SignedCommunityEvent struct { + // Signature of the payload field + Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` + // Marshaled CommunityEvent + Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignedCommunityEvent) Reset() { *m = SignedCommunityEvent{} } +func (m *SignedCommunityEvent) String() string { return proto.CompactTextString(m) } +func (*SignedCommunityEvent) ProtoMessage() {} +func (*SignedCommunityEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_52ed23dfc73918ab, []int{4} +} + +func (m *SignedCommunityEvent) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignedCommunityEvent.Unmarshal(m, b) +} +func (m *SignedCommunityEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignedCommunityEvent.Marshal(b, m, deterministic) +} +func (m *SignedCommunityEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignedCommunityEvent.Merge(m, src) +} +func (m *SignedCommunityEvent) XXX_Size() int { + return xxx_messageInfo_SignedCommunityEvent.Size(m) +} +func (m *SignedCommunityEvent) XXX_DiscardUnknown() { + xxx_messageInfo_SignedCommunityEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_SignedCommunityEvent proto.InternalMessageInfo + +func (m *SignedCommunityEvent) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func (m *SignedCommunityEvent) GetPayload() []byte { + if m != nil { + return m.Payload + } + return nil +} + // CommunityEventsMessage is a message used to propagate information // about community changes. type CommunityEventsMessage struct { @@ -424,17 +473,20 @@ type CommunityEventsMessage struct { // Events base CommunityDescription with owner signature on top of which events were generated EventsBaseCommunityDescription []byte `protobuf:"bytes,2,opt,name=events_base_community_description,json=eventsBaseCommunityDescription,proto3" json:"events_base_community_description,omitempty"` // A list of admins events for the channel in bytes - Events [][]byte `protobuf:"bytes,3,rep,name=events,proto3" json:"events,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + // Deprecated: use signed_events instead. + Events [][]byte `protobuf:"bytes,3,rep,name=events,proto3" json:"events,omitempty"` // Deprecated: Do not use. + // A list of signed community events + SignedEvents []*SignedCommunityEvent `protobuf:"bytes,4,rep,name=signed_events,json=signedEvents,proto3" json:"signed_events,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *CommunityEventsMessage) Reset() { *m = CommunityEventsMessage{} } func (m *CommunityEventsMessage) String() string { return proto.CompactTextString(m) } func (*CommunityEventsMessage) ProtoMessage() {} func (*CommunityEventsMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_52ed23dfc73918ab, []int{4} + return fileDescriptor_52ed23dfc73918ab, []int{5} } func (m *CommunityEventsMessage) XXX_Unmarshal(b []byte) error { @@ -469,6 +521,7 @@ func (m *CommunityEventsMessage) GetEventsBaseCommunityDescription() []byte { return nil } +// Deprecated: Do not use. func (m *CommunityEventsMessage) GetEvents() [][]byte { if m != nil { return m.Events @@ -476,6 +529,13 @@ func (m *CommunityEventsMessage) GetEvents() [][]byte { return nil } +func (m *CommunityEventsMessage) GetSignedEvents() []*SignedCommunityEvent { + if m != nil { + return m.SignedEvents + } + return nil +} + func init() { proto.RegisterEnum("protobuf.CommunityEvent_EventType", CommunityEvent_EventType_name, CommunityEvent_EventType_value) proto.RegisterType((*CommunityEvent)(nil), "protobuf.CommunityEvent") @@ -485,6 +545,7 @@ func init() { proto.RegisterType((*CommunityConfig)(nil), "protobuf.CommunityConfig") proto.RegisterType((*CategoryData)(nil), "protobuf.CategoryData") proto.RegisterType((*ChannelData)(nil), "protobuf.ChannelData") + proto.RegisterType((*SignedCommunityEvent)(nil), "protobuf.SignedCommunityEvent") proto.RegisterType((*CommunityEventsMessage)(nil), "protobuf.CommunityEventsMessage") } @@ -493,69 +554,73 @@ func init() { } var fileDescriptor_52ed23dfc73918ab = []byte{ - // 1010 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xdd, 0x6e, 0xdb, 0x36, - 0x14, 0x9e, 0x63, 0xe7, 0xc7, 0x47, 0xb6, 0xa3, 0x32, 0x8b, 0xe3, 0xb8, 0x6b, 0xe6, 0x7a, 0xbb, - 0x30, 0x86, 0x21, 0xc5, 0xb2, 0xa1, 0x28, 0xd6, 0x9b, 0x29, 0x32, 0x91, 0x2a, 0xa9, 0xe5, 0x8c, - 0x51, 0x30, 0xb4, 0x37, 0x04, 0x23, 0xb1, 0x89, 0x96, 0x58, 0xf2, 0x4c, 0xba, 0x80, 0x6f, 0xf7, - 0x04, 0x7b, 0x80, 0x61, 0x8f, 0x30, 0xec, 0x11, 0x07, 0x51, 0x92, 0x25, 0x25, 0x72, 0xba, 0x8b, - 0xdd, 0xd8, 0xe2, 0xf9, 0xbe, 0xf3, 0x7d, 0x87, 0x14, 0xc9, 0x23, 0x68, 0xbb, 0xe1, 0x64, 0x32, - 0x0f, 0x7c, 0xb9, 0xa0, 0xf3, 0xa9, 0xc7, 0x24, 0x3f, 0x9c, 0xce, 0x42, 0x19, 0xa2, 0x2d, 0xf5, - 0x77, 0x35, 0xff, 0xd0, 0xdd, 0x71, 0x6f, 0x98, 0xa4, 0xbe, 0xc7, 0x03, 0xe9, 0xcb, 0x45, 0x0c, - 0x77, 0x9f, 0xa4, 0x69, 0x3e, 0x17, 0x71, 0xa8, 0xff, 0x47, 0x13, 0x5a, 0x66, 0x2a, 0x86, 0x3f, - 0xf2, 0x40, 0xa2, 0x23, 0xd8, 0xcd, 0xe4, 0x79, 0x14, 0xa2, 0xee, 0x5d, 0xe8, 0xde, 0x76, 0x2a, - 0xbd, 0xca, 0xa0, 0x46, 0x76, 0xdc, 0x02, 0xdd, 0x8c, 0x20, 0xf4, 0x12, 0x6a, 0x72, 0x31, 0xe5, - 0x9d, 0xb5, 0x5e, 0x65, 0xd0, 0x3a, 0xea, 0x1f, 0xa6, 0x75, 0x1c, 0x16, 0xb5, 0x0f, 0xd5, 0xaf, - 0xb3, 0x98, 0x72, 0xa2, 0xf8, 0x68, 0x08, 0x7a, 0xe6, 0xe5, 0x86, 0xc1, 0x07, 0xff, 0xba, 0x53, - 0xed, 0x55, 0x06, 0xda, 0xd1, 0x7e, 0x89, 0x86, 0xa9, 0x08, 0x64, 0xdb, 0x2d, 0x06, 0xd0, 0x08, - 0x74, 0x19, 0xde, 0xf2, 0x80, 0x4e, 0xf9, 0x6c, 0xe2, 0x0b, 0xe1, 0x87, 0x41, 0xa7, 0xa6, 0x54, - 0xca, 0x2a, 0x71, 0x22, 0xea, 0xf9, 0x92, 0x49, 0xb6, 0x65, 0x31, 0x80, 0x5e, 0x43, 0xd3, 0x65, - 0x92, 0x5f, 0x87, 0xb3, 0x05, 0xf5, 0x98, 0x64, 0x9d, 0x75, 0xa5, 0xd5, 0xce, 0x69, 0x25, 0xf0, - 0x90, 0x49, 0x46, 0x1a, 0x6e, 0x6e, 0x84, 0x5e, 0x41, 0xc3, 0xbd, 0x61, 0x41, 0xc0, 0xef, 0xe2, - 0xdc, 0x0d, 0x95, 0xbb, 0x9b, 0xcb, 0x8d, 0x51, 0x95, 0xaa, 0xb9, 0xd9, 0x00, 0x0d, 0x40, 0x9f, - 0xf0, 0xc9, 0x15, 0x9f, 0x51, 0x19, 0x52, 0xe6, 0xca, 0x68, 0x16, 0x9b, 0xbd, 0xca, 0xa0, 0x4e, - 0x5a, 0x71, 0xdc, 0x09, 0x0d, 0x15, 0x45, 0x36, 0x34, 0xe2, 0x88, 0x30, 0x3c, 0x8f, 0x7b, 0x9d, - 0xad, 0x5e, 0x75, 0xa0, 0x1d, 0x7d, 0xb3, 0x72, 0xd5, 0x47, 0x39, 0x32, 0x0e, 0xe4, 0x6c, 0x41, - 0x0a, 0xf9, 0xe8, 0x0e, 0xda, 0x33, 0xfe, 0x2b, 0x77, 0x25, 0xf7, 0x08, 0xff, 0x6d, 0xce, 0x85, - 0x14, 0x4e, 0x78, 0x1a, 0xfa, 0x41, 0xa7, 0xae, 0x94, 0x7f, 0x58, 0xa9, 0x4c, 0x4a, 0xd3, 0x62, - 0x8f, 0x15, 0x9a, 0x91, 0x1b, 0x73, 0x5d, 0x3e, 0x7d, 0xe8, 0x06, 0x9f, 0x70, 0x33, 0x4a, 0xd3, - 0x12, 0xb7, 0x72, 0x4d, 0x74, 0x02, 0xad, 0x78, 0x6f, 0x4c, 0xb8, 0x64, 0xea, 0x8d, 0x68, 0xea, - 0x8d, 0xf4, 0x56, 0xed, 0x8c, 0x51, 0xc2, 0x23, 0x4d, 0x99, 0x1f, 0x76, 0xdf, 0xc3, 0x93, 0x07, - 0xeb, 0x88, 0x74, 0xa8, 0xde, 0xf2, 0x85, 0x3a, 0x19, 0x75, 0x12, 0x3d, 0xa2, 0x17, 0xb0, 0xfe, - 0x91, 0xdd, 0xcd, 0xe3, 0xa3, 0x50, 0xbe, 0x8d, 0x63, 0x19, 0x12, 0xf3, 0x7e, 0x5c, 0x7b, 0x55, - 0xe9, 0xde, 0xc2, 0xd3, 0x47, 0x56, 0xb2, 0xc4, 0xe5, 0x65, 0xd1, 0xa5, 0x6c, 0x32, 0x89, 0x50, - 0xac, 0x73, 0xcf, 0xec, 0x91, 0x85, 0xfc, 0x7f, 0xcd, 0xfa, 0xff, 0xd4, 0xa0, 0xbe, 0x3c, 0xf4, - 0x48, 0x83, 0xcd, 0x4b, 0xfb, 0xcc, 0x1e, 0xff, 0x62, 0xeb, 0x9f, 0x21, 0x04, 0x2d, 0x73, 0x3c, - 0x1a, 0x5d, 0xda, 0x96, 0xf3, 0x8e, 0xe2, 0xa1, 0xe5, 0xe8, 0x15, 0xf4, 0x2d, 0x0c, 0xb2, 0xd8, - 0x08, 0x8f, 0x8e, 0x31, 0xa1, 0xce, 0xf8, 0x0c, 0xdb, 0xf4, 0x1c, 0x93, 0x91, 0x75, 0x71, 0x61, - 0x8d, 0x6d, 0x6a, 0xbe, 0x31, 0xec, 0x13, 0xac, 0xaf, 0xfd, 0x37, 0xf6, 0x10, 0xbf, 0xc5, 0x0e, - 0xd6, 0xab, 0xe8, 0x19, 0xec, 0x67, 0x6c, 0xd3, 0x70, 0xf0, 0xc9, 0x98, 0xbc, 0xa3, 0x26, 0xc1, - 0x86, 0x83, 0xf5, 0xda, 0x0a, 0x38, 0xc9, 0x5e, 0x47, 0x4f, 0x61, 0xaf, 0x04, 0x56, 0x65, 0x6f, - 0xa0, 0x2f, 0xa0, 0x93, 0x03, 0xdf, 0x18, 0xb6, 0x8d, 0xdf, 0xa6, 0xca, 0x9b, 0xe5, 0x68, 0x22, - 0xbc, 0x85, 0xba, 0xd0, 0x7e, 0x88, 0x2a, 0xdd, 0x3a, 0x3a, 0x80, 0x6e, 0x89, 0x29, 0xc1, 0x63, - 0x32, 0xc4, 0x44, 0x87, 0x7b, 0x35, 0x27, 0xb9, 0x29, 0xac, 0xa1, 0xaf, 0xa1, 0x97, 0xc1, 0x04, - 0xff, 0x7c, 0x89, 0x2f, 0x1c, 0xea, 0x8c, 0xe9, 0xe9, 0xd8, 0xb2, 0xa9, 0x61, 0x9a, 0xf8, 0xdc, - 0xd1, 0x1b, 0x8f, 0xb3, 0x08, 0x3e, 0xc5, 0xa6, 0xa3, 0x37, 0xd1, 0x3e, 0xec, 0x3e, 0x58, 0xeb, - 0x33, 0xcb, 0x3c, 0xd3, 0x5b, 0xa8, 0x03, 0x9f, 0x3f, 0x80, 0x8e, 0x0d, 0x5b, 0xdf, 0x2e, 0xce, - 0x2d, 0x41, 0x2e, 0xed, 0x08, 0xd3, 0xd1, 0x1e, 0xec, 0x64, 0x58, 0xfc, 0xd6, 0x8c, 0xe1, 0x50, - 0x7f, 0xd2, 0xff, 0x7b, 0x0d, 0xb6, 0xef, 0x5d, 0xf9, 0xe8, 0x08, 0xb6, 0xd2, 0x5e, 0xa6, 0x76, - 0x66, 0xf1, 0x36, 0xbe, 0x61, 0xd2, 0x4a, 0x50, 0xb2, 0xe4, 0xa1, 0x9f, 0x40, 0xcb, 0xfa, 0x81, - 0x48, 0x36, 0xef, 0x41, 0xc9, 0xe6, 0xcd, 0xae, 0x7e, 0x41, 0xf2, 0x29, 0xd1, 0xdd, 0xc1, 0xbc, - 0x89, 0x1f, 0x50, 0xc1, 0xa5, 0xf4, 0x83, 0x6b, 0x91, 0xf4, 0xa6, 0xb2, 0x13, 0x60, 0x44, 0xc4, - 0x8b, 0x84, 0x47, 0x9a, 0x2c, 0x3f, 0x44, 0x5f, 0x41, 0xd3, 0x0f, 0xe4, 0x2c, 0xa4, 0x13, 0x2e, - 0x04, 0xbb, 0xe6, 0xaa, 0x3b, 0xd5, 0x49, 0x43, 0x05, 0x47, 0x71, 0x2c, 0x22, 0x85, 0xf3, 0x3c, - 0x69, 0x3d, 0x26, 0xa9, 0x60, 0x4a, 0x42, 0x50, 0x93, 0xec, 0x5a, 0x74, 0x36, 0x7a, 0xd5, 0x41, - 0x9d, 0xa8, 0xe7, 0xfe, 0xef, 0x15, 0x68, 0xe4, 0x3b, 0x12, 0xfa, 0x12, 0xb4, 0x65, 0x03, 0xf3, - 0xbd, 0xe4, 0x28, 0x43, 0x1a, 0xb2, 0xbc, 0x48, 0x25, 0x60, 0x93, 0xf8, 0x40, 0xd7, 0x89, 0x7a, - 0x46, 0xcf, 0x97, 0x8d, 0x4b, 0x50, 0xdf, 0x8b, 0xa6, 0x1a, 0x39, 0xa4, 0x1d, 0x4a, 0x58, 0x9e, - 0x40, 0x5d, 0xd8, 0x9a, 0x86, 0xc2, 0x97, 0x69, 0x7f, 0x5d, 0x27, 0xcb, 0x71, 0xff, 0xcf, 0x0a, - 0x68, 0xb9, 0xd6, 0xf6, 0xe9, 0x1a, 0x9e, 0x01, 0xa4, 0x8d, 0xd2, 0xf7, 0x92, 0x4a, 0xea, 0x49, - 0xc4, 0xf2, 0x0a, 0x5e, 0xd5, 0xa2, 0x17, 0xfa, 0x0e, 0x36, 0x13, 0x62, 0xd2, 0xe6, 0xf7, 0xca, - 0x3e, 0x16, 0x6e, 0x98, 0x24, 0x29, 0xaf, 0xff, 0x57, 0x05, 0xda, 0xc5, 0x6e, 0x22, 0xd2, 0x25, - 0x8d, 0x26, 0xbe, 0xfc, 0x06, 0x49, 0x4a, 0x6d, 0x10, 0x6d, 0x19, 0xb3, 0x3c, 0x64, 0xc1, 0x73, - 0xf5, 0x21, 0x24, 0xe8, 0x15, 0x13, 0x9c, 0x66, 0x74, 0x8f, 0x0b, 0x77, 0xe6, 0x4f, 0x55, 0x95, - 0x6b, 0x2a, 0xef, 0x20, 0x26, 0x1e, 0x33, 0xc1, 0x97, 0x7e, 0xc3, 0x8c, 0x85, 0xda, 0xb0, 0x11, - 0x33, 0xd4, 0x02, 0x37, 0x48, 0x32, 0x3a, 0x6e, 0xbe, 0xd7, 0x0e, 0x5f, 0xbc, 0x4e, 0xa7, 0x71, - 0xb5, 0xa1, 0x9e, 0xbe, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0xe3, 0x67, 0xf7, 0x49, 0xea, 0x09, - 0x00, 0x00, + // 1073 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcb, 0x6e, 0xdb, 0x46, + 0x14, 0xad, 0x2c, 0xf9, 0xa1, 0xab, 0x87, 0xe9, 0x71, 0x6c, 0xd3, 0x4a, 0xe2, 0x2a, 0x6a, 0x17, + 0x42, 0x51, 0x38, 0xa8, 0x5b, 0x04, 0x41, 0xb3, 0x29, 0x4d, 0x0d, 0x1c, 0xda, 0x11, 0xe5, 0x8e, + 0x69, 0x14, 0xc9, 0x86, 0x18, 0x93, 0x13, 0x99, 0xb5, 0x45, 0xaa, 0x9a, 0x51, 0x00, 0x6d, 0xfb, + 0x05, 0xfd, 0x80, 0x7e, 0x43, 0xd1, 0xbf, 0xea, 0x6f, 0x14, 0x9c, 0x21, 0x45, 0xd2, 0xa6, 0x9d, + 0x2e, 0xba, 0x91, 0x38, 0xf7, 0x9c, 0x7b, 0xce, 0xdc, 0x79, 0xf0, 0x12, 0x76, 0xbd, 0x68, 0x32, + 0x99, 0x87, 0x81, 0x58, 0xb8, 0xf3, 0xa9, 0x4f, 0x05, 0x3b, 0x9c, 0xce, 0x22, 0x11, 0xa1, 0x0d, + 0xf9, 0x77, 0x35, 0xff, 0xd8, 0xd9, 0xf6, 0xae, 0xa9, 0x70, 0x03, 0x9f, 0x85, 0x22, 0x10, 0x0b, + 0x05, 0x77, 0xb6, 0xd2, 0xb4, 0x80, 0x71, 0x15, 0xea, 0xfd, 0xd1, 0x82, 0xb6, 0x99, 0x8a, 0xe1, + 0x4f, 0x2c, 0x14, 0xe8, 0x08, 0x76, 0x32, 0x79, 0x16, 0x87, 0x5c, 0xef, 0x36, 0xf2, 0x6e, 0xf4, + 0x4a, 0xb7, 0xd2, 0xaf, 0x91, 0x6d, 0xaf, 0x40, 0x37, 0x63, 0x08, 0xbd, 0x82, 0x9a, 0x58, 0x4c, + 0x99, 0xbe, 0xd2, 0xad, 0xf4, 0xdb, 0x47, 0xbd, 0xc3, 0x74, 0x1e, 0x87, 0x45, 0xed, 0x43, 0xf9, + 0xeb, 0x2c, 0xa6, 0x8c, 0x48, 0x3e, 0x1a, 0x80, 0x96, 0x79, 0x79, 0x51, 0xf8, 0x31, 0x18, 0xeb, + 0xd5, 0x6e, 0xa5, 0xdf, 0x38, 0xda, 0x2f, 0xd1, 0x30, 0x25, 0x81, 0x6c, 0x7a, 0xc5, 0x00, 0x1a, + 0x82, 0x26, 0xa2, 0x1b, 0x16, 0xba, 0x53, 0x36, 0x9b, 0x04, 0x9c, 0x07, 0x51, 0xa8, 0xd7, 0xa4, + 0x4a, 0xd9, 0x4c, 0x9c, 0x98, 0x7a, 0xbe, 0x64, 0x92, 0x4d, 0x51, 0x0c, 0xa0, 0x37, 0xd0, 0xf2, + 0xa8, 0x60, 0xe3, 0x68, 0xb6, 0x70, 0x7d, 0x2a, 0xa8, 0xbe, 0x2a, 0xb5, 0x76, 0x73, 0x5a, 0x09, + 0x3c, 0xa0, 0x82, 0x92, 0xa6, 0x97, 0x1b, 0xa1, 0xd7, 0xd0, 0xf4, 0xae, 0x69, 0x18, 0xb2, 0x5b, + 0x95, 0xbb, 0x26, 0x73, 0x77, 0x72, 0xb9, 0x0a, 0x95, 0xa9, 0x0d, 0x2f, 0x1b, 0xa0, 0x3e, 0x68, + 0x13, 0x36, 0xb9, 0x62, 0x33, 0x57, 0x44, 0x2e, 0xf5, 0x44, 0x5c, 0xc5, 0x7a, 0xb7, 0xd2, 0xaf, + 0x93, 0xb6, 0x8a, 0x3b, 0x91, 0x21, 0xa3, 0xc8, 0x86, 0xa6, 0x8a, 0x70, 0xc3, 0xf7, 0x99, 0xaf, + 0x6f, 0x74, 0xab, 0xfd, 0xc6, 0xd1, 0x37, 0x0f, 0xae, 0xfa, 0x30, 0x47, 0xc6, 0xa1, 0x98, 0x2d, + 0x48, 0x21, 0x1f, 0xdd, 0xc2, 0xee, 0x8c, 0xfd, 0xca, 0x3c, 0xc1, 0x7c, 0xc2, 0x7e, 0x9b, 0x33, + 0x2e, 0xb8, 0x13, 0x9d, 0x46, 0x41, 0xa8, 0xd7, 0xa5, 0xf2, 0x0f, 0x0f, 0x2a, 0x93, 0xd2, 0x34, + 0xe5, 0xf1, 0x80, 0x66, 0xec, 0x46, 0x3d, 0x8f, 0x4d, 0xef, 0xbb, 0xc1, 0x67, 0xdc, 0x8c, 0xd2, + 0xb4, 0xc4, 0xad, 0x5c, 0x13, 0x9d, 0x40, 0x5b, 0x9d, 0x8d, 0x09, 0x13, 0x54, 0xee, 0x48, 0x43, + 0xee, 0x48, 0xf7, 0xa1, 0x93, 0x31, 0x4c, 0x78, 0xa4, 0x25, 0xf2, 0xc3, 0xce, 0x07, 0xd8, 0xba, + 0xb7, 0x8e, 0x48, 0x83, 0xea, 0x0d, 0x5b, 0xc8, 0x9b, 0x51, 0x27, 0xf1, 0x23, 0x7a, 0x09, 0xab, + 0x9f, 0xe8, 0xed, 0x5c, 0x5d, 0x85, 0xf2, 0x63, 0xac, 0x64, 0x88, 0xe2, 0xfd, 0xb8, 0xf2, 0xba, + 0xd2, 0xb9, 0x81, 0xa7, 0x8f, 0xac, 0x64, 0x89, 0xcb, 0xab, 0xa2, 0x4b, 0x59, 0x31, 0x89, 0x90, + 0xd2, 0xb9, 0x63, 0xf6, 0xc8, 0x42, 0xfe, 0xbf, 0x66, 0xbd, 0xbf, 0x6b, 0x50, 0x5f, 0x5e, 0x7a, + 0xd4, 0x80, 0xf5, 0x4b, 0xfb, 0xcc, 0x1e, 0xfd, 0x62, 0x6b, 0x5f, 0x20, 0x04, 0x6d, 0x73, 0x34, + 0x1c, 0x5e, 0xda, 0x96, 0xf3, 0xde, 0xc5, 0x03, 0xcb, 0xd1, 0x2a, 0xe8, 0x5b, 0xe8, 0x67, 0xb1, + 0x21, 0x1e, 0x1e, 0x63, 0xe2, 0x3a, 0xa3, 0x33, 0x6c, 0xbb, 0xe7, 0x98, 0x0c, 0xad, 0x8b, 0x0b, + 0x6b, 0x64, 0xbb, 0xe6, 0x5b, 0xc3, 0x3e, 0xc1, 0xda, 0xca, 0x7f, 0x63, 0x0f, 0xf0, 0x3b, 0xec, + 0x60, 0xad, 0x8a, 0x9e, 0xc3, 0x7e, 0xc6, 0x36, 0x0d, 0x07, 0x9f, 0x8c, 0xc8, 0x7b, 0xd7, 0x24, + 0xd8, 0x70, 0xb0, 0x56, 0x7b, 0x00, 0x4e, 0xb2, 0x57, 0xd1, 0x53, 0xd8, 0x2b, 0x81, 0xe5, 0xb4, + 0xd7, 0xd0, 0x33, 0xd0, 0x73, 0xe0, 0x5b, 0xc3, 0xb6, 0xf1, 0xbb, 0x54, 0x79, 0xbd, 0x1c, 0x4d, + 0x84, 0x37, 0x50, 0x07, 0x76, 0xef, 0xa3, 0x52, 0xb7, 0x8e, 0x0e, 0xa0, 0x53, 0x62, 0x4a, 0xf0, + 0x88, 0x0c, 0x30, 0xd1, 0xe0, 0xce, 0x9c, 0x93, 0xdc, 0x14, 0x6e, 0xa0, 0xaf, 0xa1, 0x9b, 0xc1, + 0x04, 0xff, 0x7c, 0x89, 0x2f, 0x1c, 0xd7, 0x19, 0xb9, 0xa7, 0x23, 0xcb, 0x76, 0x0d, 0xd3, 0xc4, + 0xe7, 0x8e, 0xd6, 0x7c, 0x9c, 0x45, 0xf0, 0x29, 0x36, 0x1d, 0xad, 0x85, 0xf6, 0x61, 0xe7, 0xde, + 0x5a, 0x9f, 0x59, 0xe6, 0x99, 0xd6, 0x46, 0x3a, 0x3c, 0xb9, 0x07, 0x1d, 0x1b, 0xb6, 0xb6, 0x59, + 0xac, 0x2d, 0x41, 0x2e, 0xed, 0x18, 0xd3, 0xd0, 0x1e, 0x6c, 0x67, 0x98, 0xda, 0x35, 0x63, 0x30, + 0xd0, 0xb6, 0x7a, 0x7f, 0xad, 0xc0, 0xe6, 0x9d, 0x57, 0x3e, 0x3a, 0x82, 0x8d, 0xb4, 0x97, 0xc9, + 0x93, 0x59, 0x7c, 0x1b, 0x5f, 0x53, 0x61, 0x25, 0x28, 0x59, 0xf2, 0xd0, 0x4f, 0xd0, 0xc8, 0xfa, + 0x01, 0x4f, 0x0e, 0xef, 0x41, 0xc9, 0xe1, 0xcd, 0x5e, 0xfd, 0x9c, 0xe4, 0x53, 0xe2, 0x77, 0x07, + 0xf5, 0x27, 0x41, 0xe8, 0x72, 0x26, 0x44, 0x10, 0x8e, 0x79, 0xd2, 0x9b, 0xca, 0x6e, 0x80, 0x11, + 0x13, 0x2f, 0x12, 0x1e, 0x69, 0xd1, 0xfc, 0x10, 0x7d, 0x05, 0xad, 0x20, 0x14, 0xb3, 0xc8, 0x9d, + 0x30, 0xce, 0xe9, 0x98, 0xc9, 0xee, 0x54, 0x27, 0x4d, 0x19, 0x1c, 0xaa, 0x58, 0x4c, 0x8a, 0xe6, + 0x79, 0xd2, 0xaa, 0x22, 0xc9, 0x60, 0x4a, 0x42, 0x50, 0x13, 0x74, 0xcc, 0xf5, 0xb5, 0x6e, 0xb5, + 0x5f, 0x27, 0xf2, 0xb9, 0xf7, 0x7b, 0x05, 0x9a, 0xf9, 0x8e, 0x84, 0xbe, 0x84, 0xc6, 0xb2, 0x81, + 0x05, 0x7e, 0x72, 0x95, 0x21, 0x0d, 0x59, 0x7e, 0xac, 0x12, 0xd2, 0x89, 0xba, 0xd0, 0x75, 0x22, + 0x9f, 0xd1, 0x8b, 0x65, 0xe3, 0xe2, 0x6e, 0xe0, 0xc7, 0xa5, 0xc6, 0x0e, 0x69, 0x87, 0xe2, 0x96, + 0xcf, 0x51, 0x07, 0x36, 0xa6, 0x11, 0x0f, 0x44, 0xda, 0x5f, 0x57, 0xc9, 0x72, 0xdc, 0xfb, 0xb3, + 0x02, 0x8d, 0x5c, 0x6b, 0xfb, 0xfc, 0x1c, 0x9e, 0x03, 0xa4, 0x8d, 0x32, 0xf0, 0x93, 0x99, 0xd4, + 0x93, 0x88, 0xe5, 0x17, 0xbc, 0xaa, 0x45, 0x2f, 0xf4, 0x1d, 0xac, 0x27, 0xc4, 0xa4, 0xcd, 0xef, + 0x95, 0x7d, 0x2c, 0x5c, 0x53, 0x41, 0x52, 0x5e, 0xcf, 0x86, 0x27, 0x17, 0xc1, 0x38, 0x64, 0xfe, + 0x9d, 0x8f, 0x9d, 0x67, 0x50, 0xe7, 0xc1, 0x38, 0xa4, 0x62, 0x3e, 0x63, 0x72, 0x92, 0x4d, 0x92, + 0x05, 0x90, 0x0e, 0xeb, 0x53, 0xba, 0xb8, 0x8d, 0xa8, 0x9a, 0x60, 0x93, 0xa4, 0xc3, 0xde, 0x3f, + 0x15, 0xd8, 0x2d, 0x4a, 0xf1, 0x74, 0x8b, 0xe2, 0x85, 0x5c, 0x7e, 0xd3, 0x24, 0xa5, 0x37, 0x49, + 0x63, 0x19, 0xb3, 0x7c, 0x64, 0xc1, 0x0b, 0xf9, 0x61, 0xc5, 0xdd, 0x2b, 0xca, 0x99, 0x9b, 0xd1, + 0x7d, 0xc6, 0xbd, 0x59, 0x30, 0x95, 0x55, 0x2b, 0xc7, 0x03, 0x45, 0x3c, 0xa6, 0x9c, 0x2d, 0xfd, + 0x06, 0x19, 0x0b, 0x75, 0x60, 0x4d, 0x31, 0xe4, 0x86, 0x35, 0x8f, 0x57, 0xf4, 0x0a, 0x49, 0x22, + 0xc8, 0x84, 0x16, 0x97, 0x45, 0xbb, 0x09, 0xa5, 0x26, 0x1b, 0x6c, 0xee, 0x0e, 0x94, 0xad, 0x09, + 0x69, 0xaa, 0x24, 0x55, 0xd5, 0x71, 0xeb, 0x43, 0xe3, 0xf0, 0xe5, 0x9b, 0x34, 0xe3, 0x6a, 0x4d, + 0x3e, 0x7d, 0xff, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x39, 0xf7, 0x01, 0xf5, 0x83, 0x0a, 0x00, + 0x00, } diff --git a/protocol/protobuf/community_update.proto b/protocol/protobuf/community_update.proto index babaa8351..36086bd61 100644 --- a/protocol/protobuf/community_update.proto +++ b/protocol/protobuf/community_update.proto @@ -18,7 +18,7 @@ message CommunityEvent { map rejectedRequestsToJoin = 9; map acceptedRequestsToJoin = 10; CommunityTokenMetadata token_metadata = 11; - + enum EventType { UNKNOWN = 0; COMMUNITY_EDIT = 1; @@ -64,14 +64,25 @@ message ChannelData { CommunityChat channel = 4; } +message SignedCommunityEvent { + // Signature of the payload field + bytes signature = 1; + // Marshaled CommunityEvent + bytes payload = 2; +} + // CommunityEventsMessage is a message used to propagate information // about community changes. message CommunityEventsMessage { bytes community_id = 1; - + // Events base CommunityDescription with owner signature on top of which events were generated bytes events_base_community_description = 2; - + // A list of admins events for the channel in bytes - repeated bytes events = 3; + // Deprecated: use signed_events instead. + repeated bytes events = 3 [deprecated=true]; + + // A list of signed community events + repeated SignedCommunityEvent signed_events = 4; }