From 95959fb517a5fcad3b72816ab9631e143f0a86ef Mon Sep 17 00:00:00 2001
From: Martin Shetty <1972005+martukas@users.noreply.github.com>
Date: Tue, 10 May 2022 03:15:24 -0700
Subject: [PATCH 1/3] "user db; updates #3"
---
package-lock.json | 246 +++++++++++++++++++++++++++++++
package.json | 6 +
src/client/App.js | 2 +
src/client/pages/login.jsx | 35 +++++
src/client/pages/secret_page.jsx | 21 +++
src/server/database.js | 34 +++--
src/server/routes.js | 3 +
src/server/user.js | 18 +++
8 files changed, 351 insertions(+), 14 deletions(-)
create mode 100644 src/client/pages/login.jsx
create mode 100644 src/client/pages/secret_page.jsx
create mode 100644 src/server/user.js
diff --git a/package-lock.json b/package-lock.json
index a7306ca..595460a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,9 @@
"license": "Apache2",
"dependencies": {
"axios": "^0.26.1",
+ "body-parser": "^1.20.0",
"bootstrap": "^5.1.3",
+ "connect-ensure-login": "^0.1.1",
"cookie-parser": "^1.4.6",
"core-js": "^3.22.0",
"cors": "^2.8.5",
@@ -19,10 +21,14 @@
"dotenv": "^16.0.0",
"express": "^4.17.3",
"express-fileupload": "^1.3.1",
+ "express-session": "^1.17.2",
"file-saver": "^2.0.5",
"mongodb": "^4.5.0",
"mongoose": "^6.3.2",
"morgan": "^1.10.0",
+ "passport": "^0.5.2",
+ "passport-local": "^1.0.0",
+ "passport-local-mongoose": "^7.0.0",
"react": "^18.0.0",
"react-bootstrap": "^2.3.0",
"react-dom": "^18.0.0",
@@ -3596,6 +3602,14 @@
"integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
"dev": true
},
+ "node_modules/connect-ensure-login": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/connect-ensure-login/-/connect-ensure-login-0.1.1.tgz",
+ "integrity": "sha1-F03MUSQ7nqwj+NmCFa62aU4uihI=",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
"node_modules/connect-history-api-fallback": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
@@ -5014,6 +5028,56 @@
"node": ">=12.0.0"
}
},
+ "node_modules/express-session": {
+ "version": "1.17.2",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz",
+ "integrity": "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==",
+ "dependencies": {
+ "cookie": "0.4.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~2.0.0",
+ "on-headers": "~1.0.2",
+ "parseurl": "~1.3.3",
+ "safe-buffer": "5.2.1",
+ "uid-safe": "~2.1.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/express-session/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/express-session/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "node_modules/express-session/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/express/node_modules/cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
@@ -5331,6 +5395,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/generaterr": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/generaterr/-/generaterr-1.5.0.tgz",
+ "integrity": "sha1-sM62zFFk3yoGEzjMNAqGFTlcUvw="
+ },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -7675,6 +7744,54 @@
"tslib": "^2.0.3"
}
},
+ "node_modules/passport": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/passport/-/passport-0.5.2.tgz",
+ "integrity": "sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw==",
+ "dependencies": {
+ "passport-strategy": "1.x.x",
+ "pause": "0.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/jaredhanson"
+ }
+ },
+ "node_modules/passport-local": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
+ "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
+ "dependencies": {
+ "passport-strategy": "1.x.x"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/passport-local-mongoose": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/passport-local-mongoose/-/passport-local-mongoose-7.0.0.tgz",
+ "integrity": "sha512-JwpMJJa7D73ri9vojXNOgsPT4pzw5UowH4QhdXQUW18noLngwJ+mtImo/5cMVlOuZEB6Q2tryy4YGqJRMZzC+g==",
+ "dependencies": {
+ "generaterr": "^1.5.0",
+ "passport-local": "^1.0.0",
+ "scmp": "^2.1.0"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/passport-strategy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
+ "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
"node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -7719,6 +7836,11 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
+ "node_modules/pause": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
+ "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
+ },
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -8101,6 +8223,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/random-bytes": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+ "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -8703,6 +8833,11 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/scmp": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz",
+ "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q=="
+ },
"node_modules/select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -9679,6 +9814,17 @@
"is-typedarray": "^1.0.0"
}
},
+ "node_modules/uid-safe": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
+ "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
+ "dependencies": {
+ "random-bytes": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -13422,6 +13568,11 @@
"integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
"dev": true
},
+ "connect-ensure-login": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/connect-ensure-login/-/connect-ensure-login-0.1.1.tgz",
+ "integrity": "sha1-F03MUSQ7nqwj+NmCFa62aU4uihI="
+ },
"connect-history-api-fallback": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
@@ -14513,6 +14664,41 @@
"busboy": "^0.3.1"
}
},
+ "express-session": {
+ "version": "1.17.2",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz",
+ "integrity": "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==",
+ "requires": {
+ "cookie": "0.4.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~2.0.0",
+ "on-headers": "~1.0.2",
+ "parseurl": "~1.3.3",
+ "safe-buffer": "5.2.1",
+ "uid-safe": "~2.1.5"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ }
+ }
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -14719,6 +14905,11 @@
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true
},
+ "generaterr": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/generaterr/-/generaterr-1.5.0.tgz",
+ "integrity": "sha1-sM62zFFk3yoGEzjMNAqGFTlcUvw="
+ },
"gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -16459,6 +16650,38 @@
"tslib": "^2.0.3"
}
},
+ "passport": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/passport/-/passport-0.5.2.tgz",
+ "integrity": "sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw==",
+ "requires": {
+ "passport-strategy": "1.x.x",
+ "pause": "0.0.1"
+ }
+ },
+ "passport-local": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
+ "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
+ "requires": {
+ "passport-strategy": "1.x.x"
+ }
+ },
+ "passport-local-mongoose": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/passport-local-mongoose/-/passport-local-mongoose-7.0.0.tgz",
+ "integrity": "sha512-JwpMJJa7D73ri9vojXNOgsPT4pzw5UowH4QhdXQUW18noLngwJ+mtImo/5cMVlOuZEB6Q2tryy4YGqJRMZzC+g==",
+ "requires": {
+ "generaterr": "^1.5.0",
+ "passport-local": "^1.0.0",
+ "scmp": "^2.1.0"
+ }
+ },
+ "passport-strategy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
+ "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
+ },
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -16494,6 +16717,11 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
+ "pause": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
+ "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
+ },
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -16772,6 +17000,11 @@
"side-channel": "^1.0.4"
}
},
+ "random-bytes": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+ "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
+ },
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -17223,6 +17456,11 @@
"ajv-keywords": "^3.5.2"
}
},
+ "scmp": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz",
+ "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q=="
+ },
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -17991,6 +18229,14 @@
"is-typedarray": "^1.0.0"
}
},
+ "uid-safe": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
+ "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
+ "requires": {
+ "random-bytes": "~1.0.0"
+ }
+ },
"unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
diff --git a/package.json b/package.json
index 385347d..4d65d7f 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,9 @@
"license": "Apache2",
"dependencies": {
"axios": "^0.26.1",
+ "body-parser": "^1.20.0",
"bootstrap": "^5.1.3",
+ "connect-ensure-login": "^0.1.1",
"cookie-parser": "^1.4.6",
"core-js": "^3.22.0",
"cors": "^2.8.5",
@@ -23,10 +25,14 @@
"dotenv": "^16.0.0",
"express": "^4.17.3",
"express-fileupload": "^1.3.1",
+ "express-session": "^1.17.2",
"file-saver": "^2.0.5",
"mongodb": "^4.5.0",
"mongoose": "^6.3.2",
"morgan": "^1.10.0",
+ "passport": "^0.5.2",
+ "passport-local": "^1.0.0",
+ "passport-local-mongoose": "^7.0.0",
"react": "^18.0.0",
"react-bootstrap": "^2.3.0",
"react-dom": "^18.0.0",
diff --git a/src/client/App.js b/src/client/App.js
index d2b7e7d..2166aab 100644
--- a/src/client/App.js
+++ b/src/client/App.js
@@ -5,6 +5,7 @@ import DataFileTable from './pages/data-file-table';
import UploadFile from './pages/upload-file';
import DataSet from './pages/dataset';
import NotFound from './pages/notfound';
+import Login from './pages/login';
export default function App() {
return (
@@ -15,6 +16,7 @@ export default function App() {
} />
} />
} />
+ } />
} />
diff --git a/src/client/pages/login.jsx b/src/client/pages/login.jsx
new file mode 100644
index 0000000..30834b4
--- /dev/null
+++ b/src/client/pages/login.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { Button, Container, Form } from 'react-bootstrap';
+
+function Login() {
+
+
+ return (
+
+
+
+ Email address
+
+
+ We will never share your email with anyone else.
+
+
+
+
+ Password
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default Login;
diff --git a/src/client/pages/secret_page.jsx b/src/client/pages/secret_page.jsx
new file mode 100644
index 0000000..80999b0
--- /dev/null
+++ b/src/client/pages/secret_page.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import { Button, Container, Form } from 'react-bootstrap';
+
+function SecretPage() {
+ return (
+
+
+ Secret Page
+
+
+
+ );
+}
+
+export default SecretPage;
diff --git a/src/server/database.js b/src/server/database.js
index 6505a41..6d2c8e8 100644
--- a/src/server/database.js
+++ b/src/server/database.js
@@ -1,14 +1,12 @@
const { ServerApiVersion } = require('mongodb');
const mongoose = require('mongoose');
+const schemata = require('./user');
// See README for what to put in your `.env` file
const {
MONGO_URI
} = process.env;
-const databaseName = 'test-data';
-const collectionName = 'experiments';
-
let instance = null;
// https://www.digitalocean.com/community/tutorials/containerizing-a-node-js-application-for-development-with-docker-compose
@@ -20,27 +18,35 @@ class DataBase {
useUnifiedTopology: true,
serverApi: ServerApiVersion.v1,
/* mongoose options */
- dbName: databaseName,
+ dbName: null,
autoIndex: false, // Don't build indexes
maxPoolSize: 10, // Maintain up to 10 socket connections
serverSelectionTimeoutMS: 5000, // Keep trying to send operations for 5 seconds
socketTimeoutMS: 45000, // Close sockets after 45 seconds of inactivity
family: 4 // Use IPv4, skip trying IPv6
};
- // this.client = null;
- this.experiments_db = null;
+ this.experiments_conn = null;
+ this.experiments = null;
+ this.user_model = null;
}
async connect() {
try {
- await mongoose.connect(MONGO_URI, this.mongoose_options);
+ this.mongoose_options.dbName = 'test-data';
+ this.experiments_conn = await mongoose.createConnection(
+ MONGO_URI,
+ this.mongoose_options
+ ).asPromise();
} catch (error) {
console.log(`Failed to connect to database: ${error}`);
}
- mongoose.connection.on('error', (err) => {
- console.log(`Database error: ${err}`);
+ mongoose.connection.on('error', (error) => {
+ console.log(`Database error: ${error}`);
});
- this.experiments_db = mongoose.connection.db;
+ this.experiments = this.experiments_conn.db.collection('experiments');
+ this.user_model = this.experiments_conn.model('userData', schemata.User, 'userData');
+ console.log(`connection: ${this.experiments_conn}`);
+ console.log(`col: ${this.experiments}`);
}
static getInstance() {
@@ -52,7 +58,7 @@ class DataBase {
}
async testConnectToMongo() {
- return this.experiments_db.collection(collectionName).findOne({}, (err, result) => {
+ return this.experiments.findOne({}, (err, result) => {
if (err) throw err;
console.log(result);
});
@@ -61,7 +67,7 @@ class DataBase {
// TODO: make querying more flexible, return various fields
async grabMetadata() {
const retData = [];
- await this.experiments_db.collection(collectionName).find().forEach(
+ await this.experiments.find().forEach(
(e) => {
const e2 = {
unique_id: e.unique_id,
@@ -77,11 +83,11 @@ class DataBase {
async getFullExperimentData(uniqueId) {
const query = { unique_id: uniqueId };
- return this.experiments_db.collection(collectionName).findOne(query);
+ return this.experiments.findOne(query);
}
async uploadExperiment(data, uniqueId) {
- return this.experiments_db.collection(collectionName).insertOne({
+ return this.experiments.insertOne({
unique_id: uniqueId,
...data,
});
diff --git a/src/server/routes.js b/src/server/routes.js
index 0bb1ff9..1b9bbd3 100644
--- a/src/server/routes.js
+++ b/src/server/routes.js
@@ -5,6 +5,9 @@ const { DataBase } = require('./database');
const router = express.Router();
router.get('/get-test-table-data', async (req, res) => {
+ // DataBase.getInstance().user_model.register({ username: 'candy', active: false }, 'cane');
+ // DataBase.getInstance().user_model.register({ username: 'starbuck', active: false }, 'redeye');
+
const tableData = await DataBase.getInstance().grabMetadata();
res.send({
msg: 'Worked!',
diff --git a/src/server/user.js b/src/server/user.js
new file mode 100644
index 0000000..57c8b2c
--- /dev/null
+++ b/src/server/user.js
@@ -0,0 +1,18 @@
+// dependencies
+const mongoose = require('mongoose');
+const passportLocalMongoose = require('passport-local-mongoose');
+
+// Create Model
+const { Schema } = mongoose;
+const User = new Schema({
+ // username: { type: String, required: true },
+ // password: { type: String, required: true }
+ username: String,
+ password: String
+});
+// Export Model
+User.plugin(passportLocalMongoose);
+
+module.exports = {
+ User
+};
From de0e0f771c49af668282ff557fb1f11e872381df Mon Sep 17 00:00:00 2001
From: Martin Shetty <1972005+martukas@users.noreply.github.com>
Date: Wed, 11 May 2022 03:04:28 -0700
Subject: [PATCH 2/3] "local authentication strategies; updates #3"
---
package-lock.json | 806 ++++++++++++++++++-
package.json | 7 +-
src/client/App.js | 8 +-
src/client/context/UserContext.js | 17 +
src/client/index.js | 5 +-
src/client/pages/authorize.jsx | 55 ++
src/client/pages/login.jsx | 96 ++-
src/client/pages/navbar.jsx | 3 +
src/client/pages/register.jsx | 106 +++
src/client/pages/secret_page.jsx | 21 -
src/client/pages/welcome.jsx | 91 +++
src/server/authenticate.js | 27 +
src/server/database.js | 27 +-
src/server/models/user.js | 50 ++
src/server/{routes.js => routes/dbRoutes.js} | 5 +-
src/server/routes/userRoutes.js | 174 ++++
src/server/server.js | 64 +-
src/server/strategies/JwtStrategy.js | 35 +
src/server/strategies/LocalStrategy.js | 20 +
src/server/user.js | 18 -
20 files changed, 1504 insertions(+), 131 deletions(-)
create mode 100644 src/client/context/UserContext.js
create mode 100644 src/client/pages/authorize.jsx
create mode 100644 src/client/pages/register.jsx
delete mode 100644 src/client/pages/secret_page.jsx
create mode 100644 src/client/pages/welcome.jsx
create mode 100644 src/server/authenticate.js
create mode 100644 src/server/models/user.js
rename src/server/{routes.js => routes/dbRoutes.js} (85%)
create mode 100644 src/server/routes/userRoutes.js
create mode 100644 src/server/strategies/JwtStrategy.js
create mode 100644 src/server/strategies/LocalStrategy.js
delete mode 100644 src/server/user.js
diff --git a/package-lock.json b/package-lock.json
index 595460a..c899dfe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.1.0",
"license": "Apache2",
"dependencies": {
+ "@blueprintjs/core": "^4.3.0",
"axios": "^0.26.1",
"body-parser": "^1.20.0",
"bootstrap": "^5.1.3",
@@ -23,12 +24,15 @@
"express-fileupload": "^1.3.1",
"express-session": "^1.17.2",
"file-saver": "^2.0.5",
+ "jsonwebtoken": "^8.5.1",
"mongodb": "^4.5.0",
"mongoose": "^6.3.2",
"morgan": "^1.10.0",
"passport": "^0.5.2",
+ "passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"passport-local-mongoose": "^7.0.0",
+ "path": "^0.12.7",
"react": "^18.0.0",
"react-bootstrap": "^2.3.0",
"react-dom": "^18.0.0",
@@ -53,6 +57,7 @@
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"nodemon": "^2.0.15",
+ "react-error-overlay": "^6.0.11",
"sass": "^1.50.0",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
@@ -1748,6 +1753,74 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@blueprintjs/colors": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/@blueprintjs/colors/-/colors-4.1.2.tgz",
+ "integrity": "sha512-wvq92hgRZZYrohI8GaN/pV0iQfxvWa2RI1cLYuItDvXM6i/u1riaw0RcsqqAIL1MH1fHsKFdH1O8i7Tj5a+lpQ=="
+ },
+ "node_modules/@blueprintjs/core": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@blueprintjs/core/-/core-4.3.0.tgz",
+ "integrity": "sha512-0MoQjGr6IfoC4xAtZ8EWIaGeLihsC85Ylzarc/w/APsvUdvUw+DWyGhwy7X51r3f27skhuok6HrVOw2d3/V0eg==",
+ "dependencies": {
+ "@blueprintjs/colors": "^4.1.2",
+ "@blueprintjs/icons": "^4.2.5",
+ "@juggle/resize-observer": "^3.3.1",
+ "@types/dom4": "^2.0.1",
+ "classnames": "^2.2",
+ "dom4": "^2.1.5",
+ "normalize.css": "^8.0.1",
+ "popper.js": "^1.16.1",
+ "react-popper": "^1.3.7",
+ "react-transition-group": "^4.4.1",
+ "tslib": "~2.3.1"
+ },
+ "bin": {
+ "upgrade-blueprint-2.0.0-rename": "scripts/upgrade-blueprint-2.0.0-rename.sh",
+ "upgrade-blueprint-3.0.0-rename": "scripts/upgrade-blueprint-3.0.0-rename.sh"
+ },
+ "peerDependencies": {
+ "react": "^16.8 || 17 || 18",
+ "react-dom": "^16.8 || 17 || 18"
+ }
+ },
+ "node_modules/@blueprintjs/core/node_modules/react-popper": {
+ "version": "1.3.11",
+ "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz",
+ "integrity": "sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg==",
+ "dependencies": {
+ "@babel/runtime": "^7.1.2",
+ "@hypnosphi/create-react-context": "^0.3.1",
+ "deep-equal": "^1.1.1",
+ "popper.js": "^1.14.4",
+ "prop-types": "^15.6.1",
+ "typed-styles": "^0.0.7",
+ "warning": "^4.0.2"
+ },
+ "peerDependencies": {
+ "react": "0.14.x || ^15.0.0 || ^16.0.0 || ^17.0.0"
+ }
+ },
+ "node_modules/@blueprintjs/core/node_modules/tslib": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
+ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+ },
+ "node_modules/@blueprintjs/icons": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/@blueprintjs/icons/-/icons-4.2.5.tgz",
+ "integrity": "sha512-wovXczQwIMlKoakYVYbv03s20jRQD3zivrOhJayLX0dl5FccnEVcHx2Vnxi/7nq6FVztCCdjYyd5fIUHfDe7tg==",
+ "dependencies": {
+ "change-case": "^4.1.2",
+ "classnames": "^2.2",
+ "tslib": "~2.3.1"
+ }
+ },
+ "node_modules/@blueprintjs/icons/node_modules/tslib": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
+ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+ },
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@@ -1812,6 +1885,19 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true
},
+ "node_modules/@hypnosphi/create-react-context": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz",
+ "integrity": "sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A==",
+ "dependencies": {
+ "gud": "^1.0.0",
+ "warning": "^4.0.3"
+ },
+ "peerDependencies": {
+ "prop-types": "^15.0.0",
+ "react": ">=0.14.0"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
@@ -1859,6 +1945,11 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
+ "node_modules/@juggle/resize-observer": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz",
+ "integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw=="
+ },
"node_modules/@leichtgewicht/ip-codec": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz",
@@ -1975,6 +2066,11 @@
"@types/node": "*"
}
},
+ "node_modules/@types/dom4": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@types/dom4/-/dom4-2.0.2.tgz",
+ "integrity": "sha512-Rt4IC1T7xkCWa0OG1oSsPa0iqnxlDeQqKXZAHrQGLb7wFGncWm85MaxKUjAGejOrUynOgWlFi4c6S6IyJwoK4g=="
+ },
"node_modules/@types/eslint": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz",
@@ -3067,6 +3163,11 @@
"ieee754": "^1.1.13"
}
},
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
+ },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -3159,7 +3260,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
"integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
- "dev": true,
"dependencies": {
"pascal-case": "^3.1.2",
"tslib": "^2.0.3"
@@ -3193,6 +3293,16 @@
}
]
},
+ "node_modules/capital-case": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz",
+ "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -3207,6 +3317,25 @@
"node": ">=4"
}
},
+ "node_modules/change-case": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz",
+ "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==",
+ "dependencies": {
+ "camel-case": "^4.1.2",
+ "capital-case": "^1.0.4",
+ "constant-case": "^3.0.4",
+ "dot-case": "^3.0.4",
+ "header-case": "^2.0.4",
+ "no-case": "^3.0.4",
+ "param-case": "^3.0.4",
+ "pascal-case": "^3.1.2",
+ "path-case": "^3.0.4",
+ "sentence-case": "^3.0.4",
+ "snake-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@@ -3619,6 +3748,16 @@
"node": ">=0.8"
}
},
+ "node_modules/constant-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz",
+ "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case": "^2.0.2"
+ }
+ },
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -3919,6 +4058,22 @@
"node": ">=4"
}
},
+ "node_modules/deep-equal": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
+ "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
+ "dependencies": {
+ "is-arguments": "^1.0.4",
+ "is-date-object": "^1.0.1",
+ "is-regex": "^1.0.4",
+ "object-is": "^1.0.1",
+ "object-keys": "^1.1.1",
+ "regexp.prototype.flags": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -3965,7 +4120,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
"integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "dev": true,
"dependencies": {
"has-property-descriptors": "^1.0.0",
"object-keys": "^1.1.1"
@@ -4107,6 +4261,11 @@
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
+ "node_modules/dom4": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/dom4/-/dom4-2.1.6.tgz",
+ "integrity": "sha512-JkCVGnN4ofKGbjf5Uvc8mmxaATIErKQKSgACdBXpsQ3fY6DlIpAyWfiBSrGkttATssbDCp3psiAKWXk5gmjycA=="
+ },
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
@@ -4152,7 +4311,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
- "dev": true,
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
@@ -4184,6 +4342,14 @@
"integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
"dev": true
},
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -5390,7 +5556,6 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -5571,6 +5736,11 @@
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
+ "node_modules/gud": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz",
+ "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw=="
+ },
"node_modules/handle-thing": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
@@ -5610,7 +5780,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "dev": true,
"dependencies": {
"get-intrinsic": "^1.1.1"
},
@@ -5633,7 +5802,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "dev": true,
"dependencies": {
"has-symbols": "^1.0.2"
},
@@ -5662,6 +5830,15 @@
"he": "bin/he"
}
},
+ "node_modules/header-case": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz",
+ "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==",
+ "dependencies": {
+ "capital-case": "^1.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/history": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
@@ -6054,6 +6231,21 @@
"node": ">= 0.10"
}
},
+ "node_modules/is-arguments": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
+ "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -6140,7 +6332,6 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
@@ -6339,7 +6530,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -6566,6 +6756,35 @@
"node": ">=6"
}
},
+ "node_modules/jsonwebtoken": {
+ "version": "8.5.1",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+ "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^5.6.0"
+ },
+ "engines": {
+ "node": ">=4",
+ "npm": ">=1.4.28"
+ }
+ },
+ "node_modules/jsonwebtoken/node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
"node_modules/jsx-ast-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz",
@@ -6579,6 +6798,25 @@
"node": ">=4.0"
}
},
+ "node_modules/jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/kareem": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.5.tgz",
@@ -6711,12 +6949,47 @@
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true
},
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
+ },
+ "node_modules/lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
+ },
+ "node_modules/lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+ },
"node_modules/lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -6744,7 +7017,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
- "dev": true,
"dependencies": {
"tslib": "^2.0.3"
}
@@ -7123,7 +7395,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
- "dev": true,
"dependencies": {
"lower-case": "^2.0.2",
"tslib": "^2.0.3"
@@ -7245,6 +7516,11 @@
"node": ">=8"
}
},
+ "node_modules/normalize.css": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
+ "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg=="
+ },
"node_modules/npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -7294,11 +7570,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/object-is": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
+ "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "dev": true,
"engines": {
"node": ">= 0.4"
}
@@ -7695,7 +7985,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
"integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
- "dev": true,
"dependencies": {
"dot-case": "^3.0.4",
"tslib": "^2.0.3"
@@ -7738,7 +8027,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
- "dev": true,
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
@@ -7760,6 +8048,15 @@
"url": "https://github.com/sponsors/jaredhanson"
}
},
+ "node_modules/passport-jwt": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz",
+ "integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==",
+ "dependencies": {
+ "jsonwebtoken": "^8.2.0",
+ "passport-strategy": "^1.0.0"
+ }
+ },
"node_modules/passport-local": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
@@ -7792,6 +8089,24 @@
"node": ">= 0.4.0"
}
},
+ "node_modules/path": {
+ "version": "0.12.7",
+ "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
+ "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
+ "dependencies": {
+ "process": "^0.11.1",
+ "util": "^0.10.3"
+ }
+ },
+ "node_modules/path-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz",
+ "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -7971,6 +8286,16 @@
"node": ">=8"
}
},
+ "node_modules/popper.js": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
+ "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
+ "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
"node_modules/portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -8124,6 +8449,14 @@
"renderkid": "^3.0.0"
}
},
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -8344,6 +8677,12 @@
"react": "^18.1.0"
}
},
+ "node_modules/react-error-overlay": {
+ "version": "6.0.11",
+ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
+ "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==",
+ "dev": true
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -8490,7 +8829,6 @@
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
"integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
- "dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
@@ -8918,6 +9256,16 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
+ "node_modules/sentence-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz",
+ "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
"node_modules/serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
@@ -9146,6 +9494,15 @@
"npm": ">= 3.0.0"
}
},
+ "node_modules/snake-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
+ "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/sockjs": {
"version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@@ -9766,8 +10123,7 @@
"node_modules/tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
- "dev": true
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"node_modules/type-check": {
"version": "0.4.0",
@@ -9805,6 +10161,11 @@
"node": ">= 0.6"
}
},
+ "node_modules/typed-styles": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz",
+ "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q=="
+ },
"node_modules/typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -10033,6 +10394,22 @@
"node": ">=8"
}
},
+ "node_modules/upper-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz",
+ "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/upper-case-first": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz",
+ "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -10099,12 +10476,25 @@
"node": ">=4"
}
},
+ "node_modules/util": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
+ "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
+ "dependencies": {
+ "inherits": "2.0.3"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
+ "node_modules/util/node_modules/inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
"node_modules/utila": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz",
@@ -12073,6 +12463,67 @@
"to-fast-properties": "^2.0.0"
}
},
+ "@blueprintjs/colors": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/@blueprintjs/colors/-/colors-4.1.2.tgz",
+ "integrity": "sha512-wvq92hgRZZYrohI8GaN/pV0iQfxvWa2RI1cLYuItDvXM6i/u1riaw0RcsqqAIL1MH1fHsKFdH1O8i7Tj5a+lpQ=="
+ },
+ "@blueprintjs/core": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@blueprintjs/core/-/core-4.3.0.tgz",
+ "integrity": "sha512-0MoQjGr6IfoC4xAtZ8EWIaGeLihsC85Ylzarc/w/APsvUdvUw+DWyGhwy7X51r3f27skhuok6HrVOw2d3/V0eg==",
+ "requires": {
+ "@blueprintjs/colors": "^4.1.2",
+ "@blueprintjs/icons": "^4.2.5",
+ "@juggle/resize-observer": "^3.3.1",
+ "@types/dom4": "^2.0.1",
+ "classnames": "^2.2",
+ "dom4": "^2.1.5",
+ "normalize.css": "^8.0.1",
+ "popper.js": "^1.16.1",
+ "react-popper": "^1.3.7",
+ "react-transition-group": "^4.4.1",
+ "tslib": "~2.3.1"
+ },
+ "dependencies": {
+ "react-popper": {
+ "version": "1.3.11",
+ "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.11.tgz",
+ "integrity": "sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg==",
+ "requires": {
+ "@babel/runtime": "^7.1.2",
+ "@hypnosphi/create-react-context": "^0.3.1",
+ "deep-equal": "^1.1.1",
+ "popper.js": "^1.14.4",
+ "prop-types": "^15.6.1",
+ "typed-styles": "^0.0.7",
+ "warning": "^4.0.2"
+ }
+ },
+ "tslib": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
+ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+ }
+ }
+ },
+ "@blueprintjs/icons": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/@blueprintjs/icons/-/icons-4.2.5.tgz",
+ "integrity": "sha512-wovXczQwIMlKoakYVYbv03s20jRQD3zivrOhJayLX0dl5FccnEVcHx2Vnxi/7nq6FVztCCdjYyd5fIUHfDe7tg==",
+ "requires": {
+ "change-case": "^4.1.2",
+ "classnames": "^2.2",
+ "tslib": "~2.3.1"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
+ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+ }
+ }
+ },
"@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@@ -12124,6 +12575,15 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true
},
+ "@hypnosphi/create-react-context": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz",
+ "integrity": "sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A==",
+ "requires": {
+ "gud": "^1.0.0",
+ "warning": "^4.0.3"
+ }
+ },
"@jridgewell/gen-mapping": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
@@ -12162,6 +12622,11 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
+ "@juggle/resize-observer": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz",
+ "integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw=="
+ },
"@leichtgewicht/ip-codec": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz",
@@ -12260,6 +12725,11 @@
"@types/node": "*"
}
},
+ "@types/dom4": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@types/dom4/-/dom4-2.0.2.tgz",
+ "integrity": "sha512-Rt4IC1T7xkCWa0OG1oSsPa0iqnxlDeQqKXZAHrQGLb7wFGncWm85MaxKUjAGejOrUynOgWlFi4c6S6IyJwoK4g=="
+ },
"@types/eslint": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz",
@@ -13155,6 +13625,11 @@
"ieee754": "^1.1.13"
}
},
+ "buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
+ },
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -13225,7 +13700,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
"integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
- "dev": true,
"requires": {
"pascal-case": "^3.1.2",
"tslib": "^2.0.3"
@@ -13243,6 +13717,16 @@
"integrity": "sha512-ddP1Tgm7z2iIxu6QTtbZUv6HJxSaV/PZeSrWFZtbY4JZ69tOeNhBCl3HyRQgeNZKE5AOn1kpV7fhljigy0Ty3w==",
"dev": true
},
+ "capital-case": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz",
+ "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==",
+ "requires": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -13254,6 +13738,25 @@
"supports-color": "^5.3.0"
}
},
+ "change-case": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz",
+ "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==",
+ "requires": {
+ "camel-case": "^4.1.2",
+ "capital-case": "^1.0.4",
+ "constant-case": "^3.0.4",
+ "dot-case": "^3.0.4",
+ "header-case": "^2.0.4",
+ "no-case": "^3.0.4",
+ "param-case": "^3.0.4",
+ "pascal-case": "^3.1.2",
+ "path-case": "^3.0.4",
+ "sentence-case": "^3.0.4",
+ "snake-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@@ -13579,6 +14082,16 @@
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
"dev": true
},
+ "constant-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz",
+ "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==",
+ "requires": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case": "^2.0.2"
+ }
+ },
"content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -13785,6 +14298,19 @@
"mimic-response": "^1.0.0"
}
},
+ "deep-equal": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
+ "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
+ "requires": {
+ "is-arguments": "^1.0.4",
+ "is-date-object": "^1.0.1",
+ "is-regex": "^1.0.4",
+ "object-is": "^1.0.1",
+ "object-keys": "^1.1.1",
+ "regexp.prototype.flags": "^1.2.0"
+ }
+ },
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -13822,7 +14348,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
"integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "dev": true,
"requires": {
"has-property-descriptors": "^1.0.0",
"object-keys": "^1.1.1"
@@ -13930,6 +14455,11 @@
"entities": "^2.0.0"
}
},
+ "dom4": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/dom4/-/dom4-2.1.6.tgz",
+ "integrity": "sha512-JkCVGnN4ofKGbjf5Uvc8mmxaATIErKQKSgACdBXpsQ3fY6DlIpAyWfiBSrGkttATssbDCp3psiAKWXk5gmjycA=="
+ },
"domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
@@ -13960,7 +14490,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
- "dev": true,
"requires": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
@@ -13986,6 +14515,14 @@
"integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
"dev": true
},
+ "ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -14902,8 +15439,7 @@
"functions-have-names": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "dev": true
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="
},
"generaterr": {
"version": "1.5.0",
@@ -15041,6 +15577,11 @@
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
+ "gud": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz",
+ "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw=="
+ },
"handle-thing": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
@@ -15071,7 +15612,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "dev": true,
"requires": {
"get-intrinsic": "^1.1.1"
}
@@ -15085,7 +15625,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "dev": true,
"requires": {
"has-symbols": "^1.0.2"
}
@@ -15102,6 +15641,15 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true
},
+ "header-case": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz",
+ "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==",
+ "requires": {
+ "capital-case": "^1.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"history": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
@@ -15392,6 +15940,15 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
+ "is-arguments": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
+ "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+ "requires": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ }
+ },
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -15454,7 +16011,6 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "dev": true,
"requires": {
"has-tostringtag": "^1.0.0"
}
@@ -15580,7 +16136,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
"requires": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -15746,6 +16301,30 @@
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"dev": true
},
+ "jsonwebtoken": {
+ "version": "8.5.1",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+ "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
+ "requires": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^5.6.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ }
+ }
+ },
"jsx-ast-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz",
@@ -15756,6 +16335,25 @@
"object.assign": "^4.1.2"
}
},
+ "jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "requires": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "requires": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"kareem": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.5.tgz",
@@ -15864,12 +16462,47 @@
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true
},
+ "lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
+ },
+ "lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
+ },
+ "lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
+ },
+ "lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
+ },
+ "lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
+ },
+ "lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
+ },
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
+ "lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+ },
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -15894,7 +16527,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
- "dev": true,
"requires": {
"tslib": "^2.0.3"
}
@@ -16187,7 +16819,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
- "dev": true,
"requires": {
"lower-case": "^2.0.2",
"tslib": "^2.0.3"
@@ -16281,6 +16912,11 @@
"integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==",
"dev": true
},
+ "normalize.css": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
+ "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg=="
+ },
"npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -16315,11 +16951,19 @@
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
"integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g=="
},
+ "object-is": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
+ "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
+ "requires": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ }
+ },
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "dev": true
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
},
"object.assign": {
"version": "4.1.2",
@@ -16610,7 +17254,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
"integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
- "dev": true,
"requires": {
"dot-case": "^3.0.4",
"tslib": "^2.0.3"
@@ -16644,7 +17287,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
- "dev": true,
"requires": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
@@ -16659,6 +17301,15 @@
"pause": "0.0.1"
}
},
+ "passport-jwt": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz",
+ "integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==",
+ "requires": {
+ "jsonwebtoken": "^8.2.0",
+ "passport-strategy": "^1.0.0"
+ }
+ },
"passport-local": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
@@ -16682,6 +17333,24 @@
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
"integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
},
+ "path": {
+ "version": "0.12.7",
+ "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
+ "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
+ "requires": {
+ "process": "^0.11.1",
+ "util": "^0.10.3"
+ }
+ },
+ "path-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz",
+ "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==",
+ "requires": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@@ -16815,6 +17484,11 @@
}
}
},
+ "popper.js": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
+ "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
+ },
"portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -16922,6 +17596,11 @@
"renderkid": "^3.0.0"
}
},
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
+ },
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -17092,6 +17771,12 @@
"scheduler": "^0.22.0"
}
},
+ "react-error-overlay": {
+ "version": "6.0.11",
+ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
+ "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==",
+ "dev": true
+ },
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -17211,7 +17896,6 @@
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
"integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
- "dev": true,
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
@@ -17533,6 +18217,16 @@
}
}
},
+ "sentence-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz",
+ "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==",
+ "requires": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
"serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
@@ -17719,6 +18413,15 @@
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
},
+ "snake-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
+ "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
+ "requires": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"sockjs": {
"version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@@ -18193,8 +18896,7 @@
"tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
- "dev": true
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"type-check": {
"version": "0.4.0",
@@ -18220,6 +18922,11 @@
"mime-types": "~2.1.24"
}
},
+ "typed-styles": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz",
+ "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q=="
+ },
"typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -18390,6 +19097,22 @@
}
}
},
+ "upper-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz",
+ "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==",
+ "requires": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "upper-case-first": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz",
+ "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==",
+ "requires": {
+ "tslib": "^2.0.3"
+ }
+ },
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -18432,6 +19155,21 @@
"prepend-http": "^2.0.0"
}
},
+ "util": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
+ "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
+ "requires": {
+ "inherits": "2.0.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ }
+ }
+ },
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
diff --git a/package.json b/package.json
index 4d65d7f..6b23bdb 100644
--- a/package.json
+++ b/package.json
@@ -5,15 +5,16 @@
"main": "src/server/server.js",
"scripts": {
"build": "webpack --mode production",
- "start": "npm run build && node src/server/server.js",
+ "start": "export NODE_ENV=production && npm run build && node src/server/server.js",
"client": "webpack-dev-server --mode development --devtool inline-source-map --hot",
"server": "nodemon src/server/server.js",
- "dev": "concurrently \"npm run server\" \"npm run client\""
+ "dev": "export NODE_ENV=dev && concurrently \"npm run server\" \"npm run client\""
},
"author": "RespiraWorks",
"license": "Apache2",
"dependencies": {
"axios": "^0.26.1",
+ "@blueprintjs/core": "^4.3.0",
"body-parser": "^1.20.0",
"bootstrap": "^5.1.3",
"connect-ensure-login": "^0.1.1",
@@ -27,10 +28,12 @@
"express-fileupload": "^1.3.1",
"express-session": "^1.17.2",
"file-saver": "^2.0.5",
+ "jsonwebtoken": "^8.5.1",
"mongodb": "^4.5.0",
"mongoose": "^6.3.2",
"morgan": "^1.10.0",
"passport": "^0.5.2",
+ "passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"passport-local-mongoose": "^7.0.0",
"react": "^18.0.0",
diff --git a/src/client/App.js b/src/client/App.js
index 2166aab..384836e 100644
--- a/src/client/App.js
+++ b/src/client/App.js
@@ -1,11 +1,13 @@
-import { BrowserRouter, Routes, Route } from 'react-router-dom';
+import {
+ BrowserRouter, Routes, Route
+} from 'react-router-dom';
import React from 'react';
import MyNavbar from './pages/navbar';
import DataFileTable from './pages/data-file-table';
import UploadFile from './pages/upload-file';
import DataSet from './pages/dataset';
import NotFound from './pages/notfound';
-import Login from './pages/login';
+import Authorize from './pages/authorize';
export default function App() {
return (
@@ -16,7 +18,7 @@ export default function App() {
} />
} />
} />
- } />
+ } />
} />
diff --git a/src/client/context/UserContext.js b/src/client/context/UserContext.js
new file mode 100644
index 0000000..85915af
--- /dev/null
+++ b/src/client/context/UserContext.js
@@ -0,0 +1,17 @@
+import React, { useState } from 'react';
+
+const UserContext = React.createContext([{}, p => {}]);
+
+let initialState = {};
+
+function UserProvider(props) {
+ const [state, setState] = useState(initialState);
+
+ return (
+
+ { props.children }
+
+ );
+}
+
+export { UserContext, UserProvider };
diff --git a/src/client/index.js b/src/client/index.js
index 317fb4b..6669e6f 100644
--- a/src/client/index.js
+++ b/src/client/index.js
@@ -4,12 +4,15 @@ import './App.scss';
import App from './App';
import 'core-js/stable';
import 'regenerator-runtime/runtime';
+import { UserProvider } from './context/UserContext';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
-
+
+
+
);
diff --git a/src/client/pages/authorize.jsx b/src/client/pages/authorize.jsx
new file mode 100644
index 0000000..1bdfab9
--- /dev/null
+++ b/src/client/pages/authorize.jsx
@@ -0,0 +1,55 @@
+import React, {
+ useCallback, useContext, useEffect, useState
+} from 'react';
+import {
+ Container, Spinner, Tab, Tabs
+} from 'react-bootstrap';
+import { UserContext } from '../context/UserContext';
+import Login from './login';
+import Register from './register';
+import Welcome from './welcome';
+
+function Authorize() {
+ const [userContext, setUserContext] = useContext(UserContext);
+
+ const verifyUser = useCallback(() => {
+ fetch('/users/refreshToken', {
+ method: 'POST',
+ credentials: 'include',
+ headers: { 'Content-Type': 'application/json' },
+ }).then(async (response) => {
+ if (response.ok) {
+ const data = await response.json();
+ setUserContext((oldValues) => ({ ...oldValues, token: data.token }));
+ } else {
+ setUserContext((oldValues) => ({ ...oldValues, token: null }));
+ }
+ // TODO: pick better refresh time - 5 min?
+ // call refreshToken every 1 minute to renew the authentication token.
+ setTimeout(verifyUser, 1 * 60 * 1000);
+ });
+ }, [setUserContext]);
+
+ useEffect(() => {
+ verifyUser();
+ }, [verifyUser]);
+
+ return userContext.token === null ? (
+
+
+
+
+
+
+
+
+
+
+ ) : userContext.token ? (
+
+ ) : (
+
+ );
+}
+
+export default Authorize;
diff --git a/src/client/pages/login.jsx b/src/client/pages/login.jsx
index 30834b4..4b0df02 100644
--- a/src/client/pages/login.jsx
+++ b/src/client/pages/login.jsx
@@ -1,33 +1,81 @@
-import React from 'react';
-import { Button, Container, Form } from 'react-bootstrap';
+import {
+ Button, Callout, FormGroup, InputGroup
+} from '@blueprintjs/core';
+import React, { useContext, useState } from 'react';
+import { UserContext } from '../context/UserContext';
function Login() {
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [error, setError] = useState('');
+ const [userContext, setUserContext] = useContext(UserContext);
+ const formSubmitHandler = (e) => {
+ e.preventDefault();
+ setIsSubmitting(true);
+ setError('');
+
+ const genericErrorMessage = 'Something went wrong! Please try again later.';
+
+ fetch('/users/login', {
+ method: 'POST',
+ credentials: 'include',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ username: email, password }),
+ })
+ .then(async (response) => {
+ setIsSubmitting(false);
+ if (!response.ok) {
+ if (response.status === 400) {
+ setError('Please fill all the fields correctly!');
+ } else if (response.status === 401) {
+ setError('Invalid email and password combination.');
+ } else {
+ setError(genericErrorMessage);
+ }
+ } else {
+ const data = await response.json();
+ setUserContext((oldValues) => ({ ...oldValues, token: data.token }));
+ console.log(`received context.token: ${userContext}`);
+ }
+ })
+ .catch((error) => {
+ setIsSubmitting(false);
+ setError(genericErrorMessage);
+ });
+ };
return (
-
-
- Email address
-
-
- We will never share your email with anyone else.
-
-
-
-
- Password
-
-
-
-
-
-
-
-
+ {error && {error}}
+
);
}
diff --git a/src/client/pages/navbar.jsx b/src/client/pages/navbar.jsx
index 077d839..b64ec68 100644
--- a/src/client/pages/navbar.jsx
+++ b/src/client/pages/navbar.jsx
@@ -18,6 +18,9 @@ function MyNavbar() {
UPLOAD
+
+ USER
+
diff --git a/src/client/pages/register.jsx b/src/client/pages/register.jsx
new file mode 100644
index 0000000..3462b96
--- /dev/null
+++ b/src/client/pages/register.jsx
@@ -0,0 +1,106 @@
+import {
+ Button, Callout, FormGroup, InputGroup
+} from '@blueprintjs/core';
+import React, { useContext, useState } from 'react';
+import { UserContext } from '../context/UserContext';
+
+function Register() {
+ const [firstName, setFirstName] = useState('');
+ const [lastName, setLastName] = useState('');
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [error, setError] = useState('');
+ const [userContext, setUserContext] = useContext(UserContext);
+
+ const formSubmitHandler = (e) => {
+ e.preventDefault();
+ setIsSubmitting(true);
+ setError('');
+
+ const genericErrorMessage = 'Something went wrong! Please try again later.';
+
+ fetch('/users/signup', {
+ method: 'POST',
+ credentials: 'include',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ firstName, lastName, username: email, password
+ }),
+ })
+ .then(async (response) => {
+ setIsSubmitting(false);
+ if (!response.ok) {
+ if (response.status === 400) {
+ setError('Please fill all the fields correctly!');
+ } else if (response.status === 401) {
+ setError('Invalid email and password combination.');
+ } else if (response.status === 500) {
+ console.log(response);
+ const data = await response.json();
+ if (data.message) setError(data.message || genericErrorMessage);
+ } else {
+ setError(genericErrorMessage);
+ }
+ } else {
+ const data = await response.json();
+ setUserContext((oldValues) => ({ ...oldValues, token: data.token }));
+ }
+ })
+ .catch((error) => {
+ setIsSubmitting(false);
+ setError(genericErrorMessage);
+ });
+ };
+
+ return (
+
+ {error && {error}}
+
+
+ );
+}
+
+export default Register;
diff --git a/src/client/pages/secret_page.jsx b/src/client/pages/secret_page.jsx
deleted file mode 100644
index 80999b0..0000000
--- a/src/client/pages/secret_page.jsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import { Button, Container, Form } from 'react-bootstrap';
-
-function SecretPage() {
- return (
-
-
- Secret Page
-
-
-
- );
-}
-
-export default SecretPage;
diff --git a/src/client/pages/welcome.jsx b/src/client/pages/welcome.jsx
new file mode 100644
index 0000000..1c40cc2
--- /dev/null
+++ b/src/client/pages/welcome.jsx
@@ -0,0 +1,91 @@
+import {
+ Button, Container, Spinner
+} from 'react-bootstrap';
+import React, { useCallback, useContext, useEffect } from 'react';
+import { UserContext } from '../context/UserContext';
+
+function Welcome() {
+ const [userContext, setUserContext] = useContext(UserContext);
+
+ const fetchUserDetails = useCallback(() => {
+ fetch('/users/me', {
+ method: 'GET',
+ credentials: 'include',
+ // Pass authentication token as bearer token in header
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${userContext.token}`,
+ },
+ }).then(async (response) => {
+ if (response.ok) {
+ const data = await response.json();
+ setUserContext((oldValues) => ({ ...oldValues, details: data }));
+ } else if (response.status === 401) {
+ // Edge case: when the token has expired.
+ // This could happen if the refreshToken calls have failed due to network error or
+ // User has had the tab open from previous day and tries to click on the Fetch button
+ window.location.reload();
+ } else {
+ setUserContext((oldValues) => ({ ...oldValues, details: null }));
+ }
+ });
+ }, [setUserContext, userContext.token]);
+
+ useEffect(() => {
+ // fetch only when user details are not present
+ if (!userContext.details) {
+ fetchUserDetails()
+ }
+ }, [userContext.details, fetchUserDetails]);
+
+ const logoutHandler = () => {
+ fetch('/users/logout', {
+ credentials: 'include',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${userContext.token}`,
+ },
+ }).then(async () => {
+ setUserContext((oldValues) => ({ ...oldValues, details: undefined, token: null }));
+ window.localStorage.setItem('logout', Date.now());
+ });
+ };
+
+ const refetchHandler = () => {
+ // set details to undefined so that spinner will be displayed and
+ // fetchUserDetails will be invoked from useEffect
+ setUserContext((oldValues) => ({ ...oldValues, details: undefined }));
+ };
+
+ return userContext.details === null ? (
+ 'Error Loading User details'
+ ) : !userContext.details ? (
+
+ ) : (
+
+
+
+
+ Welcome
+
+ {userContext.details.firstName}
+ {userContext.details.lastName && ` ${userContext.details.lastName}`}
+
+ !
+
+
+ Your reward points:
+ {' '}
+ {userContext.details.points}
+
+
+
+
+
+
+
+
+ );
+}
+
+export default Welcome;
diff --git a/src/server/authenticate.js b/src/server/authenticate.js
new file mode 100644
index 0000000..7a65fb9
--- /dev/null
+++ b/src/server/authenticate.js
@@ -0,0 +1,27 @@
+const passport = require('passport');
+const jwt = require('jsonwebtoken');
+
+const dev = process.env.NODE_ENV !== 'production';
+
+exports.COOKIE_OPTIONS = {
+ httpOnly: true,
+ // Since localhost is not having https protocol,
+ // secure cookies do not work correctly (in postman)
+ secure: !dev,
+ signed: true,
+ maxAge: eval(process.env.REFRESH_TOKEN_EXPIRY) * 1000,
+ sameSite: 'none',
+};
+
+exports.getToken = (user) => jwt.sign(user, process.env.JWT_SECRET, {
+ expiresIn: eval(process.env.SESSION_EXPIRY),
+});
+
+exports.getRefreshToken = (user) => {
+ const refreshToken = jwt.sign(user, process.env.REFRESH_TOKEN_SECRET, {
+ expiresIn: eval(process.env.REFRESH_TOKEN_EXPIRY),
+ });
+ return refreshToken;
+};
+
+exports.verifyUser = passport.authenticate('JwtStrategy', { session: false });
diff --git a/src/server/database.js b/src/server/database.js
index 6d2c8e8..64e88a7 100644
--- a/src/server/database.js
+++ b/src/server/database.js
@@ -1,6 +1,6 @@
const { ServerApiVersion } = require('mongodb');
const mongoose = require('mongoose');
-const schemata = require('./user');
+const schemata = require('./models/user');
// See README for what to put in your `.env` file
const {
@@ -25,15 +25,15 @@ class DataBase {
socketTimeoutMS: 45000, // Close sockets after 45 seconds of inactivity
family: 4 // Use IPv4, skip trying IPv6
};
- this.experiments_conn = null;
- this.experiments = null;
- this.user_model = null;
+ this.experiments_connection = null;
+ this.experiments_collection = null;
+ this.UserModel = null;
}
async connect() {
try {
this.mongoose_options.dbName = 'test-data';
- this.experiments_conn = await mongoose.createConnection(
+ this.experiments_connection = await mongoose.createConnection(
MONGO_URI,
this.mongoose_options
).asPromise();
@@ -43,10 +43,11 @@ class DataBase {
mongoose.connection.on('error', (error) => {
console.log(`Database error: ${error}`);
});
- this.experiments = this.experiments_conn.db.collection('experiments');
- this.user_model = this.experiments_conn.model('userData', schemata.User, 'userData');
- console.log(`connection: ${this.experiments_conn}`);
- console.log(`col: ${this.experiments}`);
+ this.experiments_collection = this.experiments_connection.db.collection('experiments');
+ // (Name, schema, collection)
+ this.UserModel = this.experiments_connection.model('User', schemata.UserSchema, 'userData');
+ console.log(`connection: ${this.experiments_connection}`);
+ console.log(`col: ${this.experiments_collection}`);
}
static getInstance() {
@@ -58,7 +59,7 @@ class DataBase {
}
async testConnectToMongo() {
- return this.experiments.findOne({}, (err, result) => {
+ return this.experiments_collection.findOne({}, (err, result) => {
if (err) throw err;
console.log(result);
});
@@ -67,7 +68,7 @@ class DataBase {
// TODO: make querying more flexible, return various fields
async grabMetadata() {
const retData = [];
- await this.experiments.find().forEach(
+ await this.experiments_collection.find().forEach(
(e) => {
const e2 = {
unique_id: e.unique_id,
@@ -83,11 +84,11 @@ class DataBase {
async getFullExperimentData(uniqueId) {
const query = { unique_id: uniqueId };
- return this.experiments.findOne(query);
+ return this.experiments_collection.findOne(query);
}
async uploadExperiment(data, uniqueId) {
- return this.experiments.insertOne({
+ return this.experiments_collection.insertOne({
unique_id: uniqueId,
...data,
});
diff --git a/src/server/models/user.js b/src/server/models/user.js
new file mode 100644
index 0000000..3ea4732
--- /dev/null
+++ b/src/server/models/user.js
@@ -0,0 +1,50 @@
+// dependencies
+const mongoose = require('mongoose');
+const passportLocalMongoose = require('passport-local-mongoose');
+
+const { Schema } = mongoose;
+
+const SessionSchema = new Schema({
+ refreshToken: {
+ type: String,
+ default: '',
+ },
+});
+
+const UserSchema = new Schema({
+ firstName: {
+ type: String,
+ default: '',
+ },
+ lastName: {
+ type: String,
+ default: '',
+ },
+ authStrategy: {
+ type: String,
+ default: 'local',
+ },
+ points: {
+ type: Number,
+ default: 50,
+ },
+ refreshToken: {
+ type: [SessionSchema],
+ },
+});
+
+// Remove refreshToken from the response
+UserSchema.set('toJSON', {
+ transform: function (doc, ret, options) {
+ delete ret.refreshToken;
+ return ret;
+ },
+});
+
+UserSchema.plugin(passportLocalMongoose);
+
+// module.exports = mongoose.model('User', User);
+
+module.exports = {
+ UserSchema
+};
diff --git a/src/server/routes.js b/src/server/routes/dbRoutes.js
similarity index 85%
rename from src/server/routes.js
rename to src/server/routes/dbRoutes.js
index 1b9bbd3..f82cdf6 100644
--- a/src/server/routes.js
+++ b/src/server/routes/dbRoutes.js
@@ -1,13 +1,10 @@
const express = require('express');
const path = require('path');
-const { DataBase } = require('./database');
+const { DataBase } = require('../database');
const router = express.Router();
router.get('/get-test-table-data', async (req, res) => {
- // DataBase.getInstance().user_model.register({ username: 'candy', active: false }, 'cane');
- // DataBase.getInstance().user_model.register({ username: 'starbuck', active: false }, 'redeye');
-
const tableData = await DataBase.getInstance().grabMetadata();
res.send({
msg: 'Worked!',
diff --git a/src/server/routes/userRoutes.js b/src/server/routes/userRoutes.js
new file mode 100644
index 0000000..a059a84
--- /dev/null
+++ b/src/server/routes/userRoutes.js
@@ -0,0 +1,174 @@
+const express = require('express');
+const passport = require('passport');
+const jwt = require('jsonwebtoken');
+const { DataBase } = require('../database');
+const {
+ // getToken,
+ // COOKIE_OPTIONS,
+ // getRefreshToken,
+ verifyUser,
+} = require('../authenticate');
+
+const router = express.Router();
+
+const { getToken, COOKIE_OPTIONS, getRefreshToken } = require('../authenticate');
+
+router.post('/signup', (req, res, next) => {
+ // Verify that first name is not empty
+ if (!req.body.firstName) {
+ res.statusCode = 500;
+ res.send({
+ name: 'FirstNameError',
+ message: 'The first name is required',
+ });
+ } else {
+ const { UserModel } = DataBase.getInstance();
+ UserModel.register(
+ new UserModel({ username: req.body.username }),
+ req.body.password,
+ (err, user) => {
+ if (err) {
+ res.statusCode = 500;
+ res.send(err);
+ } else {
+ user.firstName = req.body.firstName;
+ user.lastName = req.body.lastName || '';
+ const token = getToken({ _id: user._id });
+ const refreshToken = getRefreshToken({ _id: user._id });
+ user.refreshToken.push({ refreshToken });
+ user.save((err, user) => {
+ if (err) {
+ res.statusCode = 500;
+ res.send(err);
+ } else {
+ res.cookie('refreshToken', refreshToken, COOKIE_OPTIONS);
+ res.send({ success: true, token });
+ }
+ });
+ }
+ }
+ );
+ }
+});
+
+router.post('/login', passport.authenticate('LocalStrategy'), (req, res, next) => {
+ const token = getToken({ _id: req.user._id });
+ const refreshToken = getRefreshToken({ _id: req.user._id });
+ const { UserModel } = DataBase.getInstance();
+ UserModel.findById(req.user._id).then(
+ (user) => {
+ user.refreshToken.push({ refreshToken });
+ user.save((err, user) => {
+ if (err) {
+ res.statusCode = 500;
+ res.send(err);
+ } else {
+ res.cookie('refreshToken', refreshToken, COOKIE_OPTIONS);
+ res.send({ success: true, token });
+ }
+ });
+ },
+ (err) => next(err)
+ );
+});
+
+router.post('/refreshToken', (req, res, next) => {
+ const { signedCookies = {} } = req;
+ const { refreshToken } = signedCookies;
+
+ if (refreshToken) {
+ try {
+ const payload = jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET);
+ const userId = payload._id;
+ const { UserModel } = DataBase.getInstance();
+ UserModel.findOne({ _id: userId }).then(
+ (user) => {
+ if (user) {
+ // Find the refresh token against the user record in database
+ const tokenIndex = user.refreshToken.findIndex(
+ (item) => item.refreshToken === refreshToken
+ );
+
+ if (tokenIndex === -1) {
+ res.statusCode = 401;
+ res.send('Unauthorized');
+ } else {
+ const token = getToken({ _id: userId });
+ // If the refresh token exists, then create new one and replace it.
+ const newRefreshToken = getRefreshToken({ _id: userId });
+ user.refreshToken[tokenIndex] = { refreshToken: newRefreshToken };
+ user.save((err, user) => {
+ if (err) {
+ res.statusCode = 500;
+ res.send(err);
+ } else {
+ res.cookie('refreshToken', newRefreshToken, COOKIE_OPTIONS);
+ res.send({ success: true, token });
+ }
+ });
+ }
+ } else {
+ res.statusCode = 401;
+ res.send('Unauthorized');
+ }
+ },
+ (err) => next(err)
+ );
+ } catch (err) {
+ res.statusCode = 401;
+ res.send('Unauthorized');
+ }
+ } else {
+ res.statusCode = 401;
+ res.send('Unauthorized');
+ }
+});
+
+router.get('/me', verifyUser, (req, res, next) => {
+ res.send(req.user);
+});
+
+router.get('/logout', verifyUser, (req, res, next) => {
+ const { signedCookies = {} } = req;
+ const { refreshToken } = signedCookies;
+ const { UserModel } = DataBase.getInstance();
+ UserModel.findById(req.user._id).then(
+ (user) => {
+ const tokenIndex = user.refreshToken.findIndex(
+ (item) => item.refreshToken === refreshToken
+ );
+
+ if (tokenIndex !== -1) {
+ user.refreshToken.id(user.refreshToken[tokenIndex]._id).remove();
+ }
+
+ user.save((err, user) => {
+ if (err) {
+ res.statusCode = 500;
+ res.send(err);
+ } else {
+ res.clearCookie('refreshToken', COOKIE_OPTIONS);
+ res.send({ success: true });
+ }
+ });
+ },
+ (err) => next(err)
+ );
+});
+
+// router.post('/login', passport.authenticate('local', {
+// successReturnToOrRedirect: '/',
+// failureRedirect: '/login',
+// failureMessage: true
+// }), function(req, res) {
+// console.log(`Logged in user: ${req.user}`)
+// res.redirect('/dashboard');
+// });
+//
+// // Route to Log out
+// router.post('/logout', function(req, res) {
+// req.logout();
+// res.redirect('/login');
+// });
+
+module.exports = router;
diff --git a/src/server/server.js b/src/server/server.js
index 0b77281..c931e21 100644
--- a/src/server/server.js
+++ b/src/server/server.js
@@ -1,39 +1,81 @@
require('dotenv').config();
-const express = require('express');
+const express = require('express'); // server software
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const fileUpload = require('express-fileupload');
const cors = require('cors');
+// const session = require('express-session'); // session middleware
+const passport = require('passport'); // authentication
const { DataBase } = require('./database');
-
-const port = process.env.PORT || 8080;
+const { ConfigureJwtStrategy } = require('./strategies/JwtStrategy');
+const { ConfigureLocalStrategy } = require('./strategies/LocalStrategy');
+require('./authenticate');
const app = express();
-// allow other domains to access this server
-app.use(cors());
+app.use(logger('dev'));
+
+console.log(`node env = ${process.env.NODE_ENV}`);
+const dev = process.env.NODE_ENV !== 'production';
+
+app.use(express.json());
+app.use(express.urlencoded({ extended: false }));
+if (dev) {
+ app.use(cookieParser());
+} else {
+ app.use(cookieParser(process.env.COOKIE_SECRET));
+}
+
+// Add the client URL to the CORS policy
+const whitelist = process.env.WHITELISTED_DOMAINS
+ ? process.env.WHITELISTED_DOMAINS.split(',')
+ : [];
+const corsOptions = {
+ origin: function (origin, callback) {
+ if (!origin || whitelist.indexOf(origin) !== -1) {
+ callback(null, true);
+ } else {
+ callback(new Error('Not allowed by CORS'));
+ }
+ },
+ credentials: true
+};
+if (dev) {
+ app.use(cors());
+} else {
+ app.use(cors(corsOptions));
+}
+
app.use(fileUpload({
createParentPath: true
}));
-app.use(logger('dev'));
-app.use(express.json());
-app.use(express.urlencoded({ extended: false }));
-app.use(cookieParser());
app.use(express.static(path.resolve('dist')));
-const mongoRouter = require('./routes');
+const dataRouter = require('./routes/dbRoutes');
+const userRouter = require('./routes/userRoutes');
-app.use('/dbaccess', mongoRouter);
+app.use('/dbaccess', dataRouter);
+app.use('/users', userRouter);
// TODO: proper error handlers
app.get('*', (req, res) => res.sendFile(path.resolve('dist/index.html')));
+const port = process.env.PORT || 8080;
+
async function startServer() {
const singleton = DataBase.getInstance();
await singleton.connect();
+
+ ConfigureJwtStrategy();
+ ConfigureLocalStrategy();
+
+ // Configure More Middleware
+ app.use(passport.initialize());
+ // app.use(passport.session());
+
app.listen(port, () => console.log(`Listening on port ${port}`));
}
diff --git a/src/server/strategies/JwtStrategy.js b/src/server/strategies/JwtStrategy.js
new file mode 100644
index 0000000..87d8a02
--- /dev/null
+++ b/src/server/strategies/JwtStrategy.js
@@ -0,0 +1,35 @@
+const passport = require('passport');
+const { Strategy, ExtractJwt } = require('passport-jwt');
+const { DataBase } = require('../database');
+
+function ConfigureJwtStrategy() {
+ const opts = {};
+ opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
+ opts.secretOrKey = process.env.JWT_SECRET;
+
+ // Used by the authenticated requests to deserialize the user,
+ // i.e., to fetch user details from the JWT.
+ passport.use(
+ 'JwtStrategy',
+ new Strategy(opts, ((payload, done) => {
+ // Check against the DB only if necessary.
+ // This can be avoided if you don't want to fetch user details in each request.
+ DataBase.getInstance().UserModel.findOne({ _id: payload._id }, (err, user) => {
+ if (err) {
+ return done(err, false);
+ }
+ if (user) {
+ return done(null, user);
+ }
+ return done(null, false);
+ // or you could create a new account
+ });
+ }))
+ );
+}
+
+// export default ConfigureJwtStrategy;
+
+module.exports = {
+ ConfigureJwtStrategy
+};
diff --git a/src/server/strategies/LocalStrategy.js b/src/server/strategies/LocalStrategy.js
new file mode 100644
index 0000000..641a7dd
--- /dev/null
+++ b/src/server/strategies/LocalStrategy.js
@@ -0,0 +1,20 @@
+const passport = require('passport');
+const LocalStrategy = require('passport-local').Strategy;
+const { DataBase } = require('../database');
+
+function ConfigureLocalStrategy() {
+ // Called during login/sign up
+ passport.use(
+ 'LocalStrategy',
+ new LocalStrategy(DataBase.getInstance().UserModel.authenticate())
+ );
+
+ // Called while after logging in / signing up to set user details in req.user
+ passport.serializeUser(DataBase.getInstance().UserModel.serializeUser());
+}
+
+// export default ConfigureLocalStrategy;
+
+module.exports = {
+ ConfigureLocalStrategy
+};
diff --git a/src/server/user.js b/src/server/user.js
deleted file mode 100644
index 57c8b2c..0000000
--- a/src/server/user.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// dependencies
-const mongoose = require('mongoose');
-const passportLocalMongoose = require('passport-local-mongoose');
-
-// Create Model
-const { Schema } = mongoose;
-const User = new Schema({
- // username: { type: String, required: true },
- // password: { type: String, required: true }
- username: String,
- password: String
-});
-// Export Model
-User.plugin(passportLocalMongoose);
-
-module.exports = {
- User
-};
From 62fdc9f0e8ec750b105a5fdf8c1f2b243ef6701d Mon Sep 17 00:00:00 2001
From: Martin Shetty <1972005+martukas@users.noreply.github.com>
Date: Mon, 30 May 2022 03:45:37 -0700
Subject: [PATCH 3/3] "reimplemented auth using bootstrap components; updates
#3"
---
package.json | 1 -
src/client/pages/dataset.jsx | 2 +-
src/client/pages/login.jsx | 102 ++++++++++++++++++++++------------
src/client/pages/register.jsx | 76 +++++++++++++------------
4 files changed, 110 insertions(+), 71 deletions(-)
diff --git a/package.json b/package.json
index 6b23bdb..a1c37e5 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,6 @@
"license": "Apache2",
"dependencies": {
"axios": "^0.26.1",
- "@blueprintjs/core": "^4.3.0",
"body-parser": "^1.20.0",
"bootstrap": "^5.1.3",
"connect-ensure-login": "^0.1.1",
diff --git a/src/client/pages/dataset.jsx b/src/client/pages/dataset.jsx
index a5e7ac3..a9decaa 100644
--- a/src/client/pages/dataset.jsx
+++ b/src/client/pages/dataset.jsx
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import {
Button, Col, Container, Row, Spinner, Stack, Table,
-} from 'react-bootstrap'
+} from 'react-bootstrap';
import dateFormat from 'dateformat';
import { saveAs } from 'file-saver';
import { downloadFile } from '../api';
diff --git a/src/client/pages/login.jsx b/src/client/pages/login.jsx
index 4b0df02..5c415a7 100644
--- a/src/client/pages/login.jsx
+++ b/src/client/pages/login.jsx
@@ -1,7 +1,8 @@
import {
- Button, Callout, FormGroup, InputGroup
-} from '@blueprintjs/core';
+ Alert, Button, Container, Form,
+} from 'react-bootstrap';
import React, { useContext, useState } from 'react';
+// import axios from 'axios';
import { UserContext } from '../context/UserContext';
function Login() {
@@ -11,18 +12,51 @@ function Login() {
const [error, setError] = useState('');
const [userContext, setUserContext] = useContext(UserContext);
- const formSubmitHandler = (e) => {
- e.preventDefault();
+ function validateForm() {
+ return email.length > 0 && password.length > 0;
+ }
+
+ function handleSubmit(event) {
+ event.preventDefault();
setIsSubmitting(true);
setError('');
+ const route = '/users/login';
+ const data = { username: email, password };
const genericErrorMessage = 'Something went wrong! Please try again later.';
- fetch('/users/login', {
+ // axios.post(route, data, {
+ // headers: {
+ // Accept: { 'Content-Type': 'application/json' },
+ // },
+ // withCredentials: true
+ // }).then((response) => {
+ // setIsSubmitting(false);
+ // const responseOK = response && response.status === 200 && response.statusText === 'OK';
+ // if (!responseOK) {
+ // if (response.status === 400) {
+ // setError('Please fill all the fields correctly!');
+ // } else if (response.status === 401) {
+ // setError('Invalid email and password combination.');
+ // } else {
+ // setError(genericErrorMessage);
+ // }
+ // } else {
+ // const responseData = response.data;
+ // setUserContext((oldValues) => ({ ...oldValues, token: responseData.token }));
+ // }
+ // }).catch((caughtError) => {
+ // setIsSubmitting(false);
+ // console.log('Axios error caught');
+ // console.log(caughtError.toJSON());
+ // setError(caughtError);
+ // });
+
+ fetch(route, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ username: email, password }),
+ body: JSON.stringify(data),
})
.then(async (response) => {
setIsSubmitting(false);
@@ -35,48 +69,48 @@ function Login() {
setError(genericErrorMessage);
}
} else {
- const data = await response.json();
- setUserContext((oldValues) => ({ ...oldValues, token: data.token }));
- console.log(`received context.token: ${userContext}`);
+ const responseData = await response.json();
+ setUserContext((oldValues) => ({ ...oldValues, token: responseData.token }));
}
})
- .catch((error) => {
+ .catch((caughtError) => {
setIsSubmitting(false);
- setError(genericErrorMessage);
+ setError(caughtError);
});
- };
+ }
return (
-
+
+
+
+
);
}
diff --git a/src/client/pages/register.jsx b/src/client/pages/register.jsx
index 3462b96..5071bec 100644
--- a/src/client/pages/register.jsx
+++ b/src/client/pages/register.jsx
@@ -1,6 +1,6 @@
import {
- Button, Callout, FormGroup, InputGroup
-} from '@blueprintjs/core';
+ Alert, Button, Container, Form,
+} from 'react-bootstrap';
import React, { useContext, useState } from 'react';
import { UserContext } from '../context/UserContext';
@@ -13,8 +13,12 @@ function Register() {
const [error, setError] = useState('');
const [userContext, setUserContext] = useContext(UserContext);
- const formSubmitHandler = (e) => {
- e.preventDefault();
+ function validateForm() {
+ return email.length > 0 && password.length > 0;
+ }
+
+ function handleSubmit(event) {
+ event.preventDefault();
setIsSubmitting(true);
setError('');
@@ -47,59 +51,61 @@ function Register() {
setUserContext((oldValues) => ({ ...oldValues, token: data.token }));
}
})
- .catch((error) => {
+ .catch((caughtError) => {
setIsSubmitting(false);
- setError(genericErrorMessage);
+ setError(caughtError);
});
- };
+ }
return (
-
- {error &&
{error}}
-
-
+
+
+
+
);
}