1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-08 05:57:03 +09:00

Add new changes

This commit is contained in:
mcrakhman 2024-01-23 07:28:01 +01:00
parent 46e96664b4
commit 3f5a1dc86f
No known key found for this signature in database
GPG key ID: DED12CFEF5B8396B
6 changed files with 1104 additions and 64 deletions

File diff suppressed because it is too large Load diff

View file

@ -53,6 +53,24 @@ message AclEncryptedReadKey {
bytes encryptedReadKey = 2;
}
// AclAccountPermissionChanges contains permission changes for certain identities
message AclAccountPermissionChanges {
repeated AclAccountPermissionChange changes = 1;
}
// AclAccountsAdd contains new accounts to be added
message AclAccountsAdd {
repeated AclAccountAdd additions = 1;
}
// AclAccountAdd contains new account to be added
message AclAccountAdd {
bytes identity = 1;
AclUserPermissions permissions = 2;
bytes metadata = 3;
bytes encryptedReadKey = 4;
}
// AclAccountPermissionChange changes permissions of specific account
message AclAccountPermissionChange {
bytes identity = 1;
@ -86,11 +104,14 @@ message AclContentValue {
AclAccountInviteRevoke inviteRevoke = 2;
AclAccountRequestJoin requestJoin = 3;
AclAccountRequestAccept requestAccept = 4;
// AclAccountPermissionChange deprecated
AclAccountPermissionChange permissionChange = 5;
AclAccountRemove accountRemove = 6;
AclReadKeyChange readKeyChange = 7;
AclAccountRequestDecline requestDecline = 8;
AclAccountRequestRemove accountRequestRemove = 9;
AclAccountPermissionChanges permissionChanges = 10;
AclAccountsAdd accountsAdd = 11;
}
}

View file

@ -40,6 +40,20 @@ type PermissionChangePayload struct {
Permissions AclPermissions
}
type PermissionChangesPayload struct {
Changes []PermissionChangePayload
}
type AccountsAddPayload struct {
Additions []AccountAdd
}
type AccountAdd struct {
Identity crypto.PubKey
Permissions AclPermissions
Metadata []byte
}
type AccountRemovePayload struct {
Identities []crypto.PubKey
Change ReadKeyChangePayload
@ -62,8 +76,10 @@ type AclRecordBuilder interface {
BuildRequestDecline(requestRecordId string) (rawRecord *consensusproto.RawRecord, err error)
BuildRequestRemove() (rawRecord *consensusproto.RawRecord, err error)
BuildPermissionChange(payload PermissionChangePayload) (rawRecord *consensusproto.RawRecord, err error)
BuildPermissionChanges(payload PermissionChangesPayload) (rawRecord *consensusproto.RawRecord, err error)
BuildReadKeyChange(payload ReadKeyChangePayload) (rawRecord *consensusproto.RawRecord, err error)
BuildAccountRemove(payload AccountRemovePayload) (rawRecord *consensusproto.RawRecord, err error)
BuildAccountsAdd(payload AccountsAddPayload) (rawRecord *consensusproto.RawRecord, err error)
}
type aclRecordBuilder struct {
@ -116,6 +132,85 @@ func (a *aclRecordBuilder) buildRecord(aclContent *aclrecordproto.AclContentValu
return
}
func (a *aclRecordBuilder) BuildPermissionChanges(payload PermissionChangesPayload) (rawRecord *consensusproto.RawRecord, err error) {
if !a.state.Permissions(a.state.pubKey).CanManageAccounts() {
err = ErrInsufficientPermissions
return
}
var changes []*aclrecordproto.AclAccountPermissionChange
for _, perm := range payload.Changes {
if perm.Identity.Equals(a.state.pubKey) {
err = ErrInsufficientPermissions
return
}
if perm.Permissions.IsOwner() {
err = ErrIsOwner
return
}
protoIdentity, err := perm.Identity.Marshall()
if err != nil {
return nil, err
}
changes = append(changes, &aclrecordproto.AclAccountPermissionChange{
Identity: protoIdentity,
Permissions: aclrecordproto.AclUserPermissions(perm.Permissions),
})
}
content := &aclrecordproto.AclContentValue{Value: &aclrecordproto.AclContentValue_PermissionChanges{
&aclrecordproto.AclAccountPermissionChanges{changes},
}}
return a.buildRecord(content)
}
func (a *aclRecordBuilder) BuildAccountsAdd(payload AccountsAddPayload) (rawRecord *consensusproto.RawRecord, err error) {
var accs []*aclrecordproto.AclAccountAdd
for _, acc := range payload.Additions {
if !a.state.Permissions(acc.Identity).NoPermissions() {
return nil, ErrDuplicateAccounts
}
if acc.Permissions.IsOwner() {
return nil, ErrIsOwner
}
mkKey, err := a.state.CurrentMetadataKey()
if err != nil {
return nil, err
}
encMeta, err := mkKey.Encrypt(acc.Metadata)
if err != nil {
return nil, err
}
if len(encMeta) > MaxMetadataLen {
return nil, ErrMetadataTooLarge
}
readKey, err := a.state.CurrentReadKey()
if err != nil {
return nil, ErrNoReadKey
}
protoKey, err := readKey.Marshall()
if err != nil {
return nil, err
}
enc, err := acc.Identity.Encrypt(protoKey)
if err != nil {
return nil, err
}
protoIdentity, err := acc.Identity.Marshall()
if err != nil {
return nil, err
}
accs = append(accs, &aclrecordproto.AclAccountAdd{
Identity: protoIdentity,
Permissions: aclrecordproto.AclUserPermissions(acc.Permissions),
Metadata: encMeta,
EncryptedReadKey: enc,
})
}
content := &aclrecordproto.AclContentValue{Value: &aclrecordproto.AclContentValue_AccountsAdd{
&aclrecordproto.AclAccountsAdd{accs},
}}
return a.buildRecord(content)
}
func (a *aclRecordBuilder) BuildInvite() (res InviteResult, err error) {
if !a.state.Permissions(a.state.pubKey).CanManageAccounts() {
err = ErrInsufficientPermissions

View file

@ -298,6 +298,16 @@ func (st *AclState) applyChangeContent(ch *aclrecordproto.AclContentValue, recor
}
}
func (st *AclState) applyPermissionChanges(ch *aclrecordproto.AclAccountPermissionChanges, record *AclRecord) (err error) {
for _, ch := range ch.Changes {
err := st.applyPermissionChange(ch, record)
if err != nil {
return err
}
}
return nil
}
func (st *AclState) applyPermissionChange(ch *aclrecordproto.AclAccountPermissionChange, record *AclRecord) error {
chIdentity, err := st.keyStore.PubKeyFromProto(ch.Identity)
if err != nil {
@ -363,6 +373,34 @@ func (st *AclState) applyRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, r
return nil
}
func (st *AclState) applyAccountsAdd(ch *aclrecordproto.AclAccountsAdd, record *AclRecord) error {
err := st.contentValidator.ValidateAccountsAdd(ch, record.Identity)
if err != nil {
return err
}
for _, acc := range ch.Additions {
identity, err := st.keyStore.PubKeyFromProto(acc.Identity)
if err != nil {
return err
}
st.accountStates[mapKeyFromPubKey(identity)] = AccountState{
PubKey: identity,
Permissions: AclPermissions(acc.Permissions),
Status: StatusActive,
RequestMetadata: acc.Metadata,
KeyRecordId: st.CurrentReadKeyId(),
}
if !st.pubKey.Equals(identity) {
continue
}
err = st.unpackAllKeys(acc.EncryptedReadKey)
if err != nil {
return err
}
}
return nil
}
func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccept, record *AclRecord) error {
err := st.contentValidator.ValidateRequestAccept(ch, record.Identity)
if err != nil {
@ -390,7 +428,11 @@ func (st *AclState) applyRequestAccept(ch *aclrecordproto.AclAccountRequestAccep
if !st.pubKey.Equals(acceptIdentity) {
return nil
}
iterReadKey, err := st.unmarshallDecryptReadKey(ch.EncryptedReadKey, st.key.Decrypt)
return st.unpackAllKeys(ch.EncryptedReadKey)
}
func (st *AclState) unpackAllKeys(rk []byte) error {
iterReadKey, err := st.unmarshallDecryptReadKey(rk, st.key.Decrypt)
if err != nil {
return err
}

View file

@ -8,6 +8,8 @@ import (
type ContentValidator interface {
ValidateAclRecordContents(ch *AclRecord) (err error)
ValidatePermissionChange(ch *aclrecordproto.AclAccountPermissionChange, authorIdentity crypto.PubKey) (err error)
ValidatePermissionChanges(ch *aclrecordproto.AclAccountPermissionChanges, authorIdentity crypto.PubKey) (err error)
ValidateAccountsAdd(ch *aclrecordproto.AclAccountsAdd, authorIdentity crypto.PubKey) (err error)
ValidateInvite(ch *aclrecordproto.AclAccountInvite, authorIdentity crypto.PubKey) (err error)
ValidateInviteRevoke(ch *aclrecordproto.AclAccountInviteRevoke, authorIdentity crypto.PubKey) (err error)
ValidateRequestJoin(ch *aclrecordproto.AclAccountRequestJoin, authorIdentity crypto.PubKey) (err error)
@ -23,6 +25,35 @@ type contentValidator struct {
aclState *AclState
}
func (c *contentValidator) ValidatePermissionChanges(ch *aclrecordproto.AclAccountPermissionChanges, authorIdentity crypto.PubKey) (err error) {
for _, ch := range ch.Changes {
err := c.ValidatePermissionChange(ch, authorIdentity)
if err != nil {
return err
}
}
return nil
}
func (c *contentValidator) ValidateAccountsAdd(ch *aclrecordproto.AclAccountsAdd, authorIdentity crypto.PubKey) (err error) {
if !c.aclState.Permissions(authorIdentity).CanManageAccounts() {
return ErrInsufficientPermissions
}
for _, ch := range ch.Additions {
identity, err := c.keyStore.PubKeyFromProto(ch.Identity)
if err != nil {
return err
}
if !c.aclState.Permissions(identity).NoPermissions() {
return ErrDuplicateAccounts
}
if AclPermissions(ch.Permissions).IsOwner() {
return ErrIsOwner
}
}
return nil
}
func (c *contentValidator) ValidateAclRecordContents(ch *AclRecord) (err error) {
if ch.PrevId != c.aclState.lastRecordId {
return ErrIncorrectRecordSequence
@ -57,6 +88,10 @@ func (c *contentValidator) validateAclRecordContent(ch *aclrecordproto.AclConten
return c.ValidateRequestRemove(ch.GetAccountRequestRemove(), authorIdentity)
case ch.GetReadKeyChange() != nil:
return c.ValidateReadKeyChange(ch.GetReadKeyChange(), authorIdentity)
case ch.GetPermissionChanges() != nil:
return c.ValidatePermissionChanges(ch.GetPermissionChanges(), authorIdentity)
case ch.GetAccountsAdd() != nil:
return c.ValidateAccountsAdd(ch.GetAccountsAdd(), authorIdentity)
default:
return ErrUnexpectedContentType
}

View file

@ -1383,7 +1383,7 @@ func (m *AclAddRecordResponse) GetPayload() []byte {
return nil
}
// AclGetRecordsRequest can optionally contain the last known aclHeal, the server will return only new records or an empty list if there are no new records.
// AclGetRecordsRequest can optionally contain the last known aclHead, the server will return only new records or an empty list if there are no new records.
// If aclHead is not provided the whole list will be returned.
type AclGetRecordsRequest struct {
SpaceId string `protobuf:"bytes,1,opt,name=spaceId,proto3" json:"spaceId,omitempty"`