Skip to content
Snippets Groups Projects
Commit 7b3bdff0 authored by guoguo.yu's avatar guoguo.yu :speech_balloon:
Browse files

added distinction between admin and user, and password retrieval via mail

parent 72d6b2cf
No related branches found
No related tags found
No related merge requests found
module auth
module tp-secApp
go 1.20
......@@ -9,6 +9,7 @@ require (
)
require (
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/klauspost/compress v1.13.6 // indirect
......@@ -20,4 +21,5 @@ require (
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/text v0.7.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
)
package main
import (
"auth/models"
"tp-secApp/models"
"context"
"fmt"
"html/template"
"log"
"net/http"
"os"
"github.com/joho/godotenv"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"strconv"
"time"
"github.com/go-gomail/gomail"
)
var usersCollection *mongo.Collection
// Session represents a user session.
type Session struct {
ID string
CreationTime time.Time
}
// sessions is a map to store active sessions.
var sessions map[string]Session
func cleanupSessions(w http.ResponseWriter, r *http.Request) {
expirationDuration := 10 * time.Second
for sessionID, session := range sessions {
if time.Since(session.CreationTime) > expirationDuration {
// Session has expired, remove it
delete(sessions, sessionID)
// call the timeoutHandler
timeoutfor(w, r)
fmt.Printf("Session with ID %s has expired.\n", sessionID)
}
}
}
func timeoutfor(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Sorry, your request timed out.")
http.Redirect(w, r, "/failed-signin", http.StatusTemporaryRedirect)
}
func sendPasswordResetEmail(email, token string) error {
m := gomail.NewMessage()
//sendgrid_email := os.Getenv("SMTP_FROM_ADDRESS")
m.SetHeader("From", "notifications@mstd.dansmonorage.blue")
m.SetHeader("To", email)
m.SetHeader("Subject", "Password Reset")
m.SetBody("text/html", fmt.Sprintf(":((", token))
sendgrid := os.Getenv("SENDGRID_API_KEY")
d := gomail.NewDialer("smtp.sendgrid.net", 587, "apikey", sendgrid)
// Send the email
return d.DialAndSend(m)
}
func main() {
// Initialize the sessions map
sessions = make(map[string]Session)
// Load the .env file
godotenv.Load()
URI := os.Getenv("MONGO_URI")
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(URI))
if err != nil {
panic(err)
panic(err) //panic is a built-in function that stops the ordinary flow
// of control and begins panicking.
// When the function F calls panic, execution of F stops,
// any deferred functions in F are executed normally, and then F returns to its caller.
}
fmt.Println("Connected successfully")
usersCollection = client.Database("authentication").Collection("users")
......@@ -32,19 +83,46 @@ func main() {
http.HandleFunc("/signup", signUpHandler)
http.HandleFunc("/failed-signin", failedSignin)
http.HandleFunc("/profile", successSignin)
http.HandleFunc("/reset-password", handlePasswordReset)
log.Fatal(http.ListenAndServe(":5500", nil))
}
func handlePasswordReset(w http.ResponseWriter, r *http.Request) {
email := r.FormValue("email")
token := r.FormValue("token")
err := sendPasswordResetEmail(email, token)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, "Password reset email sent.")
}
func signUpHandler(w http.ResponseWriter, r *http.Request) {
fullName := r.FormValue("fullName")
email := r.FormValue("email")
password := r.FormValue("password")
username := r.FormValue("username")
// TODO: Add age to the database
ageStr := r.FormValue("age")
age, err := strconv.Atoi(ageStr)
bio := r.FormValue("bio")
admin := r.FormValue("admin")
if err != nil {
panic(err)
}
//age := r.FormValue("age")
user := models.User{
FullName: fullName,
Email: email,
Password: password,
Username: username,
Age: age,
Bio: bio,
Role: admin,
}
var search models.User
if usersCollection.FindOne(context.TODO(), bson.M{"username": username}).Decode(&search); search.Username == username {
......@@ -55,7 +133,7 @@ func signUpHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Email already taken")
return
}
_, err := usersCollection.InsertOne(context.TODO(), user)
_, err = usersCollection.InsertOne(context.TODO(), user)
if err != nil {
fmt.Fprintln(w, err)
return
......@@ -81,6 +159,30 @@ func successSignin(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Load the session
sessionID := r.Header.Get("Session-ID")
session, ok := sessions[sessionID]
if !ok {
// Create a new session
session = Session{
ID: time.Now().String(),
CreationTime: time.Now(),
}
sessions[session.ID] = session
}
// Create a timer for inactivity logout
timeoutDuration := 2 * time.Second // Adjust the timeout duration as needed
inactivityTimer := time.NewTimer(timeoutDuration)
go func() {
// Wait for the inactivity timer to expire
<-inactivityTimer.C
// Log the user out due to inactivity
http.Redirect(w, r, "/signin", http.StatusTemporaryRedirect)
}()
}
func signInHandler(w http.ResponseWriter, r *http.Request) {
......@@ -96,6 +198,18 @@ func signInHandler(w http.ResponseWriter, r *http.Request) {
Username: user.Username,
Fullname: user.FullName,
Email: user.Email,
Age: user.Age,
Bio: user.Bio,
Role: user.Role,
}
// Create a new session
r.Header.Add("Session-ID", time.Now().String())
session := Session{
ID: time.Now().String(),
CreationTime: time.Now(),
}
sessions[session.ID] = session
http.Redirect(w, r, "/profile", http.StatusTemporaryRedirect)
}
......@@ -4,4 +4,7 @@ type PageTemplate struct {
Username string
Email string
Fullname string
Age int
Bio string
Role string
}
......@@ -2,10 +2,20 @@ package models
import "go.mongodb.org/mongo-driver/bson/primitive"
// TODO: Instead of using string for role, use enum.
const (
Admin = "Admin"
Normal = "Normal"
)
type User struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
FullName string `bson:"fullname"`
Email string `bson:"email"`
Username string `bson:"username,omitempty,required"`
Password string `bson:"password,omitempty,required"`
Age int
Bio string
Role string
}
<!DOCTYPE html>
<html>
<head>
<title>Password Reset</title>
</head>
<body>
<h1>Password Reset</h1>
<p>If you've forgotten your password, click the link below to reset it:</p>
<!-- Password Reset Link -->
<form action="/reset-password">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<a href="/reset-password?token=your-reset-token">Reset Password</a>
</form>
</body>
</html>
\ No newline at end of file
......@@ -16,6 +16,8 @@
<input type="text" id="username" name="username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<h2>Forgot Password</h2>
<a href="forgot.html">click here</a>
<button type="submit" name="submit" id="submit">Login</button>
</form>
<p>Don't have an account? <a href="signup.html">Sign up here</a>.</p>
......
......@@ -84,6 +84,9 @@
<h2 id="fullName">{{.Fullname}}</h2>
<p id="email">{{.Email}}</p>
<p id="username">{{.Username}}</p>
<p id="age">{{.Age}}</p>
<p id="bio">{{.Bio}}</p>
<p id="admin"></p>
</div>
<p><a href="index.html">Logout</a></p>
</div>
......
......@@ -20,6 +20,12 @@
<input type="email" id="email" name="email" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<label for="age">Age:</label>
<input type="age" id="age" name="age" required>
<label for="bio">Bio:</label>
<input type="bio" id="bio" name="bio" required>
<label for="admin" id="admin" name="admin" required>Admin:</label>
<input type="checkbox" id="admin" name="admin" value="admin">
<button type="submit">Sign Up</button>
</form>
<p>Already have an account? <a href="index.html">Login here</a>.</p>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment