1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-08 14:07:02 +09:00
any-sync/commonspace/acl/aclclient/aclspaceclient.go
2024-03-26 15:55:12 +01:00

231 lines
6.4 KiB
Go

package aclclient
import (
"context"
"errors"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/object/acl/list"
"github.com/anyproto/any-sync/commonspace/object/acl/syncacl"
"github.com/anyproto/any-sync/commonspace/spacestate"
"github.com/anyproto/any-sync/consensus/consensusproto"
"github.com/anyproto/any-sync/node/nodeclient"
"github.com/anyproto/any-sync/util/crypto"
)
type InviteResponse struct {
InviteRec *consensusproto.RawRecord
InviteKey crypto.PrivKey
}
type GetRecordsResponse struct {
Records []*consensusproto.RawRecordWithId
}
type InviteSaveFunc func()
type AclSpaceClient interface {
app.Component
GenerateInvite() (list.InviteResult, error)
StopSharing(ctx context.Context, readKeyChange list.ReadKeyChangePayload) (err error)
AddRecord(ctx context.Context, consRec *consensusproto.RawRecord) error
RemoveAccounts(ctx context.Context, payload list.AccountRemovePayload) error
AcceptRequest(ctx context.Context, payload list.RequestAcceptPayload) error
DeclineRequest(ctx context.Context, identity crypto.PubKey) (err error)
CancelRequest(ctx context.Context) (err error)
ChangePermissions(ctx context.Context, permChange list.PermissionChangesPayload) (err error)
RequestSelfRemove(ctx context.Context) (err error)
RevokeInvite(ctx context.Context, inviteRecordId string) (err error)
RevokeAllInvites(ctx context.Context) (err error)
AddAccounts(ctx context.Context, add list.AccountsAddPayload) (err error)
}
func NewAclSpaceClient() AclSpaceClient {
return &aclSpaceClient{}
}
type aclSpaceClient struct {
nodeClient nodeclient.NodeClient
acl list.AclList
spaceId string
}
func (c *aclSpaceClient) Init(a *app.App) (err error) {
c.nodeClient = a.MustComponent(nodeclient.CName).(nodeclient.NodeClient)
c.acl = a.MustComponent(syncacl.CName).(list.AclList)
c.spaceId = a.MustComponent(spacestate.CName).(*spacestate.SpaceState).SpaceId
return nil
}
func (c *aclSpaceClient) Name() (name string) {
return CName
}
func (c *aclSpaceClient) RevokeInvite(ctx context.Context, inviteRecordId string) (err error) {
c.acl.Lock()
res, err := c.acl.RecordBuilder().BuildInviteRevoke(inviteRecordId)
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) RequestSelfRemove(ctx context.Context) (err error) {
c.acl.Lock()
res, err := c.acl.RecordBuilder().BuildRequestRemove()
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) ChangePermissions(ctx context.Context, permChange list.PermissionChangesPayload) (err error) {
c.acl.Lock()
res, err := c.acl.RecordBuilder().BuildPermissionChanges(permChange)
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) AddAccounts(ctx context.Context, add list.AccountsAddPayload) (err error) {
c.acl.Lock()
res, err := c.acl.RecordBuilder().BuildAccountsAdd(add)
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) RemoveAccounts(ctx context.Context, payload list.AccountRemovePayload) (err error) {
c.acl.Lock()
res, err := c.acl.RecordBuilder().BuildAccountRemove(payload)
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) RevokeAllInvites(ctx context.Context) (err error) {
c.acl.Lock()
payload := list.BatchRequestPayload{
InviteRevokes: c.acl.AclState().InviteIds(),
}
res, err := c.acl.RecordBuilder().BuildBatchRequest(payload)
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) StopSharing(ctx context.Context, readKeyChange list.ReadKeyChangePayload) (err error) {
c.acl.Lock()
var (
identities []crypto.PubKey
recIds []string
)
for _, state := range c.acl.AclState().CurrentAccounts() {
if state.Permissions.NoPermissions() || state.Permissions.IsOwner() {
continue
}
identities = append(identities, state.PubKey)
}
recs, _ := c.acl.AclState().JoinRecords(false)
for _, rec := range recs {
recIds = append(recIds, rec.RecordId)
}
payload := list.BatchRequestPayload{
Removals: list.AccountRemovePayload{
Identities: identities,
Change: readKeyChange,
},
Declines: recIds,
InviteRevokes: c.acl.AclState().InviteIds(),
}
res, err := c.acl.RecordBuilder().BuildBatchRequest(payload)
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) DeclineRequest(ctx context.Context, identity crypto.PubKey) (err error) {
c.acl.Lock()
pendingReq, err := c.acl.AclState().JoinRecord(identity, false)
if err != nil {
c.acl.Unlock()
return
}
res, err := c.acl.RecordBuilder().BuildRequestDecline(pendingReq.RecordId)
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) CancelRequest(ctx context.Context) (err error) {
c.acl.Lock()
pendingReq, err := c.acl.AclState().Record(c.acl.AclState().Identity())
if err != nil {
c.acl.Unlock()
return
}
res, err := c.acl.RecordBuilder().BuildRequestCancel(pendingReq.RecordId)
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) AcceptRequest(ctx context.Context, payload list.RequestAcceptPayload) (err error) {
c.acl.Lock()
res, err := c.acl.RecordBuilder().BuildRequestAccept(payload)
if err != nil {
c.acl.Unlock()
return
}
c.acl.Unlock()
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
}
func (c *aclSpaceClient) GenerateInvite() (resp list.InviteResult, err error) {
c.acl.RLock()
defer c.acl.RUnlock()
return c.acl.RecordBuilder().BuildInvite()
}
func (c *aclSpaceClient) AddRecord(ctx context.Context, consRec *consensusproto.RawRecord) (err error) {
return c.sendRecordAndUpdate(ctx, c.spaceId, consRec)
}
func (c *aclSpaceClient) sendRecordAndUpdate(ctx context.Context, spaceId string, rec *consensusproto.RawRecord) (err error) {
res, err := c.nodeClient.AclAddRecord(ctx, spaceId, rec)
if err != nil {
return
}
c.acl.Lock()
defer c.acl.Unlock()
err = c.acl.AddRawRecord(res)
if errors.Is(err, list.ErrRecordAlreadyExists) {
err = nil
}
return
}