diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..fb87ac1e --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +export GOPRIVATE=github.com/anytypeio + +ifndef $(GOPATH) + GOPATH=$(shell go env GOPATH) + export GOPATH +endif + +ifndef $(GOROOT) + GOROOT=$(shell go env GOROOT) + export GOROOT +endif + +export PATH=$(GOPATH)/bin:$(shell echo $$PATH) + +# TODO: folders were changed, so we should update Makefile and protos generation +protos-go: + @echo 'Generating protobuf packages (Go)...' + $(eval P_TIMESTAMP := Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types) + $(eval P_STRUCT := Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types) + @$(eval P_ACL_CHANGES := Mdata/pb/protos/aclchanges.proto=github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb) + @$(eval P_THREAD := Mdata/pb/protos/aclchanges.proto=github.com/anytypeio/go-anytype-infrastructure-experiments/thread/pb) + @$(eval P_PLAINTEXT_CHANGES := Mdata/pb/protos/plaintextchanges.proto=github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/testchanges/pb) + + $(eval PKGMAP := $$(P_TIMESTAMP),$$(P_STRUCT),$$(P_ACL_CHANGES)) + GOGO_NO_UNDERSCORE=1 GOGO_EXPORT_ONEOF_INTERFACE=1 protoc --gogofaster_out=$(PKGMAP):./aclchanges/pb aclchanges/pb/protos/*.*; mv aclchanges/pb/aclchanges/pb/protos/*.go aclchanges/pb; rm -rf aclchanges/pb/aclchanges + $(eval PKGMAP := $$(P_TIMESTAMP),$$(P_STRUCT),$$(P_THREAD)) + GOGO_NO_UNDERSCORE=1 GOGO_EXPORT_ONEOF_INTERFACE=1 protoc --gogofaster_out=$(PKGMAP):./thread/pb thread/pb/protos/*.*; mv thread/pb/thread/pb/protos/*.go thread/pb; rm -rf thread/pb/thread diff --git a/account/accountdata.go b/account/accountdata.go new file mode 100644 index 00000000..2c06b02a --- /dev/null +++ b/account/accountdata.go @@ -0,0 +1,9 @@ +package account + +import "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" + +type AccountData struct { + Identity string + SignKey keys.SigningPrivKey + EncKey keys.EncryptionPrivKey +} diff --git a/aclchanges/change.go b/aclchanges/change.go new file mode 100644 index 00000000..f8253ace --- /dev/null +++ b/aclchanges/change.go @@ -0,0 +1,10 @@ +package aclchanges + +import "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + +type Change interface { + ProtoChange() *pb.ACLChange + DecryptedChangeContent() []byte + Signature() []byte + CID() string +} diff --git a/aclchanges/pb/aclchanges.pb.go b/aclchanges/pb/aclchanges.pb.go new file mode 100644 index 00000000..39c15341 --- /dev/null +++ b/aclchanges/pb/aclchanges.pb.go @@ -0,0 +1,4620 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: aclchanges/pb/protos/aclchanges.proto + +package pb + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type ACLChangeUserPermissions int32 + +const ( + ACLChange_Admin ACLChangeUserPermissions = 0 + ACLChange_Writer ACLChangeUserPermissions = 1 + ACLChange_Reader ACLChangeUserPermissions = 2 + ACLChange_Removed ACLChangeUserPermissions = 3 +) + +var ACLChangeUserPermissions_name = map[int32]string{ + 0: "Admin", + 1: "Writer", + 2: "Reader", + 3: "Removed", +} + +var ACLChangeUserPermissions_value = map[string]int32{ + "Admin": 0, + "Writer": 1, + "Reader": 2, + "Removed": 3, +} + +func (x ACLChangeUserPermissions) String() string { + return proto.EnumName(ACLChangeUserPermissions_name, int32(x)) +} + +func (ACLChangeUserPermissions) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 0} +} + +// the element of change tree used to store and internal apply smartBlock history +type ACLChange struct { + TreeHeadIds []string `protobuf:"bytes,1,rep,name=treeHeadIds,proto3" json:"treeHeadIds,omitempty"` + AclHeadIds []string `protobuf:"bytes,2,rep,name=aclHeadIds,proto3" json:"aclHeadIds,omitempty"` + SnapshotBaseId string `protobuf:"bytes,3,opt,name=snapshotBaseId,proto3" json:"snapshotBaseId,omitempty"` + AclData *ACLChangeACLData `protobuf:"bytes,4,opt,name=aclData,proto3" json:"aclData,omitempty"` + // the data is encoded with read key and should be read in ChangesData format + ChangesData []byte `protobuf:"bytes,5,opt,name=changesData,proto3" json:"changesData,omitempty"` + CurrentReadKeyHash uint64 `protobuf:"varint,6,opt,name=currentReadKeyHash,proto3" json:"currentReadKeyHash,omitempty"` + Timestamp int64 `protobuf:"varint,7,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Identity string `protobuf:"bytes,8,opt,name=identity,proto3" json:"identity,omitempty"` +} + +func (m *ACLChange) Reset() { *m = ACLChange{} } +func (m *ACLChange) String() string { return proto.CompactTextString(m) } +func (*ACLChange) ProtoMessage() {} +func (*ACLChange) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0} +} +func (m *ACLChange) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChange.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChange.Merge(m, src) +} +func (m *ACLChange) XXX_Size() int { + return m.Size() +} +func (m *ACLChange) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChange.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChange proto.InternalMessageInfo + +func (m *ACLChange) GetTreeHeadIds() []string { + if m != nil { + return m.TreeHeadIds + } + return nil +} + +func (m *ACLChange) GetAclHeadIds() []string { + if m != nil { + return m.AclHeadIds + } + return nil +} + +func (m *ACLChange) GetSnapshotBaseId() string { + if m != nil { + return m.SnapshotBaseId + } + return "" +} + +func (m *ACLChange) GetAclData() *ACLChangeACLData { + if m != nil { + return m.AclData + } + return nil +} + +func (m *ACLChange) GetChangesData() []byte { + if m != nil { + return m.ChangesData + } + return nil +} + +func (m *ACLChange) GetCurrentReadKeyHash() uint64 { + if m != nil { + return m.CurrentReadKeyHash + } + return 0 +} + +func (m *ACLChange) GetTimestamp() int64 { + if m != nil { + return m.Timestamp + } + return 0 +} + +func (m *ACLChange) GetIdentity() string { + if m != nil { + return m.Identity + } + return "" +} + +type ACLChangeACLContentValue struct { + // Types that are valid to be assigned to Value: + // *ACLChangeACLContentValueValueOfUserAdd + // *ACLChangeACLContentValueValueOfUserRemove + // *ACLChangeACLContentValueValueOfUserPermissionChange + // *ACLChangeACLContentValueValueOfUserInvite + // *ACLChangeACLContentValueValueOfUserJoin + // *ACLChangeACLContentValueValueOfUserConfirm + Value IsACLChangeACLContentValueValue `protobuf_oneof:"value"` +} + +func (m *ACLChangeACLContentValue) Reset() { *m = ACLChangeACLContentValue{} } +func (m *ACLChangeACLContentValue) String() string { return proto.CompactTextString(m) } +func (*ACLChangeACLContentValue) ProtoMessage() {} +func (*ACLChangeACLContentValue) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 0} +} +func (m *ACLChangeACLContentValue) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeACLContentValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeACLContentValue.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeACLContentValue) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeACLContentValue.Merge(m, src) +} +func (m *ACLChangeACLContentValue) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeACLContentValue) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeACLContentValue.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeACLContentValue proto.InternalMessageInfo + +type IsACLChangeACLContentValueValue interface { + IsACLChangeACLContentValueValue() + MarshalTo([]byte) (int, error) + Size() int +} + +type ACLChangeACLContentValueValueOfUserAdd struct { + UserAdd *ACLChangeUserAdd `protobuf:"bytes,1,opt,name=userAdd,proto3,oneof" json:"userAdd,omitempty"` +} +type ACLChangeACLContentValueValueOfUserRemove struct { + UserRemove *ACLChangeUserRemove `protobuf:"bytes,2,opt,name=userRemove,proto3,oneof" json:"userRemove,omitempty"` +} +type ACLChangeACLContentValueValueOfUserPermissionChange struct { + UserPermissionChange *ACLChangeUserPermissionChange `protobuf:"bytes,3,opt,name=userPermissionChange,proto3,oneof" json:"userPermissionChange,omitempty"` +} +type ACLChangeACLContentValueValueOfUserInvite struct { + UserInvite *ACLChangeUserInvite `protobuf:"bytes,4,opt,name=userInvite,proto3,oneof" json:"userInvite,omitempty"` +} +type ACLChangeACLContentValueValueOfUserJoin struct { + UserJoin *ACLChangeUserJoin `protobuf:"bytes,5,opt,name=userJoin,proto3,oneof" json:"userJoin,omitempty"` +} +type ACLChangeACLContentValueValueOfUserConfirm struct { + UserConfirm *ACLChangeUserConfirm `protobuf:"bytes,6,opt,name=userConfirm,proto3,oneof" json:"userConfirm,omitempty"` +} + +func (*ACLChangeACLContentValueValueOfUserAdd) IsACLChangeACLContentValueValue() {} +func (*ACLChangeACLContentValueValueOfUserRemove) IsACLChangeACLContentValueValue() {} +func (*ACLChangeACLContentValueValueOfUserPermissionChange) IsACLChangeACLContentValueValue() {} +func (*ACLChangeACLContentValueValueOfUserInvite) IsACLChangeACLContentValueValue() {} +func (*ACLChangeACLContentValueValueOfUserJoin) IsACLChangeACLContentValueValue() {} +func (*ACLChangeACLContentValueValueOfUserConfirm) IsACLChangeACLContentValueValue() {} + +func (m *ACLChangeACLContentValue) GetValue() IsACLChangeACLContentValueValue { + if m != nil { + return m.Value + } + return nil +} + +func (m *ACLChangeACLContentValue) GetUserAdd() *ACLChangeUserAdd { + if x, ok := m.GetValue().(*ACLChangeACLContentValueValueOfUserAdd); ok { + return x.UserAdd + } + return nil +} + +func (m *ACLChangeACLContentValue) GetUserRemove() *ACLChangeUserRemove { + if x, ok := m.GetValue().(*ACLChangeACLContentValueValueOfUserRemove); ok { + return x.UserRemove + } + return nil +} + +func (m *ACLChangeACLContentValue) GetUserPermissionChange() *ACLChangeUserPermissionChange { + if x, ok := m.GetValue().(*ACLChangeACLContentValueValueOfUserPermissionChange); ok { + return x.UserPermissionChange + } + return nil +} + +func (m *ACLChangeACLContentValue) GetUserInvite() *ACLChangeUserInvite { + if x, ok := m.GetValue().(*ACLChangeACLContentValueValueOfUserInvite); ok { + return x.UserInvite + } + return nil +} + +func (m *ACLChangeACLContentValue) GetUserJoin() *ACLChangeUserJoin { + if x, ok := m.GetValue().(*ACLChangeACLContentValueValueOfUserJoin); ok { + return x.UserJoin + } + return nil +} + +func (m *ACLChangeACLContentValue) GetUserConfirm() *ACLChangeUserConfirm { + if x, ok := m.GetValue().(*ACLChangeACLContentValueValueOfUserConfirm); ok { + return x.UserConfirm + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*ACLChangeACLContentValue) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*ACLChangeACLContentValueValueOfUserAdd)(nil), + (*ACLChangeACLContentValueValueOfUserRemove)(nil), + (*ACLChangeACLContentValueValueOfUserPermissionChange)(nil), + (*ACLChangeACLContentValueValueOfUserInvite)(nil), + (*ACLChangeACLContentValueValueOfUserJoin)(nil), + (*ACLChangeACLContentValueValueOfUserConfirm)(nil), + } +} + +type ACLChangeACLData struct { + AclSnapshot *ACLChangeACLSnapshot `protobuf:"bytes,1,opt,name=aclSnapshot,proto3" json:"aclSnapshot,omitempty"` + AclContent []*ACLChangeACLContentValue `protobuf:"bytes,2,rep,name=aclContent,proto3" json:"aclContent,omitempty"` +} + +func (m *ACLChangeACLData) Reset() { *m = ACLChangeACLData{} } +func (m *ACLChangeACLData) String() string { return proto.CompactTextString(m) } +func (*ACLChangeACLData) ProtoMessage() {} +func (*ACLChangeACLData) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 1} +} +func (m *ACLChangeACLData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeACLData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeACLData.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeACLData) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeACLData.Merge(m, src) +} +func (m *ACLChangeACLData) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeACLData) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeACLData.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeACLData proto.InternalMessageInfo + +func (m *ACLChangeACLData) GetAclSnapshot() *ACLChangeACLSnapshot { + if m != nil { + return m.AclSnapshot + } + return nil +} + +func (m *ACLChangeACLData) GetAclContent() []*ACLChangeACLContentValue { + if m != nil { + return m.AclContent + } + return nil +} + +type ACLChangeACLSnapshot struct { + // We don't need ACLState as a separate message now, because we simplified the snapshot model + AclState *ACLChangeACLState `protobuf:"bytes,1,opt,name=aclState,proto3" json:"aclState,omitempty"` +} + +func (m *ACLChangeACLSnapshot) Reset() { *m = ACLChangeACLSnapshot{} } +func (m *ACLChangeACLSnapshot) String() string { return proto.CompactTextString(m) } +func (*ACLChangeACLSnapshot) ProtoMessage() {} +func (*ACLChangeACLSnapshot) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 2} +} +func (m *ACLChangeACLSnapshot) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeACLSnapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeACLSnapshot.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeACLSnapshot) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeACLSnapshot.Merge(m, src) +} +func (m *ACLChangeACLSnapshot) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeACLSnapshot) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeACLSnapshot.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeACLSnapshot proto.InternalMessageInfo + +func (m *ACLChangeACLSnapshot) GetAclState() *ACLChangeACLState { + if m != nil { + return m.AclState + } + return nil +} + +type ACLChangeACLState struct { + ReadKeyHashes []uint64 `protobuf:"varint,1,rep,packed,name=readKeyHashes,proto3" json:"readKeyHashes,omitempty"` + UserStates []*ACLChangeUserState `protobuf:"bytes,2,rep,name=userStates,proto3" json:"userStates,omitempty"` + Invites map[string]*ACLChangeUserInvite `protobuf:"bytes,3,rep,name=invites,proto3" json:"invites,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (m *ACLChangeACLState) Reset() { *m = ACLChangeACLState{} } +func (m *ACLChangeACLState) String() string { return proto.CompactTextString(m) } +func (*ACLChangeACLState) ProtoMessage() {} +func (*ACLChangeACLState) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 3} +} +func (m *ACLChangeACLState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeACLState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeACLState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeACLState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeACLState.Merge(m, src) +} +func (m *ACLChangeACLState) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeACLState) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeACLState.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeACLState proto.InternalMessageInfo + +func (m *ACLChangeACLState) GetReadKeyHashes() []uint64 { + if m != nil { + return m.ReadKeyHashes + } + return nil +} + +func (m *ACLChangeACLState) GetUserStates() []*ACLChangeUserState { + if m != nil { + return m.UserStates + } + return nil +} + +func (m *ACLChangeACLState) GetInvites() map[string]*ACLChangeUserInvite { + if m != nil { + return m.Invites + } + return nil +} + +type ACLChangeUserState struct { + Identity string `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"` + EncryptionKey []byte `protobuf:"bytes,2,opt,name=encryptionKey,proto3" json:"encryptionKey,omitempty"` + EncryptedReadKeys [][]byte `protobuf:"bytes,3,rep,name=encryptedReadKeys,proto3" json:"encryptedReadKeys,omitempty"` + Permissions ACLChangeUserPermissions `protobuf:"varint,4,opt,name=permissions,proto3,enum=anytype.ACLChangeUserPermissions" json:"permissions,omitempty"` + IsConfirmed bool `protobuf:"varint,5,opt,name=IsConfirmed,proto3" json:"IsConfirmed,omitempty"` +} + +func (m *ACLChangeUserState) Reset() { *m = ACLChangeUserState{} } +func (m *ACLChangeUserState) String() string { return proto.CompactTextString(m) } +func (*ACLChangeUserState) ProtoMessage() {} +func (*ACLChangeUserState) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 4} +} +func (m *ACLChangeUserState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeUserState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeUserState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeUserState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeUserState.Merge(m, src) +} +func (m *ACLChangeUserState) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeUserState) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeUserState.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeUserState proto.InternalMessageInfo + +func (m *ACLChangeUserState) GetIdentity() string { + if m != nil { + return m.Identity + } + return "" +} + +func (m *ACLChangeUserState) GetEncryptionKey() []byte { + if m != nil { + return m.EncryptionKey + } + return nil +} + +func (m *ACLChangeUserState) GetEncryptedReadKeys() [][]byte { + if m != nil { + return m.EncryptedReadKeys + } + return nil +} + +func (m *ACLChangeUserState) GetPermissions() ACLChangeUserPermissions { + if m != nil { + return m.Permissions + } + return ACLChange_Admin +} + +func (m *ACLChangeUserState) GetIsConfirmed() bool { + if m != nil { + return m.IsConfirmed + } + return false +} + +// we already know identity and encryptionKey +type ACLChangeUserAdd struct { + Identity string `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"` + EncryptionKey []byte `protobuf:"bytes,2,opt,name=encryptionKey,proto3" json:"encryptionKey,omitempty"` + EncryptedReadKeys [][]byte `protobuf:"bytes,3,rep,name=encryptedReadKeys,proto3" json:"encryptedReadKeys,omitempty"` + Permissions ACLChangeUserPermissions `protobuf:"varint,4,opt,name=permissions,proto3,enum=anytype.ACLChangeUserPermissions" json:"permissions,omitempty"` +} + +func (m *ACLChangeUserAdd) Reset() { *m = ACLChangeUserAdd{} } +func (m *ACLChangeUserAdd) String() string { return proto.CompactTextString(m) } +func (*ACLChangeUserAdd) ProtoMessage() {} +func (*ACLChangeUserAdd) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 5} +} +func (m *ACLChangeUserAdd) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeUserAdd) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeUserAdd.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeUserAdd) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeUserAdd.Merge(m, src) +} +func (m *ACLChangeUserAdd) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeUserAdd) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeUserAdd.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeUserAdd proto.InternalMessageInfo + +func (m *ACLChangeUserAdd) GetIdentity() string { + if m != nil { + return m.Identity + } + return "" +} + +func (m *ACLChangeUserAdd) GetEncryptionKey() []byte { + if m != nil { + return m.EncryptionKey + } + return nil +} + +func (m *ACLChangeUserAdd) GetEncryptedReadKeys() [][]byte { + if m != nil { + return m.EncryptedReadKeys + } + return nil +} + +func (m *ACLChangeUserAdd) GetPermissions() ACLChangeUserPermissions { + if m != nil { + return m.Permissions + } + return ACLChange_Admin +} + +// TODO: this is not used as of now +type ACLChangeUserConfirm struct { + Identity string `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"` + UserAddId string `protobuf:"bytes,2,opt,name=userAddId,proto3" json:"userAddId,omitempty"` +} + +func (m *ACLChangeUserConfirm) Reset() { *m = ACLChangeUserConfirm{} } +func (m *ACLChangeUserConfirm) String() string { return proto.CompactTextString(m) } +func (*ACLChangeUserConfirm) ProtoMessage() {} +func (*ACLChangeUserConfirm) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 6} +} +func (m *ACLChangeUserConfirm) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeUserConfirm) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeUserConfirm.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeUserConfirm) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeUserConfirm.Merge(m, src) +} +func (m *ACLChangeUserConfirm) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeUserConfirm) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeUserConfirm.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeUserConfirm proto.InternalMessageInfo + +func (m *ACLChangeUserConfirm) GetIdentity() string { + if m != nil { + return m.Identity + } + return "" +} + +func (m *ACLChangeUserConfirm) GetUserAddId() string { + if m != nil { + return m.UserAddId + } + return "" +} + +type ACLChangeUserInvite struct { + AcceptPublicKey []byte `protobuf:"bytes,1,opt,name=acceptPublicKey,proto3" json:"acceptPublicKey,omitempty"` + EncryptPublicKey []byte `protobuf:"bytes,2,opt,name=encryptPublicKey,proto3" json:"encryptPublicKey,omitempty"` + EncryptedReadKeys [][]byte `protobuf:"bytes,3,rep,name=encryptedReadKeys,proto3" json:"encryptedReadKeys,omitempty"` + Permissions ACLChangeUserPermissions `protobuf:"varint,4,opt,name=permissions,proto3,enum=anytype.ACLChangeUserPermissions" json:"permissions,omitempty"` + InviteId string `protobuf:"bytes,5,opt,name=InviteId,proto3" json:"InviteId,omitempty"` +} + +func (m *ACLChangeUserInvite) Reset() { *m = ACLChangeUserInvite{} } +func (m *ACLChangeUserInvite) String() string { return proto.CompactTextString(m) } +func (*ACLChangeUserInvite) ProtoMessage() {} +func (*ACLChangeUserInvite) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 7} +} +func (m *ACLChangeUserInvite) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeUserInvite) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeUserInvite.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeUserInvite) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeUserInvite.Merge(m, src) +} +func (m *ACLChangeUserInvite) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeUserInvite) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeUserInvite.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeUserInvite proto.InternalMessageInfo + +func (m *ACLChangeUserInvite) GetAcceptPublicKey() []byte { + if m != nil { + return m.AcceptPublicKey + } + return nil +} + +func (m *ACLChangeUserInvite) GetEncryptPublicKey() []byte { + if m != nil { + return m.EncryptPublicKey + } + return nil +} + +func (m *ACLChangeUserInvite) GetEncryptedReadKeys() [][]byte { + if m != nil { + return m.EncryptedReadKeys + } + return nil +} + +func (m *ACLChangeUserInvite) GetPermissions() ACLChangeUserPermissions { + if m != nil { + return m.Permissions + } + return ACLChange_Admin +} + +func (m *ACLChangeUserInvite) GetInviteId() string { + if m != nil { + return m.InviteId + } + return "" +} + +type ACLChangeUserJoin struct { + Identity string `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"` + EncryptionKey []byte `protobuf:"bytes,2,opt,name=encryptionKey,proto3" json:"encryptionKey,omitempty"` + AcceptSignature []byte `protobuf:"bytes,3,opt,name=acceptSignature,proto3" json:"acceptSignature,omitempty"` + UserInviteId string `protobuf:"bytes,4,opt,name=userInviteId,proto3" json:"userInviteId,omitempty"` + EncryptedReadKeys [][]byte `protobuf:"bytes,5,rep,name=encryptedReadKeys,proto3" json:"encryptedReadKeys,omitempty"` +} + +func (m *ACLChangeUserJoin) Reset() { *m = ACLChangeUserJoin{} } +func (m *ACLChangeUserJoin) String() string { return proto.CompactTextString(m) } +func (*ACLChangeUserJoin) ProtoMessage() {} +func (*ACLChangeUserJoin) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 8} +} +func (m *ACLChangeUserJoin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeUserJoin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeUserJoin.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeUserJoin) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeUserJoin.Merge(m, src) +} +func (m *ACLChangeUserJoin) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeUserJoin) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeUserJoin.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeUserJoin proto.InternalMessageInfo + +func (m *ACLChangeUserJoin) GetIdentity() string { + if m != nil { + return m.Identity + } + return "" +} + +func (m *ACLChangeUserJoin) GetEncryptionKey() []byte { + if m != nil { + return m.EncryptionKey + } + return nil +} + +func (m *ACLChangeUserJoin) GetAcceptSignature() []byte { + if m != nil { + return m.AcceptSignature + } + return nil +} + +func (m *ACLChangeUserJoin) GetUserInviteId() string { + if m != nil { + return m.UserInviteId + } + return "" +} + +func (m *ACLChangeUserJoin) GetEncryptedReadKeys() [][]byte { + if m != nil { + return m.EncryptedReadKeys + } + return nil +} + +type ACLChangeUserRemove struct { + Identity string `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"` + ReadKeyReplaces []*ACLChangeReadKeyReplace `protobuf:"bytes,3,rep,name=readKeyReplaces,proto3" json:"readKeyReplaces,omitempty"` +} + +func (m *ACLChangeUserRemove) Reset() { *m = ACLChangeUserRemove{} } +func (m *ACLChangeUserRemove) String() string { return proto.CompactTextString(m) } +func (*ACLChangeUserRemove) ProtoMessage() {} +func (*ACLChangeUserRemove) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 9} +} +func (m *ACLChangeUserRemove) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeUserRemove) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeUserRemove.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeUserRemove) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeUserRemove.Merge(m, src) +} +func (m *ACLChangeUserRemove) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeUserRemove) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeUserRemove.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeUserRemove proto.InternalMessageInfo + +func (m *ACLChangeUserRemove) GetIdentity() string { + if m != nil { + return m.Identity + } + return "" +} + +func (m *ACLChangeUserRemove) GetReadKeyReplaces() []*ACLChangeReadKeyReplace { + if m != nil { + return m.ReadKeyReplaces + } + return nil +} + +type ACLChangeReadKeyReplace struct { + Identity string `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"` + EncryptionKey []byte `protobuf:"bytes,2,opt,name=encryptionKey,proto3" json:"encryptionKey,omitempty"` + EncryptedReadKey []byte `protobuf:"bytes,3,opt,name=encryptedReadKey,proto3" json:"encryptedReadKey,omitempty"` +} + +func (m *ACLChangeReadKeyReplace) Reset() { *m = ACLChangeReadKeyReplace{} } +func (m *ACLChangeReadKeyReplace) String() string { return proto.CompactTextString(m) } +func (*ACLChangeReadKeyReplace) ProtoMessage() {} +func (*ACLChangeReadKeyReplace) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 10} +} +func (m *ACLChangeReadKeyReplace) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeReadKeyReplace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeReadKeyReplace.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeReadKeyReplace) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeReadKeyReplace.Merge(m, src) +} +func (m *ACLChangeReadKeyReplace) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeReadKeyReplace) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeReadKeyReplace.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeReadKeyReplace proto.InternalMessageInfo + +func (m *ACLChangeReadKeyReplace) GetIdentity() string { + if m != nil { + return m.Identity + } + return "" +} + +func (m *ACLChangeReadKeyReplace) GetEncryptionKey() []byte { + if m != nil { + return m.EncryptionKey + } + return nil +} + +func (m *ACLChangeReadKeyReplace) GetEncryptedReadKey() []byte { + if m != nil { + return m.EncryptedReadKey + } + return nil +} + +type ACLChangeUserPermissionChange struct { + Identity string `protobuf:"bytes,1,opt,name=identity,proto3" json:"identity,omitempty"` + Permissions ACLChangeUserPermissions `protobuf:"varint,2,opt,name=permissions,proto3,enum=anytype.ACLChangeUserPermissions" json:"permissions,omitempty"` +} + +func (m *ACLChangeUserPermissionChange) Reset() { *m = ACLChangeUserPermissionChange{} } +func (m *ACLChangeUserPermissionChange) String() string { return proto.CompactTextString(m) } +func (*ACLChangeUserPermissionChange) ProtoMessage() {} +func (*ACLChangeUserPermissionChange) Descriptor() ([]byte, []int) { + return fileDescriptor_ffc88c8445fc0f24, []int{0, 11} +} +func (m *ACLChangeUserPermissionChange) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ACLChangeUserPermissionChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ACLChangeUserPermissionChange.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ACLChangeUserPermissionChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_ACLChangeUserPermissionChange.Merge(m, src) +} +func (m *ACLChangeUserPermissionChange) XXX_Size() int { + return m.Size() +} +func (m *ACLChangeUserPermissionChange) XXX_DiscardUnknown() { + xxx_messageInfo_ACLChangeUserPermissionChange.DiscardUnknown(m) +} + +var xxx_messageInfo_ACLChangeUserPermissionChange proto.InternalMessageInfo + +func (m *ACLChangeUserPermissionChange) GetIdentity() string { + if m != nil { + return m.Identity + } + return "" +} + +func (m *ACLChangeUserPermissionChange) GetPermissions() ACLChangeUserPermissions { + if m != nil { + return m.Permissions + } + return ACLChange_Admin +} + +func init() { + proto.RegisterEnum("anytype.ACLChangeUserPermissions", ACLChangeUserPermissions_name, ACLChangeUserPermissions_value) + proto.RegisterType((*ACLChange)(nil), "anytype.ACLChange") + proto.RegisterType((*ACLChangeACLContentValue)(nil), "anytype.ACLChange.ACLContentValue") + proto.RegisterType((*ACLChangeACLData)(nil), "anytype.ACLChange.ACLData") + proto.RegisterType((*ACLChangeACLSnapshot)(nil), "anytype.ACLChange.ACLSnapshot") + proto.RegisterType((*ACLChangeACLState)(nil), "anytype.ACLChange.ACLState") + proto.RegisterMapType((map[string]*ACLChangeUserInvite)(nil), "anytype.ACLChange.ACLState.InvitesEntry") + proto.RegisterType((*ACLChangeUserState)(nil), "anytype.ACLChange.UserState") + proto.RegisterType((*ACLChangeUserAdd)(nil), "anytype.ACLChange.UserAdd") + proto.RegisterType((*ACLChangeUserConfirm)(nil), "anytype.ACLChange.UserConfirm") + proto.RegisterType((*ACLChangeUserInvite)(nil), "anytype.ACLChange.UserInvite") + proto.RegisterType((*ACLChangeUserJoin)(nil), "anytype.ACLChange.UserJoin") + proto.RegisterType((*ACLChangeUserRemove)(nil), "anytype.ACLChange.UserRemove") + proto.RegisterType((*ACLChangeReadKeyReplace)(nil), "anytype.ACLChange.ReadKeyReplace") + proto.RegisterType((*ACLChangeUserPermissionChange)(nil), "anytype.ACLChange.UserPermissionChange") +} + +func init() { + proto.RegisterFile("aclchanges/pb/protos/aclchanges.proto", fileDescriptor_ffc88c8445fc0f24) +} + +var fileDescriptor_ffc88c8445fc0f24 = []byte{ + // 907 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x56, 0x4d, 0x6f, 0xe3, 0x44, + 0x18, 0xf6, 0x24, 0x6d, 0x1d, 0xbf, 0x0e, 0x6d, 0x18, 0xf5, 0x60, 0x79, 0x8b, 0x15, 0x2a, 0x3e, + 0x22, 0x84, 0x52, 0x29, 0x8b, 0xf8, 0x12, 0x12, 0x34, 0x5d, 0x20, 0xa1, 0x1c, 0x56, 0xb3, 0x02, + 0x04, 0x12, 0x87, 0xa9, 0x3d, 0x6c, 0x2d, 0x92, 0xb1, 0xe5, 0x99, 0x54, 0xe4, 0xc2, 0x3f, 0x40, + 0xf0, 0x5b, 0xb8, 0x72, 0xe0, 0xba, 0xc7, 0x3d, 0x72, 0x44, 0xed, 0x3f, 0xe0, 0x17, 0xa0, 0xf9, + 0xb0, 0xe3, 0xa4, 0x71, 0x91, 0x50, 0x25, 0xc4, 0x6d, 0xe6, 0x99, 0xe7, 0x99, 0xbc, 0x1f, 0xcf, + 0x3b, 0x0e, 0xbc, 0x4a, 0xe3, 0x59, 0x7c, 0x49, 0xf9, 0x53, 0x26, 0x4e, 0xf2, 0x8b, 0x93, 0xbc, + 0xc8, 0x64, 0x26, 0x4e, 0x56, 0xe0, 0x50, 0x23, 0xd8, 0xa5, 0x7c, 0x29, 0x97, 0x39, 0x3b, 0xfe, + 0xed, 0x10, 0xbc, 0xd3, 0xb3, 0xcf, 0xcf, 0xf4, 0x29, 0xee, 0x83, 0x2f, 0x0b, 0xc6, 0x26, 0x8c, + 0x26, 0xd3, 0x44, 0x04, 0xa8, 0xdf, 0x1e, 0x78, 0xa4, 0x0e, 0xe1, 0x08, 0x80, 0xc6, 0xb3, 0x92, + 0xd0, 0xd2, 0x84, 0x1a, 0x82, 0x5f, 0x83, 0x7d, 0xc1, 0x69, 0x2e, 0x2e, 0x33, 0x39, 0xa6, 0x82, + 0x4d, 0x93, 0xa0, 0xdd, 0x47, 0x03, 0x8f, 0x6c, 0xa0, 0xf8, 0x2d, 0x70, 0x69, 0x3c, 0x7b, 0x44, + 0x25, 0x0d, 0x76, 0xfa, 0x68, 0xe0, 0x8f, 0xc2, 0xa1, 0x0d, 0x69, 0x58, 0x85, 0xa3, 0x56, 0x8a, + 0x41, 0x4a, 0xaa, 0x8a, 0xcf, 0xe6, 0xa1, 0x95, 0xbb, 0x7d, 0x34, 0xe8, 0x92, 0x3a, 0x84, 0x87, + 0x80, 0xe3, 0x45, 0x51, 0x30, 0x2e, 0x09, 0xa3, 0xc9, 0x39, 0x5b, 0x4e, 0xa8, 0xb8, 0x0c, 0xf6, + 0xfa, 0x68, 0xb0, 0x43, 0xb6, 0x9c, 0xe0, 0x23, 0xf0, 0x64, 0x3a, 0x67, 0x42, 0xd2, 0x79, 0x1e, + 0xb8, 0x7d, 0x34, 0x68, 0x93, 0x15, 0x80, 0x43, 0xe8, 0xa4, 0x09, 0xe3, 0x32, 0x95, 0xcb, 0xa0, + 0xa3, 0xf3, 0xa8, 0xf6, 0xe1, 0xaf, 0x6d, 0x38, 0x50, 0xa1, 0x66, 0x5c, 0x32, 0x2e, 0xbf, 0xa4, + 0xb3, 0x05, 0xc3, 0x6f, 0x83, 0xbb, 0x10, 0xac, 0x38, 0x4d, 0x92, 0x00, 0x35, 0x66, 0xf5, 0x85, + 0x61, 0x4c, 0x1c, 0x52, 0x92, 0xf1, 0x87, 0x00, 0x6a, 0x49, 0xd8, 0x3c, 0xbb, 0x62, 0x41, 0x4b, + 0x4b, 0x5f, 0x6a, 0x90, 0x1a, 0xd2, 0xc4, 0x21, 0x35, 0x09, 0xfe, 0x16, 0x0e, 0xd5, 0xee, 0x31, + 0x2b, 0xe6, 0xa9, 0x10, 0x69, 0xc6, 0x8d, 0x40, 0x17, 0xdf, 0x1f, 0xbd, 0xde, 0x70, 0xd5, 0x26, + 0x7d, 0xe2, 0x90, 0xad, 0xd7, 0x94, 0xf1, 0x4d, 0xf9, 0x55, 0x2a, 0x99, 0x6d, 0x58, 0x53, 0x7c, + 0x86, 0x54, 0xc6, 0x67, 0x76, 0xf8, 0x3d, 0xe8, 0xa8, 0xdd, 0x67, 0x59, 0xca, 0x75, 0xd7, 0xfc, + 0xd1, 0x83, 0x06, 0xb9, 0xa2, 0x4c, 0x1c, 0x52, 0xd1, 0xf1, 0x18, 0x7c, 0xb5, 0x3e, 0xcb, 0xf8, + 0x77, 0x69, 0x31, 0xd7, 0xad, 0xf4, 0x47, 0x51, 0x83, 0xda, 0xb2, 0x26, 0x0e, 0xa9, 0x8b, 0xc6, + 0x2e, 0xec, 0x5e, 0xa9, 0x06, 0x85, 0x3f, 0x23, 0x70, 0xad, 0xab, 0xf0, 0x47, 0xe0, 0xd3, 0x78, + 0xf6, 0xc4, 0xfa, 0xd2, 0x36, 0x2c, 0xda, 0x6e, 0xc3, 0x92, 0x45, 0xea, 0x12, 0x3c, 0xd6, 0xc3, + 0x60, 0x1d, 0xa0, 0x87, 0xc1, 0x1f, 0x1d, 0x6f, 0xbf, 0xa0, 0x6e, 0x13, 0x52, 0x53, 0x85, 0x9f, + 0x80, 0x5f, 0xbb, 0x1f, 0xbf, 0x03, 0x1d, 0xf5, 0x0b, 0x92, 0x4a, 0x66, 0x23, 0x7a, 0xd0, 0x10, + 0x91, 0xa2, 0x90, 0x8a, 0x1c, 0xfe, 0xd4, 0x82, 0x4e, 0x09, 0xe3, 0x57, 0xe0, 0x85, 0x62, 0x65, + 0x72, 0x66, 0x26, 0x79, 0x87, 0xac, 0x83, 0xf8, 0x03, 0xd3, 0x55, 0x2d, 0x11, 0x36, 0xfc, 0xa3, + 0x86, 0xc2, 0x9a, 0x9f, 0xab, 0xf1, 0xf1, 0x18, 0xdc, 0x54, 0x37, 0x57, 0x04, 0x6d, 0x2d, 0x1d, + 0xdc, 0x11, 0xe8, 0xd0, 0xf8, 0x40, 0x7c, 0xcc, 0x65, 0xb1, 0x24, 0xa5, 0x30, 0xfc, 0x1a, 0xba, + 0xf5, 0x03, 0xdc, 0x83, 0xf6, 0xf7, 0x6c, 0xa9, 0x13, 0xf7, 0x88, 0x5a, 0xe2, 0x87, 0xb6, 0x73, + 0xff, 0x30, 0x14, 0xe6, 0x16, 0x62, 0xb8, 0xef, 0xb7, 0xde, 0x45, 0xe1, 0x0d, 0x02, 0xaf, 0x0a, + 0x7c, 0x6d, 0x90, 0xd1, 0xfa, 0x20, 0xab, 0x62, 0x31, 0x1e, 0x17, 0xcb, 0x5c, 0xa6, 0x19, 0x3f, + 0x67, 0x4b, 0xfd, 0x53, 0x5d, 0xb2, 0x0e, 0xe2, 0x37, 0xe1, 0x45, 0x0b, 0xb0, 0xc4, 0x3e, 0x20, + 0x26, 0xf1, 0x2e, 0xb9, 0x7d, 0x80, 0x1f, 0x81, 0x9f, 0x57, 0x43, 0x24, 0xf4, 0xc4, 0xec, 0x6f, + 0xb5, 0xc6, 0xfa, 0x18, 0x0a, 0x52, 0x97, 0xa9, 0xe7, 0x6e, 0x2a, 0xac, 0x87, 0x59, 0xa2, 0x07, + 0xa7, 0x43, 0xea, 0x50, 0xf8, 0x3b, 0x02, 0xd7, 0xbe, 0x27, 0xff, 0xcf, 0x1c, 0xc3, 0x4f, 0xc1, + 0xaf, 0x0d, 0xee, 0x9d, 0x49, 0x1c, 0x81, 0x67, 0x1f, 0xcc, 0x69, 0xa2, 0x13, 0xf0, 0xc8, 0x0a, + 0x08, 0xff, 0x42, 0x00, 0x2b, 0x2b, 0xe0, 0x01, 0x1c, 0xd0, 0x38, 0x66, 0xb9, 0x7c, 0xbc, 0xb8, + 0x98, 0xa5, 0xf1, 0xb9, 0xb5, 0x55, 0x97, 0x6c, 0xc2, 0xf8, 0x0d, 0xe8, 0xd9, 0xe4, 0x56, 0x54, + 0x53, 0x9e, 0x5b, 0xf8, 0x7f, 0xe2, 0x82, 0x10, 0x3a, 0x26, 0xa7, 0xa9, 0xb1, 0x80, 0x47, 0xaa, + 0x7d, 0xf8, 0x0c, 0x41, 0xa7, 0x7c, 0x35, 0xef, 0xc1, 0x00, 0x55, 0xd1, 0x9e, 0xa4, 0x4f, 0x39, + 0x95, 0x8b, 0xc2, 0x7c, 0x41, 0xaa, 0xa2, 0x55, 0x30, 0x3e, 0x86, 0xee, 0xea, 0x79, 0x9f, 0x26, + 0x3a, 0x37, 0x8f, 0xac, 0x61, 0xdb, 0x8b, 0xb5, 0xdb, 0x50, 0xac, 0x70, 0x61, 0xda, 0x67, 0x3f, + 0x68, 0x77, 0xe5, 0x72, 0x0e, 0x07, 0xf6, 0x21, 0x23, 0x2c, 0x9f, 0xd1, 0xb8, 0x7a, 0x81, 0x5e, + 0xde, 0x52, 0x5a, 0xb2, 0xc6, 0x24, 0x9b, 0xca, 0xf0, 0x47, 0xd8, 0x5f, 0xa7, 0xdc, 0x43, 0x19, + 0x57, 0x8e, 0xaa, 0xf2, 0xb3, 0x75, 0xbc, 0x85, 0x87, 0x3f, 0xc0, 0xe1, 0xb6, 0x4f, 0xf1, 0x9d, + 0x51, 0x6c, 0xf8, 0xaa, 0xf5, 0xaf, 0x7c, 0x75, 0x7c, 0x0a, 0x07, 0x1b, 0xe7, 0xd8, 0x83, 0xdd, + 0xd3, 0x64, 0x9e, 0xf2, 0x9e, 0x83, 0x01, 0xf6, 0xbe, 0x2a, 0x52, 0xc9, 0x8a, 0x1e, 0x52, 0x6b, + 0x15, 0x2e, 0x2b, 0x7a, 0x2d, 0xec, 0x83, 0x6b, 0x5a, 0x94, 0xf4, 0xda, 0xe3, 0xa3, 0x67, 0xd7, + 0x11, 0x7a, 0x7e, 0x1d, 0xa1, 0x3f, 0xaf, 0x23, 0xf4, 0xcb, 0x4d, 0xe4, 0x3c, 0xbf, 0x89, 0x9c, + 0x3f, 0x6e, 0x22, 0xe7, 0x9b, 0x56, 0x7e, 0x71, 0xb1, 0xa7, 0xff, 0x6b, 0x3e, 0xfc, 0x3b, 0x00, + 0x00, 0xff, 0xff, 0xd3, 0xdf, 0xf9, 0x1b, 0x94, 0x0a, 0x00, 0x00, +} + +func (m *ACLChange) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0x42 + } + if m.Timestamp != 0 { + i = encodeVarintAclchanges(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x38 + } + if m.CurrentReadKeyHash != 0 { + i = encodeVarintAclchanges(dAtA, i, uint64(m.CurrentReadKeyHash)) + i-- + dAtA[i] = 0x30 + } + if len(m.ChangesData) > 0 { + i -= len(m.ChangesData) + copy(dAtA[i:], m.ChangesData) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.ChangesData))) + i-- + dAtA[i] = 0x2a + } + if m.AclData != nil { + { + size, err := m.AclData.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.SnapshotBaseId) > 0 { + i -= len(m.SnapshotBaseId) + copy(dAtA[i:], m.SnapshotBaseId) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.SnapshotBaseId))) + i-- + dAtA[i] = 0x1a + } + if len(m.AclHeadIds) > 0 { + for iNdEx := len(m.AclHeadIds) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.AclHeadIds[iNdEx]) + copy(dAtA[i:], m.AclHeadIds[iNdEx]) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.AclHeadIds[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.TreeHeadIds) > 0 { + for iNdEx := len(m.TreeHeadIds) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.TreeHeadIds[iNdEx]) + copy(dAtA[i:], m.TreeHeadIds[iNdEx]) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.TreeHeadIds[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeACLContentValue) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeACLContentValue) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLContentValue) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Value != nil { + { + size := m.Value.Size() + i -= size + if _, err := m.Value.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeACLContentValueValueOfUserAdd) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLContentValueValueOfUserAdd) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.UserAdd != nil { + { + size, err := m.UserAdd.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func (m *ACLChangeACLContentValueValueOfUserRemove) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLContentValueValueOfUserRemove) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.UserRemove != nil { + { + size, err := m.UserRemove.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} +func (m *ACLChangeACLContentValueValueOfUserPermissionChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLContentValueValueOfUserPermissionChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.UserPermissionChange != nil { + { + size, err := m.UserPermissionChange.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + return len(dAtA) - i, nil +} +func (m *ACLChangeACLContentValueValueOfUserInvite) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLContentValueValueOfUserInvite) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.UserInvite != nil { + { + size, err := m.UserInvite.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + return len(dAtA) - i, nil +} +func (m *ACLChangeACLContentValueValueOfUserJoin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLContentValueValueOfUserJoin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.UserJoin != nil { + { + size, err := m.UserJoin.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + return len(dAtA) - i, nil +} +func (m *ACLChangeACLContentValueValueOfUserConfirm) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLContentValueValueOfUserConfirm) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.UserConfirm != nil { + { + size, err := m.UserConfirm.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + return len(dAtA) - i, nil +} +func (m *ACLChangeACLData) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeACLData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AclContent) > 0 { + for iNdEx := len(m.AclContent) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AclContent[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.AclSnapshot != nil { + { + size, err := m.AclSnapshot.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeACLSnapshot) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeACLSnapshot) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLSnapshot) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.AclState != nil { + { + size, err := m.AclState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeACLState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeACLState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeACLState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Invites) > 0 { + for k := range m.Invites { + v := m.Invites[k] + baseI := i + if v != nil { + { + size, err := v.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintAclchanges(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintAclchanges(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a + } + } + if len(m.UserStates) > 0 { + for iNdEx := len(m.UserStates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.UserStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.ReadKeyHashes) > 0 { + dAtA12 := make([]byte, len(m.ReadKeyHashes)*10) + var j11 int + for _, num := range m.ReadKeyHashes { + for num >= 1<<7 { + dAtA12[j11] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j11++ + } + dAtA12[j11] = uint8(num) + j11++ + } + i -= j11 + copy(dAtA[i:], dAtA12[:j11]) + i = encodeVarintAclchanges(dAtA, i, uint64(j11)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeUserState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeUserState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeUserState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.IsConfirmed { + i-- + if m.IsConfirmed { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if m.Permissions != 0 { + i = encodeVarintAclchanges(dAtA, i, uint64(m.Permissions)) + i-- + dAtA[i] = 0x20 + } + if len(m.EncryptedReadKeys) > 0 { + for iNdEx := len(m.EncryptedReadKeys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.EncryptedReadKeys[iNdEx]) + copy(dAtA[i:], m.EncryptedReadKeys[iNdEx]) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptedReadKeys[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.EncryptionKey) > 0 { + i -= len(m.EncryptionKey) + copy(dAtA[i:], m.EncryptionKey) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptionKey))) + i-- + dAtA[i] = 0x12 + } + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeUserAdd) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeUserAdd) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeUserAdd) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Permissions != 0 { + i = encodeVarintAclchanges(dAtA, i, uint64(m.Permissions)) + i-- + dAtA[i] = 0x20 + } + if len(m.EncryptedReadKeys) > 0 { + for iNdEx := len(m.EncryptedReadKeys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.EncryptedReadKeys[iNdEx]) + copy(dAtA[i:], m.EncryptedReadKeys[iNdEx]) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptedReadKeys[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.EncryptionKey) > 0 { + i -= len(m.EncryptionKey) + copy(dAtA[i:], m.EncryptionKey) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptionKey))) + i-- + dAtA[i] = 0x12 + } + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeUserConfirm) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeUserConfirm) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeUserConfirm) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.UserAddId) > 0 { + i -= len(m.UserAddId) + copy(dAtA[i:], m.UserAddId) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.UserAddId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeUserInvite) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeUserInvite) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeUserInvite) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.InviteId) > 0 { + i -= len(m.InviteId) + copy(dAtA[i:], m.InviteId) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.InviteId))) + i-- + dAtA[i] = 0x2a + } + if m.Permissions != 0 { + i = encodeVarintAclchanges(dAtA, i, uint64(m.Permissions)) + i-- + dAtA[i] = 0x20 + } + if len(m.EncryptedReadKeys) > 0 { + for iNdEx := len(m.EncryptedReadKeys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.EncryptedReadKeys[iNdEx]) + copy(dAtA[i:], m.EncryptedReadKeys[iNdEx]) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptedReadKeys[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.EncryptPublicKey) > 0 { + i -= len(m.EncryptPublicKey) + copy(dAtA[i:], m.EncryptPublicKey) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptPublicKey))) + i-- + dAtA[i] = 0x12 + } + if len(m.AcceptPublicKey) > 0 { + i -= len(m.AcceptPublicKey) + copy(dAtA[i:], m.AcceptPublicKey) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.AcceptPublicKey))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeUserJoin) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeUserJoin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeUserJoin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.EncryptedReadKeys) > 0 { + for iNdEx := len(m.EncryptedReadKeys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.EncryptedReadKeys[iNdEx]) + copy(dAtA[i:], m.EncryptedReadKeys[iNdEx]) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptedReadKeys[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.UserInviteId) > 0 { + i -= len(m.UserInviteId) + copy(dAtA[i:], m.UserInviteId) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.UserInviteId))) + i-- + dAtA[i] = 0x22 + } + if len(m.AcceptSignature) > 0 { + i -= len(m.AcceptSignature) + copy(dAtA[i:], m.AcceptSignature) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.AcceptSignature))) + i-- + dAtA[i] = 0x1a + } + if len(m.EncryptionKey) > 0 { + i -= len(m.EncryptionKey) + copy(dAtA[i:], m.EncryptionKey) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptionKey))) + i-- + dAtA[i] = 0x12 + } + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeUserRemove) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeUserRemove) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeUserRemove) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ReadKeyReplaces) > 0 { + for iNdEx := len(m.ReadKeyReplaces) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ReadKeyReplaces[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAclchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeReadKeyReplace) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeReadKeyReplace) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeReadKeyReplace) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.EncryptedReadKey) > 0 { + i -= len(m.EncryptedReadKey) + copy(dAtA[i:], m.EncryptedReadKey) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptedReadKey))) + i-- + dAtA[i] = 0x1a + } + if len(m.EncryptionKey) > 0 { + i -= len(m.EncryptionKey) + copy(dAtA[i:], m.EncryptionKey) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.EncryptionKey))) + i-- + dAtA[i] = 0x12 + } + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ACLChangeUserPermissionChange) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ACLChangeUserPermissionChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ACLChangeUserPermissionChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Permissions != 0 { + i = encodeVarintAclchanges(dAtA, i, uint64(m.Permissions)) + i-- + dAtA[i] = 0x10 + } + if len(m.Identity) > 0 { + i -= len(m.Identity) + copy(dAtA[i:], m.Identity) + i = encodeVarintAclchanges(dAtA, i, uint64(len(m.Identity))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintAclchanges(dAtA []byte, offset int, v uint64) int { + offset -= sovAclchanges(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ACLChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TreeHeadIds) > 0 { + for _, s := range m.TreeHeadIds { + l = len(s) + n += 1 + l + sovAclchanges(uint64(l)) + } + } + if len(m.AclHeadIds) > 0 { + for _, s := range m.AclHeadIds { + l = len(s) + n += 1 + l + sovAclchanges(uint64(l)) + } + } + l = len(m.SnapshotBaseId) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + if m.AclData != nil { + l = m.AclData.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.ChangesData) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + if m.CurrentReadKeyHash != 0 { + n += 1 + sovAclchanges(uint64(m.CurrentReadKeyHash)) + } + if m.Timestamp != 0 { + n += 1 + sovAclchanges(uint64(m.Timestamp)) + } + l = len(m.Identity) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} + +func (m *ACLChangeACLContentValue) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Value != nil { + n += m.Value.Size() + } + return n +} + +func (m *ACLChangeACLContentValueValueOfUserAdd) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UserAdd != nil { + l = m.UserAdd.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} +func (m *ACLChangeACLContentValueValueOfUserRemove) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UserRemove != nil { + l = m.UserRemove.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} +func (m *ACLChangeACLContentValueValueOfUserPermissionChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UserPermissionChange != nil { + l = m.UserPermissionChange.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} +func (m *ACLChangeACLContentValueValueOfUserInvite) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UserInvite != nil { + l = m.UserInvite.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} +func (m *ACLChangeACLContentValueValueOfUserJoin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UserJoin != nil { + l = m.UserJoin.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} +func (m *ACLChangeACLContentValueValueOfUserConfirm) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UserConfirm != nil { + l = m.UserConfirm.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} +func (m *ACLChangeACLData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.AclSnapshot != nil { + l = m.AclSnapshot.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + if len(m.AclContent) > 0 { + for _, e := range m.AclContent { + l = e.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + } + return n +} + +func (m *ACLChangeACLSnapshot) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.AclState != nil { + l = m.AclState.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} + +func (m *ACLChangeACLState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ReadKeyHashes) > 0 { + l = 0 + for _, e := range m.ReadKeyHashes { + l += sovAclchanges(uint64(e)) + } + n += 1 + sovAclchanges(uint64(l)) + l + } + if len(m.UserStates) > 0 { + for _, e := range m.UserStates { + l = e.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + } + if len(m.Invites) > 0 { + for k, v := range m.Invites { + _ = k + _ = v + l = 0 + if v != nil { + l = v.Size() + l += 1 + sovAclchanges(uint64(l)) + } + mapEntrySize := 1 + len(k) + sovAclchanges(uint64(len(k))) + l + n += mapEntrySize + 1 + sovAclchanges(uint64(mapEntrySize)) + } + } + return n +} + +func (m *ACLChangeUserState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Identity) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.EncryptionKey) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + if len(m.EncryptedReadKeys) > 0 { + for _, b := range m.EncryptedReadKeys { + l = len(b) + n += 1 + l + sovAclchanges(uint64(l)) + } + } + if m.Permissions != 0 { + n += 1 + sovAclchanges(uint64(m.Permissions)) + } + if m.IsConfirmed { + n += 2 + } + return n +} + +func (m *ACLChangeUserAdd) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Identity) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.EncryptionKey) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + if len(m.EncryptedReadKeys) > 0 { + for _, b := range m.EncryptedReadKeys { + l = len(b) + n += 1 + l + sovAclchanges(uint64(l)) + } + } + if m.Permissions != 0 { + n += 1 + sovAclchanges(uint64(m.Permissions)) + } + return n +} + +func (m *ACLChangeUserConfirm) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Identity) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.UserAddId) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} + +func (m *ACLChangeUserInvite) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.AcceptPublicKey) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.EncryptPublicKey) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + if len(m.EncryptedReadKeys) > 0 { + for _, b := range m.EncryptedReadKeys { + l = len(b) + n += 1 + l + sovAclchanges(uint64(l)) + } + } + if m.Permissions != 0 { + n += 1 + sovAclchanges(uint64(m.Permissions)) + } + l = len(m.InviteId) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} + +func (m *ACLChangeUserJoin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Identity) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.EncryptionKey) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.AcceptSignature) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.UserInviteId) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + if len(m.EncryptedReadKeys) > 0 { + for _, b := range m.EncryptedReadKeys { + l = len(b) + n += 1 + l + sovAclchanges(uint64(l)) + } + } + return n +} + +func (m *ACLChangeUserRemove) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Identity) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + if len(m.ReadKeyReplaces) > 0 { + for _, e := range m.ReadKeyReplaces { + l = e.Size() + n += 1 + l + sovAclchanges(uint64(l)) + } + } + return n +} + +func (m *ACLChangeReadKeyReplace) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Identity) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.EncryptionKey) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + l = len(m.EncryptedReadKey) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + return n +} + +func (m *ACLChangeUserPermissionChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Identity) + if l > 0 { + n += 1 + l + sovAclchanges(uint64(l)) + } + if m.Permissions != 0 { + n += 1 + sovAclchanges(uint64(m.Permissions)) + } + return n +} + +func sovAclchanges(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAclchanges(x uint64) (n int) { + return sovAclchanges(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ACLChange) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ACLChange: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ACLChange: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TreeHeadIds", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TreeHeadIds = append(m.TreeHeadIds, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AclHeadIds", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AclHeadIds = append(m.AclHeadIds, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SnapshotBaseId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SnapshotBaseId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AclData", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.AclData == nil { + m.AclData = &ACLChangeACLData{} + } + if err := m.AclData.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChangesData", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChangesData = append(m.ChangesData[:0], dAtA[iNdEx:postIndex]...) + if m.ChangesData == nil { + m.ChangesData = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentReadKeyHash", wireType) + } + m.CurrentReadKeyHash = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentReadKeyHash |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + m.Timestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Timestamp |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeACLContentValue) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ACLContentValue: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ACLContentValue: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserAdd", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &ACLChangeUserAdd{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &ACLChangeACLContentValueValueOfUserAdd{v} + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserRemove", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &ACLChangeUserRemove{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &ACLChangeACLContentValueValueOfUserRemove{v} + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserPermissionChange", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &ACLChangeUserPermissionChange{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &ACLChangeACLContentValueValueOfUserPermissionChange{v} + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserInvite", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &ACLChangeUserInvite{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &ACLChangeACLContentValueValueOfUserInvite{v} + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserJoin", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &ACLChangeUserJoin{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &ACLChangeACLContentValueValueOfUserJoin{v} + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserConfirm", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &ACLChangeUserConfirm{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &ACLChangeACLContentValueValueOfUserConfirm{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeACLData) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ACLData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ACLData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AclSnapshot", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.AclSnapshot == nil { + m.AclSnapshot = &ACLChangeACLSnapshot{} + } + if err := m.AclSnapshot.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AclContent", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AclContent = append(m.AclContent, &ACLChangeACLContentValue{}) + if err := m.AclContent[len(m.AclContent)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeACLSnapshot) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ACLSnapshot: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ACLSnapshot: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AclState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.AclState == nil { + m.AclState = &ACLChangeACLState{} + } + if err := m.AclState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeACLState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ACLState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ACLState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ReadKeyHashes = append(m.ReadKeyHashes, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.ReadKeyHashes) == 0 { + m.ReadKeyHashes = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ReadKeyHashes = append(m.ReadKeyHashes, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field ReadKeyHashes", wireType) + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserStates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UserStates = append(m.UserStates, &ACLChangeUserState{}) + if err := m.UserStates[len(m.UserStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Invites", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Invites == nil { + m.Invites = make(map[string]*ACLChangeUserInvite) + } + var mapkey string + var mapvalue *ACLChangeUserInvite + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthAclchanges + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthAclchanges + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapmsglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthAclchanges + } + postmsgIndex := iNdEx + mapmsglen + if postmsgIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = &ACLChangeUserInvite{} + if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Invites[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeUserState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UserState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UserState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptionKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptionKey = append(m.EncryptionKey[:0], dAtA[iNdEx:postIndex]...) + if m.EncryptionKey == nil { + m.EncryptionKey = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptedReadKeys", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptedReadKeys = append(m.EncryptedReadKeys, make([]byte, postIndex-iNdEx)) + copy(m.EncryptedReadKeys[len(m.EncryptedReadKeys)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) + } + m.Permissions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Permissions |= ACLChangeUserPermissions(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsConfirmed", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsConfirmed = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeUserAdd) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UserAdd: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UserAdd: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptionKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptionKey = append(m.EncryptionKey[:0], dAtA[iNdEx:postIndex]...) + if m.EncryptionKey == nil { + m.EncryptionKey = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptedReadKeys", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptedReadKeys = append(m.EncryptedReadKeys, make([]byte, postIndex-iNdEx)) + copy(m.EncryptedReadKeys[len(m.EncryptedReadKeys)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) + } + m.Permissions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Permissions |= ACLChangeUserPermissions(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeUserConfirm) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UserConfirm: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UserConfirm: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserAddId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UserAddId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeUserInvite) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UserInvite: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UserInvite: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AcceptPublicKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AcceptPublicKey = append(m.AcceptPublicKey[:0], dAtA[iNdEx:postIndex]...) + if m.AcceptPublicKey == nil { + m.AcceptPublicKey = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptPublicKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptPublicKey = append(m.EncryptPublicKey[:0], dAtA[iNdEx:postIndex]...) + if m.EncryptPublicKey == nil { + m.EncryptPublicKey = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptedReadKeys", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptedReadKeys = append(m.EncryptedReadKeys, make([]byte, postIndex-iNdEx)) + copy(m.EncryptedReadKeys[len(m.EncryptedReadKeys)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) + } + m.Permissions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Permissions |= ACLChangeUserPermissions(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InviteId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InviteId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeUserJoin) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UserJoin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UserJoin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptionKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptionKey = append(m.EncryptionKey[:0], dAtA[iNdEx:postIndex]...) + if m.EncryptionKey == nil { + m.EncryptionKey = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AcceptSignature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AcceptSignature = append(m.AcceptSignature[:0], dAtA[iNdEx:postIndex]...) + if m.AcceptSignature == nil { + m.AcceptSignature = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserInviteId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UserInviteId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptedReadKeys", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptedReadKeys = append(m.EncryptedReadKeys, make([]byte, postIndex-iNdEx)) + copy(m.EncryptedReadKeys[len(m.EncryptedReadKeys)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeUserRemove) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UserRemove: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UserRemove: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReadKeyReplaces", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReadKeyReplaces = append(m.ReadKeyReplaces, &ACLChangeReadKeyReplace{}) + if err := m.ReadKeyReplaces[len(m.ReadKeyReplaces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeReadKeyReplace) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ReadKeyReplace: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReadKeyReplace: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptionKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptionKey = append(m.EncryptionKey[:0], dAtA[iNdEx:postIndex]...) + if m.EncryptionKey == nil { + m.EncryptionKey = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EncryptedReadKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EncryptedReadKey = append(m.EncryptedReadKey[:0], dAtA[iNdEx:postIndex]...) + if m.EncryptedReadKey == nil { + m.EncryptedReadKey = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ACLChangeUserPermissionChange) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UserPermissionChange: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UserPermissionChange: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Identity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAclchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAclchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Identity = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) + } + m.Permissions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAclchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Permissions |= ACLChangeUserPermissions(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipAclchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAclchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAclchanges(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAclchanges + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAclchanges + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAclchanges + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAclchanges + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAclchanges + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAclchanges + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAclchanges = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAclchanges = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAclchanges = fmt.Errorf("proto: unexpected end of group") +) diff --git a/aclchanges/pb/protos/aclchanges.proto b/aclchanges/pb/protos/aclchanges.proto new file mode 100644 index 00000000..d62b5088 --- /dev/null +++ b/aclchanges/pb/protos/aclchanges.proto @@ -0,0 +1,105 @@ +syntax = "proto3"; +package anytype; +option go_package = "pb"; + +// the element of change tree used to store and internal apply smartBlock history +message ACLChange { + repeated string treeHeadIds = 1; + repeated string aclHeadIds = 2; + string snapshotBaseId = 3; // we will only have one base snapshot for both + ACLData aclData = 4; + // the data is encoded with read key and should be read in ChangesData format + bytes changesData = 5; + uint64 currentReadKeyHash = 6; + int64 timestamp = 7; + string identity = 8; + + message ACLContentValue { + oneof value { + UserAdd userAdd = 1; + UserRemove userRemove = 2; + UserPermissionChange userPermissionChange = 3; + UserInvite userInvite = 4; + UserJoin userJoin = 5; + UserConfirm userConfirm = 6; + } + } + + message ACLData { + ACLSnapshot aclSnapshot = 1; + repeated ACLContentValue aclContent = 2; + } + + message ACLSnapshot { + // We don't need ACLState as a separate message now, because we simplified the snapshot model + ACLState aclState = 1; + } + + message ACLState { + repeated uint64 readKeyHashes = 1; + repeated UserState userStates = 2; + map invites = 3; // TODO: later + // repeated string unconfirmedUsers = 4; // TODO: later + } + + message UserState { + string identity = 1; + bytes encryptionKey = 2; + repeated bytes encryptedReadKeys = 3; // all read keys that we know + UserPermissions permissions = 4; + bool IsConfirmed = 5; + } + + // we already know identity and encryptionKey + message UserAdd { + string identity = 1; // public signing key + bytes encryptionKey = 2; // public encryption key + repeated bytes encryptedReadKeys = 3; // all read keys that we know for the user + UserPermissions permissions = 4; + } + + // TODO: this is not used as of now + message UserConfirm { // not needed for read permissions + string identity = 1; // not needed + string userAddId = 2; + } + + message UserInvite { + bytes acceptPublicKey = 1; + bytes encryptPublicKey = 2; + repeated bytes encryptedReadKeys = 3; // all read keys that we know for the user + UserPermissions permissions = 4; + string InviteId = 5; + } + + message UserJoin { + string identity = 1; + bytes encryptionKey = 2; + bytes acceptSignature = 3; // sign acceptPublicKey + string userInviteId = 4; + repeated bytes encryptedReadKeys = 5; // the idea is that user should itself reencrypt the keys with the pub key + } + + message UserRemove { + string identity = 1; + repeated ReadKeyReplace readKeyReplaces = 3; // new read key encrypted for all users + } + + message ReadKeyReplace { + string identity = 1; + bytes encryptionKey = 2; + bytes encryptedReadKey = 3; + } + + message UserPermissionChange { + string identity = 1; + UserPermissions permissions = 2; + } + + enum UserPermissions { + Admin = 0; + Writer = 1; + Reader = 2; + Removed = 3; + } +} diff --git a/acltree/aclstate.go b/acltree/aclstate.go new file mode 100644 index 00000000..9f9a5347 --- /dev/null +++ b/acltree/aclstate.go @@ -0,0 +1,411 @@ +package acltree + +import ( + "bytes" + "errors" + "fmt" + "hash/fnv" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" + "github.com/textileio/go-threads/crypto/symmetric" +) + +var ErrNoSuchUser = errors.New("no such user") +var ErrFailedToDecrypt = errors.New("failed to decrypt key") +var ErrUserRemoved = errors.New("user was removed from the document") +var ErrDocumentForbidden = errors.New("your user was forbidden access to the document") +var ErrUserAlreadyExists = errors.New("user already exists") + +type ACLState struct { + currentReadKeyHash uint64 + userReadKeys map[uint64]*symmetric.Key + userStates map[string]*pb.ACLChangeUserState + userInvites map[string]*pb.ACLChangeUserInvite + signingPubKeyDecoder keys.SigningPubKeyDecoder + encryptionKey keys.EncryptionPrivKey + identity string +} + +func newACLState( + identity string, + encryptionKey keys.EncryptionPrivKey, + signingPubKeyDecoder keys.SigningPubKeyDecoder) *ACLState { + return &ACLState{ + identity: identity, + encryptionKey: encryptionKey, + userReadKeys: make(map[uint64]*symmetric.Key), + userStates: make(map[string]*pb.ACLChangeUserState), + userInvites: make(map[string]*pb.ACLChangeUserInvite), + signingPubKeyDecoder: signingPubKeyDecoder, + } +} + +func newACLStateFromSnapshotChange( + snapshotChange *pb.ACLChange, + identity string, + encryptionKey keys.EncryptionPrivKey, + signingPubKeyDecoder keys.SigningPubKeyDecoder) (*ACLState, error) { + st := &ACLState{ + identity: identity, + encryptionKey: encryptionKey, + userReadKeys: make(map[uint64]*symmetric.Key), + userStates: make(map[string]*pb.ACLChangeUserState), + userInvites: make(map[string]*pb.ACLChangeUserInvite), + signingPubKeyDecoder: signingPubKeyDecoder, + } + err := st.recreateFromSnapshotChange(snapshotChange) + if err != nil { + return nil, err + } + return st, nil +} + +func (st *ACLState) recreateFromSnapshotChange(snapshotChange *pb.ACLChange) error { + snapshot := snapshotChange.GetAclData().GetAclSnapshot() + if snapshot == nil { + return fmt.Errorf("could not create state from snapshot, because it is nil") + } + state := snapshot.AclState + for _, userState := range state.UserStates { + st.userStates[userState.Identity] = userState + } + + userState, exists := st.userStates[st.identity] + if !exists { + return ErrNoSuchUser + } + for _, key := range userState.EncryptedReadKeys { + key, hash, err := st.decryptReadKeyAndHash(key) + if err != nil { + return ErrFailedToDecrypt + } + + st.userReadKeys[hash] = key + } + st.currentReadKeyHash = snapshotChange.CurrentReadKeyHash + if snapshot.GetAclState().GetInvites() != nil { + st.userInvites = snapshot.GetAclState().GetInvites() + } + return nil +} + +func (st *ACLState) makeSnapshot() *pb.ACLChangeACLSnapshot { + var userStates []*pb.ACLChangeUserState + for _, st := range st.userStates { + userStates = append(userStates, st) + } + + return &pb.ACLChangeACLSnapshot{AclState: &pb.ACLChangeACLState{ + ReadKeyHashes: nil, + UserStates: userStates, // TODO: make states and invites in same format + Invites: st.userInvites, + }} +} + +func (st *ACLState) applyChange(change *pb.ACLChange) (err error) { + defer func() { + if err != nil { + return + } + st.currentReadKeyHash = change.CurrentReadKeyHash + }() + + // we can't check this for the user which is joining, because it will not be in our list + // the same is for the first change to be added + skipIdentityCheck := st.isUserJoin(change) || (st.currentReadKeyHash == 0 && st.isUserAdd(change)) + if !skipIdentityCheck { + // we check signature when we add this to the Tree, so no need to do it here + if _, exists := st.userStates[change.Identity]; !exists { + err = ErrNoSuchUser + return + } + + if !st.hasPermission(change.Identity, pb.ACLChange_Admin) { + err = fmt.Errorf("user %s must have admin permissions", change.Identity) + return + } + } + + for _, ch := range change.GetAclData().GetAclContent() { + if err = st.applyChangeContent(ch); err != nil { + //log.Infof("error while applying changes: %v; ignore", err) + return err + } + } + + return nil +} + +// TODO: remove changeId, because it is not needed +func (st *ACLState) applyChangeContent(ch *pb.ACLChangeACLContentValue) error { + switch { + case ch.GetUserPermissionChange() != nil: + return st.applyUserPermissionChange(ch.GetUserPermissionChange()) + case ch.GetUserAdd() != nil: + return st.applyUserAdd(ch.GetUserAdd()) + case ch.GetUserRemove() != nil: + return st.applyUserRemove(ch.GetUserRemove()) + case ch.GetUserInvite() != nil: + return st.applyUserInvite(ch.GetUserInvite()) + case ch.GetUserJoin() != nil: + return st.applyUserJoin(ch.GetUserJoin()) + case ch.GetUserConfirm() != nil: + return st.applyUserConfirm(ch.GetUserConfirm()) + default: + return fmt.Errorf("unexpected change type: %v", ch) + } +} + +func (st *ACLState) applyUserPermissionChange(ch *pb.ACLChangeUserPermissionChange) error { + if _, exists := st.userStates[ch.Identity]; !exists { + return ErrNoSuchUser + } + + st.userStates[ch.Identity].Permissions = ch.Permissions + return nil +} + +func (st *ACLState) applyUserInvite(ch *pb.ACLChangeUserInvite) error { + st.userInvites[ch.InviteId] = ch + return nil +} + +func (st *ACLState) applyUserJoin(ch *pb.ACLChangeUserJoin) error { + invite, exists := st.userInvites[ch.UserInviteId] + if !exists { + return fmt.Errorf("no such invite with id %s", ch.UserInviteId) + } + + if _, exists = st.userStates[ch.Identity]; exists { + return ErrUserAlreadyExists + } + + // validating signature + signature := ch.GetAcceptSignature() + verificationKey, err := st.signingPubKeyDecoder.DecodeFromBytes(invite.AcceptPublicKey) + if err != nil { + return fmt.Errorf("public key verifying invite accepts is given in incorrect format: %v", err) + } + + rawSignedId, err := st.signingPubKeyDecoder.DecodeFromStringIntoBytes(ch.Identity) + if err != nil { + return fmt.Errorf("failed to decode signing identity as bytes") + } + + res, err := verificationKey.Verify(rawSignedId, signature) + if err != nil { + return fmt.Errorf("verification returned error: %w", err) + } + if !res { + return fmt.Errorf("signature is invalid") + } + + // if ourselves -> we need to decrypt the read keys + if st.identity == ch.Identity { + for _, key := range ch.EncryptedReadKeys { + key, hash, err := st.decryptReadKeyAndHash(key) + if err != nil { + return ErrFailedToDecrypt + } + + st.userReadKeys[hash] = key + } + } + + // adding user to the list + userState := &pb.ACLChangeUserState{ + Identity: ch.Identity, + EncryptionKey: ch.EncryptionKey, + EncryptedReadKeys: ch.EncryptedReadKeys, + Permissions: invite.Permissions, + IsConfirmed: true, + } + st.userStates[ch.Identity] = userState + return nil +} + +func (st *ACLState) applyUserAdd(ch *pb.ACLChangeUserAdd) error { + if _, exists := st.userStates[ch.Identity]; exists { + return ErrUserAlreadyExists + } + + st.userStates[ch.Identity] = &pb.ACLChangeUserState{ + Identity: ch.Identity, + EncryptionKey: ch.EncryptionKey, + Permissions: ch.Permissions, + EncryptedReadKeys: ch.EncryptedReadKeys, + } + + if ch.Identity == st.identity { + for _, key := range ch.EncryptedReadKeys { + key, hash, err := st.decryptReadKeyAndHash(key) + if err != nil { + return ErrFailedToDecrypt + } + + st.userReadKeys[hash] = key + } + } + + return nil +} + +func (st *ACLState) applyUserRemove(ch *pb.ACLChangeUserRemove) error { + if ch.Identity == st.identity { + return ErrDocumentForbidden + } + + if _, exists := st.userStates[ch.Identity]; !exists { + return ErrNoSuchUser + } + + delete(st.userStates, ch.Identity) + + for _, replace := range ch.ReadKeyReplaces { + userState, exists := st.userStates[replace.Identity] + if !exists { + continue + } + + userState.EncryptedReadKeys = append(userState.EncryptedReadKeys, replace.EncryptedReadKey) + // if this is our identity then we have to decrypt the key + if replace.Identity == st.identity { + key, hash, err := st.decryptReadKeyAndHash(replace.EncryptedReadKey) + if err != nil { + return ErrFailedToDecrypt + } + + st.currentReadKeyHash = hash + st.userReadKeys[st.currentReadKeyHash] = key + } + } + return nil +} + +func (st *ACLState) applyUserConfirm(ch *pb.ACLChangeUserConfirm) error { + if _, exists := st.userStates[ch.Identity]; !exists { + return ErrNoSuchUser + } + + userState := st.userStates[ch.Identity] + userState.IsConfirmed = true + return nil +} + +func (st *ACLState) decryptReadKeyAndHash(msg []byte) (*symmetric.Key, uint64, error) { + decrypted, err := st.encryptionKey.Decrypt(msg) + if err != nil { + return nil, 0, ErrFailedToDecrypt + } + + key, err := symmetric.FromBytes(decrypted) + if err != nil { + return nil, 0, ErrFailedToDecrypt + } + + hasher := fnv.New64() + hasher.Write(decrypted) + return key, hasher.Sum64(), nil +} + +func (st *ACLState) hasPermission(identity string, permission pb.ACLChangeUserPermissions) bool { + state, exists := st.userStates[identity] + if !exists { + return false + } + + return state.Permissions == permission +} + +func (st *ACLState) isUserJoin(ch *pb.ACLChange) bool { + // if we have a UserJoin, then it should always be the first one applied + return ch.AclData.GetAclContent() != nil && ch.AclData.GetAclContent()[0].GetUserJoin() != nil +} + +func (st *ACLState) isUserAdd(ch *pb.ACLChange) bool { + // if we have a UserAdd, then it should always be the first one applied + userAdd := ch.AclData.GetAclContent()[0].GetUserAdd() + return ch.AclData.GetAclContent() != nil && userAdd != nil && userAdd.GetIdentity() == ch.Identity +} + +func (st *ACLState) getPermissionDecreasedUsers(ch *pb.ACLChange) (identities []*pb.ACLChangeUserPermissionChange) { + // this should be called after general checks are completed + if ch.GetAclData().GetAclContent() == nil { + return nil + } + + contents := ch.GetAclData().GetAclContent() + for _, c := range contents { + if c.GetUserPermissionChange() != nil { + content := c.GetUserPermissionChange() + + currentState := st.userStates[content.Identity] + // the comparison works in different direction :-) + if content.Permissions > currentState.Permissions { + identities = append(identities, &pb.ACLChangeUserPermissionChange{ + Identity: content.Identity, + Permissions: content.Permissions, + }) + } + } + if c.GetUserRemove() != nil { + content := c.GetUserRemove() + identities = append(identities, &pb.ACLChangeUserPermissionChange{ + Identity: content.Identity, + Permissions: pb.ACLChange_Removed, + }) + } + } + + return identities +} + +func (st *ACLState) equal(other *ACLState) bool { + if st == nil && other == nil { + return true + } + + if st == nil || other == nil { + return false + } + + if st.currentReadKeyHash != other.currentReadKeyHash { + return false + } + + if st.identity != other.identity { + return false + } + + if len(st.userStates) != len(other.userStates) { + return false + } + + for _, st := range st.userStates { + otherSt, exists := other.userStates[st.Identity] + if !exists { + return false + } + + if st.Permissions != otherSt.Permissions { + return false + } + + if bytes.Compare(st.EncryptionKey, otherSt.EncryptionKey) != 0 { + return false + } + } + + if len(st.userInvites) != len(other.userInvites) { + return false + } + + // TODO: add detailed user invites comparison + compare other stuff + return true +} + +func (st *ACLState) GetUserStates() map[string]*pb.ACLChangeUserState { + // TODO: we should provide better API that would not allow to change this map from the outside + return st.userStates +} diff --git a/acltree/aclstatebuilder.go b/acltree/aclstatebuilder.go new file mode 100644 index 00000000..7774d9c5 --- /dev/null +++ b/acltree/aclstatebuilder.go @@ -0,0 +1,186 @@ +package acltree + +import ( + "fmt" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" +) + +type aclStateBuilder struct { + tree *Tree + identity string + key keys.EncryptionPrivKey + decoder keys.SigningPubKeyDecoder +} + +type decreasedPermissionsParameters struct { + users []*pb.ACLChangeUserPermissionChange + startChange string +} + +func newACLStateBuilder(decoder keys.SigningPubKeyDecoder, accountData *account.AccountData) *aclStateBuilder { + return &aclStateBuilder{ + decoder: decoder, + identity: accountData.Identity, + key: accountData.EncKey, + } +} + +func (sb *aclStateBuilder) Init(tree *Tree) error { + sb.tree = tree + return nil +} + +func (sb *aclStateBuilder) Build() (*ACLState, error) { + state, _, err := sb.BuildBefore("") + return state, err +} + +// TODO: we can probably have only one state builder, because we can Build both at the same time +func (sb *aclStateBuilder) BuildBefore(beforeId string) (*ACLState, bool, error) { + var ( + err error + startChange = sb.tree.root + foundId bool + idSeenMap = make(map[string][]*Change) + decreasedPermissions *decreasedPermissionsParameters + ) + root := sb.tree.Root() + if !root.IsSnapshot { + return nil, false, fmt.Errorf("root should always be a snapshot") + } + + state, err := newACLStateFromSnapshotChange( + root.Content, + sb.identity, + sb.key, + sb.decoder) + if err != nil { + return nil, false, fmt.Errorf("could not build ACLState from snapshot: %w", err) + } + + idSeenMap[startChange.Content.Identity] = append(idSeenMap[startChange.Content.Identity], startChange) + + if startChange.Content.GetChangesData() != nil { + key, exists := state.userReadKeys[startChange.Content.CurrentReadKeyHash] + if !exists { + return nil, false, fmt.Errorf("no first snapshot") + } + + err = startChange.DecryptContents(key) + if err != nil { + return nil, false, fmt.Errorf("failed to decrypt contents of first snapshot") + } + } + + if beforeId == startChange.Id { + return state, true, nil + } + + for { + // TODO: we should optimize this method to just remember last state of iterator and not iterate from the start and skip if nothing was removed from the Tree + sb.tree.IterateSkip(sb.tree.root.Id, startChange.Id, func(c *Change) (isContinue bool) { + defer func() { + if err == nil { + startChange = c + } else if err != ErrDocumentForbidden { + //log.Errorf("marking change %s as invalid: %v", c.Id, err) + sb.tree.RemoveInvalidChange(c.Id) + } + }() + + // not applying root change + if c.Id == startChange.Id { + return true + } + + idSeenMap[c.Content.Identity] = append(idSeenMap[c.Content.Identity], c) + if c.Content.GetAclData() != nil { + err = state.applyChange(c.Content) + if err != nil { + return false + } + + // if we have some users who have less permissions now + users := state.getPermissionDecreasedUsers(c.Content) + if len(users) > 0 { + decreasedPermissions = &decreasedPermissionsParameters{ + users: users, + startChange: c.Id, + } + return false + } + } + + // the user can't make changes + if !state.hasPermission(c.Content.Identity, pb.ACLChange_Writer) && !state.hasPermission(c.Content.Identity, pb.ACLChange_Admin) { + err = fmt.Errorf("user %s cannot make changes", c.Content.Identity) + return false + } + + // decrypting contents on the fly + if c.Content.GetChangesData() != nil { + key, exists := state.userReadKeys[c.Content.CurrentReadKeyHash] + if !exists { + err = fmt.Errorf("failed to find key with hash: %d", c.Content.CurrentReadKeyHash) + return false + } + + err = c.DecryptContents(key) + if err != nil { + err = fmt.Errorf("failed to decrypt contents for hash: %d", c.Content.CurrentReadKeyHash) + return false + } + } + + if c.Id == beforeId { + foundId = true + return false + } + + return true + }) + + // if we have users with decreased permissions + if decreasedPermissions != nil { + var removed bool + validChanges := sb.tree.dfs(decreasedPermissions.startChange) + + for _, permChange := range decreasedPermissions.users { + seenChanges := idSeenMap[permChange.Identity] + + for _, seen := range seenChanges { + // if we find some invalid changes + if _, exists := validChanges[seen.Id]; !exists { + // if the user didn't have enough permission to make changes + if seen.IsACLChange() || permChange.Permissions > pb.ACLChange_Writer { + removed = true + sb.tree.RemoveInvalidChange(seen.Id) + } + } + } + } + + decreasedPermissions = nil + if removed { + // starting from the beginning but with updated Tree + return sb.BuildBefore(beforeId) + } + } else if err == nil { + // we can finish the acl state building process + break + } + + // the user is forbidden to access the document + if err == ErrDocumentForbidden { + return nil, foundId, err + } + + // otherwise we have to continue from the change which we had + err = nil + } + + return state, foundId, err +} diff --git a/acltree/acltree.go b/acltree/acltree.go new file mode 100644 index 00000000..82aa688c --- /dev/null +++ b/acltree/acltree.go @@ -0,0 +1,325 @@ +package acltree + +import ( + "sync" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" +) + +type AddResultSummary int + +const ( + AddResultSummaryNothing AddResultSummary = iota + AddResultSummaryAppend + AddResultSummaryRebuild +) + +type AddResult struct { + OldHeads []string + Heads []string + // TODO: add summary for changes + Summary AddResultSummary +} + +type TreeUpdateListener interface { + Update(tree ACLTree) + Rebuild(tree ACLTree) +} + +type ACLTree interface { + ACLState() *ACLState + AddContent(f func(builder ChangeBuilder) error) (*Change, error) + AddChanges(changes ...*Change) (AddResult, error) + Heads() []string + Root() *Change + Iterate(func(change *Change) bool) + IterateFrom(string, func(change *Change) bool) + HasChange(string) bool +} + +type aclTree struct { + thread thread.Thread + accountData *account.AccountData + updateListener TreeUpdateListener + + fullTree *Tree + aclTreeFromStart *Tree // TODO: right now we don't use it, we can probably have only local var for now. This tree is built from start of the document + aclState *ACLState + + treeBuilder *treeBuilder + aclTreeBuilder *aclTreeBuilder + aclStateBuilder *aclStateBuilder + snapshotValidator *snapshotValidator + changeBuilder *changeBuilder + + sync.RWMutex +} + +func BuildACLTree( + t thread.Thread, + acc *account.AccountData, + listener TreeUpdateListener) (ACLTree, error) { + decoder := keys.NewEd25519Decoder() + aclTreeBuilder := newACLTreeBuilder(t, decoder) + treeBuilder := newTreeBuilder(t, decoder) + snapshotValidator := newSnapshotValidator(decoder, acc) + aclStateBuilder := newACLStateBuilder(decoder, acc) + changeBuilder := newChangeBuilder() + + aclTree := &aclTree{ + thread: t, + accountData: acc, + fullTree: nil, + aclState: nil, + treeBuilder: treeBuilder, + aclTreeBuilder: aclTreeBuilder, + aclStateBuilder: aclStateBuilder, + snapshotValidator: snapshotValidator, + changeBuilder: changeBuilder, + updateListener: listener, + } + err := aclTree.rebuildFromThread(false) + if err != nil { + return nil, err + } + aclTree.removeOrphans() + t.SetHeads(aclTree.Heads()) + listener.Rebuild(aclTree) + + return aclTree, nil +} + +// TODO: this is not used for now, in future we should think about not making full tree rebuild +//func (a *aclTree) rebuildFromTree(validateSnapshot bool) (err error) { +// if validateSnapshot { +// err = a.snapshotValidator.Init(a.aclTreeFromStart) +// if err != nil { +// return err +// } +// +// valid, err := a.snapshotValidator.ValidateSnapshot(a.fullTree.root) +// if err != nil { +// return err +// } +// if !valid { +// return a.rebuildFromThread(true) +// } +// } +// +// err = a.aclStateBuilder.Init(a.fullTree) +// if err != nil { +// return err +// } +// +// a.aclState, err = a.aclStateBuilder.Build() +// if err != nil { +// return err +// } +// +// return nil +//} + +func (a *aclTree) removeOrphans() { + // removing attached or invalid orphans + var toRemove []string + + for _, orphan := range a.thread.Orphans() { + if _, exists := a.fullTree.attached[orphan]; exists { + toRemove = append(toRemove, orphan) + } + if _, exists := a.fullTree.invalidChanges[orphan]; exists { + toRemove = append(toRemove, orphan) + } + } + a.thread.RemoveOrphans(toRemove...) +} + +func (a *aclTree) rebuildFromThread(fromStart bool) error { + a.treeBuilder.Init() + a.aclTreeBuilder.Init() + + var err error + a.fullTree, err = a.treeBuilder.Build(fromStart) + if err != nil { + return err + } + + // TODO: remove this from context as this is used only to validate snapshot + a.aclTreeFromStart, err = a.aclTreeBuilder.Build() + if err != nil { + return err + } + + if !fromStart { + err = a.snapshotValidator.Init(a.aclTreeFromStart) + if err != nil { + return err + } + + valid, err := a.snapshotValidator.ValidateSnapshot(a.fullTree.root) + if err != nil { + return err + } + if !valid { + return a.rebuildFromThread(true) + } + } + // TODO: there is a question how we can validate not only that the full tree is built correctly + // but also that the ACL prev ids are not messed up. I think we should probably compare the resulting + // acl state with the acl state which is built in aclTreeFromStart + + err = a.aclStateBuilder.Init(a.fullTree) + if err != nil { + return err + } + + a.aclState, err = a.aclStateBuilder.Build() + if err != nil { + return err + } + + return nil +} + +func (a *aclTree) ACLState() *ACLState { + a.RLock() + defer a.RUnlock() + return a.aclState +} + +func (a *aclTree) AddContent(build func(builder ChangeBuilder) error) (*Change, error) { + // TODO: add snapshot creation logic + a.Lock() + defer func() { + a.Unlock() + // TODO: should this be called in a separate goroutine to prevent accidental cycles (tree->updater->tree) + a.updateListener.Update(a) + }() + + a.changeBuilder.Init(a.aclState, a.fullTree, a.accountData) + err := build(a.changeBuilder) + if err != nil { + return nil, err + } + + ch, marshalled, err := a.changeBuilder.BuildAndApply() + if err != nil { + return nil, err + } + a.fullTree.AddFast(ch) + + err = a.thread.AddRawChange(&thread.RawChange{ + Payload: marshalled, + Signature: ch.Signature(), + Id: ch.Id, + }) + if err != nil { + return nil, err + } + + a.thread.SetHeads([]string{ch.Id}) + return ch, nil +} + +func (a *aclTree) AddChanges(changes ...*Change) (AddResult, error) { + a.Lock() + // TODO: make proper error handling, because there are a lot of corner cases where this will break + var err error + var mode Mode + + defer func() { + if err != nil { + return + } + a.removeOrphans() + a.thread.SetHeads(a.fullTree.Heads()) + a.Unlock() + switch mode { + case Append: + a.updateListener.Update(a) + case Rebuild: + a.updateListener.Rebuild(a) + default: + break + } + }() + + for _, ch := range changes { + err = a.thread.AddChange(ch) + if err != nil { + return AddResult{}, err + } + a.thread.AddOrphans(ch.Id) + } + + prevHeads := a.fullTree.Heads() + mode = a.fullTree.Add(changes...) + switch mode { + case Nothing: + return AddResult{ + OldHeads: prevHeads, + Heads: prevHeads, + Summary: AddResultSummaryNothing, + }, nil + + case Rebuild: + err = a.rebuildFromThread(false) + if err != nil { + return AddResult{}, err + } + + return AddResult{ + OldHeads: prevHeads, + Heads: a.fullTree.Heads(), + Summary: AddResultSummaryRebuild, + }, nil + default: + // just rebuilding the state from start without reloading everything from thread + // as an optimization we could've started from current heads, but I didn't implement that + a.aclState, err = a.aclStateBuilder.Build() + if err != nil { + return AddResult{}, err + } + + return AddResult{ + OldHeads: prevHeads, + Heads: a.fullTree.Heads(), + Summary: AddResultSummaryAppend, + }, nil + } +} + +func (a *aclTree) Iterate(f func(change *Change) bool) { + a.RLock() + defer a.RUnlock() + a.fullTree.Iterate(a.fullTree.RootId(), f) +} + +func (a *aclTree) IterateFrom(s string, f func(change *Change) bool) { + a.RLock() + defer a.RUnlock() + a.fullTree.Iterate(s, f) +} + +func (a *aclTree) HasChange(s string) bool { + a.RLock() + defer a.RUnlock() + _, attachedExists := a.fullTree.attached[s] + _, unattachedExists := a.fullTree.unAttached[s] + _, invalidExists := a.fullTree.invalidChanges[s] + return attachedExists || unattachedExists || invalidExists +} + +func (a *aclTree) Heads() []string { + a.RLock() + defer a.RUnlock() + return a.fullTree.Heads() +} + +func (a *aclTree) Root() *Change { + a.RLock() + defer a.RUnlock() + return a.fullTree.Root() +} diff --git a/acltree/acltree_test.go b/acltree/acltree_test.go new file mode 100644 index 00000000..8039e0b8 --- /dev/null +++ b/acltree/acltree_test.go @@ -0,0 +1,271 @@ +package acltree + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/threadbuilder" +) + +type mockListener struct{} + +func (m *mockListener) Update(tree ACLTree) {} + +func (m *mockListener) Rebuild(tree ACLTree) {} + +func TestACLTree_UserJoinBuild(t *testing.T) { + thr, err := threadbuilder.NewThreadBuilderWithTestName("userjoinexample.yml") + if err != nil { + t.Fatal(err) + } + keychain := thr.GetKeychain() + accountData := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + listener := &mockListener{} + tree, err := BuildACLTree(thr, accountData, listener) + if err != nil { + t.Fatalf("should Build acl ACLState without err: %v", err) + } + aclState := tree.ACLState() + aId := keychain.GeneratedIdentities["A"] + bId := keychain.GeneratedIdentities["B"] + cId := keychain.GeneratedIdentities["C"] + + assert.Equal(t, aclState.identity, aId) + assert.Equal(t, aclState.userStates[aId].Permissions, pb.ACLChange_Admin) + assert.Equal(t, aclState.userStates[bId].Permissions, pb.ACLChange_Writer) + assert.Equal(t, aclState.userStates[cId].Permissions, pb.ACLChange_Reader) + + var changeIds []string + tree.Iterate(func(c *Change) (isContinue bool) { + changeIds = append(changeIds, c.Id) + return true + }) + assert.Equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "B.1.2"}) +} + +func TestACLTree_UserJoinUpdate_Append(t *testing.T) { + thr, err := threadbuilder.NewThreadBuilderWithTestName("userjoinexampleupdate.yml") + if err != nil { + t.Fatal(err) + } + keychain := thr.GetKeychain() + accountData := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + listener := &mockListener{} + tree, err := BuildACLTree(thr, accountData, listener) + if err != nil { + t.Fatalf("should Build acl ACLState without err: %v", err) + } + rawChanges := thr.GetUpdates("append") + var changes []*Change + for _, ch := range rawChanges { + newCh, err := NewFromRawChange(ch) + if err != nil { + t.Fatalf("should be able to create change from raw: %v", err) + } + changes = append(changes, newCh) + } + + res, err := tree.AddChanges(changes...) + assert.Equal(t, res.Summary, AddResultSummaryAppend) + + aclState := tree.ACLState() + aId := keychain.GeneratedIdentities["A"] + bId := keychain.GeneratedIdentities["B"] + cId := keychain.GeneratedIdentities["C"] + dId := keychain.GeneratedIdentities["D"] + + assert.Equal(t, aclState.identity, aId) + assert.Equal(t, aclState.userStates[aId].Permissions, pb.ACLChange_Admin) + assert.Equal(t, aclState.userStates[bId].Permissions, pb.ACLChange_Writer) + assert.Equal(t, aclState.userStates[cId].Permissions, pb.ACLChange_Reader) + assert.Equal(t, aclState.userStates[dId].Permissions, pb.ACLChange_Writer) + + var changeIds []string + tree.Iterate(func(c *Change) (isContinue bool) { + changeIds = append(changeIds, c.Id) + return true + }) + assert.Equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "B.1.2", "B.1.3", "A.1.4"}) +} + +func TestACLTree_UserJoinUpdate_Rebuild(t *testing.T) { + thr, err := threadbuilder.NewThreadBuilderWithTestName("userjoinexampleupdate.yml") + if err != nil { + t.Fatal(err) + } + keychain := thr.GetKeychain() + accountData := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + listener := &mockListener{} + tree, err := BuildACLTree(thr, accountData, listener) + if err != nil { + t.Fatalf("should Build acl ACLState without err: %v", err) + } + rawChanges := thr.GetUpdates("rebuild") + var changes []*Change + for _, ch := range rawChanges { + newCh, err := NewFromRawChange(ch) + if err != nil { + t.Fatalf("should be able to create change from raw: %v", err) + } + changes = append(changes, newCh) + } + + res, err := tree.AddChanges(changes...) + assert.Equal(t, res.Summary, AddResultSummaryRebuild) + + aclState := tree.ACLState() + aId := keychain.GeneratedIdentities["A"] + bId := keychain.GeneratedIdentities["B"] + cId := keychain.GeneratedIdentities["C"] + dId := keychain.GeneratedIdentities["D"] + + assert.Equal(t, aclState.identity, aId) + assert.Equal(t, aclState.userStates[aId].Permissions, pb.ACLChange_Admin) + assert.Equal(t, aclState.userStates[bId].Permissions, pb.ACLChange_Writer) + assert.Equal(t, aclState.userStates[cId].Permissions, pb.ACLChange_Reader) + assert.Equal(t, aclState.userStates[dId].Permissions, pb.ACLChange_Writer) + + var changeIds []string + + tree.Iterate(func(c *Change) (isContinue bool) { + changeIds = append(changeIds, c.Id) + return true + }) + assert.Equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "B.1.2", "A.1.4"}) +} + +func TestACLTree_UserRemoveBuild(t *testing.T) { + thr, err := threadbuilder.NewThreadBuilderWithTestName("userremoveexample.yml") + if err != nil { + t.Fatal(err) + } + keychain := thr.GetKeychain() + accountData := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + listener := &mockListener{} + tree, err := BuildACLTree(thr, accountData, listener) + if err != nil { + t.Fatalf("should Build acl ACLState without err: %v", err) + } + aclState := tree.ACLState() + aId := keychain.GeneratedIdentities["A"] + + assert.Equal(t, aclState.identity, aId) + assert.Equal(t, aclState.userStates[aId].Permissions, pb.ACLChange_Admin) + + var changeIds []string + tree.Iterate(func(c *Change) (isContinue bool) { + changeIds = append(changeIds, c.Id) + return true + }) + assert.Equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "A.1.3", "A.1.4"}) +} + +func TestACLTree_UserRemoveBeforeBuild(t *testing.T) { + thr, err := threadbuilder.NewThreadBuilderWithTestName("userremovebeforeexample.yml") + if err != nil { + t.Fatal(err) + } + keychain := thr.GetKeychain() + accountData := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + listener := &mockListener{} + tree, err := BuildACLTree(thr, accountData, listener) + if err != nil { + t.Fatalf("should Build acl ACLState without err: %v", err) + } + aclState := tree.ACLState() + for _, s := range []string{"A", "C", "E"} { + assert.Equal(t, aclState.userStates[keychain.GetIdentity(s)].Permissions, pb.ACLChange_Admin) + } + assert.Equal(t, aclState.identity, keychain.GetIdentity("A")) + assert.Nil(t, aclState.userStates[keychain.GetIdentity("B")]) + + var changeIds []string + tree.Iterate(func(c *Change) (isContinue bool) { + changeIds = append(changeIds, c.Id) + return true + }) + assert.Equal(t, changeIds, []string{"A.1.1", "B.1.1", "A.1.2", "A.1.3"}) +} + +func TestACLTree_InvalidSnapshotBuild(t *testing.T) { + thr, err := threadbuilder.NewThreadBuilderWithTestName("invalidsnapshotexample.yml") + if err != nil { + t.Fatal(err) + } + keychain := thr.GetKeychain() + accountData := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + listener := &mockListener{} + tree, err := BuildACLTree(thr, accountData, listener) + if err != nil { + t.Fatalf("should Build acl ACLState without err: %v", err) + } + aclState := tree.ACLState() + for _, s := range []string{"A", "B", "C", "D", "E", "F"} { + assert.Equal(t, aclState.userStates[keychain.GetIdentity(s)].Permissions, pb.ACLChange_Admin) + } + assert.Equal(t, aclState.identity, keychain.GetIdentity("A")) + + var changeIds []string + tree.Iterate(func(c *Change) (isContinue bool) { + changeIds = append(changeIds, c.Id) + return true + }) + assert.Equal(t, []string{"A.1.1", "B.1.1", "A.1.2", "A.1.3", "B.1.2"}, changeIds) +} + +func TestACLTree_ValidSnapshotBuild(t *testing.T) { + thr, err := threadbuilder.NewThreadBuilderWithTestName("validsnapshotexample.yml") + if err != nil { + t.Fatal(err) + } + keychain := thr.GetKeychain() + accountData := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + listener := &mockListener{} + tree, err := BuildACLTree(thr, accountData, listener) + if err != nil { + t.Fatalf("should Build acl ACLState without err: %v", err) + } + aclState := tree.ACLState() + for _, s := range []string{"A", "B", "C", "D", "E", "F"} { + assert.Equal(t, aclState.userStates[keychain.GetIdentity(s)].Permissions, pb.ACLChange_Admin) + } + assert.Equal(t, aclState.identity, keychain.GetIdentity("A")) + + var changeIds []string + tree.Iterate(func(c *Change) (isContinue bool) { + changeIds = append(changeIds, c.Id) + return true + }) + assert.Equal(t, []string{"A.1.2", "A.1.3", "B.1.2"}, changeIds) +} diff --git a/acltree/acltreebuilder.go b/acltree/acltreebuilder.go new file mode 100644 index 00000000..dfb855fe --- /dev/null +++ b/acltree/acltreebuilder.go @@ -0,0 +1,142 @@ +package acltree + +import ( + "fmt" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" +) + +type aclTreeBuilder struct { + cache map[string]*Change + identityKeys map[string]keys.SigningPubKey + signingPubKeyDecoder keys.SigningPubKeyDecoder + tree *Tree + thread thread.Thread + + *changeLoader +} + +func newACLTreeBuilder(t thread.Thread, decoder keys.SigningPubKeyDecoder) *aclTreeBuilder { + return &aclTreeBuilder{ + signingPubKeyDecoder: decoder, + thread: t, + changeLoader: newChangeLoader( + t, + decoder, + NewACLChange), + } +} + +func (tb *aclTreeBuilder) Init() { + tb.cache = make(map[string]*Change) + tb.identityKeys = make(map[string]keys.SigningPubKey) + tb.tree = &Tree{} + tb.changeLoader.Init(tb.cache, tb.identityKeys) +} + +func (tb *aclTreeBuilder) Build() (*Tree, error) { + var headsAndOrphans []string + headsAndOrphans = append(headsAndOrphans, tb.thread.Orphans()...) + headsAndOrphans = append(headsAndOrphans, tb.thread.Heads()...) + aclHeads, err := tb.getACLHeads(headsAndOrphans) + + if err != nil { + return nil, err + } + + if err = tb.buildTreeFromStart(aclHeads); err != nil { + return nil, fmt.Errorf("buildTree error: %v", err) + } + tb.cache = nil + + return tb.tree, nil +} + +func (tb *aclTreeBuilder) buildTreeFromStart(heads []string) (err error) { + changes, root, err := tb.dfsFromStart(heads) + if err != nil { + return err + } + + tb.tree.AddFast(root) + tb.tree.AddFast(changes...) + return +} + +func (tb *aclTreeBuilder) dfsFromStart(heads []string) (buf []*Change, root *Change, err error) { + var possibleRoots []*Change + stack := make([]string, len(heads), len(heads)*2) + copy(stack, heads) + + buf = make([]*Change, 0, len(stack)*2) + uniqMap := make(map[string]struct{}) + for len(stack) > 0 { + id := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if _, exists := uniqMap[id]; exists { + continue + } + + ch, err := tb.loadChange(id) + if err != nil { + continue + } + + uniqMap[id] = struct{}{} + buf = append(buf, ch) + + for _, prev := range ch.PreviousIds { + stack = append(stack, prev) + } + if len(ch.PreviousIds) == 0 { + possibleRoots = append(possibleRoots, ch) + } + } + header := tb.thread.Header() + for _, r := range possibleRoots { + if r.Id == header.FirstChangeId { + return buf, r, nil + } + } + + return nil, nil, fmt.Errorf("could not find root change") +} + +func (tb *aclTreeBuilder) getACLHeads(heads []string) (aclTreeHeads []string, err error) { + for _, head := range heads { + if slice.FindPos(aclTreeHeads, head) != -1 { // do not scan known heads + continue + } + precedingHeads, err := tb.getPrecedingACLHeads(head) + if err != nil { + continue + } + + for _, aclHead := range precedingHeads { + if slice.FindPos(aclTreeHeads, aclHead) != -1 { + continue + } + aclTreeHeads = append(aclTreeHeads, aclHead) + } + } + + if len(aclTreeHeads) == 0 { + return nil, fmt.Errorf("no usable ACL heads in thread") + } + return aclTreeHeads, nil +} + +func (tb *aclTreeBuilder) getPrecedingACLHeads(head string) ([]string, error) { + headChange, err := tb.loadChange(head) + if err != nil { + return nil, err + } + + if headChange.Content.GetAclData() != nil { + return []string{head}, nil + } else { + return headChange.PreviousIds, nil + } +} diff --git a/acltree/change.go b/acltree/change.go new file mode 100644 index 00000000..5f3121b3 --- /dev/null +++ b/acltree/change.go @@ -0,0 +1,98 @@ +package acltree + +import ( + "fmt" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/gogo/protobuf/proto" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + "github.com/textileio/go-threads/crypto/symmetric" +) + +type ChangeContent struct { + ChangesData proto.Marshaler + ACLData *pb.ACLChangeACLData + Id string // TODO: this is just for testing, because id should be created automatically from content +} + +// Change is an abstract type for all types of changes +type Change struct { + Next []*Change + Unattached []*Change + PreviousIds []string + Id string + SnapshotId string + IsSnapshot bool + DecryptedDocumentChange []byte + + Content *pb.ACLChange + Sign []byte +} + +func (ch *Change) DecryptContents(key *symmetric.Key) error { + if ch.Content.ChangesData == nil { + return nil + } + + decrypted, err := key.Decrypt(ch.Content.ChangesData) + if err != nil { + return fmt.Errorf("failed to decrypt changes data: %w", err) + } + + ch.DecryptedDocumentChange = decrypted + return nil +} + +func (ch *Change) IsACLChange() bool { + return ch.Content.GetAclData() != nil +} + +func NewFromRawChange(rawChange *thread.RawChange) (*Change, error) { + unmarshalled := &pb.ACLChange{} + err := proto.Unmarshal(rawChange.Payload, unmarshalled) + if err != nil { + return nil, err + } + + ch := NewChange(rawChange.Id, unmarshalled) + ch.Sign = rawChange.Signature + return ch, nil +} + +func NewChange(id string, ch *pb.ACLChange) *Change { + return &Change{ + Next: nil, + PreviousIds: ch.TreeHeadIds, + Id: id, + Content: ch, + SnapshotId: ch.SnapshotBaseId, + IsSnapshot: ch.GetAclData().GetAclSnapshot() != nil, + } +} + +func NewACLChange(id string, ch *pb.ACLChange) *Change { + return &Change{ + Next: nil, + PreviousIds: ch.AclHeadIds, + Id: id, + Content: ch, + SnapshotId: ch.SnapshotBaseId, + IsSnapshot: ch.GetAclData().GetAclSnapshot() != nil, + } +} + +func (ch *Change) ProtoChange() *pb.ACLChange { + return ch.Content +} + +func (ch *Change) DecryptedChangeContent() []byte { + return ch.DecryptedDocumentChange +} + +func (ch *Change) Signature() []byte { + return ch.Sign +} + +func (ch *Change) CID() string { + return ch.Id +} diff --git a/acltree/changebuilder.go b/acltree/changebuilder.go new file mode 100644 index 00000000..1c97397c --- /dev/null +++ b/acltree/changebuilder.go @@ -0,0 +1,163 @@ +package acltree + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" + "github.com/gogo/protobuf/proto" + "github.com/textileio/go-threads/crypto/symmetric" + "hash/fnv" + "time" +) + +type MarshalledChange = []byte + +type ACLChangeBuilder interface { + UserAdd(identity string, encryptionKey keys.EncryptionPubKey, permissions pb.ACLChangeUserPermissions) error + AddId(id string) // TODO: this is only for testing + SetMakeSnapshot(bool) // TODO: who should decide this? probably ACLTree so we can delete it +} + +type ChangeBuilder interface { + ACLChangeBuilder + AddChangeContent(marshaler proto.Marshaler) // user code should be responsible for making regular snapshots +} + +type changeBuilder struct { + aclState *ACLState + tree *Tree + acc *account.AccountData + + aclData *pb.ACLChangeACLData + changeContent proto.Marshaler + id string + makeSnapshot bool + readKey *symmetric.Key + readKeyHash uint64 +} + +func newChangeBuilder() *changeBuilder { + return &changeBuilder{} +} + +func (c *changeBuilder) Init(state *ACLState, tree *Tree, acc *account.AccountData) { + c.aclState = state + c.tree = tree + c.acc = acc + + c.aclData = &pb.ACLChangeACLData{} + // setting read key for further encryption etc + if state.currentReadKeyHash == 0 { + c.readKey, _ = symmetric.NewRandom() + + hasher := fnv.New64() + hasher.Write(c.readKey.Bytes()) + c.readKeyHash = hasher.Sum64() + } else { + c.readKey = c.aclState.userReadKeys[c.aclState.currentReadKeyHash] + c.readKeyHash = c.aclState.currentReadKeyHash + } +} + +func (c *changeBuilder) AddId(id string) { + c.id = id +} + +func (c *changeBuilder) SetMakeSnapshot(b bool) { + c.makeSnapshot = b +} + +func (c *changeBuilder) UserAdd(identity string, encryptionKey keys.EncryptionPubKey, permissions pb.ACLChangeUserPermissions) error { + var allKeys []*symmetric.Key + if c.aclState.currentReadKeyHash != 0 { + for _, key := range c.aclState.userReadKeys { + allKeys = append(allKeys, key) + } + } else { + allKeys = append(allKeys, c.readKey) + } + + var encryptedKeys [][]byte + for _, k := range allKeys { + res, err := encryptionKey.Encrypt(k.Bytes()) + if err != nil { + return err + } + + encryptedKeys = append(encryptedKeys, res) + } + rawKey, err := encryptionKey.Raw() + if err != nil { + return err + } + ch := &pb.ACLChangeACLContentValue{ + Value: &pb.ACLChangeACLContentValueValueOfUserAdd{ + UserAdd: &pb.ACLChangeUserAdd{ + Identity: identity, + EncryptionKey: rawKey, + EncryptedReadKeys: encryptedKeys, + Permissions: permissions, + }, + }, + } + c.aclData.AclContent = append(c.aclData.AclContent, ch) + return nil +} + +func (c *changeBuilder) BuildAndApply() (*Change, []byte, error) { + aclChange := &pb.ACLChange{ + TreeHeadIds: c.tree.Heads(), + AclHeadIds: c.tree.ACLHeads(), + SnapshotBaseId: c.tree.RootId(), + AclData: c.aclData, + CurrentReadKeyHash: c.readKeyHash, + Timestamp: int64(time.Now().Nanosecond()), + Identity: c.acc.Identity, + } + err := c.aclState.applyChange(aclChange) + if err != nil { + return nil, nil, err + } + + if c.makeSnapshot { + c.aclData.AclSnapshot = c.aclState.makeSnapshot() + } + + var marshalled []byte + if c.changeContent != nil { + marshalled, err = c.changeContent.Marshal() + if err != nil { + return nil, nil, err + } + + encrypted, err := c.aclState.userReadKeys[c.aclState.currentReadKeyHash]. + Encrypt(marshalled) + if err != nil { + return nil, nil, err + } + aclChange.ChangesData = encrypted + } + + fullMarshalledChange, err := proto.Marshal(aclChange) + if err != nil { + return nil, nil, err + } + signature, err := c.acc.SignKey.Sign(fullMarshalledChange) + if err != nil { + return nil, nil, err + } + id, err := cid.NewCIDFromBytes(fullMarshalledChange) + if err != nil { + return nil, nil, err + } + ch := NewChange(id, aclChange) + ch.DecryptedDocumentChange = marshalled + ch.Sign = signature + + return ch, fullMarshalledChange, nil +} + +func (c *changeBuilder) AddChangeContent(marshaler proto.Marshaler) { + c.changeContent = marshaler +} diff --git a/acltree/changeloader.go b/acltree/changeloader.go new file mode 100644 index 00000000..82c3df99 --- /dev/null +++ b/acltree/changeloader.go @@ -0,0 +1,93 @@ +package acltree + +import ( + "context" + "fmt" + "time" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" + "github.com/gogo/protobuf/proto" +) + +type changeLoader struct { + cache map[string]*Change + identityKeys map[string]keys.SigningPubKey + signingPubKeyDecoder keys.SigningPubKeyDecoder + thread thread.Thread + changeCreator func(id string, ch *pb.ACLChange) *Change +} + +func newChangeLoader( + thread thread.Thread, + signingPubKeyDecoder keys.SigningPubKeyDecoder, + changeCreator func(id string, ch *pb.ACLChange) *Change) *changeLoader { + return &changeLoader{ + signingPubKeyDecoder: signingPubKeyDecoder, + thread: thread, + changeCreator: changeCreator, + } +} + +func (c *changeLoader) Init(cache map[string]*Change, + identityKeys map[string]keys.SigningPubKey) { + c.cache = cache + c.identityKeys = identityKeys +} + +func (c *changeLoader) loadChange(id string) (ch *Change, err error) { + if ch, ok := c.cache[id]; ok { + return ch, nil + } + + // TODO: Add virtual changes logic + ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) + defer cancel() + + change, err := c.thread.GetChange(ctx, id) + if err != nil { + return nil, err + } + + aclChange, err := c.makeVerifiedACLChange(change) + if err != nil { + return nil, err + } + + ch = c.changeCreator(id, aclChange) + c.cache[id] = ch + + return ch, nil +} + +func (c *changeLoader) verify(identity string, payload, signature []byte) (isVerified bool, err error) { + identityKey, exists := c.identityKeys[identity] + if !exists { + identityKey, err = c.signingPubKeyDecoder.DecodeFromString(identity) + if err != nil { + return + } + c.identityKeys[identity] = identityKey + } + return identityKey.Verify(payload, signature) +} + +func (c *changeLoader) makeVerifiedACLChange(change *thread.RawChange) (aclChange *pb.ACLChange, err error) { + aclChange = new(pb.ACLChange) + + // TODO: think what should we do with such cases, because this can be used by attacker to break our Tree + if err = proto.Unmarshal(change.Payload, aclChange); err != nil { + return + } + var verified bool + verified, err = c.verify(aclChange.Identity, change.Payload, change.Signature) + if err != nil { + return + } + if !verified { + err = fmt.Errorf("the signature of the payload cannot be verified") + return + } + return +} diff --git a/acltree/snapshotvalidator.go b/acltree/snapshotvalidator.go new file mode 100644 index 00000000..f4479859 --- /dev/null +++ b/acltree/snapshotvalidator.go @@ -0,0 +1,50 @@ +package acltree + +import ( + "fmt" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" +) + +type snapshotValidator struct { + aclTree *Tree + identity string + key keys.EncryptionPrivKey + decoder keys.SigningPubKeyDecoder + stateBuilder *aclStateBuilder +} + +func newSnapshotValidator( + decoder keys.SigningPubKeyDecoder, + accountData *account.AccountData) *snapshotValidator { + return &snapshotValidator{ + identity: accountData.Identity, + key: accountData.EncKey, + decoder: decoder, + stateBuilder: newACLStateBuilder(decoder, accountData), + } +} + +func (s *snapshotValidator) Init(aclTree *Tree) error { + s.aclTree = aclTree + return s.stateBuilder.Init(aclTree) +} + +func (s *snapshotValidator) ValidateSnapshot(ch *Change) (bool, error) { + st, found, err := s.stateBuilder.BuildBefore(ch.Id) + if err != nil { + return false, err + } + + if !found { + return false, fmt.Errorf("didn't find snapshot in ACL Tree") + } + + otherSt, err := newACLStateFromSnapshotChange(ch.Content, s.identity, s.key, s.decoder) + if err != nil { + return false, err + } + + return st.equal(otherSt), nil +} diff --git a/acltree/threadutility.go b/acltree/threadutility.go new file mode 100644 index 00000000..034ea2fd --- /dev/null +++ b/acltree/threadutility.go @@ -0,0 +1,42 @@ +package acltree + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" +) + +func BuildThreadWithACL( + acc *account.AccountData, + build func(builder ChangeBuilder) error, + create func(change *thread.RawChange) (thread.Thread, error)) (thread.Thread, error) { + bld := newChangeBuilder() + bld.Init( + newACLState(acc.Identity, acc.EncKey, keys.NewEd25519Decoder()), + &Tree{}, + acc) + err := build(bld) + if err != nil { + return nil, err + } + bld.SetMakeSnapshot(true) + + change, payload, err := bld.BuildAndApply() + if err != nil { + return nil, err + } + + rawChange := &thread.RawChange{ + Payload: payload, + Signature: change.Signature(), + Id: change.CID(), + } + + thr, err := create(rawChange) + if err != nil { + return nil, err + } + + thr.SetHeads([]string{change.CID()}) + return thr, nil +} diff --git a/acltree/threadutility_test.go b/acltree/threadutility_test.go new file mode 100644 index 00000000..91258127 --- /dev/null +++ b/acltree/threadutility_test.go @@ -0,0 +1,51 @@ +package acltree + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/threadbuilder" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBuildThreadWithACL(t *testing.T) { + keychain := threadbuilder.NewKeychain() + keychain.AddSigningKey("A") + keychain.AddEncryptionKey("A") + data := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + thr, err := BuildThreadWithACL( + data, + func(builder ChangeBuilder) error { + return builder.UserAdd( + keychain.GetIdentity("A"), + keychain.EncryptionKeys["A"].GetPublic(), + pb.ACLChange_Admin) + }, + thread.NewInMemoryThread) + if err != nil { + t.Fatalf("build should not return error") + } + if len(thr.Heads()) == 0 { + t.Fatalf("thread should have non-empty heads") + } + if thr.Header() == nil { + t.Fatalf("thread should have non-empty header") + } + assert.Equal(t, thr.Heads()[0], thr.Header().FirstChangeId) + assert.NotEmpty(t, thr.ID()) + ch, err := thr.GetChange(context.Background(), thr.Header().FirstChangeId) + if err != nil { + t.Fatalf("get change should not return error: %v", err) + } + + _, err = NewFromRawChange(ch) + if err != nil { + t.Fatalf("we should be able to unmarshall change: %v", err) + } +} diff --git a/acltree/tree.go b/acltree/tree.go new file mode 100644 index 00000000..e47ed212 --- /dev/null +++ b/acltree/tree.go @@ -0,0 +1,416 @@ +package acltree + +import ( + "bytes" + "crypto/md5" + "fmt" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" + "sort" +) + +type Mode int + +const ( + Append Mode = iota + Rebuild + Nothing +) + +// TODO: consider abstracting into separate package with iterator, remove +type Tree struct { + root *Change + headIds []string + metaHeadIds []string + attached map[string]*Change + unAttached map[string]*Change + // missed id -> list of dependency ids + waitList map[string][]string + invalidChanges map[string]struct{} + + // bufs + iterCompBuf []*Change + iterQueue []*Change + + duplicateEvents int +} + +func (t *Tree) GetUnattachedChanges(changes ...*Change) []*Change { + return nil +} + +func (t *Tree) RootId() string { + if t.root != nil { + return t.root.Id + } + return "" +} + +func (t *Tree) Root() *Change { + return t.root +} + +func (t *Tree) AddFast(changes ...*Change) { + for _, c := range changes { + // ignore existing + if _, ok := t.attached[c.Id]; ok { + continue + } else if _, ok := t.unAttached[c.Id]; ok { + continue + } + t.add(c) + } + t.updateHeads() +} + +func (t *Tree) Add(changes ...*Change) (mode Mode) { + var beforeHeadIds = t.headIds + var attached bool + var empty = t.Len() == 0 + for _, c := range changes { + // ignore existing + if _, ok := t.attached[c.Id]; ok { + continue + } else if _, ok := t.unAttached[c.Id]; ok { + continue + } + if t.add(c) { + attached = true + } + } + if !attached { + return Nothing + } + t.updateHeads() + if empty { + return Rebuild + } + for _, hid := range beforeHeadIds { + for _, newCh := range changes { + if _, ok := t.attached[newCh.Id]; ok { + if !t.after(newCh.Id, hid) { + return Rebuild + } + } + } + } + return Append +} + +func (t *Tree) RemoveInvalidChange(id string) { + stack := []string{id} + // removing all children of this id (either next or unattached) + for len(stack) > 0 { + var exists bool + top := stack[len(stack)-1] + stack = stack[:len(stack)-1] + + if _, exists = t.invalidChanges[top]; exists { + continue + } + + var rem *Change + t.invalidChanges[top] = struct{}{} + if rem, exists = t.unAttached[top]; exists { + delete(t.unAttached, top) + } else if rem, exists = t.attached[top]; exists { + // remove from all prev changes + for _, id := range rem.PreviousIds { + prev, exists := t.attached[id] + if !exists { + continue + } + for i, next := range prev.Next { + if next.Id == top { + prev.Next[i] = nil + prev.Next = append(prev.Next[:i], prev.Next[i+1:]...) + break + } + } + } + delete(t.attached, top) + } + for _, el := range rem.Unattached { + stack = append(stack, el.Id) + } + for _, el := range rem.Next { + stack = append(stack, el.Id) + } + } + t.updateHeads() +} + +func (t *Tree) add(c *Change) (attached bool) { + if c == nil { + return false + } + if _, exists := t.invalidChanges[c.Id]; exists { + return false + } + + if t.root == nil { // first element + t.root = c + t.attached = map[string]*Change{ + c.Id: c, + } + t.unAttached = make(map[string]*Change) + t.waitList = make(map[string][]string) + t.invalidChanges = make(map[string]struct{}) + return true + } + if len(c.PreviousIds) > 1 { + sort.Strings(c.PreviousIds) + } + // attaching only if all prev ids are attached + attached = true + for _, pid := range c.PreviousIds { + if prev, ok := t.attached[pid]; ok { + prev.Unattached = append(prev.Unattached, c) + continue + } + attached = false + if prev, ok := t.unAttached[pid]; ok { + prev.Unattached = append(prev.Unattached, c) + continue + } + wl := t.waitList[pid] + wl = append(wl, c.Id) + t.waitList[pid] = wl + } + if attached { + t.attach(c, true) + } else { + // clearing wait list + for _, wid := range t.waitList[c.Id] { + c.Unattached = append(c.Unattached, t.unAttached[wid]) + } + delete(t.waitList, c.Id) + t.unAttached[c.Id] = c + } + return +} + +func (t *Tree) canAttach(c *Change) (attach bool) { + if c == nil { + return false + } + attach = true + for _, id := range c.PreviousIds { + if _, exists := t.attached[id]; !exists { + attach = false + } + } + return +} + +func (t *Tree) attach(c *Change, newEl bool) { + t.attached[c.Id] = c + if !newEl { + delete(t.unAttached, c.Id) + } + + // add next to all prev changes + for _, id := range c.PreviousIds { + // prev id must be attached if we attach this id + prev := t.attached[id] + prev.Next = append(prev.Next, c) + if len(prev.Next) > 1 { + sort.Sort(sortChanges(prev.Next)) + } + for i, next := range prev.Unattached { + if next.Id == c.Id { + prev.Unattached[i] = nil + prev.Unattached = append(prev.Unattached[:i], prev.Unattached[i+1:]...) + break + } + } + } + + // clearing wait list + if waitIds, ok := t.waitList[c.Id]; ok { + for _, wid := range waitIds { + next := t.unAttached[wid] + if t.canAttach(next) { + t.attach(next, false) + } + } + delete(t.waitList, c.Id) + } + + for _, next := range c.Unattached { + if t.canAttach(next) { + t.attach(next, false) + } + } +} + +func (t *Tree) after(id1, id2 string) (found bool) { + t.iterate(t.attached[id2], func(c *Change) (isContinue bool) { + if c.Id == id1 { + found = true + return false + } + return true + }) + return +} + +func (t *Tree) dfs(startChange string) (uniqMap map[string]*Change) { + stack := make([]*Change, 0, 10) + stack = append(stack, t.attached[startChange]) + uniqMap = map[string]*Change{} + + for len(stack) > 0 { + ch := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if _, exists := uniqMap[ch.Id]; exists { + continue + } + + uniqMap[ch.Id] = ch + + for _, prev := range ch.PreviousIds { + stack = append(stack, t.attached[prev]) + } + } + return uniqMap +} + +func (t *Tree) updateHeads() { + var newHeadIds, newMetaHeadIds []string + t.iterate(t.root, func(c *Change) (isContinue bool) { + if len(c.Next) == 0 { + newHeadIds = append(newHeadIds, c.Id) + } + return true + }) + t.headIds = newHeadIds + t.metaHeadIds = newMetaHeadIds + sort.Strings(t.headIds) + sort.Strings(t.metaHeadIds) +} + +func (t *Tree) ACLHeads() []string { + var aclTreeHeads []string + for _, head := range t.Heads() { + if slice.FindPos(aclTreeHeads, head) != -1 { // do not scan known heads + continue + } + precedingHeads := t.getPrecedingACLHeads(head) + + for _, aclHead := range precedingHeads { + if slice.FindPos(aclTreeHeads, aclHead) != -1 { + continue + } + aclTreeHeads = append(aclTreeHeads, aclHead) + } + } + return aclTreeHeads +} + +func (t *Tree) getPrecedingACLHeads(head string) []string { + headChange := t.attached[head] + + if headChange.Content.GetAclData() != nil { + return []string{head} + } else { + return headChange.Content.AclHeadIds + } +} + +func (t *Tree) iterate(start *Change, f func(c *Change) (isContinue bool)) { + it := newIterator() + defer freeIterator(it) + it.iterate(start, f) +} + +func (t *Tree) iterateSkip(start *Change, skipBefore *Change, f func(c *Change) (isContinue bool)) { + it := newIterator() + defer freeIterator(it) + it.iterateSkip(start, skipBefore, f) +} + +func (t *Tree) IterateSkip(startId string, skipBeforeId string, f func(c *Change) (isContinue bool)) { + it := newIterator() + defer freeIterator(it) + it.iterateSkip(t.attached[startId], t.attached[skipBeforeId], f) +} + +func (t *Tree) Iterate(startId string, f func(c *Change) (isContinue bool)) { + t.iterate(t.attached[startId], f) +} + +func (t *Tree) IterateBranching(startId string, f func(c *Change, branchLevel int) (isContinue bool)) { + // branchLevel indicates the number of parallel branches + var bc int + t.iterate(t.attached[startId], func(c *Change) (isContinue bool) { + if pl := len(c.PreviousIds); pl > 1 { + bc -= pl - 1 + } + bl := bc + if nl := len(c.Next); nl > 1 { + bc += nl - 1 + } + return f(c, bl) + }) +} + +func (t *Tree) Hash() string { + h := md5.New() + n := 0 + t.iterate(t.root, func(c *Change) (isContinue bool) { + n++ + fmt.Fprintf(h, "-%s", c.Id) + return true + }) + return fmt.Sprintf("%d-%x", n, h.Sum(nil)) +} + +func (t *Tree) GetDuplicateEvents() int { + return t.duplicateEvents +} + +func (t *Tree) ResetDuplicateEvents() { + t.duplicateEvents = 0 +} + +func (t *Tree) Len() int { + return len(t.attached) +} + +func (t *Tree) Heads() []string { + return t.headIds +} + +func (t *Tree) String() string { + var buf = bytes.NewBuffer(nil) + t.Iterate(t.RootId(), func(c *Change) (isContinue bool) { + buf.WriteString(c.Id) + if len(c.Next) > 1 { + buf.WriteString("-<") + } else if len(c.Next) > 0 { + buf.WriteString("->") + } else { + buf.WriteString("-|") + } + return true + }) + return buf.String() +} + +func (t *Tree) Get(id string) *Change { + return t.attached[id] +} + +type sortChanges []*Change + +func (s sortChanges) Len() int { + return len(s) +} + +func (s sortChanges) Less(i, j int) bool { + return s[i].Id < s[j].Id +} + +func (s sortChanges) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} diff --git a/acltree/treebuilder.go b/acltree/treebuilder.go new file mode 100644 index 00000000..1a34a3ae --- /dev/null +++ b/acltree/treebuilder.go @@ -0,0 +1,295 @@ +package acltree + +import ( + "errors" + "fmt" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" + //"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/lib/logging" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" + "github.com/prometheus/common/log" +) + +var ( + //log = logging.Logger("anytype-data") + ErrEmpty = errors.New("logs empty") +) + +type treeBuilder struct { + cache map[string]*Change + identityKeys map[string]keys.SigningPubKey + signingPubKeyDecoder keys.SigningPubKeyDecoder + tree *Tree + thread thread.Thread + + *changeLoader +} + +func newTreeBuilder(t thread.Thread, decoder keys.SigningPubKeyDecoder) *treeBuilder { + return &treeBuilder{ + signingPubKeyDecoder: decoder, + thread: t, + changeLoader: newChangeLoader( + t, + decoder, + NewChange), + } +} + +func (tb *treeBuilder) Init() { + tb.cache = make(map[string]*Change) + tb.identityKeys = make(map[string]keys.SigningPubKey) + tb.tree = &Tree{} + tb.changeLoader.Init(tb.cache, tb.identityKeys) +} + +func (tb *treeBuilder) Build(fromStart bool) (*Tree, error) { + var headsAndOrphans []string + headsAndOrphans = append(headsAndOrphans, tb.thread.Orphans()...) + headsAndOrphans = append(headsAndOrphans, tb.thread.Heads()...) + + if fromStart { + if err := tb.buildTreeFromStart(headsAndOrphans); err != nil { + return nil, fmt.Errorf("buildTree error: %v", err) + } + } else { + breakpoint, err := tb.findBreakpoint(headsAndOrphans) + if err != nil { + return nil, fmt.Errorf("findBreakpoint error: %v", err) + } + + if err = tb.buildTree(headsAndOrphans, breakpoint); err != nil { + return nil, fmt.Errorf("buildTree error: %v", err) + } + } + + tb.cache = nil + + return tb.tree, nil +} + +func (tb *treeBuilder) buildTreeFromStart(heads []string) (err error) { + changes, root, err := tb.dfsFromStart(heads) + if err != nil { + return err + } + + tb.tree.AddFast(root) + tb.tree.AddFast(changes...) + return +} + +func (tb *treeBuilder) dfsFromStart(heads []string) (buf []*Change, root *Change, err error) { + var possibleRoots []*Change + stack := make([]string, len(heads), len(heads)*2) + copy(stack, heads) + + buf = make([]*Change, 0, len(stack)*2) + uniqMap := make(map[string]struct{}) + for len(stack) > 0 { + id := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if _, exists := uniqMap[id]; exists { + continue + } + + ch, err := tb.loadChange(id) + if err != nil { + continue + } + + uniqMap[id] = struct{}{} + buf = append(buf, ch) + + for _, prev := range ch.PreviousIds { + stack = append(stack, prev) + } + if len(ch.PreviousIds) == 0 { + possibleRoots = append(possibleRoots, ch) + } + } + header := tb.thread.Header() + for _, r := range possibleRoots { + if r.Id == header.FirstChangeId { + return buf, r, nil + } + } + + return nil, nil, fmt.Errorf("could not find root change") +} + +func (tb *treeBuilder) buildTree(heads []string, breakpoint string) (err error) { + ch, err := tb.loadChange(breakpoint) + if err != nil { + return + } + tb.tree.AddFast(ch) + changes, err := tb.dfs(heads, breakpoint) + + tb.tree.AddFast(changes...) + return +} + +func (tb *treeBuilder) dfs(heads []string, breakpoint string) (buf []*Change, err error) { + stack := make([]string, len(heads), len(heads)*2) + copy(stack, heads) + + buf = make([]*Change, 0, len(stack)*2) + uniqMap := map[string]struct{}{breakpoint: {}} + for len(stack) > 0 { + id := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if _, exists := uniqMap[id]; exists { + continue + } + + ch, err := tb.loadChange(id) + if err != nil { + continue + } + + uniqMap[id] = struct{}{} + buf = append(buf, ch) + + for _, prev := range ch.PreviousIds { + stack = append(stack, prev) + } + } + return buf, nil +} + +func (tb *treeBuilder) findBreakpoint(heads []string) (breakpoint string, err error) { + var ( + ch *Change + snapshotIds []string + ) + for _, head := range heads { + if ch, err = tb.loadChange(head); err != nil { + return + } + shId := ch.SnapshotId + if ch.IsSnapshot { + shId = ch.Id + } + if slice.FindPos(snapshotIds, shId) == -1 { + snapshotIds = append(snapshotIds, shId) + } + } + return tb.findCommonSnapshot(snapshotIds) +} + +func (tb *treeBuilder) findCommonSnapshot(snapshotIds []string) (snapshotId string, err error) { + if len(snapshotIds) == 1 { + return snapshotIds[0], nil + } else if len(snapshotIds) == 0 { + return "", fmt.Errorf("snapshots not found") + } + + for len(snapshotIds) > 1 { + l := len(snapshotIds) + shId, e := tb.findCommonForTwoSnapshots(snapshotIds[l-2], snapshotIds[l-1]) + if e != nil { + return "", e + } + snapshotIds[l-2] = shId + snapshotIds = snapshotIds[:l-1] + } + return snapshotIds[0], nil +} + +func (tb *treeBuilder) findCommonForTwoSnapshots(s1, s2 string) (s string, err error) { + // fast cases + if s1 == s2 { + return s1, nil + } + ch1, err := tb.loadChange(s1) + if err != nil { + return "", err + } + if ch1.SnapshotId == s2 { + return s2, nil + } + ch2, err := tb.loadChange(s2) + if err != nil { + return "", err + } + if ch2.SnapshotId == s1 { + return s1, nil + } + if ch1.SnapshotId == ch2.SnapshotId && ch1.SnapshotId != "" { + return ch1.SnapshotId, nil + } + // traverse + var t1 = make([]string, 0, 5) + var t2 = make([]string, 0, 5) + t1 = append(t1, ch1.Id, ch1.SnapshotId) + t2 = append(t2, ch2.Id, ch2.SnapshotId) + for { + lid1 := t1[len(t1)-1] + if lid1 != "" { + l1, e := tb.loadChange(lid1) + if e != nil { + return "", e + } + if l1.SnapshotId != "" { + if slice.FindPos(t2, l1.SnapshotId) != -1 { + return l1.SnapshotId, nil + } + } + t1 = append(t1, l1.SnapshotId) + } + lid2 := t2[len(t2)-1] + if lid2 != "" { + l2, e := tb.loadChange(t2[len(t2)-1]) + if e != nil { + return "", e + } + if l2.SnapshotId != "" { + if slice.FindPos(t1, l2.SnapshotId) != -1 { + return l2.SnapshotId, nil + } + } + t2 = append(t2, l2.SnapshotId) + } + if lid1 == "" && lid2 == "" { + break + } + } + + log.Warnf("changes build Tree: possible versions split") + + // prefer not first snapshot + if len(ch1.PreviousIds) == 0 && len(ch2.PreviousIds) > 0 { + log.Warnf("changes build Tree: prefer %s(%d prevIds) over %s(%d prevIds)", s2, len(ch2.PreviousIds), s1, len(ch1.PreviousIds)) + return s2, nil + } else if len(ch1.PreviousIds) > 0 && len(ch2.PreviousIds) == 0 { + log.Warnf("changes build Tree: prefer %s(%d prevIds) over %s(%d prevIds)", s1, len(ch1.PreviousIds), s2, len(ch2.PreviousIds)) + return s1, nil + } + + isEmptySnapshot := func(ch *Change) bool { + // TODO: add more sophisticated checks in Change for snapshots + return !ch.IsSnapshot + } + + // TODO: can we even have empty snapshots? + // prefer not empty snapshot + if isEmptySnapshot(ch1) && !isEmptySnapshot(ch2) { + log.Warnf("changes build Tree: prefer %s(not empty) over %s(empty)", s2, s1) + return s2, nil + } else if isEmptySnapshot(ch2) && !isEmptySnapshot(ch1) { + log.Warnf("changes build Tree: prefer %s(not empty) over %s(empty)", s1, s2) + return s1, nil + } + + // TODO: add virtual change mechanics + // unexpected behavior - just return lesser id + if s1 < s2 { + log.Warnf("changes build Tree: prefer %s (%s<%s)", s1, s1, s2) + return s1, nil + } + log.Warnf("changes build Tree: prefer %s (%s<%s)", s2, s2, s1) + + return s2, nil +} diff --git a/acltree/treebuilder_test.go b/acltree/treebuilder_test.go new file mode 100644 index 00000000..cc586148 --- /dev/null +++ b/acltree/treebuilder_test.go @@ -0,0 +1,64 @@ +package acltree + +//func createTreeFromThread(t thread.Thread, fromStart bool) (*Tree, error) { +// treeBuilder := newTreeBuilder(t, keys.NewEd25519Decoder()) +// treeBuilder.Init() +// return treeBuilder.Build(fromStart) +//} +// +//func TestACLTreeBuilder_UserJoinCorrectHeadsAndLen(t *testing.T) { +// thread, err := threadbuilder.NewThreadBuilderWithTestName("threadbuilder/userjoinexample.yml") +// if err != nil { +// t.Fatal(err) +// } +// +// res, err := createTreeFromThread(thread) +// if err != nil { +// t.Fatalf("build Tree should not result in an error: %v", res) +// } +// +// assert.equal(t, res.Heads(), []string{"C.1.1"}) +// assert.equal(t, res.Len(), 4) +//} +// +//func TestTreeBuilder_UserJoinTestTreeIterate(t *testing.T) { +// thread, err := threadbuilder.NewThreadBuilderWithTestName("threadbuilder/userjoinexample.yml") +// if err != nil { +// t.Fatal(err) +// } +// +// res, err := createTreeFromThread(thread) +// if err != nil { +// t.Fatalf("build Tree should not result in an error: %v", res) +// } +// +// assert.equal(t, res.Heads(), []string{"C.1.1"}) +// assert.equal(t, res.Len(), 4) +// var changeIds []string +// res.iterate(res.root, func(c *Change) (isContinue bool) { +// changeIds = append(changeIds, c.Id) +// return true +// }) +// assert.equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "C.1.1"}) +//} +// +//func TestTreeBuilder_UserRemoveTestTreeIterate(t *testing.T) { +// thread, err := threadbuilder.NewThreadBuilderWithTestName("threadbuilder/userremoveexample.yml") +// if err != nil { +// t.Fatal(err) +// } +// +// res, err := createTreeFromThread(thread) +// if err != nil { +// t.Fatalf("build Tree should not result in an error: %v", res) +// } +// +// assert.equal(t, res.Heads(), []string{"A.1.3"}) +// assert.equal(t, res.Len(), 4) +// var changeIds []string +// res.iterate(res.root, func(c *Change) (isContinue bool) { +// changeIds = append(changeIds, c.Id) +// return true +// }) +// assert.equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "A.1.3"}) +//} diff --git a/acltree/treegraph.go b/acltree/treegraph.go new file mode 100644 index 00000000..3b37fa2e --- /dev/null +++ b/acltree/treegraph.go @@ -0,0 +1,11 @@ +//go:build ((!linux && !darwin) || android || ios || nographviz) && !amd64 +// +build !linux,!darwin android ios nographviz +// +build !amd64 + +package acltree + +import "fmt" + +func (t *Tree) Graph() (data string, err error) { + return "", fmt.Errorf("not supported") +} diff --git a/acltree/treegraph_nix.go b/acltree/treegraph_nix.go new file mode 100644 index 00000000..c180c7df --- /dev/null +++ b/acltree/treegraph_nix.go @@ -0,0 +1,151 @@ +//go:build (linux || darwin) && !android && !ios && !nographviz && (amd64 || arm64) +// +build linux darwin +// +build !android +// +build !ios +// +build !nographviz +// +build amd64 arm64 + +package acltree + +import ( + "bytes" + "fmt" + "strings" + "time" + "unicode" + + "github.com/goccy/go-graphviz" + "github.com/goccy/go-graphviz/cgraph" +) + +func (t *Tree) Graph() (data string, err error) { + var order = make(map[string]string) + var seq = 0 + t.Iterate(t.RootId(), func(c *Change) (isContinue bool) { + v := order[c.Id] + if v == "" { + order[c.Id] = fmt.Sprint(seq) + } else { + order[c.Id] = fmt.Sprintf("%s,%d", v, seq) + } + seq++ + return true + }) + g := graphviz.New() + defer g.Close() + graph, err := g.Graph() + if err != nil { + return + } + defer func() { + err = graph.Close() + }() + var nodes = make(map[string]*cgraph.Node) + var addChange = func(c *Change) error { + n, e := graph.CreateNode(c.Id) + if e != nil { + return e + } + if c.Content.GetAclData() != nil { + n.SetStyle(cgraph.FilledNodeStyle) + } else if c.IsSnapshot { + n.SetStyle(cgraph.DashedNodeStyle) + } + nodes[c.Id] = n + ord := order[c.Id] + if ord == "" { + ord = "miss" + } + var chSymbs []string + if c.Content.AclData != nil { + for _, chc := range c.Content.AclData.AclContent { + tp := fmt.Sprintf("%T", chc.Value) + tp = strings.Replace(tp, "ACLChangeACLContentValueValueOf", "", 1) + res := "" + for _, ts := range tp { + if unicode.IsUpper(ts) { + res += string(ts) + } + } + chSymbs = append(chSymbs, res) + } + } + if c.DecryptedDocumentChange != nil { + // TODO: add some parser to provide custom unmarshalling for the document change + //for _, chc := range c.DecryptedDocumentChange.Content { + // tp := fmt.Sprintf("%T", chc.Value) + // tp = strings.Replace(tp, "ChangeContentValueOf", "", 1) + // res := "" + // for _, ts := range tp { + // if unicode.IsUpper(ts) { + // res += string(ts) + // } + // } + // chSymbs = append(chSymbs, res) + //} + } + + shortId := c.Id + label := fmt.Sprintf("Id: %s\nOrd: %s\nTime: %s\nChanges: %s\n", + shortId, + ord, + time.Unix(c.Content.Timestamp, 0).Format("02.01.06 15:04:05"), + strings.Join(chSymbs, ","), + ) + n.SetLabel(label) + return nil + } + for _, c := range t.attached { + if err = addChange(c); err != nil { + return + } + } + for _, c := range t.unAttached { + if err = addChange(c); err != nil { + return + } + } + var getNode = func(id string) (*cgraph.Node, error) { + if n, ok := nodes[id]; ok { + return n, nil + } + n, err := graph.CreateNode(fmt.Sprintf("%s: not in Tree", id)) + if err != nil { + return nil, err + } + nodes[id] = n + return n, nil + } + var addLinks = func(c *Change) error { + for _, prevId := range c.PreviousIds { + self, e := getNode(c.Id) + if e != nil { + return e + } + prev, e := getNode(prevId) + if e != nil { + return e + } + _, e = graph.CreateEdge("", self, prev) + if e != nil { + return e + } + } + return nil + } + for _, c := range t.attached { + if err = addLinks(c); err != nil { + return + } + } + for _, c := range t.unAttached { + if err = addLinks(c); err != nil { + return + } + } + var buf bytes.Buffer + if err = g.Render(graph, "dot", &buf); err != nil { + return + } + return buf.String(), nil +} diff --git a/acltree/treeiterator.go b/acltree/treeiterator.go new file mode 100644 index 00000000..19a20095 --- /dev/null +++ b/acltree/treeiterator.go @@ -0,0 +1,158 @@ +package acltree + +import "sync" + +var itPool = &sync.Pool{ + New: func() interface{} { + return &iterator{} + }, +} + +func newIterator() *iterator { + return itPool.Get().(*iterator) +} + +func freeIterator(i *iterator) { + itPool.Put(i) +} + +type iterator struct { + compBuf []*Change + queue []*Change + doneMap map[*Change]struct{} + breakpoint *Change + f func(c *Change) bool +} + +func (i *iterator) iterateSkip(start *Change, skipBefore *Change, f func(c *Change) (isContinue bool)) { + skipping := true + i.iterate(start, func(c *Change) (isContinue bool) { + if skipping && c != skipBefore { + return true + } + skipping = false + return f(c) + }) +} + +func (i *iterator) iterate(start *Change, f func(c *Change) (isContinue bool)) { + if start == nil { + return + } + // reset + i.queue = i.queue[:0] + i.compBuf = i.compBuf[:0] + i.doneMap = make(map[*Change]struct{}) + i.queue = append(i.queue, start) + i.breakpoint = nil + i.f = f + + for len(i.queue) > 0 { + c := i.queue[0] + i.queue = i.queue[1:] + nl := len(c.Next) + if nl == 1 { + if !i.iterateLin(c) { + return + } + if i.breakpoint != nil { + i.toQueue(i.breakpoint) + i.breakpoint = nil + } + } else { + _, done := i.doneMap[c] + if !done { + if !f(c) { + return + } + i.doneMap[c] = struct{}{} + } + if nl != 0 { + for _, next := range c.Next { + i.toQueue(next) + } + } + } + } +} + +func (i *iterator) iterateLin(c *Change) bool { + for len(c.Next) == 1 { + _, done := i.doneMap[c] + if !done { + if !i.f(c) { + return false + } + i.doneMap[c] = struct{}{} + } + + c = c.Next[0] + if len(c.PreviousIds) > 1 { + break + } + } + if len(c.Next) == 0 && len(c.PreviousIds) <= 1 { + if !i.f(c) { + return false + } + i.doneMap[c] = struct{}{} + } else { + i.breakpoint = c + } + + return true +} + +func (i *iterator) comp(c1, c2 *Change) uint8 { + if c1.Id == c2.Id { + return 0 + } + i.compBuf = i.compBuf[:0] + i.compBuf = append(i.compBuf, c1.Next...) + var uniq = make(map[*Change]struct{}) + var appendUniqueToBuf = func(next []*Change) { + for _, n := range next { + if _, ok := uniq[n]; !ok { + i.compBuf = append(i.compBuf, n) + uniq[n] = struct{}{} + } + } + } + var used int + for len(i.compBuf)-used > 0 { + l := len(i.compBuf) - used + for _, n := range i.compBuf[used:] { + delete(uniq, n) + if n.Id == c2.Id { + return 1 + } else { + appendUniqueToBuf(n.Next) + } + } + used += l + } + return 2 +} + +func (i *iterator) toQueue(c *Change) { + var pos = -1 +For: + for idx, qc := range i.queue { + switch i.comp(c, qc) { + // exists + case 0: + return + // + case 1: + pos = idx + break For + } + } + if pos == -1 { + i.queue = append(i.queue, c) + } else if pos == 0 { + i.queue = append([]*Change{c}, i.queue...) + } else { + i.queue = append(i.queue[:pos], append([]*Change{c}, i.queue[pos:]...)...) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..01f7d96e --- /dev/null +++ b/go.mod @@ -0,0 +1,60 @@ +module github.com/anytypeio/go-anytype-infrastructure-experiments + +go 1.18 + +require ( + github.com/awalterschulze/gographviz v0.0.0-20190522210029-fa59802746ab + github.com/goccy/go-graphviz v0.0.9 + github.com/gogo/protobuf v1.3.2 + github.com/libp2p/go-libp2p-core v0.8.5 + github.com/mr-tron/base58 v1.2.0 + github.com/prometheus/common v0.18.0 + github.com/stretchr/testify v1.7.0 + github.com/textileio/go-threads v1.0.2-0.20210304072541-d0f91da84404 + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c + github.com/multiformats/go-base32 v0.0.3 + github.com/multiformats/go-multiaddr v0.3.3 + github.com/multiformats/go-multiaddr-dns v0.3.1 + github.com/multiformats/go-multibase v0.0.3 + github.com/multiformats/go-multihash v0.0.15 +) + +require ( + github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect + github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect + github.com/btcsuite/btcd v0.21.0-beta // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/fogleman/gg v1.3.0 // indirect + github.com/gogo/googleapis v1.3.1 // indirect + github.com/gogo/status v1.1.0 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/golang/protobuf v1.4.3 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.2.1 // indirect + github.com/ipfs/go-cid v0.0.7 // indirect + github.com/klauspost/cpuid/v2 v2.0.4 // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect + github.com/libp2p/go-buffer-pool v0.0.2 // indirect + github.com/libp2p/go-openssl v0.0.7 // indirect + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect + github.com/minio/sha256-simd v1.0.0 // indirect + github.com/multiformats/go-base32 v0.0.3 // indirect + github.com/multiformats/go-base36 v0.1.0 // indirect + github.com/multiformats/go-multiaddr v0.3.3 // indirect + github.com/multiformats/go-multibase v0.0.3 // indirect + github.com/multiformats/go-multihash v0.0.15 // indirect + github.com/multiformats/go-varint v0.0.6 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/sirupsen/logrus v1.6.0 // indirect + github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect + golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect + golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect + golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 // indirect + google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect + google.golang.org/grpc v1.33.2 // indirect + google.golang.org/protobuf v1.25.0 // indirect + gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect +) + +replace github.com/textileio/go-threads => github.com/anytypeio/go-threads v1.1.0-rc1.0.20220223104843-a67245cee80e diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..31e899cb --- /dev/null +++ b/go.sum @@ -0,0 +1,1351 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= +github.com/alecthomas/jsonschema v0.0.0-20191017121752-4bb6e3fae4f2/go.mod h1:Juc2PrI3wtNfUwptSvAIeNx+HrETwHQs6nf+TkOJlOA= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/anytypeio/go-threads v1.1.0-rc1.0.20220223104843-a67245cee80e h1:u6UT0oqGybURAWvKw0p7BPnqoVqC+wEvOOz5K+ESBZE= +github.com/anytypeio/go-threads v1.1.0-rc1.0.20220223104843-a67245cee80e/go.mod h1:O7G/oTjIZfQmB6ZoeU42IdRxWEY9D+HZuLzF6wMk4jI= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/awalterschulze/gographviz v0.0.0-20190522210029-fa59802746ab h1:+cdNqtOJWjvepyhxy23G7z7vmpYCoC65AP0nqi1f53s= +github.com/awalterschulze/gographviz v0.0.0-20190522210029-fa59802746ab/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.29.15/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= +github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/corona10/goimagehash v1.0.2 h1:pUfB0LnsJASMPGEZLj7tGY251vF+qLGqOgEP4rUs6kA= +github.com/corona10/goimagehash v1.0.2/go.mod h1:/l9umBhvcHQXVtQO1V6Gp1yD20STawkhRnnX0D1bvVI= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= +github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= +github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgtony/collections v0.1.6/go.mod h1:olD2FRoNisWmjMhK6LDRKv+lMnDoryOZIT+owtd/o6U= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= +github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/goccy/go-graphviz v0.0.9 h1:s/FMMJ1Joj6La3S5ApO3Jk2cwM4LpXECC2muFx3IPQQ= +github.com/goccy/go-graphviz v0.0.9/go.mod h1:wXVsXxmyMQU6TN3zGRttjNn3h+iCAS7xQFC6TlNvLhk= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.3.1 h1:CzMaKrvF6Qa7XtRii064vKBQiyvmY8H8vG1xa1/W1JA= +github.com/gogo/googleapis v1.3.1/go.mod h1:d+q1s/xVJxZGKWwC/6UfPIF33J+G1Tq4GYv9Y+Tg/EU= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.1.0 h1:+eIkrewn5q6b30y+g/BJINVVdi2xH7je5MPJ3ZPK3JA= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.1 h1:V59tBiPuMkySHwJkuq/OYkK0WnOLwCwD3UkTbEMr12U= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.1/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hsanjuan/ipfs-lite v1.1.17/go.mod h1:ZetJanzQEAqWj+OwzIppE/S7x+Azu4WFF6PNMLnQGoY= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/improbable-eng/grpc-web v0.13.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3UPrwvis= +github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= +github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= +github.com/ipfs/go-bitswap v0.1.3/go.mod h1:YEQlFy0kkxops5Vy+OxWdRSEZIoS7I7KDIwoa5Chkps= +github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= +github.com/ipfs/go-bitswap v0.2.20/go.mod h1:C7TwBgHnu89Q8sHsTJP7IhUqF9XYLe71P4tT5adgmYo= +github.com/ipfs/go-bitswap v0.3.3/go.mod h1:AyWWfN3moBzQX0banEtfKOfbXb3ZeoOeXnZGNPV9S6w= +github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= +github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= +github.com/ipfs/go-blockservice v0.1.2/go.mod h1:t+411r7psEUhLueM8C7aPA7cxCclv4O3VsUVxt9kz2I= +github.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-blockservice v0.1.4/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= +github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.2/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= +github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= +github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= +github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= +github.com/ipfs/go-ds-badger v0.2.6/go.mod h1:02rnztVKA4aZwDuaRPTf8mpqcKmXP7mLl6JPxd14JHA= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= +github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= +github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= +github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= +github.com/ipfs/go-ipfs-blockstore v1.0.1/go.mod h1:MGNZlHNEnR4KGgPHM3/k8lBySIOK2Ve+0KjZubKlaOE= +github.com/ipfs/go-ipfs-blockstore v1.0.3/go.mod h1:MGNZlHNEnR4KGgPHM3/k8lBySIOK2Ve+0KjZubKlaOE= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= +github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= +github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= +github.com/ipfs/go-ipfs-config v0.10.0/go.mod h1:Ei/FLgHGTdPyqCPK0oPCwGTe8VSnsjJjx7HZqUb6Ry0= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= +github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= +github.com/ipfs/go-ipfs-ds-help v1.0.0/go.mod h1:ujAbkeIgkKAWtxxNkoZHWLCyk5JpPoKnGyCcsoF6ueE= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= +github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-provider v0.4.3/go.mod h1:rcQBVqfblDQRk5LaCtf2uxuKxMJxvKmF5pLS0pO4au4= +github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= +github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= +github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= +github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= +github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= +github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= +github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= +github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= +github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= +github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= +github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= +github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= +github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= +github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= +github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= +github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk= +github.com/libp2p/go-conn-security-multistream v0.0.2/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= +github.com/libp2p/go-conn-security-multistream v0.2.1/go.mod h1:cR1d8gA0Hr59Fj6NhaTpFhJZrjSYuNmhpT2r25zYR70= +github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= +github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-libp2p v0.0.30/go.mod h1:XWT8FGHlhptAv1+3V/+J5mEpzyui/5bvFsNuWYs611A= +github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= +github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= +github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= +github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= +github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= +github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= +github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM= +github.com/libp2p/go-libp2p v0.11.0/go.mod h1:3/ogJDXsbbepEfqtZKBR/DedzxJXCeK17t2Z9RE9bEE= +github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= +github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= +github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= +github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE= +github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= +github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= +github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= +github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= +github.com/libp2p/go-libp2p-autonat v0.3.2/go.mod h1:0OzOi1/cVc7UcxfOddemYD5vzEqi4fwRbnZcJGLi68U= +github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= +github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= +github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= +github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= +github.com/libp2p/go-libp2p-circuit v0.0.9/go.mod h1:uU+IBvEQzCu953/ps7bYzC/D/R0Ho2A9LfKVVCatlqU= +github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= +github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= +github.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4= +github.com/libp2p/go-libp2p-circuit v0.3.1/go.mod h1:8RMIlivu1+RxhebipJwFDA45DasLx+kkrp4IlJj53F4= +github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= +github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= +github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= +github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= +github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= +github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= +github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= +github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= +github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= +github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= +github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.2/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= +github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.2/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= +github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= +github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.0.5/go.mod h1:YtF20GUxjgoKZ4zmXj8j3Nb2TUSBHFlOCetzYdbZL5I= +github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= +github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= +github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4= +github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= +github.com/libp2p/go-libp2p-gostream v0.3.0/go.mod h1:pLBQu8db7vBMNINGsAwLL/ZCE8wng5V1FThoaE5rNjc= +github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= +github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= +github.com/libp2p/go-libp2p-kad-dht v0.10.0/go.mod h1:LEKcCFHxnvypOPaqZ0m6h0fLQ9Y8t1iZMOg7a0aQDD4= +github.com/libp2p/go-libp2p-kad-dht v0.11.0/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= +github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= +github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= +github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= +github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= +github.com/libp2p/go-libp2p-mplex v0.2.4/go.mod h1:mI7iOezdWFOisvUwaYd3IDrJ4oVmgoXK8H331ui39CE= +github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= +github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= +github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= +github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= +github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= +github.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= +github.com/libp2p/go-libp2p-net v0.0.2/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= +github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= +github.com/libp2p/go-libp2p-noise v0.2.0/go.mod h1:IEbYhBBzGyvdLBoxxULL/SGbJARhUeqlO8lVSREYu2Q= +github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= +github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= +github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= +github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= +github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= +github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= +github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= +github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw= +github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= +github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= +github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= +github.com/libp2p/go-libp2p-pubsub v0.4.0/go.mod h1:izkeMLvz6Ht8yAISXjx60XUQZMq9ZMe5h2ih4dLIBIQ= +github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= +github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= +github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= +github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= +github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= +github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= +github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= +github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= +github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= +github.com/libp2p/go-libp2p-swarm v0.0.6/go.mod h1:s5GZvzg9xXe8sbeESuFpjt8CJPTCa8mhEusweJqyFy8= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= +github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= +github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= +github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= +github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= +github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= +github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= +github.com/libp2p/go-libp2p-testing v0.2.0/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= +github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= +github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= +github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= +github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= +github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= +github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= +github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= +github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= +github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= +github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= +github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= +github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= +github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= +github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= +github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= +github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3BuHoeTSqhcel1wsE= +github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= +github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= +github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= +github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= +github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= +github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-netroute v0.1.5/go.mod h1:V1SR3AaECRkEQCoFFzYwVYWvYIEtlxx89+O3qcpCl4A= +github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ= +github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= +github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= +github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= +github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= +github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer v0.1.0/go.mod h1:8JAVsjeRBCWwPoZeH0W1imLOcriqXJyFvB0mR4A04sQ= +github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcccoL8L//laqawOsO03zX8Sa+eGw= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= +github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= +github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= +github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= +github.com/libp2p/go-tcp-transport v0.2.3/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= +github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= +github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= +github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU= +github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= +github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= +github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= +github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= +github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= +github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= +github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= +github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= +github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= +github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= +github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= +github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= +github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= +github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= +github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= +github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= +github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM= +github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= +github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-multistream v0.1.2/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= +github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= +github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= +github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= +github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/namsral/flag v1.7.4-pre/go.mod h1:OXldTctbM6SWH1K899kPZcf65KxJiD7MsceFUpB5yDo= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY= +github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y= +github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/textileio/go-datastore-extensions v1.0.1/go.mod h1:Pzj9FDRkb55910dr/FX8M7WywvnS26gBgEDez1ZBuLE= +github.com/textileio/go-ds-badger v0.2.7-0.20201204225019-4ee78c4a40e2/go.mod h1:qEZ/z1KyoRhGS5MYEbIcWUCCPd/0HxCkFDVeJgP1RcI= +github.com/textileio/go-ds-mongo v0.1.4/go.mod h1:Zf6JlMPiIQUUmGlFFn5Z65C9p9LAvPg7XvX+qdGmTsU= +github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.mongodb.org/mongo-driver v1.4.0/go.mod h1:llVBH2pkj9HywK0Dtdt6lDikOjFLbceHVu/Rc0iMKLs= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQgW5XwmSvR/nA2JmJ0RErg= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk= +golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524152521-dbbf3f1254d4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM= +golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/plaintextdocument/document.go b/plaintextdocument/document.go new file mode 100644 index 00000000..63c07bde --- /dev/null +++ b/plaintextdocument/document.go @@ -0,0 +1,167 @@ +package plaintextdocument + +import ( + "fmt" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + aclpb "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/acltree" + "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/testchanges/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/gogo/protobuf/proto" +) + +type PlainTextDocument interface { + Text() string + AddText(text string) error +} + +type plainTextDocument struct { + heads []string + aclTree acltree.ACLTree + state *DocumentState +} + +func (p *plainTextDocument) Text() string { + if p.state != nil { + return p.state.Text + } + return "" +} + +func (p *plainTextDocument) AddText(text string) error { + _, err := p.aclTree.AddContent(func(builder acltree.ChangeBuilder) error { + builder.AddChangeContent( + &pb.PlainTextChangeData{ + Content: []*pb.PlainTextChangeContent{ + createAppendTextChangeContent(text), + }, + }) + return nil + }) + return err +} + +func (p *plainTextDocument) Update(tree acltree.ACLTree) { + p.aclTree = tree + var err error + defer func() { + if err != nil { + fmt.Println("rebuild has returned error:", err) + } + }() + + prevHeads := p.heads + p.heads = tree.Heads() + startId := prevHeads[0] + tree.IterateFrom(startId, func(change *acltree.Change) (isContinue bool) { + if change.Id == startId { + return true + } + if change.DecryptedDocumentChange != nil { + p.state, err = p.state.ApplyChange(change.DecryptedDocumentChange, change.Id) + if err != nil { + return false + } + } + return true + }) +} + +func (p *plainTextDocument) Rebuild(tree acltree.ACLTree) { + p.aclTree = tree + p.heads = tree.Heads() + var startId string + var err error + defer func() { + if err != nil { + fmt.Println("rebuild has returned error:", err) + } + }() + + rootChange := tree.Root() + + if rootChange.DecryptedDocumentChange == nil { + err = fmt.Errorf("root doesn't have decrypted change") + return + } + + state, err := BuildDocumentStateFromChange(rootChange.DecryptedDocumentChange, rootChange.Id) + if err != nil { + return + } + + startId = rootChange.Id + tree.Iterate(func(change *acltree.Change) (isContinue bool) { + if startId == change.Id { + return true + } + if change.DecryptedDocumentChange != nil { + state, err = state.ApplyChange(change.DecryptedDocumentChange, change.Id) + if err != nil { + return false + } + } + return true + }) + if err != nil { + return + } + p.state = state +} + +func NewInMemoryPlainTextDocument(acc *account.AccountData, text string) (PlainTextDocument, error) { + return NewPlainTextDocument(acc, thread.NewInMemoryThread, text) +} + +func NewPlainTextDocument( + acc *account.AccountData, + create func(change *thread.RawChange) (thread.Thread, error), + text string) (PlainTextDocument, error) { + changeBuilder := func(builder acltree.ChangeBuilder) error { + err := builder.UserAdd(acc.Identity, acc.EncKey.GetPublic(), aclpb.ACLChange_Admin) + if err != nil { + return err + } + builder.AddChangeContent(createInitialChangeContent(text)) + return nil + } + t, err := acltree.BuildThreadWithACL( + acc, + changeBuilder, + create) + if err != nil { + return nil, err + } + + doc := &plainTextDocument{ + heads: nil, + aclTree: nil, + state: nil, + } + tree, err := acltree.BuildACLTree(t, acc, doc) + if err != nil { + return nil, err + } + doc.aclTree = tree + return doc, nil +} + +func createInitialChangeContent(text string) proto.Marshaler { + return &pb.PlainTextChangeData{ + Content: []*pb.PlainTextChangeContent{ + createAppendTextChangeContent(text), + }, + Snapshot: &pb.PlainTextChangeSnapshot{Text: text}, + } +} + +func createAppendTextChangeContent(text string) *pb.PlainTextChangeContent { + return &pb.PlainTextChangeContent{ + Value: &pb.PlainTextChangeContentValueOfTextAppend{ + TextAppend: &pb.PlainTextChangeTextAppend{ + Text: text, + }, + }, + } +} diff --git a/plaintextdocument/document_test.go b/plaintextdocument/document_test.go new file mode 100644 index 00000000..204115a0 --- /dev/null +++ b/plaintextdocument/document_test.go @@ -0,0 +1,54 @@ +package plaintextdocument + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/threadbuilder" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestDocument_NewPlainTextDocument(t *testing.T) { + keychain := threadbuilder.NewKeychain() + keychain.AddSigningKey("A") + keychain.AddEncryptionKey("A") + data := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + + doc, err := NewPlainTextDocument(data, thread.NewInMemoryThread, "Some text") + if err != nil { + t.Fatalf("should not create document with error: %v", err) + } + assert.Equal(t, doc.Text(), "Some text") +} + +func TestDocument_PlainTextDocument_AddText(t *testing.T) { + keychain := threadbuilder.NewKeychain() + keychain.AddSigningKey("A") + keychain.AddEncryptionKey("A") + data := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + + doc, err := NewPlainTextDocument(data, thread.NewInMemoryThread, "Some text") + if err != nil { + t.Fatalf("should not create document with error: %v", err) + } + + err = doc.AddText("Next") + if err != nil { + t.Fatalf("should be able to add document: %v", err) + } + assert.Equal(t, doc.Text(), "Some text|Next") + + err = doc.AddText("Shmext") + if err != nil { + t.Fatalf("should be able to add document: %v", err) + } + assert.Equal(t, doc.Text(), "Some text|Next|Shmext") +} diff --git a/plaintextdocument/plaintextdocstate.go b/plaintextdocument/plaintextdocstate.go new file mode 100644 index 00000000..d7447b03 --- /dev/null +++ b/plaintextdocument/plaintextdocstate.go @@ -0,0 +1,59 @@ +package plaintextdocument + +import ( + "fmt" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/testchanges/pb" + "github.com/gogo/protobuf/proto" +) + +type DocumentState struct { + LastChangeId string + Text string +} + +func NewDocumentState(text string, id string) *DocumentState { + return &DocumentState{ + LastChangeId: id, + Text: text, + } +} + +func BuildDocumentStateFromChange(change []byte, id string) (*DocumentState, error) { + var changesData pb.PlainTextChangeData + err := proto.Unmarshal(change, &changesData) + if err != nil { + return nil, err + } + + if changesData.GetSnapshot() == nil { + return nil, fmt.Errorf("could not create state from empty snapshot") + } + return NewDocumentState(changesData.GetSnapshot().GetText(), id), nil +} + +func (p *DocumentState) ApplyChange(change []byte, id string) (*DocumentState, error) { + var changesData pb.PlainTextChangeData + err := proto.Unmarshal(change, &changesData) + if err != nil { + return nil, err + } + + for _, content := range changesData.GetContent() { + err = p.applyChange(content) + if err != nil { + return nil, err + } + } + p.LastChangeId = id + return p, nil +} + +func (p *DocumentState) applyChange(ch *pb.PlainTextChangeContent) error { + switch { + case ch.GetTextAppend() != nil: + text := ch.GetTextAppend().GetText() + p.Text += "|" + text + } + return nil +} diff --git a/testutils/testchanges/pb/protos/testdocumentchanges.proto b/testutils/testchanges/pb/protos/testdocumentchanges.proto new file mode 100644 index 00000000..0f9177af --- /dev/null +++ b/testutils/testchanges/pb/protos/testdocumentchanges.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; +package anytype; +option go_package = "pb"; + +// TODO: move to separate package + +message PlainTextChange { + message Content { + oneof value { + TextAppend textAppend = 1; + } + } + + message TextAppend { + string text = 1; + } + + message Snapshot { + string text = 1; + } + + message Data { + repeated Content content = 1; + Snapshot snapshot = 2; + } +} diff --git a/testutils/testchanges/pb/testdocumentchanges.pb.go b/testutils/testchanges/pb/testdocumentchanges.pb.go new file mode 100644 index 00000000..ac95a1b7 --- /dev/null +++ b/testutils/testchanges/pb/testdocumentchanges.pb.go @@ -0,0 +1,1088 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: data/pb/protos/plaintextchanges.proto + +package pb + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type PlainTextChange struct { +} + +func (m *PlainTextChange) Reset() { *m = PlainTextChange{} } +func (m *PlainTextChange) String() string { return proto.CompactTextString(m) } +func (*PlainTextChange) ProtoMessage() {} +func (*PlainTextChange) Descriptor() ([]byte, []int) { + return fileDescriptor_970a1e91eeb094c9, []int{0} +} +func (m *PlainTextChange) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PlainTextChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PlainTextChange.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PlainTextChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlainTextChange.Merge(m, src) +} +func (m *PlainTextChange) XXX_Size() int { + return m.Size() +} +func (m *PlainTextChange) XXX_DiscardUnknown() { + xxx_messageInfo_PlainTextChange.DiscardUnknown(m) +} + +var xxx_messageInfo_PlainTextChange proto.InternalMessageInfo + +type PlainTextChangeContent struct { + // Types that are valid to be assigned to Value: + // *PlainTextChangeContentValueOfTextAppend + Value IsPlainTextChangeContentValue `protobuf_oneof:"value"` +} + +func (m *PlainTextChangeContent) Reset() { *m = PlainTextChangeContent{} } +func (m *PlainTextChangeContent) String() string { return proto.CompactTextString(m) } +func (*PlainTextChangeContent) ProtoMessage() {} +func (*PlainTextChangeContent) Descriptor() ([]byte, []int) { + return fileDescriptor_970a1e91eeb094c9, []int{0, 0} +} +func (m *PlainTextChangeContent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PlainTextChangeContent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PlainTextChangeContent.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PlainTextChangeContent) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlainTextChangeContent.Merge(m, src) +} +func (m *PlainTextChangeContent) XXX_Size() int { + return m.Size() +} +func (m *PlainTextChangeContent) XXX_DiscardUnknown() { + xxx_messageInfo_PlainTextChangeContent.DiscardUnknown(m) +} + +var xxx_messageInfo_PlainTextChangeContent proto.InternalMessageInfo + +type IsPlainTextChangeContentValue interface { + IsPlainTextChangeContentValue() + MarshalTo([]byte) (int, error) + Size() int +} + +type PlainTextChangeContentValueOfTextAppend struct { + TextAppend *PlainTextChangeTextAppend `protobuf:"bytes,1,opt,name=textAppend,proto3,oneof" json:"textAppend,omitempty"` +} + +func (*PlainTextChangeContentValueOfTextAppend) IsPlainTextChangeContentValue() {} + +func (m *PlainTextChangeContent) GetValue() IsPlainTextChangeContentValue { + if m != nil { + return m.Value + } + return nil +} + +func (m *PlainTextChangeContent) GetTextAppend() *PlainTextChangeTextAppend { + if x, ok := m.GetValue().(*PlainTextChangeContentValueOfTextAppend); ok { + return x.TextAppend + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*PlainTextChangeContent) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*PlainTextChangeContentValueOfTextAppend)(nil), + } +} + +type PlainTextChangeTextAppend struct { + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` +} + +func (m *PlainTextChangeTextAppend) Reset() { *m = PlainTextChangeTextAppend{} } +func (m *PlainTextChangeTextAppend) String() string { return proto.CompactTextString(m) } +func (*PlainTextChangeTextAppend) ProtoMessage() {} +func (*PlainTextChangeTextAppend) Descriptor() ([]byte, []int) { + return fileDescriptor_970a1e91eeb094c9, []int{0, 1} +} +func (m *PlainTextChangeTextAppend) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PlainTextChangeTextAppend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PlainTextChangeTextAppend.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PlainTextChangeTextAppend) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlainTextChangeTextAppend.Merge(m, src) +} +func (m *PlainTextChangeTextAppend) XXX_Size() int { + return m.Size() +} +func (m *PlainTextChangeTextAppend) XXX_DiscardUnknown() { + xxx_messageInfo_PlainTextChangeTextAppend.DiscardUnknown(m) +} + +var xxx_messageInfo_PlainTextChangeTextAppend proto.InternalMessageInfo + +func (m *PlainTextChangeTextAppend) GetText() string { + if m != nil { + return m.Text + } + return "" +} + +type PlainTextChangeSnapshot struct { + Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"` +} + +func (m *PlainTextChangeSnapshot) Reset() { *m = PlainTextChangeSnapshot{} } +func (m *PlainTextChangeSnapshot) String() string { return proto.CompactTextString(m) } +func (*PlainTextChangeSnapshot) ProtoMessage() {} +func (*PlainTextChangeSnapshot) Descriptor() ([]byte, []int) { + return fileDescriptor_970a1e91eeb094c9, []int{0, 2} +} +func (m *PlainTextChangeSnapshot) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PlainTextChangeSnapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PlainTextChangeSnapshot.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PlainTextChangeSnapshot) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlainTextChangeSnapshot.Merge(m, src) +} +func (m *PlainTextChangeSnapshot) XXX_Size() int { + return m.Size() +} +func (m *PlainTextChangeSnapshot) XXX_DiscardUnknown() { + xxx_messageInfo_PlainTextChangeSnapshot.DiscardUnknown(m) +} + +var xxx_messageInfo_PlainTextChangeSnapshot proto.InternalMessageInfo + +func (m *PlainTextChangeSnapshot) GetText() string { + if m != nil { + return m.Text + } + return "" +} + +type PlainTextChangeData struct { + Content []*PlainTextChangeContent `protobuf:"bytes,1,rep,name=content,proto3" json:"content,omitempty"` + Snapshot *PlainTextChangeSnapshot `protobuf:"bytes,2,opt,name=snapshot,proto3" json:"snapshot,omitempty"` +} + +func (m *PlainTextChangeData) Reset() { *m = PlainTextChangeData{} } +func (m *PlainTextChangeData) String() string { return proto.CompactTextString(m) } +func (*PlainTextChangeData) ProtoMessage() {} +func (*PlainTextChangeData) Descriptor() ([]byte, []int) { + return fileDescriptor_970a1e91eeb094c9, []int{0, 3} +} +func (m *PlainTextChangeData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PlainTextChangeData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PlainTextChangeData.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PlainTextChangeData) XXX_Merge(src proto.Message) { + xxx_messageInfo_PlainTextChangeData.Merge(m, src) +} +func (m *PlainTextChangeData) XXX_Size() int { + return m.Size() +} +func (m *PlainTextChangeData) XXX_DiscardUnknown() { + xxx_messageInfo_PlainTextChangeData.DiscardUnknown(m) +} + +var xxx_messageInfo_PlainTextChangeData proto.InternalMessageInfo + +func (m *PlainTextChangeData) GetContent() []*PlainTextChangeContent { + if m != nil { + return m.Content + } + return nil +} + +func (m *PlainTextChangeData) GetSnapshot() *PlainTextChangeSnapshot { + if m != nil { + return m.Snapshot + } + return nil +} + +func init() { + proto.RegisterType((*PlainTextChange)(nil), "anytype.PlainTextChange") + proto.RegisterType((*PlainTextChangeContent)(nil), "anytype.PlainTextChange.Content") + proto.RegisterType((*PlainTextChangeTextAppend)(nil), "anytype.PlainTextChange.TextAppend") + proto.RegisterType((*PlainTextChangeSnapshot)(nil), "anytype.PlainTextChange.Snapshot") + proto.RegisterType((*PlainTextChangeData)(nil), "anytype.PlainTextChange.Data") +} + +func init() { + proto.RegisterFile("data/pb/protos/plaintextchanges.proto", fileDescriptor_970a1e91eeb094c9) +} + +var fileDescriptor_970a1e91eeb094c9 = []byte{ + // 259 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4d, 0x49, 0x2c, 0x49, + 0xd4, 0x2f, 0x48, 0xd2, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x2f, 0xd6, 0x2f, 0xc8, 0x49, 0xcc, 0xcc, + 0x2b, 0x49, 0xad, 0x28, 0x49, 0xce, 0x48, 0xcc, 0x4b, 0x4f, 0x2d, 0xd6, 0x03, 0x8b, 0x0b, 0xb1, + 0x27, 0xe6, 0x55, 0x96, 0x54, 0x16, 0xa4, 0x2a, 0x6d, 0x62, 0xe2, 0xe2, 0x0f, 0x00, 0xa9, 0x09, + 0x49, 0xad, 0x28, 0x71, 0x06, 0xab, 0x91, 0x8a, 0xe4, 0x62, 0x77, 0xce, 0xcf, 0x2b, 0x49, 0xcd, + 0x2b, 0x11, 0x72, 0xe5, 0xe2, 0x02, 0x69, 0x76, 0x2c, 0x28, 0x48, 0xcd, 0x4b, 0x91, 0x60, 0x54, + 0x60, 0xd4, 0xe0, 0x36, 0x52, 0xd6, 0x83, 0x6a, 0xd6, 0x43, 0xd3, 0xa8, 0x17, 0x02, 0x57, 0xea, + 0xc1, 0x10, 0x84, 0xa4, 0xd1, 0x89, 0x9d, 0x8b, 0xb5, 0x2c, 0x31, 0xa7, 0x34, 0x55, 0x4a, 0x81, + 0x8b, 0x0b, 0xa1, 0x48, 0x48, 0x88, 0x8b, 0x05, 0xa4, 0x08, 0x6c, 0x2e, 0x67, 0x10, 0x98, 0x2d, + 0x25, 0xc7, 0xc5, 0x11, 0x9c, 0x97, 0x58, 0x50, 0x9c, 0x91, 0x5f, 0x82, 0x55, 0xbe, 0x91, 0x91, + 0x8b, 0xc5, 0x25, 0xb1, 0x24, 0x51, 0xc8, 0x8a, 0x8b, 0x3d, 0x19, 0xe2, 0x4a, 0x09, 0x46, 0x05, + 0x66, 0x0d, 0x6e, 0x23, 0x05, 0x9c, 0xee, 0x82, 0xfa, 0x26, 0x08, 0xa6, 0x41, 0xc8, 0x96, 0x8b, + 0xa3, 0x18, 0x6a, 0x89, 0x04, 0x13, 0xd8, 0x53, 0x8a, 0x38, 0x35, 0xc3, 0x5c, 0x13, 0x04, 0xd7, + 0xe2, 0x24, 0x73, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, + 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x4c, 0x05, 0x49, + 0x49, 0x6c, 0xe0, 0x20, 0x36, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x1e, 0xb0, 0x6a, 0x8b, + 0x01, 0x00, 0x00, +} + +func (m *PlainTextChange) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PlainTextChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PlainTextChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *PlainTextChangeContent) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PlainTextChangeContent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PlainTextChangeContent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Value != nil { + { + size := m.Value.Size() + i -= size + if _, err := m.Value.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *PlainTextChangeContentValueOfTextAppend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PlainTextChangeContentValueOfTextAppend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.TextAppend != nil { + { + size, err := m.TextAppend.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlaintextchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} +func (m *PlainTextChangeTextAppend) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PlainTextChangeTextAppend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PlainTextChangeTextAppend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Text) > 0 { + i -= len(m.Text) + copy(dAtA[i:], m.Text) + i = encodeVarintPlaintextchanges(dAtA, i, uint64(len(m.Text))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PlainTextChangeSnapshot) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PlainTextChangeSnapshot) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PlainTextChangeSnapshot) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Text) > 0 { + i -= len(m.Text) + copy(dAtA[i:], m.Text) + i = encodeVarintPlaintextchanges(dAtA, i, uint64(len(m.Text))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PlainTextChangeData) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PlainTextChangeData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PlainTextChangeData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Snapshot != nil { + { + size, err := m.Snapshot.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlaintextchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Content) > 0 { + for iNdEx := len(m.Content) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Content[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlaintextchanges(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintPlaintextchanges(dAtA []byte, offset int, v uint64) int { + offset -= sovPlaintextchanges(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PlainTextChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *PlainTextChangeContent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Value != nil { + n += m.Value.Size() + } + return n +} + +func (m *PlainTextChangeContentValueOfTextAppend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.TextAppend != nil { + l = m.TextAppend.Size() + n += 1 + l + sovPlaintextchanges(uint64(l)) + } + return n +} +func (m *PlainTextChangeTextAppend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Text) + if l > 0 { + n += 1 + l + sovPlaintextchanges(uint64(l)) + } + return n +} + +func (m *PlainTextChangeSnapshot) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Text) + if l > 0 { + n += 1 + l + sovPlaintextchanges(uint64(l)) + } + return n +} + +func (m *PlainTextChangeData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Content) > 0 { + for _, e := range m.Content { + l = e.Size() + n += 1 + l + sovPlaintextchanges(uint64(l)) + } + } + if m.Snapshot != nil { + l = m.Snapshot.Size() + n += 1 + l + sovPlaintextchanges(uint64(l)) + } + return n +} + +func sovPlaintextchanges(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozPlaintextchanges(x uint64) (n int) { + return sovPlaintextchanges(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PlainTextChange) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PlainTextChange: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PlainTextChange: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipPlaintextchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlaintextchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PlainTextChangeContent) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Content: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Content: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TextAppend", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlaintextchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlaintextchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &PlainTextChangeTextAppend{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Value = &PlainTextChangeContentValueOfTextAppend{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPlaintextchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlaintextchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PlainTextChangeTextAppend) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TextAppend: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TextAppend: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Text", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlaintextchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlaintextchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Text = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPlaintextchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlaintextchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PlainTextChangeSnapshot) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Snapshot: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Snapshot: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Text", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlaintextchanges + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlaintextchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Text = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPlaintextchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlaintextchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PlainTextChangeData) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Data: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Data: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Content", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlaintextchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlaintextchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Content = append(m.Content, &PlainTextChangeContent{}) + if err := m.Content[len(m.Content)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Snapshot", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlaintextchanges + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlaintextchanges + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Snapshot == nil { + m.Snapshot = &PlainTextChangeSnapshot{} + } + if err := m.Snapshot.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPlaintextchanges(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlaintextchanges + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipPlaintextchanges(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPlaintextchanges + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthPlaintextchanges + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupPlaintextchanges + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthPlaintextchanges + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthPlaintextchanges = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPlaintextchanges = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupPlaintextchanges = fmt.Errorf("proto: unexpected end of group") +) diff --git a/testutils/threadbuilder/keychain.go b/testutils/threadbuilder/keychain.go new file mode 100644 index 00000000..c8532a41 --- /dev/null +++ b/testutils/threadbuilder/keychain.go @@ -0,0 +1,149 @@ +package threadbuilder + +import ( + "hash/fnv" + "strings" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" + + "github.com/textileio/go-threads/crypto/symmetric" +) + +type SymKey struct { + Hash uint64 + Key *symmetric.Key +} + +type Keychain struct { + SigningKeys map[string]keys.SigningPrivKey + SigningKeysByIdentity map[string]keys.SigningPrivKey + EncryptionKeys map[string]keys.EncryptionPrivKey + ReadKeys map[string]*SymKey + ReadKeysByHash map[uint64]*SymKey + GeneratedIdentities map[string]string + coder *keys.Ed25519SigningPubKeyDecoder +} + +func NewKeychain() *Keychain { + return &Keychain{ + SigningKeys: map[string]keys.SigningPrivKey{}, + SigningKeysByIdentity: map[string]keys.SigningPrivKey{}, + EncryptionKeys: map[string]keys.EncryptionPrivKey{}, + GeneratedIdentities: map[string]string{}, + ReadKeys: map[string]*SymKey{}, + ReadKeysByHash: map[uint64]*SymKey{}, + coder: keys.NewEd25519Decoder(), + } +} + +func (k *Keychain) ParseKeys(keys *Keys) { + for _, encKey := range keys.Enc { + k.AddEncryptionKey(encKey) + } + + for _, signKey := range keys.Sign { + k.AddSigningKey(signKey) + } + + for _, readKey := range keys.Read { + k.AddReadKey(readKey) + } +} + +func (k *Keychain) AddEncryptionKey(name string) { + if _, exists := k.EncryptionKeys[name]; exists { + return + } + newPrivKey, _, err := keys.GenerateRandomRSAKeyPair(2048) + if err != nil { + panic(err) + } + + k.EncryptionKeys[name] = newPrivKey +} + +func (k *Keychain) AddSigningKey(name string) { + if _, exists := k.SigningKeys[name]; exists { + return + } + newPrivKey, pubKey, err := keys.GenerateRandomEd25519KeyPair() + if err != nil { + panic(err) + } + + k.SigningKeys[name] = newPrivKey + res, err := k.coder.EncodeToString(pubKey) + if err != nil { + panic(err) + } + k.SigningKeysByIdentity[res] = newPrivKey + k.GeneratedIdentities[name] = res +} + +func (k *Keychain) AddReadKey(name string) { + if _, exists := k.ReadKeys[name]; exists { + return + } + key, _ := symmetric.NewRandom() + + hasher := fnv.New64() + hasher.Write(key.Bytes()) + + k.ReadKeys[name] = &SymKey{ + Hash: hasher.Sum64(), + Key: key, + } + k.ReadKeysByHash[hasher.Sum64()] = &SymKey{ + Hash: hasher.Sum64(), + Key: key, + } +} + +func (k *Keychain) AddKey(key string) { + parts := strings.Split(key, ".") + if len(parts) != 3 { + panic("cannot parse a key") + } + name := parts[2] + + switch parts[1] { + case "Sign": + k.AddSigningKey(name) + case "Enc": + k.AddEncryptionKey(name) + case "Read": + k.AddReadKey(name) + default: + panic("incorrect format") + } +} + +func (k *Keychain) GetKey(key string) interface{} { + parts := strings.Split(key, ".") + if len(parts) != 3 { + panic("cannot parse a key") + } + name := parts[2] + + switch parts[1] { + case "Sign": + if key, exists := k.SigningKeys[name]; exists { + return key + } + case "Enc": + if key, exists := k.EncryptionKeys[name]; exists { + return key + } + case "Read": + if key, exists := k.ReadKeys[name]; exists { + return key + } + default: + panic("incorrect format") + } + return nil +} + +func (k *Keychain) GetIdentity(name string) string { + return k.GeneratedIdentities[name] +} diff --git a/testutils/threadbuilder/threadbuilder.go b/testutils/threadbuilder/threadbuilder.go new file mode 100644 index 00000000..9778a607 --- /dev/null +++ b/testutils/threadbuilder/threadbuilder.go @@ -0,0 +1,543 @@ +package threadbuilder + +import ( + "context" + "fmt" + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges" + "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/yamltests" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" + "io/ioutil" + "path" + + "github.com/gogo/protobuf/proto" + "gopkg.in/yaml.v3" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + testpb "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/testchanges/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" + threadpb "github.com/anytypeio/go-anytype-infrastructure-experiments/thread/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" +) + +const plainTextDocType uint16 = 1 + +type threadChange struct { + *pb.ACLChange + id string + readKey *SymKey + signKey keys.SigningPrivKey + + changesDataDecrypted []byte +} + +type updateUseCase struct { + changes map[string]*threadChange +} + +type ThreadBuilder struct { + threadId string + allChanges map[string]*threadChange + updates map[string]*updateUseCase + heads []string + orphans []string + keychain *Keychain + header *threadpb.ThreadHeader +} + +func NewThreadBuilder(keychain *Keychain) *ThreadBuilder { + return &ThreadBuilder{ + allChanges: make(map[string]*threadChange), + updates: make(map[string]*updateUseCase), + keychain: keychain, + } +} + +func NewThreadBuilderWithTestName(name string) (*ThreadBuilder, error) { + filePath := path.Join(yamltests.Path(), name) + return NewThreadBuilderFromFile(filePath) +} + +func NewThreadBuilderFromFile(file string) (*ThreadBuilder, error) { + content, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + thread := YMLThread{} + err = yaml.Unmarshal(content, &thread) + if err != nil { + return nil, err + } + + tb := NewThreadBuilder(NewKeychain()) + tb.Parse(&thread) + + return tb, nil +} + +func (t *ThreadBuilder) ID() string { + return t.threadId +} + +func (t *ThreadBuilder) GetKeychain() *Keychain { + return t.keychain +} + +func (t *ThreadBuilder) Heads() []string { + return t.heads +} + +func (t *ThreadBuilder) AddRawChange(change *thread.RawChange) error { + aclChange := new(pb.ACLChange) + var err error + + if err = proto.Unmarshal(change.Payload, aclChange); err != nil { + return fmt.Errorf("could not unmarshall changes") + } + var changesData []byte + + // get correct readkey + readKey := t.keychain.ReadKeysByHash[aclChange.CurrentReadKeyHash] + if aclChange.ChangesData != nil { + changesData, err = readKey.Key.Decrypt(aclChange.ChangesData) + if err != nil { + return fmt.Errorf("failed to decrypt changes data: %w", err) + } + } + + // get correct signing key + signKey := t.keychain.SigningKeysByIdentity[aclChange.Identity] + + t.allChanges[change.Id] = &threadChange{ + ACLChange: aclChange, + id: change.Id, + readKey: readKey, + signKey: signKey, + changesDataDecrypted: changesData, + } + return nil +} + +func (t *ThreadBuilder) AddOrphans(orphans ...string) { + t.orphans = append(t.orphans, orphans...) +} + +func (t *ThreadBuilder) AddChange(change aclchanges.Change) error { + aclChange := change.ProtoChange() + var err error + var changesData []byte + + // get correct readkey + readKey := t.keychain.ReadKeysByHash[aclChange.CurrentReadKeyHash] + if aclChange.ChangesData != nil { + changesData, err = readKey.Key.Decrypt(aclChange.ChangesData) + if err != nil { + return fmt.Errorf("failed to decrypt changes data: %w", err) + } + } + + // get correct signing key + signKey := t.keychain.SigningKeysByIdentity[aclChange.Identity] + + t.allChanges[change.CID()] = &threadChange{ + ACLChange: aclChange, + id: change.CID(), + readKey: readKey, + signKey: signKey, + changesDataDecrypted: changesData, + } + return nil +} + +func (t *ThreadBuilder) Orphans() []string { + return t.orphans +} + +func (t *ThreadBuilder) SetHeads(heads []string) { + // we should copy here instead of just setting the value + t.heads = heads +} + +func (t *ThreadBuilder) RemoveOrphans(orphans ...string) { + t.orphans = slice.Difference(t.orphans, orphans) +} + +func (t *ThreadBuilder) GetChange(ctx context.Context, recordID string) (*thread.RawChange, error) { + return t.getChange(recordID, t.allChanges), nil +} + +func (t *ThreadBuilder) GetUpdates(useCase string) []*thread.RawChange { + var res []*thread.RawChange + update := t.updates[useCase] + for _, ch := range update.changes { + rawCh := t.getChange(ch.id, update.changes) + res = append(res, rawCh) + } + return res +} + +func (t *ThreadBuilder) Header() *threadpb.ThreadHeader { + return t.header +} + +func (t *ThreadBuilder) getChange(changeId string, m map[string]*threadChange) *thread.RawChange { + rec := m[changeId] + + if rec.changesDataDecrypted != nil { + encrypted, err := rec.readKey.Key.Encrypt(rec.changesDataDecrypted) + if err != nil { + panic("should be able to encrypt data with read key!") + } + + rec.ChangesData = encrypted + } + + aclMarshaled, err := proto.Marshal(rec.ACLChange) + if err != nil { + panic("should be able to marshal final acl message!") + } + + signature, err := rec.signKey.Sign(aclMarshaled) + if err != nil { + panic("should be able to sign final acl message!") + } + + transformedRec := &thread.RawChange{ + Payload: aclMarshaled, + Signature: signature, + Id: changeId, + } + return transformedRec +} + +func (t *ThreadBuilder) Parse(thread *YMLThread) { + // Just to clarify - we are generating new identities for the ones that + // are specified in the yml file, because our identities should be Ed25519 + // the same thing is happening for the encryption keys + t.keychain.ParseKeys(&thread.Keys) + t.threadId = t.parseThreadId(thread.Description) + for _, ch := range thread.Changes { + newChange := t.parseChange(ch) + t.allChanges[newChange.id] = newChange + } + + t.parseGraph(thread) + t.parseOrphans(thread) + t.parseHeader(thread) + t.parseUpdates(thread.Updates) +} + +func (t *ThreadBuilder) parseChange(ch *Change) *threadChange { + newChange := &threadChange{ + id: ch.Id, + } + k := t.keychain.GetKey(ch.ReadKey).(*SymKey) + newChange.readKey = k + newChange.signKey = t.keychain.SigningKeys[ch.Identity] + aclChange := &pb.ACLChange{} + aclChange.Identity = t.keychain.GetIdentity(ch.Identity) + if len(ch.AclChanges) > 0 || ch.AclSnapshot != nil { + aclChange.AclData = &pb.ACLChangeACLData{} + if ch.AclSnapshot != nil { + aclChange.AclData.AclSnapshot = t.parseACLSnapshot(ch.AclSnapshot) + } + if ch.AclChanges != nil { + var aclChangeContents []*pb.ACLChangeACLContentValue + for _, ch := range ch.AclChanges { + aclChangeContent := t.parseACLChange(ch) + aclChangeContents = append(aclChangeContents, aclChangeContent) + } + aclChange.AclData.AclContent = aclChangeContents + } + } + if len(ch.Changes) > 0 || ch.Snapshot != nil { + changesData := &testpb.PlainTextChangeData{} + if ch.Snapshot != nil { + changesData.Snapshot = t.parseChangeSnapshot(ch.Snapshot) + } + if len(ch.Changes) > 0 { + var changeContents []*testpb.PlainTextChangeContent + for _, ch := range ch.Changes { + aclChangeContent := t.parseDocumentChange(ch) + changeContents = append(changeContents, aclChangeContent) + } + changesData.Content = changeContents + } + m, err := proto.Marshal(changesData) + if err != nil { + return nil + } + newChange.changesDataDecrypted = m + } + aclChange.CurrentReadKeyHash = k.Hash + newChange.ACLChange = aclChange + return newChange +} + +func (t *ThreadBuilder) parseThreadId(description *ThreadDescription) string { + if description == nil { + panic("no author in thread") + } + key := t.keychain.SigningKeys[description.Author] + id, err := thread.CreateACLThreadID(key.GetPublic(), plainTextDocType) + if err != nil { + panic(err) + } + + return id.String() +} + +func (t *ThreadBuilder) parseChangeSnapshot(s *PlainTextSnapshot) *testpb.PlainTextChangeSnapshot { + return &testpb.PlainTextChangeSnapshot{ + Text: s.Text, + } +} + +func (t *ThreadBuilder) parseACLSnapshot(s *ACLSnapshot) *pb.ACLChangeACLSnapshot { + newState := &pb.ACLChangeACLState{} + for _, state := range s.UserStates { + aclUserState := &pb.ACLChangeUserState{} + aclUserState.Identity = t.keychain.GetIdentity(state.Identity) + + encKey := t.keychain. + GetKey(state.EncryptionKey).(keys.EncryptionPrivKey) + rawKey, _ := encKey.GetPublic().Raw() + aclUserState.EncryptionKey = rawKey + + aclUserState.EncryptedReadKeys = t.encryptReadKeys(state.EncryptedReadKeys, encKey) + aclUserState.Permissions = t.convertPermission(state.Permissions) + newState.UserStates = append(newState.UserStates, aclUserState) + } + return &pb.ACLChangeACLSnapshot{ + AclState: newState, + } +} + +func (t *ThreadBuilder) parseDocumentChange(ch *PlainTextChange) (convCh *testpb.PlainTextChangeContent) { + switch { + case ch.TextAppend != nil: + convCh = &testpb.PlainTextChangeContent{ + Value: &testpb.PlainTextChangeContentValueOfTextAppend{ + TextAppend: &testpb.PlainTextChangeTextAppend{ + Text: ch.TextAppend.Text, + }, + }, + } + } + if convCh == nil { + panic("cannot have empty document change") + } + + return convCh +} + +func (t *ThreadBuilder) parseACLChange(ch *ACLChange) (convCh *pb.ACLChangeACLContentValue) { + switch { + case ch.UserAdd != nil: + add := ch.UserAdd + + encKey := t.keychain. + GetKey(add.EncryptionKey).(keys.EncryptionPrivKey) + rawKey, _ := encKey.GetPublic().Raw() + + convCh = &pb.ACLChangeACLContentValue{ + Value: &pb.ACLChangeACLContentValueValueOfUserAdd{ + UserAdd: &pb.ACLChangeUserAdd{ + Identity: t.keychain.GetIdentity(add.Identity), + EncryptionKey: rawKey, + EncryptedReadKeys: t.encryptReadKeys(add.EncryptedReadKeys, encKey), + Permissions: t.convertPermission(add.Permission), + }, + }, + } + case ch.UserJoin != nil: + join := ch.UserJoin + + encKey := t.keychain. + GetKey(join.EncryptionKey).(keys.EncryptionPrivKey) + rawKey, _ := encKey.GetPublic().Raw() + + idKey, _ := t.keychain.SigningKeys[join.Identity].GetPublic().Raw() + signKey := t.keychain.GetKey(join.AcceptSignature).(keys.SigningPrivKey) + signature, err := signKey.Sign(idKey) + if err != nil { + panic(err) + } + + convCh = &pb.ACLChangeACLContentValue{ + Value: &pb.ACLChangeACLContentValueValueOfUserJoin{ + UserJoin: &pb.ACLChangeUserJoin{ + Identity: t.keychain.GetIdentity(join.Identity), + EncryptionKey: rawKey, + AcceptSignature: signature, + UserInviteId: join.InviteId, + EncryptedReadKeys: t.encryptReadKeys(join.EncryptedReadKeys, encKey), + }, + }, + } + case ch.UserInvite != nil: + invite := ch.UserInvite + rawAcceptKey, _ := t.keychain.GetKey(invite.AcceptKey).(keys.SigningPrivKey).GetPublic().Raw() + encKey := t.keychain. + GetKey(invite.EncryptionKey).(keys.EncryptionPrivKey) + rawEncKey, _ := encKey.GetPublic().Raw() + + convCh = &pb.ACLChangeACLContentValue{ + Value: &pb.ACLChangeACLContentValueValueOfUserInvite{ + UserInvite: &pb.ACLChangeUserInvite{ + AcceptPublicKey: rawAcceptKey, + EncryptPublicKey: rawEncKey, + EncryptedReadKeys: t.encryptReadKeys(invite.EncryptedReadKeys, encKey), + Permissions: t.convertPermission(invite.Permissions), + InviteId: invite.InviteId, + }, + }, + } + case ch.UserConfirm != nil: + confirm := ch.UserConfirm + + convCh = &pb.ACLChangeACLContentValue{ + Value: &pb.ACLChangeACLContentValueValueOfUserConfirm{ + UserConfirm: &pb.ACLChangeUserConfirm{ + Identity: t.keychain.GetIdentity(confirm.Identity), + UserAddId: confirm.UserAddId, + }, + }, + } + case ch.UserPermissionChange != nil: + permissionChange := ch.UserPermissionChange + + convCh = &pb.ACLChangeACLContentValue{ + Value: &pb.ACLChangeACLContentValueValueOfUserPermissionChange{ + UserPermissionChange: &pb.ACLChangeUserPermissionChange{ + Identity: t.keychain.GetIdentity(permissionChange.Identity), + Permissions: t.convertPermission(permissionChange.Permission), + }, + }, + } + case ch.UserRemove != nil: + remove := ch.UserRemove + + newReadKey := t.keychain.GetKey(remove.NewReadKey).(*SymKey) + + var replaces []*pb.ACLChangeReadKeyReplace + for _, id := range remove.IdentitiesLeft { + identity := t.keychain.GetIdentity(id) + encKey := t.keychain.EncryptionKeys[id] + rawEncKey, _ := encKey.GetPublic().Raw() + encReadKey, err := encKey.GetPublic().Encrypt(newReadKey.Key.Bytes()) + if err != nil { + panic(err) + } + replaces = append(replaces, &pb.ACLChangeReadKeyReplace{ + Identity: identity, + EncryptionKey: rawEncKey, + EncryptedReadKey: encReadKey, + }) + } + + convCh = &pb.ACLChangeACLContentValue{ + Value: &pb.ACLChangeACLContentValueValueOfUserRemove{ + UserRemove: &pb.ACLChangeUserRemove{ + Identity: t.keychain.GetIdentity(remove.RemovedIdentity), + ReadKeyReplaces: replaces, + }, + }, + } + } + if convCh == nil { + panic("cannot have empty acl change") + } + + return convCh +} + +func (t *ThreadBuilder) encryptReadKeys(keys []string, encKey keys.EncryptionPrivKey) (enc [][]byte) { + for _, k := range keys { + realKey := t.keychain.GetKey(k).(*SymKey).Key.Bytes() + res, err := encKey.GetPublic().Encrypt(realKey) + if err != nil { + panic(err) + } + + enc = append(enc, res) + } + return +} + +func (t *ThreadBuilder) convertPermission(perm string) pb.ACLChangeUserPermissions { + switch perm { + case "admin": + return pb.ACLChange_Admin + case "writer": + return pb.ACLChange_Writer + case "reader": + return pb.ACLChange_Reader + default: + panic(fmt.Sprintf("incorrect permission: %s", perm)) + } +} + +func (t *ThreadBuilder) traverseFromHeads(f func(t *threadChange) error) error { + uniqMap := map[string]struct{}{} + stack := make([]string, len(t.orphans), 10) + copy(stack, t.orphans) + for len(stack) > 0 { + id := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if _, exists := uniqMap[id]; exists { + continue + } + + ch := t.allChanges[id] + uniqMap[id] = struct{}{} + if err := f(ch); err != nil { + return err + } + + for _, prev := range ch.ACLChange.TreeHeadIds { + stack = append(stack, prev) + } + } + return nil +} + +func (t *ThreadBuilder) parseUpdates(updates []*Update) { + for _, update := range updates { + useCase := &updateUseCase{ + changes: map[string]*threadChange{}, + } + for _, ch := range update.Changes { + newChange := t.parseChange(ch) + useCase.changes[newChange.id] = newChange + } + for _, node := range update.Graph { + rec := useCase.changes[node.Id] + rec.AclHeadIds = node.ACLHeads + rec.TreeHeadIds = node.TreeHeads + rec.SnapshotBaseId = node.BaseSnapshot + } + + t.updates[update.UseCase] = useCase + } +} + +func (t *ThreadBuilder) parseGraph(thread *YMLThread) { + for _, node := range thread.Graph { + rec := t.allChanges[node.Id] + rec.AclHeadIds = node.ACLHeads + rec.TreeHeadIds = node.TreeHeads + rec.SnapshotBaseId = node.BaseSnapshot + } +} + +func (t *ThreadBuilder) parseOrphans(thread *YMLThread) { + t.orphans = thread.Orphans +} + +func (t *ThreadBuilder) parseHeader(thread *YMLThread) { + t.header = &threadpb.ThreadHeader{ + FirstChangeId: thread.Header.FirstChangeId, + IsWorkspace: thread.Header.IsWorkspace, + } +} diff --git a/testutils/threadbuilder/threadbuildergraph.go b/testutils/threadbuilder/threadbuildergraph.go new file mode 100644 index 00000000..edb98971 --- /dev/null +++ b/testutils/threadbuilder/threadbuildergraph.go @@ -0,0 +1,11 @@ +//go:build ((!linux && !darwin) || android || ios || nographviz) && !amd64 +// +build !linux,!darwin android ios nographviz +// +build !amd64 + +package threadbuilder + +import "fmt" + +func (t *ThreadBuilder) Graph() (string, error) { + return "", fmt.Errorf("building graphs is not supported") +} diff --git a/testutils/threadbuilder/threadbuildergraph_nix.go b/testutils/threadbuilder/threadbuildergraph_nix.go new file mode 100644 index 00000000..cca8ad30 --- /dev/null +++ b/testutils/threadbuilder/threadbuildergraph_nix.go @@ -0,0 +1,163 @@ +//go:build (linux || darwin) && !android && !ios && !nographviz && (amd64 || arm64) +// +build linux darwin +// +build !android +// +build !ios +// +build !nographviz +// +build amd64 arm64 + +package threadbuilder + +import ( + "fmt" + + "github.com/gogo/protobuf/proto" + "strings" + "unicode" + + "github.com/awalterschulze/gographviz" + + testpb "github.com/anytypeio/go-anytype-infrastructure-experiments/testutils/testchanges/pb" +) + +// To quickly look at visualized string you can use https://dreampuf.github.io/GraphvizOnline + +type EdgeParameters struct { + style string + color string + label string +} + +func (t *ThreadBuilder) Graph() (string, error) { + // TODO: check updates on https://github.com/goccy/go-graphviz/issues/52 or make a fix yourself to use better library here + graph := gographviz.NewGraph() + graph.SetName("G") + graph.SetDir(true) + var nodes = make(map[string]struct{}) + + var addNodes = func(r *threadChange) error { + // TODO: revisit function after checking + + style := "solid" + if r.GetAclData() != nil { + style = "filled" + } else if r.changesDataDecrypted != nil { + style = "dashed" + } + + var chSymbs []string + if r.changesDataDecrypted != nil { + res := &testpb.PlainTextChangeData{} + err := proto.Unmarshal(r.changesDataDecrypted, res) + if err != nil { + return err + } + + for _, chc := range res.Content { + tp := fmt.Sprintf("%T", chc.Value) + tp = strings.Replace(tp, "ChangeContentValueOf", "", 1) + res := "" + for _, ts := range tp { + if unicode.IsUpper(ts) { + res += string(ts) + } + } + chSymbs = append(chSymbs, res) + } + } + if r.GetAclData() != nil { + for _, chc := range r.GetAclData().AclContent { + tp := fmt.Sprintf("%T", chc.Value) + tp = strings.Replace(tp, "ACLChangeACLContentValueValueOf", "", 1) + res := "" + for _, ts := range tp { + if unicode.IsUpper(ts) { + res += string(ts) + } + } + chSymbs = append(chSymbs, res) + } + } + + shortId := r.id + label := fmt.Sprintf("Id: %s\nChanges: %s\n", + shortId, + strings.Join(chSymbs, ","), + ) + e := graph.AddNode("G", "\""+r.id+"\"", map[string]string{ + "label": "\"" + label + "\"", + "style": "\"" + style + "\"", + }) + if e != nil { + return e + } + nodes[r.id] = struct{}{} + return nil + } + + var createEdge = func(firstId, secondId string, params EdgeParameters) error { + _, exists := nodes[firstId] + if !exists { + return fmt.Errorf("no such node") + } + _, exists = nodes[secondId] + if !exists { + return fmt.Errorf("no previous node") + } + + err := graph.AddEdge("\""+firstId+"\"", "\""+secondId+"\"", true, map[string]string{ + "color": params.color, + "style": params.style, + }) + if err != nil { + return err + } + + return nil + } + + var addLinks = func(t *threadChange) error { + for _, prevId := range t.AclHeadIds { + err := createEdge(t.id, prevId, EdgeParameters{ + style: "dashed", + color: "red", + }) + if err != nil { + return err + } + } + + for _, prevId := range t.TreeHeadIds { + err := createEdge(t.id, prevId, EdgeParameters{ + style: "dashed", + color: "blue", + }) + if err != nil { + return err + } + } + + if t.SnapshotBaseId != "" { + err := createEdge(t.id, t.SnapshotBaseId, EdgeParameters{ + style: "bold", + color: "blue", + }) + if err != nil { + return err + } + } + + return nil + } + + err := t.traverseFromHeads(addNodes) + if err != nil { + return "", err + } + + err = t.traverseFromHeads(addLinks) + if err != nil { + return "", err + } + + return graph.String(), nil +} diff --git a/testutils/threadbuilder/ymlentities.go b/testutils/threadbuilder/ymlentities.go new file mode 100644 index 00000000..34d9cbaf --- /dev/null +++ b/testutils/threadbuilder/ymlentities.go @@ -0,0 +1,117 @@ +package threadbuilder + +type ThreadDescription struct { + Author string `yaml:"author"` +} + +type Keys struct { + Enc []string `yaml:"Enc"` + Sign []string `yaml:"Sign"` + Read []string `yaml:"Read"` +} + +type ACLSnapshot struct { + UserStates []struct { + Identity string `yaml:"identity"` + EncryptionKey string `yaml:"encryptionKey"` + EncryptedReadKeys []string `yaml:"encryptedReadKeys"` + Permissions string `yaml:"permission"` + IsConfirmed bool `yaml:"isConfirmed"` + } `yaml:"userStates"` +} + +type PlainTextSnapshot struct { + Text string `yaml:"text"` +} + +type ACLChange struct { + UserAdd *struct { + Identity string `yaml:"identity"` + EncryptionKey string `yaml:"encryptionKey"` + EncryptedReadKeys []string `yaml:"encryptedReadKeys"` + Permission string `yaml:"permission"` + } `yaml:"userAdd"` + + UserJoin *struct { + Identity string `yaml:"identity"` + EncryptionKey string `yaml:"encryptionKey"` + AcceptSignature string `yaml:"acceptSignature"` + InviteId string `yaml:"inviteId"` + EncryptedReadKeys []string `yaml:"encryptedReadKeys"` + } `yaml:"userJoin"` + + UserInvite *struct { + AcceptKey string `yaml:"acceptKey"` + EncryptionKey string `yaml:"encryptionKey"` + EncryptedReadKeys []string `yaml:"encryptedReadKeys"` + Permissions string `yaml:"permissions"` + InviteId string `yaml:"inviteId"` + } `yaml:"userInvite"` + + UserConfirm *struct { + Identity string `yaml:"identity"` + UserAddId string `yaml:"UserAddId"` + } `yaml:"userConfirm"` + + UserRemove *struct { + RemovedIdentity string `yaml:"removedIdentity"` + NewReadKey string `yaml:"newReadKey"` + IdentitiesLeft []string `yaml:"identitiesLeft"` + } `yaml:"userRemove"` + + UserPermissionChange *struct { + Identity string `yaml:"identity"` + Permission string `yaml:"permission"` + } +} + +type PlainTextChange struct { + TextAppend *struct { + Text string `yaml:"text"` + } `yaml:"textAppend"` +} + +type GraphNode struct { + Id string `yaml:"id"` + BaseSnapshot string `yaml:"baseSnapshot"` + AclSnapshot string `yaml:"aclSnapshot"` + ACLHeads []string `yaml:"aclHeads"` + TreeHeads []string `yaml:"treeHeads"` +} + +type Change struct { + Id string `yaml:"id"` + Identity string `yaml:"identity"` + + AclSnapshot *ACLSnapshot `yaml:"aclSnapshot"` + Snapshot *PlainTextSnapshot `yaml:"snapshot"` + AclChanges []*ACLChange `yaml:"aclChanges"` + Changes []*PlainTextChange `yaml:"changes"` + + ReadKey string `yaml:"readKey"` +} + +type Header struct { + FirstChangeId string `yaml:"firstChangeId"` + IsWorkspace bool `yaml:"isWorkspace"` +} + +type Update struct { + UseCase string `yaml:"useCase"` + Changes []*Change `yaml:"changes"` + Graph []*GraphNode `yaml:"graph"` +} + +type YMLThread struct { + Description *ThreadDescription `yaml:"thread"` + Changes []*Change `yaml:"changes"` + Updates []*Update `yaml:"updates"` + + Keys Keys `yaml:"keys"` + + Graph []*GraphNode `yaml:"graph"` + + Heads []string `yaml:"heads"` + Orphans []string `yaml:"orphans"` + Header *Header `yaml:"header"` +} diff --git a/testutils/threadbuilder/ymlentities_test.go b/testutils/threadbuilder/ymlentities_test.go new file mode 100644 index 00000000..a702152b --- /dev/null +++ b/testutils/threadbuilder/ymlentities_test.go @@ -0,0 +1,12 @@ +package threadbuilder + +import ( + "fmt" + "testing" +) + +func Test_YamlParse(t *testing.T) { + tb, _ := NewThreadBuilderWithTestName("userjoinexampleupdate.yml") + gr, _ := tb.Graph() + fmt.Println(gr) +} diff --git a/testutils/yamltests/invalidsnapshotexample.yml b/testutils/yamltests/invalidsnapshotexample.yml new file mode 100644 index 00000000..e592f7d6 --- /dev/null +++ b/testutils/yamltests/invalidsnapshotexample.yml @@ -0,0 +1,126 @@ +thread: + author: A +changes: + - id: A.1.1 + identity: A + aclSnapshot: + userStates: + - identity: A + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + permission: admin + - identity: B + encryptionKey: key.Enc.B + encryptedReadKeys: [key.Read.1] + permission: admin + snapshot: + text: "some text" + aclChanges: + - userAdd: + identity: A + permission: admin + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + - userAdd: + identity: B + permission: admin + encryptionKey: key.Enc.B + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 + - id: A.1.2 + identity: A + aclSnapshot: + userStates: + - identity: A + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + permission: admin + - identity: B + encryptionKey: key.Enc.B + encryptedReadKeys: [key.Read.1] + permission: admin + - identity: D + encryptionKey: key.Enc.D + encryptedReadKeys: [ key.Read.1 ] + permission: admin + snapshot: + text: "some text" + aclChanges: + - userAdd: + identity: D + permission: admin + encryptionKey: key.Enc.D + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 + - id: A.1.3 + identity: A + aclChanges: + - userAdd: + identity: E + permission: admin + encryptionKey: key.Enc.E + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 + - id: B.1.1 + identity: B + aclChanges: + - userAdd: + identity: C + permission: admin + encryptionKey: key.Enc.C + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 + - id: B.1.2 + identity: B + aclChanges: + - userAdd: + identity: F + permission: admin + encryptionKey: key.Enc.F + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 +keys: + Enc: + - A + - B + - C + - D + - E + - F + Sign: + - A + - B + - C + - D + - E + - F + Read: + - 1 + - 2 +graph: + - id: A.1.1 + baseSnapshot: A.1.1 + aclSnapshot: A.1.1 + - id: A.1.2 + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] + - id: B.1.1 + baseSnapshot: A.1.1 + aclHeads: [A.1.1] + treeHeads: [A.1.1] + - id: B.1.2 + baseSnapshot: A.1.2 + aclHeads: [A.1.2] + treeHeads: [A.1.2] + - id: A.1.3 + baseSnapshot: A.1.2 + aclHeads: [A.1.2] + treeHeads: [A.1.2] +header: + firstChangeId: A.1.1 + isWorkspace: false +orphans: + - A.1.3 + - B.1.2 + diff --git a/testutils/yamltests/path.go b/testutils/yamltests/path.go new file mode 100644 index 00000000..c2dd2712 --- /dev/null +++ b/testutils/yamltests/path.go @@ -0,0 +1,15 @@ +package yamltests + +import ( + "path/filepath" + "runtime" +) + +var ( + _, b, _, _ = runtime.Caller(0) + basepath = filepath.Dir(b) +) + +func Path() string { + return basepath +} diff --git a/testutils/yamltests/userjoinexample.yml b/testutils/yamltests/userjoinexample.yml new file mode 100644 index 00000000..2736d311 --- /dev/null +++ b/testutils/yamltests/userjoinexample.yml @@ -0,0 +1,107 @@ +thread: + author: A +changes: + - id: A.1.1 + identity: A + aclSnapshot: + userStates: + - identity: A + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + permission: admin + snapshot: + text: "some text" + aclChanges: + - userAdd: + identity: A + permission: admin + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + changes: + - textAppend: + text: "some text" + readKey: key.Read.1 + - id: A.1.2 + identity: A + aclChanges: + - userInvite: + acceptKey: key.Sign.Onetime1 + encryptionKey: key.Enc.Onetime1 + encryptedReadKeys: [key.Read.1] + permissions: writer + inviteId: A.1.2 + - userAdd: + identity: C + permission: reader + encryptionKey: key.Enc.C + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 + - id: A.1.3 + identity: A + changes: + - textAppend: + text: "second" + readKey: key.Read.1 + - id: B.1.1 + identity: B + aclChanges: + - userJoin: + identity: B + encryptionKey: key.Enc.B + acceptSignature: key.Sign.Onetime1 + inviteId: A.1.2 + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 + - id: B.1.2 + identity: B + changes: + - textAppend: + text: "first" + readKey: key.Read.1 + - id: C.1.1 + identity: C + changes: + - textAppend: + text: "third" + readKey: key.Read.1 +keys: + Enc: + - A + - B + - C + - Onetime1 + Sign: + - A + - B + - C + - Onetime1 + Read: + - 1 +graph: + - id: A.1.1 + baseSnapshot: A.1.1 + - id: A.1.2 + baseSnapshot: A.1.1 + aclHeads: [A.1.1] + treeHeads: [A.1.1] + - id: B.1.1 + baseSnapshot: A.1.1 + aclHeads: [A.1.2] + treeHeads: [A.1.2] + - id: B.1.2 + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] + - id: A.1.3 # this should be invalid, because it is based on one of the invalid changes + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.2, C.1.1] + - id: C.1.1 # this should be invalid, because C is a reader + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] +header: + firstChangeId: A.1.1 + isWorkspace: false +orphans: + - "A.1.3" diff --git a/testutils/yamltests/userjoinexampleupdate.yml b/testutils/yamltests/userjoinexampleupdate.yml new file mode 100644 index 00000000..04ea7450 --- /dev/null +++ b/testutils/yamltests/userjoinexampleupdate.yml @@ -0,0 +1,152 @@ +thread: + author: A +changes: + - id: A.1.1 + identity: A + aclSnapshot: + userStates: + - identity: A + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + permission: admin + snapshot: + text: "some text" + aclChanges: + - userAdd: + identity: A + permission: admin + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + changes: + - textAppend: + text: "some text" + readKey: key.Read.1 + - id: A.1.2 + identity: A + aclChanges: + - userInvite: + acceptKey: key.Sign.Onetime1 + encryptionKey: key.Enc.Onetime1 + encryptedReadKeys: [key.Read.1] + permissions: writer + inviteId: A.1.2 + - userAdd: + identity: C + permission: reader + encryptionKey: key.Enc.C + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 + - id: A.1.3 + identity: A + changes: + - textAppend: + text: "second" + readKey: key.Read.1 + - id: B.1.1 + identity: B + aclChanges: + - userJoin: + identity: B + encryptionKey: key.Enc.B + acceptSignature: key.Sign.Onetime1 + inviteId: A.1.2 + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 + - id: B.1.2 + identity: B + changes: + - textAppend: + text: "first" + readKey: key.Read.1 + - id: C.1.1 + identity: C + changes: + - textAppend: + text: "third" + readKey: key.Read.1 +keys: + Enc: + - A + - B + - C + - D + - Onetime1 + Sign: + - A + - B + - C + - D + - Onetime1 + Read: + - 1 +graph: + - id: A.1.1 + baseSnapshot: A.1.1 + - id: A.1.2 + baseSnapshot: A.1.1 + aclHeads: [A.1.1] + treeHeads: [A.1.1] + - id: B.1.1 + baseSnapshot: A.1.1 + aclHeads: [A.1.2] + treeHeads: [A.1.2] + - id: B.1.2 + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] + - id: A.1.3 # this should be invalid, because it is based on one of the invalid changes + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.2, C.1.1] + - id: C.1.1 # this should be invalid, because C is a reader + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] +header: + firstChangeId: A.1.1 + isWorkspace: false +orphans: + - "A.1.3" +updates: + - useCase: append + changes: + - id: B.1.3 + identity: B + changes: + - textAppend: + text: "second" + readKey: key.Read.1 + - id: A.1.4 + identity: A + aclChanges: + - userAdd: + identity: D + permission: writer + encryptionKey: key.Enc.D + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 + graph: + - id: B.1.3 + baseSnapshot: A.1.1 + aclHeads: [ B.1.1 ] + treeHeads: [ B.1.2 ] + - id: A.1.4 + baseSnapshot: A.1.1 + aclHeads: [ B.1.1 ] + treeHeads: [ B.1.3 ] + - useCase: rebuild + changes: + - id: A.1.4 + identity: A + aclChanges: + - userAdd: + identity: D + permission: writer + encryptionKey: key.Enc.D + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 + graph: + - id: A.1.4 + baseSnapshot: A.1.1 + aclHeads: [ A.1.1 ] + treeHeads: [ A.1.1 ] diff --git a/testutils/yamltests/userremovebeforeexample.yml b/testutils/yamltests/userremovebeforeexample.yml new file mode 100644 index 00000000..c19ccaa6 --- /dev/null +++ b/testutils/yamltests/userremovebeforeexample.yml @@ -0,0 +1,109 @@ +thread: + author: A +changes: + - id: A.1.1 + identity: A + aclSnapshot: + userStates: + - identity: A + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + permission: admin + - identity: B + encryptionKey: key.Enc.B + encryptedReadKeys: [key.Read.1] + permission: admin + snapshot: + text: "some text" + aclChanges: + - userAdd: + identity: A + permission: admin + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + - userAdd: + identity: B + permission: admin + encryptionKey: key.Enc.B + encryptedReadKeys: [key.Read.1] + changes: + - textAppend: + text: "some text" + readKey: key.Read.1 + - id: A.1.2 + identity: A + aclChanges: + - userRemove: + removedIdentity: B + newReadKey: key.Read.2 + identitiesLeft: [A, C] + readKey: key.Read.2 + - id: A.1.3 + identity: A + aclChanges: + - userAdd: + identity: E + permission: admin + encryptionKey: key.Enc.E + encryptedReadKeys: [key.Read.1, key.Read.2] + readKey: key.Read.2 + - id: B.1.1 + identity: B + aclChanges: + - userAdd: + identity: C + permission: admin + encryptionKey: key.Enc.C + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 + - id: B.1.2 + identity: B + aclChanges: + - userAdd: + identity: D + permission: admin + encryptionKey: key.Enc.D + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 +keys: + Enc: + - A + - B + - C + - D + - E + Sign: + - A + - B + - C + - D + - E + Read: + - 1 + - 2 +graph: + - id: A.1.1 + baseSnapshot: A.1.1 + aclSnapshot: A.1.1 + - id: A.1.2 + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] + - id: B.1.1 + baseSnapshot: A.1.1 + aclHeads: [A.1.1] + treeHeads: [A.1.1] + - id: B.1.2 + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] + - id: A.1.3 + baseSnapshot: A.1.1 + aclHeads: [A.1.2] + treeHeads: [A.1.2] +orphans: + - "A.1.3" + - "B.1.2" +header: + firstChangeId: A.1.1 + isWorkspace: false diff --git a/testutils/yamltests/userremoveexample.yml b/testutils/yamltests/userremoveexample.yml new file mode 100644 index 00000000..bf1dfc57 --- /dev/null +++ b/testutils/yamltests/userremoveexample.yml @@ -0,0 +1,110 @@ +thread: + author: A +changes: + - id: A.1.1 + identity: A + aclSnapshot: + userStates: + - identity: A + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + permission: admin + snapshot: + text: "some text" + aclChanges: + - userAdd: + identity: A + permission: admin + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + changes: + - textAppend: + text: "some text" + readKey: key.Read.1 + - id: A.1.2 + identity: A + aclChanges: + - userInvite: + acceptKey: key.Sign.Onetime1 + encryptionKey: key.Enc.Onetime1 + encryptedReadKeys: [key.Read.1] + permissions: writer + inviteId: A.1.2 + readKey: key.Read.1 + - id: A.1.3 + identity: A + aclChanges: + - userRemove: + removedIdentity: B + newReadKey: key.Read.2 + identitiesLeft: [A] + readKey: key.Read.2 + - id: A.1.4 + identity: A + changes: + - textAppend: + text: "first" + readKey: key.Read.2 + - id: B.1.1 + identity: B + aclChanges: + - userJoin: + identity: B + encryptionKey: key.Enc.B + acceptSignature: key.Sign.Onetime1 + inviteId: A.1.2 + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 + - id: B.1.2 + identity: B + changes: + - textAppend: + text: "second" + readKey: key.Read.1 +keys: + Enc: + - A + - B + - Onetime1 + Sign: + - A + - B + - Onetime1 + Read: + - 1 + - 2 +graph: + - id: A.1.1 + baseSnapshot: A.1.1 + aclSnapshot: A.1.1 + - id: A.1.2 + baseSnapshot: A.1.1 + aclSnapshot: A.1.1 + aclHeads: [A.1.1] + treeHeads: [A.1.1] + - id: B.1.1 + baseSnapshot: A.1.1 + aclSnapshot: A.1.1 + aclHeads: [A.1.2] + treeHeads: [A.1.2] + - id: B.1.2 + baseSnapshot: A.1.1 + aclSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] + - id: A.1.3 + baseSnapshot: A.1.1 + aclSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] + - id: A.1.4 + baseSnapshot: A.1.1 + aclSnapshot: A.1.1 + aclHeads: [A.1.3] + treeHeads: [A.1.3] +orphans: + - "A.1.4" + - "B.1.2" +header: + firstChangeId: A.1.1 + isWorkspace: false diff --git a/testutils/yamltests/validsnapshotexample.yml b/testutils/yamltests/validsnapshotexample.yml new file mode 100644 index 00000000..9d5821ec --- /dev/null +++ b/testutils/yamltests/validsnapshotexample.yml @@ -0,0 +1,133 @@ +thread: + author: A +changes: + - id: A.1.1 + identity: A + aclSnapshot: + userStates: + - identity: A + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + permission: admin + - identity: B + encryptionKey: key.Enc.B + encryptedReadKeys: [key.Read.1] + permission: admin + snapshot: + text: "some text" + aclChanges: + - userAdd: + identity: A + permission: admin + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + - userAdd: + identity: B + permission: admin + encryptionKey: key.Enc.B + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 + changes: + - textAppend: + text: "some text" + - id: A.1.2 + identity: A + aclSnapshot: + userStates: + - identity: A + encryptionKey: key.Enc.A + encryptedReadKeys: [key.Read.1] + permission: admin + - identity: B + encryptionKey: key.Enc.B + encryptedReadKeys: [key.Read.1] + permission: admin + - identity: C + encryptionKey: key.Enc.C + encryptedReadKeys: [ key.Read.1 ] + permission: admin + - identity: D + encryptionKey: key.Enc.D + encryptedReadKeys: [ key.Read.1 ] + permission: admin + snapshot: + text: "some text" + aclChanges: + - userAdd: + identity: D + permission: admin + encryptionKey: key.Enc.D + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 + - id: A.1.3 + identity: A + aclChanges: + - userAdd: + identity: E + permission: admin + encryptionKey: key.Enc.E + encryptedReadKeys: [key.Read.1] + readKey: key.Read.1 + - id: B.1.1 + identity: B + aclChanges: + - userAdd: + identity: C + permission: admin + encryptionKey: key.Enc.C + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 + - id: B.1.2 + identity: B + aclChanges: + - userAdd: + identity: F + permission: admin + encryptionKey: key.Enc.F + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 +keys: + Enc: + - A + - B + - C + - D + - E + - F + Sign: + - A + - B + - C + - D + - E + - F + Read: + - 1 + - 2 +graph: + - id: A.1.1 + baseSnapshot: A.1.1 + aclSnapshot: A.1.1 + - id: A.1.2 + baseSnapshot: A.1.1 + aclHeads: [B.1.1] + treeHeads: [B.1.1] + - id: B.1.1 + baseSnapshot: A.1.1 + aclHeads: [A.1.1] + treeHeads: [A.1.1] + - id: B.1.2 + baseSnapshot: A.1.2 + aclHeads: [A.1.2] + treeHeads: [A.1.2] + - id: A.1.3 + baseSnapshot: A.1.2 + aclHeads: [A.1.2] + treeHeads: [A.1.2] +orphans: + - "A.1.3" + - "B.1.2" +header: + firstChangeId: A.1.1 + isWorkspace: false + diff --git a/thread/inmemory.go b/thread/inmemory.go new file mode 100644 index 00000000..484428ee --- /dev/null +++ b/thread/inmemory.go @@ -0,0 +1,132 @@ +package thread + +import ( + "context" + "fmt" + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" + "github.com/gogo/protobuf/proto" + "sync" +) + +type inMemoryThread struct { + id string + header *pb.ThreadHeader + heads []string + orphans []string + changes map[string]*RawChange + + sync.RWMutex +} + +func NewInMemoryThread(firstChange *RawChange) (Thread, error) { + header := &pb.ThreadHeader{ + FirstChangeId: firstChange.Id, + IsWorkspace: false, + } + marshalledHeader, err := proto.Marshal(header) + if err != nil { + return nil, err + } + threadId, err := cid.NewCIDFromBytes(marshalledHeader) + if err != nil { + return nil, err + } + + changes := make(map[string]*RawChange) + changes[firstChange.Id] = firstChange + + return &inMemoryThread{ + id: threadId, + header: header, + heads: []string{firstChange.Id}, + orphans: nil, + changes: changes, + RWMutex: sync.RWMutex{}, + }, nil +} + +func (t *inMemoryThread) ID() string { + t.RLock() + defer t.RUnlock() + return t.id +} + +func (t *inMemoryThread) Header() *pb.ThreadHeader { + t.RLock() + defer t.RUnlock() + return t.header +} + +func (t *inMemoryThread) Heads() []string { + t.RLock() + defer t.RUnlock() + return t.heads +} + +func (t *inMemoryThread) Orphans() []string { + t.RLock() + defer t.RUnlock() + return t.orphans +} + +func (t *inMemoryThread) SetHeads(heads []string) { + t.Lock() + defer t.Unlock() + t.heads = t.heads[:0] + + for _, h := range heads { + t.heads = append(t.heads, h) + } +} + +func (t *inMemoryThread) RemoveOrphans(orphans ...string) { + t.Lock() + defer t.Unlock() + t.orphans = slice.Difference(t.orphans, orphans) +} + +func (t *inMemoryThread) AddOrphans(orphans ...string) { + t.Lock() + defer t.Unlock() + t.orphans = append(t.orphans, orphans...) +} + +func (t *inMemoryThread) AddRawChange(change *RawChange) error { + t.Lock() + defer t.Unlock() + // TODO: better to do deep copy + t.changes[change.Id] = change + return nil +} + +func (t *inMemoryThread) AddChange(change aclchanges.Change) error { + t.Lock() + defer t.Unlock() + signature := change.Signature() + id := change.CID() + aclChange := change.ProtoChange() + + fullMarshalledChange, err := proto.Marshal(aclChange) + if err != nil { + return err + } + rawChange := &RawChange{ + Payload: fullMarshalledChange, + Signature: signature, + Id: id, + } + t.changes[id] = rawChange + return nil +} + +func (t *inMemoryThread) GetChange(ctx context.Context, changeId string) (*RawChange, error) { + t.RLock() + defer t.RUnlock() + if res, exists := t.changes[changeId]; exists { + return res, nil + } + return nil, fmt.Errorf("could not get change with id: %s", changeId) +} diff --git a/thread/models.go b/thread/models.go new file mode 100644 index 00000000..7a10ff67 --- /dev/null +++ b/thread/models.go @@ -0,0 +1,32 @@ +package thread + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread/pb" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges" +) + +// TODO: change methods to have errors as a return parameter, because we will be dealing with a real database +type Thread interface { + ID() string + + Header() *pb.ThreadHeader + Heads() []string + Orphans() []string + SetHeads(heads []string) + RemoveOrphans(orphan ...string) + AddOrphans(orphan ...string) + + AddRawChange(change *RawChange) error + AddChange(change aclchanges.Change) error + + // TODO: have methods with raw changes also + GetChange(ctx context.Context, recordID string) (*RawChange, error) +} + +type RawChange struct { + Payload []byte + Signature []byte + Id string +} diff --git a/thread/pb/protos/thread.proto b/thread/pb/protos/thread.proto new file mode 100644 index 00000000..97557b25 --- /dev/null +++ b/thread/pb/protos/thread.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; +package anytype; +option go_package = "pb"; + +message ThreadHeader { + string firstChangeId = 1; + bool isWorkspace = 2; + // TODO: add user identity, signature and nano timestamp +} \ No newline at end of file diff --git a/thread/pb/thread.pb.go b/thread/pb/thread.pb.go new file mode 100644 index 00000000..e941b634 --- /dev/null +++ b/thread/pb/thread.pb.go @@ -0,0 +1,355 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: thread/pb/protos/thread.proto + +package pb + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type ThreadHeader struct { + FirstChangeId string `protobuf:"bytes,1,opt,name=firstChangeId,proto3" json:"firstChangeId,omitempty"` + IsWorkspace bool `protobuf:"varint,2,opt,name=isWorkspace,proto3" json:"isWorkspace,omitempty"` +} + +func (m *ThreadHeader) Reset() { *m = ThreadHeader{} } +func (m *ThreadHeader) String() string { return proto.CompactTextString(m) } +func (*ThreadHeader) ProtoMessage() {} +func (*ThreadHeader) Descriptor() ([]byte, []int) { + return fileDescriptor_b228ffbfd554b168, []int{0} +} +func (m *ThreadHeader) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ThreadHeader) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ThreadHeader.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ThreadHeader) XXX_Merge(src proto.Message) { + xxx_messageInfo_ThreadHeader.Merge(m, src) +} +func (m *ThreadHeader) XXX_Size() int { + return m.Size() +} +func (m *ThreadHeader) XXX_DiscardUnknown() { + xxx_messageInfo_ThreadHeader.DiscardUnknown(m) +} + +var xxx_messageInfo_ThreadHeader proto.InternalMessageInfo + +func (m *ThreadHeader) GetFirstChangeId() string { + if m != nil { + return m.FirstChangeId + } + return "" +} + +func (m *ThreadHeader) GetIsWorkspace() bool { + if m != nil { + return m.IsWorkspace + } + return false +} + +func init() { + proto.RegisterType((*ThreadHeader)(nil), "anytype.ThreadHeader") +} + +func init() { proto.RegisterFile("thread/pb/protos/thread.proto", fileDescriptor_b228ffbfd554b168) } + +var fileDescriptor_b228ffbfd554b168 = []byte{ + // 156 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2d, 0xc9, 0x28, 0x4a, + 0x4d, 0x4c, 0xd1, 0x2f, 0x48, 0xd2, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x2f, 0xd6, 0x87, 0x08, 0xe8, + 0x81, 0x79, 0x42, 0xec, 0x89, 0x79, 0x95, 0x25, 0x95, 0x05, 0xa9, 0x4a, 0x61, 0x5c, 0x3c, 0x21, + 0x60, 0x09, 0x8f, 0xd4, 0xc4, 0x94, 0xd4, 0x22, 0x21, 0x15, 0x2e, 0xde, 0xb4, 0xcc, 0xa2, 0xe2, + 0x12, 0xe7, 0x8c, 0xc4, 0xbc, 0xf4, 0x54, 0xcf, 0x14, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, + 0x54, 0x41, 0x21, 0x05, 0x2e, 0xee, 0xcc, 0xe2, 0xf0, 0xfc, 0xa2, 0xec, 0xe2, 0x82, 0xc4, 0xe4, + 0x54, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x8e, 0x20, 0x64, 0x21, 0x27, 0x99, 0x13, 0x8f, 0xe4, 0x18, + 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, + 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x62, 0x2a, 0x48, 0x4a, 0x62, 0x03, 0xbb, 0xc2, 0x18, 0x10, + 0x00, 0x00, 0xff, 0xff, 0x2a, 0xae, 0x9d, 0xc2, 0xa6, 0x00, 0x00, 0x00, +} + +func (m *ThreadHeader) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ThreadHeader) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ThreadHeader) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.IsWorkspace { + i-- + if m.IsWorkspace { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.FirstChangeId) > 0 { + i -= len(m.FirstChangeId) + copy(dAtA[i:], m.FirstChangeId) + i = encodeVarintThread(dAtA, i, uint64(len(m.FirstChangeId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintThread(dAtA []byte, offset int, v uint64) int { + offset -= sovThread(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ThreadHeader) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FirstChangeId) + if l > 0 { + n += 1 + l + sovThread(uint64(l)) + } + if m.IsWorkspace { + n += 2 + } + return n +} + +func sovThread(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozThread(x uint64) (n int) { + return sovThread(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ThreadHeader) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowThread + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ThreadHeader: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ThreadHeader: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FirstChangeId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowThread + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthThread + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthThread + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FirstChangeId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsWorkspace", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowThread + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsWorkspace = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipThread(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthThread + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipThread(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowThread + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowThread + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowThread + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthThread + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupThread + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthThread + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthThread = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowThread = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupThread = fmt.Errorf("proto: unexpected end of group") +) diff --git a/thread/threadid.go b/thread/threadid.go new file mode 100644 index 00000000..406f9eea --- /dev/null +++ b/thread/threadid.go @@ -0,0 +1,72 @@ +package thread + +import ( + "crypto/rand" + "encoding/binary" + "fmt" + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" + "hash/fnv" + + "github.com/textileio/go-threads/core/thread" +) + +func CreateACLThreadID(k keys.SigningPubKey, docType uint16) (thread.ID, error) { + rndlen := 32 + buf := make([]byte, 8+rndlen) + + // adding random bytes in the end + _, err := rand.Read(buf[8 : 8+rndlen]) + if err != nil { + panic("random read failed") + } + + keyBytes, err := k.Bytes() + if err != nil { + return thread.Undef, err + } + + hasher := fnv.New64() + hasher.Write(keyBytes) + res := hasher.Sum64() + + // putting hash of the pubkey in the beginning + binary.LittleEndian.PutUint64(buf[:8], res) + + return threadIDFromBytes(docType, buf) +} + +func VerifyACLThreadID(k keys.SigningPubKey, threadId thread.ID) (bool, error) { + bytes := threadId.Bytes() + pubKeyBytes := threadId.Bytes()[len(bytes)-40 : len(bytes)-32] + hash := binary.LittleEndian.Uint64(pubKeyBytes) + + keyBytes, err := k.Bytes() + if err != nil { + return false, err + } + + hasher := fnv.New64() + hasher.Write(keyBytes) + realHash := hasher.Sum64() + + return hash == realHash, nil +} + +func threadIDFromBytes( + docType uint16, + b []byte) (thread.ID, error) { + blen := len(b) + + // two 8 bytes (max) numbers plus num + buf := make([]byte, 2*binary.MaxVarintLen64+blen) + n := binary.PutUvarint(buf, thread.V1) + n += binary.PutUvarint(buf[n:], uint64(thread.AccessControlled)) + n += binary.PutUvarint(buf[n:], uint64(docType)) + + cn := copy(buf[n:], b) + if cn != blen { + return thread.Undef, fmt.Errorf("copy length is inconsistent") + } + + return thread.Cast(buf[:n+blen]) +} diff --git a/thread/threadid_test.go b/thread/threadid_test.go new file mode 100644 index 00000000..bddef215 --- /dev/null +++ b/thread/threadid_test.go @@ -0,0 +1,27 @@ +package thread + +import ( + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys" + "testing" +) + +func TestCreateACLThreadIDVerify(t *testing.T) { + _, pubKey, err := keys.GenerateRandomEd25519KeyPair() + if err != nil { + t.Fatalf("should not return error after generating key pair: %v", err) + } + + thread, err := CreateACLThreadID(pubKey, 1) + if err != nil { + t.Fatalf("should not return error after generating thread: %v", err) + } + + verified, err := VerifyACLThreadID(pubKey, thread) + if err != nil { + t.Fatalf("verification should not return error: %v", err) + } + + if !verified { + t.Fatalf("the thread should be verified") + } +} diff --git a/util/cid/cid.go b/util/cid/cid.go new file mode 100644 index 00000000..437d23f9 --- /dev/null +++ b/util/cid/cid.go @@ -0,0 +1,22 @@ +package cid + +import ( + "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" +) + +func NewCIDFromBytes(data []byte) (string, error) { + hash, err := mh.Sum(data, mh.SHA2_256, -1) + if err != nil { + return "", err + } + return cid.NewCidV1(cid.DagCBOR, hash).String(), nil +} + +func VerifyCID(data []byte, id string) bool { + hash, err := mh.Sum(data, mh.SHA2_256, -1) + if err != nil { + return false + } + return cid.NewCidV1(cid.DagCBOR, hash).String() == id +} diff --git a/util/crc16/crc16.go b/util/crc16/crc16.go new file mode 100644 index 00000000..810f4bed --- /dev/null +++ b/util/crc16/crc16.go @@ -0,0 +1,122 @@ +// Package crc16 is implementation according to CCITT standards. +// +// Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the +// following parameters: +// +// Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN" +// Width : 16 bit +// Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1) +// Initialization : 0000 +// Reflect Input byte : False +// Reflect Output CRC : False +// Xor constant to output CRC : 0000 +// Output for "123456789" : 31C3 +// +// ported from the c++ code in the stellar-core codebase +// (https://github.com/stellar/stellar-core). The code is licensed +// as: +/* + * Copyright 2001-2010 Georges Menie (www.menie.org) + * Copyright 2010-2012 Salvatore Sanfilippo (adapted to Redis coding style) + * Copyright 2015 Stellar Development Foundation (ported to go) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package crc16 + +import ( + "bytes" + "encoding/binary" + "fmt" +) + +// ErrInvalidChecksum is returned when Validate determines either the checksum +// or the payload has been corrupted +var ErrInvalidChecksum = fmt.Errorf("invalid checksum") + +var crc16tab = [256]uint16{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, +} + +// Checksum returns the 2-byte checksum for the provided data +func Checksum(data []byte) []byte { + var crc uint16 + var out bytes.Buffer + for _, b := range data { + crc = ((crc << 8) & 0xffff) ^ crc16tab[((crc>>8)^uint16(b))&0x00FF] + } + + err := binary.Write(&out, binary.LittleEndian, crc) + if err != nil { + panic(err) + } + + return out.Bytes() +} + +// Validate returns an error if the provided checksum does not match +// the calculated checksum of the provided data +func Validate(data []byte, expected []byte) error { + + actual := Checksum(data) + + // validate the provided checksum against the calculated + if !bytes.Equal(actual, expected) { + return ErrInvalidChecksum + } + + return nil +} diff --git a/util/keys/keys.go b/util/keys/keys.go new file mode 100644 index 00000000..796b6ab3 --- /dev/null +++ b/util/keys/keys.go @@ -0,0 +1,256 @@ +package keys + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/sha512" + "crypto/subtle" + "crypto/x509" + "errors" + "io" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/strkey" + "github.com/libp2p/go-libp2p-core/crypto" + crypto_pb "github.com/libp2p/go-libp2p-core/crypto/pb" +) + +type SigningPubKey crypto.PubKey +type SigningPrivKey crypto.PrivKey + +var MinRsaKeyBits = 2048 + +var ErrKeyLengthTooSmall = errors.New("error key length too small") + +type Key interface { + Equals(Key) bool + + Raw() ([]byte, error) +} + +type EncryptionPrivKey interface { + Key + + Decrypt([]byte) ([]byte, error) + GetPublic() EncryptionPubKey +} + +type EncryptionPubKey interface { + Key + + Encrypt(data []byte) ([]byte, error) +} + +type EncryptionRsaPrivKey struct { + privKey rsa.PrivateKey +} + +type EncryptionRsaPubKey struct { + pubKey rsa.PublicKey +} + +func (e *EncryptionRsaPubKey) Equals(key Key) bool { + other, ok := (key).(*EncryptionRsaPubKey) + if !ok { + return keyEquals(e, key) + } + + return e.pubKey.N.Cmp(other.pubKey.N) == 0 && e.pubKey.E == other.pubKey.E +} + +func (e *EncryptionRsaPubKey) Raw() ([]byte, error) { + return x509.MarshalPKIXPublicKey(&e.pubKey) +} + +func (e *EncryptionRsaPubKey) Encrypt(data []byte) ([]byte, error) { + hash := sha512.New() + return rsa.EncryptOAEP(hash, rand.Reader, &e.pubKey, data, nil) +} + +func (e *EncryptionRsaPrivKey) Equals(key Key) bool { + other, ok := (key).(*EncryptionRsaPrivKey) + if !ok { + return keyEquals(e, key) + } + + return e.privKey.N.Cmp(other.privKey.N) == 0 && e.privKey.E == other.privKey.E +} + +func (e *EncryptionRsaPrivKey) Raw() ([]byte, error) { + b := x509.MarshalPKCS1PrivateKey(&e.privKey) + return b, nil +} + +func (e *EncryptionRsaPrivKey) Decrypt(bytes []byte) ([]byte, error) { + hash := sha512.New() + return rsa.DecryptOAEP(hash, rand.Reader, &e.privKey, bytes, nil) +} + +func (e *EncryptionRsaPrivKey) GetPublic() EncryptionPubKey { + return &EncryptionRsaPubKey{pubKey: e.privKey.PublicKey} +} + +func GenerateRandomRSAKeyPair(bits int) (EncryptionPrivKey, EncryptionPubKey, error) { + return GenerateRSAKeyPair(bits, rand.Reader) +} + +func GenerateRSAKeyPair(bits int, src io.Reader) (EncryptionPrivKey, EncryptionPubKey, error) { + if bits < MinRsaKeyBits { + return nil, nil, ErrKeyLengthTooSmall + } + priv, err := rsa.GenerateKey(src, bits) + if err != nil { + return nil, nil, err + } + pk := priv.PublicKey + return &EncryptionRsaPrivKey{privKey: *priv}, &EncryptionRsaPubKey{pubKey: pk}, nil +} + +func NewEncryptionRsaPrivKeyFromBytes(bytes []byte) (EncryptionPrivKey, error) { + sk, err := x509.ParsePKCS1PrivateKey(bytes) + if err != nil { + return nil, err + } + if sk.N.BitLen() < MinRsaKeyBits { + return nil, ErrKeyLengthTooSmall + } + return &EncryptionRsaPrivKey{privKey: *sk}, nil +} + +func NewEncryptionRsaPubKeyFromBytes(bytes []byte) (EncryptionPubKey, error) { + pub, err := x509.ParsePKIXPublicKey(bytes) + if err != nil { + return nil, err + } + pk, ok := pub.(*rsa.PublicKey) + if !ok { + return nil, errors.New("not actually an rsa public key") + } + if pk.N.BitLen() < MinRsaKeyBits { + return nil, ErrKeyLengthTooSmall + } + + return &EncryptionRsaPubKey{pubKey: *pk}, nil +} + +func NewSigningEd25519PubKeyFromBytes(bytes []byte) (SigningPubKey, error) { + return crypto.UnmarshalEd25519PublicKey(bytes) +} + +func GenerateRandomEd25519KeyPair() (SigningPrivKey, SigningPubKey, error) { + return crypto.GenerateEd25519Key(rand.Reader) +} + +func keyEquals(k1, k2 Key) bool { + a, err := k1.Raw() + if err != nil { + return false + } + b, err := k2.Raw() + if err != nil { + return false + } + return subtle.ConstantTimeCompare(a, b) == 1 +} + +type Ed25519SigningPubKeyDecoder struct{} + +func NewEd25519Decoder() *Ed25519SigningPubKeyDecoder { + return &Ed25519SigningPubKeyDecoder{} +} + +func (e *Ed25519SigningPubKeyDecoder) DecodeFromBytes(bytes []byte) (SigningPubKey, error) { + return NewSigningEd25519PubKeyFromBytes(bytes) +} + +func (e *Ed25519SigningPubKeyDecoder) DecodeFromString(identity string) (SigningPubKey, error) { + pubKeyRaw, err := strkey.Decode(0x5b, identity) + if err != nil { + return nil, err + } + + return e.DecodeFromBytes(pubKeyRaw) +} + +func (e *Ed25519SigningPubKeyDecoder) DecodeFromStringIntoBytes(identity string) ([]byte, error) { + return strkey.Decode(0x5b, identity) +} + +func (e *Ed25519SigningPubKeyDecoder) EncodeToString(pubkey crypto.PubKey) (string, error) { + raw, err := pubkey.Raw() + if err != nil { + return "", err + } + return strkey.Encode(0x5b, raw) +} + +type SigningPubKeyDecoder interface { + DecodeFromBytes(bytes []byte) (SigningPubKey, error) + DecodeFromString(identity string) (SigningPubKey, error) + DecodeFromStringIntoBytes(identity string) ([]byte, error) +} + +// Below keys are required for testing and mocking purposes + +type EmptyRecorderEncryptionKey struct { + recordedEncrypted [][]byte + recordedDecrypted [][]byte +} + +func (f *EmptyRecorderEncryptionKey) Equals(key Key) bool { + return true +} + +func (f *EmptyRecorderEncryptionKey) Raw() ([]byte, error) { + panic("can't get bytes from this key") +} + +func (f *EmptyRecorderEncryptionKey) GetPublic() EncryptionPubKey { + panic("this key doesn't have a public key") +} + +func (f *EmptyRecorderEncryptionKey) Encrypt(msg []byte) ([]byte, error) { + f.recordedEncrypted = append(f.recordedEncrypted, msg) + return msg, nil +} + +func (f *EmptyRecorderEncryptionKey) Decrypt(msg []byte) ([]byte, error) { + f.recordedDecrypted = append(f.recordedDecrypted, msg) + return msg, nil +} + +type SignatureVerificationPayload struct { + message []byte + signature []byte +} + +type EmptyRecorderVerificationKey struct { + verifications []SignatureVerificationPayload +} + +func (e *EmptyRecorderVerificationKey) Bytes() ([]byte, error) { + panic("can't get bytes from this key") +} + +func (e *EmptyRecorderVerificationKey) Equals(key crypto.Key) bool { + return true +} + +func (e *EmptyRecorderVerificationKey) Raw() ([]byte, error) { + panic("can't get bytes from this key") +} + +func (e *EmptyRecorderVerificationKey) Type() crypto_pb.KeyType { + panic("can't get type from this key") +} + +func (e *EmptyRecorderVerificationKey) Verify(data []byte, sig []byte) (bool, error) { + e.verifications = append(e.verifications, SignatureVerificationPayload{ + message: data, + signature: sig, + }) + return true, nil +} + +func NewMockSigningPubKeyFromBytes(bytes []byte) (SigningPubKey, error) { + return &EmptyRecorderVerificationKey{}, nil +} diff --git a/util/slice/slice.go b/util/slice/slice.go new file mode 100644 index 00000000..cc7e9067 --- /dev/null +++ b/util/slice/slice.go @@ -0,0 +1,120 @@ +package slice + +import ( + "hash/fnv" + "math/rand" + "sort" +) + +func DifferenceRemovedAdded(a, b []string) (removed []string, added []string) { + var amap = map[string]struct{}{} + var bmap = map[string]struct{}{} + + for _, item := range a { + amap[item] = struct{}{} + } + + for _, item := range b { + if _, exists := amap[item]; !exists { + added = append(added, item) + } + bmap[item] = struct{}{} + } + + for _, item := range a { + if _, exists := bmap[item]; !exists { + removed = append(removed, item) + } + } + return +} + +func FindPos(s []string, v string) int { + for i, sv := range s { + if sv == v { + return i + } + } + return -1 +} + +// Difference returns the elements in `a` that aren't in `b`. +func Difference(a, b []string) []string { + var diff = make([]string, 0, len(a)) + for _, a1 := range a { + if FindPos(b, a1) == -1 { + diff = append(diff, a1) + } + } + return diff +} + +func Insert(s []string, pos int, v ...string) []string { + if len(s) <= pos { + return append(s, v...) + } + if pos == 0 { + return append(v, s[pos:]...) + } + return append(s[:pos], append(v, s[pos:]...)...) +} + +// Remove reuses provided slice capacity. Provided s slice should not be used after without reassigning to the func return! +func Remove(s []string, v string) []string { + var n int + for _, x := range s { + if x != v { + s[n] = x + n++ + } + } + return s[:n] +} + +func Filter(vals []string, cond func(string) bool) []string { + var result = make([]string, 0, len(vals)) + for i := range vals { + if cond(vals[i]) { + result = append(result, vals[i]) + } + } + return result +} + +func GetRandomString(s []string, seed string) string { + rand.Seed(int64(hash(seed))) + return s[rand.Intn(len(s))] +} + +func hash(s string) uint64 { + h := fnv.New64a() + h.Write([]byte(s)) + return h.Sum64() +} + +func SortedEquals(s1, s2 []string) bool { + if len(s1) != len(s2) { + return false + } + for i := range s1 { + if s1[i] != s2[i] { + return false + } + } + return true +} + +func UnsortedEquals(s1, s2 []string) bool { + if len(s1) != len(s2) { + return false + } + + s1Sorted := make([]string, len(s1)) + s2Sorted := make([]string, len(s2)) + copy(s1Sorted, s1) + copy(s2Sorted, s2) + sort.Strings(s1Sorted) + sort.Strings(s2Sorted) + + return SortedEquals(s1Sorted, s2Sorted) +} diff --git a/util/strkey/strkey.go b/util/strkey/strkey.go new file mode 100644 index 00000000..0e766f12 --- /dev/null +++ b/util/strkey/strkey.go @@ -0,0 +1,118 @@ +package strkey + +import ( + "bytes" + "encoding/binary" + "fmt" + + "github.com/mr-tron/base58/base58" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/util/crc16" +) + +// ErrInvalidVersionByte is returned when the version byte from a provided +// strkey-encoded string is not one of the valid values. +var ErrInvalidVersionByte = fmt.Errorf("invalid version byte") + +// VersionByte represents one of the possible prefix values for a StrKey base +// string--the string the when encoded using base58 yields a final StrKey. +type VersionByte byte + +// Decode decodes the provided StrKey into a raw value, checking the checksum +// and ensuring the expected VersionByte (the version parameter) is the value +// actually encoded into the provided src string. +func Decode(expected VersionByte, src string) ([]byte, error) { + raw, err := decodeString(src) + if err != nil { + return nil, err + } + + // decode into components + version := VersionByte(raw[0]) + vp := raw[0 : len(raw)-2] + payload := raw[1 : len(raw)-2] + checksum := raw[len(raw)-2:] + + // ensure version byte is expected + if version != expected { + return nil, ErrInvalidVersionByte + } + + // ensure checksum is valid + if err := crc16.Validate(vp, checksum); err != nil { + return nil, err + } + + // if we made it through the gaunlet, return the decoded value + return payload, nil +} + +// MustDecode is like Decode, but panics on error +func MustDecode(expected VersionByte, src string) []byte { + d, err := Decode(expected, src) + if err != nil { + panic(err) + } + return d +} + +// Encode encodes the provided data to a StrKey, using the provided version +// byte. +func Encode(version VersionByte, src []byte) (string, error) { + var raw bytes.Buffer + + // write version byte + if err := binary.Write(&raw, binary.LittleEndian, version); err != nil { + return "", err + } + + // write payload + if _, err := raw.Write(src); err != nil { + return "", err + } + + // calculate and write checksum + checksum := crc16.Checksum(raw.Bytes()) + if _, err := raw.Write(checksum); err != nil { + return "", err + } + + result := base58.FastBase58Encoding(raw.Bytes()) + return result, nil +} + +// MustEncode is like Encode, but panics on error +func MustEncode(version VersionByte, src []byte) string { + e, err := Encode(version, src) + if err != nil { + panic(err) + } + return e +} + +// Version extracts and returns the version byte from the provided source +// string. +func Version(src string) (VersionByte, error) { + raw, err := decodeString(src) + if err != nil { + return VersionByte(0), err + } + + return VersionByte(raw[0]), nil +} + +// decodeString decodes a base58 string into the raw bytes, and ensures it could +// potentially be strkey encoded (i.e. it has both a version byte and a +// checksum, neither of which are explicitly checked by this func) +func decodeString(src string) ([]byte, error) { + raw, err := base58.FastBase58Decoding(src) + if err != nil { + return nil, fmt.Errorf("base58 decode failed: %s", err) + } + + if len(raw) < 3 { + return nil, fmt.Errorf("encoded value is %d bytes; minimum valid length is 3", len(raw)) + } + + return raw, nil +}