github.com/hoffie/larasync@v0.0.0-20151025221940-0384d2bddcef/api/client/authorization.go (about)

     1  package client
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"os"
    11  	"path"
    12  
    13  	"github.com/hoffie/larasync/api/common"
    14  	"github.com/hoffie/larasync/helpers/crypto"
    15  	"github.com/hoffie/larasync/repository"
    16  )
    17  
    18  // putAuthorizationRequest generates a request to add new authorization
    19  // data to the server
    20  func (c *Client) putAuthorizationRequest(
    21  	pubKey *[PublicKeySize]byte,
    22  	authorizationReader io.Reader,
    23  ) (*http.Request, error) {
    24  	pubKeyString := hex.EncodeToString(pubKey[:])
    25  
    26  	req, err := http.NewRequest(
    27  		"PUT",
    28  		c.BaseURL+"/authorizations/"+pubKeyString,
    29  		authorizationReader,
    30  	)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	req.Header.Set("Content-Type", "application/octet-stream")
    36  	common.SignWithKey(req, c.signingPrivateKey)
    37  	return req, nil
    38  }
    39  
    40  // PutAuthorization adds a new authorization assignment
    41  // for the passed public key to the server.
    42  func (c *Client) PutAuthorization(
    43  	pubKey *[PublicKeySize]byte,
    44  	authorizationReader io.Reader,
    45  ) error {
    46  	req, err := c.putAuthorizationRequest(pubKey, authorizationReader)
    47  	if err != nil {
    48  		return err
    49  	}
    50  
    51  	_, err = c.doRequest(req, http.StatusOK, http.StatusCreated)
    52  	return err
    53  }
    54  
    55  // getAuthorizationRequest generates a request to request a authorization
    56  // from the server.
    57  func (c *Client) getAuthorizationRequest(authorizationURL string,
    58  	authPrivKey [PrivateKeySize]byte) (*http.Request, error) {
    59  	req, err := http.NewRequest(
    60  		"GET",
    61  		authorizationURL,
    62  		nil,
    63  	)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	common.SignWithKey(req, authPrivKey)
    69  	return req, nil
    70  }
    71  
    72  // GetAuthorization loads the authorizaion from a server as a URL. Authenticates
    73  // itself against the server with the passed authorization key.
    74  func (c *Client) getAuthorization(authorizationURL string,
    75  	authPrivKey [PrivateKeySize]byte) (io.Reader, error) {
    76  	req, err := c.getAuthorizationRequest(authorizationURL, authPrivKey)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	resp, err := c.doRequest(req, http.StatusOK)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	return resp.Body, nil
    86  }
    87  
    88  // ImportAuthorization generates a new repository "repoName" and imports the
    89  // authorization information from the given URL.
    90  func ImportAuthorization(repoName string, urlString string) (*Client, *repository.ClientRepository, error) {
    91  	repo := repository.NewClient(repoName)
    92  	err := repo.Create()
    93  	if err != nil && !os.IsExist(err) {
    94  		return nil, nil, fmt.Errorf("repository creation failure (%s)", err)
    95  	}
    96  
    97  	authURL, err := parseAuthURLString(urlString)
    98  
    99  	sc, err := repo.StateConfig()
   100  	if err != nil {
   101  		return nil, nil, fmt.Errorf("unable to load state config (%s)\n", err)
   102  	}
   103  
   104  	defaultServer := sc.DefaultServer
   105  	defaultServer.URL = "https://" + authURL.URL.Host + path.Dir(path.Dir(authURL.URL.Path))
   106  	defaultServer.Fingerprint = authURL.Fingerprint
   107  	err = sc.Save()
   108  	if err != nil {
   109  		return nil, nil, fmt.Errorf("unable to save state config (%s)\n", err)
   110  	}
   111  
   112  	c := New(defaultServer.URL, defaultServer.Fingerprint, nil)
   113  
   114  	auth, err := c.getDecryptedAuthorization(authURL)
   115  	if err != nil {
   116  		return nil, nil, fmt.Errorf("unable to retrieve decrypted authorization (%s)", err)
   117  	}
   118  
   119  	err = repo.SetKeysFromAuth(auth)
   120  	if err != nil {
   121  		return nil, nil, fmt.Errorf("key storage failure (%s)", err)
   122  	}
   123  
   124  	privKey, err := repo.GetSigningPrivateKey()
   125  	if err != nil {
   126  		return nil, nil, fmt.Errorf("private signing key retrieval failure (%s)", err)
   127  	}
   128  	c.SetSigningPrivateKey(privKey)
   129  
   130  	return c, repo, nil
   131  }
   132  
   133  // getDecryptedAuthorization downloads and decrypt the authorization information
   134  // from the given (parsed) URL.
   135  func (c *Client) getDecryptedAuthorization(authURL *AuthorizationURL) (*repository.Authorization, error) {
   136  	reader, err := c.getAuthorization(authURL.URL.String(), authURL.SignKey)
   137  	if err != nil {
   138  		return nil, fmt.Errorf("server communication failure (%s)", err)
   139  	}
   140  
   141  	enc, err := ioutil.ReadAll(reader)
   142  	if err != nil {
   143  		return nil, fmt.Errorf("server data retrieval failed (%s)", err)
   144  	}
   145  
   146  	box := crypto.NewBox(authURL.EncKey)
   147  	data, err := box.DecryptContent(enc)
   148  	if err != nil {
   149  		return nil, fmt.Errorf("response decryption failure (%s)", err)
   150  	}
   151  
   152  	auth := &repository.Authorization{}
   153  	_, err = auth.ReadFrom(bytes.NewBuffer(data))
   154  	if err != nil {
   155  		return nil, fmt.Errorf("authorization data read failure (%s)", err)
   156  	}
   157  	return auth, nil
   158  }