mirror of
https://github.com/gmemstr/pogo.git
synced 2024-09-20 01:31:09 +01:00
ba9c7c7a5d
Aha! Screw you JSON headaches! I have banished thee to the realm of impossibility, and turn to the promised land of SQLite3, where the sky is blue and the grass long. ...or something. Rewrite AddUser() to insert into database, frontend soon.
257 lines
6.2 KiB
Go
257 lines
6.2 KiB
Go
package router
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"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"
|
|
)
|
|
|
|
type NewConfig struct {
|
|
Name string
|
|
Host string
|
|
Email string
|
|
Description string
|
|
Image string
|
|
PodcastURL string
|
|
}
|
|
|
|
// Handle takes multiple Handler and executes them in a serial order starting from first to last.
|
|
// In case, Any middle ware returns an error, The error is logged to console and sent to the user, Middlewares further up in chain are not executed.
|
|
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
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func Init() *mux.Router {
|
|
|
|
r := mux.NewRouter()
|
|
|
|
// "Static" paths
|
|
r.PathPrefix("/assets/").Handler(http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/web/static"))))
|
|
r.PathPrefix("/download/").Handler(http.StripPrefix("/download/", http.FileServer(http.Dir("podcasts"))))
|
|
|
|
// Paths that require specific handlers
|
|
r.Handle("/", Handle(
|
|
rootHandler(),
|
|
)).Methods("GET")
|
|
|
|
r.Handle("/rss", Handle(
|
|
rootHandler(),
|
|
)).Methods("GET")
|
|
|
|
r.Handle("/json", Handle(
|
|
rootHandler(),
|
|
)).Methods("GET")
|
|
|
|
// Authenticated endpoints should be passed to BasicAuth()
|
|
// first
|
|
r.Handle("/admin", Handle(
|
|
auth.RequireAuthorization(),
|
|
adminHandler(),
|
|
)).Methods("GET", "POST")
|
|
|
|
r.Handle("/login", Handle(
|
|
loginHandler(),
|
|
)).Methods("GET", "POST")
|
|
|
|
r.Handle("/admin/publish", Handle(
|
|
auth.RequireAuthorization(),
|
|
admin.CreateEpisode(),
|
|
)).Methods("POST")
|
|
|
|
r.Handle("/admin/newuser", Handle(
|
|
auth.RequireAuthorization(),
|
|
admin.AddUser(),
|
|
)).Methods("POST")
|
|
|
|
r.Handle("/admin/edit", Handle(
|
|
auth.RequireAuthorization(),
|
|
admin.EditEpisode(),
|
|
)).Methods("POST")
|
|
|
|
r.Handle("/admin/delete", Handle(
|
|
auth.RequireAuthorization(),
|
|
admin.RemoveEpisode(),
|
|
)).Methods("GET")
|
|
|
|
r.Handle("/admin/css", Handle(
|
|
auth.RequireAuthorization(),
|
|
admin.CustomCss(),
|
|
)).Methods("GET", "POST")
|
|
|
|
r.Handle("/setup", Handle(
|
|
serveSetup(),
|
|
)).Methods("GET", "POST")
|
|
|
|
return r
|
|
}
|
|
|
|
func loginHandler() common.Handler {
|
|
return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError {
|
|
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
|
|
}
|
|
|
|
if r.Method == "GET" {
|
|
w.Header().Set("Content-Type", "text/html")
|
|
return common.ReadAndServeFile("assets/web/login.html", w)
|
|
}
|
|
|
|
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 == "" {
|
|
return &common.HTTPError{
|
|
Message: "username or password is empty",
|
|
StatusCode: http.StatusBadRequest,
|
|
}
|
|
}
|
|
var id int
|
|
var dbun string
|
|
var dbhsh string
|
|
var dbrn string
|
|
var dbem string
|
|
for rows.Next() {
|
|
err := rows.Scan(&id,&dbun,&dbhsh,&dbrn,&dbem)
|
|
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 dbun == username && 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, "/admin", http.StatusTemporaryRedirect)
|
|
db.Close()
|
|
return nil
|
|
}
|
|
|
|
|
|
return &common.HTTPError{
|
|
Message: "Invalid credentials!",
|
|
StatusCode: http.StatusUnauthorized,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handles /, /feed and /json endpoints
|
|
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 "/rss":
|
|
w.Header().Set("Content-Type", "application/rss+xml")
|
|
file = "assets/web/feed.rss"
|
|
case "/json":
|
|
w.Header().Set("Content-Type", "application/json")
|
|
file = "assets/web/feed.json"
|
|
case "/":
|
|
w.Header().Set("Content-Type", "text/html")
|
|
file = "assets/web/index.html"
|
|
default:
|
|
return &common.HTTPError{
|
|
Message: fmt.Sprintf("%s: Not Found", r.URL.Path),
|
|
StatusCode: http.StatusNotFound,
|
|
}
|
|
}
|
|
|
|
return common.ReadAndServeFile(file, w)
|
|
}
|
|
}
|
|
|
|
func adminHandler() common.Handler {
|
|
return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError {
|
|
return common.ReadAndServeFile("assets/web/admin.html", w)
|
|
}
|
|
}
|
|
|
|
// Serve setup.html and config parameters
|
|
func serveSetup() common.Handler {
|
|
return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError {
|
|
if r.Method == "GET" {
|
|
return common.ReadAndServeFile("assets/web/setup.html", w)
|
|
}
|
|
r.ParseMultipartForm(32 << 20)
|
|
|
|
// Parse form and convert to JSON
|
|
cnf := NewConfig{
|
|
strings.Join(r.Form["podcastname"], ""), // Podcast name
|
|
strings.Join(r.Form["podcasthost"], ""), // Podcast host
|
|
strings.Join(r.Form["podcastemail"], ""), // Podcast host email
|
|
"", // Podcast image
|
|
"", // Podcast location
|
|
"", // Podcast location
|
|
}
|
|
|
|
b, err := json.Marshal(cnf)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ioutil.WriteFile("assets/config/config.json", b, 0644)
|
|
w.Write([]byte("Done"))
|
|
return nil
|
|
}
|
|
}
|