Added adminpanel to this repo

This commit is contained in:
Kasper Rynning-Tønnesen
2018-02-05 19:46:03 +01:00
parent 38bceb1a53
commit 01a42c7d68
40 changed files with 1561 additions and 35 deletions

221
package-lock.json generated
View File

@@ -98,6 +98,14 @@
"version": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
},
"assert": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
"integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
"requires": {
"util": "0.10.3"
}
},
"assert-plus": {
"version": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
@@ -145,6 +153,11 @@
"version": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
"integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY="
},
"bcrypt-nodejs": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz",
"integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs="
},
"bcrypt-pbkdf": {
"version": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
@@ -173,6 +186,11 @@
"version": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz",
"integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE="
},
"bluebird": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz",
"integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw="
},
"bmp-js": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.0.3.tgz",
@@ -362,10 +380,24 @@
"version": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"cookies": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.1.tgz",
"integrity": "sha1-fIphX1SBxhq58WyDNzG8uPZjuZs=",
"requires": {
"depd": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
"keygrip": "1.0.2"
}
},
"core-util-is": {
"version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"crc": {
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz",
"integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms="
},
"cryptiles": {
"version": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
@@ -662,6 +694,22 @@
"resolved": "https://registry.npmjs.org/express-recaptcha/-/express-recaptcha-3.0.1.tgz",
"integrity": "sha1-b/a25u1D5u94ZD9W46qP/igDlMg="
},
"express-session": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.15.6.tgz",
"integrity": "sha512-r0nrHTCYtAMrFwZ0kBzZEXa1vtPVrw0dKvGSrKP4dahwBQ1BJpF2/y1Pp4sCD/0kvxV4zZeclyvfmw0B4RMJQA==",
"requires": {
"cookie": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"cookie-signature": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"crc": "3.4.4",
"debug": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"depd": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
"on-headers": "1.0.1",
"parseurl": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"uid-safe": "2.1.5",
"utils-merge": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz"
}
},
"express-subdomain": {
"version": "https://registry.npmjs.org/express-subdomain/-/express-subdomain-1.0.5.tgz",
"integrity": "sha1-mQ75eUC39MKCPZWTZIt5voWKY4s="
@@ -1412,6 +1460,16 @@
"verror": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz"
}
},
"kareem": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.0.3.tgz",
"integrity": "sha512-WloXk3nyByx9FEB5WY7WFEXIZB/QA+zy7c2kJMjnZCebjepEyQcJzazgLiKcTS/ltZeEoeEQ1A1pau1fEDlnIA=="
},
"keygrip": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.2.tgz",
"integrity": "sha1-rTKXxVcGneqLz+ek+kkbdcXd65E="
},
"kind-of": {
"version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
@@ -1499,6 +1557,11 @@
"lodash._root": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz"
}
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.isarguments": {
"version": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
@@ -1740,6 +1803,89 @@
}
}
},
"mongoose": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.0.3.tgz",
"integrity": "sha512-y4NlLzZaQe5vJHjcEjHLKK6utjs7sVEPN971+d1vVJJGrmA+zeeFA1MEmC1J0ujD34eOSghnExXJPwCrxHHZCw==",
"requires": {
"async": "2.1.4",
"bson": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz",
"kareem": "2.0.3",
"lodash.get": "4.4.2",
"mongodb": "3.0.2",
"mongoose-legacy-pluralize": "1.0.2",
"mpath": "0.3.0",
"mquery": "3.0.0",
"ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"regexp-clone": "0.0.1",
"sliced": "1.0.1"
},
"dependencies": {
"async": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz",
"integrity": "sha1-LSFgx3iAMuTdbL4lAvH5osj2zeQ=",
"requires": {
"lodash": "4.17.5"
}
},
"lodash": {
"version": "4.17.5",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="
},
"mongodb": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.0.2.tgz",
"integrity": "sha512-E50FmpSQchZAimn2uPIegoNoH9UQYR1yiGHtQPmmg8/Ekc97w6owHoqaBoz+assnd9V5LxMzmQ/VEWMsQMgZhQ==",
"requires": {
"mongodb-core": "3.0.2"
}
},
"mongodb-core": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.0.2.tgz",
"integrity": "sha512-p1B0qwFQUw6C1OlFJnrOJp8KaX7MuGoogRbTaupRt0y+pPRkMllHWtE9V6i1CDtTvI3/3sy2sQwqWez7zuXEAA==",
"requires": {
"bson": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz",
"require_optional": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz"
}
}
}
},
"mongoose-legacy-pluralize": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
"integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ=="
},
"mpath": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.3.0.tgz",
"integrity": "sha1-elj3iem1/TyUUgY0FXlg8mvV70Q="
},
"mpromise": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mpromise/-/mpromise-0.5.5.tgz",
"integrity": "sha1-9bJCWddjrMIlewoMjG2Gb9UXMuY="
},
"mquery": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.0.0.tgz",
"integrity": "sha512-WL1Lk8v4l8VFSSwN3yCzY9TXw+fKVYKn6f+w86TRzOLSE8k1yTgGaLBPUByJQi8VcLbOdnUneFV/y3Kv874pnQ==",
"requires": {
"bluebird": "3.5.0",
"debug": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"regexp-clone": "0.0.1",
"sliced": "0.0.5"
},
"dependencies": {
"sliced": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/sliced/-/sliced-0.0.5.tgz",
"integrity": "sha1-XtwETKTrb3gW1Qui/GPiXY/kcH8="
}
}
},
"ms": {
"version": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
@@ -1855,6 +2001,11 @@
"ee-first": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz"
}
},
"on-headers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
"integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
},
"once": {
"version": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
"integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=",
@@ -1966,6 +2117,28 @@
"version": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
},
"passport": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz",
"integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=",
"requires": {
"passport-strategy": "1.0.0",
"pause": "0.0.1"
}
},
"passport-local": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
"integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
"requires": {
"passport-strategy": "1.0.0"
}
},
"passport-strategy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
"integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
},
"path-is-absolute": {
"version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
@@ -1989,6 +2162,11 @@
"version": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"pause": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
},
"performance-now": {
"version": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
@@ -2046,6 +2224,11 @@
"version": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg="
},
"random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
"integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
},
"randomatic": {
"version": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
"integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=",
@@ -2142,6 +2325,11 @@
"is-equal-shallow": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz"
}
},
"regexp-clone": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz",
"integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk="
},
"remove-trailing-separator": {
"version": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
@@ -2280,6 +2468,11 @@
"version": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
},
"sliced": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
"integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
},
"sntp": {
"version": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz",
"integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=",
@@ -2547,6 +2740,14 @@
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
"optional": true
},
"uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
"requires": {
"random-bytes": "1.0.0"
}
},
"uid2": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz",
@@ -2587,6 +2788,21 @@
"version": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz",
"integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA="
},
"util": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
"requires": {
"inherits": "2.0.1"
},
"dependencies": {
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
}
}
},
"util-deprecate": {
"version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
@@ -2624,6 +2840,11 @@
"extsprintf": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz"
}
},
"vhost": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/vhost/-/vhost-3.0.2.tgz",
"integrity": "sha1-L7HezUxGaqiLD5NBrzPcGv8keNU="
},
"vinyl": {
"version": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
"integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=",

View File

@@ -27,14 +27,18 @@
},
"homepage": "https://github.com/zoff-music/zoff#readme",
"dependencies": {
"assert": "^1.4.1",
"bad-words": "^1.5.1",
"bcrypt-nodejs": "0.0.3",
"body-parser": "^1.17.1",
"color-thief-jimp": "^2.0.2",
"cookie-parser": "^1.4.3",
"cookies": "^0.7.1",
"emoji-strip": "^0.0.3",
"express": "^4.15.2",
"express-handlebars": "^3.0.0",
"express-recaptcha": "^3.0.1",
"express-session": "^1.15.6",
"express-subdomain": "^1.0.5",
"gulp": "^3.9.1",
"gulp-concat": "^2.6.1",
@@ -44,13 +48,18 @@
"mobile-detect": "^1.3.7",
"mongodb": "^2.0.27",
"mongojs": "^2.4.0",
"mongoose": "^5.0.3",
"mpromise": "^0.5.5",
"node-cryptojs-aes": "^0.4.0",
"nodemailer": "^4.0.1",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"redis": "^2.8.0",
"request": "^2.72.0",
"socket.io": "^2.0.3",
"socket.io-redis": "^5.2.0",
"sticky-session": "^1.1.2",
"uniqid": "^4.1.1"
"uniqid": "^4.1.1",
"vhost": "^3.0.2"
}
}

215
server/admin.js Normal file
View File

@@ -0,0 +1,215 @@
var express = require('express');
var app = express();
const path = require('path');
const publicPath = path.join(__dirname, 'public');
var exphbs = require('express-handlebars');
var hbs = exphbs.create({
defaultLayout: publicPath + '/layouts/admin/main',
layoutsDir: publicPath + '/layouts',
partialsDir: publicPath + '/partials'
});
var passport = require('passport');
var mpromise = require('mpromise');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var mongo_db_cred = require(path.join(__dirname, './config/mongo_config.js'));
var mongojs = require('mongojs');
var db = mongojs(mongo_db_cred.config);
var token_db = mongojs("tokens");
var bodyParser = require('body-parser');
var Cookies = require('cookies');
var session = require('express-session');
var api = require('./routing/admin/api.js');
var User = require('./models/user.js');
var url = 'mongodb://localhost/users';
mongoose.connect(url);
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.enable('view cache');
app.set('views', publicPath);
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(session({
secret: mongo_db_cred.secret,
resave: true,
saveUninitialized: true
})); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
//app.use('/assets', express.static(publicPath + '/assets'));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with username
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose username is the same as the forms username
// we are checking to see if the user trying to login already exists
var token = req.param("token");
token_db.collection("tokens").find({token: token}, function(err, docs){
if(docs.length == 1){
token_db.collection("tokens").remove({token: token}, function(err, docs){
User.findOne({ 'username' : username }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that username
if (user) {
return done(null, false);
} else {
// if there is no user with that username
// create the user
var newUser = new User();
// set the user's local credentials
newUser.username = username;
newUser.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
} else {
return done(null, false);
}
});
});
}));
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
}, function(req, username, password, done) { // callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'username' : username }, function(err, user) {
// if there are any errors, return the error before anything else
if (err)
return done(err);
// if no user is found, return the message
if (!user)
return done(null, false); // req.flash is the way to set flashdata using connect-flash
// if the user is found but the password is wrong
if (!user.validPassword(password))
return done(null, false); // create the loginMessage and save it to session as flashdata
// all is well, return successful user
return done(null, user);
});
}));
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
app.use('/login', isLoggedInTryingToLogIn, function(req, res) {
var data = {
where_get: "not_authenticated"
};
res.render('layouts/admin/not_authenticated', data);
});
app.use('/signup', isLoggedInTryingToLogIn, function(req, res) {
var data = {
where_get: "not_authenticated"
};
res.render('layouts/admin/not_authenticated', data);
});
app.use('/', api);
app.use('/logout', function(req, res) {
req.logout();
res.redirect('/login');
});
app.use('/assets', express.static(publicPath + '/assets'));
app.use('/', isLoggedIn, function(req, res) {
var data = {
where_get: "authenticated",
year: new Date().getYear()+1900,
};
res.render('layouts/admin/authenticated', data);
});
function makeid()
{
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 20; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
function isLoggedInTryingToLogIn(req, res, next){
if(!req.isAuthenticated()){
return next();
}
res.redirect("/");
}
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/login');
}
//app.listen(default_port);
module.exports = app;

View File

@@ -4,19 +4,23 @@ var cluster = require('cluster'),
publicPath = path.join(__dirname, 'public'),
http = require('http'),
port = 8080,
num_processes = require('os').cpus().length;
num_processes = require('os').cpus().length,
express = require('express'),
vhost = require('vhost'),
app = express();
try {
a
var redis = require("redis");
var client = redis.createClient({host: "localhost", port: 6379});
client.quit();
startClustered();
startClustered(true);
} catch(e) {
console.log("Couldn't connect to redis-server, assuming non-clustered run");
startSingle(false);
startClustered(false);
}
function startClustered() {
function startClustered(redis_enabled) {
//Found https://stackoverflow.com/questions/40885592/use-node-js-cluster-with-socket-io-chat-application
if (cluster.isMaster) {
var workers = [];
@@ -47,12 +51,13 @@ function startClustered() {
worker.send('sticky-session:connection', connection);
}).listen(port);
} else {
startSingle(true);
startSingle(true, redis_enabled);
}
}
function startSingle(clustered) {
var app = require('./index.js');
function startSingle(clustered, redis_enabled) {
var client = require('./client.js');
var admin = require('./admin.js');
try {
var cert_config = require(path.join(path.join(__dirname, 'config'), 'cert_config.js'));
var fs = require('fs');
@@ -66,24 +71,47 @@ function startSingle(clustered) {
};
var https = require('https');
server = https.Server(credentials, app);
server = https.Server(credentials, client);
} catch(err){
console.log("Starting without https (probably on localhost)");
var http = require('http');
server = http.Server(app);
server = http.Server(client);
//add = ",http://localhost:80*,http://localhost:8080*,localhost:8080*, localhost:8082*,http://zoff.dev:80*,http://zoff.dev:8080*,zoff.dev:8080*, zoff.dev:8082*";
}
admin_server = http.Server(admin);
if(clustered) {
server.listen(onListen);
app
.use( vhost('*', function(req, res) {
server.emit("request", req, res);
}) )
.use( vhost('remote.*', function(req, res) {
server.emit("request", req, res);
}) )
.use( vhost('admin.*', function(req, res) {
admin_server.emit("request", req, res);
}) )
.listen(onListen);
//server.listen(onListen);
} else {
server.listen(port, onListen);
app
.use( vhost('*', function(req, res) {
server.emit("request", req, res);
}) )
.use( vhost('remote.*', function(req, res) {
server.emit("request", req, res);
}) )
.use( vhost('admin.*', function(req, res) {
admin_server.emit("request", req, res);
}) )
.listen(port, onListen);
//server.listen(port, onListen);
}
var socketIO = app.socketIO;
var socketIO = client.socketIO;
if(clustered) {
if(redis_enabled) {
var redis = require('socket.io-redis');
try {
socketIO.adapter(redis({ host: 'localhost', port: 6379 }));
@@ -91,17 +119,18 @@ function startSingle(clustered) {
console.log("No redis-server to connect to..");
}
socketIO.listen(server);
process.on('message', function(message, connection) {
if (message !== 'sticky-session:connection') {
return;
}
server.emit('connection', connection);
connection.resume();
});
} else {
socketIO.listen(server);
}
process.on('message', function(message, connection) {
if (message !== 'sticky-session:connection') {
return;
}
server.emit('connection', connection);
connection.resume();
});
}
function onListen() {

View File

@@ -9,8 +9,8 @@ var app = express();
var exphbs = require('express-handlebars');
var hbs = exphbs.create({
defaultLayout: publicPath + '/layouts/main',
layoutsDir: publicPath + '/layouts',
defaultLayout: publicPath + '/layouts/client/main',
layoutsDir: publicPath + '/layouts/client',
partialsDir: publicPath + '/partials'
});
uniqid = require('uniqid');
@@ -60,9 +60,9 @@ emojiStrip = require('emoji-strip');
Filter = require('bad-words');
filter = new Filter({ placeHolder: 'x'});
var router = require('./routing/router.js');
var api = require('./routing/api.js');
var ico_router = require('./routing/icons_routing.js');
var router = require('./routing/client/router.js');
var api = require('./routing/client/api.js');
var ico_router = require('./routing/client/icons_routing.js');
app.get('/robots.txt', function (req, res) {
res.type('text/plain');

24
server/models/user.js Normal file
View File

@@ -0,0 +1,24 @@
// app/models/user.js
// load the things we need
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
// define the schema for our user model
var userSchema = mongoose.Schema({
username : String,
password : String,
});
// methods ======================
// generating a hash
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// checking if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.password);
};
// create the model for users and expose it to our app
module.exports = mongoose.model('User', userSchema);

View File

@@ -0,0 +1,527 @@
var connection_options = {
'sync disconnect on unload':true,
'secure': true,
'force new connection': true
};
var socket = io.connect('https://zoff.me:8080', connection_options);
$(document).ready(function(){
$('ul.tabs').tabs();
});
$(document).on("click", "#refresh_all", function(e){
e.preventDefault();
$("#descriptions_cont").empty();
$("#thumbnails_cont").empty();
if(!$(".channel_things").hasClass("hide")) {
$(".channel_things").addClass("hide")
}
$(".preloader-wrapper").removeClass("hide");
$.ajax({
type: "GET",
url: "/api/lists",
success: function(response){
var output_pinned = '<option value="" disabled>Channels</option>';
var output_delete = '<option value="" disabled>Channels</option>';
for(var x = 0; x < response.length; x++){
if(response[x].count > 5){
output_pinned += "<option class='" + response[x]._id + "' value='" + response[x]._id + "'>" + response[x]._id + "</option>";
}
output_delete += "<option class='" + response[x]._id + "' value='" + response[x]._id + "'>" + response[x]._id + "</option>";
}
$("#frontpage_pinned").html(output_pinned);
$("#remove_thumbnail").html(output_delete);
$("#remove_description").html(output_delete);
$("#delete_list_name").html(output_delete);
$("#delete_userpass_name").html(output_delete);
$("#delete_channel_name").html(output_delete);
$("select").material_select();
$(".channel_things").removeClass("hide");
if(!$(".preloader-wrapper").hasClass("hide")) {
$(".preloader-wrapper").addClass("hide");
}
}
});
$.ajax({
type: "GET",
url: "/api/thumbnails",
success: function(response){
if(response.length > 0){
$(".thumbnails-badge").removeClass("hide");
$(".thumbnails-badge").text(response.length);
}
add_to_tab("thumbnails", response);
}
});
$.ajax({
type: "GET",
url: "/api/descriptions",
success: function(response){
if(response.length > 0){
$(".descriptions-badge").removeClass("hide");
$(".descriptions-badge").text(response.length);
}
add_to_tab("descriptions", response);
}
});
$("#listeners").empty();
socket.emit("get_spread");
});
socket.on("spread_listeners", function(obj){
$("#listeners").append("<p>Private listeners: " + obj.offline + "</p>");
$("#listeners").append("<p>Total listeners: " + obj.total + "</p>");
$("#listeners").append("<hr>");
for(var x in obj.online_users){
if(obj.online_users[x]._id != "total_users" && obj.online_users[x].hasOwnProperty("users") && obj.online_users[x].users.length > 0){
$("#listeners").append("<p>" + obj.online_users[x]._id + ": " + obj.online_users[x].users.length + "</p>");
}
}
});
if(!$(".channel_things").hasClass("hide")) {
$(".channel_things").addClass("hide")
}
$(".preloader-wrapper").removeClass("hide");
$.ajax({
type: "GET",
url: "/api/lists",
success: function(response){
var output_pinned = '<option value="" disabled selected>Channels</option>';
var output_delete = '<option value="" disabled selected>Channels</option>';
for(var x = 0; x < response.length; x++){
if(response[x].count > 5){
output_pinned += "<option class='" + response[x]._id + "' value='" + response[x]._id + "'>" + response[x]._id + "</option>";
}
output_delete += "<option class='" + response[x]._id + "' value='" + response[x]._id + "'>" + response[x]._id + "</option>";
}
$("#frontpage_pinned").html(output_pinned);
$("#remove_thumbnail").html(output_delete);
$("#remove_description").html(output_delete);
$("#delete_list_name").html(output_delete);
$("#delete_userpass_name").html(output_delete);
$("#delete_channel_name").html(output_delete);
$("select").material_select();
if(!$(".preloader-wrapper").hasClass("hide")) {
$(".preloader-wrapper").addClass("hide")
}
$(".channel_things").removeClass("hide");
}
});
$.ajax({
type: "GET",
url: "/api/names",
success: function(response) {
for(var i = 0; i < response.length; i++) {
var icon = "";
if(response[i].icon && response[i].icon != "") {
icon = "<img class='chat-icon' src='" + response[i].icon + "' alt='" + response[i]._id + "'>";
}
$(".names-container").append("<div class='col s12'><div class='name-chat col s3'>" + icon + response[i]._id + "</div><input type='text' class='" + response[i]._id + "_input col s7'><a class='btn green waves-effect col s2 m1 approve_name' href='#' data-name='" + response[i]._id + "'><i class='material-icons'>check</i></a></div>");
}
},
});
$.ajax({
type: "GET",
url: "/api/thumbnails",
success: function(response){
if(response.length > 0){
$(".thumbnails-badge").removeClass("hide");
$(".thumbnails-badge").text(response.length);
}
add_to_tab("thumbnails", response);
}
});
$(document).on("click", ".approve_name", function(e) {
var that = this;
var name = $(that).attr("data-name");
var value = $("." + name + "_input").val();
$.ajax({
type: "POST",
url: "/api/names",
data: {
icon: value,
name: name,
},
success: function(resp) {
if(resp == true) {
Materialize.toast("Approved image!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
});
});
$(document).on("click", ".thumbnail_link", function(e) {
e.preventDefault();
window.open("https:" + this.value,'_blank');
});
$.ajax({
type: "GET",
url: "/api/descriptions",
success: function(response){
if(response.length > 0){
$(".descriptions-badge").removeClass("hide");
$(".descriptions-badge").text(response.length);
}
add_to_tab("descriptions", response);
}
});
function add_to_tab(dest, resp){
for(var x = 0; x < resp.length; x++){
if(dest == "thumbnails"){
$("#" + dest + "_cont").append("<div><div class='col s4 m3'>" + resp[x].channel + "</div><input type='text' readonly class='col s4 m6 thumbnail_link' value='" + resp[x].thumbnail + "'><a class='btn green waves-effect col s2 m1 approve_" + dest + "' href='#' data-channel='" + resp[x].channel + "'><i class='material-icons'>check</i></a><a class='btn red waves-effect col s2 m1 deny_" + dest + "' href='#' data-channel='" + resp[x].channel + "'>X</a></div>");
} else {
$("#" + dest + "_cont").append("<div><div class='col s4 m3'>" + resp[x].channel + "</div><input type='text' readonly class='col s4 m6' value='" + resp[x].description + "'><a class='btn green waves-effect col s2 m1 approve_" + dest + "' href='#' data-channel='" + resp[x].channel + "'><i class='material-icons'>check</i></a><a class='btn red waves-effect col s2 m1 deny_" + dest + "' href='#' data-channel='" + resp[x].channel + "'>X</a></div>");
}
}
}
$(document).on("click", "#get_token", function(e){
e.preventDefault();
$.ajax({
type: "GET",
url: "/api/token",
success: function(response){
if(response != false){
$("#new_token").val(response.token);
$("#get_token").toggleClass("hide");
$("#remove_token").toggleClass("hide");
}
}
})
});
$(document).on("click", ".approve_thumbnails", function(e){
e.preventDefault();
var channel = $(this).attr("data-channel");
if(!channel) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
var that = this;
$.ajax({
type: "POST",
url: "/api/approve_thumbnail",
data: {
channel: channel
},
success: function(response){
if(response){
$(that).parent().remove();
var length = parseInt($(".thumbnails-badge").text());
length = length - 1;
$(".thumbnails-badge").text(length);
if(length <= 0 && !$(".thumbnails-badge").hasClass("hide")){
$(".thumbnails-badge").addClass("hide");
}
Materialize.toast("Approved Thumbnail!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
});
});
$(document).on("click", ".deny_thumbnails", function(e){
e.preventDefault();
var channel = $(this).attr("data-channel");
if(!channel) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
var that = this;
$.ajax({
type: "POST",
url: "/api/deny_thumbnail",
data: {
channel: channel
},
success: function(response){
if(response){
$(that).parent().remove();
var length = parseInt($(".thumbnails-badge").text());
length = length - 1;
$(".thumbnails-badge").text(length);
if(length <= 0 && !$(".thumbnails-badge").hasClass("hide")){
$(".thumbnails-badge").addClass("hide");
}
Materialize.toast("Denied thumbnail!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
});
});
$(document).on("click", ".approve_descriptions", function(e){
e.preventDefault();
var channel = $(this).attr("data-channel");
if(!channel) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
var that = this;
$.ajax({
type: "POST",
url: "/api/approve_description",
data: {
channel: channel
},
success: function(response){
if(response){
$(that).parent().remove();
var length = parseInt($(".descriptions-badge").text());
length = length - 1;
$(".descriptions-badge").text(length);
if(length <= 0 && !$(".descriptions-badge").hasClass("hide")){
$(".descriptions-badge").addClass("hide");
}
Materialize.toast("Approved description!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
});
});
$(document).on("click", ".deny_descriptions", function(e){
e.preventDefault();
var channel = $(this).attr("data-channel");
if(!channel) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
var that = this;
$.ajax({
type: "POST",
url: "/api/deny_description",
data: {
channel: channel
},
success: function(response){
if(response){
$(that).parent().remove();
var length = parseInt($(".descriptions-badge").text());
length = length - 1;
$(".descriptions-badge").text(length);
if(length <= 0 && !$(".descriptions-badge").hasClass("hide")){
$(".descriptions-badge").addClass("hide");
}
Materialize.toast("Denied description!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
});
});
$(document).on("click", "#remove_description_button", function(e){
e.preventDefault();
var channel = $("#remove_description").val();
if(!channel) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
var that = this;
$.ajax({
type: "POST",
url: "/api/remove_description",
data: {
channel: channel
},
success: function(response){
if(response){
Materialize.toast("Removed description!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
});
});
$(document).on("click", "#remove_thumbnail_button", function(e){
e.preventDefault();
var channel = $("#remove_thumbnail").val();
if(!channel) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
var that = this;
$.ajax({
type: "POST",
url: "/api/remove_thumbnail",
data: {
channel: channel
},
success: function(response){
if(response){
Materialize.toast("Removed thumbnail!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
});
});
$(document).on("submit", "#delete_channel", function(e){
e.preventDefault();
var to_delete = $("#delete_channel_name").val();
if(!to_delete) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
var r = confirm("Delete list " + to_delete + "?");
if (r == true) {
$.ajax({
type: "POST",
url: "/api/delete",
data: {
_id: to_delete
},
success: function(response){
if(response == true){
$.ajax({
type: "GET",
url: "/api/lists",
success: function(response){
var output_pinned = "";
var output_delete = "";
for(var x = 0; x < response.length; x++){
if(response[x].count > 5){
output_pinned += "<option class='" + response[x]._id + "' value='" + response[x]._id + "'>" + response[x]._id + "</option>";
}
output_delete += "<option class='" + response[x]._id + "' value='" + response[x]._id + "'>" + response[x]._id + "</option>";
}
$("#frontpage_pinned").html(output_pinned);
$("#delete_list_name").html(output_delete);
$("#delete_userpass_name").html(output_delete);
$("#delete_channel_name").html(output_delete);
$("select").material_select();
}
});
Materialize.toast("Deleted channel!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
})
}
});
$(document).on("click", "#delete_channel_button", function(e){
e.preventDefault();
$("#delete_channel").submit();
});
$(document).on("click", "#remove_token", function(e){
e.preventDefault();
$.ajax({
type: "GET",
url: "/api/remove_token",
success: function(response){
if(response != false){
$("#new_token").val("");
$("#get_token").toggleClass("hide");
$("#remove_token").toggleClass("hide");
}
}
})
});
$(document).on("submit", "#change_pinned", function(e){
e.preventDefault();
var to_pin = $("#frontpage_pinned").val();
if(!to_pin) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
$.ajax({
type: "POST",
url: "/api/pinned",
data: {
_id: to_pin
},
success: function(response){
if(response == true){
Materialize.toast("Pinned channel!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
})
});
$(document).on("click", "#change_pinned_button", function(){
$("#change_pinned").submit();
});
$(document).on("click", "#delete_admin_button", function(){
$("#delete_list").submit();
});
$(document).on("click", "#delete_userpass_button", function(){
$("#delete_userpass").submit();
});
$(document).on("submit", "#delete_list", function(e){
e.preventDefault();
var to_remove_password = $("#delete_list_name").val();
if(!to_remove_password) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
$.ajax({
type: "POST",
url: "/api/admin",
data: {
_id: to_remove_password
},
success: function(response){
if(response == true){
Materialize.toast("Removed admin password!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
})
});
$(document).on("submit", "#delete_userpass", function(e){
e.preventDefault();
var to_remove_password = $("#delete_userpass_name").val();
if(!to_remove_password) {
Materialize.toast("Something went wrong...", 2000, "red lighten");
return;
}
$.ajax({
type: "POST",
url: "/api/userpass",
data: {
_id: to_remove_password
},
success: function(response){
if(response == true){
Materialize.toast("Removed userpass password!", 2000, "green lighten");
} else {
Materialize.toast("Something went wrong...", 2000, "red lighten");
}
}
})
});
socket.emit("get_spread");

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,18 @@
$(document).on("click", "#login_button", function(e){
e.preventDefault();
$("#login_form").submit();
})
$(document).ready(function(){
if(window.location.pathname == "/signup/" || window.location.pathname == "/signup"){
$("#login_form").prepend("<input type='text' name='token' placeholder='Token' required autocomplete='off' />");
$("#login_form").attr("action", "/signup");
}
});
$(document).on("submit", "#login_form", function(e){
if(this.password.value == "" || this.username.value == ""){
e.preventDefault();
}
})

View File

@@ -0,0 +1,172 @@
<header>
<nav id="fp-nav">
<div class="nav-wrapper">
<a href="#" class="brand-logo noselect">
<img class="zicon" src="/assets/images/squareicon_small.png" alt="Zoff" title="Zoff" />
</a>
<ul class="right">
<li><a class="header-buttons waves-effect waves-cyan" id="logout" title="Logout" href="/logout">Logout</a></li>
</ul>
</div>
</nav>
</header>
<main class="container center-align admin_panel">
<div class="row">
<h2 class="col s11">Admin</h2>
<a href="#" id="refresh_all" class="col s1"><h2><i class="material-icons">refresh</i></h2></a>
</div>
<div class="row">
<div class="col s12 m10">
<ul class="tabs tabs_admin">
<li class="tab col s3"><a class="active" href="#general">General</a></li>
<li class="tab col s3"><a href="#thumbnails">Thumbnails<span class="new thumbnails-badge badge admin-panel hide"></span></a></li>
<li class="tab col s3"><a href="#descriptions">Descriptions<span class="new descriptions-badge badge admin-panel hide"></span></a></li>
<li class="tab col s3"><a href="#names">Names</a></li>
</ul>
<div id="general" class="col s12">
<div class="preloader-wrapper big active">
<div class="spinner-layer spinner-zoff-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div><div class="gap-patch">
<div class="circle"></div>
</div><div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
<div class="channel_things hide">
<form id="change_pinned">
<div class="row">
<div class="input-field col s8 m10">
<select id="frontpage_pinned">
<option value="" disabled>Channels</option>
</select>
<label>Change Pinned</label>
</div>
<div class="col s2">
<a href="#" id="change_pinned_button" class="btn green waves-effect">UPDATE</a>
</div>
</div>
</form>
<form id="delete_list">
<div class="row">
<div class="input-field col s8 m10">
<select id="delete_list_name">
<option value="" disabled>Channels</option>
</select>
<label>Delete Admin</label>
</div>
<div class="col s2">
<a href="#" id="delete_admin_button" class="btn orange waves-effect">UPDATE</a>
</div>
</div>
</form>
<form id="delete_userpass">
<div class="row">
<div class="input-field col s8 m10">
<select id="delete_userpass_name">
<option value="" disabled>Channels</option>
</select>
<label>Delete Userpass</label>
</div>
<div class="col s2">
<a href="#" id="delete_userpass_button" class="btn blue waves-effect">UPDATE</a>
</div>
</div>
</form>
<form id="delete_channel">
<div class="row">
<div class="input-field col s8 m10">
<select id="delete_channel_name">
<option value="" disabled>Channels</option>
</select>
<label>Delete Channel</label>
</div>
<div class="col s2">
<a href="#" id="delete_channel_button" class="btn red waves-effect">DELETE</a>
</div>
</div>
</form>
<div class="row">
<div class="input-field col s8 m10">
<input type="text" readonly id="new_token" />
</div>
<div class="col s2">
<a href="#" id="get_token" class="btn waves-effect">TOKEN</a>
<a href="#" id="remove_token" class="btn red waves-effect hide">REMOVE</a>
</div>
</div>
</div>
</div>
<div id="thumbnails" class="col s12">
<div class="row">
<div class="input-field col s8 m10">
<select id="remove_thumbnail">
<option value="" disabled>Channels</option>
</select>
<label>Remove Thumbnail</label>
</div>
<div class="col s2">
<a href="#" id="remove_thumbnail_button" class="btn red waves-effect">REMOVE</a>
</div>
<div id="thumbnails_cont" class="col s12">
</div>
</div>
</div>
<div id="descriptions" class="col s12">
<div class="row">
<div class="input-field col s8 m10">
<select id="remove_description">
<option value="" disabled>Channels</option>
</select>
<label>Remove Description</label>
</div>
<div class="col s2">
<a href="#" id="remove_description_button" class="btn red waves-effect">REMOVE</a>
</div>
</div>
<div id="descriptions_cont" class="col s12">
</div>
</div>
<div id="names" class="col s12">
<div class="row names-container">
</div>
</div>
</div>
<div class="col s10 m2 left-align" id="listeners">
<div class="row">
</div>
</div>
</div>
</main>
<footer class="page-footer cursor-default">
<div class="container">
<div class="row">
<div class="col l6 s12">
<h5 class="white-text">Zoff</h5>
<p class="grey-text text-lighten-4">The shared YouTube radio</p>
<p class="grey-text text-lighten-4">
Being built around the YouTube search and video API
it enables the creation of collaborative and shared live playlists,
with billions of videos and songs to choose from, all for free and without registration.
<br />
Enjoy!
</p>
</div>
<div class="col l4 offset-l2 s12 valign-wrapper">
</div>
</div>
</div>
<div class="footer-copyright">
<div class="container">
&copy; {{year}}
<a href="http://nixo.no">Nixo</a> &amp;
<a href="http://kasperrt.no">KasperRT</a>
<br>
All Rights Reserved.
</div>
</div>
</footer>

View File

@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>
Zoff Admin
</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#2D2D2D">
<meta property="og:image" content="https://zoff.me/assets/images/favicon.png">
<meta property="og:url" content="https://admin.zoff.me">
<meta property="og:title" content="Zoff Admin">
<meta property="og:description" content="Zoff admin panel">
<meta property="og:type" content="website">
<link rel="icon" id="favicon" type="image/png" href="https://zoff.me/assets/images/favicon.png">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script
src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css">
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://zoff.me/assets/css/style.css" title="Default" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
<script type="text/javascript" src="/assets/admin/{{{where_get}}}/js/main.js"></script>
<style>
.preloader-wrapper {
margin-top:15%;
}
.spinner-zoff-only {
border-color: #2d2d2d !important;
}
.tab a{
color: black !important;
}
.name-chat {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.chat-icon {
width: 16px;
height: auto;
margin-right: 2px;
}
.tabs_admin{
margin-bottom:20px;
}
.tabs_admin .indicator{
width: initial !important;
background: black !important;
}
</style>
</head>
<body>
{{{body}}}
</body>
</html>

View File

@@ -0,0 +1,11 @@
<main class="container valign-wrapper row">
<div class="center-align col m6 offset-m3">
<img src="https://zoff.me/assets/images/favicon.png" width="100" height="100" alt="image" />
<form action="/login" id="login_form" method="POST">
<input type="text" name="username" placeholder="Username" required autofocus="on" autocomplete="off" />
<input type="password" name="password" placeholder="Password" required />
<input type="submit" class="hide">
<a href="#" class="btn grey darken-3 waves-effect" id="login_button">LOGIN</a>
</form>
</div>
</main>

230
server/routing/admin/api.js Normal file
View File

@@ -0,0 +1,230 @@
var express = require('express');
var router = express.Router();
var path = require('path');
var mongo_db_cred = require(path.join(__dirname, '../../config/mongo_config.js'));
var mongojs = require('mongojs');
var db = mongojs(mongo_db_cred.config);
router.use(function(req, res, next) {
next(); // make sure we go to the next routes and don't stop here
});
router.route('/api/lists').get(function(req, res){
if(req.isAuthenticated()){
db.collection("frontpage_lists").find().sort({count: -1},function(err, docs){
res.json(docs);
});
} else {
res.send(false);
}
});
router.route('/api/thumbnails').get(function(req, res){
if(req.isAuthenticated()){
db.collection("suggested_thumbnails").find(function(err, docs){
res.json(docs);
});
} else {
res.send(false);
}
});
router.route('/api/descriptions').get(function(req, res){
if(req.isAuthenticated()){
db.collection("suggested_descriptions").find(function(err, docs){
res.json(docs);
});
} else {
res.send(false);
}
});
router.route('/api/approve_thumbnail').post(function(req, res){
if(req.isAuthenticated()){
var channel = req.param("channel");
db.collection("suggested_thumbnails").find({channel: channel}, function(err, docs){
var thumbnail = docs[0].thumbnail;
db.collection("frontpage_lists").update({_id: channel}, {$set:{thumbnail: thumbnail}}, {upsert: true}, function(err, docs){
db.collection(channel).update({views:{$exists:true}}, {$set:{thumbnail: thumbnail}}, {upsert: true}, function(err, docs){
db.collection("suggested_thumbnails").remove({channel: channel}, function(err, docs){
res.send(true);
});
});
});
});
} else {
res.send(false);
}
});
router.route('/api/deny_thumbnail').post(function(req, res){
if(req.isAuthenticated()){
var channel = req.param("channel");
db.collection("suggested_thumbnails").remove({channel: channel},function(err, docs){
res.send(true);
});
} else {
res.send(false);
}
});
router.route('/api/approve_description').post(function(req, res){
if(req.isAuthenticated()){
var channel = req.param("channel");
db.collection("suggested_descriptions").find({channel: channel}, function(err, docs){
var description = docs[0].description;
db.collection("frontpage_lists").update({_id: channel}, {$set:{description: description}}, {upsert: true}, function(err, docs){
db.collection(channel).update({views:{$exists:true}}, {$set:{description: description}}, function(err, docs){
db.collection("suggested_descriptions").remove({channel: channel}, function(err, docs){
res.send(true);
});
});
});
});
} else {
res.send(false);
}
});
router.route('/api/deny_description').post(function(req, res){
if(req.isAuthenticated()){
var channel = req.param("channel");
db.collection("suggested_descriptions").remove({channel: channel}, 1,function(err, docs){
res.send(true);
});
} else {
res.send(false);
}
});
router.route('/api/remove_thumbnail').post(function(req, res){
if(req.isAuthenticated()){
var channel = req.param("channel");
db.collection("frontpage_lists").update({_id: channel}, {$set:{thumbnail: ""}}, function(err, docs){
db.collection(channel).update({views:{$exists:true}}, {$set:{thumbnail: ""}}, function(err, docs){
res.send(true);
});
});
} else {
res.send(false);
}
});
router.route('/api/remove_description').post(function(req, res){
if(req.isAuthenticated()){
var channel = req.param("channel");
db.collection("frontpage_lists").update({_id: channel}, {$set:{description: ""}}, function(err, docs){
db.collection(channel).update({views:{$exists:true}}, {$set:{description: ""}}, function(err, docs){
res.send(true);
});
});
} else {
res.send(false);
}
});
router.route('/api/names').get(function(req, res) {
if(req.isAuthenticated()){
db.collection("registered_users").find({_id: {$exists: true}}, {_id: 1, icon: 1}, function(err, docs) {
res.json(docs);
})
} else {
res.send(false);
}
});
router.route('/api/names').post(function(req, res) {
if(req.isAuthenticated()) {
var icon = req.param("icon");
var name = req.param("name");
db.collection("registered_users").update({_id: name}, {$set: {icon: icon}}, function(err, docs) {
if(err) res.send(false);
else res.send(true);
});
} else {
res.send(false);
}
})
router.route('/api/token').get(function(req, res){
if(req.isAuthenticated()){
token_db.collection("tokens").find(function(err, docs){
if(docs.length == 1){
res.json({token: docs[0].token});
} else {
var id = new Buffer(makeid()).toString('base64');
token_db.collection("tokens").insert({token: id}, function(err, docs){
res.json({token: id});
});
}
})
} else {
res.send(false);
}
});
router.route('/api/delete').post(function(req, res){
if(req.isAuthenticated()){
var list = req.param("_id");
db.collection(list).drop(function(err, docs){
db.collection("frontpage_lists").remove({_id: list}, function(err, docs){
res.send(true);
})
});
} else {
res.send(false);
}
});
router.route('/api/remove_token').get(function(req, res){
if(req.isAuthenticated()){
token_db.collection("tokens").find(function(err, docs){
if(docs.length == 1){
token_db.collection("tokens").remove({token: docs[0].token}, function(err, docs){
res.send(true);
})
} else {
res.send(false);
}
})
} else {
res.send(false);
}
});
router.route('/api/pinned').post(function(req, res){
if(req.isAuthenticated()){
var to_pin = req.param("_id");
db.collection("frontpage_lists").update({pinned:1}, {$set:{pinned:0}}, function(err, resp){
db.collection("frontpage_lists").update({_id:to_pin}, {$set:{pinned:1}}, function(err, resp){
res.send(true);
});
});
} else {
res.send(false);
}
});
router.route('/api/admin').post(function(req, res){
if(req.isAuthenticated()){
var to_remove = req.param("_id");
db.collection(to_remove).update({views: {$exists: true}}, {$set:{adminpass: ""}}, function(err, docs){
res.send(true);
});
} else {
res.send(false);
}
});
router.route('/api/userpass').post(function(req, res){
if(req.isAuthenticated()){
var to_remove = req.param("_id");
db.collection(to_remove).update({views: {$exists: true}}, {$set:{userpass: ""}}, function(err, docs){
res.send(true);
});
} else {
res.send(false);
}
});
module.exports = router;

View File

@@ -94,8 +94,8 @@ router.route('/api/imageblob').post(function(req, res) {
var nodemailer = require('nodemailer');
try {
var mailconfig = require(path.join(__dirname, '../config/mailconfig.js'));
var recaptcha_config = require(path.join(__dirname, '../config/recaptcha.js'));
var mailconfig = require(path.join(__dirname, '../../config/mailconfig.js'));
var recaptcha_config = require(path.join(__dirname, '../../config/recaptcha.js'));
var Recaptcha = require('express-recaptcha');
var RECAPTCHA_SITE_KEY = recaptcha_config.site;
var RECAPTCHA_SECRET_KEY = recaptcha_config.key;

View File

@@ -6,7 +6,7 @@ var path = require('path');
try {
var Recaptcha = require('express-recaptcha');
var recaptcha_config = require(path.join(path.join(__dirname, '../config/'), 'recaptcha.js'));
var recaptcha_config = require(path.join(path.join(__dirname, '../../config/'), 'recaptcha.js'));
var RECAPTCHA_SITE_KEY = recaptcha_config.site;
var RECAPTCHA_SECRET_KEY = recaptcha_config.key;
var recaptcha = new Recaptcha(RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY);
@@ -56,7 +56,7 @@ function root(req, res, next) {
javascript_file: "remote.min.js",
captcha: res.recaptcha
}
res.render('layouts/remote', data);
res.render('layouts/client/remote', data);
} else if(subdomain[0] == "www") {
res.redirect("https://zoff.me");
} else {
@@ -65,7 +65,7 @@ function root(req, res, next) {
javascript_file: "main.min.js",
captcha: res.recaptcha
}
res.render('layouts/frontpage', data);
res.render('layouts/client/frontpage', data);
}
} catch(e) {
//console.log(e);
@@ -87,7 +87,7 @@ function channel(req, res, next) {
javascript_file: "remote.min.js",
captcha: res.recaptcha
}
res.render('layouts/remote', data);
res.render('layouts/client/remote', data);
} else if(subdomain.length >= 2 && subdomain[0] == "www") {
res.redirect("https://zoff.me");
} else {
@@ -109,7 +109,7 @@ function channel(req, res, next) {
res.status(404);
}
res.render('layouts/channel', data);
res.render('layouts/client/channel', data);
}
}
} catch(e) {