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:
parent
46e96664b4
commit
3f5a1dc86f
6 changed files with 1104 additions and 64 deletions
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue