diff --git a/admin/admin.go b/admin/admin.go index d667096..d59608a 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -7,32 +7,34 @@ package admin import ( + "database/sql" + "encoding/json" "fmt" + "golang.org/x/crypto/bcrypt" "io" "io/ioutil" "net/http" "os" "strings" - "encoding/json" - "golang.org/x/crypto/bcrypt" - "database/sql" - _ "github.com/mattn/go-sqlite3" "github.com/gorilla/mux" + _ "github.com/mattn/go-sqlite3" "github.com/gmemstr/pogo/common" ) + type User struct { - Id int `json:"id"` - Dbun string `json:"username"` - Dbrn string `json:"realname"` - Dbem string `json:"email"` + Id int `json:"id"` + Dbun string `json:"username"` + Dbrn string `json:"realname"` + Dbem string `json:"email"` } type UserList struct { Users []User } + /* - * The following is a set of admin commands + * The following is a set of admin commands * that the average user probably shouldn't be * able to have access to, mostly user management. */ @@ -71,7 +73,7 @@ func AddUser() common.Handler { hash, err := bcrypt.GenerateFromPassword([]byte(password), 4) - _, err = statement.Exec(username,hash,realname,email) + _, err = statement.Exec(username, hash, realname, email) if err != nil { return &common.HTTPError{ Message: fmt.Sprintf("error executing sqlite3 statement: %v", err), @@ -145,7 +147,7 @@ func EditUser() common.Handler { Message: fmt.Sprintf("error executing sqlite3 statement: %v", err), StatusCode: http.StatusInternalServerError, } - } + } } fmt.Println(hash) if bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) != nil { @@ -158,9 +160,9 @@ func EditUser() common.Handler { if newpassword != "" { pwhash, err = bcrypt.GenerateFromPassword([]byte(newpassword), 4) - } + } - _, err = statement.Exec(username,pwhash,realname,email,id) + _, err = statement.Exec(username, pwhash, realname, email, id) if err != nil { return &common.HTTPError{ Message: fmt.Sprintf("error executing sqlite3 statement: %v", err), @@ -328,15 +330,15 @@ func EditEpisode() common.Handler { fmt.Println(filename) description := strings.Join(r.Form["description"], "") - if ("./podcasts" + PreviousFilename + ".mp3" != filename) { - err = os.Rename("./podcasts/" + PreviousFilename + ".mp3", filename) + if "./podcasts"+PreviousFilename+".mp3" != filename { + err = os.Rename("./podcasts/"+PreviousFilename+".mp3", filename) if err != nil { return &common.HTTPError{ Message: err.Error(), StatusCode: http.StatusBadRequest, } } - err = os.Rename("./podcasts/" + PreviousFilename + "_SHOWNOTES.md", shownotes) + err = os.Rename("./podcasts/"+PreviousFilename+"_SHOWNOTES.md", shownotes) if err != nil { return &common.HTTPError{ Message: err.Error(), diff --git a/assets/config/users.db b/assets/config/users.db index ce23fae..cf14ec3 100644 Binary files a/assets/config/users.db and b/assets/config/users.db differ diff --git a/auth/auth.go b/auth/auth.go index a76db02..19b356c 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -6,6 +6,7 @@ import ( "crypto/hmac" "crypto/rand" "crypto/sha256" + "database/sql" "encoding/base64" "encoding/hex" "encoding/json" @@ -13,8 +14,10 @@ import ( "fmt" "log" "net/http" - "strings" "os" + "strings" + + _ "github.com/mattn/go-sqlite3" "github.com/gmemstr/pogo/common" ) @@ -27,7 +30,39 @@ const ( cookieExpiry = 60 * 60 * 24 * 30 // 30 days in seconds ) -func RequireAuthorization() common.Handler { +func UserPermissions(username string, permission int) (bool, error) { + + db, err := sql.Open("sqlite3", "assets/config/users.db") + defer db.Close() + isAllowed := false + if err != nil { + return isAllowed, err + } + + statement, err := db.Prepare("SELECT permissions FROM users WHERE username=?") + if err != nil { + return isAllowed, err + } + + rows, err := statement.Query(username) + if err != nil { + return isAllowed, err + } + + var level int + for rows.Next() { + err = rows.Scan(&level) + if err != nil { + return isAllowed, err + } + if level >= permission { + isAllowed = true + } + } + return isAllowed, nil +} + +func RequireAuthorization(permission int) common.Handler { return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError { usr, err := DecryptCookie(r) if err != nil { @@ -46,6 +81,17 @@ func RequireAuthorization() common.Handler { } rc.User = usr + + username := rc.User.Username + + hasPermission, err := UserPermissions(string(username), permission) + + if !hasPermission { + return &common.HTTPError{ + Message: "Unauthorized! Redirecting to /admin", + StatusCode: http.StatusUnauthorized, + } + } return nil } } diff --git a/router/router.go b/router/router.go index 0fe53aa..9c31b9a 100644 --- a/router/router.go +++ b/router/router.go @@ -1,21 +1,21 @@ package router import ( + "database/sql" "encoding/json" "fmt" + "golang.org/x/crypto/bcrypt" "io/ioutil" "log" "net/http" "strings" - "golang.org/x/crypto/bcrypt" - "database/sql" _ "github.com/mattn/go-sqlite3" - "github.com/gorilla/mux" "github.com/gmemstr/pogo/admin" "github.com/gmemstr/pogo/auth" "github.com/gmemstr/pogo/common" + "github.com/gorilla/mux" ) type NewConfig struct { @@ -70,7 +70,7 @@ func Init() *mux.Router { // Authenticated endpoints should be passed to BasicAuth() // first r.Handle("/admin", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(0), adminHandler(), )).Methods("GET", "POST") @@ -79,45 +79,45 @@ func Init() *mux.Router { )).Methods("GET", "POST") r.Handle("/admin/publish", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(0), admin.CreateEpisode(), )).Methods("POST") r.Handle("/admin/edituser", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(2), admin.EditUser(), )).Methods("POST") r.Handle("/admin/newuser", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(2), admin.AddUser(), )).Methods("POST") r.Handle("/admin/deleteuser/{id}", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(2), admin.DeleteUser(), )).Methods("GET") r.Handle("/admin/edit", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(0), admin.EditEpisode(), )).Methods("POST") r.Handle("/admin/delete", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(0), admin.RemoveEpisode(), )).Methods("GET") r.Handle("/admin/css", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(2), admin.CustomCss(), )).Methods("GET", "POST") r.Handle("/admin/adduser", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(1), admin.AddUser(), )).Methods("POST") r.Handle("/admin/listusers", Handle( - auth.RequireAuthorization(), + auth.RequireAuthorization(1), admin.ListUsers(), )).Methods("GET") @@ -169,13 +169,14 @@ func loginHandler() common.Handler { StatusCode: http.StatusBadRequest, } } - var id int - var dbun string + var id int + var dbun string var dbhsh string - var dbrn string - var dbem string + var dbrn string + var dbem string + var dbperm int for rows.Next() { - err := rows.Scan(&id,&dbun,&dbhsh,&dbrn,&dbem) + err := rows.Scan(&id, &dbun, &dbhsh, &dbrn, &dbem, &dbperm) if err != nil { return &common.HTTPError{ Message: fmt.Sprintf("error in decoding sql data", err), @@ -186,7 +187,7 @@ func loginHandler() common.Handler { } // Create a cookie here because the credentials are correct if dbun == username && bcrypt.CompareHashAndPassword([]byte(dbhsh), []byte(password)) == nil { - c, err := auth.CreateSession(&common.User{ + c, err := auth.CreateSession(&common.User{ Username: username, }) if err != nil { @@ -204,7 +205,6 @@ func loginHandler() common.Handler { return nil } - return &common.HTTPError{ Message: "Invalid credentials!", StatusCode: http.StatusUnauthorized,