Merge branch 'main' of https://github.com/Newtbot/MP
This commit is contained in:
commit
7dceee0b79
136
Sean/inusers.js
136
Sean/inusers.js
@ -1,136 +0,0 @@
|
||||
const allUsers = <%- JSON.stringify(allUsers) %>;
|
||||
|
||||
document.getElementById('downloadButton').addEventListener('click', function () {
|
||||
console.log('Download button clicked');
|
||||
downloadExcel(allUsers);
|
||||
});
|
||||
|
||||
document.getElementById('addUserLink').addEventListener('click', function () {
|
||||
document.getElementById('downloadButtonContainer').style.display = 'none';
|
||||
document.getElementById('userDataContainer').style.display = 'none';
|
||||
document.getElementById('createUserForm').style.display = 'block';
|
||||
});
|
||||
|
||||
document.getElementById('userDataLink').addEventListener('click', function () {
|
||||
document.getElementById('downloadButtonContainer').style.display = 'block';
|
||||
document.getElementById('userDataContainer').style.display = 'block';
|
||||
document.getElementById('createUserForm').style.display = 'none';
|
||||
});
|
||||
|
||||
document.getElementById('userForm').addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
// Use FormData directly
|
||||
const formData = new FormData(document.getElementById('userForm'));
|
||||
|
||||
// Check password complexity
|
||||
const password = formData.get('password');
|
||||
const confirmPassword = formData.get('confirmPassword');
|
||||
|
||||
if (!isStrongPassword(password)) {
|
||||
alert('Password does not meet complexity requirements. It must be at least 10 characters long and include at least one uppercase letter, one lowercase letter, one digit, and one symbol.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if passwords match
|
||||
if (password !== confirmPassword) {
|
||||
alert('Passwords do not match. Please enter the same password in both fields.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a fetch request
|
||||
fetch('/createUser', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: formData.get('name'),
|
||||
username: formData.get('username'),
|
||||
email: formData.get('email'),
|
||||
password: password, // Use the validated password
|
||||
jobTitle: formData.get('jobTitle'),
|
||||
}),
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Success:', data);
|
||||
|
||||
// Show an alert with the received data
|
||||
alert(`User Registered!`);
|
||||
|
||||
// Optionally, you can clear the form or take other actions after registration
|
||||
document.getElementById('userForm').reset();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetch Error:', error);
|
||||
});
|
||||
});
|
||||
|
||||
// Function to validate password complexity
|
||||
function isStrongPassword(password) {
|
||||
// Password must be at least 10 characters long
|
||||
if (password.length < 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one uppercase letter
|
||||
if (!/[A-Z]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one lowercase letter
|
||||
if (!/[a-z]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one digit
|
||||
if (!/\d/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Password must contain at least one symbol
|
||||
if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function downloadExcel(allUsers) {
|
||||
if (allUsers && allUsers.length > 0) {
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const worksheet = workbook.addWorksheet('All Users');
|
||||
const headers = ['Name', 'Username', 'Email', 'Password', 'Last Login', 'Job Title'];
|
||||
worksheet.addRow(headers);
|
||||
allUsers.forEach(user => {
|
||||
const rowData = [
|
||||
user.name || '',
|
||||
user.username || '',
|
||||
user.email || '',
|
||||
user.password || '',
|
||||
user.lastLogin ? new Date(user.lastLogin).toLocaleString('en-US', { timeZone: 'Asia/Singapore' }) : '',
|
||||
user.jobTitle || ''
|
||||
];
|
||||
worksheet.addRow(rowData);
|
||||
});
|
||||
workbook.xlsx.writeBuffer().then(buffer => {
|
||||
const currentDate = new Date();
|
||||
const formattedDate = currentDate.toISOString().split('T')[0];
|
||||
const formattedTime = currentDate.toTimeString().split(' ')[0].replace(/:/g, '-');
|
||||
const fileName = `user_data_${formattedDate}_${formattedTime}.xlsx`;
|
||||
const blob = new Blob([buffer], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
});
|
||||
saveAs(blob, fileName);
|
||||
});
|
||||
} else {
|
||||
console.error('No data available for download.');
|
||||
}
|
||||
}
|
@ -37,6 +37,9 @@ module.exports = (sequelize) => {
|
||||
reset_token_expiry: {
|
||||
type: DataTypes.DATE,
|
||||
},
|
||||
sessionid: {
|
||||
type: DataTypes.STRING,
|
||||
},
|
||||
}, {
|
||||
hooks: {
|
||||
beforeCreate: async (user) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
const express = require("express");
|
||||
const session = require("express-session");
|
||||
const rateLimit = require('express-rate-limit');
|
||||
|
||||
const cookieParser = require('cookie-parser');
|
||||
const bodyParser = require("body-parser");
|
||||
const bcrypt = require("bcrypt");
|
||||
const crypto = require("crypto");
|
||||
@ -10,21 +10,37 @@ const otpGenerator = require('otp-generator');
|
||||
const { body, validationResult } = require('express-validator');
|
||||
const validator = require('validator');
|
||||
const { format } = require('date-fns');
|
||||
|
||||
const helmet = require('helmet');
|
||||
const { Sequelize } = require('sequelize');
|
||||
const { transporter } = require("./modules/nodeMailer");
|
||||
|
||||
const { sequelize, User } = require("./modules/mysql");
|
||||
const userLogs= require('./models/userLogs')(sequelize); // Adjust the path based on your project structure
|
||||
const app = express();
|
||||
|
||||
const nonce = crypto.randomBytes(16).toString('base64');
|
||||
|
||||
console.log('Nonce:', nonce);
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
app.use(bodyParser.json());
|
||||
app.use(cookieParser());
|
||||
const PORT = process.env.PORT || 3000;
|
||||
require("dotenv").config();
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
app.set("view engine", "ejs");
|
||||
app.use(
|
||||
helmet.contentSecurityPolicy({
|
||||
directives: {
|
||||
defaultSrc: ["'self'",`'nonce-${nonce}'`],
|
||||
scriptSrc: ["'self'",`'nonce-${nonce}'`,"'strict-dynamic'", 'cdn.jsdelivr.net', 'fonts.googleapis.com', 'stackpath.bootstrapcdn.com', 'code.jquery.com', 'cdnjs.cloudflare.com'],
|
||||
styleSrc: ["'self'",`'nonce-${nonce}'`, 'cdn.jsdelivr.net', 'fonts.googleapis.com'],
|
||||
imgSrc: ["'self'"],
|
||||
fontSrc: ["'self'", 'fonts.gstatic.com'],
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
app.use(session({
|
||||
secret: process.env.key,
|
||||
@ -189,6 +205,19 @@ app.post("/verify-otp", [
|
||||
}
|
||||
|
||||
const sessionToken = crypto.randomBytes(32).toString('hex');
|
||||
const username = req.body.username; // Replace with the actual username
|
||||
|
||||
User.update({ sessionid: sessionToken }, { where: { username } })
|
||||
.then(([rowsUpdated]) => {
|
||||
if (rowsUpdated > 0) {
|
||||
console.log(`SessionId updated for user: ${username}`);
|
||||
} else {
|
||||
console.error('User not found.');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error updating sessionId:', error);
|
||||
});
|
||||
|
||||
req.session.authenticated = true;
|
||||
req.session.username = req.body.username;
|
||||
@ -200,7 +229,6 @@ app.post("/verify-otp", [
|
||||
// Log anti-CSRF token
|
||||
console.log(`Generated Anti-CSRF Token: ${csrfTokenSession}`);
|
||||
|
||||
// Set CSRF token as a cookie
|
||||
res.cookie('sessionToken', sessionToken, { secure: true, httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000) }); // Expires in 1 day
|
||||
|
||||
console.log(`Generated Session Token: ${sessionToken}`);
|
||||
@ -232,6 +260,7 @@ app.post("/verify-otp", [
|
||||
} else {
|
||||
console.log("Session destroyed.");
|
||||
// Log the logout activity using Sequelize
|
||||
await User.update({ sessionid: null }, { where: { username } })
|
||||
await userLogs.create({ username, activity: "User logged out. Session destroyed." });
|
||||
// Clear the session token cookie
|
||||
res.clearCookie('sessionToken');
|
||||
@ -267,7 +296,7 @@ app.post("/verify-otp", [
|
||||
const currentUsername = req.session.username;
|
||||
|
||||
// Render the inusers page with JSON data
|
||||
res.render("inusers", { allUsers, csrfToken: csrfTokenSession, currentUsername });
|
||||
res.render("inusers", { nonce: nonce, allUsers, csrfToken: csrfTokenSession, currentUsername });
|
||||
} catch (error) {
|
||||
console.error("Error fetching all users:", error);
|
||||
res.status(500).send("Internal Server Error");
|
||||
@ -324,6 +353,14 @@ app.post(
|
||||
return res.status(400).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
const sessionTokencookie = req.cookies['sessionToken'];
|
||||
|
||||
// Verify sessionToken with the one stored in the database
|
||||
const user = await User.findOne({ where: { sessionid: sessionTokencookie } });
|
||||
|
||||
if (!user) {
|
||||
return res.status(403).json({ error: 'Invalid sessionToken' });
|
||||
}
|
||||
// Validate the anti-CSRF token
|
||||
const submittedCSRFToken = req.body.csrf_token;
|
||||
|
||||
@ -595,7 +632,14 @@ app.post("/reset-password", async (req, res) => {
|
||||
if (!csrfTokenSession || submittedCSRFToken !== csrfTokenSession) {
|
||||
return res.status(403).json({ error: 'CSRF token mismatch' });
|
||||
}
|
||||
const sessionTokencookie = req.cookies['sessionToken'];
|
||||
|
||||
// Verify sessionToken with the one stored in the database
|
||||
const user = await User.findOne({ where: { sessionid: sessionTokencookie } });
|
||||
|
||||
if (!user) {
|
||||
return res.status(403).json({ error: 'Invalid sessionToken' });
|
||||
}
|
||||
// Sanitize the inputs
|
||||
const sanitizedUsername = validator.escape(username);
|
||||
const sanitizedPassword = validator.escape(password);
|
||||
@ -686,7 +730,6 @@ app.get('/api/users', async (req, res) => {
|
||||
|
||||
app.get('/api/searchUser', async (req, res) => {
|
||||
const { username } = req.query;
|
||||
console.log(username);
|
||||
try {
|
||||
// Find the user in the database by username
|
||||
const user = await User.findOne({ where: { username } });
|
||||
@ -710,14 +753,23 @@ app.delete('/api/deleteUser/:username', async (req, res) => {
|
||||
const creatorUsername = req.session.username;
|
||||
|
||||
try {
|
||||
// Extract CSRF token from the request body
|
||||
// Retrieve sessionToken from cookies
|
||||
const sessionTokencoookie = req.cookies['sessionToken'];
|
||||
// Retrieve CSRF token from the request body
|
||||
const { csrfToken } = req.body;
|
||||
|
||||
console.log(csrfToken);
|
||||
// Compare CSRF token with the one stored in the session
|
||||
if (csrfToken !== csrfTokenSession) {
|
||||
return res.status(403).json({ success: false, error: 'CSRF token mismatch' });
|
||||
}
|
||||
|
||||
// Verify sessionToken with the one stored in the database
|
||||
const user = await User.findOne({ where: { sessionid: sessionTokencoookie } });
|
||||
|
||||
if (!user) {
|
||||
return res.status(403).json({ success: false, error: 'Invalid sessionToken or user not found' });
|
||||
}
|
||||
|
||||
// Log deletion activity to UserLogs model
|
||||
const deletionActivity = `User ${username} has been successfully deleted`;
|
||||
await userLogs.create({ username: creatorUsername, activity: deletionActivity });
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
58
Sean/views/forgot-password.css
Normal file
58
Sean/views/forgot-password.css
Normal file
@ -0,0 +1,58 @@
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
form {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
.error-message {
|
||||
color: red;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.success-message {
|
||||
color: green;
|
||||
margin-top: 10px;
|
||||
}
|
@ -5,66 +5,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Forgot Password - Your Website</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
form {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
.error-message {
|
||||
color: red;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.success-message {
|
||||
color: green;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="forgot-password.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="forgotPasswordForm">
|
||||
|
@ -1,107 +0,0 @@
|
||||
document.addEventListener("DOMContentLoaded", async function () {
|
||||
console.log("DOM Loaded");
|
||||
|
||||
// Extract data from sensorData
|
||||
const sensorData = JSON.parse('<%- JSON.stringify(sensorData) %>');
|
||||
console.log("Sensor Data:", sensorData);
|
||||
|
||||
// Fetch location names from the server
|
||||
const locationNames = await fetch('/api/locations') // Adjust the API endpoint
|
||||
.then(response => response.json())
|
||||
.then(data => data.map(location => ({ id: location.id, name: location.name })))
|
||||
.catch(error => console.error('Error fetching location names:', error));
|
||||
|
||||
|
||||
|
||||
// Group sensorData by locationid
|
||||
const groupedData = groupBy(sensorData, 'locationid');
|
||||
|
||||
// Get the content div
|
||||
const contentDiv = document.getElementById('content');
|
||||
|
||||
// Create a chart for each location
|
||||
Object.keys(groupedData).forEach(locationId => {
|
||||
const locationData = groupedData[locationId];
|
||||
|
||||
// Find the corresponding location name
|
||||
const locationName = locationNames.find(location => location.id === parseInt(locationId, 10))?.name || `Unknown Location ${locationId}`;
|
||||
|
||||
// Create a container for the chart
|
||||
const container = document.createElement('div');
|
||||
container.className = 'chart-container';
|
||||
|
||||
// Create a title for the container with location name
|
||||
const title = document.createElement('h4');
|
||||
title.textContent = `Location: ${locationName}`;
|
||||
container.appendChild(title);
|
||||
|
||||
// Get labels (Location IDs)
|
||||
const labels = locationData.map(data => new Date(data.createdAt).toLocaleString('en-US', { timeZone: 'Asia/Singapore' }));
|
||||
|
||||
// Create datasets for each measurement
|
||||
const datasets = [
|
||||
{
|
||||
label: 'CO',
|
||||
data: locationData.map(data => data.measurement.co),
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.5)', // Red color
|
||||
},
|
||||
{
|
||||
label: 'O3',
|
||||
data: locationData.map(data => data.measurement.o3),
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.5)', // Blue color
|
||||
},
|
||||
{
|
||||
label: 'NO2',
|
||||
data: locationData.map(data => data.measurement.no2),
|
||||
backgroundColor: 'rgba(255, 206, 86, 0.5)', // Yellow color
|
||||
},
|
||||
{
|
||||
label: 'SO2',
|
||||
data: locationData.map(data => data.measurement.so2),
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.5)', // Green color
|
||||
},
|
||||
];
|
||||
|
||||
// Create a canvas element for each location
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 400;
|
||||
canvas.height = 200;
|
||||
|
||||
// Append canvas to the container
|
||||
container.appendChild(canvas);
|
||||
|
||||
// Append container to the content div
|
||||
contentDiv.appendChild(container);
|
||||
|
||||
// Create a bar chart for each location
|
||||
const ctx = canvas.getContext('2d');
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: datasets,
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
x: {
|
||||
beginAtZero: true,
|
||||
},
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Helper function to group data by a specified key
|
||||
function groupBy(arr, key) {
|
||||
return arr.reduce((acc, obj) => {
|
||||
const groupKey = obj[key];
|
||||
acc[groupKey] = acc[groupKey] || [];
|
||||
acc[groupKey].push(obj);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
});
|
||||
|
@ -1,64 +0,0 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const mysql = require('mysql');
|
||||
|
||||
// Replace with your MySQL connection details
|
||||
const mysqlConfig = {
|
||||
host: process.env.host,
|
||||
user: process.env.user,
|
||||
password: process.env.password,
|
||||
database: process.env.database,
|
||||
timezone: 'Z', // Set the timezone to UTC
|
||||
};
|
||||
|
||||
const mysqlConnection = mysql.createConnection(mysqlConfig);
|
||||
|
||||
// Middleware to check if the user is authenticated
|
||||
function isAuthenticated(req, res, next) {
|
||||
if (req.session && req.session.authenticated) {
|
||||
return next();
|
||||
} else {
|
||||
res.redirect('/login');
|
||||
}
|
||||
}
|
||||
|
||||
// InUsers route (renders the InUsers tab)
|
||||
router.get('/', isAuthenticated, (req, res) => {
|
||||
// Fetch all user data from the database
|
||||
const userDataQuery = 'SELECT * FROM users';
|
||||
|
||||
mysqlConnection.query(userDataQuery, (error, userData) => {
|
||||
if (error) {
|
||||
console.error('Error fetching user data:', error);
|
||||
res.status(500).send('Internal Server Error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Render the inusers page with user data
|
||||
res.render('inusers', { userData: userData });
|
||||
});
|
||||
});
|
||||
|
||||
// User Data route
|
||||
router.get('/userdata', isAuthenticated, (req, res) => {
|
||||
// Fetch all user data from the database
|
||||
const userDataQuery = 'SELECT * FROM users';
|
||||
|
||||
mysqlConnection.query(userDataQuery, (error, userData) => {
|
||||
if (error) {
|
||||
console.error('Error fetching user data:', error);
|
||||
res.status(500).send('Internal Server Error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Render the user-data page with user data
|
||||
res.render('user-data', { userData: userData });
|
||||
});
|
||||
});
|
||||
|
||||
// Edit User Data route
|
||||
router.get('/edituserdata', isAuthenticated, (req, res) => {
|
||||
res.render('edit-user-data');
|
||||
});
|
||||
|
||||
module.exports = router;
|
@ -7,7 +7,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>In-House Users</title>
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&display=swap">
|
||||
</head>
|
||||
@ -173,19 +173,21 @@
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<script nonce="<%= nonce %>">
|
||||
const allUsers = <%- JSON.stringify(allUsers) %>;
|
||||
const currentUsername = '<%= currentUsername %>';
|
||||
const nonce = "<%= nonce %>"
|
||||
console.log('Nonce:', nonce);
|
||||
</script>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.17.4/xlsx.full.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.2.1/exceljs.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.js"></script>
|
||||
<script src="inusers.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.4.min.js" nonce="<%= nonce %>"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.3.0/js/bootstrap.bundle.min.js" nonce="<%= nonce %>" ></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.17.4/xlsx.full.min.js" nonce="<%= nonce %>"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js" nonce="<%= nonce %>"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.2.1/exceljs.min.js" nonce="<%= nonce %>"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" nonce="<%= nonce %>"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.js" nonce="<%= nonce %>"></script>
|
||||
<script src="inusers.js" nonce="<%= nonce %>"></script>
|
||||
|
||||
|
||||
</body>
|
||||
|
@ -33,7 +33,7 @@ $(document).ready(function () {
|
||||
$('#logsContainer').hide();
|
||||
$('#additional-text').hide();
|
||||
$('#additional-text2').hide();
|
||||
$('#additional-text2').hide();
|
||||
$('#additional-text3').hide();
|
||||
});
|
||||
|
||||
$('#searchUserButton').on('click', function () {
|
||||
@ -124,6 +124,7 @@ $('#searchResultsList').on('click', '.deleteUserButton', function () {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include', // Include cookies in the request
|
||||
body: JSON.stringify({ csrfToken }), // Include CSRF token in the request body
|
||||
})
|
||||
.then(response => {
|
||||
@ -243,8 +244,8 @@ function resetFormFields() {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
},
|
||||
credentials: 'include', // Include cookies in the request
|
||||
body: JSON.stringify({
|
||||
name: name,
|
||||
username: username,
|
||||
@ -330,6 +331,7 @@ $('#resetPasswordForm').on('submit', function (e) {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include', // Include cookies in the request
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: password,
|
||||
@ -356,8 +358,6 @@ $('#resetPasswordForm').on('submit', function (e) {
|
||||
$('#resetPassword').val('');
|
||||
$('#resetConfirmPassword').val('');
|
||||
|
||||
// You might want to hide the reset password form after submission
|
||||
$('#resetPasswordFormContainer').hide();
|
||||
})
|
||||
.catch(error => {
|
||||
// Handle 404 error separately to show an alert
|
||||
|
67
Sean/views/login.css
Normal file
67
Sean/views/login.css
Normal file
@ -0,0 +1,67 @@
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
width: 300px;
|
||||
margin: auto; /* Center the container horizontally */
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
input {
|
||||
width: calc(100% - 16px); /* Adjust the width and center the input */
|
||||
padding: 8px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.reset-link-container {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.reset-link {
|
||||
color: #4caf50;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -4,75 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login - Eco Saver</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
width: 300px;
|
||||
margin: auto; /* Center the container horizontally */
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
input {
|
||||
width: calc(100% - 16px); /* Adjust the width and center the input */
|
||||
padding: 8px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.reset-link-container {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.reset-link {
|
||||
color: #4caf50;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="login.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-container">
|
||||
|
@ -1,146 +0,0 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap');
|
||||
*{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Poppins',sans-serif;
|
||||
}
|
||||
body{
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
background: linear-gradient(135deg, #71b7e6, #9b59b6);
|
||||
}
|
||||
.container{
|
||||
max-width: 700px;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
padding: 25px 30px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 5px 10px rgba(0,0,0,0.15);
|
||||
}
|
||||
.container .title{
|
||||
font-size: 25px;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
}
|
||||
.container .title::before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 3px;
|
||||
width: 30px;
|
||||
border-radius: 5px;
|
||||
background: linear-gradient(135deg, #71b7e6, #9b59b6);
|
||||
}
|
||||
.content form .user-details{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 20px 0 12px 0;
|
||||
}
|
||||
form .user-details .input-box{
|
||||
margin-bottom: 15px;
|
||||
width: calc(100% / 2 - 20px);
|
||||
}
|
||||
form .input-box span.details{
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.user-details .input-box input{
|
||||
height: 45px;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
font-size: 16px;
|
||||
border-radius: 5px;
|
||||
padding-left: 15px;
|
||||
border: 1px solid #ccc;
|
||||
border-bottom-width: 2px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.user-details .input-box input:focus,
|
||||
.user-details .input-box input:valid{
|
||||
border-color: #9b59b6;
|
||||
}
|
||||
form .gender-details .gender-title{
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
form .category{
|
||||
display: flex;
|
||||
width: 80%;
|
||||
margin: 14px 0 ;
|
||||
justify-content: space-between;
|
||||
}
|
||||
form .category label{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
form .category label .dot{
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
background: #d9d9d9;
|
||||
border: 5px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
#dot-1:checked ~ .category label .one,
|
||||
#dot-2:checked ~ .category label .two,
|
||||
#dot-3:checked ~ .category label .three{
|
||||
background: #9b59b6;
|
||||
border-color: #d9d9d9;
|
||||
}
|
||||
form input[type="radio"]{
|
||||
display: none;
|
||||
}
|
||||
form .button{
|
||||
height: 45px;
|
||||
margin: 35px 0
|
||||
}
|
||||
form .button input{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 1px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
background: linear-gradient(135deg, #71b7e6, #9b59b6);
|
||||
}
|
||||
form .button input:hover{
|
||||
/* transform: scale(0.99); */
|
||||
background: linear-gradient(-135deg, #71b7e6, #9b59b6);
|
||||
}
|
||||
@media(max-width: 584px){
|
||||
.container{
|
||||
max-width: 100%;
|
||||
}
|
||||
form .user-details .input-box{
|
||||
margin-bottom: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
form .category{
|
||||
width: 100%;
|
||||
}
|
||||
.content form .user-details{
|
||||
max-height: 300px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.user-details::-webkit-scrollbar{
|
||||
width: 5px;
|
||||
}
|
||||
}
|
||||
@media(max-width: 459px){
|
||||
.container .content .category{
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
50
Sean/views/otp.css
Normal file
50
Sean/views/otp.css
Normal file
@ -0,0 +1,50 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
text-align: center;
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
form {
|
||||
max-width: 300px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
padding: 10px 15px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
margin-top: 10px;
|
||||
}
|
@ -4,58 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Enter OTP</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
text-align: center;
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
form {
|
||||
max-width: 300px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
padding: 10px 15px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="otp.css">
|
||||
</head>
|
||||
<body>
|
||||
<h2>Enter OTP</h2>
|
||||
|
@ -1,162 +0,0 @@
|
||||
/* Responsive CSS Here */
|
||||
@media screen and (max-width: 950px) {
|
||||
.nav-img {
|
||||
height: 25px;
|
||||
}
|
||||
.nav-option {
|
||||
gap: 30px;
|
||||
}
|
||||
.nav-option h3 {
|
||||
font-size: 15px;
|
||||
}
|
||||
.report-topic-heading,
|
||||
.item1,
|
||||
.items {
|
||||
width: 800px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 850px) {
|
||||
.nav-img {
|
||||
height: 30px;
|
||||
}
|
||||
.nav-option {
|
||||
gap: 30px;
|
||||
}
|
||||
.nav-option h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
.report-topic-heading,
|
||||
.item1,
|
||||
.items {
|
||||
width: 700px;
|
||||
}
|
||||
.navcontainer {
|
||||
width: 100vw;
|
||||
position: absolute;
|
||||
transition: all 0.6s ease-in-out;
|
||||
top: 0;
|
||||
left: -100vw;
|
||||
}
|
||||
.nav {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
.navclose {
|
||||
left: 00px;
|
||||
}
|
||||
.searchbar {
|
||||
display: none;
|
||||
}
|
||||
.main {
|
||||
padding: 40px 30px 30px 30px;
|
||||
}
|
||||
.searchbar2 {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin: 0 0 40px 0;
|
||||
justify-content: center;
|
||||
}
|
||||
.searchbar2 input {
|
||||
width: 250px;
|
||||
height: 42px;
|
||||
border-radius: 50px 0 0 50px;
|
||||
background-color: var(--background-color3);
|
||||
padding: 0 20px;
|
||||
font-size: 15px;
|
||||
border: 2px solid var(--secondary-color);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 490px) {
|
||||
.message {
|
||||
display: none;
|
||||
}
|
||||
.logosec {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.logo {
|
||||
font-size: 20px;
|
||||
}
|
||||
.menuicn {
|
||||
height: 25px;
|
||||
}
|
||||
.nav-img {
|
||||
height: 25px;
|
||||
}
|
||||
.nav-option {
|
||||
gap: 25px;
|
||||
}
|
||||
.nav-option h3 {
|
||||
font-size: 12px;
|
||||
}
|
||||
.nav-upper-options {
|
||||
gap: 15px;
|
||||
}
|
||||
.recent-Articles {
|
||||
font-size: 20px;
|
||||
}
|
||||
.report-topic-heading,
|
||||
.item1,
|
||||
.items {
|
||||
width: 550px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
.recent-Articles {
|
||||
font-size: 17px;
|
||||
}
|
||||
.view {
|
||||
width: 60px;
|
||||
font-size: 10px;
|
||||
height: 27px;
|
||||
}
|
||||
.report-header {
|
||||
height: 60px;
|
||||
padding: 10px 10px 5px 10px;
|
||||
}
|
||||
.searchbtn img {
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 320px) {
|
||||
.recent-Articles {
|
||||
font-size: 12px;
|
||||
}
|
||||
.view {
|
||||
width: 50px;
|
||||
font-size: 8px;
|
||||
height: 27px;
|
||||
}
|
||||
.report-header {
|
||||
height: 60px;
|
||||
padding: 10px 5px 5px 5px;
|
||||
}
|
||||
.t-op {
|
||||
font-size: 12px;
|
||||
}
|
||||
.t-op-nextlvl {
|
||||
font-size: 10px;
|
||||
}
|
||||
.report-topic-heading,
|
||||
.item1,
|
||||
.items {
|
||||
width: 300px;
|
||||
}
|
||||
.report-body {
|
||||
padding: 10px;
|
||||
}
|
||||
.label-tag {
|
||||
width: 70px;
|
||||
}
|
||||
.searchbtn {
|
||||
width: 40px;
|
||||
}
|
||||
.searchbar2 input {
|
||||
width: 180px;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
<!-- setup-mfa.ejs (or your template engine's file) -->
|
||||
<h2>Setup Multi-Factor Authentication</h2>
|
||||
<p>Scan the QR code below with your authenticator app:</p>
|
||||
<img src="<%= qrCodeDataUri %>" alt="QR Code">
|
||||
|
||||
<form action="/setup-mfa" method="post">
|
||||
<label for="mfaCode">Enter MFA Code:</label>
|
||||
<input type="text" id="mfaCode" name="mfaCode" required>
|
||||
<button type="submit">Verify and Save</button>
|
||||
</form>
|
@ -56,15 +56,16 @@ async function addUser(user) {
|
||||
|
||||
//api/v0/auth/login
|
||||
async function loginUser(user) {
|
||||
//console.log(user);
|
||||
//look up username or email in db
|
||||
const userRes = await userModel.findOne({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{
|
||||
username: user.userInfo,
|
||||
username: user.username,
|
||||
},
|
||||
{
|
||||
email: user.userInfo,
|
||||
email: user.username,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -37,6 +37,9 @@ function isAddress(value){
|
||||
return addressRegex.test(value);
|
||||
}
|
||||
|
||||
//generate me an regex for alpha
|
||||
//https://stackoverflow.com/questions/11522529/regexp-for-alphabets-with-spaces
|
||||
|
||||
module.exports = {
|
||||
isAlphaNumericwithSpaces,
|
||||
isAlphaNumericWithSpacesAndDash,
|
||||
|
16
consumerWebsite/modules/nodemailer.js
Normal file
16
consumerWebsite/modules/nodemailer.js
Normal file
@ -0,0 +1,16 @@
|
||||
const nodemailer = require("nodemailer");
|
||||
const dotenv = require("dotenv");
|
||||
const path = require('path')
|
||||
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })
|
||||
|
||||
let transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
host: 'smtp.gmail.com',
|
||||
port: 587,
|
||||
secure: false,
|
||||
auth: {
|
||||
user:
|
||||
pass:
|
||||
},
|
||||
});
|
||||
module.exports = { transporter };
|
@ -254,3 +254,7 @@ form
|
||||
color: #4eae3a;
|
||||
border-color: #4eae3a;
|
||||
}
|
||||
|
||||
a {
|
||||
color: black;
|
||||
}
|
@ -59,7 +59,7 @@ button.btn-secondary:hover{
|
||||
.navbar-expand-lg.top-nav .navbar-nav .nav-link{
|
||||
padding: 10px 15px;
|
||||
color: #4e3914;
|
||||
font-size: 14px;
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
@ -149,42 +149,33 @@ app.auth = (function (app) {
|
||||
function setToken(token) {
|
||||
localStorage.setItem("APIToken", token);
|
||||
}
|
||||
/*
|
||||
function setUserId(userid) {
|
||||
console.log("userid", userid);
|
||||
localStorage.setItem("userid", userid);
|
||||
}
|
||||
|
||||
function setUsername(username) {
|
||||
localStorage.setItem("username", username);
|
||||
}
|
||||
*/
|
||||
|
||||
function getToken() {
|
||||
return localStorage.getItem("APIToken");
|
||||
}
|
||||
|
||||
|
||||
function isLoggedIn(callback) {
|
||||
if (getToken()) {
|
||||
return app.api.get("user/me", function (error, data) {
|
||||
if (!error) app.auth.user = data;
|
||||
$.scope.getUsername.push(data.username);
|
||||
//$.scope.getUsername.push(data);
|
||||
return callback(error, data);
|
||||
});
|
||||
} else {
|
||||
callback(null, false);
|
||||
}
|
||||
}
|
||||
/*
|
||||
function logIn(args, callback) {
|
||||
app.api.post("auth/login", args, function (error, data) {
|
||||
if (data.login) {
|
||||
setToken(data.token);
|
||||
}
|
||||
callback(error, !!data.token);
|
||||
|
||||
function showUser(){
|
||||
app.api.get("user/me", function (error, data) {
|
||||
if (!error) app.auth.user = data;
|
||||
$.scope.getUsername.push(data);
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
function logOut(callback) {
|
||||
//call logout route
|
||||
@ -228,29 +219,28 @@ app.auth = (function (app) {
|
||||
function homeRedirect() {
|
||||
window.location.href = location.href.replace(location.replace(`/`)) || "/";
|
||||
}
|
||||
|
||||
//if isLoggedin is true, redirect user away from login / register page
|
||||
/*
|
||||
function redirectIfLoggedIn() {
|
||||
$.holdReady(true);
|
||||
app.auth.isLoggedIn(function (error, isLoggedIn) {
|
||||
if (error || isLoggedIn) {
|
||||
location.replace(`/`);
|
||||
} else {
|
||||
$.holdReady(false);
|
||||
if (getToken()){
|
||||
homeRedirect();
|
||||
}
|
||||
});
|
||||
logInRedirect();
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
return {
|
||||
getToken: getToken,
|
||||
setToken: setToken,
|
||||
isLoggedIn: isLoggedIn,
|
||||
//logIn: logIn,
|
||||
logOut: logOut,
|
||||
forceLogin,
|
||||
logInRedirect,
|
||||
homeRedirect,
|
||||
redirectIfLoggedIn,
|
||||
showUser,
|
||||
//redirectIfLoggedIn,
|
||||
};
|
||||
})(app);
|
||||
|
||||
|
@ -283,9 +283,6 @@
|
||||
};
|
||||
|
||||
$( document ).ready( function(){
|
||||
console.log('jq-repeat', $.scope)
|
||||
//$.jqrepeat = $.scope
|
||||
|
||||
$( '[jq-repeat]' ).each(function(key, value){
|
||||
make(value);
|
||||
});
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -6,7 +6,6 @@ const router = express.Router();
|
||||
// /user/register
|
||||
router.post("/register", async (req, res, next) => {
|
||||
try {
|
||||
console.log(req.body);
|
||||
let Res = await addUser(req.body);
|
||||
if (Res == false) {
|
||||
let error = new Error("UserRegFailed");
|
||||
@ -36,7 +35,6 @@ router.post("/login", async (req, res, next) => {
|
||||
}
|
||||
else{
|
||||
//pass res back to form to be set in local storage
|
||||
console.log("my res" , Res);
|
||||
return res.json({
|
||||
message: "User login successfully",
|
||||
token: Res.token,
|
||||
@ -51,6 +49,12 @@ router.post("/login", async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
//contact
|
||||
//auth/contact
|
||||
|
||||
router.post("/contact", async (req, res, next) => {
|
||||
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
|
@ -68,8 +68,8 @@ router.get("/profile", function (req, res, next) {
|
||||
|
||||
|
||||
//forgot password page
|
||||
router.get("/forgotPassword", function (req, res, next) {
|
||||
res.render("forgotPassword");
|
||||
router.get("/forgotpassword", function (req, res, next) {
|
||||
res.render("forgotpassword");
|
||||
});
|
||||
|
||||
//resetted password page
|
||||
|
@ -7,8 +7,6 @@ const router = express.Router();
|
||||
//getbyid
|
||||
router.get("/me", async function (req, res, next) {
|
||||
try {
|
||||
|
||||
//console.log(req.user);
|
||||
let user = await getUserID(req.user);
|
||||
if (!user) {
|
||||
let error = new Error("User not found");
|
||||
@ -24,6 +22,7 @@ router.get("/me", async function (req, res, next) {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//logout
|
||||
router.delete('/logout', async function(req, res, next){
|
||||
try{
|
||||
|
@ -12,25 +12,35 @@
|
||||
<div class="left-menu">
|
||||
<div class="content-logo">
|
||||
<div class="logo">
|
||||
<img alt="platform by Emily van den Heever from the Noun Project" title="platform by Emily van den Heever from the Noun Project" src="images/apilogo.png" height="32" />
|
||||
<img alt="platform by Emily van den Heever from the Noun Project"
|
||||
title="platform by Emily van den Heever from the Noun Project" src="images/apilogo.png"
|
||||
height="32" />
|
||||
<span>API Documentation</span>
|
||||
</div>
|
||||
<button class="burger-menu-icon" id="button-menu-mobile">
|
||||
<svg width="34" height="34" viewBox="0 0 100 100"><path class="line line1" d="M 20,29.000046 H 80.000231 C 80.000231,29.000046 94.498839,28.817352 94.532987,66.711331 94.543142,77.980673 90.966081,81.670246 85.259173,81.668997 79.552261,81.667751 75.000211,74.999942 75.000211,74.999942 L 25.000021,25.000058"></path><path class="line line2" d="M 20,50 H 80"></path><path class="line line3" d="M 20,70.999954 H 80.000231 C 80.000231,70.999954 94.498839,71.182648 94.532987,33.288669 94.543142,22.019327 90.966081,18.329754 85.259173,18.331003 79.552261,18.332249 75.000211,25.000058 75.000211,25.000058 L 25.000021,74.999942"></path></svg>
|
||||
<svg width="34" height="34" viewBox="0 0 100 100">
|
||||
<path class="line line1"
|
||||
d="M 20,29.000046 H 80.000231 C 80.000231,29.000046 94.498839,28.817352 94.532987,66.711331 94.543142,77.980673 90.966081,81.670246 85.259173,81.668997 79.552261,81.667751 75.000211,74.999942 75.000211,74.999942 L 25.000021,25.000058">
|
||||
</path>
|
||||
<path class="line line2" d="M 20,50 H 80"></path>
|
||||
<path class="line line3"
|
||||
d="M 20,70.999954 H 80.000231 C 80.000231,70.999954 94.498839,71.182648 94.532987,33.288669 94.543142,22.019327 90.966081,18.329754 85.259173,18.331003 79.552261,18.332249 75.000211,25.000058 75.000211,25.000058 L 25.000021,74.999942">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="mobile-menu-closer"></div>
|
||||
<div class="content-menu">
|
||||
<div class="content-infos">
|
||||
<div class="info"><b>Version:</b> 1.0.5</div>
|
||||
<div class="info"><b>Last Updated:</b> 15th Sep, 2021</div>
|
||||
<div class="info"><b>Version:</b> 0</div>
|
||||
<div class="info"><b>Last Updated:</b> 22th January 2024</div>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="scroll-to-link active" data-target="content-get-started">
|
||||
<a>GET STARTED</a>
|
||||
</li>
|
||||
<li class="scroll-to-link" data-target="content-get-characters">
|
||||
<a>Get Characters</a>
|
||||
<a>Get Data From API</a>
|
||||
</li>
|
||||
<li class="scroll-to-link" data-target="content-errors">
|
||||
<a>Errors</a>
|
||||
@ -45,17 +55,22 @@
|
||||
<div class="overflow-hidden content-section" id="content-get-started">
|
||||
<h1>Get started</h1>
|
||||
<p>
|
||||
The Westeros API provides programmatic access to read Game of Thrones data. Retrieve a character, provide an oauth connexion, retrieve a familly, filter them, etc.
|
||||
The following API is provided by the Eco saver developer team. It allows you to get Location and
|
||||
Sensor and Sensor Data from the Eco saver database.
|
||||
</p>
|
||||
<p>
|
||||
To use this API, you need an <strong>API key</strong>. Please contact us at <a href="mailto:jon.snow@nightswatch.wes">jon.snow@nightswatch.wes</a> to get your own API key.
|
||||
To use this API, you need an <strong>API key</strong>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="overflow-hidden content-section" id="content-get-characters">
|
||||
<h2>get characters</h2>
|
||||
<div class="overflow-hidden content-section" id="content-get-location">
|
||||
<h2>Get all location</h2>
|
||||
<p>
|
||||
To get characters you need to make a POST call to the following url :<br>
|
||||
<code class="higlighted break-word">http://api.westeros.com/character/get</code>
|
||||
To get Location of sensors you need to make a GET call to the following url :<br>
|
||||
<code class="higlighted break-word">https://api.teeseng.uk/api/v0/location</code>
|
||||
<br>
|
||||
<br>
|
||||
Return Response :<br>
|
||||
<code class="higlighted break-word">{"status":"200"}</code>
|
||||
</p>
|
||||
<br>
|
||||
<h4>QUERY PARAMETERS</h4>
|
||||
@ -69,49 +84,237 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>secret_key</td>
|
||||
<td>String</td>
|
||||
<td>Authorization</td>
|
||||
<td>JSON</td>
|
||||
<td>Your API key.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>search</td>
|
||||
<td>String</td>
|
||||
<td>(optional) A search word to find character by name.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>house</td>
|
||||
<td>String</td>
|
||||
<td>
|
||||
(optional) a string array of houses:
|
||||
<td>(Required) Example: curl https://api.teeseng.uk/api/v0/location -H "Authorization: {provide your
|
||||
API key here}"</td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>alive</td>
|
||||
<td>Boolean</td>
|
||||
<td>
|
||||
(optional) a boolean to filter alived characters
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>gender</td>
|
||||
<td>String</td>
|
||||
<td>
|
||||
(optional) a string to filter character by gender:<br> m: male<br> f: female
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>offset</td>
|
||||
<td>Integer</td>
|
||||
<td>(optional - default: 0) A cursor for use in pagination. Pagination starts offset the specified offset.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>limit</td>
|
||||
<td>Integer</td>
|
||||
<td>(optional - default: 10) A limit on the number of objects to be returned, between 1 and 100.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="overflow-hidden content-section" id="content-get-location-by-id">
|
||||
<h2>Get location by ID</h2>
|
||||
<p>
|
||||
To get Location you need to make a GET call to the following url :<br>
|
||||
<code class="higlighted break-word">https://api.teeseng.uk/api/v0/location/{id}</code>
|
||||
<br>
|
||||
<br>
|
||||
Return Response :<br>
|
||||
<code class="higlighted break-word">{"status":"200"}</code>
|
||||
</p>
|
||||
<br>
|
||||
<h4>QUERY PARAMETERS</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Authorization</td>
|
||||
<td>JSON</td>
|
||||
<td>(Required) Your API key.</td>
|
||||
<td>Example: curl https://api.teeseng.uk/api/v0/location -H "Authorization: {provide your
|
||||
API key here}"</td>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="overflow-hidden content-section" id="content-add-location">
|
||||
<h2>Add Location (Only for system or admin API key)</h2>
|
||||
<p>
|
||||
To add an Location you need to make a POST call to the following url :<br>
|
||||
<code class="higlighted break-word">https://api.teeseng.uk/api/v0/location/new</code>
|
||||
<br>
|
||||
<br>
|
||||
Example :<br>
|
||||
<code class="higlighted break-word">curl https://api.teeseng.uk/api/v0/location/new -H "Content-Type: application/json" -X POST -d '{"name": "SAMPLE", "added_by": "system" , "description": "test"}'</code>
|
||||
<br>
|
||||
<br>
|
||||
Return Response :<br>
|
||||
<code class="higlighted break-word">{"status":"200"}</code>
|
||||
</p>
|
||||
<br>
|
||||
<h4>QUERY PARAMETERS</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Authorization</td>
|
||||
<td>JSON</td>
|
||||
<td>Your API key.</td>
|
||||
<td>(Required) Example: curl https://api.teeseng.uk/api/v0/location/new -H "Authorization: {provide your
|
||||
API key here}"</td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Location name</td>
|
||||
<td>JSON</td>
|
||||
<td>Location name.</td>
|
||||
<td>(Required) Location name. Example: curl https://api.teeseng.uk/api/v0/location/new -H "Authorization: provide
|
||||
your API key here" -d '{"name":"Location name"}'</td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Added by </td>
|
||||
<td>JSON</td>
|
||||
<td>System or Admin</td>
|
||||
<td>(Required) System or Admin Example: curl https://api.teeseng.uk/api/v0/location/new -H "Authorization: provide
|
||||
your API key here" -d '{"added_by":"system"}'</td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>JSON</td>
|
||||
<td>Description of Location</td>
|
||||
<td>(Required) System or Admin Example: curl https://api.teeseng.uk/api/v0/location/new -H "Authorization: provide
|
||||
your API key here" -d '{"description":"test"}'</td>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- update -->
|
||||
<div class="overflow-hidden content-section" id="content-update-location-by-id">
|
||||
<h2>Update Location (Only for system or admin API key)</h2>
|
||||
<p>
|
||||
To update an Location you need to make a PUT call to the following url :<br>
|
||||
<code class="higlighted break-word">https://api.teeseng.uk/api/v0/location/update</code>
|
||||
<br>
|
||||
<br>
|
||||
Example :<br>
|
||||
<code class="higlighted break-word">curl https://api.teeseng.uk/api/v0/location/update -H "Content-Type: application/json" -X POST -d '{"id": "7" , "name": "SAMPLE", "added_by": "system" , "description": "test"}'</code>
|
||||
<br>
|
||||
<br>
|
||||
Return Response :<br>
|
||||
<code class="higlighted break-word">{"status":"200","message":"Location 7 updated"}</code>
|
||||
</p>
|
||||
<br>
|
||||
<h4>QUERY PARAMETERS</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Authorization</td>
|
||||
<td>JSON</td>
|
||||
<td>Your API key.</td>
|
||||
<td>(Required) example: curl https://api.teeseng.uk/api/v0/location/update -H "Authorization: {provide your
|
||||
API key here}"</td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ID</td>
|
||||
<td>JSON</td>
|
||||
<td>Location ID</td>
|
||||
<td>(Required) Location ID Example: curl https://api.teeseng.uk/api/v0/location/update -H "Authorization: provide
|
||||
your API key here" -d '{"id": "7"}'</td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Location name</td>
|
||||
<td>JSON</td>
|
||||
<td>Location name.</td>
|
||||
<td>(Optional) Location name. Example: curl https://api.teeseng.uk/api/v0/location/new -H "Authorization: provide
|
||||
your API key here" -d '{"name":"Location name"}'</td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Added by </td>
|
||||
<td>JSON</td>
|
||||
<td>System or Admin</td>
|
||||
<td>(Optional) System or Admin Example: curl https://api.teeseng.uk/api/v0/location/new -H "Authorization: provide
|
||||
your API key here" -d '{"added_by":"system"}'</td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>JSON</td>
|
||||
<td>Description of Location</td>
|
||||
<td>(Optional) System or Admin Example: curl https://api.teeseng.uk/api/v0/location/new -H "Authorization: provide
|
||||
your API key here" -d '{"description":"test"}'</td>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- delete location -->
|
||||
<div class="overflow-hidden content-section" id="content-update-location-by-id">
|
||||
<h2>Delete Location (Only for system or admin API key)</h2>
|
||||
<p>
|
||||
To delete an Location you need to make a DELETE call to the following url :<br>
|
||||
<code class="higlighted break-word">https://api.teeseng.uk/api/v0/location/delete</code>
|
||||
<br>
|
||||
<br>
|
||||
Example :<br>
|
||||
<code class="higlighted break-word">curl https://api.teeseng.uk/api/v0/location/delete -H "Content-Type: application/json" -X POST -d '{"id": "7"}'</code>
|
||||
</p>
|
||||
<br>
|
||||
<h4>QUERY PARAMETERS</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Authorization</td>
|
||||
<td>JSON</td>
|
||||
<td>Your API key.</td>
|
||||
<td>(Required) example: curl https://api.teeseng.uk/api/v0/location/delete -H "Authorization: {provide your
|
||||
API key here}"</td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ID</td>
|
||||
<td>JSON</td>
|
||||
<td>Location ID</td>
|
||||
<td>(Required) Location ID Example: curl https://api.teeseng.uk/api/v0/location/delete -H "Authorization: provide
|
||||
your API key here" -d '{"id": "7"}'</td>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="overflow-hidden content-section" id="content-errors">
|
||||
<h2>Errors</h2>
|
||||
<p>
|
||||
@ -128,25 +331,30 @@
|
||||
<tr>
|
||||
<td>X000</td>
|
||||
<td>
|
||||
Some parameters are missing. This error appears when you don't pass every mandatory parameters.
|
||||
Some parameters are missing. This error appears when you don't pass every mandatory
|
||||
parameters.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X001</td>
|
||||
<td>403</td>
|
||||
<td>
|
||||
Unknown or unvalid <code class="higlighted">secret_key</code>. This error appears if you use an unknow API key or if your API key expired.
|
||||
Unknown or unvalid <code class="higlighted">secret_key</code>. This error appears if
|
||||
you use an unknow API key or if your API key expired.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X002</td>
|
||||
<td>500</td>
|
||||
<td>
|
||||
Unvalid <code class="higlighted">secret_key</code> for this domain. This error appears if you use an API key non specified for your domain. Developper or Universal API keys doesn't have domain checker.
|
||||
Unvalid <code class="higlighted">secret_key</code> No API key was supplied. Invalid
|
||||
request.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>X003</td>
|
||||
<td>
|
||||
Unknown or unvalid user <code class="higlighted">token</code>. This error appears if you use an unknow user <code class="higlighted">token</code> or if the user <code class="higlighted">token</code> expired.
|
||||
Unknown or unvalid user <code class="higlighted">token</code>. This error appears if
|
||||
you use an unknow user <code class="higlighted">token</code> or if the user <code
|
||||
class="higlighted">token</code> expired.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -158,4 +366,3 @@
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
@ -82,9 +82,6 @@
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap core JavaScript -->
|
||||
<script src="vendor/jquery/jquery.min.js"></script>
|
||||
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/learnmore.js"></script>
|
||||
<script src="js/search.js"></script>
|
||||
<script src="js/api.js"></script>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<input type="text" id="email" placeholder="Email" required />
|
||||
<input type="password" id="password" placeholder="Password" required />
|
||||
<input type="password" id="confirmPassword" placeholder="Confirm Password" required />
|
||||
<input type="submit" onclick="validateReset()" value="Reset Password" />
|
||||
<input type="submit" value="Reset Password" />
|
||||
</form>
|
||||
<br>
|
||||
<a>Dont have an account?</a> <a href="/login">Sign Up</a>
|
||||
|
@ -91,7 +91,6 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<title>EcoSaver - Your Air Quality Index Source</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
|
||||
</head>
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.1/mustache.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.1/mustache.js"></script>
|
||||
|
||||
|
||||
<!-- jquery app.js -->
|
||||
<script src="js/app.js"></script>
|
||||
|
||||
@ -83,7 +82,7 @@
|
||||
</li>
|
||||
<!-- profile button -->
|
||||
<div class="form-inline mt-2 mt-md-0">
|
||||
<a id="cl-profile-button" class="btn btn-outline-danger my-2 my-sm-0" href="/profile"
|
||||
<a id="cl-profile-button" class="btn btn-outline-info my-2 my-sm-0" href="/profile"
|
||||
style="display: none;">
|
||||
<i class="fas fa-sign-out"></i>
|
||||
Profile
|
||||
|
@ -1,6 +1,7 @@
|
||||
<%- include('logintop') %>
|
||||
<script type="text/javascript">
|
||||
app.auth.redirectIfLoggedIn();
|
||||
// Require login to see this page.
|
||||
//app.auth.redirectIfLoggedIn();
|
||||
</script>
|
||||
|
||||
<body>
|
||||
@ -11,14 +12,18 @@
|
||||
<!-- localhost/api/v0/user/register -->
|
||||
<!-- evalAjax Fires when status 200 is returned -->
|
||||
<form action="auth/register" onsubmit="formAJAX(this)" evalAJAX="app.auth.logInRedirect();">
|
||||
<input type="text" name="firstname" placeholder="First Name" required />
|
||||
<input type="text" name="lastname" placeholder="Last Name" required />
|
||||
<input type="text" name="username" placeholder="Username" required />
|
||||
<input type="text" name="email" placeholder="Email" required />
|
||||
<input type="text" name="address" placeholder="Address" required />
|
||||
<input type="text" name="phone" placeholder="Phone Number" required />
|
||||
<input type="password" name="password" placeholder="Password" required />
|
||||
<input type="password" name="confirmPassword" placeholder="Confirm Password" required />
|
||||
<input type="text" name="firstname" placeholder="First Name" required pattern="^[a-zA-Z\s]+$" />
|
||||
<input type="text" name="lastname" placeholder="Last Name" required pattern="^[a-zA-Z\s]+$" />
|
||||
<input type="text" name="username" placeholder="Username" required pattern="^\w+$" />
|
||||
<input type="email" name="email" placeholder="Email" required
|
||||
pattern="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" />
|
||||
<input type="text" name="address" placeholder="Address" required
|
||||
pattern="^(\d{1,3}.)?.+\s(\d{6})$" />
|
||||
<input type="text" name="phone" placeholder="Phone Number" required
|
||||
pattern="^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,8}$" />
|
||||
<input type="password" id="password" name="password" placeholder="Password" required />
|
||||
<input type="password" id="confirmPassword" name="confirmPassword" placeholder="Confirm Password"
|
||||
required />
|
||||
<input type="submit" value="Signup" />
|
||||
</form>
|
||||
</div>
|
||||
@ -27,28 +32,41 @@
|
||||
<header>Login</header>
|
||||
<div class="card-header shadow actionMessage" style="display:none"></div>
|
||||
<!-- evalAjax Fires when status 200 is returned -->
|
||||
<form action="auth/login" onsubmit="formAJAX(this)"
|
||||
evalAJAX="app.auth.homeRedirect();
|
||||
app.auth.setToken(data.token);
|
||||
app.auth.setUserId(data.userid);
|
||||
app.auth.setUsername(data.username);
|
||||
">
|
||||
|
||||
<input type="text" name="userInfo" placeholder="Email address | Username" required />
|
||||
<form action="auth/login" onsubmit="formAJAX(this)" evalAJAX="app.auth.homeRedirect();
|
||||
app.auth.setToken(data.token);">
|
||||
<input type="text" name="username" placeholder="Email address | Username" required
|
||||
pattern="^\w+$" />
|
||||
<input type="password" name="password" placeholder="Password" required />
|
||||
<a href="/forgotPassword">Forgot password?</a>
|
||||
<input type="submit" value="Login" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<input type="text" name="userInfo" placeholder="Email address | Username" required />
|
||||
<input type="password" name="password" placeholder="Password" required />
|
||||
<a href="/resetPassword">Forgot password?</a>
|
||||
<a href="/forgotpassword">Forgot password?</a>
|
||||
<input type="submit" value="Login" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
//both password fields must match
|
||||
var password = document.getElementById("password");
|
||||
var confirm_password = document.getElementById("confirmPassword");
|
||||
|
||||
function validatePassword() {
|
||||
var passwordValue = password.value;
|
||||
|
||||
// Strong password regex pattern
|
||||
var strongPasswordPattern = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
|
||||
|
||||
if (passwordValue != confirm_password.value) {
|
||||
confirm_password.setCustomValidity("Passwords Don't Match");
|
||||
} else if (!strongPasswordPattern.test(passwordValue)) {
|
||||
confirm_password.setCustomValidity("Password must be at least 8 characters long and include at least one letter, one number, and one special character.");
|
||||
} else {
|
||||
confirm_password.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
|
||||
password.onchange = validatePassword;
|
||||
confirm_password.onkeyup = validatePassword;
|
||||
|
||||
|
||||
|
||||
const wrapper = document.querySelector(".wrapper"),
|
||||
signupHeader = document.querySelector(".signup header"),
|
||||
loginHeader = document.querySelector(".login header");
|
||||
|
@ -33,10 +33,8 @@
|
||||
<!-- Mustache JS -->
|
||||
<script src="https://sso.theta42.com/static/js/mustache.min.js"></script>
|
||||
<!-- jQuery library -->
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.7.1.min.js"
|
||||
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||
|
||||
<!-- Bootstrap 5 JavaScript -->
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
|
||||
@ -63,6 +61,7 @@
|
||||
//check if user is logged in
|
||||
app.auth.isLoggedIn(function (error, data) {
|
||||
if (data) {
|
||||
app.auth.showUser();
|
||||
$("#cl-logout-button").show("fast");
|
||||
$("#cl-profile-button").show("fast");
|
||||
$("#cl-login-button").hide("fast");
|
||||
@ -72,6 +71,7 @@
|
||||
$("body").show("fast");
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<body>
|
||||
@ -94,7 +94,7 @@
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li jq-repeat="getUsername" class="nav-item">
|
||||
{{ username }}
|
||||
<a class="nav-link"> Welcome {{ user.username }} </a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
|
2998
package-lock.json
generated
2998
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -35,14 +35,13 @@
|
||||
"mqtt": "^5.3.3",
|
||||
"mysql2": "^3.7.1",
|
||||
"node-fetch": "^3.3.2",
|
||||
"nodemailer": "^6.9.7",
|
||||
"nodemailer": "^6.9.8",
|
||||
"otp-generator": "^4.0.1",
|
||||
"otplib": "^12.0.1",
|
||||
"qrcode": "^1.5.3",
|
||||
"sanitize-html": "^2.11.0",
|
||||
"sequelize": "^6.35.2",
|
||||
"sequelize-cli": "^6.6.2",
|
||||
"sql": "^0.78.0",
|
||||
"validator": "^13.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
17
webserver/functions/getAPIKey.js
Normal file
17
webserver/functions/getAPIKey.js
Normal file
@ -0,0 +1,17 @@
|
||||
//model for getting API key from database
|
||||
|
||||
async function getAPIKey() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = { getAPIKey }
|
@ -1,39 +1,45 @@
|
||||
const { checkAPikey } = require('../functions/database.js');
|
||||
const { checkAPikey } = require("../functions/database.js");
|
||||
async function apikeyCheck(req, res, next) {
|
||||
//const authHeader = req.headers.authorization
|
||||
try {
|
||||
let apikey = req.headers.authorization
|
||||
let apikey = req.headers.authorization;
|
||||
if (!apikey) {
|
||||
throw new Error('No API key was supplied. Invalid request')
|
||||
}
|
||||
else{
|
||||
res.status(401).json({
|
||||
message: "No API key was supplied. Invalid request",
|
||||
});
|
||||
//throw new Error("No API key was supplied. Invalid request");
|
||||
} else {
|
||||
//split the string by the -
|
||||
let splitAPIkey = apikey.split('-');
|
||||
let splitAPIkey = apikey.split("-");
|
||||
let rowid = splitAPIkey[0];
|
||||
|
||||
//rejoin withouth the rowid
|
||||
let SuppliedKey = splitAPIkey.slice(1).join('-');
|
||||
if (checkAPikey(SuppliedKey , rowid))
|
||||
{
|
||||
let SuppliedKey = splitAPIkey.slice(1).join("-");
|
||||
if (checkAPikey(SuppliedKey, rowid)) {
|
||||
//get permission
|
||||
let permission = await checkAPikey(SuppliedKey, rowid);
|
||||
console.log(permission);
|
||||
if (req.method === 'GET' && permission === 'canRead'){
|
||||
return next()
|
||||
if (req.method === "GET" && permission === "canRead") {
|
||||
return next();
|
||||
}
|
||||
//['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)
|
||||
if (["GET" , "POST" , "PUT" , "DELETE"].includes(req.method) && permission === 'canWrite'){
|
||||
console.log('write')
|
||||
return next()
|
||||
if (
|
||||
["GET", "POST", "PUT", "DELETE"].includes(req.method) &&
|
||||
permission === "canWrite"
|
||||
) {
|
||||
console.log("write");
|
||||
return next();
|
||||
}
|
||||
throw new Error('Your API key does not have the correct permissions to access this resource')
|
||||
|
||||
//throw status 403
|
||||
res.status(403).json({
|
||||
message:
|
||||
"Your API key does not have the correct permissions to access this resource",
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = { apikeyCheck };
|
||||
|
Loading…
x
Reference in New Issue
Block a user