package main
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
errors "git.sequentialread.com/forest/pkg-errors"
)
type BackblazeB2Service struct {
BaseHTTPService
BackblazeBucketName string
BackblazeKeyId string
BackblazeSecretKey string
BackblazeDownloadUrl string
BackblazeAuthorizationToken string
BackblazeAuthorizationTimestamp time . Time
}
const B2_AUTHORIZE_URL = "https://api.backblazeb2.com/b2api/v2/b2_authorize_account"
func NewBackblazeB2Service ( config * Config ) * BackblazeB2Service {
toReturn := & BackblazeB2Service {
BackblazeBucketName : config . BackblazeBucketName ,
BackblazeKeyId : config . BackblazeKeyId ,
BackblazeSecretKey : config . BackblazeSecretKey ,
}
toReturn . ClientFactory = func ( ) ( * http . Client , * time . Time , error ) {
return & http . Client { Timeout : 10 * time . Second } , nil , nil
}
return toReturn
}
func ( service * BackblazeB2Service ) Get ( key string ) ( [ ] byte , error ) {
authTokenIsExpired := time . Now ( ) . After ( service . BackblazeAuthorizationTimestamp . Add ( time . Hour ) )
if service . BackblazeAuthorizationToken == "" || authTokenIsExpired {
err := service . login ( )
if err != nil {
return nil , errors . Wrap ( err , "could not log in to backblaze b2" )
}
}
if strings . HasPrefix ( key , "/" ) {
key = key [ 1 : ]
}
url := fmt . Sprintf ( "%s/file/%s/%s" , service . BackblazeDownloadUrl , service . BackblazeBucketName , key )
statusCode , responseBytes , err := service . MyHTTP (
"GET" ,
url ,
nil ,
func ( request * http . Request ) {
request . Header . Add ( "Authorization" , service . BackblazeAuthorizationToken )
} ,
)
if err != nil {
return nil , err
}
// if its not found just return nil with no error
if statusCode == 404 {
return nil , nil
} else if statusCode >= 300 {
return responseBytes , fmt . Errorf ( "HTTP %d when HTTP GET-ing %s " , statusCode , url )
}
return responseBytes , nil
}
func ( service * BackblazeB2Service ) login ( ) error {
statusCode , responseBytes , err := service . MyHTTP (
"GET" ,
B2_AUTHORIZE_URL ,
nil ,
func ( request * http . Request ) {
request . SetBasicAuth ( service . BackblazeKeyId , service . BackblazeSecretKey )
} ,
)
if err != nil {
return err
}
if statusCode < 300 {
var loginResponse struct {
AuthorizationToken string ` json:"authorizationToken" `
DownloadUrl string ` json:"downloadUrl" `
}
err = json . Unmarshal ( responseBytes , & loginResponse )
if err != nil {
return errors . Wrap ( err , "response unmarshal error" )
}
service . BackblazeDownloadUrl = loginResponse . DownloadUrl
service . BackblazeAuthorizationToken = loginResponse . AuthorizationToken
service . BackblazeAuthorizationTimestamp = time . Now ( )
return nil
}
var backblazeErr struct {
Status int ` json:"status" `
Code string ` json:"code" `
Message string ` json:"message" `
}
err = json . Unmarshal ( responseBytes , & backblazeErr )
if err != nil {
return errors . Wrap ( err , "error response unmarshal error" )
}
return errors . Wrapf ( err , "HTTP %d, %s: %s" , backblazeErr . Status , backblazeErr . Code , backblazeErr . Message )
}
func ( service * BackblazeB2Service ) GetFileUploadShellScript ( ) string {
return fmt . Sprintf ( `
BUCKET_NAME = "%s"
AUTH_JSON = "$(curl -sS -u " % s : % s " https://api.backblazeb2.com/b2api/v2/b2_authorize_account)"
API_URL = "$(echo " $ AUTH_JSON " | grep -E -o '" apiUrl ": " ( [ ^ "]+)" ' | sed - E ' s | "apiUrl" : "([^" ] + ) "|\1|')"
ACCOUNT_ID = "$(echo " $ AUTH_JSON " | grep -E -o '" accountId ": " ( [ ^ "]+)" ' | sed - E ' s | "accountId" : "([^" ] + ) "|\1|')"
AUTH_TOKEN = "$(echo " $ AUTH_JSON " | grep -E -o '" authorizationToken ": " ( [ ^ "]+)" ' | sed - E ' s | "authorizationToken" : "([^" ] + ) "|\1|')"
LIST_BUCKETS_JSON = "$(curl -sS -H " Authorization : $ AUTH_TOKEN " " $ API_URL / b2api / v2 / b2_list_buckets ? accountId = $ ACCOUNT_ID & bucketName = $ BUCKET_NAME " )"
BUCKET_ID = "$(echo " $ LIST_BUCKETS_JSON " | grep -E -o '" bucketId ": " ( [ ^ "]+)" ' | sed - E ' s | "bucketId" : "([^" ] + ) "|\1|')"
UPLOAD_URL_JSON = "$(curl -sS -H " Authorization : $ AUTH_TOKEN " " $ API_URL / b2api / v2 / b2_get_upload_url ? bucketId = $ BUCKET_ID " )"
UPLOAD_URL = "$(echo " $ UPLOAD_URL_JSON " | grep -E -o '" uploadUrl ": " ( [ ^ "]+)" ' | sed - E ' s | "uploadUrl" : "([^" ] + ) "|\1|')"
AUTH_TOKEN = "$(echo " $ UPLOAD_URL_JSON " | grep -E -o '" authorizationToken ": " ( [ ^ "]+)" ' | sed - E ' s | "authorizationToken" : "([^" ] + ) "|\1|')"
CONTENT_SHA1 = "$(echo -n " $ CONTENT " | sha1sum | awk '{ print $1 }')"
curl - sS - X POST \
- H "Authorization: $AUTH_TOKEN" \
- H "X-Bz-File-Name: $FILE_PATH" \
- H "X-Bz-Content-Sha1: $CONTENT_SHA1" \
- H "Content-Type: text/plain" \
"$UPLOAD_URL" - d "$CONTENT"
` , service . BackblazeBucketName , service . BackblazeKeyId , service . BackblazeSecretKey )
}