Compare commits
No commits in common. "daa90869cf6a13f5d47f68b89a5bd435f0271902" and "db2bedd1d4c7ae65ce39e24020d59966e5aeb62d" have entirely different histories.
daa90869cf
...
db2bedd1d4
5 changed files with 13 additions and 55 deletions
|
|
@ -9,11 +9,4 @@ tmp/
|
||||||
.idea/
|
.idea/
|
||||||
*.log
|
*.log
|
||||||
coverage.out
|
coverage.out
|
||||||
rideaware-api
|
rideaware-api
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
.venv/
|
|
||||||
venv/
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
node_modules/
|
|
||||||
|
|
@ -29,7 +29,7 @@ Ensure you have the following installed on your system:
|
||||||
|
|
||||||
2. **Install Go Dependencies**
|
2. **Install Go Dependencies**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go mod tidy
|
go mod tidy
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -51,10 +51,8 @@ PG_USER=your_postgres_user
|
||||||
PG_PASSWORD=your_postgres_password
|
PG_PASSWORD=your_postgres_password
|
||||||
|
|
||||||
# Application Configuration
|
# Application Configuration
|
||||||
# SECRET_KEY should be a random 32+ byte string; rotate on compromise.
|
|
||||||
SECRET_KEY=your_secret_key_for_sessions
|
SECRET_KEY=your_secret_key_for_sessions
|
||||||
PORT=8080
|
PORT=8080
|
||||||
PG_SSLMODE=require # use "disable" only for local dev
|
|
||||||
|
|
||||||
# Email Configuration (Optional)
|
# Email Configuration (Optional)
|
||||||
SMTP_SERVER=your_smtp_server
|
SMTP_SERVER=your_smtp_server
|
||||||
|
|
@ -71,7 +69,7 @@ SMTP_PASSWORD=your_email_password
|
||||||
go run main.go
|
go run main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
The application will be available at [http://localhost:8080](http://localhost:8080).
|
The application will be available at http://localhost:8080.
|
||||||
|
|
||||||
#### Production Mode
|
#### Production Mode
|
||||||
|
|
||||||
|
|
@ -102,7 +100,7 @@ docker build -t rideaware-api .
|
||||||
docker run -d -p 8080:8080 --env-file .env rideaware-api
|
docker run -d -p 8080:8080 --env-file .env rideaware-api
|
||||||
```
|
```
|
||||||
|
|
||||||
The application will be available at [http://localhost:8080](http://localhost:8080).
|
The application will be available at http://localhost:8080.
|
||||||
|
|
||||||
### Example Dockerfile
|
### Example Dockerfile
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/driver/postgres"
|
"gorm.io/driver/postgres"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
@ -17,6 +16,7 @@ func InitDB() *gorm.DB {
|
||||||
user := os.Getenv("PG_USER")
|
user := os.Getenv("PG_USER")
|
||||||
password := os.Getenv("PG_PASSWORD")
|
password := os.Getenv("PG_PASSWORD")
|
||||||
|
|
||||||
|
// Try with quoted password
|
||||||
dsn := fmt.Sprintf(`host=%s port=%s user=%s password='%s' dbname=%s sslmode=disable`,
|
dsn := fmt.Sprintf(`host=%s port=%s user=%s password='%s' dbname=%s sslmode=disable`,
|
||||||
host, port, user, password, database)
|
host, port, user, password, database)
|
||||||
|
|
||||||
|
|
@ -24,19 +24,5 @@ func InitDB() *gorm.DB {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to connect to database:", err)
|
log.Fatal("Failed to connect to database:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlDB, err := db.DB()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Failed to get sql.DB from gorm:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlDB.SetMaxOpenConns(25)
|
|
||||||
sqlDB.SetMaxIdleConns(25)
|
|
||||||
sqlDB.SetConnMaxLifetime(30 * time.Minute)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Database ping failed:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
main.go
19
main.go
|
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-contrib/cors"
|
"github.com/gin-contrib/cors"
|
||||||
|
|
@ -37,22 +36,8 @@ func main() {
|
||||||
r.Use(cors.Default())
|
r.Use(cors.Default())
|
||||||
|
|
||||||
// Session middleware
|
// Session middleware
|
||||||
secret := os.Getenv("SECRET_KEY")
|
store := cookie.NewStore([]byte(os.Getenv("SECRET_KEY")))
|
||||||
if len(secret) < 32 {
|
r.Use(sessions.Sessions("session", store))
|
||||||
log.Fatal("SECRET_KEY must be at least 32 bytes")
|
|
||||||
}
|
|
||||||
|
|
||||||
authKey := []byte(secret)
|
|
||||||
encKey := []byte(secret[:32])
|
|
||||||
store := cookie.NewStore(authKey, encKey)
|
|
||||||
store.Options(sessions.Options{
|
|
||||||
Path: "/",
|
|
||||||
MaxAge: 60 * 80 * 24 * 7, // 7 days
|
|
||||||
HttpOnly: true,
|
|
||||||
Secure: os.Getenv("ENV") == "production",
|
|
||||||
SameSite: http.SameSiteLaxMode,
|
|
||||||
})
|
|
||||||
r.Use(sessions.Sessions("rideaware-session", store))
|
|
||||||
|
|
||||||
// Health check endpoint
|
// Health check endpoint
|
||||||
r.GET("/health", func(c *gin.Context) {
|
r.GET("/health", func(c *gin.Context) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package services
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"net/mail"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rideaware/rideaware-api/models"
|
"github.com/rideaware/rideaware-api/models"
|
||||||
|
|
@ -28,7 +27,7 @@ func (s *UserService) CreateUser(username, email, password string) (*models.User
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic email validation
|
// Basic email validation
|
||||||
if _, err := mail.ParseAddress(email); err != nil {
|
if !strings.Contains(email, "@") {
|
||||||
return nil, errors.New("invalid email format")
|
return nil, errors.New("invalid email format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,20 +57,17 @@ func (s *UserService) CreateUser(username, email, password string) (*models.User
|
||||||
|
|
||||||
func (s *UserService) VerifyUser(username, password string) (*models.User, error) {
|
func (s *UserService) VerifyUser(username, password string) (*models.User, error) {
|
||||||
var user models.User
|
var user models.User
|
||||||
identifier := strings.TrimSpace(username)
|
// Allow login with either username or email
|
||||||
if err := s.db.Where("username = ? OR email = ?", identifier, strings.ToLower(identifier)).First(&user).Error; err != nil {
|
if err := s.db.Where("username = ? OR email = ?", username, username).First(&user).Error; err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
log.Printf("User not found: %s", username)
|
||||||
return nil, errors.New("invalid username or password")
|
|
||||||
}
|
|
||||||
log.Printf("DB error during VerifyUser: %v", err)
|
|
||||||
return nil, errors.New("invalid username or password")
|
return nil, errors.New("invalid username or password")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.CheckPassword(password) {
|
if !user.CheckPassword(password) {
|
||||||
log.Printf("Invalid credentials")
|
log.Printf("Invalid password for user: %s", username)
|
||||||
return nil, errors.New("invalid username or password")
|
return nil, errors.New("invalid username or password")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("User login succeeded")
|
log.Printf("User verified: %s", username)
|
||||||
return &user, nil
|
return &user, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue