aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/launch.json2
-rw-r--r--package-lock.json90
-rw-r--r--package.json10
-rw-r--r--src/client/views/Main.tsx221
-rw-r--r--src/server/authentication/config/passport.ts2
-rw-r--r--src/server/authentication/controllers/user.ts76
-rw-r--r--src/server/authentication/models/User.ts3
-rw-r--r--src/server/index.ts109
-rw-r--r--views/layout.pug4
-rw-r--r--views/login.pug26
-rw-r--r--views/resources/dashlogo.pngbin0 -> 7169 bytes
-rw-r--r--views/signup.pug44
-rw-r--r--views/stylesheets/authentication.css96
13 files changed, 517 insertions, 166 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 8aa197fa5..81d901b39 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -10,7 +10,7 @@
"name": "Launch Chrome against localhost",
"sourceMaps": true,
"breakOnLoad": true,
- "url": "http://localhost:1050",
+ "url": "http://localhost:1050/signup",
"webRoot": "${workspaceFolder}",
"skipFiles": [
"${workspaceRoot}/node_modules/**/*.js",
diff --git a/package-lock.json b/package-lock.json
index e0ad39229..5d864d644 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -37,6 +37,11 @@
"resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.0.tgz",
"integrity": "sha512-7WcbyctkE8GTzogDb0ulRAEw7v8oIS54ft9mQTU7PfM0hp5e+8kpa+HeQ7IQrFbKtJXBKcZ4bh+Em9dTw5L6AQ=="
},
+ "@types/async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/@types/async/-/async-2.4.1.tgz",
+ "integrity": "sha512-C09BK/wXzbW+/JK9zckhe+FeSbg7NmvVjUWwApnw7ksRpUq3ecGLiq2Aw1LlY4Z/VmtdhSaIs7jO5/MWRYMcOA=="
+ },
"@types/babel-types": {
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.5.tgz",
@@ -77,6 +82,11 @@
"@types/node": "10.12.24"
}
},
+ "@types/caseless": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.1.tgz",
+ "integrity": "sha512-FhlMa34NHp9K5MY1Uz8yb+ZvuX0pnvn3jScRSNAb75KHGB8d3rEU6hqMs3Z2vjuytcMfRg6c5CHMc3wtYyD2/A=="
+ },
"@types/chai": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz",
@@ -99,6 +109,14 @@
"@types/express": "4.16.1"
}
},
+ "@types/cookie-parser": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.1.tgz",
+ "integrity": "sha512-iJY6B3ZGufLiDf2OCAgiAAQuj1sMKC/wz/7XCEjZ+/MDuultfFJuSwrBKcLSmJ5iYApLzCCYBYJZs0Ws8GPmwA==",
+ "requires": {
+ "@types/express": "*"
+ }
+ },
"@types/express": {
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.16.1.tgz",
@@ -144,6 +162,14 @@
"express-validator": "5.3.1"
}
},
+ "@types/form-data": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
+ "integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/jquery": {
"version": "3.3.29",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.29.tgz",
@@ -214,6 +240,14 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.24.tgz",
"integrity": "sha512-GWWbvt+z9G5otRBW8rssOFgRY87J9N/qbhqfjMZ+gUuL6zoL+Hm6gP/8qQBG4jjimqdaNLCehcVapZ/Fs2WjCQ=="
},
+ "@types/nodemailer": {
+ "version": "4.6.6",
+ "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-4.6.6.tgz",
+ "integrity": "sha512-N2czhXs7fbQhvoquEGzmHAWttnxLfrM3+cWMRFX4hTQq4GE3VyaSE3MOOse4VoNgvtti/H5ow/Hq9KXu/UMWqA==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/orderedmap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/orderedmap/-/orderedmap-1.0.0.tgz",
@@ -367,6 +401,17 @@
"@types/react": "16.8.1"
}
},
+ "@types/request": {
+ "version": "2.48.1",
+ "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.1.tgz",
+ "integrity": "sha512-ZgEZ1TiD+KGA9LiAAPPJL68Id2UWfeSO62ijSXZjFJArVV+2pKcsVHmrcu+1oiE3q6eDGiFiSolRc4JHoerBBg==",
+ "requires": {
+ "@types/caseless": "*",
+ "@types/form-data": "*",
+ "@types/node": "*",
+ "@types/tough-cookie": "*"
+ }
+ },
"@types/serve-static": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz",
@@ -399,6 +444,11 @@
"resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.4.tgz",
"integrity": "sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ=="
},
+ "@types/tough-cookie": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz",
+ "integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg=="
+ },
"@types/typescript": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/typescript/-/typescript-2.0.0.tgz",
@@ -965,10 +1015,12 @@
"integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk="
},
"async": {
- "version": "1.5.2",
- "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
- "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
- "dev": true
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
+ "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
+ "requires": {
+ "lodash": "^4.17.11"
+ }
},
"async-each": {
"version": "1.0.1",
@@ -2008,6 +2060,15 @@
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
},
+ "cookie-parser": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz",
+ "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==",
+ "requires": {
+ "cookie": "0.3.1",
+ "cookie-signature": "1.0.6"
+ }
+ },
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
@@ -5789,6 +5850,11 @@
"true-case-path": "1.0.3"
}
},
+ "nodemailer": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-5.1.1.tgz",
+ "integrity": "sha512-hKGCoeNdFL2W7S76J/Oucbw0/qRlfG815tENdhzcqTpSjKgAN91mFOqU2lQUflRRxFM7iZvCyaFcAR9noc/CqQ=="
+ },
"nodemon": {
"version": "1.18.10",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.10.tgz",
@@ -9801,9 +9867,17 @@
"integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==",
"dev": true,
"requires": {
- "async": "1.5.2",
- "debug": "2.6.9",
- "mkdirp": "0.5.1"
+ "async": "^1.5.2",
+ "debug": "^2.2.0",
+ "mkdirp": "0.5.x"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ }
}
},
"posix-character-classes": {
@@ -13314,4 +13388,4 @@
"dev": true
}
}
-}
+} \ No newline at end of file
diff --git a/package.json b/package.json
index 32567b121..299f040c4 100644
--- a/package.json
+++ b/package.json
@@ -33,9 +33,12 @@
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.14",
+ "@types/async": "^2.4.1",
"@types/bcrypt-nodejs": "0.0.30",
"@types/bluebird": "^3.5.25",
"@types/body-parser": "^1.17.0",
+ "@types/connect-flash": "0.0.34",
+ "@types/cookie-parser": "^1.4.1",
"@types/express": "^4.16.1",
"@types/express-flash": "0.0.0",
"@types/express-session": "^1.15.12",
@@ -46,6 +49,7 @@
"@types/mongodb": "^3.1.19",
"@types/mongoose": "^5.3.16",
"@types/node": "^10.12.24",
+ "@types/nodemailer": "^4.6.6",
"@types/passport": "^1.0.0",
"@types/passport-local": "^1.0.33",
"@types/prosemirror-commands": "^1.0.1",
@@ -59,15 +63,19 @@
"@types/pug": "^2.0.4",
"@types/react-measure": "^2.0.4",
"@types/react-table": "^6.7.21",
+ "@types/request": "^2.48.1",
"@types/socket.io": "^2.1.2",
"@types/socket.io-client": "^1.4.32",
"@types/typescript": "^2.0.0",
"@types/uuid": "^3.4.4",
"@types/webpack": "^4.4.24",
+ "async": "^2.6.2",
"bcrypt-nodejs": "0.0.3",
"bluebird": "^3.5.3",
"body-parser": "^1.18.3",
+ "connect-flash": "^0.1.1",
"connect-mongo": "^2.0.3",
+ "cookie-parser": "^1.4.4",
"express": "^4.16.4",
"express-flash": "0.0.2",
"express-session": "^1.15.6",
@@ -84,6 +92,7 @@
"mongodb": "^3.1.13",
"mongoose": "^5.4.12",
"node-sass": "^4.11.0",
+ "nodemailer": "^5.1.1",
"nodemon": "^1.18.10",
"normalize.css": "^8.0.1",
"npm": "^6.7.0",
@@ -108,6 +117,7 @@
"react-mosaic": "0.0.20",
"react-split-pane": "^0.1.85",
"react-table": "^6.9.0",
+ "request": "^2.88.0",
"socket.io": "^2.2.0",
"socket.io-client": "^2.2.0",
"url-loader": "^1.1.2",
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 661a2ac20..cbc19d7fe 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -13,6 +13,8 @@ import { Server } from '../Server';
import { Utils } from '../../Utils';
import { ServerUtils } from '../../server/ServerUtil';
import { MessageStore, DocumentTransfer } from '../../server/Message';
+import { Database } from '../../server/database';
+import * as request from 'request'
import { Transform } from '../util/Transform';
import { CollectionDockingView } from './collections/CollectionDockingView';
import { FieldWaiting } from '../../fields/Field';
@@ -34,6 +36,21 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) {
}
}), true)
+let mainDocId: string;
+request.get(window.location.origin + "/getUserDocId", (error, response, body) => {
+ if (body) {
+ mainDocId = body;
+ } else {
+ mainDocId = Utils.GenerateGuid();
+ request.post(window.location.origin + "/setUserDocId", {
+ body: {
+ userDocumentId: mainDocId
+ },
+ json: true
+ })
+ }
+ init();
+})
//runInAction(() =>
// let doc1 = Documents.TextDocument({ title: "hello" });
@@ -51,114 +68,114 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) {
// schemaDocs[4].SetData(KS.Author, "Bob", TextField);
// schemaDocs.push(doc2);
// const doc7 = Documents.SchemaDocument(schemaDocs)
+function init() {
+ Documents.initProtos(() => {
+ Utils.EmitCallback(Server.Socket, MessageStore.GetField, mainDocId, (res: any) => {
+ console.log("HELLO WORLD")
+ console.log("RESPONSE: " + res)
+ let mainContainer: Document;
+ let mainfreeform: Document;
+ if (res) {
+ mainContainer = ServerUtils.FromJson(res) as Document;
+ mainContainer.GetAsync(KeyStore.ActiveFrame, field => mainfreeform = field as Document);
+ }
+ else {
+ mainContainer = Documents.DockDocument(JSON.stringify({ content: [{ type: 'row', content: [] }] }), { title: "main container" }, mainDocId);
+ Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(mainContainer.ToJson()))
-const mainDocId = "mainDoc";
-Documents.initProtos(() => {
- Utils.EmitCallback(Server.Socket, MessageStore.GetField, mainDocId, (res: any) => {
- console.log("HELLO WORLD")
- console.log("RESPONSE: " + res)
- let mainContainer: Document;
- let mainfreeform: Document;
- if (res) {
- mainContainer = ServerUtils.FromJson(res) as Document;
- mainContainer.GetAsync(KeyStore.ActiveFrame, field => mainfreeform = field as Document);
- }
- else {
- mainContainer = Documents.DockDocument(JSON.stringify({ content: [{ type: 'row', content: [] }] }), { title: "main container" }, mainDocId);
- Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(mainContainer.ToJson()))
+ setTimeout(() => {
+ mainfreeform = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" });
+ Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(mainfreeform.ToJson()));
- setTimeout(() => {
- mainfreeform = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" });
- Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(mainfreeform.ToJson()));
+ var docs = [mainfreeform].map(doc => CollectionDockingView.makeDocumentConfig(doc));
+ mainContainer.SetText(KeyStore.Data, JSON.stringify({ content: [{ type: 'row', content: docs }] }));
+ mainContainer.Set(KeyStore.ActiveFrame, mainfreeform);
+ }, 0);
+ }
- var docs = [mainfreeform].map(doc => CollectionDockingView.makeDocumentConfig(doc));
- mainContainer.SetText(KeyStore.Data, JSON.stringify({ content: [{ type: 'row', content: docs }] }));
- mainContainer.Set(KeyStore.ActiveFrame, mainfreeform);
- }, 0);
- }
+ let addImageNode = action(() => {
+ mainfreeform.GetList<Document>(KeyStore.Data, []).push(Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", {
+ x: 0, y: 300, width: 200, height: 200, title: "added note"
+ }));
+ })
+ let addTextNode = action(() => {
+ mainfreeform.GetList<Document>(KeyStore.Data, []).push(Documents.TextDocument({
+ x: 0, y: 300, width: 200, height: 200, title: "added note"
+ }));
+ })
+ let addColNode = action(() => {
+ mainfreeform.GetList<Document>(KeyStore.Data, []).push(Documents.FreeformDocument([], {
+ x: 0, y: 300, width: 200, height: 200, title: "added note"
+ }));
+ })
+ let addSchemaNode = action(() => {
+ mainfreeform.GetList<Document>(KeyStore.Data, []).push(Documents.SchemaDocument([Documents.TextDocument()], {
+ x: 0, y: 300, width: 200, height: 200, title: "added note"
+ }));
+ })
- let addImageNode = action(() => {
- mainfreeform.GetList<Document>(KeyStore.Data, []).push(Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", {
- x: 0, y: 300, width: 200, height: 200, title: "added note"
- }));
- })
- let addTextNode = action(() => {
- mainfreeform.GetList<Document>(KeyStore.Data, []).push(Documents.TextDocument({
- x: 0, y: 300, width: 200, height: 200, title: "added note"
- }));
- })
- let addColNode = action(() => {
- mainfreeform.GetList<Document>(KeyStore.Data, []).push(Documents.FreeformDocument([], {
- x: 0, y: 300, width: 200, height: 200, title: "added note"
- }));
- })
- let addSchemaNode = action(() => {
- mainfreeform.GetList<Document>(KeyStore.Data, []).push(Documents.SchemaDocument([Documents.TextDocument()], {
- x: 0, y: 300, width: 200, height: 200, title: "added note"
- }));
- })
+ let clearDatabase = action(() => {
+ Utils.Emit(Server.Socket, MessageStore.DeleteAll, {});
+ })
- let clearDatabase = action(() => {
- Utils.Emit(Server.Socket, MessageStore.DeleteAll, {});
+ ReactDOM.render((
+ <div style={{ position: "absolute", width: "100%", height: "100%" }}>
+ <DocumentView Document={mainContainer}
+ AddDocument={undefined} RemoveDocument={undefined} ScreenToLocalTransform={() => Transform.Identity}
+ ContentScaling={() => 1}
+ PanelWidth={() => 0}
+ PanelHeight={() => 0}
+ isTopMost={true}
+ ContainingCollectionView={undefined} />
+ <DocumentDecorations />
+ <ContextMenu />
+ <button style={{
+ position: 'absolute',
+ bottom: '0px',
+ left: '0px',
+ width: '150px'
+ }} onClick={addImageNode}>Add Image</button>
+ <button style={{
+ position: 'absolute',
+ bottom: '25px',
+ left: '0px',
+ width: '150px'
+ }} onClick={addTextNode}>Add Text</button>
+ <button style={{
+ position: 'absolute',
+ bottom: '50px',
+ left: '0px',
+ width: '150px'
+ }} onClick={addColNode}>Add Collection</button>
+ <button style={{
+ position: 'absolute',
+ bottom: '100',
+ left: '0px',
+ width: '150px'
+ }} onClick={addSchemaNode}>Add Schema</button>
+ <button style={{
+ position: 'absolute',
+ bottom: '75px',
+ left: '0px',
+ width: '150px'
+ }} onClick={clearDatabase}>Clear Database</button>
+ <button style={{
+ position: 'absolute',
+ bottom: '25',
+ right: '0px',
+ width: '150px'
+ }} onClick={() => UndoManager.Undo()}>Undo</button>
+ <button style={{
+ position: 'absolute',
+ bottom: '0',
+ right: '0px',
+ width: '150px'
+ }} onClick={() => UndoManager.Redo()}>Redo</button>
+ </div>),
+ document.getElementById('root'));
})
-
- ReactDOM.render((
- <div style={{ position: "absolute", width: "100%", height: "100%" }}>
- <DocumentView Document={mainContainer}
- AddDocument={undefined} RemoveDocument={undefined} ScreenToLocalTransform={() => Transform.Identity}
- ContentScaling={() => 1}
- PanelWidth={() => 0}
- PanelHeight={() => 0}
- isTopMost={true}
- ContainingCollectionView={undefined} />
- <DocumentDecorations />
- <ContextMenu />
- <button style={{
- position: 'absolute',
- bottom: '0px',
- left: '0px',
- width: '150px'
- }} onClick={addImageNode}>Add Image</button>
- <button style={{
- position: 'absolute',
- bottom: '25px',
- left: '0px',
- width: '150px'
- }} onClick={addTextNode}>Add Text</button>
- <button style={{
- position: 'absolute',
- bottom: '50px',
- left: '0px',
- width: '150px'
- }} onClick={addColNode}>Add Collection</button>
- <button style={{
- position: 'absolute',
- bottom: '100',
- left: '0px',
- width: '150px'
- }} onClick={addSchemaNode}>Add Schema</button>
- <button style={{
- position: 'absolute',
- bottom: '75px',
- left: '0px',
- width: '150px'
- }} onClick={clearDatabase}>Clear Database</button>
- <button style={{
- position: 'absolute',
- bottom: '25',
- right: '0px',
- width: '150px'
- }} onClick={() => UndoManager.Undo()}>Undo</button>
- <button style={{
- position: 'absolute',
- bottom: '0',
- right: '0px',
- width: '150px'
- }} onClick={() => UndoManager.Redo()}>Redo</button>
- </div>),
- document.getElementById('root'));
- })
-});
+ });
+}
// let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", {
// x: 650, y: 500, width: 600, height: 600, title: "cat 2"
// });
diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/config/passport.ts
index 05f6c3133..9f1303135 100644
--- a/src/server/authentication/config/passport.ts
+++ b/src/server/authentication/config/passport.ts
@@ -18,7 +18,7 @@ passport.deserializeUser<any, any>((id, done) => {
});
// AUTHENTICATE JUST WITH EMAIL AND PASSWORD
-passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
+passport.use(new LocalStrategy({ usernameField: 'email', passReqToCallback: true }, (req, email, password, done) => {
User.findOne({ email: email.toLowerCase() }, (error: any, user: any) => {
if (error) return done(error);
if (!user) return done(undefined, false, { message: "Invalid email or password" }) // invalid email
diff --git a/src/server/authentication/controllers/user.ts b/src/server/authentication/controllers/user.ts
index f74ff9039..a496959d1 100644
--- a/src/server/authentication/controllers/user.ts
+++ b/src/server/authentication/controllers/user.ts
@@ -9,15 +9,30 @@ import * as session from "express-session";
import * as pug from 'pug';
/**
+ * GET /
+ * Whenever a user navigates to the root of Dash
+ * (doesn't specify a sub-route), redirect to login.
+ * If the user is already signed in, it will effectively
+ * automatically redirect them to /home instead
+ */
+export let getEntry = (req: Request, res: Response) => {
+ res.redirect("/login");
+}
+
+/**
* GET /signup
- * Signup page.
+ * Directs user to the signup page
+ * modeled by signup.pug in views
*/
export let getSignup = (req: Request, res: Response) => {
if (req.user) {
- return res.redirect("/");
+ let user = req.user;
+ return res.redirect("/home");
}
res.render("signup.pug", {
- title: "Sign Up"
+ title: "Sign Up",
+ user: req.user,
+ errors: req.flash("Unable to facilitate sign up. Please try again.")
});
};
@@ -31,21 +46,33 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => {
req.assert("confirmPassword", "Passwords do not match").equals(req.body.password);
req.sanitize("email").normalizeEmail({ gmail_remove_dots: false });
+ req.flash("Working on something!!!");
+
const errors = req.validationErrors();
if (errors) {
- req.flash("errors", "Unable to facilitate sign up. Please try again.");
+ res.render("signup.pug", {
+ title: "Sign Up",
+ errors: req.flash("Unable to facilitate sign up. Please try again.")
+ });
return res.redirect("/signup");
}
+ const email = req.body.email;
+ const password = req.body.password;
+
const user = new User({
- email: req.body.email,
- password: req.body.password
+ email,
+ password,
+ userDoc: "document here"
});
- User.findOne({ email: req.body.email }, (err, existingUser) => {
+ User.findOne({ email }, (err, existingUser) => {
if (err) { return next(err); }
if (existingUser) {
+ if (existingUser) {
+ // existingUser.update({ $set: { email: please_work } }, (err, res) => { });
+ }
req.flash("errors", "Account with that email address already exists.");
return res.redirect("/signup");
}
@@ -59,6 +86,7 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => {
});
});
});
+
};
@@ -68,17 +96,18 @@ export let postSignup = (req: Request, res: Response, next: NextFunction) => {
*/
export let getLogin = (req: Request, res: Response) => {
if (req.user) {
- return res.redirect("/");
+ return res.redirect("/home");
}
- res.send("<p>dear lord please render</p>");
- // res.render("account/login", {
- // title: "Login"
- // });
+ res.render("login.pug", {
+ title: "Log In",
+ user: req.user
+ });
};
/**
* POST /login
* Sign in using email and password.
+ * On failure, redirect to login page
*/
export let postLogin = (req: Request, res: Response, next: NextFunction) => {
req.assert("email", "Email is not valid").isEmail();
@@ -89,19 +118,32 @@ export let postLogin = (req: Request, res: Response, next: NextFunction) => {
if (errors) {
req.flash("errors", "Unable to login at this time. Please try again.");
- return res.redirect("/login");
+ return res.redirect("/signup");
}
passport.authenticate("local", (err: Error, user: UserModel, info: IVerifyOptions) => {
if (err) { return next(err); }
if (!user) {
- req.flash("errors", info.message);
- return res.redirect("/login");
+ return res.redirect("/signup");
}
req.logIn(user, (err) => {
if (err) { return next(err); }
req.flash("success", "Success! You are logged in.");
- res.redirect("/");
+ res.redirect("/home");
});
})(req, res, next);
-}; \ No newline at end of file
+};
+
+/**
+ * GET /logout
+ * Invokes the logout function on the request
+ * and destroys the user's current session.
+ */
+export let getLogout = (req: Request, res: Response) => {
+ req.logout();
+ const sess = req.session;
+ if (sess) {
+ sess.destroy((err) => { if (err) { console.log(err); } });
+ }
+ res.redirect('/login');
+} \ No newline at end of file
diff --git a/src/server/authentication/models/User.ts b/src/server/authentication/models/User.ts
index 9752c4260..30fcecd81 100644
--- a/src/server/authentication/models/User.ts
+++ b/src/server/authentication/models/User.ts
@@ -1,6 +1,5 @@
//@ts-ignore
import * as bcrypt from "bcrypt-nodejs";
-import * as crypto from "crypto";
//@ts-ignore
import * as mongoose from "mongoose";
var url = 'mongodb://localhost:27017/Dash'
@@ -47,6 +46,8 @@ const userSchema = new mongoose.Schema({
passwordResetToken: String,
passwordResetExpires: Date,
+ userDocumentId: String,
+
facebook: String,
twitter: String,
google: String,
diff --git a/src/server/index.ts b/src/server/index.ts
index f5e66b31b..05d0f598a 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -3,7 +3,6 @@ const app = express()
import * as webpack from 'webpack'
import * as wdm from 'webpack-dev-middleware';
import * as whm from 'webpack-hot-middleware';
-import * as path from 'path'
import * as passport from 'passport';
import { MessageStore, Message, SetFieldArgs, GetFieldArgs, Transferable } from "./Message";
import { Client } from './Client';
@@ -14,23 +13,30 @@ import { FieldId, Field } from '../fields/Field';
import { Database } from './database';
import { ServerUtils } from './ServerUtil';
import { ObjectID } from 'mongodb';
+import * as bcrypt from "bcrypt-nodejs";
import { Document } from '../fields/Document';
import * as io from 'socket.io'
import * as passportConfig from './authentication/config/passport';
-import { getLogin, postLogin, getSignup, postSignup } from './authentication/controllers/user';
+import { getLogin, postLogin, getSignup, postSignup, getLogout, getEntry } from './authentication/controllers/user';
const config = require('../../webpack.config');
const compiler = webpack(config);
const port = 1050; // default port to listen
const serverPort = 1234;
import * as expressValidator from 'express-validator';
import expressFlash = require('express-flash');
+import flash = require('express-flash');
import * as bodyParser from 'body-parser';
import * as session from 'express-session';
+import * as cookieParser from 'cookie-parser';
+import * as nodemailer from 'nodemailer';
import c = require("crypto");
const MongoStore = require('connect-mongo')(session);
const mongoose = require('mongoose');
+import * as async from 'async';
const bluebird = require('bluebird');
import { performance } from 'perf_hooks'
+import * as path from 'path'
+import User, { UserModel } from './authentication/models/User';
const mongoUrl = 'mongodb://localhost:27017/Dash';
// mongoose.Promise = bluebird;
@@ -44,18 +50,24 @@ mongoose.connection.on('connected', function () {
console.log("connected");
})
-app.use(bodyParser.json());
-app.use(bodyParser.urlencoded({ extended: true }));
-app.use(expressValidator());
-app.use(expressFlash());
-app.use(require('express-session')({
+// SESSION MANAGEMENT AND AUTHENTICATION MIDDLEWARE
+// ORDER OF IMPORTS MATTERS
+
+app.use(cookieParser("secret"));
+app.use(session({
secret: `${c.randomBytes(64)}`,
resave: true,
+ cookie: { maxAge: 60000 },
saveUninitialized: true,
store: new MongoStore({
url: 'mongodb://localhost:27017/Dash'
})
}));
+app.use(flash());
+app.use(expressFlash());
+app.use(bodyParser.json());
+app.use(bodyParser.urlencoded({ extended: true }));
+app.use(expressValidator());
app.use(passport.initialize());
app.use(passport.session());
app.use((req, res, next) => {
@@ -63,18 +75,91 @@ app.use((req, res, next) => {
next();
});
+// AUTHENTICATION ROUTING
+
+// ***
+// Look for the definitions of these get and post
+// functions in the exports of user.ts
+
+// /home defines destination after a successful log in
+app.get("/home", (req, res) => {
+ // if user is not logged in, redirect to log in page
+ if (!req.user) {
+ res.redirect("/login");
+ return;
+ }
+ // otherwise, connect them to Dash
+ // TODO: store and manage users' workspaces
+ res.sendFile(path.join(__dirname, '../../deploy/index.html'));
+});
+
+app.get("/getUserDocId", (req, res) => {
+ console.log(req.user)
+ if (!req.user) {
+ return;
+ }
+ res.send(req.user.userDocumentId || "");
+})
+
+app.post("/setUserDocId", (req, res) => {
+ if (!req.user) {
+ return;
+ }
+ req.user.update({ $set: { userDocumentId: req.body.userDocumentId } }, () => { });
+})
+
+// anyone attempting to navigate to localhost at this port will
+// first have to login
+app.get("/", getEntry);
+
+// Sign Up
app.get("/signup", getSignup);
app.post("/signup", postSignup);
+
+// Log In
app.get("/login", getLogin);
app.post("/login", postLogin);
+// Log Out
+app.get('/logout', getLogout);
+
+// ***
+
+// FORGOT PASSWORD EMAIL HANDLING
+app.post('/forgot', function (req, res, next) {
+ const email = req.body.email;
+ async.waterfall([
+ function (done: any) {
+ const seed = new Uint16Array();
+ seed.set([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+ let token = crypto.getRandomValues(seed);
+ done(token);
+ },
+ function (token: Uint16Array, done: any) {
+ User.findOne({ email }, function (err, user: UserModel) {
+ if (!user) {
+ // NO ACCOUNT WITH SUBMITTED EMAIL
+ return res.redirect('/forgot');
+ }
+ user.passwordResetToken = token.toString();
+ user.passwordResetExpires = new Date(Date.now() + 3600000); // 1 HOUR
+ user.save(function (err: any) {
+ done(err, token, user);
+ });
+ });
+ },
+ function (token: Uint16Array, user: UserModel, done: any) {
+ const transport = nodemailer.createTransport('SMTP', {
+ auth: {
+ user: 'test.nodemailer@gmail.com',
+ pass: 'placeholder'
+ }
+ });
+ }
+ ])
+})
let FieldStore: ObservableMap<FieldId, Field> = new ObservableMap();
-// define a route handler for the default home page
-app.get("/", (req, res) => {
- res.sendFile(path.join(__dirname, '../../deploy/index.html'));
-});
-
app.get("/hello", (req, res) => {
res.send("<p>Hello</p>");
})
diff --git a/views/layout.pug b/views/layout.pug
index fb22ae770..95a5a391f 100644
--- a/views/layout.pug
+++ b/views/layout.pug
@@ -12,6 +12,4 @@ html(lang='')
link(rel='stylesheet', href='/css/main.css')
body
-
- .container
- block content \ No newline at end of file
+ block content \ No newline at end of file
diff --git a/views/login.pug b/views/login.pug
new file mode 100644
index 000000000..c379a6605
--- /dev/null
+++ b/views/login.pug
@@ -0,0 +1,26 @@
+
+extends ./layout
+
+block content
+ style
+ include ./stylesheets/authentication.css
+ form.form-horizontal(id='login-form', method='POST')
+ input(type='hidden', name='_csrf', value=_csrf)
+ .overlay(id='overlay_login')
+ a(href="/signup")
+ img(id='new_user', src="https://bit.ly/2EuqPb4", alt="")
+ .inner.login
+ h3.auth_header Log In
+ .form-group
+ //- label.col-sm-3.control-label(for='email', id='email_label') Email
+ .col-sm-7
+ input.form-control(type='email', name='email', id='email', placeholder='Email', autofocus, required)
+ .form-group
+ //- label.col-sm-3.control-label(for='password') Password
+ .col-sm-7
+ input.form-control(type='password', name='password', id='password', placeholder='Password', required)
+ .form-group
+ .col-sm-offset-3.col-sm-7
+ button.btn.btn-success(id='submit', type='submit')
+ i.fa.fa-user-plus
+ | Submit \ No newline at end of file
diff --git a/views/resources/dashlogo.png b/views/resources/dashlogo.png
new file mode 100644
index 000000000..3ba4e111b
--- /dev/null
+++ b/views/resources/dashlogo.png
Binary files differ
diff --git a/views/signup.pug b/views/signup.pug
index a23f334af..374710e6f 100644
--- a/views/signup.pug
+++ b/views/signup.pug
@@ -2,24 +2,26 @@
extends ./layout
block content
- .page-header
- h3 Sign up
- form.form-horizontal(id='signup-form', method='POST')
- input(type='hidden', name='_csrf', value=_csrf)
- .form-group
- label.col-sm-3.control-label(for='email') Email
- .col-sm-7
- input.form-control(type='email', name='email', id='email', placeholder='Email', autofocus, required)
- .form-group
- label.col-sm-3.control-label(for='password') Password
- .col-sm-7
- input.form-control(type='password', name='password', id='password', placeholder='Password', required)
- .form-group
- label.col-sm-3.control-label(for='confirmPassword') Confirm Password
- .col-sm-7
- input.form-control(type='password', name='confirmPassword', id='confirmPassword', placeholder='Confirm Password', required)
- .form-group
- .col-sm-offset-3.col-sm-7
- button.btn.btn-success(type='submit')
- i.fa.fa-user-plus
- | Signup \ No newline at end of file
+ style
+ include ./stylesheets/authentication.css
+ form.form-horizontal(id='signup-form', method='POST')
+ input(type='hidden', name='_csrf', value=_csrf)
+ .overlay(id='overlay_signup')
+ a(href="/login")
+ img(id='to_login', src="https://bit.ly/2U6ouZk", alt="")
+ .inner.signup
+ h3.auth_header Create An Account
+ .form-group
+ .col-sm-7
+ input.form-control(type='email', name='email', id='email', placeholder='Email', autofocus, required)
+ .form-group
+ .col-sm-7
+ input.form-control(type='password', name='password', id='password', placeholder='Password', required)
+ .form-group
+ .col-sm-7
+ input.form-control(type='password', name='confirmPassword', id='confirmPassword', placeholder='Confirm Password', required)
+ .form-group
+ .col-sm-offset-3.col-sm-7
+ button.btn.btn-success(type='submit')
+ i.fa.fa-user-plus
+ | Signup \ No newline at end of file
diff --git a/views/stylesheets/authentication.css b/views/stylesheets/authentication.css
new file mode 100644
index 000000000..232e5a091
--- /dev/null
+++ b/views/stylesheets/authentication.css
@@ -0,0 +1,96 @@
+#email_label {
+ color: blue;
+ margin-top: 10px;
+}
+
+h3,
+label {
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+body {
+ /* background-color: #ccbbcc; */
+ background-color: #251f1f;
+ /* background-image: url(https://bit.ly/2XibZvI);
+ background-repeat: no-repeat;
+ background-size: cover; */
+}
+
+#logo {
+ width: 100px;
+ height: 100px;
+ position: absolute;
+}
+
+.auth_header {
+ text-align: left;
+}
+
+.login {
+ height: 220px;
+}
+
+.signup {
+ height: 273px;
+}
+
+.btn {
+ width: 224px;
+ height: 35px;
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 14px;
+ font-style: oblique;
+}
+
+#overlay_signup {
+ height: 345px;
+}
+
+#overlay_login {
+ height: 300px;
+}
+
+#new_user,
+#to_login {
+ width: 20px;
+ height: 20px;
+ position: absolute;
+ top: 15px;
+ right: 15px;
+}
+
+.overlay {
+ border: 2px solid yellow;
+ text-align: center;
+ position: absolute;
+ margin: auto;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 400px;
+ background-color: white;
+ border-radius: 8px;
+ box-shadow: 10px 10px 10px #00000099;
+}
+
+.inner {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 230px;
+ margin: auto;
+}
+
+.form-control {
+ width: 200px;
+ margin-bottom: 15px;
+ height: 30px;
+ outline: none;
+ padding-left: 10px;
+ padding-right: 10px;
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 16px;
+} \ No newline at end of file