Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

first commit #321

Closed
wants to merge 2 commits into from
Closed
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
5 changes: 0 additions & 5 deletions .env

This file was deleted.

9 changes: 0 additions & 9 deletions .github/CODEOWNERS

This file was deleted.

11 changes: 0 additions & 11 deletions .github/dependabot.yml

This file was deleted.

16 changes: 3 additions & 13 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
# Node build artifacts
node_modules
npm-debug.log

# Local development
*.env
*.dev
.DS_Store
.idea

# Docker
Dockerfile
docker-compose.yml
/node_modules
/config.env
/package-lock.json
1 change: 0 additions & 1 deletion Procfile

This file was deleted.

80 changes: 80 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
const rateLimit = require("express-rate-limit");
const helmet = require("helmet");
const mongoSanitize = require("express-mongo-sanitize");
const xss = require("xss-clean");
const hpp = require("hpp");

const AppError = require("./utils/appError");
const globalErrorHandler = require("./controllers/errorController");
var usersRouter = require("./routes/users");
var coursesRouter = require("./routes/courses");
var materialsRouter = require("./routes/materials");

var app = express();

app.use(helmet()); //set security HTTP headers

//limit requests from same api
const limiter = rateLimit({
max: 100,
windowMs: 60 * 60 * 1000,
message: "Too many requests from this IP, please try again in an hour.",
});
app.use("/login", limiter);

// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jade");

app.use(logger("dev"));
app.use(express.json());

//Data sanitization against NoSQL query injection
app.use(mongoSanitize());

// Data sanitization against XSS
app.use(xss());

// privent parameter poullution
// app.use(hpp({
// whitelist: []
// }));

app.use(express.urlencoded({ extended: false }));

app.use(cookieParser());

app.use(express.static(path.join(__dirname, "public")));

app.use("/users", usersRouter);
app.use("/courses", coursesRouter);
app.use("/materials", materialsRouter);

app.all("*", (req, res, next) => {
next(new AppError(`Can't find ${req.originalUrl} on this server!`, 404));
});

app.use(globalErrorHandler);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};

// render the error page
res.status(err.status || 500);
res.render("error");
});

module.exports = app;
8 changes: 0 additions & 8 deletions app.json

This file was deleted.

197 changes: 197 additions & 0 deletions controllers/authController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
const { promisify } = require("util");
const User = require("../models/userModel");
const catchAsync = require("../utils/catchAsync");
const jwt = require("jsonwebtoken");
const AppError = require("../utils/appError");
const sendEmail = require("../utils/email");
const crypto = require("crypto");

const signToken = (id) => {
return jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN,
});
};

const createSendToken = (user, statusCode, res) => {
const token = signToken(user._id);
const cookiesOptions = {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES_IN * 24 * 60 * 60 * 1000
),
httpOnly: true, // this means cookies can not be access or modified in any way by the browser
};

if (process.env.NODE_ENV === "production") cookiesOptions.secure = true; // this means cookies will be sent only on HTTPs
res.cookie("jwt", token, cookiesOptions);

user.password = undefined;

res.status(statusCode).json({
status: "success",
token,
data: {
user,
},
});
};

exports.signup = catchAsync(async (req, res, next) => {
const newUser = await User.create({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: req.body.password,
passwordConfirm: req.body.passwordConfirm,
role: req.body.role,
});
createSendToken(newUser, 201, res);
});

exports.login = catchAsync(async (req, res, next) => {
const { email, password } = req.body;

if (!email || !password) {
return next(new AppError("Please provide email and password", 400));
}

const user = await User.findOne({ email }).select("+password");

if (!user || !(await user.correctPassword(password, user.password))) {
return next(new AppError("Incorrect email or password", 401));
}

createSendToken(user, 200, res);
});

exports.protect = catchAsync(async (req, res, next) => {
//1) Getting the token and checking if its there
let token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith("Bearer")
) {
token = req.headers.authorization.split(" ")[1];
}

if (!token) {
return next(
new AppError("You are not logged in! Please log in to get access.", 401)
);
}
// 2)verification token
const decoded = await promisify(jwt.verify)(token, process.env.JWT_SECRET); // here we uesd promisify to convert function to return promise

// 3) Check if the user still exists
const currentUser = await User.findById(decoded.id);
if (!currentUser) {
return next(
new AppError("The user belongs to this token dose no longer exist.", 401)
);
}

//4) Check if the user changed password after the token was issued
if (currentUser.changedPasswordAfter(decoded.iat)) {
return next(
new AppError("User recently changed password! Please log in again", 401)
);
}

req.user = currentUser;
next();
});

exports.restrictTo = (role) => {
return (req, res, next) => {
if (role != req.user.role) {
return next(
new AppError("you don't have permission to perform this action", 403)
);
}
next();
};
};

exports.forgotPassword = catchAsync(async (req, res, next) => {
// 1) Get user based on posted email
const user = await User.findOne({ email: req.body.email });
if (!user) {
return next(new AppError("There is no user with that email address.", 404));
}

//2) Generate the random reset token
const resetToken = user.createPasswordResetToken();
await user.save({ validateBeforeSave: false });

//3) Send it to users email
const resetURL = `${req.protocol}//${req.get("host")}/api/v1/users/reset/${resetToken}`;
const message = `Forgot your Password? Submit a PATCH request with your new password and passwordConfirm to: ${resetURL}. \n If you didn't forgot your password, please ignore this email`;

try {
await sendEmail({
email: user.email,
subject: "Your passwword reset token (valid for 10 minutes)",
message,
});

return res.status(200).json({
status: "success",
message: "Token sent to email",
});
} catch (error) {
user.passwordResetToken = undefined;
user.passwordResetExpires = undefined;
await user.save({ validateBeforeSave: false });
console.log(error);
return next(
new AppError("There was an error sending an email. Try again later!", 500)
);
}
});

exports.resetPassword = catchAsync(async (req, res, next) => {
//1) Get user based on the token
const hashedToken = crypto
.createHash("sha256")
.update(req.params.token)
.digest("hex");

const user = await User.findOne({
passwordResetToken: hashedToken,
passwordResetExpires: { $gt: Date.now() },
});

//2) If token has not expired, and there is user, set the new password
if (!user) {
return next(new AppError("Token is invalid or expired", 400));
}
user.password = req.body.password;
user.passwordConfirm = req.body.passwordConfirm;
user.passwordResetToken = undefined;
user.passwordResetExpires = undefined;
await user.save();

createSendToken(user, 200, res);
});

exports.updatePassword = catchAsync(async (req, res, next) => {
// 1) Get user from the collection
const password = req.body.password;

if (!password) {
return next(new AppError("Please provide password", 400));
}

const user = await User.findById(req.user.id).select("+password");

//2) Check if POSTed current password matches
if (!(await user.correctPassword(password, user.password))) {
return next(new AppError("Incorrect password", 401));
}
//3) If so update password
user.password = req.body.newPassword;
user.passwordConfirm = req.body.passwordConfirm;

await user.save();

createSendToken(user, 200, res);
});
Loading