More RESTApi explanation in README and more endpoints

This commit is contained in:
Kasper Rynning-Tønnesen
2018-03-01 19:11:20 +01:00
parent 557bc521a5
commit 92a7c88e42
3 changed files with 454 additions and 216 deletions

View File

@@ -4,7 +4,7 @@ Under ``` /server/apps/ ```, there are two files, ``` admin.js ``` and ``` clien
## REST
All PUT, DELETE and POST endpoints have a 2-second waitlimit for each command per client. You'll get a response with Retry-After header for how long you have to wait. Shuffling in a player has a 5-second waitlimit, but per channel instead of per client.
All PUT, DELETE and POST endpoints have a 2-second waitlimit for each command per client. You'll get a response with Retry-After header for how long you have to wait. Shuffling in a player has a 5-second waitlimit, but per channel instead of per client.
Add song
@@ -19,6 +19,7 @@ POST /api/list/:channel_name/:video_id
"userpass": USER_PASSWORD
}
Returns 400 for bad request
Returns 403 for bad authentication
Returns 409 if the song exists
Returns 429 if you're doing too much of this request, with a Retry-After int value in the header.
@@ -33,8 +34,9 @@ DELETE /api/list/:channel_name/:video_id
"userpass": USER_PASSWORD
}
Returns 400 for bad request
Returns 403 for bad authentication
Returns 404 if the song doesnt exist
Returns 404 if the song doesnt exist or is the currently playing song
Returns 429 if you're doing too much of this request, with a Retry-After int value in the header.
Returns 200 if successful
```
@@ -47,6 +49,7 @@ PUT /api/list/:channel_name/:video_id
"userpass": USER_PASSWORD
}
Returns 400 for bad request
Returns 403 for bad authentication
Returns 404 if the song doesnt exist
Returns 409 if you've already voted on that song
@@ -71,12 +74,103 @@ PUT /api/conf/:channel_name
"userpass_changed": BOOLEAN (this must be true if you want to keep the userpassword you're sending)
}
Returns 400 for bad request
Returns 403 for bad authentication
Returns 404 if the list doesn't exist
Returns 429 if you're doing too much of this request, with a Retry-After int value in the header.
Returns 200 and the newly added configuration if successful
```
Get channelsettings
```
GET /api/conf/:channel_name/
Returns 403 for bad authentication (if you get this, try POST with userpassword attached)
Returns 404 if the channel doesn't exist
Returns 200 and the settings-object
```
Get channelsettings (protected)
```
POST /api/conf/:channel_name/
{
"userpass": USERPASS
}
Returns 400 for bad request
Returns 403 for bad authentication
Returns 404 if the channel doesn't exist
Returns 200 and the settings-object
```
Get song in channel
```
GET /api/list/:channel_name/
Returns 403 for bad authentication (if you get this, the channel is protected, try getting the full channel with POST, and search through the object)
Returns 404 if the song doesn't exist
Returns 200 and the song
```
Get song in channel (protected)
```
// Important fetch_song is present, or else the request will try to add a song to the channel
POST /api/list/:channel_name/
{
"fetch_song": ANYTHING_HERE,
"userpass": USERPASS
}
Returns 403 for bad authentication
Returns 404 if the song doesn't exist
Returns 200 and the song
```
Get channelsettings
```
GET /api/list/:channel_name/
Returns 403 for bad authentication (if you get this, try POST with userpassword attached)
Returns 404 if the channel doesn't exist
Returns 200 and the objects in the channel
```
Get channelsettings (protected)
```
POST /api/list/:channel_name/
{
"userpass": USERPASS
}
Returns 400 for bad request
Returns 403 for bad authentication
Returns 404 if the channel doesn't exist
Returns 200 and the objects in the channel
```
Get now playing song
```
GET /api/list/:channel_name/__np__
Returns 400 for bad request
Returns 403 for bad authentication (if you get this, try POST with userpassword attached)
Returns 404 if the channel doesn't exist
Returns 200 and the now playing object
```
Get now playing song (protected)
```
POST /api/list/:channel_name/__np__
{
"userpass": USERPASS
}
Returns 400 for bad request
Returns 403 for bad authentication (if you get this, try POST with userpassword attached)
Returns 404 if the channel doesn't exist
Returns 200 and the now playing object
```
Still to come: SKIP and SHUFFLE RESTApi calls..

View File

@@ -8,12 +8,12 @@ try {
process.exit();
}
function get_correct_info(song_generated, channel, broadcast) {
function get_correct_info(song_generated, channel, broadcast, callback) {
request({
type: "GET",
url: "https://www.googleapis.com/youtube/v3/videos?part=contentDetails,snippet,id&key="+key+"&id=" + song_generated.id,
}, function(error, response, body, callback) {
}, function(error, response, body) {
try {
var resp = JSON.parse(body);
if(resp.items.length == 1) {
@@ -39,9 +39,11 @@ function get_correct_info(song_generated, channel, broadcast) {
if(broadcast && docs.nModified == 1) {
song_generated.new_id = song_generated.id;
io.to(channel).emit("channel", {type: "changed_values", value: song_generated});
if(callback) {
if(typeof(callback) == "function") {
callback();
}
} else {
callback();
}
});
}

View File

@@ -3,6 +3,32 @@ var router = express.Router();
var path = require('path');
var mongojs = require('mongojs');
var ObjectId = mongojs.ObjectId;
var toShowChannel = {
start: 1,
end: 1,
added: 1,
id: 1,
title: 1,
votes: 1,
duration: 1,
type: 1,
_id: 0,
now_playing: 1,
};
var toShowConfig = {
addsongs: 1,
adminpass: 1,
allvideos: 1,
frontpage: 1,
longsongs: 1,
removeplay: 1,
shuffle: 1,
skip: 1,
startTime: 1,
userpass: 1,
vote: 1,
_id: 0
};
router.use(function(req, res, next) {
next(); // make sure we go to the next routes and don't stop here
@@ -17,7 +43,8 @@ router.route('/api/frontpages').get(function(req, res) {
db.collection("frontpage_lists").find({frontpage: true, count: {$gt: 0}}, function(err, docs) {
db.collection("connected_users").find({"_id": "total_users"}, function(err, tot) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({channels: docs, viewers: tot[0].total_users.length}));
res.status(200).send(JSON.stringify({channels: docs, viewers: tot[0].total_users.length}));
return;
});
});
});
@@ -38,7 +65,7 @@ router.route('/api/list/:channel_name/:video_id').delete(function(req, res) {
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]);
var adminpass = req.body.adminpass == "" ? "" : Functions.hash_pass(crypto.createHash('sha256').update(req.body.adminpass, 'utf8').digest("hex"));
req.body.userpass = crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
req.body.userpass = req.body.userpass == "" ? "" : crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
var userpass = req.body.userpass;
var channel_name = cleanChannelName(req.params.channel_name);
var video_id = req.params.video_id;
@@ -50,21 +77,7 @@ router.route('/api/list/:channel_name/:video_id').delete(function(req, res) {
return;
}
db.collection("timeout_api").find({
type: "DELETE",
guid: guid,
}, function(err, docs) {
if(docs.length > 0) {
var date = new Date(docs[0].createdAt);
date.setSeconds(date.getSeconds() + 2);
var now = new Date();
var retry_in = (date.getTime() - now.getTime()) / 1000;
if(retry_in > 0) {
res.header({'Retry-After': retry_in});
res.sendStatus(429);
return;
}
}
checkTimeout(guid, res, "DELETE", function() {
validateLogin(adminpass, userpass, channel_name, "delete", res, function(exists) {
if(!exists) {
res.sendStatus(404);
@@ -84,25 +97,13 @@ router.route('/api/list/:channel_name/:video_id').delete(function(req, res) {
io.to(channel_name).emit("channel", {type:"deleted", value: video_id});
if(dont_increment) {
db.collection("frontpage_lists").update({_id: channel_name, count: {$gt: 0}}, {$inc: {count: -1}, $set:{accessed: Functions.get_time()}}, {upsert: true}, function(err, docs){
db.collection("timeout_api").update({type: "DELETE", guid: guid}, {
$set: {
"createdAt": new Date(),
type: "DELETE",
guid: guid,
},
}, {upsert: true}, function(err, docs) {
updateTimeout(guid, res, "DELETE", function(err, docs) {
res.sendStatus(200);
return;
});
});
} else {
db.collection("timeout_api").update({type: "DELETE", guid: guid}, {
$set: {
"createdAt": new Date(),
type: "DELETE",
guid: guid,
},
}, {upsert: true}, function(err, docs) {
updateTimeout(guid, res, "DELETE", function(err, docs) {
res.sendStatus(200);
return;
});
@@ -114,45 +115,14 @@ router.route('/api/list/:channel_name/:video_id').delete(function(req, res) {
});
});
function cleanChannelName(channel_name) {
var coll = emojiStrip(channel_name).toLowerCase();
coll = coll.replace("_", "");
coll = encodeURIComponent(coll).replace(/\W/g, '');
coll = filter.clean(coll);
return coll;
}
function validateLogin(adminpass, userpass, channel_name, type, res, callback) {
db.collection(channel_name + "_settings").find({views: {$exists: true}}, function(err, conf) {
var exists = false;
if(conf.length > 0 && ((conf[0].userpass == undefined || conf[0].userpass == "" || conf[0].userpass == userpass))) {
exists = true;
} else if(conf.length > 0) {
res.sendStatus(403);
return;
}
if(
(type == "add" && ((conf[0].addsongs && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) || !conf[0].addsongs)) ||
(type == "delete" && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) ||
(type == "vote" && ((conf[0].vote && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) || !conf[0].vote)) ||
(type == "config" && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass))
) {
callback(exists);
} else {
res.sendStatus(403);
return;
}
});
}
router.route('/api/conf/:channel_name').put(function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if(!req.body.hasOwnProperty('adminpass') || !req.body.hasOwnProperty('userpass') ||
!req.params.hasOwnProperty('channel_name') || !req.body.hasOwnProperty('voting') ||
!req.params.hasOwnProperty('channel_name') || !req.body.hasOwnProperty('vote') ||
!req.body.hasOwnProperty('addsongs') || !req.body.hasOwnProperty('longsongs') ||
!req.body.hasOwnProperty('frontpage') || !req.body.hasOwnProperty('allvideos') ||
!req.body.hasOwnProperty('skipping') || !req.body.hasOwnProperty('shuffling') ||
!req.body.hasOwnProperty('skip') || !req.body.hasOwnProperty('shuffle') ||
!req.body.hasOwnProperty('userpass_changed')) {
res.sendStatus(400);
return;
@@ -161,16 +131,16 @@ router.route('/api/conf/:channel_name').put(function(req, res) {
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]);
var adminpass = req.body.adminpass == "" ? "" : Functions.hash_pass(crypto.createHash('sha256').update(req.body.adminpass, 'utf8').digest("hex"));
req.body.userpass = crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
req.body.userpass = req.body.userpass == "" ? "" : crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
var userpass = req.body.userpass;
var voting = req.body.voting;
var voting = req.body.vote;
var addsongs = req.body.addsongs;
var longsongs = req.body.longsongs;
var frontpage = req.body.frontpage;
var allvideos = req.body.allvideos;
var removeplay = req.body.removeplay;
var skipping = req.body.skipping;
var shuffling = req.body.shuffling;
var skipping = req.body.skip;
var shuffling = req.body.shuffle;
var userpass_changed = req.body.userpass_changed;
var channel_name = cleanChannelName(req.params.channel_name);
if(typeof(userpass) != "string" || typeof(adminpass) != "string" ||
@@ -182,27 +152,12 @@ router.route('/api/conf/:channel_name').put(function(req, res) {
throw "Wrong format";
}
} catch(e) {
res.send(e);
res.sendStatus(400);
return;
}
db.collection("timeout_api").find({
type: "CONFIG",
guid: guid,
}, function(err, docs) {
if(docs.length > 0) {
var date = new Date(docs[0].createdAt);
date.setSeconds(date.getSeconds() + 2);
var now = new Date();
var retry_in = (date.getTime() - now.getTime()) / 1000;
if(retry_in > 0) {
res.header({'Retry-After': retry_in});
res.sendStatus(429);
return;
}
}
validateLogin(adminpass, userpass, channel_name, "config", res, function(exists) {
if(!exists) {
checkTimeout(guid, res, "CONFIG", function() {
validateLogin(adminpass, userpass, channel_name, "config", res, function(exists, conf) {
if(!exists && conf.length == 0) {
res.sendStatus(404);
return;
}
@@ -244,15 +199,10 @@ router.route('/api/conf/:channel_name').put(function(req, res) {
frontpage:frontpage, accessed: Functions.get_time()}
},
{upsert:true}, function(err, docs){
db.collection("timeout_api").update({type: "CONFIG", guid: guid}, {
$set: {
"createdAt": new Date(),
type: "CONFIG",
guid: guid,
},
}, {upsert: true}, function(err, docs) {
updateTimeout(guid, res, "CONFIG", function(err, docs) {
res.header({'Content-Type': 'application/json'});
res.status(200).send(JSON.stringify(obj));
return;
});
});
});
@@ -273,7 +223,7 @@ router.route('/api/list/:channel_name/:video_id').put(function(req,res) {
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]);
var adminpass = req.body.adminpass == "" ? "" : Functions.hash_pass(crypto.createHash('sha256').update(req.body.adminpass, 'utf8').digest("hex"));
req.body.userpass = crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
req.body.userpass = req.body.userpass == "" ? "" : crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
var userpass = req.body.userpass;
var channel_name = cleanChannelName(req.params.channel_name);
var video_id = req.params.video_id;
@@ -281,27 +231,11 @@ router.route('/api/list/:channel_name/:video_id').put(function(req,res) {
throw "Wrong format";
}
} catch(e) {
res.send(e);
res.sendStatus(400);
return;
}
db.collection("timeout_api").find({
type: "PUT",
guid: guid,
}, function(err, docs) {
if(docs.length > 0) {
var date = new Date(docs[0].createdAt);
date.setSeconds(date.getSeconds() + 2);
var now = new Date();
var retry_in = (date.getTime() - now.getTime()) / 1000;
if(retry_in > 0) {
res.header({'Retry-After': retry_in});
res.sendStatus(429);
return;
}
}
checkTimeout(guid, res, "PUT", function() {
validateLogin(adminpass, userpass, channel_name, "vote", res, function(exists) {
if(!exists) {
res.sendStatus(404);
@@ -320,13 +254,7 @@ router.route('/api/list/:channel_name/:video_id').put(function(req,res) {
db.collection(channel_name).update({id: video_id}, {$inc:{votes:1}, $set:{added:Functions.get_time()}, $push :{guids: guid}}, function(err, success) {
io.to(channel_name).emit("channel", {type: "vote", value: video_id, time: Functions.get_time()});
List.getNextSong(channel_name, function() {
db.collection("timeout_api").update({type: "PUT", guid: guid}, {
$set: {
"createdAt": new Date(),
type: "PUT",
guid: guid,
},
}, {upsert: true}, function(err, docs) {
updateTimeout(guid, res, "PUT", function(err, docs) {
res.header({'Content-Type': 'application/json'});
res.status(200).send(JSON.stringify(song[0]));
return;
@@ -339,58 +267,98 @@ router.route('/api/list/:channel_name/:video_id').put(function(req,res) {
});
});
router.route('/api/list/:channel_name/__np__').post(function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if(!req.body.hasOwnProperty('userpass')) {
res.sendStatus(400);
return;
}
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]);
var channel_name = req.params.channel_name;
req.body.userpass = req.body.userpass == "" ? "" : crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
var userpass = req.body.userpass;
if(typeof(userpass) != "string") {
res.sendStatus(400);
return;
}
checkTimeout(guid, res, "POST", function() {
db.collection(channel_name).find({now_playing: true}, toShowChannel, function(err, list) {
if(list.length > 0) {
db.collection(channel_name + "_settings").find({views: {$exists: true}}, function(err, conf) {
if(conf.length == 0) {
res.sendStatus(404);
return;
} else if(conf[0].userpass != userpass && conf[0].userpass != "") {
res.sendStatus(403);
return;
}
updateTimeout(guid, res, "POST", function(err, docs) {
res.setHeader('Content-Type', 'application/json');
res.status(200).send(JSON.stringify(list[0]));
});
});
} else {
res.sendStatus(404);
}
});
});
});
router.route('/api/list/:channel_name/:video_id').post(function(req,res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if(!req.body.hasOwnProperty('adminpass') || !req.body.hasOwnProperty('userpass') ||
var fetch_only = false;
if(req.body.hasOwnProperty('fetch_song')) {
fetch_only = true;
}
if(!fetch_only && (!req.body.hasOwnProperty('adminpass') || !req.body.hasOwnProperty('userpass') ||
!req.params.hasOwnProperty('channel_name') || !req.params.hasOwnProperty('video_id') ||
!req.body.hasOwnProperty('duration') || !req.body.hasOwnProperty('start_time') ||
!req.body.hasOwnProperty('end_time') || !req.body.hasOwnProperty('title')) {
!req.body.hasOwnProperty('end_time') || !req.body.hasOwnProperty('title'))) {
res.sendStatus(400);
return;
}
try {
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]);
var adminpass = req.body.adminpass == "" ? "" : Functions.hash_pass(crypto.createHash('sha256').update(req.body.adminpass, 'utf8').digest("hex"));
req.body.userpass = crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
req.body.userpass = req.body.userpass == "" ? "" : crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
var userpass = req.body.userpass;
var channel_name = cleanChannelName(req.params.channel_name);
var video_id = req.params.video_id;
var duration = parseInt(req.body.duration);
var start_time = parseInt(req.body.start_time);
var end_time = parseInt(req.body.end_time);
if(duration != end_time - start_time) duration = end_time - start_time;
var title = req.body.title;
if(typeof(userpass) != "string" || typeof(adminpass) != "string" ||
typeof(title) != "string") {
throw "Wrong format";
}
if(!fetch_only) {
var adminpass = req.body.adminpass == "" ? "" : Functions.hash_pass(crypto.createHash('sha256').update(req.body.adminpass, 'utf8').digest("hex"));
var duration = parseInt(req.body.duration);
var start_time = parseInt(req.body.start_time);
var end_time = parseInt(req.body.end_time);
if(duration != end_time - start_time) duration = end_time - start_time;
var title = req.body.title;
if(typeof(userpass) != "string" || typeof(adminpass) != "string" ||
typeof(title) != "string") {
throw "Wrong format";
}
}
} catch(e) {
res.send(e);
console.log("crash here", e);
res.sendStatus(400);
return;
}
db.collection("timeout_api").find({
type: "POST",
guid: guid,
}, function(err, docs) {
if(docs.length > 0) {
var date = new Date(docs[0].createdAt);
date.setSeconds(date.getSeconds() + 2);
var now = new Date();
var retry_in = (date.getTime() - now.getTime()) / 1000;
if(retry_in > 0) {
res.header({'Retry-After': retry_in});
res.sendStatus(429);
return;
}
}
validateLogin(adminpass, userpass, channel_name, "add", res, function(exists) {
checkTimeout(guid, res, "POST", function() {
var type = fetch_only ? "fetch_song" : "add";
validateLogin(adminpass, userpass, channel_name, type, res, function(exists) {
db.collection(channel_name).find({id: video_id}, function(err, result) {
if(result.length == 0) {
if(fetch_only) {
res.sendStatus(404);
return;
}
db.collection(channel_name).find({now_playing: true}, function(err, now_playing) {
var set_np = false;
if(now_playing.length == 0) {
@@ -427,6 +395,10 @@ router.route('/api/list/:channel_name/:video_id').post(function(req,res) {
});
})
})
} else if(fetch_only) {
res.setHeader('Content-Type', 'application/json');
res.status(200).send(JSON.stringify(result[0]));
return;
} else {
res.sendStatus(409);
return;
@@ -436,72 +408,68 @@ router.route('/api/list/:channel_name/:video_id').post(function(req,res) {
});
});
function postEnd(channel_name, configs, new_song, guid, res) {
if(configs != undefined) {
io.to(channel_name).emit("conf", configs);
}
List.getNextSong(channel_name, function() {
db.collection("timeout_api").update({type: "POST", guid: guid}, {
$set: {
"createdAt": new Date(),
type: "POST",
guid: guid,
},
}, {upsert: true}, function(err, docs) {
Search.get_correct_info(new_song, channel_name, !new_song.now_playing, function() {
res.header({'Content-Type': 'application/json'});
res.status(200).send(JSON.stringify(new_song));
return;
});
});
});
}
router.route('/api/list/:channel_name').get(function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
var channel_name = req.params.channel_name;
db.collection(channel_name).find({views: {$exists: false}}, {
start: 1,
end: 1,
added: 1,
id: 1,
title: 1,
votes: 1,
duration: 1,
type: 1,
_id: 0,
now_playing: 1,
}, function(err, docs) {
db.collection(channel_name).find({views: {$exists: false}}, toShowChannel, function(err, docs) {
if(docs.length > 0) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(docs));
db.collection(channel_name + "_settings").find({views: {$exists: true}}, function(err, conf) {
if(conf.length == 0) {
res.sendStatus(404);
return;
} else if(conf[0].userpass != "" && conf[0].userpass != undefined) {
res.sendStatus(403);
return;
}
res.setHeader('Content-Type', 'application/json');
res.status(200).send(JSON.stringify(docs));
});
} else {
/*res.status(404);
res.send(404);*/
res.status(404).redirect("/404");
res.sendStatus(404);
}
});
});
router.route('/api/list/:channel_name/:video_id').get(function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
var channel_name = req.params.channel_name;
var video_id = req.params.video_id;
var searchQuery = {id: video_id};
if(video_id == "__np__") {
searchQuery = {now_playing: true};
}
db.collection(channel_name).find(searchQuery, toShowChannel, function(err, docs) {
if(docs.length > 0) {
db.collection(channel_name + "_settings").find({views: {$exists: true}}, function(err, conf) {
if(conf.length == 0) {
res.sendStatus(404);
return;
} else if(conf[0].userpass != "" && conf[0].userpass != undefined) {
res.sendStatus(403);
return;
}
res.setHeader('Content-Type', 'application/json');
res.status(200).send(JSON.stringify(docs[0]));
return;
});
} else {
res.sendStatus(404);
return;
}
});
});
router.route('/api/conf/:channel_name').get(function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
var channel_name = req.params.channel_name;
db.collection(channel_name + "_settings").find({views: {$exists: true}}, {
addsongs: 1,
adminpass: 1,
allvideos: 1,
frontpage: 1,
longsongs: 1,
removeplay: 1,
shuffle: 1,
skip: 1,
startTime: 1,
userpass: 1,
vote: 1,
_id: 0
}, function(err, docs) {
if(docs.length > 0) {
db.collection(channel_name + "_settings").find({views: {$exists: true}}, toShowConfig, function(err, docs) {
if(docs.length > 0 && docs[0].userpass == "" || docs[0].userpass == undefined) {
var conf = docs[0];
if(conf.adminpass != "") {
conf.adminpass = true;
@@ -514,22 +482,116 @@ router.route('/api/conf/:channel_name').get(function(req, res) {
conf.userpass = false;
}
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(conf));
res.status(200).send(JSON.stringify(conf));
} else if(docs.length > 0 && docs[0].userpass != "" && docs[0].userpass != undefined){
res.sendStatus(403);
return;
} else {
/*res.status(404);
res.send(404);*/
res.status(404).redirect("/404");
res.sendStatus(404);
return;
}
});
});
router.route('/api/conf/:channel_name').post(function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if(!req.body.hasOwnProperty('userpass')) {
res.sendStatus(400);
return;
}
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]);
var channel_name = req.params.channel_name;
req.body.userpass = req.body.userpass == "" ? "" : crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
var userpass = req.body.userpass;
if(typeof(userpass) != "string") {
res.sendStatus(400);
return;
}
checkTimeout(guid, res, "POST", function() {
db.collection(channel_name + "_settings").find({views: {$exists: true}}, toShowConfig, function(err, docs) {
if(docs.length > 0 && docs[0].userpass == userpass) {
var conf = docs[0];
if(conf.adminpass != "") {
conf.adminpass = true;
} else {
conf.adminpass = false;
}
if(conf.userpass != "") {
conf.userpass = true;
} else {
conf.userpass = false;
}
updateTimeout(guid, res, "POST", function(err, docs) {
res.setHeader('Content-Type', 'application/json');
res.status(200).send(JSON.stringify(conf));
});
} else if(docs.length > 0 && docs[0].userpass != userpass) {
res.sendStatus(403);
return;
} else {
res.sendStatus(404);
return;
}
});
});
});
router.route('/api/list/:channel_name').post(function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if(!req.body.hasOwnProperty('userpass')) {
res.sendStatus(400);
return;
}
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]);
var channel_name = req.params.channel_name;
req.body.userpass = req.body.userpass == "" ? "" : crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex");
var userpass = req.body.userpass;
if(typeof(userpass) != "string") {
res.sendStatus(400);
return;
}
checkTimeout(guid, res, "POST", function() {
db.collection(channel_name).find({views: {$exists: false}}, toShowChannel, function(err, list) {
if(list.length > 0) {
db.collection(channel_name + "_settings").find({views: {$exists: true}}, function(err, conf) {
if(conf.length == 0) {
res.sendStatus(404);
return;
} else if(conf[0].userpass != userpass && conf[0].userpass != "") {
res.sendStatus(403);
return;
}
updateTimeout(guid, res, "POST", function(err, docs) {
res.setHeader('Content-Type', 'application/json');
res.status(200).send(JSON.stringify(list));
});
});
} else {
res.sendStatus(404);
}
});
});
});
router.route('/api/imageblob').post(function(req, res) {
var Jimp = require("jimp");
Jimp.read('https://img.youtube.com/vi/' + req.body.id + '/mqdefault.jpg', function (err, image) {
if (err) console.log(err);
image.blur(50)
.write(path.join(pathThumbnails, '/public/assets/images/thumbnails/' + req.body.id + '.jpg'), function(e, r) {
res.send(req.body.id + ".jpg");
res.status(200).send(req.body.id + ".jpg");
return;
});
});
});
@@ -568,17 +630,17 @@ try {
}
transporter.sendMail(msg, (error, info) => {
if (error) {
res.send("failed");
res.status(500).send("failed");
transporter.close();
return;
}
res.send("success");
res.status(200).send("success");
transporter.close();
});
}
});
} else {
res.send("failed");
res.status(500).send("failed");
return;
}
});
@@ -587,9 +649,89 @@ try {
console.log("Seems you forgot to create a mailconfig.js in /server/config/. Have a look at the mailconfig.example.js.");
router.route('/api/mail').post(function(req, res) {
console.log("Someone tried to send a mail, but the mailsystem hasn't been enabled..")
res.send("failed");
res.status(500).send("failed");
return;
});
}
function updateTimeout(guid, res, type, callback) {
db.collection("timeout_api").update({type: "DELETE", guid: guid}, {
$set: {
"createdAt": new Date(),
type: "DELETE",
guid: guid,
},
}, {upsert: true}, function(err, docs) {
callback(err, docs);
});
}
function checkTimeout(guid, res, type, callback) {
db.collection("timeout_api").find({
type: type,
guid: guid,
}, function(err, docs) {
if(docs.length > 0) {
var date = new Date(docs[0].createdAt);
date.setSeconds(date.getSeconds() + 2);
var now = new Date();
var retry_in = (date.getTime() - now.getTime()) / 1000;
if(retry_in > 0) {
res.header({'Retry-After': retry_in});
res.sendStatus(429);
return;
}
}
callback();
});
}
function cleanChannelName(channel_name) {
var coll = emojiStrip(channel_name).toLowerCase();
coll = coll.replace("_", "");
coll = encodeURIComponent(coll).replace(/\W/g, '');
coll = filter.clean(coll);
return coll;
}
function validateLogin(adminpass, userpass, channel_name, type, res, callback) {
db.collection(channel_name + "_settings").find({views: {$exists: true}}, function(err, conf) {
var exists = false;
if(conf.length > 0 && ((conf[0].userpass == undefined || conf[0].userpass == "" || conf[0].userpass == userpass))) {
exists = true;
} else if(conf.length > 0 && type != "config") {
res.sendStatus(403);
return;
}
if(
(type == "fetch_song") ||
(type == "add" && ((conf[0].addsongs && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) || !conf[0].addsongs)) ||
(type == "delete" && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) ||
(type == "vote" && ((conf[0].vote && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) || !conf[0].vote)) ||
(type == "config" && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass))
) {
callback(exists, conf);
} else {
res.sendStatus(403);
return;
}
});
}
function postEnd(channel_name, configs, new_song, guid, res) {
if(configs != undefined) {
io.to(channel_name).emit("conf", configs);
}
List.getNextSong(channel_name, function() {
updateTimeout(guid, res, "POST", function(err, docs) {
Search.get_correct_info(new_song, channel_name, !new_song.now_playing, function() {
res.header({'Content-Type': 'application/json'});
res.status(200).send(JSON.stringify(new_song));
return;
});
});
});
}
module.exports = router;