github.com/hoffie/larasync@v0.0.0-20151025221940-0384d2bddcef/api/client/authorizationUrl.go (about) 1 package client 2 3 import ( 4 "encoding/hex" 5 "errors" 6 "fmt" 7 "net/url" 8 "regexp" 9 10 edhelpers "github.com/hoffie/larasync/helpers/ed25519" 11 "github.com/hoffie/larasync/repository" 12 ) 13 14 var ( 15 signKeyRegexp = regexp.MustCompile("AuthSignKey=(?P<key>[^&]+)") 16 encKeyRegexp = regexp.MustCompile("AuthEncKey=(?P<key>[^&]+)") 17 fingerprintRegexp = regexp.MustCompile("Fingerprint=(?P<key>[^&]+)") 18 ) 19 20 // AuthorizationURL is used to pass and create a authorizations 21 // for registering against a new server. 22 type AuthorizationURL struct { 23 URL *url.URL 24 SignKey [PrivateKeySize]byte 25 EncKey [repository.EncryptionKeySize]byte 26 Fingerprint string 27 } 28 29 // parseAuthURL takes a URL and tries to extract the encryption key 30 // and the auhtorization key from the fragment. 31 func parseAuthURL(URL *url.URL) (*AuthorizationURL, error) { 32 authURL := &AuthorizationURL{} 33 err := authURL.parse(URL) 34 if err != nil { 35 return nil, err 36 } 37 return authURL, nil 38 } 39 40 // parseAuthURLString takes a string URL and uses parseAuthURL on it to derive 41 // an AuthorizationURL object. 42 func parseAuthURLString(urlString string) (*AuthorizationURL, error) { 43 u, err := url.Parse(urlString) 44 if err != nil { 45 return nil, fmt.Errorf("unparsable url (%s)", err) 46 } 47 return parseAuthURL(u) 48 } 49 50 // NewAuthURL generates a new authorization URL with the passed 51 // arguments. 52 func NewAuthURL(repositoryBaseURL string, 53 signingPrivKey *[PrivateKeySize]byte, 54 encryptionKey *[repository.EncryptionKeySize]byte, 55 fingerprint string) (*AuthorizationURL, error) { 56 57 pubKey := edhelpers.GetPublicKeyFromPrivate(*signingPrivKey) 58 pubKeyString := hex.EncodeToString(pubKey[:]) 59 60 u, err := url.Parse(fmt.Sprintf("%s/authorizations/%s", repositoryBaseURL, pubKeyString)) 61 if err != nil { 62 return nil, err 63 } 64 65 authURL := &AuthorizationURL{ 66 SignKey: *signingPrivKey, 67 EncKey: *encryptionKey, 68 Fingerprint: fingerprint, 69 URL: u, 70 } 71 return authURL, nil 72 } 73 74 // SignKeyString returns the authorization key encoded as hex. 75 func (a *AuthorizationURL) SignKeyString() string { 76 return hex.EncodeToString(a.SignKey[:]) 77 } 78 79 // EncKeyString returns the encryption key encoded as hex. 80 func (a *AuthorizationURL) EncKeyString() string { 81 return hex.EncodeToString(a.EncKey[:]) 82 } 83 84 // String formats the AuthorizationURL which should be passed to 85 // the new client to authorize. 86 func (a *AuthorizationURL) String() string { 87 return fmt.Sprintf("%s#AuthEncKey=%s&AuthSignKey=%s&Fingerprint=%s", 88 a.URL.String(), a.EncKeyString(), a.SignKeyString(), a.Fingerprint) 89 } 90 91 func (a *AuthorizationURL) parse(URL *url.URL) error { 92 authData := URL.Fragment 93 URL.Fragment = "" 94 95 encKey, err := a.parseForEncKey(authData) 96 if err != nil { 97 return err 98 } 99 100 signKey, err := a.parseForSignKey(authData) 101 if err != nil { 102 return err 103 } 104 105 fingerprint, err := a.parseForFingerprint(authData) 106 if err != nil { 107 return err 108 } 109 110 a.URL = URL 111 a.SignKey = signKey 112 a.EncKey = encKey 113 a.Fingerprint = fingerprint 114 return nil 115 } 116 117 // parseForEncKey tries to extract the encryption key. 118 func (a *AuthorizationURL) parseForEncKey(data string) ([repository.EncryptionKeySize]byte, error) { 119 encKeySlice, err := a.parseForKey(data, encKeyRegexp) 120 encKey := [repository.EncryptionKeySize]byte{} 121 if err != nil { 122 return encKey, errors.New("Could not retrieve encryption key.") 123 } 124 if len(encKeySlice) != repository.EncryptionKeySize { 125 return encKey, errors.New("Invalid encryption key size.") 126 } 127 128 copy(encKey[:], encKeySlice) 129 return encKey, nil 130 } 131 132 // parseForSignKey tries to extract the signing key. 133 func (a *AuthorizationURL) parseForSignKey(data string) ([PrivateKeySize]byte, error) { 134 signKeySlice, err := a.parseForKey(data, signKeyRegexp) 135 signKey := [PrivateKeySize]byte{} 136 if err != nil { 137 return signKey, errors.New("Could not retrieve signing key.") 138 } 139 if len(signKeySlice) != PrivateKeySize { 140 return signKey, errors.New("Invalid signature key size.") 141 } 142 143 copy(signKey[:], signKeySlice) 144 return signKey, nil 145 } 146 147 // parseForFingerprint tries to extract the fingerprint 148 func (a *AuthorizationURL) parseForFingerprint(data string) (string, error) { 149 matches := fingerprintRegexp.FindStringSubmatch(data) 150 if len(matches) < 2 { 151 return "", errors.New("Could not parse fingerprint") 152 } 153 return string(matches[1]), nil 154 } 155 156 // parseForKey tries to parse a key from the data string and parses it with the given regexp. 157 func (a *AuthorizationURL) parseForKey(data string, r *regexp.Regexp) ([]byte, error) { 158 keyMatches := r.FindStringSubmatch(data) 159 extractionError := errors.New("Could not extract key.") 160 161 if len(keyMatches) < 2 { 162 return nil, extractionError 163 } 164 keyString := keyMatches[1] 165 keySlice, err := hex.DecodeString(keyString) 166 if err != nil { 167 return nil, extractionError 168 } 169 return keySlice, nil 170 }