Added login screen

master
Keith Irwin 2017-04-01 13:03:31 -04:00
parent 7153f7bb9b
commit 861fb48bb6
No known key found for this signature in database
GPG Key ID: 378933C743E2BBC0
7 changed files with 355 additions and 0 deletions

31
config/env-sample.js Normal file
View File

@ -0,0 +1,31 @@
'use strict';
module.exports = {
// Local variables
mode: 'development', // or production
// Random strings to prevent hijacking
session: 'SomeSecret',
cookie: 'SomeOtherSecret',
// Location of your mongoDB
mongoSetup: 'mongodb://localhost:27017/tracman',
// URL and port where this will run
url: 'https://localhost:8080',
port: 8080,
// OAuth API keys
facebookAppId: 'XXXXXXXXXXXXXXXX',
facebookAppSecret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
twitterConsumerKey: 'XXXXXXXXXXXXXXXXXXXXXXXXX',
twitterConsumerSecret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
googleClientId: '############-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com',
googleClientSecret: 'XXXXXXXXX_XXXXXXXXXXXXXX',
// Google maps API key
googleMapsAPI: 'XXXXXXXXXXXXXXX_XXXXXXXXXXXXXXXXXXXXXXX',
};

16
config/mail.js Normal file
View File

@ -0,0 +1,16 @@
'use strict';
module.exports = require('nodemailer').createTransport({
host: 'keithirwin.us',
port: 587,
secure: false,
requireTLS: true,
auth: {
user: 'NoReply@tracman.org',
pass: 'Ei0UwfrZuE'
},
// logger: true,
// debug: true
});
// require('./mail.js').(mailData, context).then(...).catch(...);

37
config/models.js Normal file
View File

@ -0,0 +1,37 @@
'use strict';
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: {type:String, required:true},
email: String,
slug: {type:String, required:true, unique:true},
requestId: String,
isAdmin: {type:Boolean, required:true, default:false},
isPro: {type:Boolean, required:true, default:false},
created: Date,
lastLogin: Date,
googleID: {type:Number, unique:true},
settings: {
units: {type:String, default:'standard'},
defaultMap: {type:String, default:'road'},
defaultZoom: {type:Number, default:11},
showSpeed: {type:Boolean, default:false},
showTemp: {type:Boolean, default:false},
showAlt: {type:Boolean, default:false},
showStreetview: {type:Boolean, default:false}
},
last: {
time: Date,
lat: {type:Number, default:0},
lon: {type:Number, default:0},
dir: {type:Number, default:0},
alt: {type:Number, default:0},
spd: {type:Number, default:0}
},
sk32: {type:String, required:true, unique:true}
});
module.exports = {
'user': mongoose.model('User', userSchema)
};

141
config/passport.js Normal file
View File

@ -0,0 +1,141 @@
'use strict';
var vars = require('./env.js'),
User = require('./models.js').user,
LocalStrategy = require('passport-local').Strategy,
GoogleStrategy = require('passport-google-oauth20').Strategy,
FacebookStrategy = require('passport-facebook').Strategy,
TwitterStrategy = require('passport-twitter').Strategy;
module.exports = function(passport) {
// Serialize/deserialize users
passport.serializeUser(function(user,done) {
done(null, user.id);
});
passport.deserializeUser(function(id,done) {
User.findById(id, function(err, user) {
if(!err){ done(null, user); }
else { done(err, null); }
});
});
// Signup
// passport.use('signup', new LocalStrategy({
// usernameField: 'email',
// passwordField: 'password',
// passReqToCallback : true
// }, function(req, email, password, done) {
// process.nextTick(function() {
// User.findOne({'email':email }, function(err, user) {
// if (err){ return done(err); }
// // Check for existing user
// if (user) {
// return done( null, false, req.flash('warning','That email is already in use. Try logging in below.') );
// // Create user
// } else {
// var newUser = new User();
// newUser.email = email;
// newUser.created = Date.now();
// newUser.lastLogin = Date.now();
// newUser.generateHash(password, function(err, hash){
// if (err){ return done(err); }
// newUser.auth.password = hash;
// newUser.save(function(err) {
// if (err){ return done(err); }
// return done( null, newUser );
// });
// });
// }
// });
// });
// })
// );
// Local
passport.use('local', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback : true
}, function(req, email, password, done) {
User.findOne({ 'email':email }, function (err, user) {
if (err){ return done(err); }
// Wrong username
if (!user) {
return done( null, false, req.flash('danger','No account exists for that email.') );
// Username correct, password incorrect
} else {
// Check password
user.validPassword(password, function(err,res){
if (err){ console.log('Passport error:\n',err); }
if (!res) { // Password incorrect
return done( null, false, req.flash('danger','Incorrect password.') );
} else { // Successful login
user.lastLogin = Date.now();
user.save();
return done( null, user );
}
});
}
});
}
));
// Social login
function socialLogin(req, service, profileId, done) {
if (!req.user) { // Log in
var query = {};
query['auth.'+service] = profileId;
User.findOne(query, function (err, user) {
if (err){ return done(err); }
else if (!user){ return done(); }
else { return done(null, user); }
});
} else {
req.user.auth[service] = profileId;
req.user.save(function(err){
if (err){ return done(err); }
else { return done(null, req.user); }
});
}
}
// Google
passport.use('google', new GoogleStrategy({
clientID: vars.googleClientId,
clientSecret: vars.googleClientSecret,
callbackURL: vars.url+'/login/google/cb',
passReqToCallback: true
}, function(req, accessToken, refreshToken, profile, done) {
socialLogin(req, 'google', profile.id, done);
}
));
// Facebook
passport.use('facebook', new FacebookStrategy({
clientID: vars.facebookAppId,
clientSecret: vars.facebookAppSecret,
callbackURL: vars.url+'/login/facebook/cb',
passReqToCallback: true
}, function(req, accessToken, refreshToken, profile, done) {
socialLogin(req, 'facebook', profile.id, done);
}
));
// Twitter
passport.use(new TwitterStrategy({
consumerKey: vars.twitterConsumerKey,
consumerSecret: vars.twitterConsumerSecret,
callbackURL: vars.url+'/login/twitter/cb',
passReqToCallback: true
}, function(req, token, tokenSecret, profile, done) {
socialLogin(req, 'twitter', profile.id, done);
}
));
return passport;
};

59
static/css/form.css Normal file
View File

@ -0,0 +1,59 @@
form label {
font-size: 1.2em;
margin-right: 3%;
}
form input, form textarea, form select {
-moz-box-shadow: inset .11vw .18vw .25vw rgba(0,0,0,.5);
-webkit-box-shadow: inset .11vw .18vw .25vw rgba(0,0,0,.5);
box-shadow: inset .11vw .18vw .25vw rgba(0,0,0,.5);
color: #eee;
background-color: rgba(255,255,255,0.1);
padding: 1% 1.5%;
border: 1px solid #666;
border-radius: .3vw;
}
form input:active, form textarea:active, form select:active,
form input:focus, form textarea:focus, form select:focus {
outline: none;
border: 1px solid #fbc93d;
}
::-webkit-input-placeholder {
color: #666;
}:-moz-placeholder {
color: #666;
opacity: 1;
}::-moz-placeholder {
color: #666;
opacity: 1;
}:-ms-input-placeholder {
color: #666;
}
form select {
-moz-box-shadow: inset 0 1px 6px rgba(255,255,255,.2),
inset -.11vw -.18vw .52vw rgba(0,0,0,.4);
-webkit-box-shadow: inset -.11vw -.18vw .52vw rgba(255,255,255,.2),
inset -.11vw -.18vw .52vw rgba(0,0,0,.4);
box-shadow: inset 0 .11vw .52vw rgba(255,255,255,.2),
inset 0 .11vw .52vw rgba(0,0,0,.4);
}
form select > option {
color: #000;
}
form input[type="checkbox"], form input[type="radio"] {
width: auto;
margin: 8px 8px 8px 0;
}
form input[type="checkbox"]:active, form input[type="radio"]:active,
form input[type="checkbox"]:focus, form input[type="radio"]:focus {
outline: 1px solid #fbc93d;
}
form .btn {
font-size: 1.5em;
}

49
static/css/login.css Normal file
View File

@ -0,0 +1,49 @@
section > .flex > div {
width: 50%;
padding: 0 2%;
}
form input {
width: 96%;
}
form input.btn,
form #social-login {
width: 100%;
}
#social-login .btn {
padding: 0;
font-size: 1.3em;
height: 60px;
text-align: center;
width: 60px;
margin: 0 3%;
color: #FFF;
} #social-login .btn .fa {
margin: 0;
position: relative;
padding-top: 20px;
} #social-login .btn.gp {
background: rgb(206,77,57);
} #social-login .btn.gp:hover {
background: rgb(251,122,102);
} #social-login .btn.fb {
background: rgb(48,88,145);
} #social-login .btn.fb:hover {
background: rgb(93,133,190);
} #social-login .btn.tw {
background: rgb(44,168,210);
} #social-login .btn.tw:hover {
background: rgb(89,213,255);
}
@media (max-width: 800px) {
section > .flex {
flex-direction: column;
}
section > .flex > div {
width: 100%;
}
hr.hide { display:block; }
}

22
views/privacy.html Normal file
View File

@ -0,0 +1,22 @@
{% extends 'templates/base.html' %}
{% block title %}{{super()}} | Privacy Policy{% endblock %}
{% block main %}
<section class='container'>
<h2>Privacy Policy</h2>
<p>In lieu of legalease, which I don't speak, here is a quick rundown of what Tracman does with your data (such as location). </p>
<h3>Location history</h3>
<p>Your location is saved on the database as long as you have it "set" or "tracking". If you "clear" the data, it will be deleted from the database too. This doesn't mean all copies are destroyed. Our servers keep occasional backups, and caches could exist on other servers (google index, wayback archive, etc). </p>
<p>This means that all public access to your location is essentially deleted when you clear it. But anyone could record your location while it's publicly available and rebroadcast it. Tracman doesn't store location histories (except as mentioned above), but histories may exist elsewhere! If you have (or plan to have) trouble with the law, don't use Tracman. Authorities have easy access to those histories. </p>
<h3>Email addresses</h3>
<p>Tracman stores email addresses so we can contact users for important stuff (urgent security updates, deletion requests, lost passwords). We will never subscribe you to anything else by default. </p>
</section>
{% endblock %}