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
2 changes: 2 additions & 0 deletions backend/.env.sample
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
PORT=5000
MONGO_URI=mongodb://localhost:27017/githubTracker
SESSION_SECRET=your-secret-key
# CLIENT_URL=http://localhost:5173
CLIENT_URL=https://your-frontend-domain.com
5 changes: 3 additions & 2 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"dev": "nodemon server.js",
"start": "node server.js",
"test": "jasmine spec/**/*.spec.cjs"

},
"keywords": [],
"author": "",
Expand All @@ -15,10 +14,12 @@
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.3",
"cors": "^2.8.5",
"cors": "^2.8.6",
"dotenv": "^16.4.5",
"express": "^4.21.1",
"express-rate-limit": "^8.5.2",
"express-session": "^1.18.1",
"helmet": "^8.1.0",
"mongoose": "^8.8.2",
"passport": "^0.7.0",
"passport-local": "^1.0.0",
Expand Down
118 changes: 104 additions & 14 deletions backend/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,125 @@ const passport = require('passport');
const bodyParser = require('body-parser');
require('dotenv').config();
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

// Passport configuration
require('./config/passportConfig');

const app = express();

// CORS configuration
app.use(cors('*'));
/* =========================
Security Middleware
========================= */

// Helmet security headers
app.use(helmet());

// Rate Limiter
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 mins
max: 100,
message: 'Too many requests from this IP, please try again later.',
standardHeaders: true,
legacyHeaders: false,
});

app.use('/api', limiter);

/* =========================
CORS Configuration
========================= */

const rawAllowedOrigins =
process.env.ALLOWED_ORIGINS ||
process.env.CLIENT_URL ||
'http://localhost:5173';

const allowedOrigins = rawAllowedOrigins
.split(',')
.map(origin => origin.trim());

app.use(cors({
origin: (origin, callback) => {
// Allow server-to-server requests
if (!origin) {
return callback(null, true);
}

if (allowedOrigins.includes(origin)) {
return callback(null, true);
}

return callback(new Error('Not allowed by CORS'));
},
credentials: true,
}));

/* =========================
Body Parser
========================= */

// Middleware
app.use(bodyParser.json());

/* =========================
Session Configuration
========================= */

const sessionSecret = process.env.SESSION_SECRET;

if (!sessionSecret) {
console.warn('⚠ SESSION_SECRET is missing in .env');
}

app.use(session({
secret: process.env.SESSION_SECRET,
secret: sessionSecret || 'dev-secret',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 1000 * 60 * 60 * 24, // 1 day
},
}));

/* =========================
Passport Middleware
========================= */

app.use(passport.initialize());
app.use(passport.session());

// Routes
/* =========================
Routes
========================= */

const authRoutes = require('./routes/auth');

app.use('/api/auth', authRoutes);

// Connect to MongoDB
mongoose.connect(process.env.MONGO_URI, {}).then(() => {
console.log('Connected to MongoDB');
app.listen(process.env.PORT, () => {
console.log(`Server running on port ${process.env.PORT}`);
});
}).catch((err) => {
console.log('MongoDB connection error:', err);
});
/* =========================
MongoDB Connection
========================= */

const PORT = process.env.PORT || 5000;
const MONGO_URI =
process.env.MONGO_URI ||
'mongodb://127.0.0.1:27017/githubTracker';

if (!process.env.MONGO_URI) {
console.warn('⚠ MONGO_URI missing in .env');
}

mongoose.connect(MONGO_URI)
.then(() => {
console.log('✅ Connected to MongoDB');

app.listen(PORT, () => {
console.log(`🚀 Server running on port ${PORT}`);
});
})
.catch((err) => {
console.error('❌ MongoDB connection error:', err);
});
4 changes: 2 additions & 2 deletions src/components/Features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ const Features = () => {
{features.map((feature, index) => {
const IconComponent = feature.icon;
return (
<div key={index} className={`group h-72 w-full bg-gray-100 dark:bg-gray-800 ${feature.hoverColor} ${feature.borderColor} rounded-2xl shadow-md hover:shadow-2xl border dark:border-gray-800 transform hover:-translate-y-2 hover:scale-[1.02] transition-all duration-300 ease-linear p-6`}>
<div className={`${feature.bgColor} w-12 h-12 rounded-lg flex items-center justify-center mb-6`}>
<div key={index} className={`group h-72 w-full bg-gray-100 dark:bg-gray-800 ${feature.hoverColor} ${feature.borderColor} rounded-2xl shadow-md hover:shadow-2xl hover:shadow-blue-500/20 border dark:border-gray-800 transform hover:-translate-y-3 hover:scale-105 backdrop-blur-sm transition-all duration-300 ease-linear p-6`}>
<div className={`${feature.bgColor} w-12 h-12 rounded-lg flex items-center justify-center mb-6 transition-transform duration-300 group-hover:rotate-6 group-hover:scale-110`}>
<IconComponent className={`h-6 w-6 ${feature.iconColor}`} />
</div>
<h3 className=" text-2xl font-bold text-gray-900 dark:text-gray-100 group-hover:text-black dark:group-hover:text-white transition-colors duration-300">{feature.title}</h3>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useNavigate, Link } from "react-router-dom";
import { ThemeContext } from "../../context/ThemeContext";
import type { ThemeContextType } from "../../context/ThemeContext";

const backendUrl = import.meta.env.VITE_BACKEND_URL;
const backendUrl = import.meta.env.VITE_BACKEND_URL ?? "http://localhost:5000";

interface LoginFormData {
email: string;
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Signup/Signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { User, Mail, Lock, Eye, EyeOff } from "lucide-react";
import { ThemeContext } from "../../context/ThemeContext";
import type { ThemeContextType } from "../../context/ThemeContext";

const backendUrl = import.meta.env.VITE_BACKEND_URL;
const backendUrl = import.meta.env.VITE_BACKEND_URL ?? "http://localhost:5000";

interface SignUpFormData {
username: string;
Expand Down