This commit is contained in:
Leo committed 2024-01-22 14:37:27 +08:00
commit 7dceee0b79
42 files changed
+3294 -5920

No files matched your search

-136
View File
@@ -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.');
}
}
+3
View File
@@ -37,6 +37,9 @@ module.exports = (sequelize) => {
reset_token_expiry: {
type: DataTypes.DATE,
},
sessionid: {
type: DataTypes.STRING,
},
}, {
hooks: {
beforeCreate: async (user) => {
+62 -10
View File
@@ -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,7 +205,20 @@ 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;
req.session.sessionToken = sessionToken;
@@ -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 } });
@@ -709,13 +752,22 @@ app.delete('/api/deleteUser/:username', async (req, res) => {
const { username } = req.params;
const creatorUsername = req.session.username;
try {
// Extract CSRF token from the request body
try {
// 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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

+58
View 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;
}
+1 -60
View File
@@ -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">
-107
View File
@@ -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;
}, {});
}
});
-64
View File
@@ -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;
+12 -10
View File
@@ -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>
+4 -4
View File
@@ -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
View 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;
}
+1 -69
View File
@@ -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">
-146
View File
@@ -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
View 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;
}
+1 -52
View File
@@ -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>
-162
View File
@@ -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;
}
}
-10
View File
@@ -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>
+3 -2
View File
@@ -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
View 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 };
+4
View File
@@ -254,3 +254,7 @@ form
color: #4eae3a;
border-color: #4eae3a;
}
a {
color: black;
}
+1 -1
View File
@@ -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;
}
Whitespace-only changes.
+29 -39
View File
@@ -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
@@ -210,14 +201,14 @@ app.auth = (function (app) {
}
function forceLogin() {
app.auth.isLoggedIn(function (error, isLoggedIn) {
if (error || !isLoggedIn) {
app.auth.logOut(function () {
location.replace(`/login`);
});
}
});
}
app.auth.isLoggedIn(function (error, isLoggedIn) {
if (error || !isLoggedIn) {
app.auth.logOut(function () {
location.replace(`/login`);
});
}
});
}
function logInRedirect() {
window.location.href =
@@ -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);
-3
View File
@@ -283,9 +283,6 @@
};
$( document ).ready( function(){
console.log('jq-repeat', $.scope)
//$.jqrepeat = $.scope
$( '[jq-repeat]' ).each(function(key, value){
make(value);
});
@@ -1,7 +0,0 @@
/*!
* Bootstrap v4.1.1 (https://getbootstrap.com/)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weigLine truncated
/*# sourceMappingURL=bootstrap.min.css.map */
File diff suppressed because it is too large. Load diff
-2
View File
@@ -1,2 +0,0 @@
/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:n.sort,splice:n.splice},w.extend=w.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||g(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],a!==(r=e[t])&&(l&&r&&(w.isPlainObject(r)||(i=Array.isArray(r)))?(i?(i=!1,o=n&&Array.isArray(n)?n:[]):o=n&&w.isPlainObject(n)?n:{},a[t]=w.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},w.extend({expando:"jQuery"+("3.3.1"+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==c.call(e))&&(!(t=i(e))||"function"==typeof(n=f.call(t,"constructor")&&t.constructor)&&p.call(n)===d)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e){m(e)},each:function(e,t){var n,r=0;if(C(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(C(Object(e))?w.merge(n,"string"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:u.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)(r=!t(e[o],o))!==s&&i.push(e[o]);return i},map:function(e,t,n){var r,i,o=0,s=[];if(C(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&s.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&s.push(i);return a.apply([],s)},guid:1,support:h}),"function"==typeof Symbol&&(w.fn[Symbol.iterator]=n[Symbol.iterator]),w.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function C(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!g(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},P="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",I="\\["+M+"*("+R+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+R+"))|)"+M+"*\\]",W=":("+R+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+I+")*)|.*)\\)|)",$=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),F=new RegExp("^"+M+"*,"+M+"*"),_=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)Line truncated
+6 -2
View File
@@ -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;
+2 -2
View File
@@ -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
+1 -2
View File
@@ -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{
+356 -149
View File
@@ -8,154 +8,361 @@
<%- include('top') %>
<link rel="stylesheet" href="css/api.css" media="all">
<body class="one-content-column-version">
<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" />
<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>
</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>
<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>
</li>
<li class="scroll-to-link" data-target="content-errors">
<a>Errors</a>
</li>
</ul>
</div>
</div>
<div class="content-page">
<div class="content">
<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.
</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.
</p>
</div>
<div class="overflow-hidden content-section" id="content-get-characters">
<h2>get characters</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>
</p>
<br>
<h4>QUERY PARAMETERS</h4>
<table>
<thead>
<tr>
<th>Field</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>secret_key</td>
<td>String</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>
</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-errors">
<h2>Errors</h2>
<p>
The Westeros API uses the following error codes:
</p>
<table>
<thead>
<tr>
<th>Error Code</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>X000</td>
<td>
Some parameters are missing. This error appears when you don't pass every mandatory parameters.
</td>
</tr>
<tr>
<td>X001</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.
</td>
</tr>
<tr>
<td>X002</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.
</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.
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<body class="one-content-column-version">
<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" />
<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>
</button>
</div>
<div class="mobile-menu-closer"></div>
<div class="content-menu">
<div class="content-infos">
<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 Data From API</a>
</li>
<li class="scroll-to-link" data-target="content-errors">
<a>Errors</a>
</li>
</ul>
</div>
</div>
</body>
</html>
<div class="content-page">
<div class="content">
<div class="overflow-hidden content-section" id="content-get-started">
<h1>Get started</h1>
<p>
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>.
</p>
</div>
<div class="overflow-hidden content-section" id="content-get-location">
<h2>Get all location</h2>
<p>
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>
<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 -H "Authorization: {provide your
API key here}"</td>
</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>
The Westeros API uses the following error codes:
</p>
<table>
<thead>
<tr>
<th>Error Code</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>X000</td>
<td>
Some parameters are missing. This error appears when you don't pass every mandatory
parameters.
</td>
</tr>
<tr>
<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.
</td>
</tr>
<tr>
<td>500</td>
<td>
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.
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
-3
View File
@@ -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>
+1 -1
View File
@@ -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>
-1
View File
@@ -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>
+1 -2
View File
@@ -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
+47 -29
View File
@@ -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,44 +12,61 @@
<!-- 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>
<div class="form login iot-card">
<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 />
<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 />
<div class="form login iot-card">
<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);">
<input type="text" name="username" placeholder="Email address | Username" required
pattern="^\w+$" />
<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");
+6 -6
View File
@@ -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");
@@ -71,7 +70,8 @@
}
$("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>
+2500 -894
View File
File diff suppressed because it is too large. Load diff
+1 -2
View File
@@ -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
View File
@@ -0,0 +1,17 @@
//model for getting API key from database
async function getAPIKey() {
}
module.exports = { getAPIKey }
+41 -35
View File
@@ -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
if(!apikey){
throw new Error('No API key was supplied. Invalid request')
}
else{
//split the string by the -
let splitAPIkey = apikey.split('-');
let rowid = splitAPIkey[0];
//rejoin withouth the 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()
}
//['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)
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')
}
}
}catch(error){
next(error);
}
//const authHeader = req.headers.authorization
try {
let apikey = req.headers.authorization;
if (!apikey) {
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 rowid = splitAPIkey[0];
//rejoin withouth the 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();
}
//['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)
if (
["GET", "POST", "PUT", "DELETE"].includes(req.method) &&
permission === "canWrite"
) {
console.log("write");
return next();
}
//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 };
@@ -56,4 +62,4 @@ If it's correct API key and has canWrite perms
I allow it to access put and post
*/
*/