Add CORS middleware and user database schema
- Implemented CORS middleware in the project to handle cross-origin requests. - Added necessary files for the CORS package including README, LICENSE, and history documentation. - Created a SQL schema for the users table with appropriate fields and constraints. - Inserted mock data into the users table for testing purposes.
This commit is contained in:
4
backend/.env
Executable file
4
backend/.env
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
DB_HOST=mysql
|
||||||
|
DB_USER=root
|
||||||
|
DB_PASSWORD=D7Ze0lwV9hMrNQHdz1Q8yi0MIQuOO8
|
||||||
|
DB_NAME=bikelane
|
142
backend/database.js
Normal file
142
backend/database.js
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import mysql from "mysql2";
|
||||||
|
import dotenv from "dotenv";
|
||||||
|
import { error } from "console";
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
// Create a MySQL connection pool using environment variables for configuration
|
||||||
|
const pool = mysql
|
||||||
|
.createPool({
|
||||||
|
host: process.env.DB_HOST,
|
||||||
|
user: process.env.DB_USER,
|
||||||
|
password: process.env.DB_PASSWORD,
|
||||||
|
database: process.env.DB_NAME,
|
||||||
|
})
|
||||||
|
.promise();
|
||||||
|
|
||||||
|
// Function to authenticate a user by username and password
|
||||||
|
export async function loginUser(username, password) {
|
||||||
|
// Query the users table for a matching username and password
|
||||||
|
const [result] = await pool.query(
|
||||||
|
"SELECT * FROM users WHERE username = ? AND password = ?",
|
||||||
|
[username, password]
|
||||||
|
);
|
||||||
|
|
||||||
|
// If a user is found, return success and user data
|
||||||
|
if (result.length > 0) {
|
||||||
|
console.log("User found: ", result[0].username, " ", result[0].id);
|
||||||
|
return { success: true, user: result[0] };
|
||||||
|
} else {
|
||||||
|
// If no user is found, return failure message
|
||||||
|
console.error(`Invalid username or password!; ${result[0]}`);
|
||||||
|
return { success: false, message: "Invalid username or password" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to create a new user in the database
|
||||||
|
export async function createUser(
|
||||||
|
username,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
password,
|
||||||
|
email
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Insert a new user record into the users table
|
||||||
|
const [result] = await pool.query(
|
||||||
|
"INSERT INTO users (username, first_name, last_name, password, email) VALUES (?, ?, ?, ?, ?)",
|
||||||
|
[username, first_name, last_name, password, email]
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("User created successfully!");
|
||||||
|
return { success: true, message: "User created successfully!" };
|
||||||
|
} catch (error) {
|
||||||
|
// Handle errors during user creation
|
||||||
|
console.log("Error creating user: ", error);
|
||||||
|
return { success: false, message: "Error creating user!" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to update an existing user's information
|
||||||
|
export async function updateUser(
|
||||||
|
username,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
password,
|
||||||
|
email
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Update user details based on username
|
||||||
|
const [result] = await pool.query(
|
||||||
|
"UPDATE users SET first_name = ?, last_name = ?, password = ?, email = ? WHERE username = ?",
|
||||||
|
[first_name, last_name, password, email, username]
|
||||||
|
);
|
||||||
|
const resultOfquery = result.affectedRows;
|
||||||
|
|
||||||
|
// If a user was updated, return success
|
||||||
|
if (resultOfquery > 0) {
|
||||||
|
console.log("User updated successfully!");
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "User updated successfully!",
|
||||||
|
resultOfquery: result,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no user was updated, return failure
|
||||||
|
if (resultOfquery === 0) {
|
||||||
|
console.log("Error updating user!");
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error updating user!",
|
||||||
|
resultOfquery: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (err) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to delete a user from the database
|
||||||
|
export async function deleteUser(
|
||||||
|
username,
|
||||||
|
first_name,
|
||||||
|
last_name,
|
||||||
|
password,
|
||||||
|
email
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Delete user based on username and password
|
||||||
|
const [result] = await pool.query(
|
||||||
|
"DELETE FROM users WHERE username = ? AND password = ?",
|
||||||
|
[username, password]
|
||||||
|
);
|
||||||
|
const resultOfquery = result.affectedRows;
|
||||||
|
|
||||||
|
// If a user was deleted, return success
|
||||||
|
if (resultOfquery > 0) {
|
||||||
|
console.log("User deleted successfully!");
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "User deleted successfully!",
|
||||||
|
resultOfquery: result,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no user was deleted, return failure
|
||||||
|
if (resultOfquery === 0) {
|
||||||
|
console.log("Error deleting user!");
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error deleting user!",
|
||||||
|
resultOfquery: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (err) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAllUsers() {
|
||||||
|
try {
|
||||||
|
const [data] = await pool.query("SELECT * FROM users;");
|
||||||
|
return { result: data, success: true };
|
||||||
|
} catch (err) {
|
||||||
|
return { result: err, success: false };
|
||||||
|
}
|
||||||
|
}
|
148
backend/package-lock.json
generated
148
backend/package-lock.json
generated
@@ -9,8 +9,11 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^17.2.0",
|
||||||
"ejs": "^3.1.10",
|
"ejs": "^3.1.10",
|
||||||
"express": "^5.1.0"
|
"express": "^5.1.0",
|
||||||
|
"mysql2": "^3.14.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
@@ -47,6 +50,15 @@
|
|||||||
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/aws-ssl-profiles": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -200,6 +212,19 @@
|
|||||||
"node": ">=6.6.0"
|
"node": ">=6.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cors": {
|
||||||
|
"version": "2.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||||
|
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"object-assign": "^4",
|
||||||
|
"vary": "^1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
||||||
@@ -217,6 +242,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/denque": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
@@ -226,6 +260,18 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dotenv": {
|
||||||
|
"version": "17.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.0.tgz",
|
||||||
|
"integrity": "sha512-Q4sgBT60gzd0BB0lSyYD3xM4YxrXA9y4uBDof1JNYGzOXrQdQ6yX+7XIAqoFOGQFOTK1D3Hts5OllpxMDZFONQ==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dunder-proto": {
|
"node_modules/dunder-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
@@ -431,6 +477,15 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/generate-function": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-property": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-intrinsic": {
|
"node_modules/get-intrinsic": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
@@ -571,6 +626,12 @@
|
|||||||
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/is-property": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/jake": {
|
"node_modules/jake": {
|
||||||
"version": "10.9.2",
|
"version": "10.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz",
|
||||||
@@ -589,6 +650,36 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/long": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/lru-cache": {
|
||||||
|
"version": "7.18.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
|
||||||
|
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lru.min": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"bun": ">=1.0.0",
|
||||||
|
"deno": ">=1.30.0",
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wellwelwel"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
@@ -658,6 +749,38 @@
|
|||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/mysql2": {
|
||||||
|
"version": "3.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.14.2.tgz",
|
||||||
|
"integrity": "sha512-YD6mZMeoypmheHT6b2BrVmQFvouEpRICuvPIREulx2OvP1xAxxeqkMQqZSTBefv0PiOBKGYFa2zQtY+gf/4eQw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"aws-ssl-profiles": "^1.1.1",
|
||||||
|
"denque": "^2.1.0",
|
||||||
|
"generate-function": "^2.3.1",
|
||||||
|
"iconv-lite": "^0.6.3",
|
||||||
|
"long": "^5.2.1",
|
||||||
|
"lru.min": "^1.0.0",
|
||||||
|
"named-placeholders": "^1.1.3",
|
||||||
|
"seq-queue": "^0.0.5",
|
||||||
|
"sqlstring": "^2.3.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/named-placeholders": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"lru-cache": "^7.14.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/negotiator": {
|
"node_modules/negotiator": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
||||||
@@ -667,6 +790,15 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/object-inspect": {
|
"node_modules/object-inspect": {
|
||||||
"version": "1.13.4",
|
"version": "1.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||||
@@ -834,6 +966,11 @@
|
|||||||
"node": ">= 18"
|
"node": ">= 18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/seq-queue": {
|
||||||
|
"version": "0.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
|
||||||
|
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
|
||||||
|
},
|
||||||
"node_modules/serve-static": {
|
"node_modules/serve-static": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
||||||
@@ -927,6 +1064,15 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sqlstring": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||||
|
@@ -12,7 +12,10 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^17.2.0",
|
||||||
"ejs": "^3.1.10",
|
"ejs": "^3.1.10",
|
||||||
"express": "^5.1.0"
|
"express": "^5.1.0",
|
||||||
|
"mysql2": "^3.14.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +1,46 @@
|
|||||||
//statics
|
//statics
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
import cors from "cors";
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 5002;
|
const port = 5002;
|
||||||
|
import {
|
||||||
|
loginUser,
|
||||||
|
createUser,
|
||||||
|
updateUser,
|
||||||
|
deleteUser,
|
||||||
|
getAllUsers,
|
||||||
|
} from "./database.js";
|
||||||
|
|
||||||
//view engine ejs
|
//view engine ejs
|
||||||
app.set("view engine", "ejs");
|
app.set("view engine", "ejs");
|
||||||
|
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
app.use(cors());
|
||||||
|
|
||||||
app.get("/", (req, res) => {
|
app.get("/", (req, res) => {
|
||||||
res.render("index.ejs");
|
res.render("index.ejs");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post("/api/login", async (req, res) => {
|
||||||
|
console.log(req.body);
|
||||||
|
|
||||||
|
loginUser(req.body.username, req.body.password)
|
||||||
|
.then((result) => {
|
||||||
|
if (result.success) {
|
||||||
|
res.status(200).json(result);
|
||||||
|
} else {
|
||||||
|
res.status(401).json(result);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Error logging in:", err);
|
||||||
|
res
|
||||||
|
.status(500)
|
||||||
|
.json({ success: false, message: "Internal server error" });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Server is running at http://localhost:${port}`);
|
console.log(`Server is running at http://localhost:${port}`);
|
||||||
});
|
});
|
||||||
|
@@ -1,35 +1,66 @@
|
|||||||
import { useState } from 'react'
|
import React, { useState } from "react";
|
||||||
import reactLogo from './assets/react.svg'
|
import "./App.css";
|
||||||
import viteLogo from '/vite.svg'
|
|
||||||
import './App.css'
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [count, setCount] = useState(0)
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("http://localhost:5002/api/login", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
console.log("Login successful");
|
||||||
|
// Handle successful login here
|
||||||
|
} else {
|
||||||
|
console.log("Login failed");
|
||||||
|
// Handle login error here
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Login error:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://vite.dev" target="_blank">
|
<label htmlFor="username">Username:</label>
|
||||||
<img src={viteLogo} className="logo" alt="Vite logo" />
|
<input
|
||||||
</a>
|
type="text"
|
||||||
<a href="https://react.dev" target="_blank">
|
id="username"
|
||||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
name="username"
|
||||||
</a>
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h1>Vite + React</h1>
|
<div>
|
||||||
<div className="card">
|
<label htmlFor="password">Password:</label>
|
||||||
<button onClick={() => setCount((count) => count + 1)}>
|
<input
|
||||||
count is {count}
|
type="password"
|
||||||
</button>
|
id="password"
|
||||||
<p>
|
name="password"
|
||||||
Edit <code>src/App.tsx</code> and save to test HMR
|
value={password}
|
||||||
</p>
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="read-the-docs">
|
<button type="submit">Login</button>
|
||||||
Click on the Vite and React logos to learn more
|
</form>
|
||||||
</p>
|
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App;
|
||||||
|
0
client/src/layout/header.tsx
Normal file
0
client/src/layout/header.tsx
Normal file
38
node_modules/.package-lock.json
generated
vendored
Normal file
38
node_modules/.package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "bikelane",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"node_modules/cors": {
|
||||||
|
"version": "2.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||||
|
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"object-assign": "^4",
|
||||||
|
"vary": "^1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vary": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
node_modules/cors/CONTRIBUTING.md
generated
vendored
Normal file
33
node_modules/cors/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# contributing to `cors`
|
||||||
|
|
||||||
|
CORS is a node.js package for providing a [connect](http://www.senchalabs.org/connect/)/[express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options. Learn more about the project in [the README](README.md).
|
||||||
|
|
||||||
|
## The CORS Spec
|
||||||
|
|
||||||
|
[http://www.w3.org/TR/cors/](http://www.w3.org/TR/cors/)
|
||||||
|
|
||||||
|
## Pull Requests Welcome
|
||||||
|
|
||||||
|
* Include `'use strict';` in every javascript file.
|
||||||
|
* 2 space indentation.
|
||||||
|
* Please run the testing steps below before submitting.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install
|
||||||
|
$ npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Interactive Testing Harness
|
||||||
|
|
||||||
|
[http://node-cors-client.herokuapp.com](http://node-cors-client.herokuapp.com)
|
||||||
|
|
||||||
|
Related git repositories:
|
||||||
|
|
||||||
|
* [https://github.com/TroyGoode/node-cors-server](https://github.com/TroyGoode/node-cors-server)
|
||||||
|
* [https://github.com/TroyGoode/node-cors-client](https://github.com/TroyGoode/node-cors-client)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT License](http://www.opensource.org/licenses/mit-license.php)
|
58
node_modules/cors/HISTORY.md
generated
vendored
Normal file
58
node_modules/cors/HISTORY.md
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
2.8.5 / 2018-11-04
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix setting `maxAge` option to `0`
|
||||||
|
|
||||||
|
2.8.4 / 2017-07-12
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Work-around Safari bug in default pre-flight response
|
||||||
|
|
||||||
|
2.8.3 / 2017-03-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix error when options delegate missing `methods` option
|
||||||
|
|
||||||
|
2.8.2 / 2017-03-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix error when frozen options are passed
|
||||||
|
* Send "Vary: Origin" when using regular expressions
|
||||||
|
* Send "Vary: Access-Control-Request-Headers" when dynamic `allowedHeaders`
|
||||||
|
|
||||||
|
2.8.1 / 2016-09-08
|
||||||
|
==================
|
||||||
|
|
||||||
|
This release only changed documentation.
|
||||||
|
|
||||||
|
2.8.0 / 2016-08-23
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `optionsSuccessStatus` option
|
||||||
|
|
||||||
|
2.7.2 / 2016-08-23
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix error when Node.js running in strict mode
|
||||||
|
|
||||||
|
2.7.1 / 2015-05-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Move module into expressjs organization
|
||||||
|
|
||||||
|
2.7.0 / 2015-05-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Allow array of matching condition as `origin` option
|
||||||
|
* Allow regular expression as `origin` option
|
||||||
|
|
||||||
|
2.6.1 / 2015-05-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Update `license` in package.json
|
||||||
|
|
||||||
|
2.6.0 / 2015-04-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `preflightContinue` option
|
||||||
|
* Fix "Vary: Origin" header added for "*"
|
22
node_modules/cors/LICENSE
generated
vendored
Normal file
22
node_modules/cors/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2013 Troy Goode <troygoode@gmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
243
node_modules/cors/README.md
generated
vendored
Normal file
243
node_modules/cors/README.md
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
# cors
|
||||||
|
|
||||||
|
[![NPM Version][npm-image]][npm-url]
|
||||||
|
[![NPM Downloads][downloads-image]][downloads-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
CORS is a node.js package for providing a [Connect](http://www.senchalabs.org/connect/)/[Express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options.
|
||||||
|
|
||||||
|
**[Follow me (@troygoode) on Twitter!](https://twitter.com/intent/user?screen_name=troygoode)**
|
||||||
|
|
||||||
|
* [Installation](#installation)
|
||||||
|
* [Usage](#usage)
|
||||||
|
* [Simple Usage](#simple-usage-enable-all-cors-requests)
|
||||||
|
* [Enable CORS for a Single Route](#enable-cors-for-a-single-route)
|
||||||
|
* [Configuring CORS](#configuring-cors)
|
||||||
|
* [Configuring CORS Asynchronously](#configuring-cors-asynchronously)
|
||||||
|
* [Enabling CORS Pre-Flight](#enabling-cors-pre-flight)
|
||||||
|
* [Configuration Options](#configuration-options)
|
||||||
|
* [Demo](#demo)
|
||||||
|
* [License](#license)
|
||||||
|
* [Author](#author)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||||
|
[npm registry](https://www.npmjs.com/). Installation is done using the
|
||||||
|
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install cors
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Simple Usage (Enable *All* CORS Requests)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var express = require('express')
|
||||||
|
var cors = require('cors')
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
app.use(cors())
|
||||||
|
|
||||||
|
app.get('/products/:id', function (req, res, next) {
|
||||||
|
res.json({msg: 'This is CORS-enabled for all origins!'})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(80, function () {
|
||||||
|
console.log('CORS-enabled web server listening on port 80')
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enable CORS for a Single Route
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var express = require('express')
|
||||||
|
var cors = require('cors')
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
app.get('/products/:id', cors(), function (req, res, next) {
|
||||||
|
res.json({msg: 'This is CORS-enabled for a Single Route'})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(80, function () {
|
||||||
|
console.log('CORS-enabled web server listening on port 80')
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring CORS
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var express = require('express')
|
||||||
|
var cors = require('cors')
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
var corsOptions = {
|
||||||
|
origin: 'http://example.com',
|
||||||
|
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
|
||||||
|
res.json({msg: 'This is CORS-enabled for only example.com.'})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(80, function () {
|
||||||
|
console.log('CORS-enabled web server listening on port 80')
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring CORS w/ Dynamic Origin
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var express = require('express')
|
||||||
|
var cors = require('cors')
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
var whitelist = ['http://example1.com', 'http://example2.com']
|
||||||
|
var corsOptions = {
|
||||||
|
origin: function (origin, callback) {
|
||||||
|
if (whitelist.indexOf(origin) !== -1) {
|
||||||
|
callback(null, true)
|
||||||
|
} else {
|
||||||
|
callback(new Error('Not allowed by CORS'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
|
||||||
|
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(80, function () {
|
||||||
|
console.log('CORS-enabled web server listening on port 80')
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
If you do not want to block REST tools or server-to-server requests,
|
||||||
|
add a `!origin` check in the origin function like so:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var corsOptions = {
|
||||||
|
origin: function (origin, callback) {
|
||||||
|
if (whitelist.indexOf(origin) !== -1 || !origin) {
|
||||||
|
callback(null, true)
|
||||||
|
} else {
|
||||||
|
callback(new Error('Not allowed by CORS'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enabling CORS Pre-Flight
|
||||||
|
|
||||||
|
Certain CORS requests are considered 'complex' and require an initial
|
||||||
|
`OPTIONS` request (called the "pre-flight request"). An example of a
|
||||||
|
'complex' CORS request is one that uses an HTTP verb other than
|
||||||
|
GET/HEAD/POST (such as DELETE) or that uses custom headers. To enable
|
||||||
|
pre-flighting, you must add a new OPTIONS handler for the route you want
|
||||||
|
to support:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var express = require('express')
|
||||||
|
var cors = require('cors')
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
app.options('/products/:id', cors()) // enable pre-flight request for DELETE request
|
||||||
|
app.del('/products/:id', cors(), function (req, res, next) {
|
||||||
|
res.json({msg: 'This is CORS-enabled for all origins!'})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(80, function () {
|
||||||
|
console.log('CORS-enabled web server listening on port 80')
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also enable pre-flight across-the-board like so:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
app.options('*', cors()) // include before other routes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring CORS Asynchronously
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var express = require('express')
|
||||||
|
var cors = require('cors')
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
var whitelist = ['http://example1.com', 'http://example2.com']
|
||||||
|
var corsOptionsDelegate = function (req, callback) {
|
||||||
|
var corsOptions;
|
||||||
|
if (whitelist.indexOf(req.header('Origin')) !== -1) {
|
||||||
|
corsOptions = { origin: true } // reflect (enable) the requested origin in the CORS response
|
||||||
|
} else {
|
||||||
|
corsOptions = { origin: false } // disable CORS for this request
|
||||||
|
}
|
||||||
|
callback(null, corsOptions) // callback expects two parameters: error and options
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/products/:id', cors(corsOptionsDelegate), function (req, res, next) {
|
||||||
|
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(80, function () {
|
||||||
|
console.log('CORS-enabled web server listening on port 80')
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
* `origin`: Configures the **Access-Control-Allow-Origin** CORS header. Possible values:
|
||||||
|
- `Boolean` - set `origin` to `true` to reflect the [request origin](http://tools.ietf.org/html/draft-abarth-origin-09), as defined by `req.header('Origin')`, or set it to `false` to disable CORS.
|
||||||
|
- `String` - set `origin` to a specific origin. For example if you set it to `"http://example.com"` only requests from "http://example.com" will be allowed.
|
||||||
|
- `RegExp` - set `origin` to a regular expression pattern which will be used to test the request origin. If it's a match, the request origin will be reflected. For example the pattern `/example\.com$/` will reflect any request that is coming from an origin ending with "example.com".
|
||||||
|
- `Array` - set `origin` to an array of valid origins. Each origin can be a `String` or a `RegExp`. For example `["http://example1.com", /\.example2\.com$/]` will accept any request from "http://example1.com" or from a subdomain of "example2.com".
|
||||||
|
- `Function` - set `origin` to a function implementing some custom logic. The function takes the request origin as the first parameter and a callback (which expects the signature `err [object], allow [bool]`) as the second.
|
||||||
|
* `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: `['GET', 'PUT', 'POST']`).
|
||||||
|
* `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Type,Authorization') or an array (ex: `['Content-Type', 'Authorization']`). If not specified, defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header.
|
||||||
|
* `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range') or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed.
|
||||||
|
* `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header, otherwise it is omitted.
|
||||||
|
* `maxAge`: Configures the **Access-Control-Max-Age** CORS header. Set to an integer to pass the header, otherwise it is omitted.
|
||||||
|
* `preflightContinue`: Pass the CORS preflight response to the next handler.
|
||||||
|
* `optionsSuccessStatus`: Provides a status code to use for successful `OPTIONS` requests, since some legacy browsers (IE11, various SmartTVs) choke on `204`.
|
||||||
|
|
||||||
|
The default configuration is the equivalent of:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"origin": "*",
|
||||||
|
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
|
||||||
|
"preflightContinue": false,
|
||||||
|
"optionsSuccessStatus": 204
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For details on the effect of each CORS header, read [this](http://www.html5rocks.com/en/tutorials/cors/) article on HTML5 Rocks.
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
|
||||||
|
A demo that illustrates CORS working (and not working) using jQuery is available here: [http://node-cors-client.herokuapp.com/](http://node-cors-client.herokuapp.com/)
|
||||||
|
|
||||||
|
Code for that demo can be found here:
|
||||||
|
|
||||||
|
* Client: [https://github.com/TroyGoode/node-cors-client](https://github.com/TroyGoode/node-cors-client)
|
||||||
|
* Server: [https://github.com/TroyGoode/node-cors-server](https://github.com/TroyGoode/node-cors-server)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT License](http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
[Troy Goode](https://github.com/TroyGoode) ([troygoode@gmail.com](mailto:troygoode@gmail.com))
|
||||||
|
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/expressjs/cors/master.svg
|
||||||
|
[coveralls-url]: https://coveralls.io/r/expressjs/cors?branch=master
|
||||||
|
[downloads-image]: https://img.shields.io/npm/dm/cors.svg
|
||||||
|
[downloads-url]: https://npmjs.org/package/cors
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/cors.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/cors
|
||||||
|
[travis-image]: https://img.shields.io/travis/expressjs/cors/master.svg
|
||||||
|
[travis-url]: https://travis-ci.org/expressjs/cors
|
238
node_modules/cors/lib/index.js
generated
vendored
Normal file
238
node_modules/cors/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
(function () {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assign = require('object-assign');
|
||||||
|
var vary = require('vary');
|
||||||
|
|
||||||
|
var defaults = {
|
||||||
|
origin: '*',
|
||||||
|
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||||
|
preflightContinue: false,
|
||||||
|
optionsSuccessStatus: 204
|
||||||
|
};
|
||||||
|
|
||||||
|
function isString(s) {
|
||||||
|
return typeof s === 'string' || s instanceof String;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOriginAllowed(origin, allowedOrigin) {
|
||||||
|
if (Array.isArray(allowedOrigin)) {
|
||||||
|
for (var i = 0; i < allowedOrigin.length; ++i) {
|
||||||
|
if (isOriginAllowed(origin, allowedOrigin[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (isString(allowedOrigin)) {
|
||||||
|
return origin === allowedOrigin;
|
||||||
|
} else if (allowedOrigin instanceof RegExp) {
|
||||||
|
return allowedOrigin.test(origin);
|
||||||
|
} else {
|
||||||
|
return !!allowedOrigin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function configureOrigin(options, req) {
|
||||||
|
var requestOrigin = req.headers.origin,
|
||||||
|
headers = [],
|
||||||
|
isAllowed;
|
||||||
|
|
||||||
|
if (!options.origin || options.origin === '*') {
|
||||||
|
// allow any origin
|
||||||
|
headers.push([{
|
||||||
|
key: 'Access-Control-Allow-Origin',
|
||||||
|
value: '*'
|
||||||
|
}]);
|
||||||
|
} else if (isString(options.origin)) {
|
||||||
|
// fixed origin
|
||||||
|
headers.push([{
|
||||||
|
key: 'Access-Control-Allow-Origin',
|
||||||
|
value: options.origin
|
||||||
|
}]);
|
||||||
|
headers.push([{
|
||||||
|
key: 'Vary',
|
||||||
|
value: 'Origin'
|
||||||
|
}]);
|
||||||
|
} else {
|
||||||
|
isAllowed = isOriginAllowed(requestOrigin, options.origin);
|
||||||
|
// reflect origin
|
||||||
|
headers.push([{
|
||||||
|
key: 'Access-Control-Allow-Origin',
|
||||||
|
value: isAllowed ? requestOrigin : false
|
||||||
|
}]);
|
||||||
|
headers.push([{
|
||||||
|
key: 'Vary',
|
||||||
|
value: 'Origin'
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function configureMethods(options) {
|
||||||
|
var methods = options.methods;
|
||||||
|
if (methods.join) {
|
||||||
|
methods = options.methods.join(','); // .methods is an array, so turn it into a string
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
key: 'Access-Control-Allow-Methods',
|
||||||
|
value: methods
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function configureCredentials(options) {
|
||||||
|
if (options.credentials === true) {
|
||||||
|
return {
|
||||||
|
key: 'Access-Control-Allow-Credentials',
|
||||||
|
value: 'true'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function configureAllowedHeaders(options, req) {
|
||||||
|
var allowedHeaders = options.allowedHeaders || options.headers;
|
||||||
|
var headers = [];
|
||||||
|
|
||||||
|
if (!allowedHeaders) {
|
||||||
|
allowedHeaders = req.headers['access-control-request-headers']; // .headers wasn't specified, so reflect the request headers
|
||||||
|
headers.push([{
|
||||||
|
key: 'Vary',
|
||||||
|
value: 'Access-Control-Request-Headers'
|
||||||
|
}]);
|
||||||
|
} else if (allowedHeaders.join) {
|
||||||
|
allowedHeaders = allowedHeaders.join(','); // .headers is an array, so turn it into a string
|
||||||
|
}
|
||||||
|
if (allowedHeaders && allowedHeaders.length) {
|
||||||
|
headers.push([{
|
||||||
|
key: 'Access-Control-Allow-Headers',
|
||||||
|
value: allowedHeaders
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function configureExposedHeaders(options) {
|
||||||
|
var headers = options.exposedHeaders;
|
||||||
|
if (!headers) {
|
||||||
|
return null;
|
||||||
|
} else if (headers.join) {
|
||||||
|
headers = headers.join(','); // .headers is an array, so turn it into a string
|
||||||
|
}
|
||||||
|
if (headers && headers.length) {
|
||||||
|
return {
|
||||||
|
key: 'Access-Control-Expose-Headers',
|
||||||
|
value: headers
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function configureMaxAge(options) {
|
||||||
|
var maxAge = (typeof options.maxAge === 'number' || options.maxAge) && options.maxAge.toString()
|
||||||
|
if (maxAge && maxAge.length) {
|
||||||
|
return {
|
||||||
|
key: 'Access-Control-Max-Age',
|
||||||
|
value: maxAge
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyHeaders(headers, res) {
|
||||||
|
for (var i = 0, n = headers.length; i < n; i++) {
|
||||||
|
var header = headers[i];
|
||||||
|
if (header) {
|
||||||
|
if (Array.isArray(header)) {
|
||||||
|
applyHeaders(header, res);
|
||||||
|
} else if (header.key === 'Vary' && header.value) {
|
||||||
|
vary(res, header.value);
|
||||||
|
} else if (header.value) {
|
||||||
|
res.setHeader(header.key, header.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cors(options, req, res, next) {
|
||||||
|
var headers = [],
|
||||||
|
method = req.method && req.method.toUpperCase && req.method.toUpperCase();
|
||||||
|
|
||||||
|
if (method === 'OPTIONS') {
|
||||||
|
// preflight
|
||||||
|
headers.push(configureOrigin(options, req));
|
||||||
|
headers.push(configureCredentials(options, req));
|
||||||
|
headers.push(configureMethods(options, req));
|
||||||
|
headers.push(configureAllowedHeaders(options, req));
|
||||||
|
headers.push(configureMaxAge(options, req));
|
||||||
|
headers.push(configureExposedHeaders(options, req));
|
||||||
|
applyHeaders(headers, res);
|
||||||
|
|
||||||
|
if (options.preflightContinue) {
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
// Safari (and potentially other browsers) need content-length 0,
|
||||||
|
// for 204 or they just hang waiting for a body
|
||||||
|
res.statusCode = options.optionsSuccessStatus;
|
||||||
|
res.setHeader('Content-Length', '0');
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// actual response
|
||||||
|
headers.push(configureOrigin(options, req));
|
||||||
|
headers.push(configureCredentials(options, req));
|
||||||
|
headers.push(configureExposedHeaders(options, req));
|
||||||
|
applyHeaders(headers, res);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function middlewareWrapper(o) {
|
||||||
|
// if options are static (either via defaults or custom options passed in), wrap in a function
|
||||||
|
var optionsCallback = null;
|
||||||
|
if (typeof o === 'function') {
|
||||||
|
optionsCallback = o;
|
||||||
|
} else {
|
||||||
|
optionsCallback = function (req, cb) {
|
||||||
|
cb(null, o);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return function corsMiddleware(req, res, next) {
|
||||||
|
optionsCallback(req, function (err, options) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
} else {
|
||||||
|
var corsOptions = assign({}, defaults, options);
|
||||||
|
var originCallback = null;
|
||||||
|
if (corsOptions.origin && typeof corsOptions.origin === 'function') {
|
||||||
|
originCallback = corsOptions.origin;
|
||||||
|
} else if (corsOptions.origin) {
|
||||||
|
originCallback = function (origin, cb) {
|
||||||
|
cb(null, corsOptions.origin);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (originCallback) {
|
||||||
|
originCallback(req.headers.origin, function (err2, origin) {
|
||||||
|
if (err2 || !origin) {
|
||||||
|
next(err2);
|
||||||
|
} else {
|
||||||
|
corsOptions.origin = origin;
|
||||||
|
cors(corsOptions, req, res, next);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// can pass either an options hash, an options delegate, or nothing
|
||||||
|
module.exports = middlewareWrapper;
|
||||||
|
|
||||||
|
}());
|
41
node_modules/cors/package.json
generated
vendored
Normal file
41
node_modules/cors/package.json
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "cors",
|
||||||
|
"description": "Node.js CORS middleware",
|
||||||
|
"version": "2.8.5",
|
||||||
|
"author": "Troy Goode <troygoode@gmail.com> (https://github.com/troygoode/)",
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"cors",
|
||||||
|
"express",
|
||||||
|
"connect",
|
||||||
|
"middleware"
|
||||||
|
],
|
||||||
|
"repository": "expressjs/cors",
|
||||||
|
"main": "./lib/index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"object-assign": "^4",
|
||||||
|
"vary": "^1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"after": "0.8.2",
|
||||||
|
"eslint": "2.13.1",
|
||||||
|
"express": "4.16.3",
|
||||||
|
"mocha": "5.2.0",
|
||||||
|
"nyc": "13.1.0",
|
||||||
|
"supertest": "3.3.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/index.js",
|
||||||
|
"CONTRIBUTING.md",
|
||||||
|
"HISTORY.md",
|
||||||
|
"LICENSE",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "npm run lint && nyc --reporter=html --reporter=text mocha --require test/support/env",
|
||||||
|
"lint": "eslint lib test"
|
||||||
|
}
|
||||||
|
}
|
90
node_modules/object-assign/index.js
generated
vendored
Normal file
90
node_modules/object-assign/index.js
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
object-assign
|
||||||
|
(c) Sindre Sorhus
|
||||||
|
@license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
|
||||||
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||||
|
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
|
||||||
|
|
||||||
|
function toObject(val) {
|
||||||
|
if (val === null || val === undefined) {
|
||||||
|
throw new TypeError('Object.assign cannot be called with null or undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldUseNative() {
|
||||||
|
try {
|
||||||
|
if (!Object.assign) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect buggy property enumeration order in older V8 versions.
|
||||||
|
|
||||||
|
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
|
||||||
|
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
|
||||||
|
test1[5] = 'de';
|
||||||
|
if (Object.getOwnPropertyNames(test1)[0] === '5') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
|
||||||
|
var test2 = {};
|
||||||
|
for (var i = 0; i < 10; i++) {
|
||||||
|
test2['_' + String.fromCharCode(i)] = i;
|
||||||
|
}
|
||||||
|
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
|
||||||
|
return test2[n];
|
||||||
|
});
|
||||||
|
if (order2.join('') !== '0123456789') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
|
||||||
|
var test3 = {};
|
||||||
|
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
|
||||||
|
test3[letter] = letter;
|
||||||
|
});
|
||||||
|
if (Object.keys(Object.assign({}, test3)).join('') !==
|
||||||
|
'abcdefghijklmnopqrst') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
// We don't expect any of the above to throw, but better to be safe.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
|
||||||
|
var from;
|
||||||
|
var to = toObject(target);
|
||||||
|
var symbols;
|
||||||
|
|
||||||
|
for (var s = 1; s < arguments.length; s++) {
|
||||||
|
from = Object(arguments[s]);
|
||||||
|
|
||||||
|
for (var key in from) {
|
||||||
|
if (hasOwnProperty.call(from, key)) {
|
||||||
|
to[key] = from[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getOwnPropertySymbols) {
|
||||||
|
symbols = getOwnPropertySymbols(from);
|
||||||
|
for (var i = 0; i < symbols.length; i++) {
|
||||||
|
if (propIsEnumerable.call(from, symbols[i])) {
|
||||||
|
to[symbols[i]] = from[symbols[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return to;
|
||||||
|
};
|
21
node_modules/object-assign/license
generated
vendored
Normal file
21
node_modules/object-assign/license
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
42
node_modules/object-assign/package.json
generated
vendored
Normal file
42
node_modules/object-assign/package.json
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "object-assign",
|
||||||
|
"version": "4.1.1",
|
||||||
|
"description": "ES2015 `Object.assign()` ponyfill",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "sindresorhus/object-assign",
|
||||||
|
"author": {
|
||||||
|
"name": "Sindre Sorhus",
|
||||||
|
"email": "sindresorhus@gmail.com",
|
||||||
|
"url": "sindresorhus.com"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "xo && ava",
|
||||||
|
"bench": "matcha bench.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"object",
|
||||||
|
"assign",
|
||||||
|
"extend",
|
||||||
|
"properties",
|
||||||
|
"es2015",
|
||||||
|
"ecmascript",
|
||||||
|
"harmony",
|
||||||
|
"ponyfill",
|
||||||
|
"prollyfill",
|
||||||
|
"polyfill",
|
||||||
|
"shim",
|
||||||
|
"browser"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"ava": "^0.16.0",
|
||||||
|
"lodash": "^4.16.4",
|
||||||
|
"matcha": "^0.7.0",
|
||||||
|
"xo": "^0.16.0"
|
||||||
|
}
|
||||||
|
}
|
61
node_modules/object-assign/readme.md
generated
vendored
Normal file
61
node_modules/object-assign/readme.md
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# object-assign [](https://travis-ci.org/sindresorhus/object-assign)
|
||||||
|
|
||||||
|
> ES2015 [`Object.assign()`](http://www.2ality.com/2014/01/object-assign.html) [ponyfill](https://ponyfill.com)
|
||||||
|
|
||||||
|
|
||||||
|
## Use the built-in
|
||||||
|
|
||||||
|
Node.js 4 and up, as well as every evergreen browser (Chrome, Edge, Firefox, Opera, Safari),
|
||||||
|
support `Object.assign()` :tada:. If you target only those environments, then by all
|
||||||
|
means, use `Object.assign()` instead of this package.
|
||||||
|
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install --save object-assign
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
const objectAssign = require('object-assign');
|
||||||
|
|
||||||
|
objectAssign({foo: 0}, {bar: 1});
|
||||||
|
//=> {foo: 0, bar: 1}
|
||||||
|
|
||||||
|
// multiple sources
|
||||||
|
objectAssign({foo: 0}, {bar: 1}, {baz: 2});
|
||||||
|
//=> {foo: 0, bar: 1, baz: 2}
|
||||||
|
|
||||||
|
// overwrites equal keys
|
||||||
|
objectAssign({foo: 0}, {foo: 1}, {foo: 2});
|
||||||
|
//=> {foo: 2}
|
||||||
|
|
||||||
|
// ignores null and undefined sources
|
||||||
|
objectAssign({foo: 0}, null, {bar: 1}, undefined);
|
||||||
|
//=> {foo: 0, bar: 1}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### objectAssign(target, [source, ...])
|
||||||
|
|
||||||
|
Assigns enumerable own properties of `source` objects to the `target` object and returns the `target` object. Additional `source` objects will overwrite previous ones.
|
||||||
|
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [ES2015 spec - Object.assign](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign)
|
||||||
|
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [deep-assign](https://github.com/sindresorhus/deep-assign) - Recursive `Object.assign()`
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT © [Sindre Sorhus](https://sindresorhus.com)
|
39
node_modules/vary/HISTORY.md
generated
vendored
Normal file
39
node_modules/vary/HISTORY.md
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
1.1.2 / 2017-09-23
|
||||||
|
==================
|
||||||
|
|
||||||
|
* perf: improve header token parsing speed
|
||||||
|
|
||||||
|
1.1.1 / 2017-03-20
|
||||||
|
==================
|
||||||
|
|
||||||
|
* perf: hoist regular expression
|
||||||
|
|
||||||
|
1.1.0 / 2015-09-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Only accept valid field names in the `field` argument
|
||||||
|
- Ensures the resulting string is a valid HTTP header value
|
||||||
|
|
||||||
|
1.0.1 / 2015-07-08
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix setting empty header from empty `field`
|
||||||
|
* perf: enable strict mode
|
||||||
|
* perf: remove argument reassignments
|
||||||
|
|
||||||
|
1.0.0 / 2014-08-10
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Accept valid `Vary` header string as `field`
|
||||||
|
* Add `vary.append` for low-level string manipulation
|
||||||
|
* Move to `jshttp` orgainzation
|
||||||
|
|
||||||
|
0.1.0 / 2014-06-05
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Support array of fields to set
|
||||||
|
|
||||||
|
0.0.0 / 2014-06-04
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial release
|
22
node_modules/vary/LICENSE
generated
vendored
Normal file
22
node_modules/vary/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2017 Douglas Christopher Wilson
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
101
node_modules/vary/README.md
generated
vendored
Normal file
101
node_modules/vary/README.md
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# vary
|
||||||
|
|
||||||
|
[![NPM Version][npm-image]][npm-url]
|
||||||
|
[![NPM Downloads][downloads-image]][downloads-url]
|
||||||
|
[![Node.js Version][node-version-image]][node-version-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
Manipulate the HTTP Vary header
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||||
|
[npm registry](https://www.npmjs.com/). Installation is done using the
|
||||||
|
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install vary
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
<!-- eslint-disable no-unused-vars -->
|
||||||
|
|
||||||
|
```js
|
||||||
|
var vary = require('vary')
|
||||||
|
```
|
||||||
|
|
||||||
|
### vary(res, field)
|
||||||
|
|
||||||
|
Adds the given header `field` to the `Vary` response header of `res`.
|
||||||
|
This can be a string of a single field, a string of a valid `Vary`
|
||||||
|
header, or an array of multiple fields.
|
||||||
|
|
||||||
|
This will append the header if not already listed, otherwise leaves
|
||||||
|
it listed in the current location.
|
||||||
|
|
||||||
|
<!-- eslint-disable no-undef -->
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Append "Origin" to the Vary header of the response
|
||||||
|
vary(res, 'Origin')
|
||||||
|
```
|
||||||
|
|
||||||
|
### vary.append(header, field)
|
||||||
|
|
||||||
|
Adds the given header `field` to the `Vary` response header string `header`.
|
||||||
|
This can be a string of a single field, a string of a valid `Vary` header,
|
||||||
|
or an array of multiple fields.
|
||||||
|
|
||||||
|
This will append the header if not already listed, otherwise leaves
|
||||||
|
it listed in the current location. The new header string is returned.
|
||||||
|
|
||||||
|
<!-- eslint-disable no-undef -->
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Get header string appending "Origin" to "Accept, User-Agent"
|
||||||
|
vary.append('Accept, User-Agent', 'Origin')
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Updating the Vary header when content is based on it
|
||||||
|
|
||||||
|
```js
|
||||||
|
var http = require('http')
|
||||||
|
var vary = require('vary')
|
||||||
|
|
||||||
|
http.createServer(function onRequest (req, res) {
|
||||||
|
// about to user-agent sniff
|
||||||
|
vary(res, 'User-Agent')
|
||||||
|
|
||||||
|
var ua = req.headers['user-agent'] || ''
|
||||||
|
var isMobile = /mobi|android|touch|mini/i.test(ua)
|
||||||
|
|
||||||
|
// serve site, depending on isMobile
|
||||||
|
res.setHeader('Content-Type', 'text/html')
|
||||||
|
res.end('You are (probably) ' + (isMobile ? '' : 'not ') + 'a mobile user')
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/vary.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/vary
|
||||||
|
[node-version-image]: https://img.shields.io/node/v/vary.svg
|
||||||
|
[node-version-url]: https://nodejs.org/en/download
|
||||||
|
[travis-image]: https://img.shields.io/travis/jshttp/vary/master.svg
|
||||||
|
[travis-url]: https://travis-ci.org/jshttp/vary
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/jshttp/vary/master.svg
|
||||||
|
[coveralls-url]: https://coveralls.io/r/jshttp/vary
|
||||||
|
[downloads-image]: https://img.shields.io/npm/dm/vary.svg
|
||||||
|
[downloads-url]: https://npmjs.org/package/vary
|
149
node_modules/vary/index.js
generated
vendored
Normal file
149
node_modules/vary/index.js
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/*!
|
||||||
|
* vary
|
||||||
|
* Copyright(c) 2014-2017 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = vary
|
||||||
|
module.exports.append = append
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegExp to match field-name in RFC 7230 sec 3.2
|
||||||
|
*
|
||||||
|
* field-name = token
|
||||||
|
* token = 1*tchar
|
||||||
|
* tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
|
||||||
|
* / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
|
||||||
|
* / DIGIT / ALPHA
|
||||||
|
* ; any VCHAR, except delimiters
|
||||||
|
*/
|
||||||
|
|
||||||
|
var FIELD_NAME_REGEXP = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a field to a vary header.
|
||||||
|
*
|
||||||
|
* @param {String} header
|
||||||
|
* @param {String|Array} field
|
||||||
|
* @return {String}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function append (header, field) {
|
||||||
|
if (typeof header !== 'string') {
|
||||||
|
throw new TypeError('header argument is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!field) {
|
||||||
|
throw new TypeError('field argument is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
// get fields array
|
||||||
|
var fields = !Array.isArray(field)
|
||||||
|
? parse(String(field))
|
||||||
|
: field
|
||||||
|
|
||||||
|
// assert on invalid field names
|
||||||
|
for (var j = 0; j < fields.length; j++) {
|
||||||
|
if (!FIELD_NAME_REGEXP.test(fields[j])) {
|
||||||
|
throw new TypeError('field argument contains an invalid header name')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// existing, unspecified vary
|
||||||
|
if (header === '*') {
|
||||||
|
return header
|
||||||
|
}
|
||||||
|
|
||||||
|
// enumerate current values
|
||||||
|
var val = header
|
||||||
|
var vals = parse(header.toLowerCase())
|
||||||
|
|
||||||
|
// unspecified vary
|
||||||
|
if (fields.indexOf('*') !== -1 || vals.indexOf('*') !== -1) {
|
||||||
|
return '*'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < fields.length; i++) {
|
||||||
|
var fld = fields[i].toLowerCase()
|
||||||
|
|
||||||
|
// append value (case-preserving)
|
||||||
|
if (vals.indexOf(fld) === -1) {
|
||||||
|
vals.push(fld)
|
||||||
|
val = val
|
||||||
|
? val + ', ' + fields[i]
|
||||||
|
: fields[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a vary header into an array.
|
||||||
|
*
|
||||||
|
* @param {String} header
|
||||||
|
* @return {Array}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function parse (header) {
|
||||||
|
var end = 0
|
||||||
|
var list = []
|
||||||
|
var start = 0
|
||||||
|
|
||||||
|
// gather tokens
|
||||||
|
for (var i = 0, len = header.length; i < len; i++) {
|
||||||
|
switch (header.charCodeAt(i)) {
|
||||||
|
case 0x20: /* */
|
||||||
|
if (start === end) {
|
||||||
|
start = end = i + 1
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 0x2c: /* , */
|
||||||
|
list.push(header.substring(start, end))
|
||||||
|
start = end = i + 1
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
end = i + 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// final token
|
||||||
|
list.push(header.substring(start, end))
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark that a request is varied on a header field.
|
||||||
|
*
|
||||||
|
* @param {Object} res
|
||||||
|
* @param {String|Array} field
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function vary (res, field) {
|
||||||
|
if (!res || !res.getHeader || !res.setHeader) {
|
||||||
|
// quack quack
|
||||||
|
throw new TypeError('res argument is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
// get existing header
|
||||||
|
var val = res.getHeader('Vary') || ''
|
||||||
|
var header = Array.isArray(val)
|
||||||
|
? val.join(', ')
|
||||||
|
: String(val)
|
||||||
|
|
||||||
|
// set new header
|
||||||
|
if ((val = append(header, field))) {
|
||||||
|
res.setHeader('Vary', val)
|
||||||
|
}
|
||||||
|
}
|
43
node_modules/vary/package.json
generated
vendored
Normal file
43
node_modules/vary/package.json
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "vary",
|
||||||
|
"description": "Manipulate the HTTP Vary header",
|
||||||
|
"version": "1.1.2",
|
||||||
|
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"http",
|
||||||
|
"res",
|
||||||
|
"vary"
|
||||||
|
],
|
||||||
|
"repository": "jshttp/vary",
|
||||||
|
"devDependencies": {
|
||||||
|
"beautify-benchmark": "0.2.4",
|
||||||
|
"benchmark": "2.1.4",
|
||||||
|
"eslint": "3.19.0",
|
||||||
|
"eslint-config-standard": "10.2.1",
|
||||||
|
"eslint-plugin-import": "2.7.0",
|
||||||
|
"eslint-plugin-markdown": "1.0.0-beta.6",
|
||||||
|
"eslint-plugin-node": "5.1.1",
|
||||||
|
"eslint-plugin-promise": "3.5.0",
|
||||||
|
"eslint-plugin-standard": "3.0.1",
|
||||||
|
"istanbul": "0.4.5",
|
||||||
|
"mocha": "2.5.3",
|
||||||
|
"supertest": "1.1.0"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"HISTORY.md",
|
||||||
|
"LICENSE",
|
||||||
|
"README.md",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"bench": "node benchmark/index.js",
|
||||||
|
"lint": "eslint --plugin markdown --ext js,md .",
|
||||||
|
"test": "mocha --reporter spec --bail --check-leaks test/",
|
||||||
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
|
||||||
|
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
|
||||||
|
}
|
||||||
|
}
|
17
scheme.sql
Normal file
17
scheme.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
-- Table structure for the database
|
||||||
|
CREATE TABLE users (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
username VARCHAR(50) NOT NULL UNIQUE,
|
||||||
|
first_name VARCHAR(50) NOT NULL,
|
||||||
|
last_name VARCHAR(50) NOT NULL,
|
||||||
|
email VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
created TIMESTAMP NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Mock data for users
|
||||||
|
INSERT INTO users (username, first_name, last_name, email, password)
|
||||||
|
VALUES
|
||||||
|
('test1', 'John', 'Doe', 'jdoe@example.com', '1test'),
|
||||||
|
('t', 'John', 'Doe', 'd@example.com', 'g'),
|
||||||
|
('test2', 'Alice', 'Smith', 'asmith@example.com', '2test');
|
Reference in New Issue
Block a user