forked from CSI-KJSCE/appointment_to_examiner
initial commit
This commit is contained in:
2
server/.gitignore
vendored
Normal file
2
server/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
.env
|
||||
12
server/ConnectionDb.js
Normal file
12
server/ConnectionDb.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const mongoose = require("mongoose");
|
||||
require("dotenv").config();
|
||||
exports.connectdb = () => {
|
||||
mongoose.connect(process.env.mongoURI);
|
||||
};
|
||||
|
||||
const db = mongoose.connection;
|
||||
|
||||
db.on("error", console.error.bind("Connection Error!"));
|
||||
db.once("open", function () {
|
||||
console.log("Connection Established!!!");
|
||||
});
|
||||
56
server/config/passport.js
Normal file
56
server/config/passport.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const passport = require("passport");
|
||||
const User = require("../models/User");
|
||||
require("dotenv").config();
|
||||
const GoogleStrategy = require("passport-google-oauth20").Strategy;
|
||||
|
||||
passport.use(
|
||||
new GoogleStrategy(
|
||||
{
|
||||
clientID: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
callbackURL: "http://localhost:8080/auth/google/callback",
|
||||
scope: ["profile", "email", "displayName"],
|
||||
},
|
||||
async (accessToken, refreshToken, profile, done) => {
|
||||
try {
|
||||
// Check if a user with the same email already exists
|
||||
let user = await User.findOne({ email: profile.emails[0].value });
|
||||
|
||||
if (user) {
|
||||
// If the user exists, update their Google ID and profile information
|
||||
user.googleId = profile.id;
|
||||
user.username = profile.displayName;
|
||||
user.profilePicture = profile.photos[0].value;
|
||||
await user.save();
|
||||
return done(null, user);
|
||||
} else {
|
||||
// If the user doesn't exist, create a new user
|
||||
const newUser = new User({
|
||||
googleId: profile.id,
|
||||
username: profile.displayName,
|
||||
email: profile.emails[0].value,
|
||||
profilePicture: profile.photos[0].value,
|
||||
});
|
||||
|
||||
user = await newUser.save();
|
||||
return done(null, user);
|
||||
}
|
||||
} catch (error) {
|
||||
return done(error, false);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
passport.serializeUser((user, done) => {
|
||||
done(null, user.id); // Use user id for serialization
|
||||
});
|
||||
|
||||
passport.deserializeUser(async (id, done) => {
|
||||
try {
|
||||
const user = await User.findById(id); // Fetch user by id from MongoDB
|
||||
done(null, user); // Pass the user object to the next middleware
|
||||
} catch (error) {
|
||||
done(error, false);
|
||||
}
|
||||
});
|
||||
27
server/models/User.js
Normal file
27
server/models/User.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const mongoose = require("mongoose");
|
||||
const passportLocalMongoose = require("passport-local-mongoose");
|
||||
|
||||
const UserSchema = new mongoose.Schema(
|
||||
{
|
||||
googleId: String,
|
||||
username: String,
|
||||
email: String,
|
||||
password: String,
|
||||
profilePicture: String,
|
||||
resetPasswordToken: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
resetPasswordExpires: {
|
||||
type: Date,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
UserSchema.plugin(passportLocalMongoose);
|
||||
|
||||
module.exports = mongoose.model("User", UserSchema);
|
||||
2266
server/package-lock.json
generated
Normal file
2266
server/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
server/package.json
Normal file
42
server/package.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "server",
|
||||
"version": "1.0.0",
|
||||
"description": "appointment_to_examiner",
|
||||
"main": "sever.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build" : "npm install --prefix ../client && npm run build --prefix ../client && npm install",
|
||||
"start": "nodemon server.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/hk151109/appointment_to_examiner.git"
|
||||
},
|
||||
"author": "Harikrishnan",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/hk151109/appointment_to_examiner/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "^1.20.2",
|
||||
"connect-mongo": "^5.1.0",
|
||||
"cors": "^2.8.5",
|
||||
"crypto": "^1.0.1",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
"express-session": "^1.18.0",
|
||||
"googleapis": "^134.0.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mongoose": "^8.3.1",
|
||||
"mongoose-findorcreate": "^4.0.0",
|
||||
"nodemailer": "^6.9.13",
|
||||
"passport": "^0.7.0",
|
||||
"passport-google-oauth20": "^2.0.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-local-mongoose": "^8.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.1.0"
|
||||
}
|
||||
}
|
||||
124
server/routes/authRoutes.js
Normal file
124
server/routes/authRoutes.js
Normal file
@@ -0,0 +1,124 @@
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const bcrypt = require("bcryptjs");
|
||||
const User = require("../models/User");
|
||||
const crypto = require("crypto");
|
||||
const nodemailer = require("nodemailer");
|
||||
const { google } = require("googleapis");
|
||||
require("dotenv").config();
|
||||
|
||||
// Set up Google OAuth2 credentials
|
||||
const oauth2Client = new google.auth.OAuth2(
|
||||
process.env.GOOGLE_CLIENT_ID,
|
||||
process.env.GOOGLE_CLIENT_SECRET,
|
||||
"https://developers.google.com/oauthplayground" // Redirect URI
|
||||
);
|
||||
|
||||
oauth2Client.setCredentials({
|
||||
refresh_token: process.env.GOOGLE_REFRESH_TOKEN,
|
||||
});
|
||||
|
||||
// Nodemailer transporter using Google OAuth2
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: "gmail",
|
||||
auth: {
|
||||
type: "OAuth2",
|
||||
user: process.env.EMAIL_USERNAME,
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
refreshToken: process.env.GOOGLE_REFRESH_TOKEN,
|
||||
accessToken: async () => {
|
||||
const accessToken = await getAccessToken();
|
||||
return accessToken;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Function to refresh OAuth2 token
|
||||
async function getAccessToken() {
|
||||
try {
|
||||
const { token } = await oauth2Client.getAccessToken();
|
||||
return token;
|
||||
} catch (error) {
|
||||
console.error("Error refreshing access token:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Forgot Password
|
||||
router.post("/forgot-password", async (req, res) => {
|
||||
try {
|
||||
const { email } = req.body;
|
||||
const user = await User.findOne({ email });
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: "User not found" });
|
||||
}
|
||||
|
||||
// Generate reset token
|
||||
const resetToken = crypto.randomBytes(20).toString("hex");
|
||||
user.resetPasswordToken = resetToken;
|
||||
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
||||
await user.save();
|
||||
|
||||
// Send reset email
|
||||
const mailOptions = {
|
||||
from: `"MERN Auth App" <${process.env.EMAIL_USERNAME}>`,
|
||||
to: email,
|
||||
subject: "Password Reset Verification",
|
||||
html: `
|
||||
<p>Hi there,</p>
|
||||
<br>
|
||||
<p>We received a request to reset the password for your account. To proceed with the password reset, please click on the link below:</p>
|
||||
<p>Click here : <a href="http://localhost:3000/ResetPw/${resetToken}">Reset Password</a></p>
|
||||
<br>
|
||||
<p>Please ensure you use this link within the next 1 hour as it will expire after that for security reasons.</p>
|
||||
<p>If you didn't request a password reset, please ignore this email.</p>
|
||||
|
||||
<br>
|
||||
<p>Best regards,</p>
|
||||
<p>MERN Auth App Team</p>
|
||||
`,
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, (error, info) => {
|
||||
if (error) {
|
||||
console.error("Error sending email:", error);
|
||||
return res.status(500).json({ message: "Error sending email" });
|
||||
}
|
||||
console.log("Email sent:", info.response);
|
||||
res.status(200).json({ message: "Reset password email sent" });
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Forgot password error:", error);
|
||||
res.status(500).json({ message: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Reset Password
|
||||
router.post("/reset-password", async (req, res) => {
|
||||
try {
|
||||
const { resetToken, newPassword } = req.body;
|
||||
const user = await User.findOne({
|
||||
resetPasswordToken: resetToken,
|
||||
resetPasswordExpires: { $gt: Date.now() },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res.status(400).json({ message: "Invalid or expired token" });
|
||||
}
|
||||
|
||||
// Reset password
|
||||
const hashedPassword = await bcrypt.hash(newPassword, 10);
|
||||
user.password = hashedPassword;
|
||||
user.resetPasswordToken = undefined;
|
||||
user.resetPasswordExpires = undefined;
|
||||
await user.save();
|
||||
|
||||
res.status(200).json({ message: "Password reset successful" });
|
||||
} catch (error) {
|
||||
console.error("Reset password error:", error);
|
||||
res.status(500).json({ message: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
188
server/server.js
Normal file
188
server/server.js
Normal file
@@ -0,0 +1,188 @@
|
||||
const express = require("express");
|
||||
const User = require("./models/User");
|
||||
const cors = require("cors");
|
||||
const passport = require("passport");
|
||||
const session = require("express-session");
|
||||
const bodyParser = require("body-parser");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const LocalStrategy = require("passport-local").Strategy;
|
||||
const PasswordRouter = require("./routes/authRoutes");
|
||||
const crypto = require("crypto");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const path = require("path");
|
||||
|
||||
const { connectdb } = require("./ConnectionDb");
|
||||
connectdb();
|
||||
|
||||
const app = express();
|
||||
|
||||
// Middleware
|
||||
app.use(express.json());
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
app.use(
|
||||
session({
|
||||
secret: "secret",
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
})
|
||||
);
|
||||
|
||||
app.use(passport.initialize());
|
||||
app.use(passport.session());
|
||||
|
||||
// CORS configuration
|
||||
app.use(
|
||||
cors({
|
||||
origin: "http://localhost:3000",
|
||||
credentials: true,
|
||||
})
|
||||
);
|
||||
|
||||
// Passport configuration
|
||||
require("./config/passport");
|
||||
|
||||
passport.use(
|
||||
new LocalStrategy(
|
||||
{ usernameField: "email" },
|
||||
async (email, password, done) => {
|
||||
try {
|
||||
const user = await User.findOne({ email });
|
||||
if (!user) {
|
||||
return done(null, false, { message: "Incorrect email" });
|
||||
}
|
||||
const isMatch = await bcrypt.compare(password, user.password);
|
||||
if (isMatch) {
|
||||
return done(null, user);
|
||||
} else {
|
||||
return done(null, false, { message: "Incorrect password" });
|
||||
}
|
||||
} catch (error) {
|
||||
return done(error);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
passport.serializeUser((user, done) => {
|
||||
done(null, user.id); // Store user ID in the session
|
||||
});
|
||||
|
||||
passport.deserializeUser((id, done) => {
|
||||
User.findById(id, (err, user) => {
|
||||
done(err, user);
|
||||
});
|
||||
});
|
||||
|
||||
// Routes
|
||||
app.use("/password", PasswordRouter);
|
||||
|
||||
app.get(
|
||||
"/auth/google",
|
||||
passport.authenticate("google", { scope: ["profile", "email"] })
|
||||
);
|
||||
|
||||
app.get(
|
||||
"/auth/google/callback",
|
||||
passport.authenticate("google", { failureRedirect: "/" }),
|
||||
function (req, res) {
|
||||
res.redirect("http://localhost:3000/Home");
|
||||
}
|
||||
);
|
||||
|
||||
app.post("/api/register", async (req, res) => {
|
||||
try {
|
||||
const { username, email, password } = req.body;
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
let user = await User.findOne({ email });
|
||||
|
||||
if (user) {
|
||||
if (user.googleId && user.password) {
|
||||
return res.status(400).json({ message: "User already exists" });
|
||||
}
|
||||
if (!user.googleId && user.password) {
|
||||
return res.status(400).json({ message: "User already exists" });
|
||||
}
|
||||
if (user.googleId && !user.password) {
|
||||
user.password = hashedPassword;
|
||||
await user.save();
|
||||
}
|
||||
} else {
|
||||
user = new User({ username, email, password: hashedPassword });
|
||||
await user.save();
|
||||
}
|
||||
|
||||
req.login(user, (err) => {
|
||||
if (err) {
|
||||
console.error("Error logging in user after registration:", err);
|
||||
return res.status(500).send("Internal server error");
|
||||
}
|
||||
return res.status(200).json({
|
||||
message: "Registered and logged in successfully",
|
||||
user,
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error registering user:", error);
|
||||
res.status(400).send("Registration failed");
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/login", (req, res, next) => {
|
||||
passport.authenticate("local", (err, user, info) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ message: "Internal server error" });
|
||||
}
|
||||
if (!user) {
|
||||
return res.status(401).json({ message: "Incorrect email or password" });
|
||||
}
|
||||
req.logIn(user, (err) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ message: "Internal server error" });
|
||||
}
|
||||
return res.status(200).json({ message: "Login successful", user });
|
||||
});
|
||||
})(req, res, next);
|
||||
});
|
||||
|
||||
app.get("/auth/logout", function (req, res) {
|
||||
req.logout((err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return res.status(500).json({ message: "Error logging out" });
|
||||
}
|
||||
req.session.destroy(function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return res.status(500).json({ message: "Error destroying session" });
|
||||
}
|
||||
res.json({ message: "Logout successful" });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/api/user/profile", async (req, res) => {
|
||||
try {
|
||||
if (req.user) {
|
||||
return res.json({ user: req.user });
|
||||
} else {
|
||||
return res.status(401).json({ error: "Unauthorized" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching user data:", error);
|
||||
res.status(500).json({ message: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Serve static files
|
||||
app.use(express.static(path.join(__dirname, "../client/build")));
|
||||
|
||||
// Catch-all route to serve React app
|
||||
app.get("*", (req, res) =>
|
||||
res.sendFile(path.join(__dirname, "../client/build/index.html"))
|
||||
);
|
||||
|
||||
const Port = 8080;
|
||||
app.listen(Port, () => {
|
||||
console.log(`Server is Running at port ${Port}`);
|
||||
});
|
||||
Reference in New Issue
Block a user