2016-08-10 17:27:39 +02:00
|
|
|
package imguploader
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
2017-09-15 15:05:48 +02:00
|
|
|
"context"
|
2016-08-10 17:27:39 +02:00
|
|
|
"fmt"
|
2022-08-10 13:37:51 +00:00
|
|
|
"io"
|
2017-02-24 17:22:12 +01:00
|
|
|
"net"
|
2016-08-10 17:27:39 +02:00
|
|
|
"net/http"
|
|
|
|
|
"net/url"
|
2022-08-10 13:37:51 +00:00
|
|
|
"os"
|
2016-08-10 17:27:39 +02:00
|
|
|
"path"
|
2018-07-17 20:10:12 +02:00
|
|
|
"strings"
|
2017-02-24 17:22:12 +01:00
|
|
|
"time"
|
2016-08-10 17:27:39 +02:00
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/util"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type WebdavUploader struct {
|
2017-03-23 16:23:46 +01:00
|
|
|
url string
|
|
|
|
|
username string
|
|
|
|
|
password string
|
|
|
|
|
public_url string
|
2016-08-10 17:27:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-24 17:22:12 +01:00
|
|
|
var netTransport = &http.Transport{
|
2017-05-17 03:58:18 +03:00
|
|
|
Proxy: http.ProxyFromEnvironment,
|
2017-02-24 17:22:12 +01:00
|
|
|
Dial: (&net.Dialer{
|
2022-11-22 10:09:15 +03:00
|
|
|
Timeout: time.Minute,
|
2017-02-24 17:22:12 +01:00
|
|
|
}).Dial,
|
|
|
|
|
TLSHandshakeTimeout: 5 * time.Second,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var netClient = &http.Client{
|
|
|
|
|
Timeout: time.Second * 60,
|
|
|
|
|
Transport: netTransport,
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-17 20:10:12 +02:00
|
|
|
func (u *WebdavUploader) PublicURL(filename string) string {
|
2023-09-27 23:35:10 +02:00
|
|
|
if strings.Contains(u.public_url, "{{file}}") {
|
|
|
|
|
return strings.ReplaceAll(u.public_url, "{{file}}", filename)
|
2018-07-17 20:10:12 +02:00
|
|
|
}
|
2019-04-23 11:24:47 +03:00
|
|
|
|
|
|
|
|
publicURL, _ := url.Parse(u.public_url)
|
|
|
|
|
publicURL.Path = path.Join(publicURL.Path, filename)
|
|
|
|
|
return publicURL.String()
|
2018-07-17 20:10:12 +02:00
|
|
|
}
|
|
|
|
|
|
2020-12-03 22:13:06 +01:00
|
|
|
func (u *WebdavUploader) Upload(ctx context.Context, imgToUpload string) (string, error) {
|
2016-08-10 17:27:39 +02:00
|
|
|
url, _ := url.Parse(u.url)
|
2019-10-23 10:40:12 +02:00
|
|
|
filename, err := util.GetRandomString(20)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
filename += pngExt
|
2017-03-23 16:23:46 +01:00
|
|
|
url.Path = path.Join(url.Path, filename)
|
2016-08-10 17:27:39 +02:00
|
|
|
|
2020-12-03 22:13:06 +01:00
|
|
|
// We can ignore the gosec G304 warning on this one because `imgToUpload` comes
|
|
|
|
|
// from alert notifiers and is only used to upload images generated by alerting.
|
|
|
|
|
// nolint:gosec
|
2022-08-10 13:37:51 +00:00
|
|
|
imgData, err := os.ReadFile(imgToUpload)
|
2018-04-23 20:03:57 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-10 17:27:39 +02:00
|
|
|
req, err := http.NewRequest("PUT", url.String(), bytes.NewReader(imgData))
|
2018-04-23 20:03:57 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
2020-01-17 12:07:16 +01:00
|
|
|
if ctx != nil {
|
|
|
|
|
req = req.WithContext(ctx)
|
|
|
|
|
}
|
2016-12-02 16:18:40 +01:00
|
|
|
if u.username != "" {
|
|
|
|
|
req.SetBasicAuth(u.username, u.password)
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-24 17:22:12 +01:00
|
|
|
res, err := netClient.Do(req)
|
2016-08-10 17:27:39 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
2020-12-15 09:32:06 +01:00
|
|
|
defer func() {
|
|
|
|
|
if err := res.Body.Close(); err != nil {
|
|
|
|
|
logger.Warn("Failed to close response body", "err", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
2016-08-10 17:27:39 +02:00
|
|
|
|
|
|
|
|
if res.StatusCode != http.StatusCreated {
|
2022-08-10 13:37:51 +00:00
|
|
|
body, err := io.ReadAll(res.Body)
|
2020-12-15 09:32:06 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return "", fmt.Errorf("failed to read response body: %w", err)
|
|
|
|
|
}
|
2020-11-05 13:07:06 +01:00
|
|
|
return "", fmt.Errorf("failed to upload image, statuscode: %d, body: %s", res.StatusCode, body)
|
2016-08-10 17:27:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-23 16:23:46 +01:00
|
|
|
if u.public_url != "" {
|
2018-07-17 20:10:12 +02:00
|
|
|
return u.PublicURL(filename), nil
|
2017-03-23 16:23:46 +01:00
|
|
|
}
|
2017-04-25 17:20:03 +02:00
|
|
|
|
|
|
|
|
return url.String(), nil
|
2016-08-10 17:27:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-23 16:23:46 +01:00
|
|
|
func NewWebdavImageUploader(url, username, password, public_url string) (*WebdavUploader, error) {
|
2016-08-10 17:27:39 +02:00
|
|
|
return &WebdavUploader{
|
2017-03-23 16:23:46 +01:00
|
|
|
url: url,
|
|
|
|
|
username: username,
|
|
|
|
|
password: password,
|
|
|
|
|
public_url: public_url,
|
2016-08-10 17:27:39 +02:00
|
|
|
}, nil
|
|
|
|
|
}
|