@@ -17,6 +17,7 @@ import (
1717 "github.com/anyproto/any-sync/net/peer"
1818 "github.com/anyproto/any-sync/net/rpc/server"
1919 "github.com/anyproto/any-sync/nodeconf"
20+ "github.com/anyproto/any-sync/util/crypto"
2021 blocks "github.com/ipfs/go-block-format"
2122 "github.com/ipfs/go-cid"
2223 "go.uber.org/zap"
@@ -37,7 +38,9 @@ func New() Service {
3738 return new (fileNode )
3839}
3940
41+ //go:generate mockgen -destination mock_filenode/mock_filenode.go github.com/anyproto/any-sync-filenode/filenode Service
4042type Service interface {
43+ OwnershipTransfer (ctx context.Context , spaceId , oldIdentity string , aclRecordId string ) (err error )
4144 app.Component
4245}
4346
@@ -180,13 +183,24 @@ func (fn *fileNode) StoreKey(ctx context.Context, spaceId string, checkLimit boo
180183 return storageKey , fileprotoerr .ErrForbidden
181184 }
182185
183- ownerPubKey , err := fn . acl . OwnerPubKey ( ctx , spaceId )
184- if err != nil {
185- log . WarnCtx ( ctx , "acl ownerPubKey error" , zap . Error ( err ))
186- return storageKey , fileprotoerr . ErrForbidden
187- }
186+ var (
187+ ownerPubKey crypto. PubKey
188+ ownerRecordIndex int
189+ isOneToOne bool
190+ )
188191
189- err = fn .acl .ReadState (ctx , spaceId , func (aclState * list.AclState ) error {
192+ err = fn .acl .ReadList (ctx , spaceId , func (aclList list.AclList ) error {
193+ aclState := aclList .AclState ()
194+ var ownerRecordId string
195+ if ownerPubKey , ownerRecordId , err = aclState .OwnerPubKeyWithRecordId (); err != nil {
196+ log .WarnCtx (ctx , "acl ownerPubKey error" , zap .Error (err ))
197+ return fileprotoerr .ErrForbidden
198+ }
199+ ownerRecordIndex = aclList .GetRecordIndex (ownerRecordId )
200+ if ownerRecordIndex < 0 {
201+ log .ErrorCtx (ctx , "acl ownerRecordIndex not found" , zap .String ("spaceId" , spaceId ), zap .String ("recordId" , ownerRecordId ), zap .Error (err ))
202+ return fileprotoerr .ErrUnexpected
203+ }
190204 if aclState .IsOneToOne () {
191205 if aclState .Permissions (identity ).NoPermissions () {
192206 return fileprotoerr .ErrForbidden
@@ -207,6 +221,7 @@ func (fn *fileNode) StoreKey(ctx context.Context, spaceId string, checkLimit boo
207221 GroupId : identity .Account (),
208222 SpaceId : newSpaceId ,
209223 }
224+ isOneToOne = true
210225 } else {
211226 storageKey = index.Key {
212227 GroupId : ownerPubKey .Account (),
@@ -231,10 +246,19 @@ func (fn *fileNode) StoreKey(ctx context.Context, spaceId string, checkLimit boo
231246 }
232247 }
233248
234- if e := fn .index .Migrate (ctx , storageKey ); e != nil {
235- log .WarnCtx (ctx , "space migrate error" , zap .String ("spaceId" , spaceId ), zap .Error (e ))
249+ if ! isOneToOne {
250+ if e := fn .index .Migrate (ctx , storageKey ); e != nil {
251+ log .WarnCtx (ctx , "space migrate error" , zap .String ("spaceId" , spaceId ), zap .Error (e ))
252+ }
253+ var oldIdentity string
254+ if ownerRecordIndex == 0 {
255+ oldIdentity = storageKey .GroupId
256+ }
257+ if err = fn .index .CheckAndMoveOwnership (ctx , storageKey , oldIdentity , ownerRecordIndex ); err != nil {
258+ log .ErrorCtx (ctx , "check ownership error" , zap .String ("spaceId" , spaceId ), zap .Error (err ))
259+ return storageKey , fileprotoerr .ErrUnexpected
260+ }
236261 }
237-
238262 if checkLimit {
239263 if err = fn .index .CheckLimits (ctx , storageKey ); err != nil {
240264 if errors .Is (err , index .ErrLimitExceed ) {
@@ -417,3 +441,35 @@ func (fn *fileNode) FilesGet(ctx context.Context, spaceId string) (fileIds []str
417441 }
418442 return fn .index .FilesList (ctx , storeKey )
419443}
444+
445+ func (fn * fileNode ) OwnershipTransfer (ctx context.Context , spaceId , oldIdentity , aclRecordId string ) (err error ) {
446+ var (
447+ ownerPubKey crypto.PubKey
448+ ownerRecordIndex int
449+ )
450+ defer func () {
451+ log .InfoCtx (ctx , "ownership transfer" , zap .String ("spaceId" , spaceId ), zap .String ("recordId" , aclRecordId ), zap .Error (err ))
452+ }()
453+ err = fn .acl .ReadList (ctx , spaceId , func (aclList list.AclList ) error {
454+ if ! aclList .HasHead (aclRecordId ) {
455+ log .WarnCtx (ctx , "ownership transfer error: acl record not found" , zap .String ("spaceId" , spaceId ), zap .String ("recordId" , aclRecordId ))
456+ return fileprotoerr .ErrAclRecordNotFound
457+ }
458+ aclState := aclList .AclState ()
459+ var ownerRecordId string
460+ if ownerPubKey , ownerRecordId , err = aclState .OwnerPubKeyWithRecordId (); err != nil {
461+ log .WarnCtx (ctx , "acl ownerPubKey error" , zap .Error (err ))
462+ return fileprotoerr .ErrForbidden
463+ }
464+ ownerRecordIndex = aclList .GetRecordIndex (ownerRecordId )
465+ if ownerRecordIndex < 0 {
466+ log .ErrorCtx (ctx , "acl ownerRecordIndex not found" , zap .String ("spaceId" , spaceId ), zap .String ("recordId" , ownerRecordId ), zap .Error (err ))
467+ return fileprotoerr .ErrUnexpected
468+ }
469+ return nil
470+ })
471+ if err != nil {
472+ return
473+ }
474+ return fn .index .CheckAndMoveOwnership (ctx , index.Key {GroupId : ownerPubKey .Account (), SpaceId : spaceId }, oldIdentity , ownerRecordIndex )
475+ }
0 commit comments