package proton_api_bridge import ( "context" "log" "github.com/henrybear327/Proton-API-Bridge/common" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/henrybear327/go-proton-api" ) type ProtonDrive struct { MainShare *proton.Share RootLink *proton.Link MainShareKR *crypto.KeyRing AddrKR *crypto.KeyRing Config *common.Config c *proton.Client m *proton.Manager userKR *crypto.KeyRing addrKRs map[string]*crypto.KeyRing addrData []proton.Address signatureAddress string } func NewDefaultConfig() *common.Config { return common.NewConfigWithDefaultValues() } func NewProtonDrive(ctx context.Context, config *common.Config) (*ProtonDrive, error) { /* Log in and logout */ m, c, userKR, addrKRs, addrData, err := common.Login(ctx, config) if err != nil { return nil, err } /* Current understanding (at the time of the commit) The volume is the mount point. A link is like a folder in POSIX. A share is associated with a link to represent the access control, and serves as an entry point to a location in the file structure (Volume). It points to a link, of file or folder type, anywhere in the tree and holds a key called the ShareKey. To access a link, of file or folder type, a user must be a member of a share. A volume has a default share for access control and is owned by the creator of the volume. A volume has a default link as it's root folder. MIMETYPE holds type, e.g. folder, image/png, etc. */ volumes, err := listAllVolumes(ctx, c) if err != nil { return nil, err } // log.Printf("all volumes %#v", volumes) mainShareID := "" for i := range volumes { // iOS drive: first active volume if volumes[i].State == proton.VolumeStateActive { mainShareID = volumes[i].Share.ShareID } } // log.Println("total volumes", len(volumes), "mainShareID", mainShareID) /* Get root folder from the main share of the volume */ mainShare, err := getShareByID(ctx, c, mainShareID) if err != nil { return nil, err } // check for main share integrity { mainShareCheck := false shares, err := getAllShares(ctx, c) if err != nil { return nil, err } for i := range shares { if shares[i].ShareID == mainShare.ShareID && shares[i].LinkID == mainShare.LinkID && shares[i].Flags == proton.PrimaryShare && shares[i].Type == proton.ShareTypeMain { mainShareCheck = true } } if !mainShareCheck { log.Printf("mainShare %#v", mainShare) log.Printf("shares %#v", shares) return nil, ErrMainSharePreconditionsFailed } } // Note: rootLink's parentLinkID == "" /* Link holds the tree structure, for the clients, they represent the files and folders of a given volume. They have a ParentLinkID that points to parent folders. Links also hold the file name (encrypted) and a hash of the name for name collisions. Link data is encrypted with its owning Share keyring. */ rootLink, err := c.GetLink(ctx, mainShare.ShareID, mainShare.LinkID) if err != nil { return nil, err } if err != nil { return nil, err } // log.Printf("rootLink %#v", rootLink) // log.Printf("addrKRs %#v", addrKRs)= addrKR := addrKRs[mainShare.AddressID] // log.Println("addrKR CountDecryptionEntities", addrKR.CountDecryptionEntities()) mainShareKR, err := mainShare.GetKeyRing(addrKR) if err != nil { return nil, err } // log.Println("mainShareKR CountDecryptionEntities", mainShareKR.CountDecryptionEntities()) return &ProtonDrive{ MainShare: mainShare, RootLink: &rootLink, MainShareKR: mainShareKR, AddrKR: addrKR, Config: config, c: c, m: m, userKR: userKR, addrKRs: addrKRs, addrData: addrData, signatureAddress: mainShare.Creator, }, nil } func (protonDrive *ProtonDrive) Logout(ctx context.Context) error { return common.Logout(ctx, protonDrive.Config, protonDrive.m, protonDrive.c, protonDrive.userKR, protonDrive.addrKRs) } func (protonDrive *ProtonDrive) About(ctx context.Context) (*proton.User, error) { user, err := protonDrive.c.GetUser(ctx) if err != nil { return nil, err } return &user, nil } func (protonDrive *ProtonDrive) GetLink(ctx context.Context, linkID string) (*proton.Link, error) { link, err := protonDrive.c.GetLink(ctx, protonDrive.MainShare.ShareID, linkID) return &link, err }