mirror of
https://github.com/henrybear327/Proton-API-Bridge.git
synced 2026-05-19 04:16:09 -04:00
Implememt the file download seek support
Update to support more fields in RevisionXAttrCommon
This commit is contained in:
@@ -406,3 +406,53 @@ func TestUploadLargeNumberOfBlocks(t *testing.T) {
|
||||
deleteBySearchingFromRoot(t, ctx, protonDrive, filename, false, false)
|
||||
checkActiveFileListing(t, ctx, protonDrive, []string{})
|
||||
}
|
||||
|
||||
func TestFileSeek(t *testing.T) {
|
||||
ctx, cancel, protonDrive := setup(t, false)
|
||||
t.Cleanup(func() {
|
||||
defer cancel()
|
||||
defer tearDown(t, ctx, protonDrive)
|
||||
})
|
||||
|
||||
// in order to simulate seeking over blocks
|
||||
// we use 1KB for the UPLOAD_BLOCK_SIZE
|
||||
ORIGINAL_UPLOAD_BLOCK_SIZE := UPLOAD_BLOCK_SIZE
|
||||
defer func() {
|
||||
UPLOAD_BLOCK_SIZE = ORIGINAL_UPLOAD_BLOCK_SIZE
|
||||
}()
|
||||
blocks := 10
|
||||
UPLOAD_BLOCK_SIZE = 10
|
||||
|
||||
filename := "fileContent.txt"
|
||||
file1Content := RandomString(UPLOAD_BLOCK_SIZE*blocks + 5) // intentionally make the data not aligned to a block
|
||||
file1ContentReader := strings.NewReader(file1Content)
|
||||
|
||||
log.Println("Upload fileContent.txt")
|
||||
uploadFileByReader(t, ctx, protonDrive, "", filename, file1ContentReader, 0)
|
||||
checkRevisions(protonDrive, ctx, t, filename, 1, 1, 0, 0)
|
||||
checkActiveFileListing(t, ctx, protonDrive, []string{"/" + filename})
|
||||
|
||||
{
|
||||
log.Println("Download fileContent.txt with offset 0")
|
||||
downloadFileWithOffset(t, ctx, protonDrive, "", filename, "", file1Content, 0)
|
||||
}
|
||||
{
|
||||
offset := int64(UPLOAD_BLOCK_SIZE)
|
||||
log.Println("Download fileContent.txt with offset", offset)
|
||||
downloadFileWithOffset(t, ctx, protonDrive, "", filename, "", file1Content[offset:], offset)
|
||||
}
|
||||
{
|
||||
offset := int64(UPLOAD_BLOCK_SIZE + 5)
|
||||
log.Println("Download fileContent.txt with offset", offset)
|
||||
downloadFileWithOffset(t, ctx, protonDrive, "", filename, "", file1Content[offset:], offset)
|
||||
}
|
||||
{
|
||||
offset := int64(UPLOAD_BLOCK_SIZE*blocks/2 + 3)
|
||||
log.Println("Download fileContent.txt with offset", offset)
|
||||
downloadFileWithOffset(t, ctx, protonDrive, "", filename, "", file1Content[offset:], offset)
|
||||
}
|
||||
|
||||
log.Println("Delete file fileContent.txt")
|
||||
deleteBySearchingFromRoot(t, ctx, protonDrive, filename, false, false)
|
||||
checkActiveFileListing(t, ctx, protonDrive, []string{})
|
||||
}
|
||||
|
||||
@@ -188,6 +188,10 @@ func uploadFileByFilepath(t *testing.T, ctx context.Context, protonDrive *Proton
|
||||
}
|
||||
|
||||
func downloadFile(t *testing.T, ctx context.Context, protonDrive *ProtonDrive, parent, name string, filepath string, data string) {
|
||||
downloadFileWithOffset(t, ctx, protonDrive, parent, name, filepath, data, 0)
|
||||
}
|
||||
|
||||
func downloadFileWithOffset(t *testing.T, ctx context.Context, protonDrive *ProtonDrive, parent, name string, filepath string, data string, offset int64) {
|
||||
parentLink := protonDrive.RootLink
|
||||
if parent != "" {
|
||||
targetFolderLink, err := protonDrive.SearchByNameRecursivelyFromRoot(ctx, parent, true, false)
|
||||
@@ -211,7 +215,7 @@ func downloadFile(t *testing.T, ctx context.Context, protonDrive *ProtonDrive, p
|
||||
if targetFileLink == nil {
|
||||
t.Fatalf("File %v not found", name)
|
||||
} else {
|
||||
reader, sizeOnServer, fileSystemAttr, err := protonDrive.DownloadFileByID(ctx, targetFileLink.LinkID)
|
||||
reader, sizeOnServer, fileSystemAttr, err := protonDrive.DownloadFileByID(ctx, targetFileLink.LinkID, offset)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -228,7 +232,7 @@ func downloadFile(t *testing.T, ctx context.Context, protonDrive *ProtonDrive, p
|
||||
if fileSystemAttr.Size != 0 && sizeOnServer == fileSystemAttr.Size {
|
||||
t.Fatalf("Not possible due to encryption file overhead")
|
||||
}
|
||||
if len(downloadedData) != int(fileSystemAttr.Size) {
|
||||
if offset == 0 && len(downloadedData) != int(fileSystemAttr.Size) {
|
||||
t.Fatalf("Downloaded file size != uploaded file size: %#v vs %#v", len(downloadedData), int(fileSystemAttr.Size))
|
||||
}
|
||||
}
|
||||
@@ -238,6 +242,7 @@ func downloadFile(t *testing.T, ctx context.Context, protonDrive *ProtonDrive, p
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
originalData = originalData[offset:]
|
||||
|
||||
if !bytes.Equal(downloadedData, originalData) {
|
||||
t.Fatalf("Downloaded content is different from the original content")
|
||||
|
||||
1
error.go
1
error.go
@@ -19,4 +19,5 @@ var (
|
||||
ErrCantFindDraftRevision = errors.New("can't find a draft revision")
|
||||
ErrWrongUsageOfGetLinkKR = errors.New("internal error for GetLinkKR - nil passed in for link")
|
||||
ErrWrongUsageOfGetLink = errors.New("internal error for getLink - empty linkID passed in")
|
||||
ErrSeekOffsetAfterSkippingBlocks = errors.New("internal error for download seek - the offset after skipping blocks is wrong")
|
||||
)
|
||||
|
||||
189
file.go
189
file.go
@@ -4,9 +4,12 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"log"
|
||||
"mime"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -20,6 +23,8 @@ import (
|
||||
type FileSystemAttrs struct {
|
||||
ModificationTime time.Time
|
||||
Size int64
|
||||
BlockSizes []int64
|
||||
Digests string // sha1 string
|
||||
}
|
||||
|
||||
type FileDownloadReader struct {
|
||||
@@ -33,12 +38,18 @@ type FileDownloadReader struct {
|
||||
nextRevision int
|
||||
|
||||
isEOF bool
|
||||
|
||||
// TODO: integrity check if the entire file is read
|
||||
}
|
||||
|
||||
func (r *FileDownloadReader) Read(p []byte) (int, error) {
|
||||
if r.data.Len() == 0 {
|
||||
// TODO: do we have memory sharing bug?
|
||||
// to avoid sharing the underlying buffer array across re-population
|
||||
r.data = bytes.NewBuffer(nil)
|
||||
|
||||
// we download and decrypt more content
|
||||
err := r.downloadFileOnRead()
|
||||
err := r.populateBufferOnRead()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -58,7 +69,33 @@ func (r *FileDownloadReader) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) DownloadFileByID(ctx context.Context, linkID string) (io.ReadCloser, int64, *FileSystemAttrs, error) {
|
||||
func (reader *FileDownloadReader) populateBufferOnRead() error {
|
||||
if len(reader.revision.Blocks) == 0 || len(reader.revision.Blocks) == reader.nextRevision {
|
||||
reader.isEOF = true
|
||||
return nil
|
||||
}
|
||||
|
||||
offset := reader.nextRevision
|
||||
for i := offset; i-offset < DOWNLOAD_BATCH_BLOCK_SIZE && i < len(reader.revision.Blocks); i++ {
|
||||
// TODO: parallel download
|
||||
blockReader, err := reader.protonDrive.c.GetBlock(reader.ctx, reader.revision.Blocks[i].BareURL, reader.revision.Blocks[i].Token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer blockReader.Close()
|
||||
|
||||
err = decryptBlockIntoBuffer(reader.sessionKey, reader.protonDrive.AddrKR, reader.nodeKR, reader.revision.Blocks[i].Hash, reader.revision.Blocks[i].EncSignature, reader.data, blockReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reader.nextRevision = i + 1
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) DownloadFileByID(ctx context.Context, linkID string, offset int64) (io.ReadCloser, int64, *FileSystemAttrs, error) {
|
||||
/* It's like event system, we need to get the latest information before creating the move request! */
|
||||
protonDrive.removeLinkIDFromCache(linkID, false)
|
||||
|
||||
@@ -67,7 +104,7 @@ func (protonDrive *ProtonDrive) DownloadFileByID(ctx context.Context, linkID str
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
|
||||
return protonDrive.DownloadFile(ctx, link)
|
||||
return protonDrive.DownloadFile(ctx, link, offset)
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) GetRevisions(ctx context.Context, link *proton.Link, revisionType proton.RevisionState) ([]*proton.RevisionMetadata, error) {
|
||||
@@ -88,6 +125,15 @@ func (protonDrive *ProtonDrive) GetRevisions(ctx context.Context, link *proton.L
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) GetActiveRevisionAttrsByID(ctx context.Context, linkID string) (*FileSystemAttrs, error) {
|
||||
link, err := protonDrive.getLink(ctx, linkID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return protonDrive.GetActiveRevisionAttrs(ctx, link)
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) GetActiveRevisionAttrs(ctx context.Context, link *proton.Link) (*FileSystemAttrs, error) {
|
||||
if link == nil {
|
||||
return nil, ErrLinkMustNotBeNil
|
||||
@@ -120,6 +166,8 @@ func (protonDrive *ProtonDrive) GetActiveRevisionAttrs(ctx context.Context, link
|
||||
return &FileSystemAttrs{
|
||||
ModificationTime: modificationTime,
|
||||
Size: revisionXAttrCommon.Size,
|
||||
BlockSizes: revisionXAttrCommon.BlockSizes,
|
||||
Digests: revisionXAttrCommon.Digests,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -160,10 +208,12 @@ func (protonDrive *ProtonDrive) GetActiveRevisionWithAttrs(ctx context.Context,
|
||||
return &revision, &FileSystemAttrs{
|
||||
ModificationTime: modificationTime,
|
||||
Size: revisionXAttrCommon.Size,
|
||||
BlockSizes: revisionXAttrCommon.BlockSizes,
|
||||
Digests: revisionXAttrCommon.Digests,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) DownloadFile(ctx context.Context, link *proton.Link) (io.ReadCloser, int64, *FileSystemAttrs, error) {
|
||||
func (protonDrive *ProtonDrive) DownloadFile(ctx context.Context, link *proton.Link, offset int64) (io.ReadCloser, int64, *FileSystemAttrs, error) {
|
||||
if link.Type != proton.LinkTypeFile {
|
||||
return nil, 0, nil, ErrLinkTypeMustToBeFileType
|
||||
}
|
||||
@@ -201,59 +251,67 @@ func (protonDrive *ProtonDrive) DownloadFile(ctx context.Context, link *proton.L
|
||||
isEOF: false,
|
||||
}
|
||||
|
||||
err = reader.downloadFileOnRead()
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
useFallbackDownload := false
|
||||
if fileSystemAttrs != nil {
|
||||
// based on offset, infer the nextRevision (0-based)
|
||||
if fileSystemAttrs.BlockSizes == nil {
|
||||
useFallbackDownload = true
|
||||
} else {
|
||||
// infer nextRevision
|
||||
totalBytes := int64(0)
|
||||
for i := 0; i < len(fileSystemAttrs.BlockSizes); i++ {
|
||||
prevTotalBytes := totalBytes
|
||||
totalBytes += fileSystemAttrs.BlockSizes[i]
|
||||
if offset <= totalBytes {
|
||||
offset = offset - prevTotalBytes
|
||||
reader.nextRevision = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// download will start from the specified block
|
||||
n, err := io.CopyN(io.Discard, reader, offset)
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
if int64(n) != offset {
|
||||
return nil, 0, nil, ErrSeekOffsetAfterSkippingBlocks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if useFallbackDownload {
|
||||
log.Println("Performing inefficient seek as metadata of encrypted file is missing")
|
||||
n, err := io.CopyN(io.Discard, reader, offset)
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
if int64(n) != offset {
|
||||
return nil, 0, nil, ErrSeekOffsetAfterSkippingBlocks
|
||||
}
|
||||
}
|
||||
return reader, link.Size, fileSystemAttrs, nil
|
||||
}
|
||||
|
||||
func (reader *FileDownloadReader) downloadFileOnRead() error {
|
||||
if len(reader.revision.Blocks) == 0 || len(reader.revision.Blocks) == reader.nextRevision {
|
||||
reader.isEOF = true
|
||||
return nil
|
||||
}
|
||||
|
||||
offset := reader.nextRevision
|
||||
for i := offset; i-offset < DOWNLOAD_BATCH_BLOCK_SIZE && i < len(reader.revision.Blocks); i++ {
|
||||
// TODO: parallel download
|
||||
blockReader, err := reader.protonDrive.c.GetBlock(reader.ctx, reader.revision.Blocks[i].BareURL, reader.revision.Blocks[i].Token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer blockReader.Close()
|
||||
|
||||
err = decryptBlockIntoBuffer(reader.sessionKey, reader.protonDrive.AddrKR, reader.nodeKR, reader.revision.Blocks[i].Hash, reader.revision.Blocks[i].EncSignature, reader.data, blockReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reader.nextRevision = i + 1
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) UploadFileByReader(ctx context.Context, parentLinkID string, filename string, modTime time.Time, file io.Reader, testParam int) (string, int64, error) {
|
||||
func (protonDrive *ProtonDrive) UploadFileByReader(ctx context.Context, parentLinkID string, filename string, modTime time.Time, file io.Reader, testParam int) (string, *proton.RevisionXAttrCommon, error) {
|
||||
parentLink, err := protonDrive.getLink(ctx, parentLinkID)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return protonDrive.uploadFile(ctx, parentLink, filename, modTime, file, testParam)
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) UploadFileByPath(ctx context.Context, parentLink *proton.Link, filename string, filePath string, testParam int) (string, int64, error) {
|
||||
func (protonDrive *ProtonDrive) UploadFileByPath(ctx context.Context, parentLink *proton.Link, filename string, filePath string, testParam int) (string, *proton.RevisionXAttrCommon, error) {
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
return "", nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
info, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
in := bufio.NewReader(f)
|
||||
@@ -455,14 +513,14 @@ func (protonDrive *ProtonDrive) createFileUploadDraft(ctx context.Context, paren
|
||||
return linkID, revisionID, newSessionKey, newNodeKR, nil
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) uploadAndCollectBlockData(ctx context.Context, newSessionKey *crypto.SessionKey, newNodeKR *crypto.KeyRing, file io.Reader, linkID, revisionID string) ([]byte, int64, error) {
|
||||
func (protonDrive *ProtonDrive) uploadAndCollectBlockData(ctx context.Context, newSessionKey *crypto.SessionKey, newNodeKR *crypto.KeyRing, file io.Reader, linkID, revisionID string) ([]byte, int64, []int64, string, error) {
|
||||
type PendingUploadBlocks struct {
|
||||
blockUploadInfo proton.BlockUploadInfo
|
||||
encData []byte
|
||||
}
|
||||
|
||||
if newSessionKey == nil || newNodeKR == nil {
|
||||
return nil, 0, ErrMissingInputUploadAndCollectBlockData
|
||||
return nil, 0, nil, "", ErrMissingInputUploadAndCollectBlockData
|
||||
}
|
||||
|
||||
totalFileSize := int64(0)
|
||||
@@ -520,11 +578,13 @@ func (protonDrive *ProtonDrive) uploadAndCollectBlockData(ctx context.Context, n
|
||||
}
|
||||
|
||||
shouldContinue := true
|
||||
sha1Digests := sha1.New()
|
||||
blockSizes := make([]int64, 0)
|
||||
for i := 1; shouldContinue; i++ {
|
||||
if (i-1) > 0 && (i-1)%UPLOAD_BATCH_BLOCK_SIZE == 0 {
|
||||
err := uploadPendingBlocks()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, 0, nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,26 +601,28 @@ func (protonDrive *ProtonDrive) uploadAndCollectBlockData(ctx context.Context, n
|
||||
shouldContinue = false
|
||||
} else {
|
||||
// all other errors
|
||||
return nil, 0, err
|
||||
return nil, 0, nil, "", err
|
||||
}
|
||||
}
|
||||
data = data[:readBytes]
|
||||
totalFileSize += int64(readBytes)
|
||||
sha1Digests.Write(data)
|
||||
blockSizes = append(blockSizes, int64(readBytes))
|
||||
|
||||
// encrypt data
|
||||
dataPlainMessage := crypto.NewPlainMessage(data)
|
||||
encData, err := newSessionKey.Encrypt(dataPlainMessage)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, 0, nil, "", err
|
||||
}
|
||||
|
||||
encSignature, err := protonDrive.AddrKR.SignDetachedEncrypted(dataPlainMessage, newNodeKR)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, 0, nil, "", err
|
||||
}
|
||||
encSignatureStr, err := encSignature.GetArmored()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, 0, nil, "", err
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
@@ -568,7 +630,7 @@ func (protonDrive *ProtonDrive) uploadAndCollectBlockData(ctx context.Context, n
|
||||
hash := h.Sum(nil)
|
||||
base64Hash := base64.StdEncoding.EncodeToString(hash)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, 0, nil, "", err
|
||||
}
|
||||
manifestSignatureData = append(manifestSignatureData, hash...)
|
||||
|
||||
@@ -584,13 +646,15 @@ func (protonDrive *ProtonDrive) uploadAndCollectBlockData(ctx context.Context, n
|
||||
}
|
||||
err := uploadPendingBlocks()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
return nil, 0, nil, "", err
|
||||
}
|
||||
|
||||
return manifestSignatureData, totalFileSize, nil
|
||||
sha1Hash := sha1Digests.Sum(nil)
|
||||
sha1String := hex.EncodeToString(sha1Hash)
|
||||
return manifestSignatureData, totalFileSize, blockSizes, sha1String, nil
|
||||
}
|
||||
|
||||
func (protonDrive *ProtonDrive) commitNewRevision(ctx context.Context, nodeKR *crypto.KeyRing, modificationTime time.Time, size int64, manifestSignatureData []byte, linkID, revisionID string) error {
|
||||
func (protonDrive *ProtonDrive) commitNewRevision(ctx context.Context, nodeKR *crypto.KeyRing, xAttrCommon *proton.RevisionXAttrCommon, manifestSignatureData []byte, linkID, revisionID string) error {
|
||||
manifestSignature, err := protonDrive.AddrKR.SignDetached(crypto.NewPlainMessage(manifestSignatureData))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -604,7 +668,8 @@ func (protonDrive *ProtonDrive) commitNewRevision(ctx context.Context, nodeKR *c
|
||||
ManifestSignature: manifestSignatureString,
|
||||
SignatureAddress: protonDrive.signatureAddress,
|
||||
}
|
||||
err = commitRevisionReq.SetEncXAttrString(protonDrive.AddrKR, nodeKR, modificationTime, size)
|
||||
|
||||
err = commitRevisionReq.SetEncXAttrString(protonDrive.AddrKR, nodeKR, xAttrCommon)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -621,7 +686,7 @@ func (protonDrive *ProtonDrive) commitNewRevision(ctx context.Context, nodeKR *c
|
||||
// 0 = normal mode
|
||||
// 1 = up to create revision
|
||||
// 2 = up to block upload
|
||||
func (protonDrive *ProtonDrive) uploadFile(ctx context.Context, parentLink *proton.Link, filename string, modTime time.Time, file io.Reader, testParam int) (string, int64, error) {
|
||||
func (protonDrive *ProtonDrive) uploadFile(ctx context.Context, parentLink *proton.Link, filename string, modTime time.Time, file io.Reader, testParam int) (string, *proton.RevisionXAttrCommon, error) {
|
||||
// TODO: if we should use github.com/gabriel-vasile/mimetype to detect the MIME type from the file content itself
|
||||
// Note: this approach might cause the upload progress to display the "fake" progress, since we read in all the content all-at-once
|
||||
// mimetype.SetLimit(0)
|
||||
@@ -638,32 +703,38 @@ func (protonDrive *ProtonDrive) uploadFile(ctx context.Context, parentLink *prot
|
||||
/* step 1: create a draft */
|
||||
linkID, revisionID, newSessionKey, newNodeKR, err := protonDrive.createFileUploadDraft(ctx, parentLink, filename, modTime, mimeType)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if testParam == 1 {
|
||||
return "", 0, nil
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
/* step 2: upload blocks and collect block data */
|
||||
manifestSignature, fileSize, err := protonDrive.uploadAndCollectBlockData(ctx, newSessionKey, newNodeKR, file, linkID, revisionID)
|
||||
manifestSignature, fileSize, blockSizes, digests, err := protonDrive.uploadAndCollectBlockData(ctx, newSessionKey, newNodeKR, file, linkID, revisionID)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if testParam == 2 {
|
||||
// for integration tests
|
||||
// we try to simulate blocks uploaded but not yet commited
|
||||
return "", 0, nil
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
/* step 3: mark the file as active by commiting the revision */
|
||||
err = protonDrive.commitNewRevision(ctx, newNodeKR, modTime, fileSize, manifestSignature, linkID, revisionID)
|
||||
xAttrCommon := &proton.RevisionXAttrCommon{
|
||||
ModificationTime: modTime.Format("2006-01-02T15:04:05-0700"), /* ISO8601 */
|
||||
Size: fileSize,
|
||||
BlockSizes: blockSizes,
|
||||
Digests: digests,
|
||||
}
|
||||
err = protonDrive.commitNewRevision(ctx, newNodeKR, xAttrCommon, manifestSignature, linkID, revisionID)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return linkID, fileSize, nil
|
||||
return linkID, xAttrCommon, nil
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -106,7 +106,7 @@ func (protonDrive *ProtonDrive) ListDirectoriesRecursively(
|
||||
log.Println("Downloading", currentPath)
|
||||
defer log.Println("Completes downloading", currentPath)
|
||||
|
||||
reader, _, _, err := protonDrive.DownloadFile(ctx, link)
|
||||
reader, _, _, err := protonDrive.DownloadFile(ctx, link, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
10
go.mod
10
go.mod
@@ -3,20 +3,21 @@ module github.com/henrybear327/Proton-API-Bridge
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.1
|
||||
github.com/henrybear327/go-proton-api v0.0.0-20230713211354-02be61689e29
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.2
|
||||
github.com/henrybear327/go-proton-api v0.0.0-20230717103708-031d819d74ab
|
||||
github.com/relvacode/iso8601 v1.3.0
|
||||
golang.org/x/sync v0.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf // indirect
|
||||
github.com/ProtonMail/gluon v0.17.0 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230710112148-e01326fd72eb // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
|
||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect
|
||||
github.com/ProtonMail/go-srp v0.0.7 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.8.1 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.2 // indirect
|
||||
github.com/bradenaw/juniper v0.13.0 // indirect
|
||||
github.com/bradenaw/juniper v0.13.1 // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/cronokirby/saferith v0.33.0 // indirect
|
||||
github.com/emersion/go-message v0.16.0 // indirect
|
||||
@@ -29,7 +30,6 @@ require (
|
||||
golang.org/x/crypto v0.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
|
||||
golang.org/x/net v0.12.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
)
|
||||
|
||||
16
go.sum
16
go.sum
@@ -5,21 +5,21 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9
|
||||
github.com/ProtonMail/gluon v0.17.0 h1:QfMRUcXd47MANHmoerj1ZHXsNzfW9gjsLmF+7Dim5ZU=
|
||||
github.com/ProtonMail/gluon v0.17.0/go.mod h1:Og5/Dz1MiGpCJn51XujZwxiLG7WzvvjE5PRpZBQmAHo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230710112148-e01326fd72eb h1:RU+Ff2vE68zFQSoBqlb/LChFztEWWJ9EZ8LU4gA3ubU=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230710112148-e01326fd72eb/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=
|
||||
github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=
|
||||
github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1JrI=
|
||||
github.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.1/go.mod h1:/BU5gfAVwqyd8EfC3Eu7zmuhwYQpKs+cGD8M//iiaxs=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.2 h1:mIwxSUPezxNYq0RA5106VPWyKC+Ly3FvBUnBJh/7GWw=
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.2/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g=
|
||||
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
||||
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
||||
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
||||
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
||||
github.com/bradenaw/juniper v0.13.0 h1:KKMAiWDkRt45YUNzzw00Jec4nOgWDLVtztjf39E0ppI=
|
||||
github.com/bradenaw/juniper v0.13.0/go.mod h1:Z2B7aJlQ7xbfWsnMLROj5t/5FQ94/MkIdKC30J4WvzI=
|
||||
github.com/bradenaw/juniper v0.13.1 h1:9P7/xeaYuEyqPuJHSHCJoisWyPvZH4FAi59BxJLh7F8=
|
||||
github.com/bradenaw/juniper v0.13.1/go.mod h1:Z2B7aJlQ7xbfWsnMLROj5t/5FQ94/MkIdKC30J4WvzI=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
@@ -49,8 +49,8 @@ github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSM
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/henrybear327/go-proton-api v0.0.0-20230713211354-02be61689e29 h1:OUVzxoIPZ6T4yC5hzvvIEjRaYwom3c9N5VwJgJvr9cs=
|
||||
github.com/henrybear327/go-proton-api v0.0.0-20230713211354-02be61689e29/go.mod h1:l42xBSOrCmkAxzWUHcoUsG/cP8m1hMhV72GoChOX3bg=
|
||||
github.com/henrybear327/go-proton-api v0.0.0-20230717103708-031d819d74ab h1:Lj7+orKyKsOo3UwlopF+IxC7RWdyboAi800RWHiI8Ig=
|
||||
github.com/henrybear327/go-proton-api v0.0.0-20230717103708-031d819d74ab/go.mod h1:l42xBSOrCmkAxzWUHcoUsG/cP8m1hMhV72GoChOX3bg=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
|
||||
Reference in New Issue
Block a user