Skip to content

Commit c40f59b

Browse files
committedMar 22, 2023
feat: add armory support for private Github apis
1 parent 2ece520 commit c40f59b

File tree

3 files changed

+67
-123
lines changed

3 files changed

+67
-123
lines changed
 

‎client/command/armory/armory.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ func fetchPackageSignature(wg *sync.WaitGroup, armoryConfig *assets.ArmoryConfig
484484

485485
var sig *minisign.Signature
486486
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
487-
sig, _, err = pkgParser(armoryPkg, true, clientConfig)
487+
sig, _, err = pkgParser(armoryConfig, armoryPkg, true, clientConfig)
488488
} else {
489489
sig, _, err = DefaultArmoryPkgParser(armoryConfig, armoryPkg, true, clientConfig)
490490
}

‎client/command/armory/install.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func installAliasPackageByName(name string, clientConfig ArmoryHTTPConfig, con *
143143
var sig *minisign.Signature
144144
var tarGz []byte
145145
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
146-
sig, tarGz, err = pkgParser(&entry.Pkg, false, clientConfig)
146+
sig, tarGz, err = pkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
147147
} else {
148148
sig, tarGz, err = DefaultArmoryPkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
149149
}
@@ -261,7 +261,7 @@ func installExtensionPackageByName(name string, clientConfig ArmoryHTTPConfig, c
261261
var sig *minisign.Signature
262262
var tarGz []byte
263263
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
264-
sig, tarGz, err = pkgParser(&entry.Pkg, false, clientConfig)
264+
sig, tarGz, err = pkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
265265
} else {
266266
sig, tarGz, err = DefaultArmoryPkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
267267
}

‎client/command/armory/parsers.go

+64-120
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import (
4040
type ArmoryIndexParser func(*assets.ArmoryConfig, ArmoryHTTPConfig) (*ArmoryIndex, error)
4141

4242
// ArmoryPackageParser - Generic interface to fetch armory package manifests
43-
type ArmoryPackageParser func(*ArmoryPackage, bool, ArmoryHTTPConfig) (*minisign.Signature, []byte, error)
43+
type ArmoryPackageParser func(*assets.ArmoryConfig, *ArmoryPackage, bool, ArmoryHTTPConfig) (*minisign.Signature, []byte, error)
4444

4545
var (
4646
indexParsers = map[string]ArmoryIndexParser{
@@ -79,28 +79,7 @@ func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig Ar
7979
return nil, err
8080
}
8181

82-
client := httpClient(clientConfig)
83-
repoURL, err := url.Parse(armoryConfig.RepoURL)
84-
if err != nil {
85-
return nil, err
86-
}
87-
req := &http.Request{
88-
Method: http.MethodGet,
89-
URL: repoURL,
90-
Header: map[string][]string{},
91-
}
92-
if armoryConfig.Authorization != "" {
93-
req.Header.Set("Authorization", armoryConfig.Authorization)
94-
}
95-
resp, err := client.Do(req)
96-
if err != nil {
97-
return nil, err
98-
}
99-
defer resp.Body.Close()
100-
body, err := ioutil.ReadAll(resp.Body)
101-
if err != nil {
102-
return nil, err
103-
}
82+
resp, body, err := httpRequest(clientConfig, armoryConfig.RepoURL, armoryConfig, http.Header{})
10483
if resp.StatusCode != http.StatusOK {
10584
return nil, errors.New("api returned non-200 status code")
10685
}
@@ -125,9 +104,8 @@ func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig Ar
125104
return nil, errors.New("index has invalid signature")
126105
}
127106

128-
armoryIndex := &ArmoryIndex{ArmoryConfig: armoryConfig}
129-
if err != nil {
130-
return nil, err
107+
armoryIndex := &ArmoryIndex{
108+
ArmoryConfig: armoryConfig,
131109
}
132110
err = json.Unmarshal(armoryIndexData, armoryIndex)
133111
if err != nil {
@@ -144,25 +122,7 @@ func DefaultArmoryPkgParser(armoryConfig *assets.ArmoryConfig, armoryPkg *Armory
144122
return nil, nil, err
145123
}
146124

147-
client := httpClient(clientConfig)
148-
repoURL, err := url.Parse(armoryConfig.RepoURL)
149-
if err != nil {
150-
return nil, nil, err
151-
}
152-
req := &http.Request{
153-
Method: http.MethodGet,
154-
URL: repoURL,
155-
Header: map[string][]string{},
156-
}
157-
if armoryConfig.Authorization != "" {
158-
req.Header.Set("Authorization", armoryConfig.Authorization)
159-
}
160-
resp, err := client.Do(req)
161-
if err != nil {
162-
return nil, nil, err
163-
}
164-
defer resp.Body.Close()
165-
body, err := ioutil.ReadAll(resp.Body)
125+
resp, body, err := httpRequest(clientConfig, armoryConfig.RepoURL, armoryConfig, http.Header{})
166126
if err != nil {
167127
return nil, nil, err
168128
}
@@ -187,18 +147,10 @@ func DefaultArmoryPkgParser(armoryConfig *assets.ArmoryConfig, armoryPkg *Armory
187147
if tarGzURL.Scheme != "https" && tarGzURL.Scheme != "http" {
188148
return nil, nil, errors.New("invalid url scheme")
189149
}
190-
resp, err := client.Get(tarGzURL.String())
191-
if err != nil {
192-
return nil, nil, err
193-
}
194-
defer resp.Body.Close()
195-
tarGz, err = ioutil.ReadAll(resp.Body)
150+
tarGz, err = downloadRequest(clientConfig, tarGzURL.String(), armoryConfig)
196151
if err != nil {
197152
return nil, nil, err
198153
}
199-
if resp.StatusCode != http.StatusOK {
200-
return nil, nil, errors.New("api returned non-200 status code")
201-
}
202154
}
203155
return sig, tarGz, nil
204156
}
@@ -239,21 +191,15 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig
239191
return nil, err
240192
}
241193

242-
client := httpClient(clientConfig)
243-
resp, err := client.Get(armoryConfig.RepoURL)
244-
if err != nil {
245-
return nil, err
246-
}
247-
defer resp.Body.Close()
248-
body, err := ioutil.ReadAll(resp.Body)
194+
resp, body, err := httpRequest(clientConfig, armoryConfig.RepoURL, armoryConfig, http.Header{})
249195
if err != nil {
250196
return nil, err
251197
}
252198
if resp.StatusCode != http.StatusOK {
253199
if resp.StatusCode == http.StatusForbidden {
254200
return nil, errors.New("you hit the github api rate limit (60 req/hr), try later")
255201
}
256-
return nil, errors.New("api returned non-200 status code")
202+
return nil, fmt.Errorf("api returned non-200 status code: %d", resp.StatusCode)
257203
}
258204

259205
releases := []GithubRelease{}
@@ -270,23 +216,13 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig
270216
var sigData []byte
271217
for _, asset := range release.Assets {
272218
if asset.Name == armoryIndexFileName {
273-
resp, err := client.Get(asset.BrowserDownloadURL)
274-
if err != nil {
275-
return nil, err
276-
}
277-
defer resp.Body.Close()
278-
armoryIndexData, err = ioutil.ReadAll(resp.Body)
219+
armoryIndexData, err = downloadRequest(clientConfig, asset.URL, armoryConfig)
279220
if err != nil {
280221
return nil, err
281222
}
282223
}
283224
if asset.Name == armoryIndexSigFileName {
284-
resp, err := client.Get(asset.BrowserDownloadURL)
285-
if err != nil {
286-
return nil, err
287-
}
288-
defer resp.Body.Close()
289-
sigData, err = ioutil.ReadAll(resp.Body)
225+
sigData, err = downloadRequest(clientConfig, asset.URL, armoryConfig)
290226
if err != nil {
291227
return nil, err
292228
}
@@ -299,7 +235,9 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig
299235
return nil, errors.New("invalid signature")
300236
}
301237

302-
armoryIndex := &ArmoryIndex{}
238+
armoryIndex := &ArmoryIndex{
239+
ArmoryConfig: armoryConfig,
240+
}
303241
err = json.Unmarshal(armoryIndexData, armoryIndex)
304242
if err != nil {
305243
return nil, err
@@ -308,28 +246,22 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig
308246
}
309247

310248
// GithubAPIArmoryPackageParser - Retrieve the minisig and tar.gz for an armory package from a GitHub release
311-
func GithubAPIArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
249+
func GithubAPIArmoryPackageParser(armoryConfig *assets.ArmoryConfig, armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
312250
var publicKey minisign.PublicKey
313251
err := publicKey.UnmarshalText([]byte(armoryPkg.PublicKey))
314252
if err != nil {
315253
return nil, nil, err
316254
}
317255

318-
client := httpClient(clientConfig)
319-
resp, err := client.Get(armoryPkg.RepoURL)
320-
if err != nil {
321-
return nil, nil, err
322-
}
323-
defer resp.Body.Close()
324-
body, err := ioutil.ReadAll(resp.Body)
256+
resp, body, err := httpRequest(clientConfig, armoryPkg.RepoURL, armoryConfig, http.Header{})
325257
if err != nil {
326258
return nil, nil, err
327259
}
328260
if resp.StatusCode != http.StatusOK {
329261
if resp.StatusCode == http.StatusForbidden {
330262
return nil, nil, errors.New("you hit the github api rate limit (60 req/hr), try later")
331263
}
332-
return nil, nil, errors.New("api returned non-200 status code")
264+
return nil, nil, fmt.Errorf("api returned non-200 status code: %d", resp.StatusCode)
333265
}
334266

335267
releases := []GithubRelease{}
@@ -343,14 +275,7 @@ func GithubAPIArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, client
343275
var tarGz []byte
344276
for _, asset := range release.Assets {
345277
if asset.Name == fmt.Sprintf("%s.minisig", armoryPkg.CommandName) {
346-
var resp *http.Response
347-
resp, err = client.Get(asset.BrowserDownloadURL)
348-
if err != nil {
349-
break
350-
}
351-
defer resp.Body.Close()
352-
var body []byte
353-
body, err = ioutil.ReadAll(resp.Body)
278+
body, err := downloadRequest(clientConfig, asset.URL, armoryConfig)
354279
if err != nil {
355280
break
356281
}
@@ -360,13 +285,7 @@ func GithubAPIArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, client
360285
}
361286
}
362287
if asset.Name == fmt.Sprintf("%s.tar.gz", armoryPkg.CommandName) && !sigOnly {
363-
var resp *http.Response
364-
resp, err = client.Get(asset.BrowserDownloadURL)
365-
if err != nil {
366-
break
367-
}
368-
defer resp.Body.Close()
369-
tarGz, err = ioutil.ReadAll(resp.Body)
288+
tarGz, err = downloadRequest(clientConfig, asset.URL, armoryConfig)
370289
if err != nil {
371290
break
372291
}
@@ -380,31 +299,27 @@ func GithubAPIArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, client
380299
//
381300

382301
// GithubArmoryPackageParser - Uses github.com instead of api.github.com to download packages
383-
func GithubArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
302+
func GithubArmoryPackageParser(_ *assets.ArmoryConfig, armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
384303
latestTag, err := githubLatestTagParser(armoryPkg, clientConfig)
385304
if err != nil {
386305
return nil, nil, err
387306
}
388-
client := httpClient(clientConfig)
389307

390308
sigURL, err := url.Parse(armoryPkg.RepoURL)
391309
if err != nil {
392310
return nil, nil, fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
393311
}
394312
sigURL.Path = path.Join(sigURL.Path, "releases", "download", latestTag, fmt.Sprintf("%s.minisig", armoryPkg.CommandName))
395-
sigResp, err := client.Get(sigURL.String())
396-
if err != nil {
397-
return nil, nil, err
398-
}
399-
defer sigResp.Body.Close()
400-
if sigResp.StatusCode != http.StatusOK {
401-
return nil, nil, fmt.Errorf("failed to get signature for armory pkg '%s': %s", armoryPkg.RepoURL, sigResp.Status)
313+
314+
// Setup dummy auth here as the non-api endpoints don't support the Authorization header
315+
noAuth := &assets.ArmoryConfig{
316+
Authorization: "",
402317
}
403-
var body []byte
404-
body, err = ioutil.ReadAll(sigResp.Body)
318+
body, err := downloadRequest(clientConfig, sigURL.String(), noAuth)
405319
if err != nil {
406-
return nil, nil, fmt.Errorf("failed to read resp body '%s': %s", armoryPkg.RepoURL, err)
320+
return nil, nil, err
407321
}
322+
408323
sig, err := parsePkgMinsig(body)
409324
if err != nil {
410325
return nil, nil, fmt.Errorf("failed to parse pkg sig '%s': %s", armoryPkg.RepoURL, err)
@@ -417,18 +332,10 @@ func GithubArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, clientCon
417332
return nil, nil, fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
418333
}
419334
tarGzURL.Path = path.Join(tarGzURL.Path, "releases", "download", latestTag, fmt.Sprintf("%s.tar.gz", armoryPkg.CommandName))
420-
tarGzResp, err := client.Get(tarGzURL.String())
335+
tarGz, err = downloadRequest(clientConfig, tarGzURL.String(), noAuth)
421336
if err != nil {
422337
return nil, nil, err
423338
}
424-
defer tarGzResp.Body.Close()
425-
if tarGzResp.StatusCode != http.StatusOK {
426-
return nil, nil, fmt.Errorf("failed to get tar.gz for armory pkg '%s': %s", armoryPkg.RepoURL, tarGzResp.Status)
427-
}
428-
tarGz, err = ioutil.ReadAll(tarGzResp.Body)
429-
if err != nil {
430-
return nil, nil, fmt.Errorf("failed to read tar.gz body '%s': %s", armoryPkg.RepoURL, err)
431-
}
432339
}
433340

434341
return sig, tarGz, nil
@@ -498,3 +405,40 @@ func httpClient(config ArmoryHTTPConfig) *http.Client {
498405
},
499406
}
500407
}
408+
409+
func httpRequest(clientConfig ArmoryHTTPConfig, reqURL string, armoryConfig *assets.ArmoryConfig, extraHeaders http.Header) (*http.Response, []byte, error) {
410+
client := httpClient(clientConfig)
411+
req, err := http.NewRequest(http.MethodGet, reqURL, http.NoBody)
412+
if err != nil {
413+
return nil, nil, err
414+
}
415+
416+
if len(extraHeaders) > 0 {
417+
for key := range extraHeaders {
418+
req.Header.Add(key, strings.Join(extraHeaders[key], ","))
419+
}
420+
}
421+
if armoryConfig.Authorization != "" {
422+
req.Header.Set("Authorization", armoryConfig.Authorization)
423+
}
424+
resp, err := client.Do(req)
425+
if err != nil {
426+
return nil, nil, err
427+
}
428+
defer resp.Body.Close()
429+
430+
body, err := ioutil.ReadAll(resp.Body)
431+
return resp, body, err
432+
}
433+
434+
func downloadRequest(clientConfig ArmoryHTTPConfig, reqURL string, armoryConfig *assets.ArmoryConfig) ([]byte, error) {
435+
downloadHdr := http.Header{
436+
"Accept": {"application/octet-stream"},
437+
}
438+
resp, body, err := httpRequest(clientConfig, reqURL, armoryConfig, downloadHdr)
439+
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusFound {
440+
return nil, fmt.Errorf("Error downloading asset: http %d", resp.StatusCode)
441+
}
442+
443+
return body, err
444+
}

0 commit comments

Comments
 (0)
Please sign in to comment.