Skip to content

Commit 08a7380

Browse files
committed
fix: honor key filename from content-disposition
Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
1 parent ebd9255 commit 08a7380

2 files changed

Lines changed: 63 additions & 1 deletion

File tree

pkg/apk/apk/implementation.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ func (a *APK) InitKeyring(ctx context.Context, keyFiles, extraKeyFiles []string)
543543
for _, element := range keyFiles {
544544
eg.Go(func() error {
545545
log.Debugf("installing key %v", element)
546+
keyName := filepath.Base(element)
546547

547548
var asURL *url.URL
548549
var err error
@@ -586,6 +587,9 @@ func (a *APK) InitKeyring(ctx context.Context, keyFiles, extraKeyFiles []string)
586587
if resp.StatusCode < 200 || resp.StatusCode > 299 {
587588
return fmt.Errorf("failed to fetch apk key from %s: http response indicated error code: %d", req.Host, resp.StatusCode)
588589
}
590+
if contentDispositionFileName := keyFilenameFromContentDisposition(resp.Header.Get("Content-Disposition")); contentDispositionFileName != "" {
591+
keyName = contentDispositionFileName
592+
}
589593

590594
data, err = io.ReadAll(resp.Body)
591595
if err != nil {
@@ -596,7 +600,7 @@ func (a *APK) InitKeyring(ctx context.Context, keyFiles, extraKeyFiles []string)
596600
}
597601

598602
// #nosec G306 -- apk keyring must be publicly readable
599-
if err := a.fs.WriteFile(filepath.Join("etc", "apk", "keys", filepath.Base(element)), data,
603+
if err := a.fs.WriteFile(filepath.Join("etc", "apk", "keys", keyName), data,
600604
0o644); err != nil {
601605
return fmt.Errorf("failed to write apk key: %w", err)
602606
}
@@ -608,6 +612,43 @@ func (a *APK) InitKeyring(ctx context.Context, keyFiles, extraKeyFiles []string)
608612
return eg.Wait()
609613
}
610614

615+
func keyFilenameFromContentDisposition(contentDisposition string) string {
616+
if contentDisposition == "" {
617+
return ""
618+
}
619+
620+
for _, field := range strings.Split(contentDisposition, ";") {
621+
field = strings.TrimSpace(field)
622+
lower := strings.ToLower(field)
623+
624+
if strings.HasPrefix(lower, "filename*=") {
625+
filename := strings.TrimSpace(field[len("filename*="):])
626+
filename = strings.Trim(filename, `"`)
627+
if i := strings.Index(filename, "''"); i >= 0 {
628+
filename = filename[i+2:]
629+
}
630+
if decodedFilename, err := url.PathUnescape(filename); err == nil {
631+
filename = decodedFilename
632+
}
633+
filename = filepath.Base(filename)
634+
if filename != "" && filename != "." {
635+
return filename
636+
}
637+
}
638+
639+
if strings.HasPrefix(lower, "filename=") {
640+
filename := strings.TrimSpace(field[len("filename="):])
641+
filename = strings.Trim(filename, `"`)
642+
filename = filepath.Base(filename)
643+
if filename != "" && filename != "." {
644+
return filename
645+
}
646+
}
647+
}
648+
649+
return ""
650+
}
651+
611652
// ResolveWorld determine the target state for the requested dependencies in /etc/apk/world. Does not install anything.
612653
func (a *APK) ResolveWorld(ctx context.Context) (toInstall []*RepositoryPackage, conflicts []string, err error) {
613654
log := clog.FromContext(ctx)

pkg/apk/apk/implementation_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,27 @@ func TestInitKeyring(t *testing.T) {
519519
// should be 2 keys
520520
require.Len(t, fi, 2)
521521

522+
t.Run("remote keys use content-disposition filename", func(t *testing.T) {
523+
src := apkfs.NewMemFS()
524+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
525+
w.Header().Set("Content-Disposition", `attachment; filename="test@5c6bb80ae094a76863d00718d8ff0fc208ae441d0e3e302d29d185b929eea22c.rsa.pub"; filename*=UTF-8''test@5c6bb80ae094a76863d00718d8ff0fc208ae441d0e3e302d29d185b929eea22c.rsa.pub`)
526+
_, _ = w.Write([]byte(testDemoKey))
527+
}))
528+
defer server.Close()
529+
530+
a, err := New(t.Context(), WithFS(src), WithIgnoreMknodErrors(ignoreMknodErrors))
531+
require.NoError(t, err)
532+
533+
err = a.InitKeyring(context.Background(), []string{server.URL + "/key"}, nil)
534+
require.NoError(t, err)
535+
536+
_, err = src.Stat(filepath.Join(DefaultKeyRingPath, "test@5c6bb80ae094a76863d00718d8ff0fc208ae441d0e3e302d29d185b929eea22c.rsa.pub"))
537+
require.NoError(t, err)
538+
539+
_, err = src.Stat(filepath.Join(DefaultKeyRingPath, "key"))
540+
require.Error(t, err)
541+
})
542+
522543
// Add an invalid file
523544
keyfiles = []string{
524545
"/liksdjlksdjlksjlksjdl",

0 commit comments

Comments
 (0)