Merge remote-tracking branch 'upstream/3.0' into 3.0
This commit is contained in:
commit
a291cfecb4
|
@ -64,6 +64,8 @@ http:
|
|||
gzip: true
|
||||
# Customize the threshold byte size for applying gzip
|
||||
gzip-threshold: 1024
|
||||
# Secret used for signed cookies. Can be anything, but make it unique and hard to guess
|
||||
cookie-secret: 'change-me'
|
||||
|
||||
# HTTPS server details
|
||||
https:
|
||||
|
@ -109,6 +111,7 @@ mail:
|
|||
user: 'some.user@gmail.com'
|
||||
pass: 'supersecretpassword'
|
||||
from-address: 'some.user@gmail.com'
|
||||
from-name: 'CyTube Services'
|
||||
|
||||
# GData API v2 developer key (for non-anonymous youtube requests)
|
||||
youtube-v2-key: ''
|
||||
|
|
|
@ -33,7 +33,8 @@ var defaults = {
|
|||
minify: false,
|
||||
"max-age": "7d",
|
||||
gzip: true,
|
||||
"gzip-threshold": 1024
|
||||
"gzip-threshold": 1024,
|
||||
"cookie-secret": "change-me"
|
||||
},
|
||||
https: {
|
||||
enabled: false,
|
||||
|
@ -53,7 +54,8 @@ var defaults = {
|
|||
enabled: false,
|
||||
/* the key "config" is omitted because the format depends on the
|
||||
service the owner is configuring for nodemailer */
|
||||
"from-address": "some.user@gmail.com"
|
||||
"from-address": "some.user@gmail.com",
|
||||
"from-name": "CyTube Services"
|
||||
},
|
||||
"youtube-v2-key": "",
|
||||
"channel-save-interval": 5,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
//var db = require("../database");
|
||||
var $util = require("../utilities");
|
||||
var bcrypt = require("bcrypt");
|
||||
var db = require("../database");
|
||||
|
@ -59,6 +58,25 @@ module.exports = {
|
|||
});
|
||||
},
|
||||
|
||||
getUser: function (name, callback) {
|
||||
if (typeof callback !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
db.query("SELECT * FROM `users` WHERE name = ?", [name], function (err, rows) {
|
||||
if (err) {
|
||||
callback(err, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rows.length !== 1) {
|
||||
return callback("User does not exist");
|
||||
}
|
||||
|
||||
callback(null, rows[0]);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Registers a new user account
|
||||
*/
|
||||
|
@ -198,11 +216,7 @@ module.exports = {
|
|||
} else if (!match) {
|
||||
callback("Invalid username/password combination", null);
|
||||
} else {
|
||||
callback(null, {
|
||||
name: rows[0].name,
|
||||
hash: rows[0].password,
|
||||
global_rank: rows[0].global_rank
|
||||
});
|
||||
callback(null, rows[0]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,8 @@ const TBL_USERS = "" +
|
|||
"`global_rank` INT NOT NULL," +
|
||||
"`email` VARCHAR(255) NOT NULL," +
|
||||
"`profile` TEXT CHARACTER SET utf8mb4 NOT NULL," +
|
||||
"`ip` VARCHAR(39) NOT NULL," + "`time` BIGINT NOT NULL," +
|
||||
"`ip` VARCHAR(39) NOT NULL," +
|
||||
"`time` BIGINT NOT NULL," +
|
||||
"PRIMARY KEY(`id`)," +
|
||||
"UNIQUE(`name`)) " +
|
||||
"CHARACTER SET utf8";
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
var sio = require("socket.io");
|
||||
var cookieParser = require("cookie-parser")();
|
||||
var Logger = require("../logger");
|
||||
var db = require("../database");
|
||||
var User = require("../user");
|
||||
var Server = require("../server");
|
||||
var Config = require("../config");
|
||||
var cookieParser = require("cookie-parser")(Config.get("http.cookie-secret"));
|
||||
var $util = require("../utilities");
|
||||
var Flags = require("../flags");
|
||||
var Account = require("../account");
|
||||
|
@ -13,6 +13,7 @@ var net = require("net");
|
|||
var util = require("../utilities");
|
||||
var crypto = require("crypto");
|
||||
var isTorExit = require("../tor").isTorExit;
|
||||
var session = require("../session");
|
||||
|
||||
var CONNECT_RATE = {
|
||||
burst: 5,
|
||||
|
@ -32,8 +33,12 @@ function handleAuth(socket, accept) {
|
|||
socket.user = false;
|
||||
if (data.headers.cookie) {
|
||||
cookieParser(data, null, function () {
|
||||
var auth = data.cookies.auth;
|
||||
db.users.verifyAuth(auth, function (err, user) {
|
||||
var auth = data.signedCookies.auth;
|
||||
if (!auth) {
|
||||
return accept(null, true);
|
||||
}
|
||||
|
||||
session.verifySession(auth, function (err, user) {
|
||||
if (!err) {
|
||||
socket.user = {
|
||||
name: user.name,
|
||||
|
|
54
lib/session.js
Normal file
54
lib/session.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
var dbAccounts = require("./database/accounts");
|
||||
var util = require("./utilities");
|
||||
var crypto = require("crypto");
|
||||
|
||||
function sha256(input) {
|
||||
var hash = crypto.createHash("sha256");
|
||||
hash.update(input);
|
||||
return hash.digest("base64");
|
||||
}
|
||||
|
||||
exports.genSession = function (account, expiration, cb) {
|
||||
if (expiration instanceof Date) {
|
||||
expiration = Date.parse(expiration);
|
||||
}
|
||||
|
||||
var salt = crypto.pseudoRandomBytes(24).toString("base64");
|
||||
var hashInput = [account.name, account.password, expiration, salt].join(":");
|
||||
var hash = sha256(hashInput);
|
||||
|
||||
cb(null, [account.name, expiration, salt, hash].join(":"));
|
||||
};
|
||||
|
||||
exports.verifySession = function (input, cb) {
|
||||
if (typeof input !== "string") {
|
||||
return cb("Invalid auth string");
|
||||
}
|
||||
|
||||
var parts = input.split(":");
|
||||
if (parts.length !== 4) {
|
||||
return cb("Invalid auth string");
|
||||
}
|
||||
|
||||
var name = parts[0];
|
||||
var expiration = parts[1];
|
||||
var salt = parts[2];
|
||||
var hash = parts[3];
|
||||
|
||||
if (Date.now() > parseInt(expiration)) {
|
||||
return cb("Session expired");
|
||||
}
|
||||
|
||||
dbAccounts.getUser(name, function (err, account) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
var hashInput = [account.name, account.password, expiration, salt].join(":");
|
||||
if (sha256(hashInput) !== hash) {
|
||||
return cb("Invalid auth string");
|
||||
}
|
||||
|
||||
cb(null, account);
|
||||
});
|
||||
};
|
|
@ -11,6 +11,7 @@ var db = require("../database");
|
|||
var $util = require("../utilities");
|
||||
var Config = require("../config");
|
||||
var Server = require("../server");
|
||||
var session = require("../session");
|
||||
|
||||
/**
|
||||
* Handles a GET request for /account/edit
|
||||
|
@ -20,23 +21,7 @@ function handleAccountEditPage(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
}
|
||||
|
||||
db.users.verifyAuth(req.cookies.auth, function (err, user) {
|
||||
if (err) {
|
||||
return sendJade(res, "account-edit", {
|
||||
loggedIn: false
|
||||
});
|
||||
}
|
||||
|
||||
sendJade(res, "account-edit", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName
|
||||
});
|
||||
});
|
||||
sendJade(res, "account-edit", {});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,10 +49,6 @@ function handleChangePassword(req, res) {
|
|||
var name = req.body.name;
|
||||
var oldpassword = req.body.oldpassword;
|
||||
var newpassword = req.body.newpassword;
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
}
|
||||
|
||||
if (typeof name !== "string" ||
|
||||
typeof oldpassword !== "string" ||
|
||||
|
@ -78,20 +59,23 @@ function handleChangePassword(req, res) {
|
|||
|
||||
if (newpassword.length === 0) {
|
||||
sendJade(res, "account-edit", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
errorMessage: "New password must not be empty"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!req.user) {
|
||||
sendJade(res, "account-edit", {
|
||||
errorMessage: "You must be logged in to change your password"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
newpassword = newpassword.substring(0, 100);
|
||||
|
||||
db.users.verifyLogin(name, oldpassword, function (err, user) {
|
||||
if (err) {
|
||||
sendJade(res, "account-edit", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
errorMessage: err
|
||||
});
|
||||
return;
|
||||
|
@ -100,18 +84,49 @@ function handleChangePassword(req, res) {
|
|||
db.users.setPassword(name, newpassword, function (err, dbres) {
|
||||
if (err) {
|
||||
sendJade(res, "account-edit", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
errorMessage: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.eventlog.log("[account] " + webserver.ipForRequest(req) +
|
||||
" changed password for " + name);
|
||||
sendJade(res, "account-edit", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
successMessage: "Password changed."
|
||||
|
||||
db.users.getUser(name, function (err, user) {
|
||||
if (err) {
|
||||
return sendJade(res, "account-edit", {
|
||||
errorMessage: err
|
||||
});
|
||||
}
|
||||
|
||||
res.user = user;
|
||||
var expiration = new Date(parseInt(req.signedCookies.auth.split(":")[1]));
|
||||
session.genSession(user, expiration, function (err, auth) {
|
||||
if (err) {
|
||||
return sendJade(res, "account-edit", {
|
||||
errorMessage: err
|
||||
});
|
||||
}
|
||||
|
||||
if (req.hostname.indexOf(Config.get("http.root-domain")) >= 0) {
|
||||
res.cookie("auth", auth, {
|
||||
domain: Config.get("http.root-domain-dotted"),
|
||||
expires: expiration,
|
||||
httpOnly: true,
|
||||
signed: true
|
||||
});
|
||||
} else {
|
||||
res.cookie("auth", auth, {
|
||||
expires: expiration,
|
||||
httpOnly: true,
|
||||
signed: true
|
||||
});
|
||||
}
|
||||
|
||||
sendJade(res, "account-edit", {
|
||||
successMessage: "Password changed."
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -124,10 +139,6 @@ function handleChangeEmail(req, res) {
|
|||
var name = req.body.name;
|
||||
var password = req.body.password;
|
||||
var email = req.body.email;
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
}
|
||||
|
||||
if (typeof name !== "string" ||
|
||||
typeof password !== "string" ||
|
||||
|
@ -138,8 +149,6 @@ function handleChangeEmail(req, res) {
|
|||
|
||||
if (!$util.isValidEmail(email) && email !== "") {
|
||||
sendJade(res, "account-edit", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
errorMessage: "Invalid email address"
|
||||
});
|
||||
return;
|
||||
|
@ -148,8 +157,6 @@ function handleChangeEmail(req, res) {
|
|||
db.users.verifyLogin(name, password, function (err, user) {
|
||||
if (err) {
|
||||
sendJade(res, "account-edit", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
errorMessage: err
|
||||
});
|
||||
return;
|
||||
|
@ -158,8 +165,6 @@ function handleChangeEmail(req, res) {
|
|||
db.users.setEmail(name, email, function (err, dbres) {
|
||||
if (err) {
|
||||
sendJade(res, "account-edit", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
errorMessage: err
|
||||
});
|
||||
return;
|
||||
|
@ -168,8 +173,6 @@ function handleChangeEmail(req, res) {
|
|||
" changed email for " + name +
|
||||
" to " + email);
|
||||
sendJade(res, "account-edit", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
successMessage: "Email address changed."
|
||||
});
|
||||
});
|
||||
|
@ -184,33 +187,17 @@ function handleAccountChannelPage(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
if (!req.user) {
|
||||
return sendJade(res, "account-channels", {
|
||||
channels: []
|
||||
});
|
||||
}
|
||||
|
||||
if (loginName) {
|
||||
db.users.verifyAuth(req.cookies.auth, function (err, user) {
|
||||
if (err) {
|
||||
return sendJade(res, "account-channels", {
|
||||
loggedIn: false
|
||||
});
|
||||
}
|
||||
|
||||
db.channels.listUserChannels(loginName, function (err, channels) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
channels: channels
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
db.channels.listUserChannels(req.user.name, function (err, channels) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: false,
|
||||
channels: [],
|
||||
channels: channels
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -242,87 +229,64 @@ function handleNewChannel(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
} else {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: false,
|
||||
if (!req.user) {
|
||||
return sendJade(res, "account-channels", {
|
||||
channels: []
|
||||
});
|
||||
return;
|
||||
}
|
||||
db.users.verifyAuth(req.cookies.auth, function (err, user) {
|
||||
|
||||
db.channels.listUserChannels(req.user.name, function (err, channels) {
|
||||
if (err) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: false,
|
||||
channels: [],
|
||||
newChannelError: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
db.channels.listUserChannels(loginName, function (err, channels) {
|
||||
if (err) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
channels: [],
|
||||
newChannelError: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (name.match(Config.get("reserved-names.channels"))) {
|
||||
sendJade(res, "account-channels", {
|
||||
channels: channels,
|
||||
newChannelError: "That channel name is reserved"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.match(Config.get("reserved-names.channels"))) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
channels: channels,
|
||||
newChannelError: "That channel name is reserved"
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (channels.length >= Config.get("max-channels-per-user")) {
|
||||
sendJade(res, "account-channels", {
|
||||
channels: channels,
|
||||
newChannelError: "You are not allowed to register more than " +
|
||||
Config.get("max-channels-per-user") + " channels."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (channels.length >= Config.get("max-channels-per-user")) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
channels: channels,
|
||||
newChannelError: "You are not allowed to register more than " +
|
||||
Config.get("max-channels-per-user") + " channels."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
db.channels.register(name, user.name, function (err, channel) {
|
||||
if (!err) {
|
||||
Logger.eventlog.log("[channel] " + user.name + "@" +
|
||||
webserver.ipForRequest(req) +
|
||||
" registered channel " + name);
|
||||
var sv = Server.getServer();
|
||||
if (sv.isChannelLoaded(name)) {
|
||||
var chan = sv.getChannel(name);
|
||||
var users = Array.prototype.slice.call(chan.users);
|
||||
users.forEach(function (u) {
|
||||
u.kick("Channel reloading");
|
||||
});
|
||||
|
||||
if (!chan.dead) {
|
||||
chan.emit("empty");
|
||||
}
|
||||
}
|
||||
channels.push({
|
||||
name: name
|
||||
db.channels.register(name, req.user.name, function (err, channel) {
|
||||
if (!err) {
|
||||
Logger.eventlog.log("[channel] " + req.user.name + "@" +
|
||||
webserver.ipForRequest(req) +
|
||||
" registered channel " + name);
|
||||
var sv = Server.getServer();
|
||||
if (sv.isChannelLoaded(name)) {
|
||||
var chan = sv.getChannel(name);
|
||||
var users = Array.prototype.slice.call(chan.users);
|
||||
users.forEach(function (u) {
|
||||
u.kick("Channel reloading");
|
||||
});
|
||||
|
||||
if (!chan.dead) {
|
||||
chan.emit("empty");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
channels: channels,
|
||||
newChannelError: err ? err : undefined
|
||||
channels.push({
|
||||
name: name
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sendJade(res, "account-channels", {
|
||||
channels: channels,
|
||||
newChannelError: err ? err : undefined
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -338,75 +302,55 @@ function handleDeleteChannel(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
} else {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: false,
|
||||
if (!req.user) {
|
||||
return sendJade(res, "account-channels", {
|
||||
channels: [],
|
||||
});
|
||||
return;
|
||||
}
|
||||
db.users.verifyAuth(req.cookies.auth, function (err, user) {
|
||||
|
||||
|
||||
db.channels.lookup(name, function (err, channel) {
|
||||
if (err) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: false,
|
||||
channels: [],
|
||||
deleteChannelError: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
db.channels.lookup(name, function (err, channel) {
|
||||
if (err) {
|
||||
if (channel.owner !== req.user.name && req.user.global_rank < 255) {
|
||||
db.channels.listUserChannels(req.user.name, function (err2, channels) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
channels: [],
|
||||
deleteChannelError: err
|
||||
channels: err2 ? [] : channels,
|
||||
deleteChannelError: "You do not have permission to delete this channel"
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel.owner !== user.name && user.global_rank < 255) {
|
||||
db.channels.listUserChannels(loginName, function (err2, channels) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
channels: err2 ? [] : channels,
|
||||
deleteChannelError: "You do not have permission to delete this channel"
|
||||
});
|
||||
db.channels.drop(name, function (err) {
|
||||
if (!err) {
|
||||
Logger.eventlog.log("[channel] " + req.user.name + "@" +
|
||||
webserver.ipForRequest(req) + " deleted channel " +
|
||||
name);
|
||||
}
|
||||
var sv = Server.getServer();
|
||||
if (sv.isChannelLoaded(name)) {
|
||||
var chan = sv.getChannel(name);
|
||||
chan.clearFlag(require("../flags").C_REGISTERED);
|
||||
var users = Array.prototype.slice.call(chan.users);
|
||||
users.forEach(function (u) {
|
||||
u.kick("Channel reloading");
|
||||
});
|
||||
return;
|
||||
|
||||
if (!chan.dead) {
|
||||
chan.emit("empty");
|
||||
}
|
||||
}
|
||||
|
||||
db.channels.drop(name, function (err) {
|
||||
if (!err) {
|
||||
Logger.eventlog.log("[channel] " + loginName + "@" +
|
||||
webserver.ipForRequest(req) + " deleted channel " +
|
||||
name);
|
||||
}
|
||||
var sv = Server.getServer();
|
||||
if (sv.isChannelLoaded(name)) {
|
||||
var chan = sv.getChannel(name);
|
||||
chan.clearFlag(require("../flags").C_REGISTERED);
|
||||
var users = Array.prototype.slice.call(chan.users);
|
||||
users.forEach(function (u) {
|
||||
u.kick("Channel reloading");
|
||||
});
|
||||
|
||||
if (!chan.dead) {
|
||||
chan.emit("empty");
|
||||
}
|
||||
}
|
||||
db.channels.listUserChannels(loginName, function (err2, channels) {
|
||||
sendJade(res, "account-channels", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
channels: err2 ? [] : channels,
|
||||
deleteChannelError: err ? err : undefined
|
||||
});
|
||||
db.channels.listUserChannels(req.user.name, function (err2, channels) {
|
||||
sendJade(res, "account-channels", {
|
||||
channels: err2 ? [] : channels,
|
||||
deleteChannelError: err ? err : undefined
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -421,70 +365,49 @@ function handleAccountProfilePage(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
var loginName = false;
|
||||
if (!req.cookies.auth) {
|
||||
if (!req.user) {
|
||||
return sendJade(res, "account-profile", {
|
||||
loggedIn: false,
|
||||
profileImage: "",
|
||||
profileText: ""
|
||||
});
|
||||
} else {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
db.users.verifyAuth(req.cookies.auth, function (err, user) {
|
||||
if (err) {
|
||||
return sendJade(res, "account-profile", {
|
||||
loggedIn: false
|
||||
});
|
||||
}
|
||||
|
||||
db.users.getProfile(loginName, function (err, profile) {
|
||||
if (err) {
|
||||
sendJade(res, "account-profile", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
profileError: err,
|
||||
profileImage: "",
|
||||
profileText: ""
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
sendJade(res, "account-profile", {
|
||||
loggedIn: true,
|
||||
loginName: loginName,
|
||||
profileImage: profile.image,
|
||||
profileText: profile.text,
|
||||
profileError: false
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
db.users.getProfile(req.user.name, function (err, profile) {
|
||||
if (err) {
|
||||
sendJade(res, "account-profile", {
|
||||
profileError: err,
|
||||
profileImage: "",
|
||||
profileText: ""
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
sendJade(res, "account-profile", {
|
||||
profileImage: profile.image,
|
||||
profileText: profile.text,
|
||||
profileError: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a POST request to edit a profile
|
||||
*/
|
||||
function handleAccountProfile(req, res) {
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
} else {
|
||||
sendJade(res, "account-profile", {
|
||||
loggedIn: false,
|
||||
if (!req.user) {
|
||||
return sendJade(res, "account-profile", {
|
||||
profileImage: "",
|
||||
profileText: "",
|
||||
profileError: "You must be logged in to edit your profile",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var image = req.body.image;
|
||||
var text = req.body.text;
|
||||
|
||||
db.users.verifyAuth(req.cookies.auth, function (err, user) {
|
||||
db.users.setProfile(req.user.name, { image: image, text: text }, function (err) {
|
||||
if (err) {
|
||||
sendJade(res, "account-profile", {
|
||||
loggedIn: false,
|
||||
profileImage: "",
|
||||
profileText: "",
|
||||
profileError: err
|
||||
|
@ -492,25 +415,10 @@ function handleAccountProfile(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
db.users.setProfile(user.name, { image: image, text: text }, function (err) {
|
||||
if (err) {
|
||||
sendJade(res, "account-profile", {
|
||||
loggedIn: true,
|
||||
loginName: user.name,
|
||||
profileImage: "",
|
||||
profileText: "",
|
||||
profileError: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
sendJade(res, "account-profile", {
|
||||
loggedIn: true,
|
||||
loginName: user.name,
|
||||
profileImage: image,
|
||||
profileText: text,
|
||||
profileError: false
|
||||
});
|
||||
sendJade(res, "account-profile", {
|
||||
profileImage: image,
|
||||
profileText: text,
|
||||
profileError: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -621,7 +529,7 @@ function handlePasswordReset(req, res) {
|
|||
Config.get("http.domain") + "/account/passwordrecover/"+hash;
|
||||
|
||||
var mail = {
|
||||
from: "CyTube Services <" + Config.get("mail.from") + ">",
|
||||
from: Config.get("mail.from-name") + " <" + Config.get("mail.from-address") + ">",
|
||||
to: email,
|
||||
subject: "Password reset request",
|
||||
text: msg
|
||||
|
@ -664,8 +572,7 @@ function handlePasswordRecover(req, res) {
|
|||
if (err) {
|
||||
sendJade(res, "account-passwordrecover", {
|
||||
recovered: false,
|
||||
recoverErr: err,
|
||||
loginName: false
|
||||
recoverErr: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -675,8 +582,7 @@ function handlePasswordRecover(req, res) {
|
|||
recovered: false,
|
||||
recoverErr: "This password recovery link has expired. Password " +
|
||||
"recovery links are valid only for 24 hours after " +
|
||||
"submission.",
|
||||
loginName: false
|
||||
"submission."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -691,8 +597,8 @@ function handlePasswordRecover(req, res) {
|
|||
sendJade(res, "account-passwordrecover", {
|
||||
recovered: false,
|
||||
recoverErr: "Database error. Please contact an administrator if " +
|
||||
"this persists.",
|
||||
loginName: false
|
||||
"this persists."
|
||||
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -702,8 +608,7 @@ function handlePasswordRecover(req, res) {
|
|||
|
||||
sendJade(res, "account-passwordrecover", {
|
||||
recovered: true,
|
||||
recoverPw: newpw,
|
||||
loginName: false
|
||||
recoverPw: newpw
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,31 +8,18 @@ var Config = require("../config");
|
|||
|
||||
function checkAdmin(cb) {
|
||||
return function (req, res) {
|
||||
var auth = req.cookies.auth;
|
||||
if (!auth) {
|
||||
if (!req.user) {
|
||||
return res.send(403);
|
||||
}
|
||||
|
||||
if (req.user.global_rank < 255) {
|
||||
res.send(403);
|
||||
Logger.eventlog.log("[acp] Attempted GET "+req.path+" from non-admin " +
|
||||
user.name + "@" + webserver.ipForRequest(req));
|
||||
return;
|
||||
}
|
||||
db.users.verifyAuth(auth, function (err, user) {
|
||||
if (err) {
|
||||
if (err === "Invalid auth string" ||
|
||||
err === "Auth string does not match an existing user") {
|
||||
res.send(403);
|
||||
} else {
|
||||
res.send(500);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.global_rank < 255) {
|
||||
res.send(403);
|
||||
Logger.eventlog.log("[acp] Attempted GET "+req.path+" from non-admin " +
|
||||
user.name + "@" + webserver.ipForRequest(req));
|
||||
return;
|
||||
}
|
||||
|
||||
cb(req, res, user);
|
||||
});
|
||||
cb(req, res, req.user);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -49,8 +36,6 @@ function handleAcp(req, res, user) {
|
|||
sio += "/socket.io/socket.io.js";
|
||||
|
||||
sendJade(res, "acp", {
|
||||
loginName: user.name,
|
||||
loggedIn: true,
|
||||
sioSource: sio
|
||||
});
|
||||
}
|
||||
|
|
224
lib/web/auth.js
224
lib/web/auth.js
|
@ -14,6 +14,7 @@ var $util = require("../utilities");
|
|||
var db = require("../database");
|
||||
var Config = require("../config");
|
||||
var url = require("url");
|
||||
var session = require("../session");
|
||||
|
||||
/**
|
||||
* Processes a login request. Sets a cookie upon successful authentication
|
||||
|
@ -21,12 +22,29 @@ var url = require("url");
|
|||
function handleLogin(req, res) {
|
||||
var name = req.body.name;
|
||||
var password = req.body.password;
|
||||
var rememberMe = req.body.remember;
|
||||
var dest = req.body.dest || req.header("referer") || null;
|
||||
dest = dest.match(/login|logout/) ? null : dest;
|
||||
|
||||
if (typeof name !== "string" || typeof password !== "string") {
|
||||
res.send(400);
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
var host = req.hostname;
|
||||
if (host.indexOf(Config.get("http.root-domain")) === -1 &&
|
||||
Config.get("http.alt-domains").indexOf(host) === -1) {
|
||||
Logger.syslog.log("WARNING: Attempted login from non-approved domain " + host);
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
|
||||
var expiration;
|
||||
if (rememberMe) {
|
||||
expiration = new Date("Fri, 31 Dec 9999 23:59:59 GMT");
|
||||
} else {
|
||||
expiration = new Date(Date.now() + 7*24*60*60*1000);
|
||||
}
|
||||
|
||||
password = password.substring(0, 100);
|
||||
|
||||
db.users.verifyLogin(name, password, function (err, user) {
|
||||
|
@ -39,124 +57,43 @@ function handleLogin(req, res) {
|
|||
loggedIn: false,
|
||||
loginError: err
|
||||
});
|
||||
} else {
|
||||
var auth = user.name + ":" + user.hash;
|
||||
res.cookie("auth", auth, {
|
||||
expires: new Date(Date.now() + 7*24*60*60*1000),
|
||||
httpOnly: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.cookie("auth", auth, {
|
||||
domain: Config.get("http.root-domain-dotted"),
|
||||
expires: new Date(Date.now() + 7*24*60*60*1000),
|
||||
httpOnly: true
|
||||
});
|
||||
|
||||
res.cookie("rank", user.global_rank, {
|
||||
domain: Config.get("http.root-domain-dotted"),
|
||||
expires: new Date(Date.now() + 7*24*60*60*1000),
|
||||
});
|
||||
|
||||
// Try to find an appropriate redirect
|
||||
var ref = req.header("referrer");
|
||||
if (!ref) {
|
||||
ref = req.body.redirect;
|
||||
}
|
||||
|
||||
if (typeof ref !== "string") {
|
||||
ref = "";
|
||||
}
|
||||
|
||||
// Redirect to shim cookie layer if the host doesn't match
|
||||
try {
|
||||
var data = url.parse(ref);
|
||||
if (data.host.indexOf(Config.get("http.root-domain")) === -1) {
|
||||
var host = data.host.replace(/:\d+$/, "");
|
||||
if (Config.get("http.alt-domains").indexOf(host) === -1) {
|
||||
Logger.syslog.log("WARNING: Attempted login from non-approved "+
|
||||
"domain " + host);
|
||||
} else {
|
||||
var dest = "/shimcookie?auth=" + encodeURIComponent(auth) +
|
||||
"&rank=" + encodeURIComponent(user.global_rank) +
|
||||
"&redirect=" + encodeURIComponent(ref);
|
||||
res.redirect(data.protocol + "//" + data.host + dest);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
if (ref.match(/login|logout/)) {
|
||||
ref = "";
|
||||
}
|
||||
|
||||
if (ref) {
|
||||
res.redirect(ref);
|
||||
} else {
|
||||
session.genSession(user, expiration, function (err, auth) {
|
||||
if (err) {
|
||||
sendJade(res, "login", {
|
||||
loggedIn: true,
|
||||
loginName: user.name
|
||||
loggedIn: false,
|
||||
loginError: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.hostname.indexOf(Config.get("http.root-domain")) >= 0) {
|
||||
// Prevent non-root cookie from screwing things up
|
||||
res.clearCookie("auth");
|
||||
res.cookie("auth", auth, {
|
||||
domain: Config.get("http.root-domain-dotted"),
|
||||
expires: expiration,
|
||||
httpOnly: true,
|
||||
signed: true
|
||||
});
|
||||
} else {
|
||||
res.cookie("auth", auth, {
|
||||
expires: expiration,
|
||||
httpOnly: true,
|
||||
signed: true
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleShimCookie(req, res) {
|
||||
var auth = req.query.auth;
|
||||
var rank = req.query.rank;
|
||||
var redirect = req.query.redirect;
|
||||
if (typeof auth !== "string" || typeof redirect !== "string" ||
|
||||
typeof rank !== "string") {
|
||||
res.send(400);
|
||||
return;
|
||||
}
|
||||
|
||||
res.cookie("auth", auth, {
|
||||
expires: new Date(Date.now() + 7*24*60*60*1000),
|
||||
httpOnly: true
|
||||
});
|
||||
|
||||
res.cookie("rank", rank, {
|
||||
expires: new Date(Date.now() + 7*24*60*60*1000),
|
||||
});
|
||||
|
||||
if (redirect.match(/login|logout/)) {
|
||||
redirect = "";
|
||||
}
|
||||
|
||||
if (redirect) {
|
||||
res.redirect(redirect);
|
||||
} else {
|
||||
sendJade(res, "login", {
|
||||
loggedIn: true,
|
||||
loginName: auth.split(":")[0]
|
||||
if (dest) {
|
||||
res.redirect(dest);
|
||||
} else {
|
||||
res.user = user;
|
||||
sendJade(res, "login", {});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleShimLogout(req, res) {
|
||||
var redirect = req.query.redirect;
|
||||
if (typeof redirect !== "string") {
|
||||
res.send(400);
|
||||
return;
|
||||
}
|
||||
|
||||
res.clearCookie("auth");
|
||||
res.clearCookie("rank");
|
||||
res.clearCookie("auth", { domain: Config.get("http.root-domain-dotted") });
|
||||
res.clearCookie("rank", { domain: Config.get("http.root-domain-dotted") });
|
||||
|
||||
|
||||
if (redirect.match(/login|logout/)) {
|
||||
redirect = "";
|
||||
}
|
||||
|
||||
if (redirect) {
|
||||
res.redirect(redirect);
|
||||
} else {
|
||||
sendJade(res, "logout", {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,20 +104,14 @@ function handleLoginPage(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (req.cookies.auth) {
|
||||
var split = req.cookies.auth.split(":");
|
||||
if (split.length === 2) {
|
||||
sendJade(res, "login", {
|
||||
wasAlreadyLoggedIn: true,
|
||||
loggedIn: true,
|
||||
loginName: split[0]
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (req.user) {
|
||||
return sendJade(res, "login", {
|
||||
wasAlreadyLoggedIn: true
|
||||
});
|
||||
}
|
||||
|
||||
sendJade(res, "login", {
|
||||
loggedIn: false,
|
||||
redirect: req.header("Referrer")
|
||||
redirect: req.query.dest || req.header("referer")
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -189,34 +120,17 @@ function handleLoginPage(req, res) {
|
|||
*/
|
||||
function handleLogout(req, res) {
|
||||
res.clearCookie("auth");
|
||||
res.clearCookie("rank");
|
||||
// Try to find an appropriate redirect
|
||||
var ref = req.header("referrer");
|
||||
if (!ref) {
|
||||
ref = req.query.redirect;
|
||||
}
|
||||
|
||||
if (typeof ref !== "string") {
|
||||
ref = "";
|
||||
}
|
||||
var dest = req.query.dest || req.header("referer");
|
||||
dest = dest.match(/login|logout|account/) ? null : dest;
|
||||
|
||||
var host = req.hostname;
|
||||
if (host.indexOf(Config.get("http.root-domain")) !== -1) {
|
||||
res.clearCookie("auth", { domain: Config.get("http.root-domain-dotted") });
|
||||
res.clearCookie("rank", { domain: Config.get("http.root-domain-dotted") });
|
||||
} else {
|
||||
var dest = Config.get("http.full-address") + "/shimlogout?redirect=" +
|
||||
encodeURIComponent(ref);
|
||||
}
|
||||
|
||||
if (dest) {
|
||||
res.redirect(dest);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ref.match(/login|logout/)) {
|
||||
ref = "";
|
||||
}
|
||||
|
||||
if (ref) {
|
||||
res.redirect(ref);
|
||||
} else {
|
||||
sendJade(res, "logout", {});
|
||||
}
|
||||
|
@ -230,15 +144,9 @@ function handleRegisterPage(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (req.cookies.auth) {
|
||||
var split = req.cookies.auth.split(":");
|
||||
if (split.length === 2) {
|
||||
sendJade(res, "register", {
|
||||
loggedIn: true,
|
||||
loginName: split[0]
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (req.user) {
|
||||
sendJade(res, "register", {});
|
||||
return;
|
||||
}
|
||||
|
||||
sendJade(res, "register", {
|
||||
|
@ -260,7 +168,7 @@ function handleRegister(req, res) {
|
|||
var ip = webserver.ipForRequest(req);
|
||||
|
||||
if (typeof name !== "string" || typeof password !== "string") {
|
||||
res.send(400);
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -321,7 +229,5 @@ module.exports = {
|
|||
app.get("/logout", handleLogout);
|
||||
app.get("/register", handleRegisterPage);
|
||||
app.post("/register", handleRegister);
|
||||
app.get("/shimcookie", handleShimCookie);
|
||||
app.get("/shimlogout", handleShimLogout);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,13 +3,12 @@ var fs = require("fs");
|
|||
var path = require("path");
|
||||
var Config = require("../config");
|
||||
var templates = path.join(__dirname, "..", "..", "templates");
|
||||
|
||||
var cache = {};
|
||||
|
||||
/**
|
||||
* Merges locals with globals for jade rendering
|
||||
*/
|
||||
function merge(locals) {
|
||||
function merge(locals, res) {
|
||||
var _locals = {
|
||||
siteTitle: Config.get("html-template.title"),
|
||||
siteDescription: Config.get("html-template.description"),
|
||||
|
@ -30,6 +29,8 @@ function merge(locals) {
|
|||
* Renders and serves a jade template
|
||||
*/
|
||||
function sendJade(res, view, locals) {
|
||||
locals.loggedIn = locals.loggedIn || !!res.user;
|
||||
locals.loginName = locals.loginName || res.user ? res.user.name : false;
|
||||
if (!(view in cache) || Config.get("debug")) {
|
||||
var file = path.join(templates, view + ".jade");
|
||||
var fn = jade.compile(fs.readFileSync(file), {
|
||||
|
@ -38,7 +39,7 @@ function sendJade(res, view, locals) {
|
|||
});
|
||||
cache[view] = fn;
|
||||
}
|
||||
var html = cache[view](merge(locals));
|
||||
var html = cache[view](merge(locals, res));
|
||||
res.send(html);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ var bodyParser = require("body-parser");
|
|||
var cookieParser = require("cookie-parser");
|
||||
var static = require("serve-static");
|
||||
var morgan = require("morgan");
|
||||
var session = require("../session");
|
||||
|
||||
const LOG_FORMAT = ':real-address - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"';
|
||||
morgan.token('real-address', function (req) { return req._ip; });
|
||||
|
@ -46,6 +47,10 @@ function ipForRequest(req) {
|
|||
function redirectHttps(req, res) {
|
||||
if (!req.secure && Config.get("https.enabled")) {
|
||||
var ssldomain = Config.get("https.full-address");
|
||||
if (ssldomain.indexOf(req.hostname) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
res.redirect(ssldomain + req.path);
|
||||
return true;
|
||||
}
|
||||
|
@ -74,11 +79,6 @@ function handleChannel(req, res) {
|
|||
return;
|
||||
}
|
||||
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
}
|
||||
|
||||
var sio;
|
||||
if (net.isIPv6(ipForRequest(req))) {
|
||||
sio = Config.get("io.ipv6-default");
|
||||
|
@ -92,8 +92,6 @@ function handleChannel(req, res) {
|
|||
|
||||
sendJade(res, "channel", {
|
||||
channelName: req.params.channel,
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
sioSource: sio
|
||||
});
|
||||
}
|
||||
|
@ -102,11 +100,6 @@ function handleChannel(req, res) {
|
|||
* Handles a request for the index page
|
||||
*/
|
||||
function handleIndex(req, res) {
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
}
|
||||
|
||||
var channels = Server.getServer().packChannelList(true);
|
||||
channels.sort(function (a, b) {
|
||||
if (a.usercount === b.usercount) {
|
||||
|
@ -117,8 +110,6 @@ function handleIndex(req, res) {
|
|||
});
|
||||
|
||||
sendJade(res, "index", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
channels: channels
|
||||
});
|
||||
}
|
||||
|
@ -142,30 +133,19 @@ function handleSocketConfig(req, res) {
|
|||
if (!iourl) {
|
||||
iourl = Config.get("io.ipv4-default");
|
||||
}
|
||||
|
||||
sioconfig += "var IO_URL='" + iourl + "';";
|
||||
sioconfig += "var IO_V6=" + ipv6 + ";";
|
||||
res.send(sioconfig);
|
||||
}
|
||||
|
||||
function handleUserAgreement(req, res) {
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
}
|
||||
|
||||
sendJade(res, "tos", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
domain: Config.get("http.domain")
|
||||
});
|
||||
}
|
||||
|
||||
function handleContactPage(req, res) {
|
||||
var loginName = false;
|
||||
if (req.cookies.auth) {
|
||||
loginName = req.cookies.auth.split(":")[0];
|
||||
}
|
||||
|
||||
// Make a copy to prevent messing with the original
|
||||
var contacts = Config.get("contacts").map(function (c) {
|
||||
return {
|
||||
|
@ -189,8 +169,6 @@ function handleContactPage(req, res) {
|
|||
});
|
||||
|
||||
sendJade(res, "contact", {
|
||||
loggedIn: loginName !== false,
|
||||
loginName: loginName,
|
||||
contacts: contacts
|
||||
});
|
||||
}
|
||||
|
@ -208,7 +186,10 @@ module.exports = {
|
|||
extended: false,
|
||||
limit: '1kb' // No POST data should ever exceed this size under normal usage
|
||||
}));
|
||||
app.use(cookieParser());
|
||||
if (Config.get("http.cookie-secret") === "change-me") {
|
||||
Logger.errlog.log("YOU SHOULD CHANGE THE VALUE OF cookie-secret IN config.yaml");
|
||||
}
|
||||
app.use(cookieParser(Config.get("http.cookie-secret")));
|
||||
app.use(morgan(LOG_FORMAT, {
|
||||
stream: require("fs").createWriteStream(path.join(__dirname, "..", "..",
|
||||
"http.log"), {
|
||||
|
@ -217,6 +198,24 @@ module.exports = {
|
|||
})
|
||||
}));
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
if (req.path.match(/^\/(css|js|img|boop).*$/)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!req.signedCookies || !req.signedCookies.auth) {
|
||||
return next();
|
||||
}
|
||||
|
||||
session.verifySession(req.signedCookies.auth, function (err, account) {
|
||||
if (!err) {
|
||||
req.user = res.user = account;
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
if (Config.get("http.gzip")) {
|
||||
app.use(require("compression")({ threshold: Config.get("http.gzip-threshold") }));
|
||||
Logger.syslog.log("Enabled gzip compression");
|
||||
|
@ -267,5 +266,5 @@ module.exports = {
|
|||
|
||||
redirectHttps: redirectHttps,
|
||||
|
||||
redirectHttp: redirectHttp,
|
||||
redirectHttp: redirectHttp
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ html(lang="en")
|
|||
ul.nav.navbar-nav
|
||||
mixin navdefaultlinks("/login")
|
||||
if loggedIn
|
||||
mixin navlogoutform()
|
||||
mixin navlogoutform("/")
|
||||
section#mainpage.container
|
||||
if wasAlreadyLoggedIn
|
||||
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
||||
|
@ -27,7 +27,7 @@ html(lang="en")
|
|||
h2 Login
|
||||
form(role="form", action="/login", method="post")
|
||||
if redirect
|
||||
input(type="hidden", name="redirect", value=redirect)
|
||||
input(type="hidden", name="dest", value=redirect)
|
||||
.form-group
|
||||
label(for="username") Username
|
||||
input#username.form-control(type="text", name="name")
|
||||
|
@ -35,6 +35,11 @@ html(lang="en")
|
|||
label(for="password") Password
|
||||
input#password.form-control(type="password", name="password")
|
||||
a(href="/account/passwordreset") Forgot password?
|
||||
.form-group
|
||||
.checkbox
|
||||
label
|
||||
input(type="checkbox", name="remember")
|
||||
| Remember me
|
||||
button.btn.btn-success.btn-block(type="submit") Login
|
||||
else
|
||||
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
||||
|
|
|
@ -11,7 +11,7 @@ html(lang="en")
|
|||
#nav-collapsible.collapse.navbar-collapse
|
||||
ul.nav.navbar-nav
|
||||
mixin navdefaultlinks("/logout")
|
||||
mixin navloginform()
|
||||
mixin navloginform("/")
|
||||
section#mainpage.container
|
||||
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
||||
.alert.alert-info.center.messagebox
|
||||
|
|
|
@ -27,13 +27,13 @@ mixin navdefaultlinks(page)
|
|||
b.caret
|
||||
ul.dropdown-menu
|
||||
if loggedIn
|
||||
li: a(href="/logout?redirect=#{page}") Logout
|
||||
li: a(href="/logout?dest=#{page}") Logout
|
||||
li.divider
|
||||
li: a(href="/account/channels") Channels
|
||||
li: a(href="/account/profile") Profile
|
||||
li: a(href="/account/edit") Change Password/Email
|
||||
else
|
||||
li: a(href="/login") Login
|
||||
li: a(href="/login?dest=#{page}") Login
|
||||
li: a(href="/register") Register
|
||||
|
||||
mixin navloginlogout(redirect)
|
||||
|
@ -43,25 +43,30 @@ mixin navloginlogout(redirect)
|
|||
mixin navloginform(redirect)
|
||||
|
||||
mixin navloginform(redirect)
|
||||
.visible-md.visible-lg
|
||||
if loginDomain == null
|
||||
- loginDomain = ""
|
||||
if loginDomain == null
|
||||
- loginDomain = ""
|
||||
.visible-lg
|
||||
form#loginform.navbar-form.navbar-right(action="#{loginDomain}/login", method="post")
|
||||
input(type="hidden", name="redirect", value=redirect)
|
||||
input(type="hidden", name="dest", value=redirect)
|
||||
.form-group
|
||||
input#username.form-control(type="text", name="name", placeholder="Username")
|
||||
.form-group
|
||||
input#password.form-control(type="password", name="password", placeholder="Password")
|
||||
.form-group
|
||||
.checkbox
|
||||
label
|
||||
input(type="checkbox", name="remember")
|
||||
span.navbar-text-nofloat Remember me
|
||||
button#login.btn.btn-default(type="submit") Login
|
||||
.visible-md
|
||||
p#loginform.navbar-text.pull-right
|
||||
a#login.navbar-link(href="#{loginDomain}/login?dest=#{redirect}") Log in
|
||||
span ·
|
||||
a#register.navbar-link(href="/register") Register
|
||||
|
||||
|
||||
mixin navlogoutform(redirect)
|
||||
if loginDomain == null
|
||||
- loginDomain = ""
|
||||
if redirect
|
||||
- url = "logout?redirect=" + redirect
|
||||
else
|
||||
- url = "logout"
|
||||
p#logoutform.navbar-text.pull-right
|
||||
span#welcome Welcome, #{loginName}
|
||||
span ·
|
||||
a#logout.navbar-link(href="#{loginDomain}/#{url}") Logout
|
||||
a#logout.navbar-link(href="/logout?dest=#{redirect}") Logout
|
||||
|
|
8
www/css/themes/bootstrap-theme.min.css
vendored
8
www/css/themes/bootstrap-theme.min.css
vendored
|
@ -69,3 +69,11 @@ footer {
|
|||
.queue_entry.queue_active {
|
||||
background-color: #d9edf7;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-text-nofloat {
|
||||
color: #9d9d9d;
|
||||
}
|
||||
|
||||
.queue_entry.queue_active {
|
||||
background-color: #d9edf7;
|
||||
}
|
||||
|
|
|
@ -78,6 +78,10 @@ input.form-control[type="email"], textarea.form-control {
|
|||
background-color: #060606;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-text-nofloat {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.queue_entry.queue_active {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
|
|
@ -63,3 +63,11 @@ footer {
|
|||
.queue_entry.queue_active {
|
||||
background-color: #d9edf7;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-text-nofloat {
|
||||
color: #9d9d9d;
|
||||
}
|
||||
|
||||
.queue_entry.queue_active {
|
||||
background-color: #d9edf7;
|
||||
}
|
||||
|
|
|
@ -169,3 +169,7 @@ input.form-control[type="email"], textarea.form-control {
|
|||
#newpollbtn {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-text-nofloat {
|
||||
color: #c8c8c8;
|
||||
}
|
||||
|
|
|
@ -93,3 +93,7 @@ input.form-control[type="email"], textarea.form-control {
|
|||
border-color: #aaaaaa;
|
||||
background-color: #272b30;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-text-nofloat {
|
||||
color: #ccc;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue