diff --git a/Procfile b/Procfile
deleted file mode 100644
index c154cc553..000000000
--- a/Procfile
+++ /dev/null
@@ -1 +0,0 @@
-web: npm start --prefix backend
diff --git a/README.md b/README.md
index dfa05e177..d3ff50537 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,27 @@
# 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 is a user authentication system built with React, Express.js, MongoDB, bcrypt, and crypto. The application provides secure user registration, login, and access to protected routes.
## 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?
+.React: For building the frontend.
+.Express.js: For handling backend routing and API logic.
+.MongoDB: For storing user data.
+.bcrypt: For hashing passwords before storing them in the database.
+.crypto: For generating secure access tokens.
+
+If more time were available, the next steps would include implementing user roles, adding more comprehensive validation and error handling.
+
+## API Endpoints
+
+GET
+./: Basic root route for testing, returns a welcome message.
+./secrets: Access a protected route, requires a valid access token.
+
+POST
+./users: Register a new user.
+./sessions: Log in an existing user.
## 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.
+You can view the live project [here](https://doggyadopt.netlify.app/)
diff --git a/backend/.gitignore b/backend/.gitignore
index 25c8fdbab..8f5e467c8 100644
--- a/backend/.gitignore
+++ b/backend/.gitignore
@@ -1,2 +1,3 @@
node_modules
-package-lock.json
\ No newline at end of file
+package-lock.json
+.env
\ No newline at end of file
diff --git a/backend/package.json b/backend/package.json
index 8de5c4ce0..29b1eb4ef 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,5 +1,5 @@
{
- "name": "project-auth-backend",
+ "name": "project-auth-backendproject-auth",
"version": "1.0.0",
"description": "Starter project to get up and running with express quickly",
"scripts": {
@@ -9,12 +9,17 @@
"author": "",
"license": "ISC",
"dependencies": {
- "@babel/core": "^7.17.9",
- "@babel/node": "^7.16.8",
- "@babel/preset-env": "^7.16.11",
+ "@babel/core": "^7.24.5",
+ "@babel/node": "^7.23.9",
+ "@babel/preset-env": "^7.24.5",
+ "bcrypt-nodejs": "^0.0.3",
+ "bcryptjs": "^2.4.3",
"cors": "^2.8.5",
- "express": "^4.17.3",
- "mongoose": "^8.0.0",
- "nodemon": "^3.0.1"
+ "dotenv": "^16.4.5",
+ "express": "^4.19.2",
+ "express-list-endpoints": "^7.1.0",
+ "mongodb": "^6.6.2",
+ "mongoose": "^8.3.5",
+ "nodemon": "^3.1.0"
}
}
diff --git a/backend/server.js b/backend/server.js
index 2d7ae8aa1..594a96c4f 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -1,27 +1,114 @@
-import express from "express";
-import cors from "cors";
-import mongoose from "mongoose";
+import express from "express"
+import cors from "cors"
+import mongoose from "mongoose"
+import dotenv from "dotenv"
+import crypto from "crypto"
+import bcrypt from "bcryptjs"
-const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo";
-mongoose.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true });
-mongoose.Promise = Promise;
+dotenv.config()
-// 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 app = express();
+const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/Authorization"
+mongoose.connect(mongoUrl)
+mongoose.Promise = Promise
+const SALT_ROUNDS = 12
+const passwordValidator = (password) => {
+ const regex = /^(?=.*[A-Z])(?=.*d)[A-Za-zd]{8,}$/
+ return regex.test(password)
+}
+const userSchema = new mongoose.Schema({
+ name: {
+ type: String,
+ unique: true,
+ minLength: 5,
+ },
+ email: {
+ type: String,
+ unique: true,
+ required: [true, "Email is required"],
+ match: [/\S+@\S+\.\S+/, "Email is invalid"],
+ },
+ password: {
+ type: String,
+ required: [true, "Password is required"],
+ validate: {
+ validator: passwordValidator,
+ message:
+ "Password must contain at least one uppercase letter, one number, and be at least 8 characters long",
+ },
+ },
+ accessToken: {
+ type: String,
+ default: () => crypto.randomBytes(128).toString("hex"),
+ },
+})
+userSchema.pre("save", async function (next) {
+ if (this.isModified("password") || this.isNew) {
+ this.password = await bcrypt.hash(this.password, SALT_ROUNDS)
+ }
+ next()
+})
+const User = mongoose.model("User", userSchema)
+const authenticateUser = async (req, res, next) => {
+ const user = await User.findOne({
+ accessToken: req.header("Authorization"),
+ }).exec()
+ if (!accessToken) {
+ return res
+ .status(401)
+ .json({ error: "Unauthorized. Access token missing." })
+ }
+ 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());
-app.use(express.json());
+const port = process.env.PORT || 8080
+const app = express()
+
+app.use(cors())
+app.use(express.json())
+
+// Enable CORS middleware
+app.use(
+ cors({
+ origin: true,
+ methods: ["GET", "POST"],
+ allowedHeaders: ["Content-Type", "Authorization"],
+ })
+)
// Start defining your routes here
-app.get("/", (req, res) => {
- res.send("Hello Technigo!");
-});
+app.post("/users", async (req, res) => {
+ try {
+ const { name, email, password } = req.body
+ const existingUser = await User.findOne({ name }).exec()
+ if (existingUser) {
+ return res.status(409).json({ message: "Username already taken" })
+ }
+ const user = new User({ name, email, password: bcrypt.hashSync(password) })
+ user.save()
+ res.status(201).json({ id: user._id, accessToken: user.accessToken })
+ } catch (err) {
+ res.status(400).json({ message: "Could not save user", errors: err.errors })
+ }
+})
+app.get("/secrets", authenticateUser)
+app.get("/secrets", (req, res) => {
+ res.send(" This is the secret page to show after logging or registration.")
+})
+app.post("/sessions", async (req, res) => {
+ const user = await User.findOne({ email: req.body.email }).exec()
+ if (user && bcrypt.compareSync(req.body.password, user.password)) {
+ res.json({ userId: user._id, accessToken: user.accessToken })
+ } else {
+ res.json({ notFound: true })
+ }
+})
// Start the server
app.listen(port, () => {
- console.log(`Server running on http://localhost:${port}`);
-});
+ console.log(`Server running on http://localhost:${port}`)
+})
diff --git a/frontend/index.html b/frontend/index.html
index 0c589eccd..d123758e3 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -1,10 +1,10 @@
-
+
-
+
- Vite + React
+ DoggyAdopt
diff --git a/frontend/package.json b/frontend/package.json
index e9c95b79f..866abc046 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -10,8 +10,10 @@
"preview": "vite preview"
},
"dependencies": {
- "react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "react-router-dom": "^6.23.1",
+ "styled-components": "^6.1.11"
},
"devDependencies": {
"@types/react": "^18.2.15",
diff --git a/frontend/public/dog.png b/frontend/public/dog.png
new file mode 100644
index 000000000..03f8f2ec1
Binary files /dev/null and b/frontend/public/dog.png differ
diff --git a/frontend/public/dog2.jpg b/frontend/public/dog2.jpg
new file mode 100644
index 000000000..fa2174beb
Binary files /dev/null and b/frontend/public/dog2.jpg differ
diff --git a/frontend/public/dog3.jpg b/frontend/public/dog3.jpg
new file mode 100644
index 000000000..796198c4c
Binary files /dev/null and b/frontend/public/dog3.jpg differ
diff --git a/frontend/public/dog4.jpg b/frontend/public/dog4.jpg
new file mode 100644
index 000000000..1df3021f4
Binary files /dev/null and b/frontend/public/dog4.jpg differ
diff --git a/frontend/public/logo.svg b/frontend/public/logo.svg
new file mode 100644
index 000000000..a60d66e84
--- /dev/null
+++ b/frontend/public/logo.svg
@@ -0,0 +1,10 @@
+
diff --git a/frontend/public/paw-print.svg b/frontend/public/paw-print.svg
new file mode 100644
index 000000000..0b5910c1a
--- /dev/null
+++ b/frontend/public/paw-print.svg
@@ -0,0 +1,150 @@
+
+
+
diff --git a/frontend/public/rectangles.svg b/frontend/public/rectangles.svg
new file mode 100644
index 000000000..362b0e9f0
--- /dev/null
+++ b/frontend/public/rectangles.svg
@@ -0,0 +1,18 @@
+
diff --git a/frontend/public/rottie.jpg b/frontend/public/rottie.jpg
new file mode 100644
index 000000000..0633bc915
Binary files /dev/null and b/frontend/public/rottie.jpg differ
diff --git a/frontend/public/svg-edited.svg b/frontend/public/svg-edited.svg
new file mode 100644
index 000000000..27d0a0ff7
--- /dev/null
+++ b/frontend/public/svg-edited.svg
@@ -0,0 +1,150 @@
+
+
+
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 1091d4310..40ebdd187 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -1,3 +1,19 @@
+import { RegistrationForm } from "./RegistrationForm"
+import { BrowserRouter, Routes, Route } from "react-router-dom"
+import { Homepage } from "./Homepage"
+import { Dashboard } from "./Dashboard"
+import { Login } from "./Login"
+
export const App = () => {
- return