2019-02-24 08:25:39 +00:00
|
|
|
package router
|
|
|
|
|
|
|
|
import (
|
2019-07-14 04:19:28 +01:00
|
|
|
"database/sql"
|
2019-02-24 08:25:39 +00:00
|
|
|
"fmt"
|
2019-07-14 04:19:28 +01:00
|
|
|
"github.com/gmemstr/nas/auth"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
2019-02-24 08:25:39 +00:00
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"github.com/gmemstr/nas/common"
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
)
|
|
|
|
|
|
|
|
func Handle(handlers ...common.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
rc := &common.RouterContext{}
|
|
|
|
for _, handler := range handlers {
|
|
|
|
err := handler(rc, w, r)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("%v", err)
|
|
|
|
|
|
|
|
w.Write([]byte(http.StatusText(err.StatusCode)))
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Actual router, define endpoints here.
|
|
|
|
func Init() *mux.Router {
|
|
|
|
|
|
|
|
r := mux.NewRouter()
|
|
|
|
|
|
|
|
// "Static" paths
|
2020-03-22 00:18:19 +00:00
|
|
|
r.PathPrefix("/javascript/").Handler(http.StripPrefix("/javascript/", http.FileServer(http.Dir("assets/web/javascript"))))
|
|
|
|
r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", http.FileServer(http.Dir("assets/web/css"))))
|
2019-02-24 08:25:39 +00:00
|
|
|
|
|
|
|
// Paths that require specific handlers
|
|
|
|
r.Handle("/", Handle(
|
2020-03-22 00:18:19 +00:00
|
|
|
//auth.RequireAuthorization(1),
|
2019-02-24 08:25:39 +00:00
|
|
|
rootHandler(),
|
|
|
|
)).Methods("GET")
|
2019-07-14 04:19:28 +01:00
|
|
|
|
|
|
|
r.Handle(`/login`, Handle(
|
|
|
|
loginHandler(),
|
|
|
|
)).Methods("POST", "GET")
|
2019-03-03 01:41:13 +00:00
|
|
|
|
2020-02-24 18:07:47 +00:00
|
|
|
r.Handle("/api/providers", Handle(
|
2020-03-22 00:18:19 +00:00
|
|
|
//auth.RequireAuthorization(1),
|
2020-02-24 18:07:47 +00:00
|
|
|
ListProviders(),
|
2019-04-02 06:43:57 +01:00
|
|
|
)).Methods("GET")
|
2020-02-24 18:07:47 +00:00
|
|
|
|
2020-03-22 00:18:19 +00:00
|
|
|
r.Handle(`/api/files/{provider:[a-zA-Z0-9]+\/*}`, Handle(
|
2020-02-24 18:07:47 +00:00
|
|
|
//auth.RequireAuthorization(1),
|
|
|
|
HandleProvider(),
|
2019-02-24 08:25:39 +00:00
|
|
|
)).Methods("GET")
|
2019-07-28 05:43:05 +01:00
|
|
|
|
2020-02-24 18:07:47 +00:00
|
|
|
r.Handle(`/api/files/{provider}/{file:[a-zA-Z0-9=\-\/\s.,&_+]+}`, Handle(
|
|
|
|
//auth.RequireAuthorization(1),
|
|
|
|
HandleProvider(),
|
2019-03-03 01:41:13 +00:00
|
|
|
)).Methods("GET")
|
2019-02-24 08:25:39 +00:00
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2019-07-14 04:19:28 +01:00
|
|
|
|
|
|
|
func loginHandler() common.Handler {
|
|
|
|
return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError {
|
|
|
|
if r.Method == "GET" {
|
|
|
|
w.Header().Set("Content-Type", "text/html")
|
|
|
|
file := "assets/web/index.html"
|
|
|
|
|
|
|
|
return common.ReadAndServeFile(file, w)
|
|
|
|
}
|
|
|
|
db, err := sql.Open("sqlite3", "assets/config/users.db")
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return &common.HTTPError{
|
|
|
|
Message: fmt.Sprintf("error in reading user database: %v", err),
|
|
|
|
StatusCode: http.StatusInternalServerError,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
statement, err := db.Prepare("SELECT * FROM users WHERE username=?")
|
|
|
|
|
|
|
|
if _, err := auth.DecryptCookie(r); err == nil {
|
|
|
|
http.Redirect(w, r, "/admin", http.StatusTemporaryRedirect)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err = r.ParseForm()
|
|
|
|
if err != nil {
|
|
|
|
return &common.HTTPError{
|
|
|
|
Message: fmt.Sprintf("error in parsing form: %v", err),
|
|
|
|
StatusCode: http.StatusBadRequest,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
username := r.Form.Get("username")
|
|
|
|
password := r.Form.Get("password")
|
|
|
|
rows, err := statement.Query(username)
|
|
|
|
|
|
|
|
if username == "" || password == "" || err != nil {
|
|
|
|
return &common.HTTPError{
|
|
|
|
Message: "username or password is invalid",
|
|
|
|
StatusCode: http.StatusBadRequest,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var id int
|
|
|
|
var dbun string
|
|
|
|
var dbhsh string
|
2019-07-28 05:43:05 +01:00
|
|
|
var dbtoken sql.NullString
|
2019-07-14 04:19:28 +01:00
|
|
|
var dbperm int
|
|
|
|
for rows.Next() {
|
2019-07-28 05:43:05 +01:00
|
|
|
err := rows.Scan(&id, &dbun, &dbhsh, &dbtoken, &dbperm)
|
2019-07-14 04:19:28 +01:00
|
|
|
if err != nil {
|
|
|
|
return &common.HTTPError{
|
|
|
|
Message: fmt.Sprintf("error in decoding sql data", err),
|
|
|
|
StatusCode: http.StatusBadRequest,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// Create a cookie here because the credentials are correct
|
|
|
|
if bcrypt.CompareHashAndPassword([]byte(dbhsh), []byte(password)) == nil {
|
|
|
|
c, err := auth.CreateSession(&common.User{
|
|
|
|
Username: username,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return &common.HTTPError{
|
|
|
|
Message: err.Error(),
|
|
|
|
StatusCode: http.StatusInternalServerError,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// r.AddCookie(c)
|
|
|
|
w.Header().Add("Set-Cookie", c.String())
|
|
|
|
// And now redirect the user to admin page
|
|
|
|
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
|
|
|
db.Close()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &common.HTTPError{
|
|
|
|
Message: "Invalid credentials!",
|
|
|
|
StatusCode: http.StatusUnauthorized,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-24 08:25:39 +00:00
|
|
|
// Handles /.
|
|
|
|
func rootHandler() common.Handler {
|
|
|
|
return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError {
|
|
|
|
|
|
|
|
var file string
|
|
|
|
switch r.URL.Path {
|
|
|
|
case "/":
|
|
|
|
w.Header().Set("Content-Type", "text/html")
|
|
|
|
file = "assets/web/index.html"
|
2019-03-03 01:41:13 +00:00
|
|
|
|
2019-02-24 08:25:39 +00:00
|
|
|
default:
|
|
|
|
return &common.HTTPError{
|
|
|
|
Message: fmt.Sprintf("%s: Not Found", r.URL.Path),
|
|
|
|
StatusCode: http.StatusNotFound,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-03 01:41:13 +00:00
|
|
|
return common.ReadAndServeFile(file, w)
|
2019-02-24 08:25:39 +00:00
|
|
|
}
|
|
|
|
}
|