Added Social Authentication + fixed Agent Cron
This commit is contained in:
parent
fa7391ea4b
commit
dc6fc449f0
16
.snyk
16
.snyk
@ -1,16 +0,0 @@
|
||||
failThreshold: high
|
||||
version: v1.5.2
|
||||
ignore:
|
||||
'npm:moment:20160126':
|
||||
- express-brute-mongo > moment:
|
||||
reason: None given
|
||||
expires: '2016-11-16T22:23:46.921Z'
|
||||
patch:
|
||||
'npm:negotiator:20160616':
|
||||
- socket.io > engine.io > accepts > negotiator:
|
||||
patched: '2016-09-09T02:19:31.082Z'
|
||||
'npm:ws:20160624':
|
||||
- socket.io > engine.io > ws:
|
||||
patched: '2016-09-09T02:19:31.082Z'
|
||||
- socket.io > socket.io-client > engine.io-client > ws:
|
||||
patched: '2016-09-09T02:19:31.082Z'
|
@ -20,13 +20,22 @@
|
||||
|
||||
##### Milestones
|
||||
- [ ] Assets Management
|
||||
- [x] Images
|
||||
- [ ] Files/Documents
|
||||
- [ ] Authentication
|
||||
- [ ] Local
|
||||
- [x] Microsoft Account
|
||||
- [x] Google ID
|
||||
- [x] Facebook
|
||||
- [x] Background Agent (git sync, cache purge, etc.)
|
||||
- [x] Caching
|
||||
- [x] Create Entry
|
||||
- [x] Edit Entry
|
||||
- [x] Git Management
|
||||
- [ ] Markdown Editor
|
||||
- [x] Basic Formatting
|
||||
- [ ] Links
|
||||
- [ ] Table Editor
|
||||
- [x] Move Entry
|
||||
- [x] Navigation
|
||||
- [x] Parsing / Tree / Metadata
|
||||
|
4
agent.js
4
agent.js
@ -167,7 +167,9 @@ var job = new cron({
|
||||
|
||||
if(!jobUplWatchStarted) {
|
||||
jobUplWatchStarted = true;
|
||||
upl.initialScan();
|
||||
upl.initialScan().then(() => {
|
||||
job.start();
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
#bg,#bg>div{width:100%;height:100%;top:0;left:0}#root,#root button,#root h1,a{color:#FFF}html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}[v-cloak]{display:none}body{padding:0;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px}a{transition:color .4s ease;text-decoration:none}a:hover{color:#FB8C00;text-decoration:underline}#bg{position:fixed;z-index:1;background-color:#000}#bg>div{background-size:cover;background-position:center center;position:absolute;opacity:0;visibility:hidden;transition:opacity 3s ease,visibility 3s;animation:bg 30s linear infinite}#copyright,#root{display:flex;left:10vw;z-index:2}#bg>div:nth-child(1){animation-delay:10s}#bg>div:nth-child(2){animation-delay:20s}#root h1,#root h2{animation:headerIntro 3s ease;padding:0}#root{position:fixed;top:15vh;flex-direction:column}#root h1{font-size:4rem;margin:0}#root h2{font-size:1.5rem;font-weight:400;color:rgba(255,255,255,.7);margin:0 0 25px}#root input[type=password],#root input[type=text]{width:350px;max-width:80vw;border:1px solid rgba(255,255,255,.3);border-radius:3px;background-color:rgba(0,0,0,.2);padding:0 15px;height:40px;margin:0 0 10px;color:#FFF;font-weight:700;font-size:14px;transition:all .4s ease}#root input[type=password]:focus,#root input[type=text]:focus{outline:0;border-color:rgba(255,255,255,.8)}#root button{background-color:#FB8C00;border:1px solid #ffa32f;border-radius:3px;height:40px;width:125px;padding:0;font-weight:700;margin:15px 0 0;transition:all .4s ease;cursor:pointer}#root button:focus{outline:0;border-color:#FFF}#root button:hover{background-color:#c87000}#copyright{align-items:center;justify-content:flex-start;position:absolute;bottom:10vh;color:rgba(255,255,255,.5);font-weight:700}#copyright .icon{font-size:1.2rem;margin:0 8px}#copyright a{opacity:.75}@-webkit-keyframes bg{0%{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1);visibility:visible;opacity:0}33%,5%{opacity:.5}38%{-webkit-transform:scale(1.2,1.2);-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-o-transform:scale(1.2,1.2);transform:scale(1.2,1.2);opacity:0}39%{visibility:hidden}100%{visibility:hidden;opacity:0}}@-moz-keyframes bg{0%{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1);visibility:visible;opacity:0}33%,5%{opacity:.5}38%{-webkit-transform:scale(1.2,1.2);-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-o-transform:scale(1.2,1.2);transform:scale(1.2,1.2);opacity:0}39%{visibility:hidden}100%{visibility:hidden;opacity:0}}@-o-keyframes bg{0%{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1);visibility:visible;opacity:0}33%,5%{opacity:.5}38%{-webkit-transform:scale(1.2,1.2);-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-o-transform:scale(1.2,1.2);transform:scale(1.2,1.2);opacity:0}39%{visibility:hidden}100%{visibility:hidden;opacity:0}}@keyframes bg{0%{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1);visibility:visible;opacity:0}33%,5%{opacity:.5}38%{-webkit-transform:scale(1.2,1.2);-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-o-transform:scale(1.2,1.2);transform:scale(1.2,1.2);opacity:0}39%{visibility:hidden}100%{visibility:hidden;opacity:0}}@-webkit-keyframes headerIntro{0%{opacity:0}100%{opacity:1}}@-moz-keyframes headerIntro{0%{opacity:0}100%{opacity:1}}@-o-keyframes headerIntro{0%{opacity:0}100%{opacity:1}}@keyframes headerIntro{0%{opacity:0}100%{opacity:1}}
|
||||
#bg,#bg>div{width:100%;height:100%;top:0;left:0}#root,#root button,#root h1,a{color:#FFF}html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}[v-cloak]{display:none}body{padding:0;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px}a{transition:color .4s ease;text-decoration:none}a:hover{color:#FB8C00;text-decoration:underline}#bg{position:fixed;z-index:1;background-color:#000}#bg>div{background-size:cover;background-position:center center;position:absolute;opacity:0;visibility:hidden;transition:opacity 3s ease,visibility 3s;animation:bg 30s linear infinite}#copyright,#root{left:10vw;z-index:2}#bg>div:nth-child(1){animation-delay:10s}#bg>div:nth-child(2){animation-delay:20s}#root h1,#root h2{animation:headerIntro 3s ease;padding:0}#root{position:fixed;top:15vh;display:flex;flex-direction:column}#root h1{font-size:4rem;margin:0}#root h2{font-size:1.5rem;font-weight:400;color:rgba(255,255,255,.7);margin:0 0 25px}#root input[type=password],#root input[type=text]{width:350px;max-width:80vw;border:1px solid rgba(255,255,255,.3);border-radius:3px;background-color:rgba(0,0,0,.2);padding:0 15px;height:40px;margin:0 0 10px;color:#FFF;font-weight:700;font-size:14px;transition:all .4s ease}#root input[type=password]:focus,#root input[type=text]:focus{outline:0;border-color:rgba(255,255,255,.8)}#root button{background-color:#FB8C00;border:1px solid #ffa32f;border-radius:3px;height:40px;width:125px;padding:0;font-weight:700;margin:15px 0 0;transition:all .4s ease;cursor:pointer}#root button:focus{outline:0;border-color:#FFF}#root button:hover{background-color:#c87000}#root #social{margin-top:25px}#root #social>span{display:block;font-weight:700;color:rgba(255,255,255,.7)}#root #social button{margin-right:5px;width:auto;padding:0 15px}#root #social button>i{margin-right:10px;font-size:16px}#root #social button.ms{background-color:#009688;border-color:#00c9b6}#root #social button.ms:hover{background-color:#00635a}#root #social button.google{background-color:#2196F3;border-color:#51adf6}#root #social button.google:hover{background-color:#0c7cd5}#root #social button.facebook{background-color:#673AB7;border-color:#8259cb}#root #social button.facebook:hover{background-color:#512e90}#copyright{display:flex;align-items:center;justify-content:flex-start;position:absolute;bottom:10vh;color:rgba(255,255,255,.5);font-weight:700}#copyright .icon{font-size:1.2rem;margin:0 8px}#copyright a{opacity:.75}@-webkit-keyframes bg{0%{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1);visibility:visible;opacity:0}33%,5%{opacity:.5}38%{-webkit-transform:scale(1.2,1.2);-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-o-transform:scale(1.2,1.2);transform:scale(1.2,1.2);opacity:0}39%{visibility:hidden}100%{visibility:hidden;opacity:0}}@-moz-keyframes bg{0%{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1);visibility:visible;opacity:0}33%,5%{opacity:.5}38%{-webkit-transform:scale(1.2,1.2);-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-o-transform:scale(1.2,1.2);transform:scale(1.2,1.2);opacity:0}39%{visibility:hidden}100%{visibility:hidden;opacity:0}}@-o-keyframes bg{0%{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1);visibility:visible;opacity:0}33%,5%{opacity:.5}38%{-webkit-transform:scale(1.2,1.2);-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-o-transform:scale(1.2,1.2);transform:scale(1.2,1.2);opacity:0}39%{visibility:hidden}100%{visibility:hidden;opacity:0}}@keyframes bg{0%{-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1);visibility:visible;opacity:0}33%,5%{opacity:.5}38%{-webkit-transform:scale(1.2,1.2);-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-o-transform:scale(1.2,1.2);transform:scale(1.2,1.2);opacity:0}39%{visibility:hidden}100%{visibility:hidden;opacity:0}}@-webkit-keyframes headerIntro{0%{opacity:0}100%{opacity:1}}@-moz-keyframes headerIntro{0%{opacity:0}100%{opacity:1}}@-o-keyframes headerIntro{0%{opacity:0}100%{opacity:1}}@keyframes headerIntro{0%{opacity:0}100%{opacity:1}}
|
Binary file not shown.
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 144 KiB |
Binary file not shown.
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 134 KiB |
File diff suppressed because one or more lines are too long
@ -205,6 +205,7 @@
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
padding-top: 52px;
|
||||
font-family: $family-monospace;
|
||||
}
|
||||
|
||||
.CodeMirror .CodeMirror-code .cm-url {
|
||||
|
@ -36,6 +36,13 @@
|
||||
.mkcontent {
|
||||
|
||||
h1 {
|
||||
border-bottom: 1px dotted $blue;
|
||||
padding-bottom: 4px;
|
||||
font-weight: 400;
|
||||
color: desaturate($blue, 20%);
|
||||
}
|
||||
|
||||
h2 {
|
||||
border-bottom: 1px dotted $grey-light;
|
||||
padding-bottom: 4px;
|
||||
font-weight: 400;
|
||||
@ -44,7 +51,7 @@
|
||||
|
||||
a.toc-anchor {
|
||||
font-size: 80%;
|
||||
color: $purple;
|
||||
color: $blue;
|
||||
border-bottom: none;
|
||||
|
||||
&:visited {
|
||||
@ -74,6 +81,7 @@
|
||||
|
||||
pre {
|
||||
padding: 0;
|
||||
font-family: $family-monospace;
|
||||
|
||||
> code {
|
||||
box-shadow: inset 0 0 5px 0 $grey-light;
|
||||
@ -94,6 +102,7 @@
|
||||
float: right;
|
||||
margin-top: -50px;
|
||||
max-width: 200px;
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
strong {
|
||||
@ -104,6 +113,23 @@
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
table thead th {
|
||||
background-color: $blue;
|
||||
color: #FFF;
|
||||
border-color: #FFF;
|
||||
border-bottom-color: $blue;
|
||||
border-top-color: $blue;
|
||||
|
||||
&:first-child {
|
||||
border-left-color: $blue;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-right-color: $blue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.content a:not(.button):visited {
|
||||
|
@ -20,7 +20,7 @@ $yellow: #fce473 !default
|
||||
|
||||
// Typography
|
||||
|
||||
$family-monospace: monospace;
|
||||
$family-monospace: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
$family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
|
||||
$size-1: 48px !default
|
||||
|
@ -125,6 +125,59 @@ a {
|
||||
|
||||
}
|
||||
|
||||
#social {
|
||||
margin-top: 25px;
|
||||
|
||||
> span {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
color: rgba(255,255,255,0.7);
|
||||
}
|
||||
|
||||
button {
|
||||
margin-right: 5px;
|
||||
width: auto;
|
||||
padding: 0 15px;
|
||||
|
||||
> i {
|
||||
margin-right: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&.ms {
|
||||
background-color: #009688;
|
||||
border-color: lighten(#009688, 10%);
|
||||
|
||||
&:hover {
|
||||
background-color: darken(#009688, 10%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.google {
|
||||
background-color: #2196F3;
|
||||
border-color: lighten(#2196F3, 10%);
|
||||
|
||||
&:hover {
|
||||
background-color: darken(#2196F3, 10%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.facebook {
|
||||
background-color: #673AB7;
|
||||
border-color: lighten(#673AB7, 10%);
|
||||
|
||||
&:hover {
|
||||
background-color: darken(#673AB7, 10%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#copyright {
|
||||
|
@ -31,6 +31,26 @@ paths:
|
||||
repo: ./repo
|
||||
data: ./data
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Site Authentication
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
auth:
|
||||
local:
|
||||
enabled: true
|
||||
google:
|
||||
enabled: true
|
||||
clientId: GOOGLE_CLIENT_ID
|
||||
clientSecret: GOOGLE_CLIENT_SECRET
|
||||
microsoft:
|
||||
enabled: true
|
||||
clientId: MS_APP_ID
|
||||
clientSecret: MS_APP_SECRET
|
||||
facebook:
|
||||
enabled: false
|
||||
clientId: FACEBOOK_APP_ID
|
||||
clientSecret: FACEBOOK_APP_SECRET
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Database Connection String
|
||||
# ---------------------------------------------------------------------
|
||||
|
@ -59,6 +59,18 @@ router.post('/login', bruteforce.prevent, function(req, res, next) {
|
||||
})(req, res, next);
|
||||
});
|
||||
|
||||
/**
|
||||
* Social Login
|
||||
*/
|
||||
|
||||
router.get('/login/ms', passport.authenticate('windowslive', { scope: ['wl.signin', 'wl.basic', 'wl.emails'] }));
|
||||
router.get('/login/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
|
||||
router.get('/login/facebook', passport.authenticate('facebook', { scope: ['public_profile', 'email'] }));
|
||||
|
||||
router.get('/login/ms/callback', passport.authenticate('windowslive', { failureRedirect: '/login', successRedirect: '/' }));
|
||||
router.get('/login/google/callback', passport.authenticate('google', { failureRedirect: '/login', successRedirect: '/' }));
|
||||
router.get('/login/facebook/callback', passport.authenticate('facebook', { failureRedirect: '/login', successRedirect: '/' }));
|
||||
|
||||
/**
|
||||
* Logout
|
||||
*/
|
||||
|
@ -1,6 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = (socket) => {
|
||||
|
||||
console.log(socket.request.user);
|
||||
|
||||
//-----------------------------------------
|
||||
// SEARCH
|
||||
|
186
libs/auth.js
186
libs/auth.js
@ -1,66 +1,148 @@
|
||||
var LocalStrategy = require('passport-local').Strategy;
|
||||
"use strict";
|
||||
|
||||
const LocalStrategy = require('passport-local').Strategy;
|
||||
const GoogleStrategy = require('passport-google-oauth20').Strategy;
|
||||
const WindowsLiveStrategy = require('passport-windowslive').Strategy;
|
||||
const FacebookStrategy = require('passport-facebook').Strategy;
|
||||
const _ = require('lodash');
|
||||
|
||||
module.exports = function(passport, appconfig) {
|
||||
|
||||
// Serialization user methods
|
||||
// Serialization user methods
|
||||
|
||||
passport.serializeUser(function(user, done) {
|
||||
done(null, user._id);
|
||||
});
|
||||
passport.serializeUser(function(user, done) {
|
||||
done(null, user._id);
|
||||
});
|
||||
|
||||
passport.deserializeUser(function(id, done) {
|
||||
let user = db.User.find({ id });
|
||||
if(user) {
|
||||
done(null, user);
|
||||
} else {
|
||||
done(err, null);
|
||||
}
|
||||
});
|
||||
passport.deserializeUser(function(id, done) {
|
||||
db.User.findById(id).then((user) => {
|
||||
if(user) {
|
||||
done(null, user);
|
||||
} else {
|
||||
done(new Error('User not found.'), null);
|
||||
}
|
||||
return true;
|
||||
}).catch((err) => {
|
||||
done(err, null);
|
||||
});
|
||||
});
|
||||
|
||||
// Setup local user authentication strategy
|
||||
// Local Account
|
||||
|
||||
passport.use(
|
||||
'local',
|
||||
new LocalStrategy({
|
||||
usernameField : 'email',
|
||||
passwordField : 'password',
|
||||
passReqToCallback : true
|
||||
},
|
||||
function(req, uEmail, uPassword, done) {
|
||||
db.User.findOne({ 'email' : uEmail }).then((user) => {
|
||||
if (user) {
|
||||
user.validatePassword(uPassword).then((isValid) => {
|
||||
return (isValid) ? done(null, user) : done(null, false);
|
||||
});
|
||||
} else {
|
||||
return done(null, false);
|
||||
}
|
||||
}).catch((err) => {
|
||||
done(err);
|
||||
});
|
||||
})
|
||||
);
|
||||
if(appconfig.auth.local && appconfig.auth.local.enabled) {
|
||||
|
||||
// Check for admin access
|
||||
passport.use('local',
|
||||
new LocalStrategy({
|
||||
usernameField : 'email',
|
||||
passwordField : 'password',
|
||||
passReqToCallback : true
|
||||
},
|
||||
function(req, uEmail, uPassword, done) {
|
||||
db.User.findOne({ 'email' : uEmail }).then((user) => {
|
||||
if (user) {
|
||||
user.validatePassword(uPassword).then((isValid) => {
|
||||
return (isValid) ? done(null, user) : done(null, false);
|
||||
});
|
||||
} else {
|
||||
return done(null, false);
|
||||
}
|
||||
}).catch((err) => {
|
||||
done(err);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
db.onReady.then(() => {
|
||||
}
|
||||
|
||||
/*if(db.User.count() < 1) {
|
||||
winston.info('No administrator account found. Creating a new one...');
|
||||
if(db.User.insert({
|
||||
email: appconfig.admin,
|
||||
firstName: "Admin",
|
||||
lastName: "Admin",
|
||||
password: "admin123"
|
||||
})) {
|
||||
winston.info('Administrator account created successfully!');
|
||||
} else {
|
||||
winston.error('An error occured while creating administrator account: ');
|
||||
}
|
||||
}*/
|
||||
// Google ID
|
||||
|
||||
return true;
|
||||
if(appconfig.auth.google && appconfig.auth.google.enabled) {
|
||||
|
||||
});
|
||||
passport.use('google',
|
||||
new GoogleStrategy({
|
||||
clientID: appconfig.auth.google.clientId,
|
||||
clientSecret: appconfig.auth.google.clientSecret,
|
||||
callbackURL: appconfig.host + '/login/google/callback'
|
||||
},
|
||||
(accessToken, refreshToken, profile, cb) => {
|
||||
db.User.processProfile(profile).then((user) => {
|
||||
return cb(null, user) || true;
|
||||
}).catch((err) => {
|
||||
return cb(err, null) || true;
|
||||
});
|
||||
}
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
// Microsoft Accounts
|
||||
|
||||
if(appconfig.auth.microsoft && appconfig.auth.microsoft.enabled) {
|
||||
|
||||
passport.use('windowslive',
|
||||
new WindowsLiveStrategy({
|
||||
clientID: appconfig.auth.microsoft.clientId,
|
||||
clientSecret: appconfig.auth.microsoft.clientSecret,
|
||||
callbackURL: appconfig.host + '/login/ms/callback'
|
||||
},
|
||||
function(accessToken, refreshToken, profile, cb) {
|
||||
db.User.processProfile(profile).then((user) => {
|
||||
return cb(null, user) || true;
|
||||
}).catch((err) => {
|
||||
return cb(err, null) || true;
|
||||
});
|
||||
}
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
// Facebook
|
||||
|
||||
if(appconfig.auth.facebook && appconfig.auth.facebook.enabled) {
|
||||
|
||||
passport.use('facebook',
|
||||
new FacebookStrategy({
|
||||
clientID: appconfig.auth.facebook.clientId,
|
||||
clientSecret: appconfig.auth.facebook.clientSecret,
|
||||
callbackURL: appconfig.host + '/login/facebook/callback',
|
||||
profileFields: ['id', 'displayName', 'email']
|
||||
},
|
||||
function(accessToken, refreshToken, profile, cb) {
|
||||
db.User.processProfile(profile).then((user) => {
|
||||
return cb(null, user) || true;
|
||||
}).catch((err) => {
|
||||
return cb(err, null) || true;
|
||||
});
|
||||
}
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
// Check for admin access
|
||||
|
||||
db.onReady.then(() => {
|
||||
|
||||
db.User.count().then((c) => {
|
||||
if(c < 1) {
|
||||
winston.info('[' + PROCNAME + '][AUTH] No administrator account found. Creating a new one...');
|
||||
db.User.hashPassword('admin123').then((pwd) => {
|
||||
return db.User.create({
|
||||
provider: 'local',
|
||||
email: appconfig.admin,
|
||||
name: "Administrator",
|
||||
password: pwd
|
||||
});
|
||||
}).then(() => {
|
||||
winston.info('[' + PROCNAME + '][AUTH] Administrator account created successfully!');
|
||||
}).catch((err) => {
|
||||
winston.error('[' + PROCNAME + '][AUTH] An error occured while creating administrator account:');
|
||||
winston.error(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
});
|
||||
|
||||
};
|
@ -21,15 +21,36 @@ module.exports = (confPath) => {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return _.defaultsDeep(appconfig, {
|
||||
// Merge with defaults
|
||||
|
||||
appconfig = _.defaultsDeep(appconfig, {
|
||||
title: "Requarks Wiki",
|
||||
host: "http://localhost",
|
||||
port: process.env.PORT,
|
||||
wsPort: 8080,
|
||||
auth: {
|
||||
local: { enabled: true },
|
||||
microsoft: { enabled: false },
|
||||
google: { enabled: false },
|
||||
facebook: { enabled: false },
|
||||
},
|
||||
db: "mongodb://localhost/wiki",
|
||||
redis: null,
|
||||
sessionSecret: null,
|
||||
admin: null
|
||||
});
|
||||
|
||||
// List authentication strategies
|
||||
|
||||
appconfig.authStrategies = {
|
||||
list: _.filter(appconfig.auth, ['enabled', true]),
|
||||
socialEnabled: (_.chain(appconfig.auth).omit('local').reject({ enabled: false }).value().length > 0)
|
||||
}
|
||||
if(appconfig.authStrategies.list.length < 1) {
|
||||
winston.error(new Error('You must enable at least 1 authentication strategy!'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
return appconfig;
|
||||
|
||||
};
|
@ -6,7 +6,7 @@ module.exports = (isDebug) => {
|
||||
|
||||
winston.remove(winston.transports.Console);
|
||||
winston.add(winston.transports.Console, {
|
||||
level: (isDebug) ? 'info' : 'warn',
|
||||
level: (isDebug) ? 'debug' : 'info',
|
||||
prettyPrint: true,
|
||||
colorize: true,
|
||||
silent: false,
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
const modb = require('mongoose'),
|
||||
Promise = require('bluebird'),
|
||||
bcrypt = require('bcryptjs-then'),
|
||||
_ = require('lodash');
|
||||
|
||||
/**
|
||||
@ -12,13 +13,75 @@ const modb = require('mongoose'),
|
||||
var userSchema = modb.Schema({
|
||||
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
index: true
|
||||
},
|
||||
|
||||
provider: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
providerId: {
|
||||
type: String
|
||||
},
|
||||
|
||||
password: {
|
||||
type: String
|
||||
},
|
||||
|
||||
name: {
|
||||
type: String
|
||||
},
|
||||
|
||||
rights: [{
|
||||
type: String
|
||||
}]
|
||||
|
||||
},
|
||||
{
|
||||
timestamps: {}
|
||||
});
|
||||
|
||||
userSchema.statics.processProfile = (profile) => {
|
||||
|
||||
let primaryEmail = '';
|
||||
if(_.isArray(profile.emails)) {
|
||||
let e = _.find(profile.emails, ['primary', true]);
|
||||
primaryEmail = (e) ? e.value : _.first(profile.emails).value;
|
||||
} else if(_.isString(profile.email) && profile.email.length > 5) {
|
||||
primaryEmail = profile.email;
|
||||
} else {
|
||||
return Promise.reject(new Error('Invalid User Email'));
|
||||
}
|
||||
|
||||
return db.User.findOneAndUpdate({
|
||||
email: primaryEmail,
|
||||
provider: profile.provider
|
||||
}, {
|
||||
email: primaryEmail,
|
||||
provider: profile.provider,
|
||||
providerId: profile.id,
|
||||
name: profile.displayName
|
||||
}, {
|
||||
new: true,
|
||||
upsert: true
|
||||
}).then((user) => {
|
||||
return (user) ? user : Promise.reject(new Error('User Upsert failed.'));
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
userSchema.statics.hashPassword = (rawPwd) => {
|
||||
return bcrypt.hash(rawPwd);
|
||||
};
|
||||
|
||||
userSchema.methods.validatePassword = function(rawPwd) {
|
||||
let self = this;
|
||||
return bcrypt.hash(rawPwd).then((pwd) => {
|
||||
return (self.password === pwd) ? true : Promise.reject(new Error('Invalid Password'));
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = modb.model('User', userSchema);
|
@ -73,7 +73,11 @@
|
||||
"mongoose": "^4.6.3",
|
||||
"multer": "^1.2.0",
|
||||
"passport": "^0.3.2",
|
||||
"passport-facebook": "^2.1.1",
|
||||
"passport-google-oauth20": "^1.0.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-windowslive": "^1.0.2",
|
||||
"passport.socketio": "^3.6.2",
|
||||
"pug": "^2.0.0-beta6",
|
||||
"read-chunk": "^2.0.0",
|
||||
"remove-markdown": "^0.1.0",
|
||||
|
35
server.js
35
server.js
@ -46,6 +46,7 @@ const http = require('http');
|
||||
const i18next_backend = require('i18next-node-fs-backend');
|
||||
const i18next_mw = require('i18next-express-middleware');
|
||||
const passport = require('passport');
|
||||
const passportSocketIo = require('passport.socketio');
|
||||
const path = require('path');
|
||||
const session = require('express-session');
|
||||
const sessionMongoStore = require('connect-mongo')(session);
|
||||
@ -81,15 +82,16 @@ app.use(express.static(path.join(ROOTPATH, 'assets')));
|
||||
// Session
|
||||
// ----------------------------------------
|
||||
|
||||
var strategy = require('./libs/auth')(passport, appconfig);
|
||||
const strategies = require('./libs/auth')(passport, appconfig);
|
||||
var sessionStore = new sessionMongoStore({
|
||||
mongooseConnection: db.connection,
|
||||
touchAfter: 15
|
||||
});
|
||||
|
||||
app.use(cookieParser());
|
||||
app.use(session({
|
||||
name: 'requarkswiki.sid',
|
||||
store: new sessionMongoStore({
|
||||
mongooseConnection: db.connection,
|
||||
touchAfter: 15
|
||||
}),
|
||||
store: sessionStore,
|
||||
secret: appconfig.sessionSecret,
|
||||
resave: false,
|
||||
saveUninitialized: false
|
||||
@ -144,9 +146,9 @@ app.use(mw.flash);
|
||||
|
||||
app.use('/', ctrl.auth);
|
||||
|
||||
app.use('/uploads', ctrl.uploads);
|
||||
app.use('/uploads', mw.auth, ctrl.uploads);
|
||||
app.use('/admin', mw.auth, ctrl.admin);
|
||||
app.use('/', ctrl.pages);
|
||||
app.use('/', mw.auth, ctrl.pages);
|
||||
|
||||
// ----------------------------------------
|
||||
// Error handling
|
||||
@ -202,9 +204,26 @@ server.on('listening', () => {
|
||||
});
|
||||
|
||||
// ----------------------------------------
|
||||
// WebSocket handlers
|
||||
// WebSocket
|
||||
// ----------------------------------------
|
||||
|
||||
io.use(passportSocketIo.authorize({
|
||||
key: 'requarkswiki.sid',
|
||||
store: sessionStore,
|
||||
secret: appconfig.sessionSecret,
|
||||
passport,
|
||||
cookieParser,
|
||||
success: (data, accept) => {
|
||||
accept();
|
||||
},
|
||||
fail: (data, message, error, accept) => {
|
||||
if(error) {
|
||||
throw new Error(message);
|
||||
}
|
||||
return accept(new Error(message));
|
||||
}
|
||||
}));
|
||||
|
||||
io.on('connection', ctrl.ws);
|
||||
|
||||
// ----------------------------------------
|
||||
|
@ -27,14 +27,33 @@ html
|
||||
|
||||
body
|
||||
#bg
|
||||
each bg in [1, 2, 3]
|
||||
each bg in _.sampleSize([1, 2, 3],3)
|
||||
div(style="background-image:url(/images/bg_" + bg + ".jpg);")
|
||||
#root
|
||||
h1= appconfig.title
|
||||
h2 Login required
|
||||
input#login-user(type='text', placeholder='Email address')
|
||||
input#login-pass(type='password', placeholder='Password')
|
||||
button Log In
|
||||
if appconfig.auth.local.enabled
|
||||
input#login-user(type='text', placeholder='Email address')
|
||||
input#login-pass(type='password', placeholder='Password')
|
||||
button Log In
|
||||
if appconfig.authStrategies.socialEnabled
|
||||
#social
|
||||
if appconfig.auth.local.enabled
|
||||
span Or, log in using...
|
||||
else
|
||||
span Log in using...
|
||||
if appconfig.auth.microsoft && appconfig.auth.microsoft.enabled
|
||||
button.ms(onclick="window.location.assign('/login/ms')")
|
||||
i.fa.fa-windows
|
||||
span Microsoft Account
|
||||
if appconfig.auth.google && appconfig.auth.google.enabled
|
||||
button.google(onclick="window.location.assign('/login/google')")
|
||||
i.fa.fa-google
|
||||
span Google ID
|
||||
if appconfig.auth.facebook && appconfig.auth.facebook.enabled
|
||||
button.facebook(onclick="window.location.assign('/login/facebook')")
|
||||
i.fa.fa-facebook
|
||||
span Facebook
|
||||
#copyright
|
||||
= t('footer.poweredby') + ' '
|
||||
a.icon(href='https://github.com/Requarks/wiki')
|
||||
|
Loading…
Reference in New Issue
Block a user