This repository has been archived on 2024-01-11. You can view files and clone it, but cannot push or open issues or pull requests.
admin/main.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)
}