Skip to content

Commit 3f1f75e

Browse files
Merge branch 'main' into feat/tracker-glassmorphism-ui
2 parents 7095620 + f212191 commit 3f1f75e

42 files changed

Lines changed: 4340 additions & 638 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

SECURITY.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# 🔒 Security Policy
2+
3+
Thank you for helping keep **GitHub Tracker** and its community safe.
4+
5+
We take security vulnerabilities seriously and appreciate responsible disclosure from contributors, users, and security researchers.
6+
7+
Please report security issues responsibly and avoid public disclosure until the issue has been resolved.
8+
9+
---
10+
11+
# 📌 Supported Versions
12+
13+
The following table outlines the versions of the project currently receiving security updates and maintenance support.
14+
15+
| Version | Supported |
16+
| ------- | --------- |
17+
| Current development version ||
18+
| Older versions ||
19+
20+
We recommend always using the latest version of the project to benefit from recent security fixes and improvements.
21+
22+
---
23+
24+
# 🚨 Reporting a Vulnerability
25+
26+
If you discover a security vulnerability within this project, please report it responsibly.
27+
28+
## Please Do NOT
29+
30+
- Open a public GitHub issue for security vulnerabilities
31+
- Publicly disclose the vulnerability before it has been reviewed
32+
- Share exploit details publicly without prior coordination
33+
34+
---
35+
36+
# 📬 How to Report
37+
38+
Please report vulnerabilities by contacting the maintainers through one of the following methods:
39+
40+
- Open a private GitHub Security Advisory (if enabled)
41+
- Contact repository maintainers through GitHub Discussions or direct GitHub communication
42+
- Provide detailed reproduction steps and supporting information
43+
44+
When submitting a report, please include:
45+
46+
- Description of the vulnerability
47+
- Steps to reproduce the issue
48+
- Potential impact
49+
- Screenshots or proof-of-concept (if applicable)
50+
- Suggested fixes or mitigation ideas (optional)
51+
52+
---
53+
54+
# 🔍 What to Expect
55+
56+
After a vulnerability report is submitted:
57+
58+
1. The maintainers will review the report
59+
2. The issue will be validated and assessed
60+
3. A fix or mitigation strategy will be prepared
61+
4. Security patches may be released if necessary
62+
5. Responsible disclosure coordination will be followed before public release
63+
64+
We aim to acknowledge valid security reports within a reasonable timeframe.
65+
66+
---
67+
68+
# 🛡 Responsible Disclosure Guidelines
69+
70+
To help protect users and contributors, we request that you:
71+
72+
- Act in good faith
73+
- Avoid accessing or modifying data that does not belong to you
74+
- Avoid disrupting repository services or workflows
75+
- Provide sufficient details for reproduction
76+
- Allow maintainers reasonable time to investigate and resolve issues
77+
78+
---
79+
80+
# 🔐 Security Best Practices for Contributors
81+
82+
Contributors are encouraged to follow secure development practices:
83+
84+
- Keep dependencies updated
85+
- Avoid committing secrets or API keys
86+
- Validate and sanitize user input
87+
- Follow secure authentication practices
88+
- Review dependencies for known vulnerabilities
89+
90+
---
91+
92+
# 📦 Dependency Security
93+
94+
This project uses modern JavaScript and Node.js tooling including:
95+
96+
- React + Vite
97+
- Node.js + Express
98+
- TailwindCSS
99+
- Axios
100+
- MongoDB / Mongoose
101+
102+
Contributors should regularly audit dependencies using:
103+
104+
```bash
105+
npm audit
106+
```
107+
108+
To automatically fix non-breaking vulnerabilities:
109+
110+
```bash
111+
npm audit fix
112+
```
113+
114+
---
115+
116+
# 🤝 Security Acknowledgements
117+
118+
We appreciate responsible security disclosures and value the efforts of contributors helping improve the security and reliability of this project.
119+
120+
Thank you for helping make **GitHub Tracker** safer for everyone. 🚀

backend/.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Server
2+
PORT=5000
3+
NODE_ENV=development
4+
5+
# MongoDB
6+
MONGO_URI=mongodb://127.0.0.1:27017/github_tracker
7+
8+
# Session
9+
SESSION_SECRET=your_session_secret_here
10+
11+
# CORS — comma-separated list of allowed frontend origins
12+
# In production, set this to your actual frontend URL(s).
13+
# If not set, defaults to http://localhost:5173
14+
ALLOWED_ORIGINS=http://localhost:5173

backend/config/passportConfig.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ passport.use(
77
{ usernameField: "email" },
88
async (email, password, done) => {
99
try {
10-
const user = await User.findOne( {email} );
10+
const user = await User.findOne( {email} ).select("+password");;
1111
if (!user) {
1212
return done(null, false, { message: 'Email is invalid '});
1313
}
@@ -20,7 +20,8 @@ passport.use(
2020
return done(null, {
2121
id : user._id.toString(),
2222
username: user.username,
23-
email: user.email
23+
email: user.email,
24+
token: user.token
2425
});
2526
} catch (err) {
2627
return done(err);
@@ -38,7 +39,10 @@ passport.serializeUser((user, done) => {
3839
passport.deserializeUser(async (id, done) => {
3940
try {
4041
const user = await User.findById(id);
41-
done(null, user);
42+
if (!user) {
43+
return done(null, false);
44+
}
45+
done(null,user);
4246
} catch (err) {
4347
done(err, null);
4448
}

backend/models/User.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ const UserSchema = new mongoose.Schema({
1616
type: String,
1717
required: true,
1818
},
19+
token: {
20+
type: String,
21+
unique: true,
22+
sparse: true,
23+
},
1924
});
2025

2126
// ✅ FIXED: no next()
22-
UserSchema.pre('save', async function () {
23-
if (!this.isModified('password')) return;
27+
UserSchema.pre("save", async function () {
28+
if (!this.isModified("password")) return;
2429

2530
const salt = await bcrypt.genSalt(10);
2631
this.password = await bcrypt.hash(this.password, salt);
@@ -31,4 +36,5 @@ UserSchema.methods.comparePassword = async function (enteredPassword) {
3136
return bcrypt.compare(enteredPassword, this.password);
3237
};
3338

34-
module.exports = mongoose.model("User", UserSchema);
39+
module.exports = mongoose.model("User", UserSchema);
40+

backend/routes/auth.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,24 @@ router.post("/login", validateRequest(loginSchema), passport.authenticate('local
3535
res.status(200).json( { message: 'Login successful', user: req.user } );
3636
});
3737

38+
// Save GitHub token route
39+
router.post("/token", async (req, res) => {
40+
if (!req.isAuthenticated()) {
41+
return res.status(401).json({ message: 'Not authenticated' });
42+
}
43+
const { token } = req.body;
44+
if (!token) {
45+
return res.status(400).json({ message: 'Token is required' });
46+
}
47+
try {
48+
await User.findByIdAndUpdate(req.user._id, { token });
49+
req.user.token = token;
50+
res.status(200).json({ success: true, message: 'Token saved successfully' });
51+
} catch (err) {
52+
res.status(500).json({ message: 'Error saving token', error: err.message });
53+
}
54+
});
55+
3856
// Logout route
3957
router.get("/logout", (req, res) => {
4058

backend/server.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,19 @@ const logger = require('./logger');
1313

1414
const app = express();
1515

16-
// CORS configuration
17-
const allowedOrigins = ['http://localhost:5173', 'https://github-spy.etlify.app'];
16+
// CORS configuration — allowed origins are read from the ALLOWED_ORIGINS env var
17+
// (comma-separated). Falls back to localhost for local development.
18+
const parsedOrigins = process.env.ALLOWED_ORIGINS
19+
? process.env.ALLOWED_ORIGINS.split(',').map(origin => origin.trim()).filter(Boolean)
20+
: [];
21+
const allowedOrigins = parsedOrigins.length > 0 ? parsedOrigins : ['http://localhost:5173'];
22+
1823
app.use(cors({
1924
origin: function (origin, callback) {
25+
// Allow requests with no origin (e.g. server-to-server, curl, mobile apps)
2026
if (!origin || allowedOrigins.indexOf(origin) !== -1) {
2127
callback(null, true);
22-
} else{
28+
} else {
2329
callback(new Error('Blocked by CORS policy'));
2430
}
2531
},

backend/validators/authValidator.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ const signupSchema = z.object({
66
.min(3, "Username must be at least 3 characters long")
77
.max(30, "Username must be at most 30 characters long")
88
.regex(/^[a-zA-Z0-9_]+$/, "Username can only contain letters, numbers, and underscores")
9-
,
10-
9+
,
10+
1111
email: z.string()
1212
.trim()
1313
.toLowerCase()
@@ -18,7 +18,7 @@ const signupSchema = z.object({
1818
.min(8, "Password must be at least 8 characters long")
1919
.max(100, "Password must be at most 100 characters long")
2020
.regex(
21-
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/,
21+
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}+$/,
2222
'Password must contain uppercase, lowercase, number, and special character'
2323
),
2424
});

0 commit comments

Comments
 (0)