Skip to content
Open
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
4 changes: 4 additions & 0 deletions backend/middleware/loggin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"socialpredict/models"
"socialpredict/security"
"socialpredict/util"
"strings"
"time"

"github.com/golang-jwt/jwt/v4"
Expand Down Expand Up @@ -47,6 +48,9 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
return
}

// Trim whitespace from username before validation
req.Username = strings.TrimSpace(req.Username)

// Validate and sanitize login input
if err := securityService.Validator.ValidateStruct(req); err != nil {
http.Error(w, "Invalid input: "+err.Error(), http.StatusBadRequest)
Expand Down
61 changes: 61 additions & 0 deletions backend/middleware/middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"socialpredict/models"
"socialpredict/models/modelstesting"
"socialpredict/util"
"testing"
"time"

Expand Down Expand Up @@ -235,6 +236,11 @@ func TestLoginHandler_ValidationFailure(t *testing.T) {
username: "Test@User",
password: "password123",
},
{
name: "Username with only whitespace",
username: " ",
password: "password123",
},
}

for _, tt := range tests {
Expand All @@ -257,6 +263,61 @@ func TestLoginHandler_ValidationFailure(t *testing.T) {
}
}

func TestLoginHandler_TrimsUsernameWhitespace(t *testing.T) {
db := modelstesting.NewFakeDB(t)
util.DB = db

testUser := modelstesting.GenerateUser("testuser", 1000)
if err := testUser.HashPassword("password123"); err != nil {
t.Fatalf("Failed to hash password: %v", err)
}
if err := db.Create(&testUser).Error; err != nil {
t.Fatalf("Failed to create test user: %v", err)
}

// Test that usernames with leading/trailing spaces are trimmed before DB lookup
tests := []struct {
name string
username string
password string
}{
{
name: "Username with leading space",
username: " testuser",
password: "password123",
},
{
name: "Username with trailing space",
username: "testuser ",
password: "password123",
},
{
name: "Username with both leading and trailing spaces",
username: " testuser ",
password: "password123",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
loginReq := map[string]string{
"username": tt.username,
"password": tt.password,
}
jsonData, _ := json.Marshal(loginReq)

req := httptest.NewRequest(http.MethodPost, "/login", bytes.NewBuffer(jsonData))
w := httptest.NewRecorder()

LoginHandler(w, req)

if w.Code != http.StatusOK {
t.Errorf("Usernames should be trimmed before DB lookup. Expected status code %d, got %d (body: %s)", http.StatusOK, w.Code, w.Body.String())
}
})
}
}

func TestValidateTokenAndGetUser_MissingHeader(t *testing.T) {
db := modelstesting.NewFakeDB(t)

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/modals/login/LoginModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const LoginModal = ({ isOpen, onClose, onLogin, redirectAfterLogin }) => {
setError('');

try {
const loginSuccess = await onLogin(username, password);
const loginSuccess = await onLogin(username.trim(), password);
if (loginSuccess) {
onClose();
history.push(redirectAfterLogin);
Expand Down