207 lines
4.4 KiB
Go
207 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
"text/template"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// Config types
|
|
// ------------
|
|
type ServerConfig struct {
|
|
Name string
|
|
Homepage string
|
|
}
|
|
type PanelConfig struct {
|
|
Host string
|
|
WebRoot string
|
|
Port int
|
|
LogPath string
|
|
}
|
|
type AuthConfig struct {
|
|
GiteaURL string
|
|
ClientID string
|
|
ClientSecret string
|
|
AuthorizedUsers []string
|
|
}
|
|
type Config struct {
|
|
Server ServerConfig
|
|
Panel PanelConfig
|
|
Auth AuthConfig
|
|
}
|
|
|
|
var config = new(Config)
|
|
var redirecturi string
|
|
var requesturl string
|
|
|
|
func loadConfig() (err error) {
|
|
configfile, err := ioutil.ReadFile("config.yml")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = yaml.Unmarshal(configfile, &config)
|
|
|
|
// todo: check for bad data !!
|
|
|
|
var re = regexp.MustCompile(`(((ftp|http|https):\/\/)|(\/)|(..\/))(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?`)
|
|
tocheck := [2]string{config.Panel.Host, config.Auth.GiteaURL}
|
|
|
|
for _, val := range tocheck {
|
|
if len(re.FindStringIndex(val)) == 0 {
|
|
log.Fatalf(`"%s" is not a valid url.`, val)
|
|
}
|
|
}
|
|
|
|
if config.Panel.Port > 65535 {
|
|
log.Fatalf("port is too big (max 65535)")
|
|
}
|
|
|
|
// init oauth bits
|
|
redirecturi = fmt.Sprintf("%s/login/endpoint", config.Panel.Host)
|
|
requesturl = fmt.Sprintf("%s/login/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&state=STATE",
|
|
strings.Trim(config.Auth.GiteaURL, " "),
|
|
strings.Trim(config.Auth.ClientID, " "),
|
|
strings.Trim(redirecturi, " "))
|
|
|
|
return err
|
|
}
|
|
|
|
func openLogFile(logfile string) {
|
|
if logfile != "" {
|
|
lf, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640)
|
|
|
|
if err != nil {
|
|
log.Fatal("OpenLogfile: os.OpenFile:", err)
|
|
}
|
|
|
|
log.SetOutput(lf)
|
|
}
|
|
}
|
|
|
|
func logRequest(handler http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL)
|
|
handler.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
func main() {
|
|
err := loadConfig()
|
|
|
|
if err != nil {
|
|
log.Fatalf("couldn't load config: %s", err)
|
|
}
|
|
|
|
openLogFile(config.Panel.LogPath)
|
|
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
|
|
|
|
http.HandleFunc("/login/", loginHandler)
|
|
http.Handle("/resources/",
|
|
http.StripPrefix("/resources/",
|
|
http.FileServer(http.Dir("./resources"))))
|
|
http.HandleFunc("/", handler)
|
|
|
|
fmt.Printf("listening on %v\n", config.Panel.Port)
|
|
fmt.Printf("Logging to %v\n", config.Panel.LogPath)
|
|
|
|
err = http.ListenAndServe(fmt.Sprintf(":%d", config.Panel.Port), logRequest(http.DefaultServeMux))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func exists(path string) (bool, error) {
|
|
_, err := os.Stat(path)
|
|
if err == nil {
|
|
return true, nil
|
|
}
|
|
if os.IsNotExist(err) {
|
|
return false, nil
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
func handler(w http.ResponseWriter, r *http.Request) {
|
|
path := r.URL.Path
|
|
loc := fmt.Sprintf("templates%s.html", path)
|
|
|
|
// var re = regexp.MustCompile(`\.(svg|jpg|jpeg|png|webp|ico|css|js)$`)
|
|
|
|
// if re.MatchString(path) {
|
|
// http.StripPrefix("/resources/",
|
|
// http.FileServer(http.Dir("./resources")))
|
|
// return
|
|
// }
|
|
|
|
var tmpl string
|
|
|
|
anonPath := regexp.MustCompile(`^/(signup|login|hello)$`)
|
|
m := anonPath.FindStringSubmatch(path)
|
|
|
|
if m != nil {
|
|
userid, err := r.Cookie("user-id")
|
|
if errors.As(err, &http.ErrNoCookie) {
|
|
http.Redirect(w, r, "/hello", http.StatusFound)
|
|
}
|
|
fmt.Print(userid)
|
|
}
|
|
|
|
switch path {
|
|
case "/":
|
|
tmpl = "templates/home.html"
|
|
t, _ := template.ParseFiles(tmpl)
|
|
t.Execute(w, config)
|
|
default:
|
|
|
|
exists, err := exists(loc)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if !exists {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
|
|
tmpl = fmt.Sprintf("templates%s.html", path)
|
|
t, _ := template.ParseFiles(tmpl)
|
|
t.Execute(w, config)
|
|
}
|
|
}
|
|
|
|
func loginHandler(w http.ResponseWriter, r *http.Request) {
|
|
userid, err := r.Cookie("user-id")
|
|
fmt.Print(userid, err)
|
|
|
|
if errors.As(err, &http.ErrNoCookie) {
|
|
useridbody := uuid.New()
|
|
expiration := time.Now().Add(365 * 24 * time.Hour)
|
|
cookie := http.Cookie{Name: "user-id", Value: useridbody.String(), Expires: expiration}
|
|
http.SetCookie(w, &cookie)
|
|
// todo: store in db
|
|
}
|
|
|
|
switch strings.TrimRight(r.URL.Path, "/") {
|
|
case "/login":
|
|
http.Redirect(w, r, requesturl, http.StatusFound)
|
|
case "/login/endpoint":
|
|
loginEndpoint(w, r)
|
|
}
|
|
}
|
|
|
|
func loginEndpoint(w http.ResponseWriter, r *http.Request) {
|
|
token := r.FormValue("code")
|
|
fmt.Print(token)
|
|
}
|