From 5a042e3c6623f290be13ef932d3040d90b9cb2d7 Mon Sep 17 00:00:00 2001 From: hunterlong Date: Sun, 21 Jun 2020 21:51:40 -0700 Subject: [PATCH 1/6] metrics now include service name for each service metric --- types/failures/database.go | 1 - types/hits/database.go | 1 - types/metrics/services.go | 2 +- types/services/routine.go | 16 +++++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/types/failures/database.go b/types/failures/database.go index e2cd7d1b..e3aad286 100644 --- a/types/failures/database.go +++ b/types/failures/database.go @@ -28,7 +28,6 @@ func (f *Failure) AfterDelete() { } func (f *Failure) AfterCreate() { - metrics.Inc("failure", f.Service) metrics.Query("failure", "create") } diff --git a/types/hits/database.go b/types/hits/database.go index 3268279f..5c3ce19f 100644 --- a/types/hits/database.go +++ b/types/hits/database.go @@ -27,7 +27,6 @@ func (h *Hit) AfterDelete() { } func (h *Hit) AfterCreate() { - metrics.Inc("success", h.Service) metrics.Query("hit", "create") } diff --git a/types/metrics/services.go b/types/metrics/services.go index 24f5908b..a0b43439 100644 --- a/types/metrics/services.go +++ b/types/metrics/services.go @@ -10,7 +10,7 @@ var ( Name: "service_online", Help: "If service is online", }, - []string{"service", "name", "type"}, + []string{"service", "type"}, ) // service failures diff --git a/types/services/routine.go b/types/services/routine.go index 3162d641..30eb2b8d 100644 --- a/types/services/routine.go +++ b/types/services/routine.go @@ -88,7 +88,7 @@ func isIPv6(address string) bool { // checkIcmp will send a ICMP ping packet to the service func CheckIcmp(s *Service, record bool) (*Service, error) { defer s.updateLastCheck() - timer := prometheus.NewTimer(metrics.ServiceTimer(s.Id)) + timer := prometheus.NewTimer(metrics.ServiceTimer(s.Name)) defer timer.ObserveDuration() if err := utils.Ping(s.Domain, s.Timeout); err != nil { @@ -105,7 +105,7 @@ func CheckIcmp(s *Service, record bool) (*Service, error) { // CheckGrpc will check a gRPC service func CheckGrpc(s *Service, record bool) (*Service, error) { defer s.updateLastCheck() - timer := prometheus.NewTimer(metrics.ServiceTimer(s.Id)) + timer := prometheus.NewTimer(metrics.ServiceTimer(s.Name)) defer timer.ObserveDuration() dnsLookup, err := dnsCheck(s) @@ -152,7 +152,7 @@ func CheckGrpc(s *Service, record bool) (*Service, error) { // checkTcp will check a TCP service func CheckTcp(s *Service, record bool) (*Service, error) { defer s.updateLastCheck() - timer := prometheus.NewTimer(metrics.ServiceTimer(s.Id)) + timer := prometheus.NewTimer(metrics.ServiceTimer(s.Name)) defer timer.ObserveDuration() dnsLookup, err := dnsCheck(s) @@ -219,7 +219,7 @@ func (s *Service) updateLastCheck() { // checkHttp will check a HTTP service func CheckHttp(s *Service, record bool) (*Service, error) { defer s.updateLastCheck() - timer := prometheus.NewTimer(metrics.ServiceTimer(s.Id)) + timer := prometheus.NewTimer(metrics.ServiceTimer(s.Name)) defer timer.ObserveDuration() dnsLookup, err := dnsCheck(s) @@ -285,7 +285,7 @@ func CheckHttp(s *Service, record bool) (*Service, error) { s.LastResponse = string(content) s.LastStatusCode = res.StatusCode - metrics.Gauge("status_code", float64(res.StatusCode), s.Id) + metrics.Gauge("status_code", float64(res.StatusCode), s.Name) if s.Expected.String != "" { match, err := regexp.MatchString(s.Expected.String, string(content)) @@ -329,7 +329,8 @@ func recordSuccess(s *Service) { fmt.Sprintf("Service #%d '%v' Successful Response: %s | Lookup in: %s | Online: %v | Interval: %d seconds", s.Id, s.Name, humanMicro(hit.Latency), humanMicro(hit.PingTime), s.Online, s.Interval)) s.LastLookupTime = hit.PingTime s.LastLatency = hit.Latency - metrics.Gauge("online", 1., s.Id, s.Name, s.Type) + metrics.Gauge("online", 1., s.Name, s.Type) + metrics.Inc("success", s.Name) sendSuccess(s) s.SuccessNotified = true } @@ -383,7 +384,8 @@ func recordFailure(s *Service, issue string) { s.Online = false s.SuccessNotified = false s.DownText = s.DowntimeText() - metrics.Gauge("online", 0., s.Id, s.Name, s.Type) + metrics.Gauge("online", 0., s.Name, s.Type) + metrics.Inc("failure", s.Name) sendFailure(s, fail) } From 04a04ad7152313ba9e28a9621fccc03ffafaeea0 Mon Sep 17 00:00:00 2001 From: hunterlong Date: Mon, 22 Jun 2020 00:13:57 -0700 Subject: [PATCH 2/6] added Switch and List inputs for notifiers, added more variable examples --- .../src/components/Dashboard/Variables.vue | 28 +++++++++++++++++-- frontend/src/forms/Notifier.vue | 26 ++++++++++++++--- frontend/src/forms/Setup.vue | 13 +++++++-- notifiers/email.go | 2 +- notifiers/pushover.go | 16 ++++++++++- notifiers/twilio.go | 4 +-- notifiers/webhook.go | 3 +- 7 files changed, 78 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/Dashboard/Variables.vue b/frontend/src/components/Dashboard/Variables.vue index 57393818..3dc1ec9d 100644 --- a/frontend/src/components/Dashboard/Variables.vue +++ b/frontend/src/components/Dashboard/Variables.vue @@ -38,8 +38,16 @@ 8080 - {{"\{\{.Service.DowntimeAgo\}\}"}} - 35 minutes ago + {{"\{\{.Service.Downtime.Human\}\}"}} + 2 minutes + + + {{"\{\{.Service.Uptime.Human\}\}"}} + 13 hours + + + {{"\{\{.Service.Online\}\}"}} + true/false {{"\{\{.Service.LastStatusCode\}\}"}} @@ -49,6 +57,22 @@ {{"\{\{.Service.FailuresLast24Hours\}\}"}} 38 + + {{"\{\{.Service.LastOnline\}\}"}} + 2020-11-05T13:15:30Z + + + {{"\{\{.Service.LastOffline\}\}"}} + 2020-10-01T13:15:30Z + + + {{"\{\{.Service.Online24Hours\}\}"}} + 0.99 + + + {{"\{\{.Service.Online7Days\}\}"}} + 0.97 + Additional variables within the Service struct diff --git a/frontend/src/forms/Notifier.vue b/frontend/src/forms/Notifier.vue index a071dbeb..cddf47a6 100644 --- a/frontend/src/forms/Notifier.vue +++ b/frontend/src/forms/Notifier.vue @@ -14,7 +14,16 @@
- + + + + + + + +
@@ -155,7 +164,7 @@ export default { theme: 'neat', mode: "mymode", lineWrapping: true, - json: true, + json: this.notifier.data_type === "json", autoRefresh: true, mime: this.notifier.data_type === "json" ? "application/json" : "text/plain" }, @@ -166,6 +175,9 @@ export default { }, methods: { + formVisible(want, form) { + return !!want.includes(form.type); + }, visible(isVisible, entry) { if (isVisible) { this.$refs.cmfailure.codemirror.refresh() @@ -173,13 +185,19 @@ export default { } }, onCmSuccessReady(cm) { - this.success_data = beautify(this.notifier.success_data, this.beautifySettings) + this.success_data = this.notifier.success_data + if (this.notifier.data_type === "json") { + this.success_data = beautify(this.notifier.success_data, this.beautifySettings) + } setTimeout(function() { cm.refresh(); },1); }, onCmFailureReady(cm) { - this.failure_data = beautify(this.notifier.failure_data, this.beautifySettings) + this.failure_data = this.notifier.failure_data + if (this.notifier.data_type === "json") { + this.failure_data = beautify(this.notifier.failure_data, this.beautifySettings) + } setTimeout(function() { cm.refresh(); },1); diff --git a/frontend/src/forms/Setup.vue b/frontend/src/forms/Setup.vue index 8f5fc45c..5232b4e0 100644 --- a/frontend/src/forms/Setup.vue +++ b/frontend/src/forms/Setup.vue @@ -74,12 +74,12 @@
- +
- +
@@ -100,6 +100,7 @@
+ Both passwords should match
@@ -108,7 +109,7 @@
-
+
@@ -145,6 +146,7 @@ error: null, loading: false, disabled: true, + passnomatch: false, setup: { language: "en", db_connection: "sqlite", @@ -186,6 +188,11 @@ canSubmit() { this.error = null const s = this.setup + if (s.confirm_password.length > 0 && s.confirm_password !== s.password) { + this.passnomatch = true + } else { + this.passnomatch = false + } if (s.db_connection !== 'sqlite') { if (!s.db_host || !s.db_port || !s.db_user || !s.db_password || !s.db_database) { this.disabled = true diff --git a/notifiers/email.go b/notifiers/email.go index 1f7b5d03..37c1a291 100644 --- a/notifiers/email.go +++ b/notifiers/email.go @@ -70,7 +70,7 @@ var email = &emailer{¬ifications.Notification{ Type: "switch", Title: "Disable TLS/SSL", Placeholder: "", - SmallText: "To Disable TLS/SSL insert 'true'", + SmallText: "Enabling this will set Insecure Skip Verify to true", DbField: "api_key", }}}, } diff --git a/notifiers/pushover.go b/notifiers/pushover.go index f480a3ad..bb45a6a3 100644 --- a/notifiers/pushover.go +++ b/notifiers/pushover.go @@ -41,7 +41,7 @@ var Pushover = &pushover{¬ifications.Notification{ Form: []notifications.NotificationForm{{ Type: "text", Title: "User Token", - Placeholder: "Insert your device's Pushover Token", + Placeholder: "Insert your Pushover User Token", DbField: "api_key", Required: true, }, { @@ -50,6 +50,20 @@ var Pushover = &pushover{¬ifications.Notification{ Placeholder: "Create an Application and insert the API Key here", DbField: "api_secret", Required: true, + }, { + Type: "list", + Title: "Priority", + Placeholder: "Set the notification priority level", + DbField: "Var1", + Required: true, + ListOptions: []string{"Lowest", "Low", "Normal", "High", "Emergency"}, + }, { + Type: "list", + Title: "Notification Sound", + Placeholder: "Choose a sound for this Pushover notification", + DbField: "Var2", + Required: true, + ListOptions: []string{"none", "pushover", "bike", "bugle", "cashregister", "classical", "cosmic", "falling", "gamelan", "incoming", "intermissioon", "magic", "mechanical", "painobar", "siren", "spacealarm", "tugboat", "alien", "climb", "persistent", "echo", "updown"}, }, }}, } diff --git a/notifiers/twilio.go b/notifiers/twilio.go index da4272f3..2892fd1b 100644 --- a/notifiers/twilio.go +++ b/notifiers/twilio.go @@ -50,13 +50,13 @@ var Twilio = &twilio{¬ifications.Notification{ DbField: "api_secret", Required: true, }, { - Type: "text", + Type: "number", Title: "SMS to Phone Number", Placeholder: "18555555555", DbField: "Var1", Required: true, }, { - Type: "text", + Type: "number", Title: "From Phone Number", Placeholder: "18555555555", DbField: "Var2", diff --git a/notifiers/webhook.go b/notifiers/webhook.go index 30a43b6e..e2ab9327 100644 --- a/notifiers/webhook.go +++ b/notifiers/webhook.go @@ -44,12 +44,13 @@ var Webhook = &webhooker{¬ifications.Notification{ DbField: "Host", Required: true, }, { - Type: "text", + Type: "list", Title: "HTTP Method", Placeholder: "POST", SmallText: "Choose a HTTP method for example: GET, POST, DELETE, or PATCH.", DbField: "Var1", Required: true, + ListOptions: []string{"GET", "POST", "PATCH", "DELETE"}, }, { Type: "text", Title: "Content Type", From 1044337ec610b3f567c3763e98a84ac7fa2ccd18 Mon Sep 17 00:00:00 2001 From: hunterlong Date: Mon, 22 Jun 2020 00:21:26 -0700 Subject: [PATCH 3/6] add error for theme editor --- frontend/src/components/Dashboard/ThemeEditor.vue | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Dashboard/ThemeEditor.vue b/frontend/src/components/Dashboard/ThemeEditor.vue index 5d402f16..bf0f6d1a 100644 --- a/frontend/src/components/Dashboard/ThemeEditor.vue +++ b/frontend/src/components/Dashboard/ThemeEditor.vue @@ -107,9 +107,14 @@ }, async createAssets() { this.pending = true - const resp = await Api.theme_generate(true) + let resp + try { + resp = await Api.theme_generate(true) + } catch(e) { + this.error = e.response.data.error + } this.pending = false - await this.fetchTheme() + await this.fetchTheme() }, async deleteAssets() { this.pending = true From 7be131d0cf6a43a83334232e8b9ead5c6f655b53 Mon Sep 17 00:00:00 2001 From: hunterlong Date: Wed, 24 Jun 2020 18:58:21 -0700 Subject: [PATCH 4/6] added http headers for outgoing requests, removed mobile notifier inputs, added Pushover notifier fields --- frontend/src/forms/Notifier.vue | 19 +++++++++++++++---- notifiers/pushover.go | 21 +++++++++++++++++++++ notifiers/webhook.go | 10 +++++----- utils/env.go | 2 +- utils/log.go | 8 ++++---- utils/utils.go | 4 ++++ 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/frontend/src/forms/Notifier.vue b/frontend/src/forms/Notifier.vue index cddf47a6..53cd3fef 100644 --- a/frontend/src/forms/Notifier.vue +++ b/frontend/src/forms/Notifier.vue @@ -12,7 +12,12 @@

-

+
+ + Scan this QR Code on the Statping Mobile App for quick setup +
+ +
@@ -171,9 +176,15 @@ export default { beautifySettings: { indent_size: 2, space_in_empty_paren: true }, } }, - computed: { - - }, + computed: { + core() { + return this.$store.getters.core + }, + qrcode() { + const u = `statping://setup?domain=${this.core.domain}&api=${this.core.api_secret}` + return "https://chart.googleapis.com/chart?chs=500x500&cht=qr&chl=" + encodeURIComponent(u) + } + }, methods: { formVisible(want, form) { return !!want.includes(form.type); diff --git a/notifiers/pushover.go b/notifiers/pushover.go index bb45a6a3..1f295e13 100644 --- a/notifiers/pushover.go +++ b/notifiers/pushover.go @@ -68,12 +68,33 @@ var Pushover = &pushover{¬ifications.Notification{ }}, } +func priority(val string) string { + switch strings.ToLower(val) { + case "lowest": + return "-2" + case "low": + return "-1" + case "normal": + return "0" + case "high": + return "1" + case "emergency": + return "2" + default: + return "1" + } +} + // Send will send a HTTP Post to the Pushover API. It accepts type: string func (t *pushover) sendMessage(message string) (string, error) { v := url.Values{} v.Set("token", t.ApiSecret) v.Set("user", t.ApiKey) v.Set("message", message) + v.Set("priority", priority(t.Var1)) + if t.Var2 != "" { + v.Set("sound", t.Var2) + } rb := strings.NewReader(v.Encode()) content, _, err := utils.HttpRequest(pushoverUrl, "POST", "application/x-www-form-urlencoded", nil, rb, time.Duration(10*time.Second), true, nil) diff --git a/notifiers/webhook.go b/notifiers/webhook.go index e2ab9327..b1ff300d 100644 --- a/notifiers/webhook.go +++ b/notifiers/webhook.go @@ -31,9 +31,9 @@ var Webhook = &webhooker{¬ifications.Notification{ Author: "Hunter Long", AuthorUrl: "https://github.com/hunterlong", Icon: "fas fa-code-branch", - Delay: time.Duration(1 * time.Second), - SuccessData: `{"id": {{.Service.Id}}, "online": true}`, - FailureData: `{"id": {{.Service.Id}}, "online": false}`, + Delay: time.Duration(3 * time.Second), + SuccessData: `{"id": "{{.Service.Id}}", "online": true}`, + FailureData: `{"id": "{{.Service.Id}}", "online": false}`, DataType: "json", Limits: 180, Form: []notifications.NotificationForm{{ @@ -83,8 +83,7 @@ func (w *webhooker) sendHttpWebhook(body string) (*http.Response, error) { utils.Log.Infoln(fmt.Sprintf("sending body: '%v' to %v as a %v request", body, w.Host, w.Var1)) client := new(http.Client) client.Timeout = time.Duration(10 * time.Second) - var buf *bytes.Buffer - buf = bytes.NewBuffer(nil) + buf := bytes.NewBuffer(nil) if w.Var2 != "" { buf = bytes.NewBuffer([]byte(body)) } @@ -103,6 +102,7 @@ func (w *webhooker) sendHttpWebhook(body string) (*http.Response, error) { req.Header.Add("Content-Type", w.ApiKey) } req.Header.Set("User-Agent", "Statping") + req.Header.Set("Statping-Version", utils.Version) resp, err := client.Do(req) if err != nil { return nil, err diff --git a/utils/env.go b/utils/env.go index 295760c9..10b9ab08 100644 --- a/utils/env.go +++ b/utils/env.go @@ -24,7 +24,7 @@ func InitEnvs() { Log.Errorln(err) defaultDir = "." } - Params.Set("VERSION", version) + Params.Set("VERSION", Version) Params.SetDefault("DISABLE_HTTP", false) Params.SetDefault("STATPING_DIR", defaultDir) Params.SetDefault("GO_ENV", "production") diff --git a/utils/log.go b/utils/log.go index a6aaf5ea..35da0913 100644 --- a/utils/log.go +++ b/utils/log.go @@ -21,7 +21,7 @@ var ( LastLines []*logRow LockLines sync.Mutex VerboseMode int - version string + Version string allowReports bool ) @@ -36,7 +36,7 @@ func SentryInit(v *string, allow bool) { if *v == "" { *v = "development" } - version = *v + Version = *v } goEnv := Params.GetString("GO_ENV") allowReports := Params.GetBool("ALLOW_REPORTS") @@ -44,7 +44,7 @@ func SentryInit(v *string, allow bool) { if err := sentry.Init(sentry.ClientOptions{ Dsn: errorReporter, Environment: goEnv, - Release: version, + Release: Version, AttachStacktrace: true, }); err != nil { Log.Errorln(err) @@ -63,7 +63,7 @@ func SentryErr(err error) { func SentryLogEntry(entry *Logger.Entry) { e := sentry.NewEvent() e.Message = entry.Message - e.Release = version + e.Release = Version e.Contexts = entry.Data sentry.CaptureEvent(e) } diff --git a/utils/utils.go b/utils/utils.go index bd293b37..353c4be7 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -217,6 +217,10 @@ func HttpRequest(url, method string, content interface{}, headers []string, body } } } + + req.Header.Set("User-Agent", "Statping") + req.Header.Set("Statping-Version", Version) + var resp *http.Response dialer := &net.Dialer{ From 6f0f712bad0ec89a10cc06a8ed4a7de9fbc27bb4 Mon Sep 17 00:00:00 2001 From: hunterlong Date: Thu, 25 Jun 2020 17:15:59 -0700 Subject: [PATCH 5/6] oauth fixes, login cookies fixes --- frontend/src/API.js | 12 +-- frontend/src/components/Dashboard/TopNav.vue | 2 +- frontend/src/forms/Login.vue | 5 +- frontend/src/forms/OAuth.vue | 21 ++--- frontend/src/routes.js | 2 +- frontend/src/store.js | 14 +-- frontend/vue.config.js | 15 ++- handlers/api.go | 11 ++- handlers/handlers.go | 8 +- handlers/jwt.go | 10 +- handlers/oauth.go | 29 +----- handlers/oauth_github.go | 99 ++++++++++++++++++++ handlers/routes.go | 4 +- 13 files changed, 157 insertions(+), 75 deletions(-) create mode 100644 handlers/oauth_github.go diff --git a/frontend/src/API.js b/frontend/src/API.js index 1adbbacc..aed0c464 100644 --- a/frontend/src/API.js +++ b/frontend/src/API.js @@ -9,7 +9,7 @@ const errorReporter = "https://bed4d75404924cb3a799e370733a1b64@sentry.statping. class Api { constructor() { - + axios.defaults.withCredentials = true } async oauth() { @@ -251,17 +251,13 @@ class Api { } token() { - const tk = $cookies.get(tokenKey) - if (!tk) { - return {admin: false}; - } - return tk; + return $cookies.get(tokenKey); } authToken() { const tk = $cookies.get(tokenKey) - if (tk.token) { - return {'Authorization': 'Bearer ' + tk.token}; + if (tk) { + return {'Authorization': 'Bearer ' + tk}; } else { return {}; } diff --git a/frontend/src/components/Dashboard/TopNav.vue b/frontend/src/components/Dashboard/TopNav.vue index 8b887f89..3129592a 100644 --- a/frontend/src/components/Dashboard/TopNav.vue +++ b/frontend/src/components/Dashboard/TopNav.vue @@ -52,7 +52,7 @@ this.$store.commit('setHasAllData', false) this.$store.commit('setToken', null) this.$store.commit('setAdmin', false) - this.$cookies.remove("statping_auth") + // this.$cookies.remove("statping_auth") await this.$router.push('/logout') } } diff --git a/frontend/src/forms/Login.vue b/frontend/src/forms/Login.vue index dd0fce1d..796f02ec 100644 --- a/frontend/src/forms/Login.vue +++ b/frontend/src/forms/Login.vue @@ -80,9 +80,8 @@ if (auth.error) { this.error = true } else if (auth.token) { - const u = {username: this.username, admin: auth.admin, token: auth.token} - this.$cookies.set("statping_auth", JSON.stringify(u)) - this.$store.dispatch('loadAdmin') + // this.$cookies.set("statping_auth", auth.token) + await this.$store.dispatch('loadAdmin') this.$store.commit('setAdmin', auth.admin) this.$router.push('/dashboard') } diff --git a/frontend/src/forms/OAuth.vue b/frontend/src/forms/OAuth.vue index ca0c7a5d..46933705 100644 --- a/frontend/src/forms/OAuth.vue +++ b/frontend/src/forms/OAuth.vue @@ -1,6 +1,5 @@