-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
search.go
109 lines (92 loc) · 3.07 KB
/
search.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package proton_api_bridge
import (
"context"
"github.com/henrybear327/go-proton-api"
)
/*
The filename is unique in a given folder, since it's checked (by using hash) on the server
*/
// if the target isn't found, nil will be returned for both return values
func (protonDrive *ProtonDrive) SearchByNameInActiveFolderByID(ctx context.Context,
folderLinkID string,
targetName string,
searchForFile, searchForFolder bool,
targetState proton.LinkState) (*proton.Link, error) {
folderLink, err := protonDrive.getLink(ctx, folderLinkID)
if err != nil {
return nil, err
}
return protonDrive.SearchByNameInActiveFolder(ctx, folderLink, targetName, searchForFile, searchForFolder, targetState)
}
func (protonDrive *ProtonDrive) SearchByNameInActiveFolder(
ctx context.Context,
folderLink *proton.Link,
targetName string,
searchForFile, searchForFolder bool,
targetState proton.LinkState) (*proton.Link, error) {
if !searchForFile && !searchForFolder {
// nothing to search
return nil, nil
}
// we search all folders and files within this designated folder only
if folderLink.Type != proton.LinkTypeFolder {
return nil, ErrLinkTypeMustToBeFolderType
}
if folderLink.State != proton.LinkStateActive {
// we only search in the active folders
return nil, nil
}
// get target name Hash
parentNodeKR, err := protonDrive.getLinkKRByID(ctx, folderLink.ParentLinkID)
if err != nil {
return nil, err
}
signatureVerificationKR, err := protonDrive.getSignatureVerificationKeyring([]string{folderLink.SignatureEmail})
if err != nil {
return nil, err
}
folderLinkKR, err := folderLink.GetKeyRing(parentNodeKR, signatureVerificationKR)
if err != nil {
return nil, err
}
signatureVerificationKR, err = protonDrive.getSignatureVerificationKeyring([]string{folderLink.SignatureEmail}, folderLinkKR)
if err != nil {
return nil, err
}
folderHashKey, err := folderLink.GetHashKey(folderLinkKR, signatureVerificationKR)
if err != nil {
return nil, err
}
targetNameHash, err := proton.GetNameHash(targetName, folderHashKey)
if err != nil {
return nil, err
}
// use available hash to check if it exists
// more efficient than linear scan to just do existence check
// used in rclone when Put(), it will try to see if the object exists or not
res, err := protonDrive.c.CheckAvailableHashes(ctx, protonDrive.MainShare.ShareID, folderLink.LinkID, proton.CheckAvailableHashesReq{
Hashes: []string{targetNameHash},
})
if err != nil {
return nil, err
}
if len(res.AvailableHashes) == 1 {
// name isn't taken == name doesn't exist
return nil, nil
}
childrenLinks, err := protonDrive.c.ListChildren(ctx, protonDrive.MainShare.ShareID, folderLink.LinkID, true)
if err != nil {
return nil, err
}
for _, childLink := range childrenLinks {
if childLink.State != targetState {
continue
}
if searchForFile && childLink.Type == proton.LinkTypeFile && childLink.Hash == targetNameHash {
return &childLink, nil
} else if searchForFolder && childLink.Type == proton.LinkTypeFolder && childLink.Hash == targetNameHash {
return &childLink, nil
}
}
return nil, nil
}