2020-02-24 18:07:47 +00:00
|
|
|
package files
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2020-03-30 20:51:26 +01:00
|
|
|
"crypto/sha1"
|
2020-02-24 18:07:47 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2020-03-19 10:13:38 +00:00
|
|
|
"io"
|
2020-02-24 18:07:47 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type BackblazeProvider struct {
|
|
|
|
FileProvider
|
|
|
|
Bucket string
|
2020-03-15 23:48:37 +00:00
|
|
|
DownloadLocation string
|
2020-02-24 18:07:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type BackblazeAuthPayload struct {
|
|
|
|
AccountId string `json:"accountId"`
|
|
|
|
AuthToken string `json:"authorizationToken"`
|
|
|
|
ApiUrl string `json:"apiUrl"`
|
2020-03-15 23:48:37 +00:00
|
|
|
DownloadUrl string `json:"downloadUrl"`
|
2020-02-24 18:07:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type BackblazeFile struct {
|
|
|
|
Action string `json:"action"`
|
2020-03-23 10:53:58 +00:00
|
|
|
Size int64 `json:"contentLength"`
|
2020-02-24 18:07:47 +00:00
|
|
|
Type string `json:"contentType"`
|
|
|
|
FileName string `json:"fileName"`
|
2020-03-23 10:53:58 +00:00
|
|
|
Timestamp int64 `json:"uploadTimestamp"`
|
2020-02-24 18:07:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type BackblazeFilePayload struct {
|
|
|
|
Files []BackblazeFile `json:"files"`
|
|
|
|
}
|
|
|
|
|
2020-03-15 23:48:37 +00:00
|
|
|
type BackblazeBucketInfo struct {
|
|
|
|
BucketId string `json:"bucketId"`
|
|
|
|
BucketName string `json:"bucketName"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type BackblazeBucketInfoPayload struct {
|
|
|
|
Buckets []BackblazeBucketInfo `json:"buckets"`
|
|
|
|
}
|
|
|
|
|
2020-03-30 20:51:26 +01:00
|
|
|
type BackblazeUploadInfo struct {
|
|
|
|
UploadUrl string `json:"uploadUrl"`
|
|
|
|
AuthToken string `json:"authorizationToken"`
|
|
|
|
}
|
|
|
|
|
2020-02-24 18:07:47 +00:00
|
|
|
// Call Backblaze API endpoint to authorize and gather facts.
|
2020-03-21 00:31:24 +00:00
|
|
|
func (bp *BackblazeProvider) Setup(args map[string]string) bool {
|
|
|
|
applicationKeyId := args["applicationKeyId"]
|
|
|
|
applicationKey := args["applicationKey"]
|
|
|
|
|
2020-02-24 18:07:47 +00:00
|
|
|
client := &http.Client{}
|
|
|
|
req, err := http.NewRequest("GET",
|
|
|
|
"https://api.backblazeb2.com/b2api/v2/b2_authorize_account",
|
|
|
|
nil)
|
|
|
|
if err != nil {
|
2020-03-21 00:31:24 +00:00
|
|
|
return false
|
2020-02-24 18:07:47 +00:00
|
|
|
}
|
2020-03-21 00:31:24 +00:00
|
|
|
req.SetBasicAuth(applicationKeyId, applicationKey)
|
2020-02-24 18:07:47 +00:00
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
2020-03-21 00:31:24 +00:00
|
|
|
return false
|
2020-02-24 18:07:47 +00:00
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
2020-03-21 00:31:24 +00:00
|
|
|
|
2020-02-24 18:07:47 +00:00
|
|
|
if err != nil {
|
2020-03-21 00:31:24 +00:00
|
|
|
return false
|
2020-02-24 18:07:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var data BackblazeAuthPayload
|
|
|
|
|
|
|
|
err = json.Unmarshal(body, &data)
|
|
|
|
if err != nil {
|
2020-03-21 00:31:24 +00:00
|
|
|
return false
|
2020-02-24 18:07:47 +00:00
|
|
|
}
|
2020-03-21 00:31:24 +00:00
|
|
|
|
2020-02-24 18:07:47 +00:00
|
|
|
bp.Authentication = data.AuthToken
|
|
|
|
bp.Location = data.ApiUrl
|
2020-03-15 23:48:37 +00:00
|
|
|
bp.Name = data.AccountId
|
|
|
|
bp.DownloadLocation = data.DownloadUrl
|
2020-03-21 00:31:24 +00:00
|
|
|
|
|
|
|
return true
|
2020-02-24 18:07:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (bp *BackblazeProvider) GetDirectory(path string) Directory {
|
|
|
|
client := &http.Client{}
|
|
|
|
|
|
|
|
requestBody := fmt.Sprintf(`{"bucketId": "%s"}`, bp.Bucket)
|
|
|
|
|
|
|
|
req, err := http.NewRequest("POST",
|
|
|
|
bp.Location + "/b2api/v2/b2_list_file_names",
|
|
|
|
bytes.NewBuffer([]byte(requestBody)))
|
|
|
|
if err != nil {
|
2020-03-23 10:53:58 +00:00
|
|
|
fmt.Println(err.Error())
|
2020-02-24 18:07:47 +00:00
|
|
|
return Directory{}
|
|
|
|
}
|
|
|
|
req.Header.Add("Authorization", bp.Authentication)
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
2020-03-23 10:53:58 +00:00
|
|
|
fmt.Println(err.Error())
|
2020-02-24 18:07:47 +00:00
|
|
|
return Directory{}
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
2020-03-23 10:53:58 +00:00
|
|
|
fmt.Println(err.Error())
|
2020-02-24 18:07:47 +00:00
|
|
|
return Directory{}
|
|
|
|
}
|
|
|
|
|
|
|
|
var data BackblazeFilePayload
|
|
|
|
err = json.Unmarshal(body, &data)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return Directory{}
|
|
|
|
}
|
|
|
|
finalDir := Directory{
|
|
|
|
Path: bp.Bucket,
|
|
|
|
}
|
|
|
|
for _, v := range data.Files {
|
|
|
|
file := FileInfo{
|
|
|
|
IsDirectory: v.Action == "folder",
|
|
|
|
Name: v.FileName,
|
|
|
|
}
|
|
|
|
if v.Action != "folder" {
|
|
|
|
split := strings.Split(v.FileName, ".")
|
|
|
|
file.Extension = split[len(split) - 1]
|
|
|
|
}
|
|
|
|
finalDir.Files = append(finalDir.Files, file)
|
|
|
|
}
|
|
|
|
|
|
|
|
return finalDir
|
|
|
|
}
|
|
|
|
|
2020-04-15 23:19:33 +01:00
|
|
|
func (bp *BackblazeProvider) FilePath(path string) string {
|
2020-04-15 12:16:27 +01:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bp *BackblazeProvider) RemoteFile(path string, w io.Writer) {
|
2020-03-15 23:48:37 +00:00
|
|
|
client := &http.Client{}
|
|
|
|
// Get bucket name >:(
|
|
|
|
bucketIdPayload := fmt.Sprintf(`{"accountId": "%s", "bucketId": "%s"}`, bp.Name, bp.Bucket)
|
|
|
|
|
|
|
|
req, err := http.NewRequest("POST", bp.Location + "/b2api/v2/b2_list_buckets",
|
|
|
|
bytes.NewBuffer([]byte(bucketIdPayload)))
|
2020-03-21 00:31:24 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return
|
|
|
|
}
|
2020-03-15 23:48:37 +00:00
|
|
|
req.Header.Add("Authorization", bp.Authentication)
|
|
|
|
|
|
|
|
res, err := client.Do(req)
|
2020-03-21 00:31:24 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return
|
|
|
|
}
|
2020-03-15 23:48:37 +00:00
|
|
|
bucketData, err := ioutil.ReadAll(res.Body)
|
2020-03-21 00:31:24 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return
|
|
|
|
}
|
2020-03-15 23:48:37 +00:00
|
|
|
|
|
|
|
var data BackblazeBucketInfoPayload
|
|
|
|
json.Unmarshal(bucketData, &data)
|
|
|
|
ourBucket := data.Buckets[0].BucketName
|
|
|
|
// Get file and write over to client.
|
|
|
|
url := strings.Join([]string{bp.DownloadLocation,"file",ourBucket,path}, "/")
|
|
|
|
req, err = http.NewRequest("GET",
|
|
|
|
url,
|
|
|
|
bytes.NewBuffer([]byte("")))
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
2020-03-19 10:13:38 +00:00
|
|
|
return
|
2020-03-15 23:48:37 +00:00
|
|
|
}
|
|
|
|
req.Header.Add("Authorization", bp.Authentication)
|
|
|
|
file, err := client.Do(req)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
2020-03-19 10:13:38 +00:00
|
|
|
return
|
2020-03-15 23:48:37 +00:00
|
|
|
}
|
|
|
|
|
2020-03-19 10:13:38 +00:00
|
|
|
_, err = io.Copy(w, file.Body)
|
2020-03-15 23:48:37 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
2020-03-19 10:13:38 +00:00
|
|
|
return
|
2020-03-15 23:48:37 +00:00
|
|
|
}
|
2020-02-24 18:07:47 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 13:26:06 +01:00
|
|
|
func (bp *BackblazeProvider) SaveFile(file io.Reader, filename string, path string) bool {
|
2020-03-30 20:51:26 +01:00
|
|
|
client := &http.Client{}
|
|
|
|
bucketIdPayload := fmt.Sprintf(`{"bucketId": "%s"}`, bp.Bucket)
|
|
|
|
|
|
|
|
req, err := http.NewRequest("POST", bp.Location + "/b2api/v2/b2_get_upload_url",
|
|
|
|
bytes.NewBuffer([]byte(bucketIdPayload)))
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
req.Header.Add("Authorization", bp.Authentication)
|
|
|
|
|
|
|
|
res, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
bucketData, err := ioutil.ReadAll(res.Body)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
var data BackblazeUploadInfo
|
2020-04-02 15:31:30 +01:00
|
|
|
err = json.Unmarshal(bucketData, &data)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return false
|
|
|
|
}
|
2020-03-30 20:51:26 +01:00
|
|
|
|
|
|
|
req, err = http.NewRequest("POST",
|
|
|
|
data.UploadUrl,
|
|
|
|
file,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
// Read the content
|
|
|
|
var bodyBytes []byte
|
|
|
|
if req.Body != nil {
|
|
|
|
bodyBytes, _ = ioutil.ReadAll(req.Body)
|
|
|
|
}
|
|
|
|
req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
|
|
|
|
|
|
|
|
// Calculate SHA1 and add required headers.
|
|
|
|
fileSha := sha1.New()
|
|
|
|
fileSha.Write(bodyBytes)
|
|
|
|
|
|
|
|
req.Header.Add("Authorization", data.AuthToken)
|
2020-04-03 13:26:06 +01:00
|
|
|
req.Header.Add("X-Bz-File-Name", filename)
|
2020-03-30 20:51:26 +01:00
|
|
|
req.Header.Add("Content-Type", "b2/x-auto")
|
|
|
|
req.Header.Add("X-Bz-Content-Sha1", fmt.Sprintf("%x", fileSha.Sum(nil)))
|
2020-04-03 13:26:06 +01:00
|
|
|
req.ContentLength = int64(len(bodyBytes))
|
2020-03-30 20:51:26 +01:00
|
|
|
|
2020-04-02 15:31:30 +01:00
|
|
|
res, err = client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
return false
|
|
|
|
}
|
2020-03-30 20:51:26 +01:00
|
|
|
|
2020-02-24 18:07:47 +00:00
|
|
|
return true
|
2020-03-15 23:48:37 +00:00
|
|
|
}
|
|
|
|
|
2020-04-15 23:19:33 +01:00
|
|
|
func (bp *BackblazeProvider) ObjectInfo(path string) (bool, bool, string) {
|
2020-04-12 22:10:51 +01:00
|
|
|
// B2 is really a "flat" filesystem, with directories being virtual.
|
|
|
|
// Therefore, we can assume everything is a file ;)
|
2020-04-15 23:19:33 +01:00
|
|
|
// TODO: Return true value.
|
|
|
|
isDir := path == ""
|
|
|
|
return true, isDir, FILE_IS_REMOTE
|
2020-03-21 00:31:24 +00:00
|
|
|
}
|
2020-04-12 22:10:51 +01:00
|
|
|
|
|
|
|
func (bp *BackblazeProvider) CreateDirectory(path string) bool {
|
|
|
|
// See above comment about virtual directories.
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bp *BackblazeProvider) Delete(path string) bool {
|
|
|
|
// TODO
|
|
|
|
return false
|
|
|
|
}
|