11package main
22
33import (
4+ "bytes"
45 "context"
6+ "crypto/tls"
57 "encoding/json"
68 "flag"
79 "fmt"
810 "image/color"
911 "math"
12+ "net/http"
13+ // debug
14+ // "net/http/httputil"
1015 "os"
16+ "os/exec"
1117 "strconv"
1218 "time"
1319
@@ -42,6 +48,73 @@ type myTheme struct {
4248 Config * Config
4349}
4450
51+ // Custom transport to add Basic Auth to each request
52+ type basicAuthTransport struct {
53+ Username string
54+ Password string
55+ Transport http.RoundTripper
56+ }
57+
58+ // Struct to hold Bitwarden login fields
59+ type BitwardenItem struct {
60+ Login struct {
61+ Username string `json:"username"`
62+ Password string `json:"password"`
63+ } `json:"login"`
64+ }
65+
66+ func (bat * basicAuthTransport ) RoundTrip (req * http.Request ) (* http.Response , error ) {
67+ req .SetBasicAuth (bat .Username , bat .Password )
68+ // Dump request
69+ //dump, err := httputil.DumpRequestOut(req, false) // `true` if you want to include the body
70+ //if err != nil {
71+ // fmt.Printf("Request dump error: %v\n", err)
72+ //} else {
73+ // fmt.Printf("🚀 Outgoing request:\n%s\n", dump)
74+ //}
75+
76+ //resp, err := bat.transport().RoundTrip(req)
77+ //if err != nil {
78+ // return nil, err
79+ //}
80+
81+ // Dump response
82+ //fmt.Printf("HTTP Response requested:\n")
83+ //respDump, err := httputil.DumpResponse(resp, true)
84+ //if err == nil {
85+ // fmt.Printf("📥 HTTP Response:\n%s\n", respDump)
86+ //}
87+ return bat .transport ().RoundTrip (req )
88+ }
89+
90+ func (bat * basicAuthTransport ) transport () http.RoundTripper {
91+ if bat .Transport != nil {
92+ return bat .Transport
93+ }
94+ return http .DefaultTransport
95+ }
96+
97+ // Get BW_SESSION from env
98+ func getSessionToken () string {
99+ return os .Getenv ("BW_SESSION" )
100+ }
101+
102+ // Run Bitwarden CLI to get the item JSON
103+ func getBitwardenItemJSON (itemName string ) ([]byte , error ) {
104+ cmd := exec .Command ("bw" , "get" , "item" , itemName )
105+ cmd .Env = append (os .Environ (), "BW_SESSION=" + getSessionToken ())
106+
107+ var out bytes.Buffer
108+ cmd .Stdout = & out
109+
110+ err := cmd .Run ()
111+ if err != nil {
112+ return nil , err
113+ }
114+
115+ return out .Bytes (), nil
116+ }
117+
45118func loadMetricsFromFile (path string ) ([]Metric , error ) {
46119 data , err := os .ReadFile (path )
47120 if err != nil {
@@ -70,14 +143,39 @@ func GetConfig() (*Config, error) {
70143 }, nil
71144}
72145
73- func (c * Config ) getMetricValue (metric string ) (int , error ) {
74- client , err := api .NewClient (api.Config {Address : c .PrometheusURL })
146+ func (c * Config ) getMetricValue (metric string , username string , password string ) (int , error ) {
147+
148+ prometheus := c .PrometheusURL
149+
150+ customClient := & http.Client {
151+ Transport : & http.Transport {
152+ Proxy : http .ProxyFromEnvironment ,
153+ TLSClientConfig : & tls.Config {
154+ InsecureSkipVerify : true ,
155+ },
156+ },
157+ Timeout : 10 * time .Second ,
158+ }
159+
160+ // Wrap customClient with basic auth
161+ transportWithAuth := basicAuthTransport {
162+ Username : username ,
163+ Password : password ,
164+ Transport : customClient .Transport ,
165+ }
166+
167+ // Create Prometheus API client
168+ client , err := api .NewClient (api.Config {
169+ Address : prometheus ,
170+ RoundTripper : & transportWithAuth ,
171+ })
172+
75173 if err != nil {
76174 return 0 , err
77175 }
78176
79177 v1api := v1 .NewAPI (client )
80- ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
178+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
81179 defer cancel ()
82180
83181 result , _ , err := v1api .Query (ctx , metric , time .Now ())
@@ -109,6 +207,7 @@ func (m *myTheme) Icon(name fyne.ThemeIconName) fyne.Resource { return theme.Def
109207func main () {
110208
111209 verbose := flag .Bool ("v" , false , "enable verbose logging" )
210+ bitwarden := flag .Bool ("bw" , false , "enable Bitwarden password store" )
112211 flag .Parse ()
113212
114213 config , err := GetConfig ()
@@ -130,6 +229,27 @@ func main() {
130229 w .SetContent (content )
131230 w .Show ()
132231
232+ username := os .Getenv ("PROM_USER" )
233+ password := os .Getenv ("PROM_PASS" )
234+
235+ if * bitwarden == true {
236+ // doing bitwarden stuff here to get prometheus credentials
237+ itemName := "Prometheus Agent RemoteWrite"
238+ jsonData , err := getBitwardenItemJSON (itemName )
239+ if err != nil {
240+ fmt .Printf ("Failed to get item from Bitwarden: %v\n " , err )
241+ }
242+
243+ var item BitwardenItem
244+ err = json .Unmarshal (jsonData , & item )
245+ if err != nil {
246+ fmt .Printf ("Failed to parse Bitwarden JSON: %v\n " , err )
247+ }
248+
249+ username = item .Login .Username
250+ password = item .Login .Password
251+ }
252+
133253 go func () {
134254 for {
135255 var (
@@ -139,7 +259,7 @@ func main() {
139259 )
140260
141261 for _ , metric := range config .Metrics {
142- val , err := config .getMetricValue (metric .Name )
262+ val , err := config .getMetricValue (metric .Name , username , password )
143263
144264 var icon * canvas.Text
145265 var statusText string
0 commit comments