diff --git a/src/login.go b/src/login.go new file mode 100644 index 0000000..8a6f008 --- /dev/null +++ b/src/login.go @@ -0,0 +1,61 @@ +package main +import ( + "time" + "net/http" + "bytes" + "github.com/cornelk/hashmap" +) +type loginStruct struct { + FalsePassword bool +} +var sessions hashmap.HashMap +const sessionName string = "session" +func login(w http.ResponseWriter, r *http.Request) { + var err error + loginStruct := loginStruct{} + var login bool = false + if loggedIn(r) { + http.Redirect(w, r, "dash", http.StatusSeeOther) + return + } + if r.Method == http.MethodPost { + var username string = r.FormValue("username") + var password string = r.FormValue("password") + var hash []byte + var salt []byte + db.QueryRow("SELECT hash,salt FROM account WHERE username = ?", username).Scan(&hash, &salt) + login = bytes.Equal(hashFunc([]byte(password), salt), hash) + loginStruct.FalsePassword = !login + if login { + key, err := GenerateRandomString(64) + log(err) + cookie := http.Cookie{ + Name: sessionName, + Value: key, + Expires: time.Now().Add(10 * 24 * time.Hour), + HttpOnly: true, + Secure: true, + } + http.SetCookie(w, &cookie) + sessions.Set(key, username) + http.Redirect(w, r, "dash", http.StatusSeeOther) + } else { + w.Header().Set("Content-Type", "text/html") + err = loginTmpl.Execute(w, loginStruct) + log(err) + } + } else { + w.Header().Set("Content-Type", "text/html") + loginTmpl.Execute(w, loginStruct) + log(err) + } +} + +func loggedIn(r *http.Request) bool { + key, err := r.Cookie(sessionName) + if err != nil { + return false + } + _, valid := sessions.GetStringKey(key.Value) + return valid +} diff --git a/src/main.go b/src/main.go index ca1b3e2..1369da9 100644 --- a/src/main.go +++ b/src/main.go @@ -12,7 +12,6 @@ import ( "net/http" "os" "regexp" - "github.com/cornelk/hashmap" "code.gitea.io/sdk/gitea" "fmt" "golang.org/x/crypto/argon2" @@ -20,11 +19,11 @@ import ( var discord *discordgo.Session var secret secrets_json var config config_json -var cacheAccounts hashmap.HashMap var db *sql.DB var giteaClient *gitea.Client var registerTmpl *template.Template var submitTmpl *template.Template +var loginTmpl *template.Template type account struct { email string username string @@ -100,10 +99,13 @@ func main() { _ = moodle registerTmpl = template.Must(template.ParseFiles("tmpl/register.html")) submitTmpl = template.Must(template.ParseFiles("tmpl/submit.html")) + loginTmpl = template.Must(template.ParseFiles("tmpl/login.html")) remail = regexp2.MustCompile("^(?=.{0,255}$)(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])$", 0) rusername = regexp.MustCompile("^([[:lower:]]|\\d|_|-|\\.){1,40}$") rpassword = regexp2.MustCompile("^(?=.{8,255}$)(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\\W).*$", 0) http.HandleFunc("/register", register) + http.HandleFunc("/submit", submit) + http.HandleFunc("/login", login) http.ListenAndServe(":" + fmt.Sprint(config.Port), nil) } @@ -113,6 +115,6 @@ func log(err error) { } } -func hash(password []byte, salt []byte) []byte { +func hashFunc(password []byte, salt []byte) []byte { return argon2.IDKey(password, salt, 1, 64*1024, 4, 32) } diff --git a/src/register.go b/src/register.go index 8648ed3..8f06914 100644 --- a/src/register.go +++ b/src/register.go @@ -10,7 +10,9 @@ import ( "time" "code.gitea.io/sdk/gitea" "crypto/rand" + "github.com/cornelk/hashmap" ) +var cacheAccounts hashmap.HashMap var rusername *regexp.Regexp var remail *regexp2.Regexp var rpassword *regexp2.Regexp @@ -43,8 +45,8 @@ func register(w http.ResponseWriter, r *http.Request) { newAccount.discordId = newRbuMember.User.ID { var username string - registerstruct.AlreadyEsitsInDatabase.Username = db.QueryRow("select username from account where username = ?", newAccount.username).Scan(&username) == nil || UsernameExistsInMem(newAccount.username) // check if username exits - registerstruct.AlreadyEsitsInDatabase.DiscordUsername = db.QueryRow("select username from account where discordUserId = ?", newAccount.discordId).Scan(&username) == nil || discordUsernameExistsInMem(newAccount.discordId) + registerstruct.AlreadyEsitsInDatabase.Username = db.QueryRow("SELECT username FROM account WHERE username = ?", newAccount.username).Scan(&username) == nil || UsernameExistsInMem(newAccount.username) // check if username exits + registerstruct.AlreadyEsitsInDatabase.DiscordUsername = db.QueryRow("SELECT username FROM account WHERE discordUserId = ?", newAccount.discordId).Scan(&username) == nil || discordUsernameExistsInMem(newAccount.discordId) } registerstruct.Success = !registerstruct.WrongAccount.User && !registerstruct.WrongAccount.Pass && !registerstruct.WrongAccount.Email && !registerstruct.WrongAccount.DiscordUser && !registerstruct.AlreadyEsitsInDatabase.DiscordUsername && !registerstruct.AlreadyEsitsInDatabase.Username if !registerstruct.Success { @@ -76,7 +78,7 @@ func register(w http.ResponseWriter, r *http.Request) { salt := make([]byte, 32) _, err := rand.Read(salt) log(err) - hash := hash([]byte(account.password), salt) + hash := hashFunc([]byte(account.password), salt) // add user to the database query := "INSERT INTO account(username, email, hash, salt, discordUserId) VALUES (?, ?, ?, ?, ?)" ctx, cancelfunc := context.WithTimeout(context.Background(), 5*time.Second) diff --git a/tmpl/login.html b/tmpl/login.html new file mode 100644 index 0000000..98a6a66 --- /dev/null +++ b/tmpl/login.html @@ -0,0 +1,10 @@ +{{if .FalsePassword}} +

falches Passwort

+{{end}} +
+
+
+
+
+ +