mirror of
https://github.com/drone-plugins/drone-download.git
synced 2026-06-04 18:24:21 +08:00
158 lines
3.5 KiB
Go
158 lines
3.5 KiB
Go
// Copyright (c) 2020, the Drone Plugins project authors.
|
|
// Please see the AUTHORS file for details. All rights reserved.
|
|
// Use of this source code is governed by an Apache 2.0 license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package plugin
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"hash"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// Settings for the plugin.
|
|
type Settings struct {
|
|
Source string
|
|
Destination string
|
|
Authorization string
|
|
Username string
|
|
Password string
|
|
MD5 string
|
|
SHA256 string
|
|
|
|
destination string
|
|
}
|
|
|
|
// Validate handles the settings validation of the plugin.
|
|
func (p *Plugin) Validate() error {
|
|
// Verify the source url
|
|
source := p.settings.Source
|
|
if source == "" {
|
|
return fmt.Errorf("no source provided")
|
|
}
|
|
|
|
u, err := url.Parse(source)
|
|
if err != nil {
|
|
return fmt.Errorf("could not parse url %s: %w", source, err)
|
|
}
|
|
|
|
// Verify the destination
|
|
destination := filepath.ToSlash(p.settings.Destination)
|
|
if destination == "" {
|
|
destination = path.Base(u.Path)
|
|
} else if strings.HasSuffix(destination, "/") {
|
|
destination = path.Join(destination, path.Base(u.Path))
|
|
}
|
|
|
|
destination = filepath.FromSlash(path.Clean(destination))
|
|
err = os.MkdirAll(filepath.Dir(destination), os.ModePerm)
|
|
if err != nil {
|
|
return fmt.Errorf("creating directory failed: %w", err)
|
|
}
|
|
p.settings.destination = destination
|
|
|
|
return nil
|
|
}
|
|
|
|
// Execute provides the implementation of the plugin.
|
|
func (p *Plugin) Execute() error {
|
|
req, err := http.NewRequestWithContext(
|
|
p.network.Context,
|
|
"GET",
|
|
p.settings.Source,
|
|
nil,
|
|
)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("initializing request failed: %w", err)
|
|
}
|
|
|
|
p.addAuth(req)
|
|
|
|
client := p.network.Client
|
|
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
|
p.addAuth(req)
|
|
return nil
|
|
}
|
|
|
|
logrus.WithFields(logrus.Fields{
|
|
"source": p.settings.Source,
|
|
"destination": p.settings.destination,
|
|
}).Info("Downloading file")
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("executing request failed: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("request failed, status %s", http.StatusText(resp.StatusCode))
|
|
}
|
|
|
|
target, err := os.Create(p.settings.destination)
|
|
if err != nil {
|
|
return fmt.Errorf("creating destination failed: %w", err)
|
|
}
|
|
defer target.Close()
|
|
|
|
_, err = io.Copy(target, resp.Body)
|
|
if err != nil {
|
|
return fmt.Errorf("copying destination failed: %w", err)
|
|
}
|
|
|
|
var h hash.Hash
|
|
alg := ""
|
|
exp := ""
|
|
|
|
if p.settings.SHA256 != "" {
|
|
exp = p.settings.SHA256
|
|
alg = "SHA256"
|
|
h = sha256.New()
|
|
} else if p.settings.MD5 != "" {
|
|
exp = p.settings.MD5
|
|
alg = "MD5"
|
|
h = md5.New()
|
|
}
|
|
|
|
if exp != "" {
|
|
logrus.WithField("hash", alg).Info("Computing checksum")
|
|
_, _ = target.Seek(0, 0)
|
|
|
|
if _, err := io.Copy(h, target); err != nil {
|
|
defer os.Remove(target.Name())
|
|
return fmt.Errorf("failed to compare checksum: %w", err)
|
|
}
|
|
|
|
check := fmt.Sprintf("%x", h.Sum(nil))
|
|
|
|
if exp != check {
|
|
defer os.Remove(target.Name())
|
|
return fmt.Errorf("checksum doesn't match, got %s and expected %s", check, exp)
|
|
}
|
|
logrus.WithField("checksum", check).Info("Checksum matched")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Plugin) addAuth(req *http.Request) {
|
|
if p.settings.Username != "" && p.settings.Password != "" {
|
|
req.SetBasicAuth(p.settings.Username, p.settings.Password)
|
|
}
|
|
if p.settings.Authorization != "" {
|
|
req.Header.Add("Authorization", p.settings.Authorization)
|
|
}
|
|
}
|