diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 907a3fb..4548776 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -3,15 +3,22 @@ package auth import ( "time" "os" + "net/http" "github.com/golang-jwt/jwt/v5" ) + +type contextKey string +const UserContextKey = contextKey("user") + + type Claims struct { Username string `json:"username"` jwt.RegisteredClaims } + func CreateToken(username string, expiration time.Time) string { var signedToken string var err error @@ -30,3 +37,18 @@ func CreateToken(username string, expiration time.Time) string { return signedToken } + + +func GetUser(r *http.Request) *Claims { + var ( + claims *Claims + ok bool + ) + + claims, ok = r.Context().Value(UserContextKey).(*Claims) + if !ok { + return nil + } + + return claims +} diff --git a/internal/controllers/files.go b/internal/controllers/files.go index 759376f..d43ad47 100644 --- a/internal/controllers/files.go +++ b/internal/controllers/files.go @@ -4,48 +4,69 @@ import ( "fmt" "os" "io" + "time" "net/http" "html/template" "path/filepath" "mime/multipart" "github.com/jean0t/EurekaFile/internal/database" + "github.com/jean0t/EurekaFile/internal/auth" "gorm.io/gorm" ) const basePath string = "internal/views" -var templ = template.Must(template.ParseFiles( +func formatDate(t time.Time) string { + return t.Format("02 Jan 2006 15:04") +} + +var templ = template.Must(template.New("").Funcs(template.FuncMap{ + "formatDate": formatDate, +}).ParseFiles( filepath.Join(basePath, "files.tmpl"), filepath.Join(basePath, "upload.tmpl"), filepath.Join(basePath, "navbar.tmpl"), )) +type FilesViewData struct { + Files []database.File +} + func Files(w http.ResponseWriter, r *http.Request) { var ( err error db *gorm.DB files []database.File + data FilesViewData ) db, err = database.ConnectToDB() if err != nil { fmt.Println("[!] Error connecting to database") + http.Error(w, "

Internal Server Error

", http.StatusInternalServerError) + return } files, err = database.GetAllFiles(db) if err != nil { fmt.Println("[!] Error fetching all files from the database") + http.Error(w, "

Internal Server Error

", http.StatusInternalServerError) + return } - err = templ.ExecuteTemplate(w, "Files", files) + data = FilesViewData{Files: files} + err = templ.ExecuteTemplate(w, "Files", data) if err != nil { fmt.Println("[!] Error executing template for /files") + http.Error(w, "

Internal Server Error

", http.StatusInternalServerError) + return } } + type UploadPageData struct { Message string } @@ -53,21 +74,44 @@ type UploadPageData struct { func Upload(w http.ResponseWriter, r *http.Request) { var ( err error - file multipart.File - handler *multipart.FileHeader - saveDir string - destination string - destinationFile *os.File uploadPageData UploadPageData = UploadPageData{Message: ""} ) if r.Method == http.MethodPost { + var ( + file multipart.File + handler *multipart.FileHeader + saveDir string = "./uploaded_files" + destination string + destinationFile *os.File + + db *gorm.DB + user database.User + claims *auth.Claims = auth.GetUser(r) + ) + + db, err = database.ConnectToDB() + if err != nil { + fmt.Println("[!] Error connecting to database") + http.Error(w, "

Internal Server Error

", http.StatusInternalServerError) + return + } + + user, err = database.QueryUser(db, claims.Username) + if err != nil { + fmt.Println("[!] Failed to query the user, can't save file to database") + templ.ExecuteTemplate(w, "Upload", uploadPageData) + return + } + + err = r.ParseMultipartForm(5 << 20) // 5MB if err != nil { fmt.Println("[!] Parse Multipart gave an error") return } + file, handler, err = r.FormFile("file") if err != nil { fmt.Println("[!] Error parsing the uploaded file") @@ -75,7 +119,7 @@ func Upload(w http.ResponseWriter, r *http.Request) { } defer file.Close() - saveDir = "./uploaded_files" + if err = os.MkdirAll(saveDir, os.ModePerm); err != nil { http.Error(w, "Unable to create save directory: "+err.Error(), http.StatusInternalServerError) return @@ -90,17 +134,26 @@ func Upload(w http.ResponseWriter, r *http.Request) { } defer destinationFile.Close() + if _, err = io.Copy(destinationFile, file); err != nil { fmt.Println("[!] Error coping file data to server") return } + + if err = database.RegisterFile(db, user, handler.Filename); err != nil { + fmt.Println("[!] Error registering file data to database") + uploadPageData.Message = "File Upload Failed" + templ.ExecuteTemplate(w, "Upload", uploadPageData) + return + } + uploadPageData.Message = "File Uploaded Successfully" templ.ExecuteTemplate(w, "Upload", uploadPageData) return } - templ.ExecuteTemplate(w, "Upload", uploadPageData) + err = templ.ExecuteTemplate(w, "Upload", uploadPageData) if err != nil { fmt.Println("[!] Error executing template for /upload") } diff --git a/internal/controllers/index.go b/internal/controllers/index.go index c16ad42..f0f26f9 100644 --- a/internal/controllers/index.go +++ b/internal/controllers/index.go @@ -11,5 +11,5 @@ func Index(w http.ResponseWriter, r *http.Request) { filepath.Join("internal", "views", "login.tmpl"), )) - templ.ExecuteTemplate(w, "Login", nil) + _ = templ.ExecuteTemplate(w, "Login", nil) } diff --git a/internal/controllers/user.go b/internal/controllers/user.go index 4a247c2..e338bad 100644 --- a/internal/controllers/user.go +++ b/internal/controllers/user.go @@ -18,22 +18,24 @@ func Login(w http.ResponseWriter, r *http.Request) { var password string = strings.TrimSpace(r.FormValue("password")) var db *gorm.DB - if username == "" || password == "" { - http.Redirect(w, r, "/", http.StatusUnauthorized) - return - } - db, err= database.ConnectToDB() + if len(strings.Split(username, "")) < 3 || len(strings.Split(password, "")) < 3 { + http.Redirect(w, r, "/", http.StatusUnauthorized) + return + } + + + db, err = database.ConnectToDB() if err != nil { - fmt.Println("Error connecting to DB") - http.Redirect(w, r, "/", http.StatusUnauthorized) + fmt.Println("[!] Error connecting to DB") + http.Error(w, "

There was an unexpected error on the server

", http.StatusInternalServerError) return } err = database.IsValidUser(db, username, password) if err != nil { fmt.Println("Error validating user") - http.Redirect(w, r, "/", http.StatusUnauthorized) + http.Error(w, "

Failed to authenticate

", http.StatusUnauthorized) return } diff --git a/internal/database/files.go b/internal/database/files.go index 3e80e84..abf9fd2 100644 --- a/internal/database/files.go +++ b/internal/database/files.go @@ -10,7 +10,7 @@ func GetAllFiles(db *gorm.DB) ([]File, error) { err error ) - err = db.Find(&files).Error + err = db.Preload("Author").Find(&files).Error if err != nil { return []File{}, err } diff --git a/internal/database/user.go b/internal/database/user.go index 97c3814..85180ed 100644 --- a/internal/database/user.go +++ b/internal/database/user.go @@ -23,6 +23,13 @@ func RegisterUser(db *gorm.DB, username, password string) error { } +func QueryUser(db *gorm.DB, username string) (User, error) { + var user User + + var result = db.Where("username = ?", username).First(&user) + return user, result.Error +} + func IsValidUser(db *gorm.DB, username, password string) error { var user User var passwordHashed string = HashPassword(password) diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go index 8b16fb4..438bae5 100644 --- a/internal/middleware/auth.go +++ b/internal/middleware/auth.go @@ -6,13 +6,9 @@ import ( "context" "github.com/jean0t/EurekaFile/internal/auth" - "github.com/golang-jwt/jwt/v5" ) -type contextKey string - -const userContextKey = contextKey("user") func WithAuth(next http.Handler) http.Handler { var jwtKey []byte = []byte(os.Getenv("JWT_SECRET")) @@ -41,17 +37,7 @@ func WithAuth(next http.Handler) http.Handler { return } - var ctx context.Context = context.WithValue(r.Context(), userContextKey, claims) + var ctx context.Context = context.WithValue(r.Context(), auth.UserContextKey, claims) next.ServeHTTP(w, r.WithContext(ctx)) }) } - - -func GetUser(r *http.Request) *auth.Claims { - claims, ok := r.Context().Value(userContextKey).(*auth.Claims) - if !ok { - return nil - } - - return claims -} diff --git a/internal/views/files.tmpl b/internal/views/files.tmpl index 4b037cd..b8bbcda 100644 --- a/internal/views/files.tmpl +++ b/internal/views/files.tmpl @@ -33,8 +33,8 @@ {{ range .Files }} {{ .Name }} - {{ .Author }} - {{ .CreatedAt }} + {{ .Author.Username }} + {{ .CreatedAt | formatDate }} Download