1package backend
2
3import (
4	"encoding/json"
5	"time"
6
7	"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
8)
9
10const dataCustomOptionsKey = "grafanaData"
11const secureDataCustomOptionsKey = "grafanaSecureData"
12
13// User represents a Grafana user.
14type User struct {
15	Login string
16	Name  string
17	Email string
18	Role  string
19}
20
21// AppInstanceSettings represents settings for an app instance.
22//
23// In Grafana an app instance is an app plugin of certain
24// type that have been configured and enabled in a Grafana organization.
25type AppInstanceSettings struct {
26	// JSONData repeats the properties at this level of the object (excluding DataSourceConfig), and also includes any
27	// custom properties associated with the plugin config instance.
28	JSONData json.RawMessage
29
30	// DecryptedSecureJSONData contains key,value pairs where the encrypted configuration plugin instance in Grafana
31	// server have been decrypted before passing them to the plugin.
32	DecryptedSecureJSONData map[string]string
33
34	// Updated is the last time this plugin instance's configuration was updated.
35	Updated time.Time
36}
37
38// HTTPClientOptions creates httpclient.Options based on settings.
39func (s *AppInstanceSettings) HTTPClientOptions() (httpclient.Options, error) {
40	httpSettings, err := parseHTTPSettings(s.JSONData, s.DecryptedSecureJSONData)
41	if err != nil {
42		return httpclient.Options{}, err
43	}
44
45	opts := httpSettings.HTTPClientOptions()
46	setCustomOptionsFromHTTPSettings(&opts, httpSettings)
47
48	return opts, nil
49}
50
51// DataSourceInstanceSettings represents settings for a data source instance.
52//
53// In Grafana a data source instance is a data source plugin of certain
54// type that have been configured and created in a Grafana organization.
55type DataSourceInstanceSettings struct {
56	// ID is the Grafana assigned numeric identifier of the the data source instance.
57	ID int64
58
59	// UID is the Grafana assigned string identifier of the the data source instance.
60	UID string
61
62	// Name is the configured name of the data source instance.
63	Name string
64
65	// URL is the configured URL of a data source instance (e.g. the URL of an API endpoint).
66	URL string
67
68	// User is a configured user for a data source instance. This is not a Grafana user, rather an arbitrary string.
69	User string
70
71	// Database is the configured database for a data source instance. (e.g. the default Database a SQL data source would connect to).
72	Database string
73
74	// BasicAuthEnabled indicates if this data source instance should use basic authentication.
75	BasicAuthEnabled bool
76
77	// BasicAuthUser is the configured user for basic authentication. (e.g. when a data source uses basic
78	// authentication to connect to whatever API it fetches data from).
79	BasicAuthUser string
80
81	// JSONData contains the raw DataSourceConfig as JSON as stored by Grafana server. It repeats the properties in
82	// this object and includes custom properties.
83	JSONData json.RawMessage
84
85	// DecryptedSecureJSONData contains key,value pairs where the encrypted configuration in Grafana server have been
86	// decrypted before passing them to the plugin.
87	DecryptedSecureJSONData map[string]string
88
89	// Updated is the last time the configuration for the data source instance was updated.
90	Updated time.Time
91}
92
93// HTTPClientOptions creates httpclient.Options based on settings.
94func (s *DataSourceInstanceSettings) HTTPClientOptions() (httpclient.Options, error) {
95	httpSettings, err := parseHTTPSettings(s.JSONData, s.DecryptedSecureJSONData)
96	if err != nil {
97		return httpclient.Options{}, err
98	}
99
100	if s.BasicAuthEnabled {
101		httpSettings.BasicAuthEnabled = s.BasicAuthEnabled
102		httpSettings.BasicAuthUser = s.BasicAuthUser
103		httpSettings.BasicAuthPassword = s.DecryptedSecureJSONData["basicAuthPassword"]
104	} else if s.User != "" {
105		httpSettings.BasicAuthEnabled = true
106		httpSettings.BasicAuthUser = s.User
107		httpSettings.BasicAuthPassword = s.DecryptedSecureJSONData["password"]
108	}
109
110	opts := httpSettings.HTTPClientOptions()
111	opts.Labels["datasource_name"] = s.Name
112	opts.Labels["datasource_uid"] = s.UID
113
114	setCustomOptionsFromHTTPSettings(&opts, httpSettings)
115
116	return opts, nil
117}
118
119// PluginContext holds contextual information about a plugin request, such as
120// Grafana organization, user and plugin instance settings.
121type PluginContext struct {
122	// OrgID is The Grafana organization identifier the request originating from.
123	OrgID int64
124
125	// PluginID is the unique identifier of the plugin that the request is for.
126	PluginID string
127
128	// User is the Grafana user making the request.
129	//
130	// Will not be provided if Grafana backend initiated the request,
131	// for example when request is coming from Grafana Alerting.
132	User *User
133
134	// AppInstanceSettings is the configured app instance settings.
135	//
136	// In Grafana an app instance is an app plugin of certain
137	// type that have been configured and enabled in a Grafana organization.
138	//
139	// Will only be set if request targeting an app instance.
140	AppInstanceSettings *AppInstanceSettings
141
142	// DataSourceConfig is the configured data source instance
143	// settings.
144	//
145	// In Grafana a data source instance is a data source plugin of certain
146	// type that have been configured and created in a Grafana organization.
147	//
148	// Will only be set if request targeting a data source instance.
149	DataSourceInstanceSettings *DataSourceInstanceSettings
150}
151
152func setCustomOptionsFromHTTPSettings(opts *httpclient.Options, httpSettings *HTTPSettings) {
153	opts.CustomOptions = map[string]interface{}{}
154
155	if httpSettings.JSONData != nil {
156		opts.CustomOptions[dataCustomOptionsKey] = httpSettings.JSONData
157	}
158
159	if httpSettings.SecureJSONData != nil {
160		opts.CustomOptions[secureDataCustomOptionsKey] = httpSettings.SecureJSONData
161	}
162}
163
164// JSONDataFromHTTPClientOptions extracts JSON data from CustomOptions of httpclient.Options.
165func JSONDataFromHTTPClientOptions(opts httpclient.Options) (res map[string]interface{}) {
166	if opts.CustomOptions == nil {
167		return
168	}
169
170	val, exists := opts.CustomOptions[dataCustomOptionsKey]
171	if !exists {
172		return
173	}
174
175	jsonData, ok := val.(map[string]interface{})
176	if !ok {
177		return
178	}
179
180	return jsonData
181}
182
183// SecureJSONDataFromHTTPClientOptions extracts secure JSON data from CustomOptions of httpclient.Options.
184func SecureJSONDataFromHTTPClientOptions(opts httpclient.Options) (res map[string]string) {
185	if opts.CustomOptions == nil {
186		return
187	}
188
189	val, exists := opts.CustomOptions[secureDataCustomOptionsKey]
190	if !exists {
191		return
192	}
193
194	secureJSONData, ok := val.(map[string]string)
195	if !ok {
196		return
197	}
198
199	return secureJSONData
200}
201