read only routes with api key - push notification update

pull/116/head
Hunter Long 2018-12-14 01:19:55 -08:00
parent 86958c1d36
commit 220080e323
17 changed files with 138 additions and 92 deletions

View File

@ -36,7 +36,7 @@ type apiResponse struct {
}
func apiIndexHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -45,7 +45,7 @@ func apiIndexHandler(w http.ResponseWriter, r *http.Request) {
}
func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}

View File

@ -28,7 +28,7 @@ import (
)
func apiAllCheckinsHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -42,7 +42,7 @@ func apiAllCheckinsHandler(w http.ResponseWriter, r *http.Request) {
}
func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -59,7 +59,7 @@ func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
}
func checkinCreateHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -115,7 +115,7 @@ func checkinHitHandler(w http.ResponseWriter, r *http.Request) {
}
func checkinDeleteHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}

View File

@ -27,7 +27,7 @@ import (
)
func dashboardHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
err := core.ErrorResponse{}
ExecuteResponse(w, r, "login.gohtml", err, nil)
} else {
@ -63,7 +63,7 @@ func logoutHandler(w http.ResponseWriter, r *http.Request) {
}
func helpHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -72,7 +72,7 @@ func helpHandler(w http.ResponseWriter, r *http.Request) {
}
func logsHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -88,7 +88,7 @@ func logsHandler(w http.ResponseWriter, r *http.Request) {
}
func logsLineHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsReadAuthenticated(r) {
w.WriteHeader(http.StatusInternalServerError)
return
}
@ -100,7 +100,7 @@ func logsLineHandler(w http.ResponseWriter, r *http.Request) {
}
func exportHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
w.WriteHeader(http.StatusInternalServerError)
return
}

View File

@ -96,9 +96,28 @@ func RunHTTPServer(ip string, port int) error {
return nil
}
// IsAuthenticated returns true if the HTTP request is authenticated. You can set the environment variable GO_ENV=test
// IsReadAuthenticated will allow Read Only authentication for some routes
func IsReadAuthenticated(r *http.Request) bool {
var token string
query := r.URL.Query()
key := query.Get("api")
if key == core.CoreApp.ApiKey {
return true
}
tokens, ok := r.Header["Authorization"]
if ok && len(tokens) >= 1 {
token = tokens[0]
token = strings.TrimPrefix(token, "Bearer ")
if token == core.CoreApp.ApiKey {
return true
}
}
return IsFullAuthenticated(r)
}
// IsFullAuthenticated returns true if the HTTP request is authenticated. You can set the environment variable GO_ENV=test
// to bypass the admin authenticate to the dashboard features.
func IsAuthenticated(r *http.Request) bool {
func IsFullAuthenticated(r *http.Request) bool {
if os.Getenv("GO_ENV") == "test" {
return true
}
@ -139,7 +158,7 @@ var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap
return template.URL(u)
},
"Auth": func() bool {
return IsAuthenticated(r)
return IsFullAuthenticated(r)
},
"VERSION": func() string {
return core.VERSION

View File

@ -26,7 +26,7 @@ import (
)
func messagesHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -35,7 +35,7 @@ func messagesHandler(w http.ResponseWriter, r *http.Request) {
}
func viewMessageHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -50,7 +50,7 @@ func viewMessageHandler(w http.ResponseWriter, r *http.Request) {
}
func apiAllMessagesHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsReadAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -64,7 +64,7 @@ func apiAllMessagesHandler(w http.ResponseWriter, r *http.Request) {
}
func apiMessageCreateHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -85,7 +85,7 @@ func apiMessageCreateHandler(w http.ResponseWriter, r *http.Request) {
}
func apiMessageGetHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsReadAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -100,7 +100,7 @@ func apiMessageGetHandler(w http.ResponseWriter, r *http.Request) {
}
func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -119,7 +119,7 @@ func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) {
}
func apiMessageUpdateHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}

View File

@ -27,7 +27,7 @@ import (
)
func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -41,7 +41,7 @@ func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
}
func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -56,7 +56,7 @@ func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
}
func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -83,7 +83,7 @@ func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
func testNotificationHandler(w http.ResponseWriter, r *http.Request) {
var err error
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}

View File

@ -27,7 +27,7 @@ type PluginSelect struct {
}
func pluginSavedHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -43,7 +43,7 @@ func pluginSavedHandler(w http.ResponseWriter, r *http.Request) {
}
func pluginsDownloadHandler(w http.ResponseWriter, r *http.Request) {
auth := IsAuthenticated(r)
auth := IsFullAuthenticated(r)
if !auth {
http.Redirect(w, r, "/", http.StatusSeeOther)
return

View File

@ -33,7 +33,7 @@ import (
//
func prometheusHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsReadAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}

View File

@ -93,7 +93,7 @@ func Router() *mux.Router {
r.Handle("/api/services", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
r.Handle("/api/services", http.HandlerFunc(apiCreateServiceHandler)).Methods("POST")
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceHandler)).Methods("GET")
r.Handle("/api/services/reorder", http.HandlerFunc(reorderServiceHandler)).Methods("POST")
r.Handle("/api/reorder", http.HandlerFunc(reorderServiceHandler)).Methods("POST")
r.Handle("/api/services/{id}/data", cached("30s", "application/json", http.HandlerFunc(apiServiceDataHandler))).Methods("GET")
r.Handle("/api/services/{id}/ping", http.HandlerFunc(apiServicePingDataHandler)).Methods("GET")
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceUpdateHandler)).Methods("POST")

View File

@ -47,7 +47,7 @@ func renderServiceChartsHandler(w http.ResponseWriter, r *http.Request) {
}
func servicesHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -60,7 +60,7 @@ type serviceOrder struct {
}
func reorderServiceHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -119,7 +119,7 @@ func servicesViewHandler(w http.ResponseWriter, r *http.Request) {
}
func apiServiceHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsReadAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -134,7 +134,7 @@ func apiServiceHandler(w http.ResponseWriter, r *http.Request) {
}
func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -155,7 +155,7 @@ func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
}
func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -219,7 +219,7 @@ func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
}
func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -238,7 +238,7 @@ func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) {
}
func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsReadAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -248,7 +248,7 @@ func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
}
func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}

View File

@ -28,7 +28,7 @@ import (
)
func settingsHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -36,7 +36,7 @@ func settingsHandler(w http.ResponseWriter, r *http.Request) {
}
func saveSettingsHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -77,7 +77,7 @@ func saveSettingsHandler(w http.ResponseWriter, r *http.Request) {
}
func saveSASSHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -94,7 +94,7 @@ func saveSASSHandler(w http.ResponseWriter, r *http.Request) {
}
func saveAssetsHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -115,7 +115,7 @@ func saveAssetsHandler(w http.ResponseWriter, r *http.Request) {
}
func deleteAssetsHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}

View File

@ -28,7 +28,7 @@ import (
)
func usersHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -37,7 +37,7 @@ func usersHandler(w http.ResponseWriter, r *http.Request) {
}
func usersEditHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
@ -48,7 +48,7 @@ func usersEditHandler(w http.ResponseWriter, r *http.Request) {
}
func apiUserHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -64,7 +64,7 @@ func apiUserHandler(w http.ResponseWriter, r *http.Request) {
}
func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -88,7 +88,7 @@ func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) {
}
func apiUserDeleteHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -112,7 +112,7 @@ func apiUserDeleteHandler(w http.ResponseWriter, r *http.Request) {
}
func apiAllUsersHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}
@ -126,7 +126,7 @@ func apiAllUsersHandler(w http.ResponseWriter, r *http.Request) {
}
func apiCreateUsersHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
if !IsFullAuthenticated(r) {
sendUnauthorizedJson(w, r)
return
}

View File

@ -16,12 +16,13 @@
package notifiers
import (
"bytes"
"encoding/json"
"fmt"
"github.com/hunterlong/statping/core/notifier"
"github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils"
"github.com/oliveroneill/exponent-server-sdk-golang/sdk"
"strings"
"os"
"time"
)
@ -44,6 +45,12 @@ var mobile = &mobilePush{&notifier.Notification{
Placeholder: "A list of your mobile device push notification ID's.",
DbField: "var1",
IsHidden: true,
}, {
Type: "number",
Title: "Array of device numbers",
Placeholder: "1 for iphone 2 for android",
DbField: "var2",
IsHidden: true,
}}},
}
@ -59,7 +66,7 @@ func (u *mobilePush) Select() *notifier.Notification {
return u.Notification
}
func dataJson(s *types.Service, f *types.Failure) map[string]string {
func dataJson(s *types.Service, f *types.Failure) map[string]interface{} {
serviceId := "0"
if s != nil {
serviceId = utils.ToString(s.Id)
@ -73,7 +80,7 @@ func dataJson(s *types.Service, f *types.Failure) map[string]string {
issue = f.Issue
}
link := fmt.Sprintf("statup://service?id=%v", serviceId)
out := map[string]string{
out := map[string]interface{}{
"status": online,
"id": serviceId,
"issue": issue,
@ -85,12 +92,10 @@ func dataJson(s *types.Service, f *types.Failure) map[string]string {
// OnFailure will trigger failing service
func (u *mobilePush) OnFailure(s *types.Service, f *types.Failure) {
data := dataJson(s, f)
msg := &expo.PushMessage{
Body: fmt.Sprintf("Your service '%v' is currently failing! Reason: %v", s.Name, f.Issue),
Sound: "default",
Title: "Service Offline",
Data: data,
Priority: expo.DefaultPriority,
msg := &PushArray{
Message: fmt.Sprintf("Your service '%v' is currently failing! Reason: %v", s.Name, f.Issue),
Title: "Service Offline",
Data: data,
}
u.AddQueue(s.Id, msg)
u.Online = false
@ -101,12 +106,10 @@ func (u *mobilePush) OnSuccess(s *types.Service) {
data := dataJson(s, nil)
if !u.Online {
u.ResetUniqueQueue(s.Id)
msg := &expo.PushMessage{
Body: fmt.Sprintf("Your service '%v' is back online!", s.Name),
Sound: "default",
Title: "Service Online",
Data: data,
Priority: expo.DefaultPriority,
msg := &PushArray{
Message: fmt.Sprintf("Your service '%v' is back online!", s.Name),
Title: "Service Online",
Data: data,
}
u.AddQueue(s.Id, msg)
}
@ -115,11 +118,9 @@ func (u *mobilePush) OnSuccess(s *types.Service) {
// OnSave triggers when this notifier has been saved
func (u *mobilePush) OnSave() error {
msg := &expo.PushMessage{
Body: "The Mobile Notifier has been saved",
Sound: "default",
Title: "Notification Saved",
Priority: expo.DefaultPriority,
msg := &PushArray{
Message: "The Mobile Notifier has been saved",
Title: "Notification Saved",
}
u.AddQueue(0, msg)
return nil
@ -130,26 +131,45 @@ func (u *mobilePush) OnTest() error {
return nil
}
// Send will send message to expo mobile push notifications endpoint
// Send will send message to Statping push notifications endpoint
func (u *mobilePush) Send(msg interface{}) error {
pushMessage := msg.(*expo.PushMessage)
client := expo.NewPushClient(nil)
splitIds := strings.Split(u.Var1, ",")
for _, id := range splitIds {
pushToken, err := expo.NewExponentPushToken(expo.ExponentPushToken(id))
if err != nil {
return err
}
pushMessage.To = pushToken
response, err := client.Publish(pushMessage)
if err != nil {
return err
}
if response.ValidateResponse() != nil {
fmt.Println(response.PushMessage.To, "failed")
}
pushMessage := msg.(*PushArray)
pushMessage.Tokens = []string{u.Var1}
pushMessage.Platform = utils.ToInt(u.Var2)
err := pushRequest(pushMessage)
if err != nil {
return err
}
return nil
}
func pushRequest(msg *PushArray) error {
if msg.Platform == 1 {
msg.Title = ""
}
body, _ := json.Marshal(&PushNotification{[]*PushArray{msg}})
url := "https://push.statping.com/api/push"
if os.Getenv("GO_ENV") == "test" {
url = "https://pushdev.statping.com/api/push"
}
_, _, err := utils.HttpRequest(url, "POST", "application/json", nil, bytes.NewBuffer(body), time.Duration(10*time.Second))
return err
}
type PushNotification struct {
Array []*PushArray `json:"notifications"`
}
type PushArray struct {
Tokens []string `json:"tokens"`
Platform int64 `json:"platform"`
Message string `json:"message"`
Title string `json:"title,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
}
type MobileResponse struct {
Counts int `json:"counts"`
Logs []interface{} `json:"logs"`
Success string `json:"success"`
}

View File

@ -24,17 +24,20 @@ import (
)
var (
MOBILE_ID string
MOBILE_ID string
MOBILE_NUMBER string
)
func init() {
MOBILE_ID = os.Getenv("MOBILE_ID")
MOBILE_NUMBER = os.Getenv("MOBILE_NUMBER")
mobile.Var1 = MOBILE_ID
}
func TestMobileNotifier(t *testing.T) {
t.Parallel()
mobile.Var1 = MOBILE_ID
mobile.Var2 = os.Getenv("MOBILE_NUMBER")
if MOBILE_ID == "" {
t.Log("mobile notifier testing skipped, missing MOBILE_ID environment variable")
t.SkipNow()
@ -43,12 +46,14 @@ func TestMobileNotifier(t *testing.T) {
t.Run("Load mobile", func(t *testing.T) {
mobile.Var1 = MOBILE_ID
mobile.Var2 = MOBILE_NUMBER
mobile.Delay = time.Duration(100 * time.Millisecond)
mobile.Limits = 3
err := notifier.AddNotifier(mobile)
assert.Nil(t, err)
assert.Equal(t, "Hunter Long", mobile.Author)
assert.Equal(t, MOBILE_ID, mobile.Var1)
assert.Equal(t, MOBILE_NUMBER, mobile.Var2)
})
t.Run("Load mobile Notifier", func(t *testing.T) {

View File

@ -61,7 +61,7 @@
newOrder.push(o);
});
$.ajax({
url: "/api/services/reorder",
url: "/api/reorder",
type: 'POST',
data: JSON.stringify(newOrder),
contentType: "application/json",

View File

@ -106,6 +106,7 @@
<label for="api_key" class="col-sm-3 col-form-label">API Key</label>
<div class="col-sm-9">
<input type="text" class="form-control select-input" value="{{ .ApiKey }}" id="api_key" readonly>
<small class="form-text text-muted">API Key can be used for read only routes</small>
</div>
</div>
@ -113,6 +114,7 @@
<label for="api_secret" class="col-sm-3 col-form-label">API Secret</label>
<div class="col-sm-9">
<input type="text" class="form-control select-input" value="{{ .ApiSecret }}" id="api_secret" readonly>
<small class="form-text text-muted">API Secret is used for read, create, update and delete routes</small>
<small class="form-text text-muted">You can <a class="confirm_btn" data-msg="Are you sure you want to reset the API keys?" href="/api/renew">Regenerate API Keys</a> if you need to.</small>
</div>
</div>

View File

@ -1 +1 @@
0.80.1
0.80.2