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/
 | 
			
		||||
*.log
 | 
			
		||||
coverage.out
 | 
			
		||||
rideaware-api
 | 
			
		||||
__pycache__/
 | 
			
		||||
*.py[cod]
 | 
			
		||||
.venv/
 | 
			
		||||
venv/
 | 
			
		||||
dist/
 | 
			
		||||
build/
 | 
			
		||||
node_modules/
 | 
			
		||||
rideaware-api
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ Ensure you have the following installed on your system:
 | 
			
		|||
 | 
			
		||||
2. **Install Go Dependencies**  
 | 
			
		||||
   
 | 
			
		||||
   ```bash
 | 
			
		||||
	```bash
 | 
			
		||||
   go mod tidy
 | 
			
		||||
   ```
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -51,10 +51,8 @@ PG_USER=your_postgres_user
 | 
			
		|||
PG_PASSWORD=your_postgres_password
 | 
			
		||||
 | 
			
		||||
# Application Configuration
 | 
			
		||||
# SECRET_KEY should be a random 32+ byte string; rotate on compromise.
 | 
			
		||||
SECRET_KEY=your_secret_key_for_sessions
 | 
			
		||||
PORT=8080
 | 
			
		||||
PG_SSLMODE=require  # use "disable" only for local dev
 | 
			
		||||
 | 
			
		||||
# Email Configuration (Optional)
 | 
			
		||||
SMTP_SERVER=your_smtp_server
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +69,7 @@ SMTP_PASSWORD=your_email_password
 | 
			
		|||
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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -102,7 +100,7 @@ docker build -t 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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gorm.io/driver/postgres"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +16,7 @@ func InitDB() *gorm.DB {
 | 
			
		|||
	user := os.Getenv("PG_USER")
 | 
			
		||||
	password := os.Getenv("PG_PASSWORD")
 | 
			
		||||
 | 
			
		||||
	// Try with quoted password
 | 
			
		||||
	dsn := fmt.Sprintf(`host=%s port=%s user=%s password='%s' dbname=%s sslmode=disable`,
 | 
			
		||||
		host, port, user, password, database)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,19 +24,5 @@ func InitDB() *gorm.DB {
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								main.go
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								main.go
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -2,7 +2,6 @@ package main
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-contrib/cors"
 | 
			
		||||
| 
						 | 
				
			
			@ -37,22 +36,8 @@ func main() {
 | 
			
		|||
	r.Use(cors.Default())
 | 
			
		||||
 | 
			
		||||
	// Session middleware
 | 
			
		||||
	secret := os.Getenv("SECRET_KEY")
 | 
			
		||||
	if len(secret) < 32 {
 | 
			
		||||
		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))
 | 
			
		||||
	store := cookie.NewStore([]byte(os.Getenv("SECRET_KEY")))
 | 
			
		||||
	r.Use(sessions.Sessions("session", store))
 | 
			
		||||
 | 
			
		||||
	// Health check endpoint
 | 
			
		||||
	r.GET("/health", func(c *gin.Context) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ package services
 | 
			
		|||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/mail"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/rideaware/rideaware-api/models"
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +27,7 @@ func (s *UserService) CreateUser(username, email, password string) (*models.User
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Basic email validation
 | 
			
		||||
	if _, err := mail.ParseAddress(email); err != nil {
 | 
			
		||||
	if !strings.Contains(email, "@") {
 | 
			
		||||
		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) {
 | 
			
		||||
	var user models.User
 | 
			
		||||
	identifier := strings.TrimSpace(username)
 | 
			
		||||
	if err := s.db.Where("username = ? OR email = ?", identifier, strings.ToLower(identifier)).First(&user).Error; err != nil {
 | 
			
		||||
		if errors.Is(err, gorm.ErrRecordNotFound) {
 | 
			
		||||
			return nil, errors.New("invalid username or password")
 | 
			
		||||
		}
 | 
			
		||||
		log.Printf("DB error during VerifyUser: %v", err)
 | 
			
		||||
	// Allow login with either username or email
 | 
			
		||||
	if err := s.db.Where("username = ? OR email = ?", username, username).First(&user).Error; err != nil {
 | 
			
		||||
		log.Printf("User not found: %s", username)
 | 
			
		||||
		return nil, errors.New("invalid username or 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")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Printf("User login succeeded")
 | 
			
		||||
	log.Printf("User verified: %s", username)
 | 
			
		||||
	return &user, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue