We also need to upgrade the linter together with the Go version, all the changes should relate to either fixing linting problems or upgrading the Go version used to build Grafana.
126 lines
3.4 KiB
Go
126 lines
3.4 KiB
Go
package pluginproxy
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io/ioutil" //nolint:staticcheck // No need to change in v8.
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/plugins"
|
|
"github.com/grafana/grafana/pkg/services/pluginsettings"
|
|
"github.com/grafana/grafana/pkg/services/secrets"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
"github.com/grafana/grafana/pkg/util"
|
|
"github.com/grafana/grafana/pkg/util/proxyutil"
|
|
)
|
|
|
|
type templateData struct {
|
|
JsonData map[string]interface{}
|
|
SecureJsonData map[string]string
|
|
}
|
|
|
|
// NewApiPluginProxy create a plugin proxy
|
|
func NewApiPluginProxy(ctx *models.ReqContext, proxyPath string, route *plugins.Route,
|
|
appID string, cfg *setting.Cfg, pluginSettingsService pluginsettings.Service,
|
|
secretsService secrets.Service) *httputil.ReverseProxy {
|
|
appProxyLogger := logger.New(
|
|
"userId", ctx.UserId,
|
|
"orgId", ctx.OrgId,
|
|
"uname", ctx.Login,
|
|
"app", appID,
|
|
"path", ctx.Req.URL.Path,
|
|
"remote_addr", ctx.RemoteAddr(),
|
|
"referer", ctx.Req.Referer(),
|
|
)
|
|
|
|
director := func(req *http.Request) {
|
|
query := pluginsettings.GetByPluginIDArgs{OrgID: ctx.OrgId, PluginID: appID}
|
|
ps, err := pluginSettingsService.GetPluginSettingByPluginID(ctx.Req.Context(), &query)
|
|
if err != nil {
|
|
ctx.JsonApiErr(500, "Failed to fetch plugin settings", err)
|
|
return
|
|
}
|
|
|
|
secureJsonData, err := secretsService.DecryptJsonData(ctx.Req.Context(), ps.SecureJSONData)
|
|
if err != nil {
|
|
ctx.JsonApiErr(500, "Failed to decrypt plugin settings", err)
|
|
return
|
|
}
|
|
|
|
data := templateData{
|
|
JsonData: ps.JSONData,
|
|
SecureJsonData: secureJsonData,
|
|
}
|
|
|
|
interpolatedURL, err := interpolateString(route.URL, data)
|
|
if err != nil {
|
|
ctx.JsonApiErr(500, "Could not interpolate plugin route url", err)
|
|
return
|
|
}
|
|
targetURL, err := url.Parse(interpolatedURL)
|
|
if err != nil {
|
|
ctx.JsonApiErr(500, "Could not parse url", err)
|
|
return
|
|
}
|
|
req.URL.Scheme = targetURL.Scheme
|
|
req.URL.Host = targetURL.Host
|
|
req.Host = targetURL.Host
|
|
req.URL.Path = util.JoinURLFragments(targetURL.Path, proxyPath)
|
|
|
|
// clear cookie headers
|
|
req.Header.Del("Cookie")
|
|
req.Header.Del("Set-Cookie")
|
|
|
|
// Create a HTTP header with the context in it.
|
|
ctxJSON, err := json.Marshal(ctx.SignedInUser)
|
|
if err != nil {
|
|
ctx.JsonApiErr(500, "failed to marshal context to json.", err)
|
|
return
|
|
}
|
|
|
|
req.Header.Set("X-Grafana-Context", string(ctxJSON))
|
|
|
|
applyUserHeader(cfg.SendUserHeader, req, ctx.SignedInUser)
|
|
|
|
if err := addHeaders(&req.Header, route, data); err != nil {
|
|
ctx.JsonApiErr(500, "Failed to render plugin headers", err)
|
|
return
|
|
}
|
|
|
|
if err := setBodyContent(req, route, data); err != nil {
|
|
appProxyLogger.Error("Failed to set plugin route body content", "error", err)
|
|
}
|
|
}
|
|
|
|
logAppPluginProxyRequest(appID, cfg, ctx)
|
|
|
|
return proxyutil.NewReverseProxy(appProxyLogger, director)
|
|
}
|
|
|
|
func logAppPluginProxyRequest(appID string, cfg *setting.Cfg, c *models.ReqContext) {
|
|
if !cfg.DataProxyLogging {
|
|
return
|
|
}
|
|
|
|
var body string
|
|
if c.Req.Body != nil {
|
|
buffer, err := ioutil.ReadAll(c.Req.Body)
|
|
if err == nil {
|
|
c.Req.Body = ioutil.NopCloser(bytes.NewBuffer(buffer))
|
|
body = string(buffer)
|
|
}
|
|
}
|
|
|
|
logger.Info("Proxying incoming request",
|
|
"userid", c.UserId,
|
|
"orgid", c.OrgId,
|
|
"username", c.Login,
|
|
"app", appID,
|
|
"uri", c.Req.RequestURI,
|
|
"method", c.Req.Method,
|
|
"body", body)
|
|
}
|