github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/security/ticket/b2.go (about)

     1  // Copyright 2018 GRAIL, Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache-2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package ticket
     6  
     7  import (
     8  	"encoding/base64"
     9  	"encoding/json"
    10  	"fmt"
    11  	"net/http"
    12  
    13  	"github.com/Schaudge/grailbase/common/log"
    14  	"github.com/Schaudge/grailbase/security/keycrypt"
    15  )
    16  
    17  const (
    18  	b2AuthorizeURL = "https://api.backblazeb2.com/b2api/v1/b2_authorize_account"
    19  )
    20  
    21  func (b *B2AccountAuthorizationBuilder) newB2Ticket(ctx *TicketContext) (TicketB2Ticket, error) {
    22  	log.Info(ctx.ctx, "Creating BackBlaze ticket.", "B2AccountAuthorizationBuilder", b)
    23  
    24  	b2Ticket, err := b.genB2Ticket(ctx)
    25  	if err != nil {
    26  		return TicketB2Ticket{}, err
    27  	}
    28  
    29  	return TicketB2Ticket{
    30  		Value: *b2Ticket,
    31  	}, nil
    32  }
    33  
    34  func (b *B2AccountAuthorizationBuilder) genB2Ticket(ctx *TicketContext) (*B2Ticket, error) {
    35  	secret, err := keycrypt.Lookup(b.ApplicationKey)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	applicationKey, err := secret.Get()
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	headerForAuthorizeAccount := "Basic " + base64.StdEncoding.EncodeToString([]byte(b.AccountId+":"+string(applicationKey)))
    46  
    47  	req, err := http.NewRequest("GET", b2AuthorizeURL, nil)
    48  	if err != nil {
    49  		log.Error(ctx.ctx, "Failed to create new request.", "b2AuthorizeURL", b2AuthorizeURL, "err", err.Error())
    50  		return nil, err
    51  	}
    52  	req.Header.Set("Authorization", headerForAuthorizeAccount)
    53  	client := &http.Client{}
    54  	resp, err := client.Do(req)
    55  	if err != nil {
    56  		log.Error(ctx.ctx, "Failed to authorize.", "b2AuthorizeURL", b2AuthorizeURL, "err", err.Error())
    57  		return nil, err
    58  	}
    59  	defer resp.Body.Close()
    60  
    61  	if resp.StatusCode != http.StatusOK {
    62  		type ErrorResponse struct {
    63  			Status  int
    64  			Code    string
    65  			Message string
    66  		}
    67  		var er ErrorResponse
    68  		if err := json.NewDecoder(resp.Body).Decode(&er); err != nil {
    69  			log.Error(ctx.ctx, "Failed to decode response.", "errResponse", er, "err", err.Error())
    70  			return nil, err
    71  		}
    72  		err := fmt.Errorf("status %d: %s", er.Status, er.Message)
    73  		log.Error(ctx.ctx, "Request failed.", "err", err.Error())
    74  		return nil, err
    75  	}
    76  
    77  	var b2Ticket B2Ticket
    78  	if err := json.NewDecoder(resp.Body).Decode(&b2Ticket); err != nil {
    79  		log.Error(ctx.ctx, "Failed to decode BackBlaze ticket.", "b2Ticket", b2Ticket, "err", err.Error())
    80  		return nil, err
    81  	}
    82  	return &b2Ticket, nil
    83  }