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 }