This commit is contained in:
133
main.go
133
main.go
@@ -1,7 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
@@ -15,6 +17,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
_ "modernc.org/sqlite" // statt github.com/mattn/go-sqlite3
|
||||
)
|
||||
|
||||
@@ -37,14 +40,15 @@ func Enabled(k string, def bool) bool {
|
||||
}
|
||||
|
||||
var (
|
||||
username = GetENV("KT_USERNAME", "root")
|
||||
password = GetENV("KT_PASSWORD", "root")
|
||||
membername = GetENV("KT_MEMBER", "demo")
|
||||
productive = Enabled("KT_PRODUCTIVE", false)
|
||||
hasimpressum = Enabled("KT_HASIMPRESSUM", false)
|
||||
impressum = GetENV("KT_IMPRESSUM", "")
|
||||
orte = []string{}
|
||||
schiffe = []string{
|
||||
username = GetENV("KT_USERNAME", "root")
|
||||
password = GetENV("KT_PASSWORD", "root")
|
||||
membername = GetENV("KT_MEMBER", "demo")
|
||||
productive = Enabled("KT_PRODUCTIVE", false)
|
||||
hasimpressum = Enabled("KT_HASIMPRESSUM", false)
|
||||
impressum = GetENV("KT_IMPRESSUM", "")
|
||||
hashedPassword = ""
|
||||
orte = []string{}
|
||||
schiffe = []string{
|
||||
"", "100i", "125a", "135c", "Arrow", "Aurora CL", "Aurora ES", "Aurora LN", "Aurora LX", "Aurora MR",
|
||||
"Avenger Stalker", "Avenger Titan", "Avenger Titan Renegade", "Avenger Warlock",
|
||||
"Blade", "Buccaneer", "C1 Spirit", "C2 Hercules Starlifter", "M2 Hercules Starlifter", "A2 Hercules Starlifter", "C8 Pisces", "C8R Pisces Rescue",
|
||||
@@ -190,7 +194,40 @@ func reverse(s string) string {
|
||||
|
||||
func isAuthenticated(r *http.Request) bool {
|
||||
cookie, err := r.Cookie("session")
|
||||
return err == nil && cookie.Value == "authenticated"
|
||||
if err != nil {
|
||||
fmt.Println("Debug-1:", err)
|
||||
return false
|
||||
}
|
||||
// Prüfen, ob der Token im sessionStore existiert
|
||||
a, ok := sessionStore[cookie.Value]
|
||||
fmt.Println(ok, a)
|
||||
fmt.Println(sessionStore)
|
||||
return ok
|
||||
}
|
||||
|
||||
var sessionStore = make(map[string]string) // token → username
|
||||
var loginAttempts = make(map[string]int)
|
||||
var loginLastAttempt = make(map[string]time.Time)
|
||||
var loginBlockedUntil = make(map[string]time.Time)
|
||||
var loginMutex sync.Mutex
|
||||
|
||||
func hashPassword(pw string) string {
|
||||
hash, _ := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
|
||||
return string(hash)
|
||||
}
|
||||
|
||||
func checkPasswordHash(pw, hash string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(pw))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func generateSessionToken() string {
|
||||
b := make([]byte, 32)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return "" // handle error besser im echten Code
|
||||
}
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -220,6 +257,8 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
hashedPassword = hashPassword(password)
|
||||
|
||||
var pois []POI
|
||||
if err := json.Unmarshal(data, &pois); err != nil {
|
||||
panic(err)
|
||||
@@ -246,34 +285,88 @@ func main() {
|
||||
}
|
||||
|
||||
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
ip := strings.Split(r.RemoteAddr, ":")[0]
|
||||
|
||||
loginMutex.Lock()
|
||||
blockUntil, blocked := loginBlockedUntil[ip]
|
||||
if blocked && time.Now().Before(blockUntil) {
|
||||
loginMutex.Unlock()
|
||||
http.Error(w, "Zu viele Fehlversuche. Bitte versuch es später erneut.", http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
loginMutex.Unlock()
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
r.ParseForm()
|
||||
user := r.FormValue("username")
|
||||
pass := r.FormValue("password")
|
||||
if user == username && pass == password {
|
||||
|
||||
if user == username && checkPasswordHash(pass, hashedPassword) {
|
||||
token := generateSessionToken()
|
||||
|
||||
// Speichere Session
|
||||
sessionStore[token] = user
|
||||
fmt.Println("Login", token)
|
||||
|
||||
// Cookie setzen
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "session",
|
||||
Value: "authenticated",
|
||||
Path: "/",
|
||||
Name: "session",
|
||||
Value: token,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Secure: true,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
|
||||
// Erfolgreich -> Versuche zurücksetzen
|
||||
loginMutex.Lock()
|
||||
delete(loginAttempts, ip)
|
||||
delete(loginLastAttempt, ip)
|
||||
delete(loginBlockedUntil, ip)
|
||||
loginMutex.Unlock()
|
||||
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
// Fehlversuch behandeln
|
||||
loginMutex.Lock()
|
||||
loginAttempts[ip]++
|
||||
loginLastAttempt[ip] = time.Now()
|
||||
if loginAttempts[ip] >= 5 {
|
||||
loginBlockedUntil[ip] = time.Now().Add(10 * time.Minute)
|
||||
}
|
||||
loginMutex.Unlock()
|
||||
|
||||
http.Error(w, "Login fehlgeschlagen", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// GET: Login-Formular
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
w.Write([]byte(loginForm))
|
||||
})
|
||||
|
||||
http.HandleFunc("/logout", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "session",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
MaxAge: -1,
|
||||
})
|
||||
cookie, err := r.Cookie("session")
|
||||
if err == nil {
|
||||
token := cookie.Value
|
||||
fmt.Println("Logout", token)
|
||||
// Token aus dem serverseitigen Store löschen
|
||||
delete(sessionStore, token)
|
||||
|
||||
// Cookie ungültig machen
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "session",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
MaxAge: -1,
|
||||
HttpOnly: true,
|
||||
Secure: true,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
})
|
||||
|
||||
@@ -387,6 +480,7 @@ func main() {
|
||||
cacheMutex.RUnlock()
|
||||
|
||||
if validCache {
|
||||
cachedData.LoggedIn = isAuthenticated(r)
|
||||
tmpl.Execute(w, cachedData)
|
||||
return
|
||||
}
|
||||
@@ -529,7 +623,6 @@ func main() {
|
||||
OffeneSumme: offeneSumme,
|
||||
Abteilungen: abteilungen,
|
||||
Monatsstatistik: monatsStat,
|
||||
LoggedIn: isAuthenticated(r),
|
||||
Member: membername,
|
||||
HasImpressum: hasimpressum,
|
||||
Impressum: impressum,
|
||||
|
Reference in New Issue
Block a user