diff --git a/README.md b/README.md index dfa05e177..5545418c3 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # Project Auth API -Replace this readme with your own information about your project. - -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +This project was about buildig a registration form. The user should be able to sign up and then sign in with the credentials. Once signed in the user should see something that would be accessable if not logged in. This fullstack project was built in a group of three people. +We started by setting up the backend and then the frontend. ## The problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +We were having some issues with setting the frontend functionallity up since we wanted to have it pretty dry in the beginning but then in the end saw that this is making things even harder. ## View it live -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +Backend: https://project-auth-moonlight-flamingos.onrender.com +Frontend: https://project-auth-moonlight-flamingos.netlify.app/ diff --git a/backend/.gitignore b/backend/.gitignore index 25c8fdbab..16b0af9c2 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,2 +1,8 @@ node_modules -package-lock.json \ No newline at end of file +package-lock.json +.DS_Store +.env +.env.local +.env.development.local +.env.test.local +.env.production.local \ No newline at end of file diff --git a/backend/models/userSchema.js b/backend/models/userSchema.js new file mode 100644 index 000000000..417a6a3c6 --- /dev/null +++ b/backend/models/userSchema.js @@ -0,0 +1,25 @@ +import bcrypt from "bcrypt" +import mongoose from "mongoose"; + +const { Schema, model } = mongoose; +const UserSchema = new Schema({ + username: { + type: String, + required: true, + minlength: 4, + unique: true, + }, + password: { + type: String, + required: true, + minlength: 8, + }, + accessToken: { + type: String, + default: () => bcrypt.genSaltSync(), + }, +}); + +// Username, email?, encrypted password, role? + +export const User = model("User", UserSchema); diff --git a/backend/package.json b/backend/package.json index 8de5c4ce0..e6ef0e256 100644 --- a/backend/package.json +++ b/backend/package.json @@ -12,8 +12,11 @@ "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcrypt": "^5.1.1", "cors": "^2.8.5", + "dotenv": "^16.4.5", "express": "^4.17.3", + "express-list-endpoints": "^7.1.0", "mongoose": "^8.0.0", "nodemon": "^3.0.1" } diff --git a/backend/server.js b/backend/server.js index dfe86fb8e..1b1dc3b8e 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,24 +1,156 @@ +import bcrypt from "bcrypt"; import cors from "cors"; +import dotenv from "dotenv"; import express from "express"; +import expressListEndpoints from "express-list-endpoints"; import mongoose from "mongoose"; -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; +// Importing the Model +import { User } from "./models/userSchema"; + +// Getting the dotenv file +dotenv.config(); + +const mongoUrl = + process.env.MONGO_URL || "mongodb://localhost/project-authorization"; mongoose.connect(mongoUrl); mongoose.Promise = Promise; // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: // PORT=9000 npm start -const port = process.env.PORT || 8080; +const port = process.env.PORT || 8088; const app = express(); +//Middleware to Authenticate User +const authenticateUser = async (req, res, next) => { + const user = await User.findOne({ accessToken: req.header("Authorization") }); + if (user) { + req.user = user; + next(); + } else { + res.status(401).json({ loggedOut: true }); + } +}; + // Add middlewares to enable cors and json body parsing -app.use(cors()); +// Adding our frontend URL to the cors that way only that URL is allowed to make backend requests. +app.use(cors("https://project-auth-moonlight-flamingos.netlify.app/")); app.use(express.json()); -// Start defining your routes here +// API Documentation app.get("/", (req, res) => { - res.send("Hello Technigo!"); + try { + const endpoints = expressListEndpoints(app).map((endpoint) => { + if (endpoint.path === "/register") { + endpoint.query = { + description: `In this endpoint you can register a new user with a POST request. Send a username of at least four characters and a password of at least eight characters in a JSON to set up a new user.`, + }; + } + if (endpoint.path === "/login") { + endpoint.query = { + description: `In this endpoint you can login in a user with a POST request. Please send the users password and username in a JSON file to log in and acces the token for the user.`, + }; + } + if (endpoint.path === "/secrets") { + endpoint.query = { + description: `For this endpoint there is only the GET request available if you have a valid access token you will be able to see this endpoint otherwise not.`, + }; + } + return endpoint; + }); + res.status(200).json(endpoints); + } catch (err) { + console.error("The following error occured:", err); + res + .status(500) + .send( + "Sorry, this page is not available at the moment. Please try again later." + ); + } +}); + +//Sign Up Endpoint +app.post("/register", async (req, res) => { + try { + const { username, password } = req.body; + + //Check the username + if (!username) { + return res.status(400).json({ message: "Username is required" }); + } + + if (username.length < 4) { + return res + .status(400) + .json({ message: "Username must be at least 4 characters long" }); + } + + //Check the password + if (!password) { + return res.status(400).json({ message: "Password is required" }); + } + + if (password.length < 8) { + return res + .status(400) + .json({ message: "Password must be at least 8 characters long" }); + } + + //Create a User + const user = new User({ + username: username, + password: bcrypt.hashSync(password, 10), + }); + await user.save(); + res.status(201).json({ + message: "Registration Complete!", + id: user._id, + accessToken: user.accessToken, + }); + } catch (err) { + res + .status(400) + .json({ message: "Could not register user.", error: err.errors }); + } +}); + +// Login Endpoint +app.post("/login", async (req, res) => { + try { + const { username, password } = req.body; + + //Find the user by username in the Database + const user = await User.findOne({ username: username }); + + //Compare the password of the found user + if (user) { + const isPasswordCorrect = await bcrypt.compare(password, user.password); + if (isPasswordCorrect) { + res.status(202).json({ + message: "Logged in", + id: user._id, + username: user.username, + accessToken: user.accessToken, + }); + } else { + res.status(401).json({ message: "This password is incorrect." }); + } + } else { + res.status(404).json({ message: "User not found." }); + } + } catch (err) { + res.status(500).json({ + message: "Somethings wrong with the sign in. Please try again later.", + error: err.message, + }); + } +}); + +//Secrets Endpoint +app.get("/secrets", authenticateUser); +app.get("/secrets", (req, res) => { + res.status(200).json({ secret: `Super secrets... nobody will know. Well other signed in people will know I guess...` }); }); // Start the server diff --git a/frontend/README.md b/frontend/README.md deleted file mode 100644 index f768e33fc..000000000 --- a/frontend/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# React + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh diff --git a/frontend/index.html b/frontend/index.html index 0c589eccd..dcbdd6cbd 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,10 +1,15 @@ - + - + - Vite + React + + + Authentication Project
diff --git a/frontend/package.json b/frontend/package.json index e9c95b79f..f9fb3dbae 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "lottie-react": "^2.4.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/frontend/public/auth.png b/frontend/public/auth.png new file mode 100644 index 000000000..867587d49 Binary files /dev/null and b/frontend/public/auth.png differ diff --git a/frontend/public/background.png b/frontend/public/background.png new file mode 100644 index 000000000..e97a2abad Binary files /dev/null and b/frontend/public/background.png differ diff --git a/frontend/public/crypTech.svg b/frontend/public/crypTech.svg new file mode 100644 index 000000000..f1318b555 --- /dev/null +++ b/frontend/public/crypTech.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg deleted file mode 100644 index e7b8dfb1b..000000000 --- a/frontend/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 1091d4310..85949e030 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,3 +1,30 @@ +import { useState } from "react"; +import { Footer } from "./Footer"; +import { Header } from "./Header"; +import { MainSection } from "./MainSection"; + export const App = () => { - return
Find me in src/app.jsx!
; + const [formSelect, setFormSelect] = useState("Sign Up"); + const [isLoggedIn, setIsLoggedIn] = useState(false); + const [isMessage, setIsMessage] = useState(false); + + return ( + <> +
+ +