Skip to content

Commit

Permalink
fix install single plugin file from url
Browse files Browse the repository at this point in the history
Signed-off-by: Patrick Zheng <[email protected]>
  • Loading branch information
Two-Hearts committed Jan 4, 2024
1 parent e8a112b commit 96570a6
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 16 deletions.
40 changes: 31 additions & 9 deletions cmd/notation/internal/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import (
"context"
"fmt"
"io"
"mime"
"net/http"
"os"
"path"
"path/filepath"
"time"

"github.com/notaryproject/notation/internal/httputil"
Expand Down Expand Up @@ -52,35 +56,53 @@ const (
// URL
const DownloadPluginFromURLTimeout = 10 * time.Minute

// DownloadPluginFromURL downloads plugin source from url to a tmp file on file
// system
func DownloadPluginFromURL(ctx context.Context, pluginURL string, tmpFile io.Writer) error {
// DownloadPluginFromURL downloads plugin source from url to a tmp dir on file
// system. On success, it returns the downloaded file.
func DownloadPluginFromURL(ctx context.Context, pluginURL, tmpDir string) (*os.File, error) {
// Get the data
client := httputil.NewAuthClient(ctx, &http.Client{Timeout: DownloadPluginFromURLTimeout})
req, err := http.NewRequest(http.MethodGet, pluginURL, nil)
if err != nil {
return err
return nil, err
}
resp, err := client.Do(req)
if err != nil {
return err
return nil, err
}
defer resp.Body.Close()
// Check server response
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("%s %q: https response bad status: %s", resp.Request.Method, resp.Request.URL, resp.Status)
return nil, fmt.Errorf("%s %q: https response bad status: %s", resp.Request.Method, resp.Request.URL, resp.Status)
}
var downloadedFilename string
if cd := resp.Header.Get("Content-Disposition"); cd != "" {
_, params, err := mime.ParseMediaType(cd)
if err == nil { // if there's an error, use the filename in URL
downloadedFilename = params["filename"]
}
}
if downloadedFilename == "" {
downloadedFilename = path.Base(req.URL.Path)
}
// Write the body to file
tmpFilePath := filepath.Join(tmpDir, downloadedFilename)
tmpFile, err := os.Create(tmpFilePath)
if err != nil {
return nil, err
}
lr := &io.LimitedReader{
R: resp.Body,
N: MaxPluginSourceBytes,
}
_, err = io.Copy(tmpFile, lr)
if err != nil {
return err
tmpFile.Close()
return nil, err
}
if lr.N == 0 {
return fmt.Errorf("%s %q: https response reached the %d MiB size limit", resp.Request.Method, resp.Request.URL, MaxPluginSourceBytes/1024/1024)
tmpFile.Close()
return nil, fmt.Errorf("%s %q: https response reached the %d MiB size limit", resp.Request.Method, resp.Request.URL, MaxPluginSourceBytes/1024/1024)
}
return nil
tmpFile.Close()
return tmpFile, nil
}
17 changes: 10 additions & 7 deletions cmd/notation/plugin/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ import (
)

const (
notationPluginTmpDir = "notation-plugin"
notationPluginDownloadTmpFile = "notation-plugin-download"
notationPluginTmpDir = "notation-plugin"
)

type pluginInstallOpts struct {
Expand Down Expand Up @@ -136,14 +135,13 @@ func install(command *cobra.Command, opts *pluginInstallOpts) error {
if pluginURL.Scheme != "https" {
return fmt.Errorf("failed to download plugin from URL: only the HTTPS scheme is supported, but got %s", pluginURL.Scheme)
}
tmpFile, err := os.CreateTemp("", notationPluginDownloadTmpFile)
tmpDir, err := os.MkdirTemp("", notationPluginTmpDir)
if err != nil {
return fmt.Errorf("failed to create temporary file required for downloading plugin: %w", err)
return fmt.Errorf("failed to create temporary directory: %w", err)
}
defer os.Remove(tmpFile.Name())
defer tmpFile.Close()
defer os.RemoveAll(tmpDir)
fmt.Printf("Downloading plugin from %s\n", opts.pluginSource)
err = notationplugin.DownloadPluginFromURL(ctx, opts.pluginSource, tmpFile)
tmpFile, err := notationplugin.DownloadPluginFromURL(ctx, opts.pluginSource, tmpDir)
if err != nil {
return fmt.Errorf("failed to download plugin from URL %s with error: %w", opts.pluginSource, err)
}
Expand Down Expand Up @@ -200,6 +198,11 @@ func installPlugin(ctx context.Context, inputPath string, inputChecksum string,
if inputFileInfo.Size() >= osutil.MaxFileBytes {
return fmt.Errorf("file size reached the %d MiB size limit", osutil.MaxFileBytes/1024/1024)
}
// set permission to 0700 for plugin validation before installation.
// The eventual plugin permission is updated in notation-go.
if err := os.Chmod(inputPath, 0700); err != nil {
return err
}
installOpts := plugin.CLIInstallOptions{
PluginPath: inputPath,
Overwrite: force,
Expand Down

0 comments on commit 96570a6

Please sign in to comment.