+
@@ -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/frontend/src/routes.js b/frontend/src/routes.js
index be7e8a5c..ab1ad3c5 100644
--- a/frontend/src/routes.js
+++ b/frontend/src/routes.js
@@ -38,7 +38,7 @@ const routes = [
beforeEnter: async (to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
let tk = await Api.token()
- if (to.path !== '/login' && !tk.admin) {
+ if (to.path !== '/login' && !tk) {
next('/login')
return
}
diff --git a/frontend/src/store.js b/frontend/src/store.js
index 673724e1..c8738d22 100644
--- a/frontend/src/store.js
+++ b/frontend/src/store.js
@@ -147,9 +147,9 @@ export default new Vuex.Store({
const core = await Api.core()
const token = await Api.token()
context.commit("setCore", core);
- context.commit('setAdmin', token.admin)
+ context.commit('setAdmin', token)
context.commit('setCore', core)
- context.commit('setUser', token.token!==undefined)
+ context.commit('setUser', token!==undefined)
},
async loadRequired(context) {
const groups = await Api.groups()
@@ -170,14 +170,8 @@ export default new Vuex.Store({
const messages = await Api.messages()
context.commit("setMessages", messages)
context.commit("setHasPublicData", true)
- try {
- const checkins = await Api.checkins()
- context.commit("setCheckins", checkins);
- } catch(e) {
- window.console.error(e)
- await Api.logout()
- return
- }
+ const checkins = await Api.checkins()
+ context.commit("setCheckins", checkins);
const notifiers = await Api.notifiers()
context.commit("setNotifiers", notifiers);
const users = await Api.users()
diff --git a/frontend/vue.config.js b/frontend/vue.config.js
index 8ce147cc..39d5beb2 100644
--- a/frontend/vue.config.js
+++ b/frontend/vue.config.js
@@ -3,14 +3,23 @@ module.exports = {
assetsDir: 'assets',
filenameHashing: false,
devServer: {
- proxy: {
+ disableHostCheck: true,
+ proxyTable: {
'/api': {
logLevel: 'debug',
- target: 'http://0.0.0.0:8585'
+ target: 'http://0.0.0.0:8585',
+ changeOrigin: true,
+ pathRewrite: {
+ '^/api': ''
+ }
},
'/oauth': {
logLevel: 'debug',
- target: 'http://0.0.0.0:8585/oauth/'
+ target: 'http://0.0.0.0:8585',
+ changeOrigin: true,
+ pathRewrite: {
+ '^/oauth': ''
+ }
}
}
}
diff --git a/handlers/api.go b/handlers/api.go
index e04d1777..b153bb98 100644
--- a/handlers/api.go
+++ b/handlers/api.go
@@ -46,13 +46,20 @@ func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
func apiUpdateOAuthHandler(w http.ResponseWriter, r *http.Request) {
var c core.OAuth
- err := DecodeJSON(r, &c)
- if err != nil {
+ if err := DecodeJSON(r, &c); err != nil {
sendErrorJson(err, w, r)
return
}
+
app := core.App
app.OAuth = c
+ if err := app.Update(); err != nil {
+ sendErrorJson(err, w, r)
+ return
+ }
+
+ fmt.Println(app)
+
sendJsonAction(app.OAuth, "update", w, r)
}
diff --git a/handlers/handlers.go b/handlers/handlers.go
index 2bc643b2..93db3860 100644
--- a/handlers/handlers.go
+++ b/handlers/handlers.go
@@ -19,7 +19,7 @@ const (
)
var (
- jwtKey string
+ jwtKey []byte
httpServer *http.Server
usingSSL bool
mainTmpl = `{{define "main" }} {{ template "base" . }} {{ end }}`
@@ -96,7 +96,11 @@ func IsFullAuthenticated(r *http.Request) bool {
if ok := hasAuthorizationHeader(r); ok {
return true
}
- return IsAdmin(r)
+ claim, err := getJwtToken(r)
+ if err != nil {
+ return false
+ }
+ return claim.Admin
}
// ScopeName will show private JSON fields in the API.
diff --git a/handlers/jwt.go b/handlers/jwt.go
index 797c6e05..76a8abc8 100644
--- a/handlers/jwt.go
+++ b/handlers/jwt.go
@@ -33,7 +33,7 @@ func setJwtToken(user *users.User, w http.ResponseWriter) (JwtClaim, string) {
ExpiresAt: expirationTime.Unix(),
}}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtClaim)
- tokenString, err := token.SignedString([]byte(jwtKey))
+ tokenString, err := token.SignedString(jwtKey)
if err != nil {
log.Errorln("error setting token: ", err)
}
@@ -44,6 +44,7 @@ func setJwtToken(user *users.User, w http.ResponseWriter) (JwtClaim, string) {
Value: tokenString,
Expires: expirationTime,
MaxAge: int(time.Duration(72 * time.Hour).Seconds()),
+ Path: "/",
})
return jwtClaim, tokenString
}
@@ -56,11 +57,12 @@ func getJwtToken(r *http.Request) (JwtClaim, error) {
}
return JwtClaim{}, err
}
- tknStr := c.Value
+
var claims JwtClaim
- tkn, err := jwt.ParseWithClaims(tknStr, &claims, func(token *jwt.Token) (interface{}, error) {
- return []byte(jwtKey), nil
+ tkn, err := jwt.ParseWithClaims(c.Value, &claims, func(token *jwt.Token) (interface{}, error) {
+ return jwtKey, nil
})
+
if err != nil {
if err == jwt.ErrSignatureInvalid {
return JwtClaim{}, err
diff --git a/handlers/oauth.go b/handlers/oauth.go
index 3fd38bff..14f9bc40 100644
--- a/handlers/oauth.go
+++ b/handlers/oauth.go
@@ -9,7 +9,6 @@ import (
"github.com/statping/statping/types/users"
"github.com/statping/statping/utils"
"golang.org/x/oauth2"
- "golang.org/x/oauth2/github"
"golang.org/x/oauth2/google"
"golang.org/x/oauth2/slack"
"net/http"
@@ -51,40 +50,18 @@ func oauthHandler(w http.ResponseWriter, r *http.Request) {
}
func oauthLogin(oauth *oAuth, w http.ResponseWriter, r *http.Request) {
- log.Infoln(oauth)
user := &users.User{
Id: 0,
Username: oauth.Username,
Email: oauth.Email,
Admin: null.NewNullBool(true),
}
- log.Infoln(fmt.Sprintf("OAuth User %s logged in from IP %s", oauth.Email, r.RemoteAddr))
+ log.Infoln(fmt.Sprintf("OAuth %s User %s logged in from IP %s", oauth.Type, oauth.Email, r.RemoteAddr))
+
setJwtToken(user, w)
//returnJson(user, w, r)
- http.Redirect(w, r, core.App.Domain, http.StatusPermanentRedirect)
-}
-
-func githubOAuth(r *http.Request) (*oAuth, error) {
- c := *core.App
- code := r.URL.Query().Get("code")
-
- config := &oauth2.Config{
- ClientID: c.OAuth.GithubClientID,
- ClientSecret: c.OAuth.GithubClientSecret,
- Endpoint: github.Endpoint,
- }
-
- gg, err := config.Exchange(r.Context(), code)
- if err != nil {
- return nil, err
- }
-
- return &oAuth{
- Token: gg.AccessToken,
- RefreshToken: gg.RefreshToken,
- Valid: gg.Valid(),
- }, nil
+ http.Redirect(w, r, core.App.Domain+"/dashboard", http.StatusPermanentRedirect)
}
func googleOAuth(r *http.Request) (*oAuth, error) {
diff --git a/handlers/oauth_github.go b/handlers/oauth_github.go
new file mode 100644
index 00000000..fb6a848a
--- /dev/null
+++ b/handlers/oauth_github.go
@@ -0,0 +1,99 @@
+package handlers
+
+import (
+ "encoding/json"
+ "github.com/statping/statping/types/core"
+ "github.com/statping/statping/utils"
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/github"
+ "net/http"
+ "strings"
+ "time"
+)
+
+func githubOAuth(r *http.Request) (*oAuth, error) {
+ c := *core.App
+ code := r.URL.Query().Get("code")
+
+ config := &oauth2.Config{
+ ClientID: c.OAuth.GithubClientID,
+ ClientSecret: c.OAuth.GithubClientSecret,
+ Endpoint: github.Endpoint,
+ }
+
+ gg, err := config.Exchange(r.Context(), code)
+ if err != nil {
+ return nil, err
+ }
+
+ headers := []string{
+ "Accept=application/vnd.github.machine-man-preview+json",
+ "Authorization=token " + gg.AccessToken,
+ }
+
+ resp, _, err := utils.HttpRequest("https://api.github.com/user", "GET", nil, headers, nil, 10*time.Second, true, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ var user githubUser
+ if err := json.Unmarshal(resp, &user); err != nil {
+ return nil, err
+ }
+
+ return &oAuth{
+ Token: gg.AccessToken,
+ RefreshToken: gg.RefreshToken,
+ Valid: gg.Valid(),
+ Username: strings.ToLower(user.Name),
+ Email: strings.ToLower(user.Email),
+ Type: "github",
+ }, nil
+}
+
+type githubUser struct {
+ Login string `json:"login"`
+ ID int `json:"id"`
+ NodeID string `json:"node_id"`
+ AvatarURL string `json:"avatar_url"`
+ GravatarID string `json:"gravatar_id"`
+ URL string `json:"url"`
+ HTMLURL string `json:"html_url"`
+ FollowersURL string `json:"followers_url"`
+ FollowingURL string `json:"following_url"`
+ GistsURL string `json:"gists_url"`
+ StarredURL string `json:"starred_url"`
+ SubscriptionsURL string `json:"subscriptions_url"`
+ OrganizationsURL string `json:"organizations_url"`
+ ReposURL string `json:"repos_url"`
+ EventsURL string `json:"events_url"`
+ ReceivedEventsURL string `json:"received_events_url"`
+ Type string `json:"type"`
+ SiteAdmin bool `json:"site_admin"`
+ Name string `json:"name"`
+ Company string `json:"company"`
+ Blog string `json:"blog"`
+ Location string `json:"location"`
+ Email string `json:"email"`
+ Hireable bool `json:"hireable"`
+ Bio string `json:"bio"`
+ TwitterUsername string `json:"twitter_username"`
+ PublicRepos int `json:"public_repos"`
+ PublicGists int `json:"public_gists"`
+ Followers int `json:"followers"`
+ Following int `json:"following"`
+ CreatedAt time.Time `json:"created_at"`
+ UpdatedAt time.Time `json:"updated_at"`
+ PrivateGists int `json:"private_gists"`
+ TotalPrivateRepos int `json:"total_private_repos"`
+ OwnedPrivateRepos int `json:"owned_private_repos"`
+ DiskUsage int `json:"disk_usage"`
+ Collaborators int `json:"collaborators"`
+ TwoFactorAuthentication bool `json:"two_factor_authentication"`
+ Plan struct {
+ Name string `json:"name"`
+ Space int `json:"space"`
+ PrivateRepos int `json:"private_repos"`
+ Collaborators int `json:"collaborators"`
+ } `json:"plan"`
+}
diff --git a/handlers/routes.go b/handlers/routes.go
index 114b0c22..0ff7f3ea 100644
--- a/handlers/routes.go
+++ b/handlers/routes.go
@@ -1,12 +1,10 @@
package handlers
import (
- "fmt"
sentryhttp "github.com/getsentry/sentry-go/http"
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/statping/statping/source"
- "github.com/statping/statping/types/core"
"github.com/statping/statping/utils"
"net/http"
"net/http/pprof"
@@ -192,5 +190,5 @@ func resetRouter() {
}
func resetCookies() {
- jwtKey = fmt.Sprintf("%s_%d", core.App.ApiSecret, utils.Now().Nanosecond())
+ jwtKey = []byte(utils.NewSHA256Hash())
}
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..1f295e13 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,16 +50,51 @@ 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"},
},
}},
}
+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/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..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{{
@@ -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",
@@ -82,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))
}
@@ -102,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/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)
}
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{
diff --git a/version.txt b/version.txt
index 74094774..2e31fdc9 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-0.90.55
+0.90.56