Merge pull request #18 from gmemstr/permissions

Permissions
This commit is contained in:
Gabriel Simmer 2017-12-01 14:20:04 -08:00 committed by GitHub
commit fc292b497e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 111 additions and 45 deletions

View file

@ -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.
*/
@ -48,7 +50,7 @@ func AddUser() common.Handler {
StatusCode: http.StatusInternalServerError,
}
}
statement, err := db.Prepare("INSERT INTO users(username,hash,realname,email) VALUES (?,?,?,?)")
statement, err := db.Prepare("INSERT INTO users(username,hash,realname,email,permissions) VALUES (?,?,?,?,?)")
if err != nil {
return &common.HTTPError{
Message: fmt.Sprintf("error preparing sqlite3 statement: %v", err),
@ -68,10 +70,11 @@ func AddUser() common.Handler {
password := strings.Join(r.Form["password"], "")
realname := strings.Join(r.Form["realname"], "")
email := strings.Join(r.Form["email"], "")
permissions := strings.Join(r.Form["permissions"], "")
hash, err := bcrypt.GenerateFromPassword([]byte(password), 4)
_, err = statement.Exec(username,hash,realname,email)
_, err = statement.Exec(username, hash, realname, email, permissions)
if err != nil {
return &common.HTTPError{
Message: fmt.Sprintf("error executing sqlite3 statement: %v", err),
@ -110,9 +113,10 @@ func EditUser() common.Handler {
newpassword := strings.Join(r.Form["newpw1"], "")
realname := strings.Join(r.Form["realname"], "")
email := strings.Join(r.Form["email"], "")
permissions := strings.Join(r.Form["permissions"], "")
pwhash, err := bcrypt.GenerateFromPassword([]byte(password), 4)
statement, err := db.Prepare("UPDATE users SET username=?, hash=?, realname=?, email=? WHERE id=?")
statement, err := db.Prepare("UPDATE users SET username=?, hash=?, realname=?, email=?, permissions=? WHERE id=?")
if err != nil {
return &common.HTTPError{
Message: fmt.Sprintf("error preparing sqlite3 statement: %v", err),
@ -145,7 +149,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 +162,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, permissions)
if err != nil {
return &common.HTTPError{
Message: fmt.Sprintf("error executing sqlite3 statement: %v", err),
@ -328,15 +332,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(),

Binary file not shown.

View file

@ -91,6 +91,12 @@ const usernew = {
<label for="password">New Password</label>
<input type="password" id="password" name="password">
<label for="permissions">Permission Level</label>
<select name="permissions">
<option value="0">Publishing only</option>
<option value="1">Publishing and Episode Management</option>
<option value="2">Publishing, Episode and User management</option>
</select>
<br /><br />
<input type="submit" class="button" value="Save"></form>
</div>
@ -205,6 +211,7 @@ const episodemanagement = {
} else {
var t = JSON.parse(items).items
for (var i = t.length - 1; i >= 0; i--) {
console.log(i)
this.items.push({
title: t[i].title,
url: t[i].url,
@ -312,10 +319,14 @@ const customcss = {
get("/admin/css", (err, css) => {
this.loading = false
if (err) {
this.error = err.toString()
if (css == "{}") {
this.css = "You aren't allowed to edit this CSS!"
} else {
this.css = css
if (err) {
this.error = err.toString()
} else {
this.css = css
}
}
})
}
@ -348,8 +359,13 @@ const app = new Vue({
function get(url,callback) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
callback(null, xmlHttp.responseText)
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
if (xmlHttp.responseText == "Unauthorized") {
callback(null, "{}")
} else {
callback(null, xmlHttp.responseText)
}
}
}
xmlHttp.open("GET", url, true);
xmlHttp.send(null);

View file

@ -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
}
}

View file

@ -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(1),
admin.EditEpisode(),
)).Methods("POST")
r.Handle("/admin/delete", Handle(
auth.RequireAuthorization(),
auth.RequireAuthorization(1),
admin.RemoveEpisode(),
)).Methods("GET")
r.Handle("/admin/css", Handle(
auth.RequireAuthorization(),
auth.RequireAuthorization(1),
admin.CustomCss(),
)).Methods("GET", "POST")
r.Handle("/admin/adduser", Handle(
auth.RequireAuthorization(),
auth.RequireAuthorization(2),
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,