mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-08 05:57:03 +09:00
Add batch invite logic
This commit is contained in:
parent
854823d81e
commit
985a1d7184
4 changed files with 163 additions and 51 deletions
|
@ -19,6 +19,10 @@ type InviteResponse struct {
|
||||||
InviteKey crypto.PrivKey
|
InviteKey crypto.PrivKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InviteChange struct {
|
||||||
|
Perms list.AclPermissions
|
||||||
|
}
|
||||||
|
|
||||||
type GetRecordsResponse struct {
|
type GetRecordsResponse struct {
|
||||||
Records []*consensusproto.RawRecordWithId
|
Records []*consensusproto.RawRecordWithId
|
||||||
}
|
}
|
||||||
|
@ -27,8 +31,8 @@ type InviteSaveFunc func()
|
||||||
|
|
||||||
type AclSpaceClient interface {
|
type AclSpaceClient interface {
|
||||||
app.Component
|
app.Component
|
||||||
GenerateInvite() (list.InviteResult, error)
|
GenerateInvite(shouldRevokeAll, isRequestToJoin bool, permissions list.AclPermissions) (list.InviteResult, error)
|
||||||
GenerateAnyoneCanJoinInvite(permissions list.AclPermissions) (list.InviteResult, error)
|
ChangeInvite(ctx context.Context, inviteId string, permissions list.AclPermissions) error
|
||||||
StopSharing(ctx context.Context, readKeyChange list.ReadKeyChangePayload) (err error)
|
StopSharing(ctx context.Context, readKeyChange list.ReadKeyChangePayload) (err error)
|
||||||
AddRecord(ctx context.Context, consRec *consensusproto.RawRecord) error
|
AddRecord(ctx context.Context, consRec *consensusproto.RawRecord) error
|
||||||
RemoveAccounts(ctx context.Context, payload list.AccountRemovePayload) error
|
RemoveAccounts(ctx context.Context, payload list.AccountRemovePayload) error
|
||||||
|
@ -129,7 +133,7 @@ func (c *aclSpaceClient) RevokeAllInvites(ctx context.Context) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.acl.Unlock()
|
c.acl.Unlock()
|
||||||
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
|
return c.sendRecordAndUpdate(ctx, c.spaceId, res.Rec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *aclSpaceClient) StopSharing(ctx context.Context, readKeyChange list.ReadKeyChangePayload) (err error) {
|
func (c *aclSpaceClient) StopSharing(ctx context.Context, readKeyChange list.ReadKeyChangePayload) (err error) {
|
||||||
|
@ -166,7 +170,7 @@ func (c *aclSpaceClient) StopSharing(ctx context.Context, readKeyChange list.Rea
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.acl.Unlock()
|
c.acl.Unlock()
|
||||||
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
|
return c.sendRecordAndUpdate(ctx, c.spaceId, res.Rec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *aclSpaceClient) DeclineRequest(ctx context.Context, identity crypto.PubKey) (err error) {
|
func (c *aclSpaceClient) DeclineRequest(ctx context.Context, identity crypto.PubKey) (err error) {
|
||||||
|
@ -212,10 +216,46 @@ func (c *aclSpaceClient) AcceptRequest(ctx context.Context, payload list.Request
|
||||||
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
|
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *aclSpaceClient) GenerateInvite() (resp list.InviteResult, err error) {
|
func (c *aclSpaceClient) ChangeInvite(ctx context.Context, inviteId string, permissions list.AclPermissions) error {
|
||||||
|
c.acl.Lock()
|
||||||
|
res, err := c.acl.RecordBuilder().BuildInviteChange(list.InviteChangePayload{
|
||||||
|
IniviteRecordId: inviteId,
|
||||||
|
Permissions: permissions,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.acl.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.acl.Unlock()
|
||||||
|
return c.sendRecordAndUpdate(ctx, c.spaceId, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *aclSpaceClient) GenerateInvite(isRevoke, isRequestToJoin bool, permissions list.AclPermissions) (list.InviteResult, error) {
|
||||||
c.acl.Lock()
|
c.acl.Lock()
|
||||||
defer c.acl.Unlock()
|
defer c.acl.Unlock()
|
||||||
return c.acl.RecordBuilder().BuildInvite()
|
var inviteIds []string
|
||||||
|
if isRevoke {
|
||||||
|
for _, invite := range c.acl.AclState().Invites() {
|
||||||
|
if isRequestToJoin && invite.Type == aclrecordproto.AclInviteType_RequestToJoin {
|
||||||
|
return list.InviteResult{}, list.ErrDuplicateInvites
|
||||||
|
} else if invite.Permissions == permissions {
|
||||||
|
return list.InviteResult{}, list.ErrDuplicateInvites
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inviteIds = c.acl.AclState().InviteIds()
|
||||||
|
}
|
||||||
|
payload := list.BatchRequestPayload{
|
||||||
|
InviteRevokes: inviteIds,
|
||||||
|
NewInvites: []list.AclPermissions{permissions},
|
||||||
|
}
|
||||||
|
res, err := c.acl.RecordBuilder().BuildBatchRequest(payload)
|
||||||
|
if err != nil {
|
||||||
|
return list.InviteResult{}, err
|
||||||
|
}
|
||||||
|
return list.InviteResult{
|
||||||
|
InviteRec: res.Rec,
|
||||||
|
InviteKey: res.Invites[0],
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *aclSpaceClient) GenerateAnyoneCanJoinInvite(permissions list.AclPermissions) (resp list.InviteResult, err error) {
|
func (c *aclSpaceClient) GenerateAnyoneCanJoinInvite(permissions list.AclPermissions) (resp list.InviteResult, err error) {
|
||||||
|
|
|
@ -66,6 +66,10 @@ type AccountAdd struct {
|
||||||
Metadata []byte
|
Metadata []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NewInvites struct {
|
||||||
|
Permissions AclPermissions
|
||||||
|
}
|
||||||
|
|
||||||
type BatchRequestPayload struct {
|
type BatchRequestPayload struct {
|
||||||
Additions []AccountAdd
|
Additions []AccountAdd
|
||||||
Changes []PermissionChangePayload
|
Changes []PermissionChangePayload
|
||||||
|
@ -73,6 +77,8 @@ type BatchRequestPayload struct {
|
||||||
Approvals []RequestAcceptPayload
|
Approvals []RequestAcceptPayload
|
||||||
Declines []string
|
Declines []string
|
||||||
InviteRevokes []string
|
InviteRevokes []string
|
||||||
|
InviteChanges []InviteChangePayload
|
||||||
|
NewInvites []AclPermissions
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccountRemovePayload struct {
|
type AccountRemovePayload struct {
|
||||||
|
@ -85,12 +91,17 @@ type InviteResult struct {
|
||||||
InviteKey crypto.PrivKey
|
InviteKey crypto.PrivKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BatchResult struct {
|
||||||
|
Rec *consensusproto.RawRecord
|
||||||
|
Invites []crypto.PrivKey
|
||||||
|
}
|
||||||
|
|
||||||
type AclRecordBuilder interface {
|
type AclRecordBuilder interface {
|
||||||
UnmarshallWithId(rawIdRecord *consensusproto.RawRecordWithId) (rec *AclRecord, err error)
|
UnmarshallWithId(rawIdRecord *consensusproto.RawRecordWithId) (rec *AclRecord, err error)
|
||||||
Unmarshall(rawRecord *consensusproto.RawRecord) (rec *AclRecord, err error)
|
Unmarshall(rawRecord *consensusproto.RawRecord) (rec *AclRecord, err error)
|
||||||
|
|
||||||
BuildRoot(content RootContent) (rec *consensusproto.RawRecordWithId, err error)
|
BuildRoot(content RootContent) (rec *consensusproto.RawRecordWithId, err error)
|
||||||
BuildBatchRequest(payload BatchRequestPayload) (rawRecord *consensusproto.RawRecord, err error)
|
BuildBatchRequest(payload BatchRequestPayload) (batchResult BatchResult, err error)
|
||||||
BuildInvite() (res InviteResult, err error)
|
BuildInvite() (res InviteResult, err error)
|
||||||
BuildInviteAnyone(permissions AclPermissions) (res InviteResult, err error)
|
BuildInviteAnyone(permissions AclPermissions) (res InviteResult, err error)
|
||||||
BuildInviteChange(inviteChange InviteChangePayload) (rawRecord *consensusproto.RawRecord, err error)
|
BuildInviteChange(inviteChange InviteChangePayload) (rawRecord *consensusproto.RawRecord, err error)
|
||||||
|
@ -125,51 +136,84 @@ func NewAclRecordBuilder(id string, keyStorage crypto.KeyStorage, keys *accountd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclRecordBuilder) BuildBatchRequest(payload BatchRequestPayload) (rawRec *consensusproto.RawRecord, err error) {
|
func (a *aclRecordBuilder) BuildBatchRequest(payload BatchRequestPayload) (batchResult BatchResult, err error) {
|
||||||
var aclContent []*aclrecordproto.AclContentValue
|
var (
|
||||||
|
contentList []*aclrecordproto.AclContentValue
|
||||||
|
content *aclrecordproto.AclContentValue
|
||||||
|
)
|
||||||
if len(payload.Removals.Identities) > 0 {
|
if len(payload.Removals.Identities) > 0 {
|
||||||
content, err := a.buildAccountRemove(payload.Removals)
|
content, err = a.buildAccountRemove(payload.Removals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
aclContent = append(aclContent, content)
|
contentList = append(contentList, content)
|
||||||
}
|
}
|
||||||
if len(payload.Additions) > 0 {
|
if len(payload.Additions) > 0 {
|
||||||
content, err := a.buildAccountsAdd(AccountsAddPayload{Additions: payload.Additions}, payload.Removals.Change.MetadataKey.GetPublic(), payload.Removals.Change.ReadKey)
|
content, err = a.buildAccountsAdd(AccountsAddPayload{Additions: payload.Additions}, payload.Removals.Change.MetadataKey.GetPublic(), payload.Removals.Change.ReadKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
aclContent = append(aclContent, content)
|
contentList = append(contentList, content)
|
||||||
}
|
}
|
||||||
if len(payload.Changes) > 0 {
|
if len(payload.Changes) > 0 {
|
||||||
content, err := a.buildPermissionChanges(PermissionChangesPayload{Changes: payload.Changes})
|
content, err = a.buildPermissionChanges(PermissionChangesPayload{Changes: payload.Changes})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
aclContent = append(aclContent, content)
|
contentList = append(contentList, content)
|
||||||
}
|
}
|
||||||
for _, acc := range payload.Approvals {
|
for _, acc := range payload.Approvals {
|
||||||
content, err := a.buildRequestAccept(acc, payload.Removals.Change.ReadKey)
|
content, err = a.buildRequestAccept(acc, payload.Removals.Change.ReadKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
aclContent = append(aclContent, content)
|
contentList = append(contentList, content)
|
||||||
}
|
}
|
||||||
for _, id := range payload.Declines {
|
for _, id := range payload.Declines {
|
||||||
content, err := a.buildRequestDecline(id)
|
content, err = a.buildRequestDecline(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
aclContent = append(aclContent, content)
|
contentList = append(contentList, content)
|
||||||
}
|
}
|
||||||
for _, id := range payload.InviteRevokes {
|
for _, id := range payload.InviteRevokes {
|
||||||
content, err := a.buildInviteRevoke(id)
|
content, err = a.buildInviteRevoke(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
aclContent = append(aclContent, content)
|
contentList = append(contentList, content)
|
||||||
}
|
}
|
||||||
return a.buildRecords(aclContent)
|
for _, invite := range payload.InviteChanges {
|
||||||
|
content, err = a.buildInviteChange(invite)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
contentList = append(contentList, content)
|
||||||
|
}
|
||||||
|
for _, perms := range payload.NewInvites {
|
||||||
|
var privKey crypto.PrivKey
|
||||||
|
if perms.NoPermissions() {
|
||||||
|
privKey, content, err = a.buildInvite()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
contentList = append(contentList, content)
|
||||||
|
batchResult.Invites = append(batchResult.Invites, privKey)
|
||||||
|
} else {
|
||||||
|
privKey, content, err = a.buildInviteAnyone(perms)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
contentList = append(contentList, content)
|
||||||
|
batchResult.Invites = append(batchResult.Invites, privKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res, err := a.buildRecords(contentList)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
batchResult.Rec = res
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclRecordBuilder) buildRecord(aclContent *aclrecordproto.AclContentValue) (rawRec *consensusproto.RawRecord, err error) {
|
func (a *aclRecordBuilder) buildRecord(aclContent *aclrecordproto.AclContentValue) (rawRec *consensusproto.RawRecord, err error) {
|
||||||
|
@ -316,6 +360,20 @@ func (a *aclRecordBuilder) buildAccountsAdd(payload AccountsAddPayload, mkKey cr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclRecordBuilder) BuildInvite() (res InviteResult, err error) {
|
func (a *aclRecordBuilder) BuildInvite() (res InviteResult, err error) {
|
||||||
|
privKey, content, err := a.buildInvite()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rawRec, err := a.buildRecord(content)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.InviteKey = privKey
|
||||||
|
res.InviteRec = rawRec
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *aclRecordBuilder) buildInvite() (invKey crypto.PrivKey, content *aclrecordproto.AclContentValue, err error) {
|
||||||
if !a.state.Permissions(a.state.pubKey).CanManageAccounts() {
|
if !a.state.Permissions(a.state.pubKey).CanManageAccounts() {
|
||||||
err = ErrInsufficientPermissions
|
err = ErrInsufficientPermissions
|
||||||
return
|
return
|
||||||
|
@ -329,7 +387,37 @@ func (a *aclRecordBuilder) BuildInvite() (res InviteResult, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
inviteRec := &aclrecordproto.AclAccountInvite{InviteKey: invitePubKey}
|
inviteRec := &aclrecordproto.AclAccountInvite{InviteKey: invitePubKey}
|
||||||
content := &aclrecordproto.AclContentValue{Value: &aclrecordproto.AclContentValue_Invite{Invite: inviteRec}}
|
content = &aclrecordproto.AclContentValue{Value: &aclrecordproto.AclContentValue_Invite{Invite: inviteRec}}
|
||||||
|
invKey = privKey
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *aclRecordBuilder) BuildInviteChange(inviteChange InviteChangePayload) (rawRecord *consensusproto.RawRecord, err error) {
|
||||||
|
content, err := a.buildInviteChange(inviteChange)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return a.buildRecord(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *aclRecordBuilder) buildInviteChange(inviteChange InviteChangePayload) (content *aclrecordproto.AclContentValue, err error) {
|
||||||
|
if !a.state.Permissions(a.state.pubKey).CanManageAccounts() {
|
||||||
|
err = ErrInsufficientPermissions
|
||||||
|
return
|
||||||
|
}
|
||||||
|
inviteRec := &aclrecordproto.AclAccountInviteChange{
|
||||||
|
InviteRecordId: inviteChange.IniviteRecordId,
|
||||||
|
Permissions: aclrecordproto.AclUserPermissions(inviteChange.Permissions),
|
||||||
|
}
|
||||||
|
content = &aclrecordproto.AclContentValue{Value: &aclrecordproto.AclContentValue_InviteChange{InviteChange: inviteRec}}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *aclRecordBuilder) BuildInviteAnyone(permissions AclPermissions) (res InviteResult, err error) {
|
||||||
|
privKey, content, err := a.buildInviteAnyone(permissions)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
rawRec, err := a.buildRecord(content)
|
rawRec, err := a.buildRecord(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -339,20 +427,7 @@ func (a *aclRecordBuilder) BuildInvite() (res InviteResult, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aclRecordBuilder) BuildInviteChange(inviteChange InviteChangePayload) (rawRecord *consensusproto.RawRecord, err error) {
|
func (a *aclRecordBuilder) buildInviteAnyone(permissions AclPermissions) (invKey crypto.PrivKey, content *aclrecordproto.AclContentValue, err error) {
|
||||||
if !a.state.Permissions(a.state.pubKey).CanManageAccounts() {
|
|
||||||
err = ErrInsufficientPermissions
|
|
||||||
return
|
|
||||||
}
|
|
||||||
inviteRec := &aclrecordproto.AclAccountInviteChange{
|
|
||||||
InviteRecordId: inviteChange.IniviteRecordId,
|
|
||||||
Permissions: aclrecordproto.AclUserPermissions(inviteChange.Permissions),
|
|
||||||
}
|
|
||||||
content := &aclrecordproto.AclContentValue{Value: &aclrecordproto.AclContentValue_InviteChange{InviteChange: inviteRec}}
|
|
||||||
return a.buildRecord(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *aclRecordBuilder) BuildInviteAnyone(permissions AclPermissions) (res InviteResult, err error) {
|
|
||||||
if !a.state.Permissions(a.state.pubKey).CanManageAccounts() {
|
if !a.state.Permissions(a.state.pubKey).CanManageAccounts() {
|
||||||
err = ErrInsufficientPermissions
|
err = ErrInsufficientPermissions
|
||||||
return
|
return
|
||||||
|
@ -383,13 +458,8 @@ func (a *aclRecordBuilder) BuildInviteAnyone(permissions AclPermissions) (res In
|
||||||
Permissions: aclrecordproto.AclUserPermissions_Reader,
|
Permissions: aclrecordproto.AclUserPermissions_Reader,
|
||||||
EncryptedReadKey: encReadKey,
|
EncryptedReadKey: encReadKey,
|
||||||
}
|
}
|
||||||
content := &aclrecordproto.AclContentValue{Value: &aclrecordproto.AclContentValue_Invite{Invite: inviteRec}}
|
content = &aclrecordproto.AclContentValue{Value: &aclrecordproto.AclContentValue_Invite{Invite: inviteRec}}
|
||||||
rawRec, err := a.buildRecord(content)
|
invKey = privKey
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res.InviteKey = privKey
|
|
||||||
res.InviteRec = rawRec
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ type Invite struct {
|
||||||
Key crypto.PubKey
|
Key crypto.PubKey
|
||||||
Type aclrecordproto.AclInviteType
|
Type aclrecordproto.AclInviteType
|
||||||
Permissions AclPermissions
|
Permissions AclPermissions
|
||||||
|
Id string
|
||||||
encryptedKey []byte
|
encryptedKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,6 +508,7 @@ func (st *AclState) applyInvite(ch *aclrecordproto.AclAccountInvite, record *Acl
|
||||||
}
|
}
|
||||||
st.invites[record.Id] = Invite{
|
st.invites[record.Id] = Invite{
|
||||||
Key: inviteKey,
|
Key: inviteKey,
|
||||||
|
Id: record.Id,
|
||||||
Type: ch.InviteType,
|
Type: ch.InviteType,
|
||||||
Permissions: AclPermissions(ch.Permissions),
|
Permissions: AclPermissions(ch.Permissions),
|
||||||
encryptedKey: ch.EncryptedReadKey,
|
encryptedKey: ch.EncryptedReadKey,
|
||||||
|
|
|
@ -217,7 +217,7 @@ func (a *AclTestExecutor) buildBatchRequest(args []string, acl AclList, getPerm
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return afterAll, addRec(WrapAclRecord(res))
|
return afterAll, addRec(WrapAclRecord(res.Rec))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AclTestExecutor) Execute(cmd string) (err error) {
|
func (a *AclTestExecutor) Execute(cmd string) (err error) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue