-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for downloading public files #24
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1037,6 +1037,112 @@ func (m *Mega) NewDownload(src *Node) (*Download, error) { | |
return d, nil | ||
} | ||
|
||
// Create a new public Download from the hash and key | ||
// | ||
// Call Chunks to find out how many chunks there are, then for id = | ||
// 0..chunks-1 call DownloadChunk. Finally call Finish() to receive | ||
// the error status. | ||
func (m *Mega) NewPublicDownload(hash, key string) (*Download, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not too sure on using the existing A nicer option may be a whole new |
||
var msg [1]DownloadMsg | ||
var res [1]DownloadResp | ||
|
||
// XXX: Do we need this mutex here? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think the mutex is required |
||
m.FS.mutex.Lock() | ||
msg[0].Cmd = "g" | ||
msg[0].G = 1 | ||
msg[0].P = hash | ||
m.FS.mutex.Unlock() | ||
|
||
request, err := json.Marshal(msg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
result, err := m.api_request(request) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
err = json.Unmarshal(result, &res) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// DownloadResp has an embedded error in it for some reason | ||
if res[0].Err != 0 { | ||
return nil, parseError(res[0].Err) | ||
} | ||
|
||
rawkey, err := base64urldecode(key) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
compkey, err := bytes_to_a32(rawkey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
aes_key, err := a32_to_bytes([]uint32{compkey[0] ^ compkey[4], compkey[1] ^ compkey[5], compkey[2] ^ compkey[6], compkey[3] ^ compkey[7]}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has been copied from |
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
attr, err := decryptAttr(aes_key, res[0].Attr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
chunks := getChunkSizes(int64(res[0].Size)) | ||
|
||
aes_block, err := aes.NewCipher(aes_key) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
mac_enc := cipher.NewCBCEncrypter(aes_block, zero_iv) | ||
|
||
var meta NodeMeta | ||
meta.key = aes_key | ||
meta.iv, err = a32_to_bytes([]uint32{compkey[4], compkey[5], 0, 0}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
meta.mac, err = a32_to_bytes([]uint32{compkey[6], compkey[7]}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
meta.compkey, err = a32_to_bytes(compkey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
t, err := bytes_to_a32(meta.iv) | ||
if err != nil { | ||
return nil, err | ||
} | ||
iv, err := a32_to_bytes([]uint32{t[0], t[1], t[0], t[1]}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
d := &Download{ | ||
m: m, | ||
src: &Node{ | ||
fs: m.FS, | ||
name: attr.Name, | ||
hash: hash, | ||
meta: meta, | ||
}, | ||
resourceUrl: res[0].G, | ||
aes_block: aes_block, | ||
iv: iv, | ||
mac_enc: mac_enc, | ||
chunks: chunks, | ||
chunk_macs: make([][]byte, len(chunks)), | ||
} | ||
return d, nil | ||
} | ||
|
||
// Chunks returns The number of chunks in the download. | ||
func (d *Download) Chunks() int { | ||
return len(d.chunks) | ||
|
@@ -1170,19 +1276,14 @@ func (d *Download) Finish() (err error) { | |
} | ||
|
||
// Download file from filesystem reporting progress if not nil | ||
func (m *Mega) DownloadFile(src *Node, dstpath string, progress *chan int) error { | ||
func (m *Mega) downloadFile(d *Download, dstpath string, progress *chan int) error { | ||
defer func() { | ||
if progress != nil { | ||
close(*progress) | ||
} | ||
}() | ||
|
||
d, err := m.NewDownload(src) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = os.Stat(dstpath) | ||
_, err := os.Stat(dstpath) | ||
if os.IsExist(err) { | ||
err = os.Remove(dstpath) | ||
if err != nil { | ||
|
@@ -1258,6 +1359,28 @@ func (m *Mega) DownloadFile(src *Node, dstpath string, progress *chan int) error | |
return d.Finish() | ||
} | ||
|
||
// Download file from filesystem reporting progress if not nil | ||
func (m *Mega) DownloadFile(src *Node, dstpath string, progress *chan int) error { | ||
d, err := m.NewDownload(src) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
return m.downloadFile(d, dstpath, progress) | ||
} | ||
|
||
// Download public file from filesystem reporting progress if not nil | ||
func (m *Mega) DownloadPublicFile(hash, key, dstpath string, progress *chan int) error { | ||
d, err := m.NewPublicDownload(hash, key) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
return m.downloadFile(d, dstpath, progress) | ||
} | ||
|
||
// Upload contains the internal state of a upload | ||
type Upload struct { | ||
m *Mega | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where do you get the hash for a public file? From the URL?
What about directories?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe hash isn't the best name... ID might be better?
I've not actually tested this with directories, but I'd guess that they work completely differently (looking at the URLs at least).