Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
71 changes: 62 additions & 9 deletions internal/controllers/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,78 +4,122 @@ 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, "<h1>Internal Server Error</h1>", http.StatusInternalServerError)
return
}

files, err = database.GetAllFiles(db)
if err != nil {
fmt.Println("[!] Error fetching all files from the database")
http.Error(w, "<h1>Internal Server Error</h1>", 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, "<h1>Internal Server Error</h1>", http.StatusInternalServerError)
return
}
}



type UploadPageData struct {
Message string
}

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, "<h1>Internal Server Error</h1>", 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")
return
}
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
Expand All @@ -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")
}
Expand Down
2 changes: 1 addition & 1 deletion internal/controllers/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
18 changes: 10 additions & 8 deletions internal/controllers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, "<h1>There was an unexpected error on the server</h1>", 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, "<h1>Failed to authenticate</h1>", http.StatusUnauthorized)
return
}

Expand Down
2 changes: 1 addition & 1 deletion internal/database/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
7 changes: 7 additions & 0 deletions internal/database/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 1 addition & 15 deletions internal/middleware/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions internal/views/files.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
{{ range .Files }}
<tr>
<td>{{ .Name }}</td>
<td>{{ .Author }}</td>
<td>{{ .CreatedAt }}</td>
<td>{{ .Author.Username }}</td>
<td>{{ .CreatedAt | formatDate }}</td>
<td>
<a class="btn btn-primary btn-sm" href="/files/{{ .ID }}" download>
Download
Expand Down