🌱🏠 instant least-authority port-forwarding (with automatic HTTPS) for anyone, anywhere! We **really** don't want your TLS private keys, you can keep them 😃 https://greenhouse.server.garden/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
4.5 KiB

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)
}