mirror of
				https://github.com/KevinMidboe/zoff.git
				synced 2025-10-29 18:00:23 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2511 lines
		
	
	
		
			81 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			2511 lines
		
	
	
		
			81 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| var express = require("express");
 | |
| var router = express.Router();
 | |
| var path = require("path");
 | |
| var mongojs = require("mongojs");
 | |
| var ObjectId = mongojs.ObjectId;
 | |
| var token_db = mongojs("tokens");
 | |
| var cookieParser = require("cookie-parser");
 | |
| var db = require(pathThumbnails + "/handlers/db.js");
 | |
| var allowed_key;
 | |
| 
 | |
| try {
 | |
|   allowed_key = require(pathThumbnails + "/config/allowed_api.js");
 | |
| } catch (e) {
 | |
|   allowed_key = ["***"];
 | |
|   console.log(
 | |
|     "(!) Missing file - /config/allowed_api.js Have a look at /config/allowed_api.example.js."
 | |
|   );
 | |
| }
 | |
| var crypto = require("crypto");
 | |
| var List = require(pathThumbnails + "/handlers/list.js");
 | |
| var Functions = require(pathThumbnails + "/handlers/functions.js");
 | |
| var Frontpage = require(pathThumbnails + "/handlers/frontpage.js");
 | |
| var Search = require(pathThumbnails + "/handlers/search.js");
 | |
| var uniqid = require("uniqid");
 | |
| var Filter = require("bad-words");
 | |
| var filter = new Filter({ placeHolder: "x" });
 | |
| var paginate = require("mongojs-paginate");
 | |
| 
 | |
| var _exports = {
 | |
|   router: router,
 | |
|   sIO: {}
 | |
| };
 | |
| var projects = require(pathThumbnails + "/handlers/aggregates.js");
 | |
| 
 | |
| var error = {
 | |
|   not_found: {
 | |
|     youtube: {
 | |
|       status: 404,
 | |
|       error: "Couldn't find a song like that on YouTube.",
 | |
|       success: false,
 | |
|       results: []
 | |
|     },
 | |
|     local: {
 | |
|       status: 404,
 | |
|       error: "Couldn't find a song like that in the channel",
 | |
|       success: false,
 | |
|       results: []
 | |
|     },
 | |
|     list: {
 | |
|       status: 404,
 | |
|       error: "The list doesn't exist",
 | |
|       success: false,
 | |
|       results: []
 | |
|     }
 | |
|   },
 | |
|   not_authenticated: {
 | |
|     status: 403,
 | |
|     error: "Wrong adminpassword or userpassword.",
 | |
|     success: false,
 | |
|     results: []
 | |
|   },
 | |
|   formatting: {
 | |
|     status: 400,
 | |
|     error: "Malformed request parameters.",
 | |
|     success: false,
 | |
|     results: []
 | |
|   },
 | |
|   conflicting: {
 | |
|     status: 409,
 | |
|     error: "That element already exists.",
 | |
|     success: false,
 | |
|     results: []
 | |
|   },
 | |
|   wrong_token: {
 | |
|     status: 400,
 | |
|     error:
 | |
|       "You're using a faulty token. Try getting a new token, or send the request without the token.",
 | |
|     success: false,
 | |
|     results: []
 | |
|   },
 | |
|   tooMany: {
 | |
|     status: 429,
 | |
|     error:
 | |
|       "You're doing too many requests, check header-field Retry-After for the wait-time left.",
 | |
|     success: false,
 | |
|     results: []
 | |
|   },
 | |
|   settings: {
 | |
|     status: 409,
 | |
|     error: "The channel doesn't have strict skipping enabled.",
 | |
|     success: false,
 | |
|     results: []
 | |
|   },
 | |
|   already_skip: {
 | |
|     status: 206,
 | |
|     error: false,
 | |
|     success: true,
 | |
|     results: []
 | |
|   },
 | |
|   more_skip_needed: {
 | |
|     status: 202,
 | |
|     error: false,
 | |
|     success: true,
 | |
|     results: []
 | |
|   },
 | |
|   no_error: {
 | |
|     status: 200,
 | |
|     error: false,
 | |
|     success: true,
 | |
|     results: []
 | |
|   }
 | |
| };
 | |
| 
 | |
| router.use(function(req, res, next) {
 | |
|   next(); // make sure we go to the next routes and don't stop here
 | |
| });
 | |
| 
 | |
| router.route("/api/help").get(function(req, res) {
 | |
|   res.redirect("https://github.com/zoff-music/zoff/blob/master/server/REST.md");
 | |
|   return;
 | |
| });
 | |
| 
 | |
| router.route("/api/frontpages").get(function(req, res) {
 | |
|   res.header("Access-Control-Allow-Origin", "*");
 | |
|   res.header(
 | |
|     "Access-Control-Allow-Headers",
 | |
|     "Origin, X-Requested-With, Content-Type, Accept"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   var ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress;
 | |
|   var guid = Functions.hash_pass(
 | |
|     req.get("User-Agent") + ip + req.headers["accept-language"]
 | |
|   );
 | |
| 
 | |
|   checkTimeout(guid, res, false, "GET", function() {
 | |
|     Frontpage.get_frontpage_lists(function(err, docs) {
 | |
|       //db.collection("frontpage_lists").find({frontpage: true, count: {$gt: 0}}, function(err, docs) {
 | |
|       db.collection("connected_users").find({ _id: "total_users" }, function(
 | |
|         err,
 | |
|         tot
 | |
|       ) {
 | |
|         var to_return = error.no_error;
 | |
|         to_return.results = {
 | |
|           channels: docs,
 | |
|           viewers: tot[0].total_users.length
 | |
|         };
 | |
|         res.status(200).send(to_return);
 | |
|         return;
 | |
|       });
 | |
|     });
 | |
|   });
 | |
| });
 | |
| 
 | |
| router.route("/api/frontpages").post(function(req, res) {
 | |
|   res.header("Access-Control-Allow-Origin", "*");
 | |
|   res.header(
 | |
|     "Access-Control-Allow-Headers",
 | |
|     "Origin, X-Requested-With, Content-Type, Accept"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   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 token = "";
 | |
|   if (req.body.hasOwnProperty("token")) {
 | |
|     token = req.body.token;
 | |
|   }
 | |
| 
 | |
|   var ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress;
 | |
|   var guid = Functions.hash_pass(
 | |
|     req.get("User-Agent") + ip + req.headers["accept-language"]
 | |
|   );
 | |
| 
 | |
|   token_db
 | |
|     .collection("api_token")
 | |
|     .find({ token: token }, function(err, token_docs) {
 | |
|       var authorized = false;
 | |
|       var origin;
 | |
|       try {
 | |
|         origin = req.headers.referer.split("/")[2];
 | |
|       } catch (e) {
 | |
|         origin = "";
 | |
|       }
 | |
|       if (
 | |
|         token_docs.length == 1 &&
 | |
|         token_docs[0].token == token &&
 | |
|         (token_docs[0].origin == "*" ||
 | |
|           origin.indexOf(token_docs[0].origin) > -1)
 | |
|       ) {
 | |
|         authorized = true;
 | |
|       }
 | |
|       checkOveruseApiToken(authorized, token_docs, res, function() {
 | |
|         checkTimeout(guid, res, authorized, "POST", function() {
 | |
|           Frontpage.get_frontpage_lists(function(err, docs) {
 | |
|             //db.collection("frontpage_lists").find({frontpage: true, count: {$gt: 0}}, function(err, docs) {
 | |
|             db.collection("connected_users").find(
 | |
|               { _id: "total_users" },
 | |
|               function(err, tot) {
 | |
|                 var to_return = error.no_error;
 | |
|                 to_return.results = {
 | |
|                   channels: docs,
 | |
|                   viewers: tot[0].total_users.length
 | |
|                 };
 | |
|                 res.status(200).send(to_return);
 | |
|                 return;
 | |
|               }
 | |
|             );
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|     });
 | |
| });
 | |
| 
 | |
| router.route("/api/generate_name").get(function(req, res) {
 | |
|   Functions.generate_channel_name(res);
 | |
| });
 | |
| 
 | |
| router.route("/api/list/:channel_name/:video_id").delete(function(req, res) {
 | |
|   res.header("Access-Control-Allow-Origin", "*");
 | |
|   res.header(
 | |
|     "Access-Control-Allow-Headers",
 | |
|     "Origin, X-Requested-With, Content-Type, Accept"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   if (
 | |
|     !req.body.hasOwnProperty("adminpass") ||
 | |
|     !req.body.hasOwnProperty("userpass") ||
 | |
|     !req.params.hasOwnProperty("channel_name") ||
 | |
|     !req.params.hasOwnProperty("video_id")
 | |
|   ) {
 | |
|     var result = {
 | |
|       adminpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("adminpass")
 | |
|           ? typeof req.body.adminpass
 | |
|           : undefined
 | |
|       },
 | |
|       userpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("userpass")
 | |
|           ? typeof req.body.userpass
 | |
|           : undefined
 | |
|       }
 | |
|     };
 | |
|     var to_send = error.formatting;
 | |
|     to_send.results = [result];
 | |
|     res.status(400).send(to_send);
 | |
|     return;
 | |
|   }
 | |
|   var token = "";
 | |
|   if (req.body.hasOwnProperty("token")) {
 | |
|     token = req.body.token;
 | |
|   }
 | |
|   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 =
 | |
|       req.body.userpass == ""
 | |
|         ? ""
 | |
|         : crypto
 | |
|             .createHash("sha256")
 | |
|             .update(req.body.userpass, "utf8")
 | |
|             .digest("base64");
 | |
|     var userpass = req.body.userpass;
 | |
|     var channel_name = cleanChannelName(req.params.channel_name);
 | |
|     var video_id = req.params.video_id;
 | |
|     if (typeof userpass != "string" || typeof adminpass != "string") {
 | |
|       throw "Wrong format";
 | |
|     }
 | |
|   } catch (e) {
 | |
|     var result = {
 | |
|       adminpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("adminpass")
 | |
|           ? typeof req.body.adminpass
 | |
|           : undefined
 | |
|       },
 | |
|       userpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("userpass")
 | |
|           ? typeof req.body.userpass
 | |
|           : undefined
 | |
|       }
 | |
|     };
 | |
|     var to_send = error.formatting;
 | |
|     to_send.results = [result];
 | |
|     res.status(400).send(to_send);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   var cookie = req.cookies._uI;
 | |
| 
 | |
|   Functions.getSessionAdminUser(cookie, channel_name, function(_u, _a) {
 | |
|     if (req.body.adminpass == "") {
 | |
|       adminpass = Functions.hash_pass(_a);
 | |
|     }
 | |
|     if (req.body.userpass == "") {
 | |
|       userpass = _u;
 | |
|     }
 | |
|     token_db
 | |
|       .collection("api_token")
 | |
|       .find({ token: token }, function(err, token_docs) {
 | |
|         var authorized = false;
 | |
|         var origin;
 | |
|         try {
 | |
|           origin = req.headers.referer.split("/")[2];
 | |
|         } catch (e) {
 | |
|           origin = "";
 | |
|         }
 | |
|         if (
 | |
|           token_docs.length == 1 &&
 | |
|           token_docs[0].token == token &&
 | |
|           (token_docs[0].origin == "*" ||
 | |
|             origin.indexOf(token_docs[0].origin) > -1)
 | |
|         ) {
 | |
|           authorized = true;
 | |
|         }
 | |
|         checkOveruseApiToken(authorized, token_docs, res, function() {
 | |
|           checkTimeout(guid, res, authorized, "DELETE", function() {
 | |
|             if (token != "" && !authorized) {
 | |
|               //updateTimeout(guid, res, authorized, "DELETE", function(err, docs) {
 | |
|               res.status(400).send(error.wrong_token);
 | |
|               return;
 | |
|               //});
 | |
|             } else {
 | |
|               validateLogin(
 | |
|                 adminpass,
 | |
|                 userpass,
 | |
|                 channel_name,
 | |
|                 "delete",
 | |
|                 res,
 | |
|                 function(exists) {
 | |
|                   if (!exists) {
 | |
|                     res.status(404).send(error.not_found.list);
 | |
|                     return;
 | |
|                   }
 | |
|                   db.collection(channel_name).find(
 | |
|                     { id: video_id, now_playing: false },
 | |
|                     function(err, docs) {
 | |
|                       if (docs.length == 0) {
 | |
|                         res.status(404).send(error.not_found.local);
 | |
|                         return;
 | |
|                       }
 | |
|                       var dont_increment = false;
 | |
|                       if (docs[0]) {
 | |
|                         if (docs[0].type == "suggested") {
 | |
|                           dont_increment = true;
 | |
|                         }
 | |
|                         db.collection(channel_name).remove(
 | |
|                           { id: video_id },
 | |
|                           function(err, docs) {
 | |
|                             if (authorized) {
 | |
|                               incrementToken(token);
 | |
|                             }
 | |
|                             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) {
 | |
|                                   //updateTimeout(guid, res, authorized, "DELETE", function(err, docs) {
 | |
|                                   res.status(200).send(error.no_error);
 | |
|                                   return;
 | |
|                                   //});
 | |
|                                 }
 | |
|                               );
 | |
|                             } else {
 | |
|                               //updateTimeout(guid, res, authorized, "DELETE", function(err, docs) {
 | |
|                               res.status(200).send(error.no_error);
 | |
|                               return;
 | |
|                               //});
 | |
|                             }
 | |
|                           }
 | |
|                         );
 | |
|                       }
 | |
|                     }
 | |
|                   );
 | |
|                 }
 | |
|               );
 | |
|             }
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|   });
 | |
| });
 | |
| 
 | |
| router.route("/api/skip/: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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
| 
 | |
|   var api_key = req.body.api_key;
 | |
|   var guid = req.body.chat_name;
 | |
|   var channel_name = cleanChannelName(req.params.channel_name);
 | |
|   var userpass = "";
 | |
|   if (req.body.userpass && req.body.userpass != "")
 | |
|     userpass = crypto
 | |
|       .createHash("sha256")
 | |
|       .update(Functions.decrypt_string(req.body.userpass))
 | |
|       .digest("base64");
 | |
|   if (allowed_key.indexOf(api_key) > -1 || allowed_key.indexOf("***") > -1) {
 | |
|     db.collection(channel_name + "_settings").find({ id: "config" }, function(
 | |
|       err,
 | |
|       settings
 | |
|     ) {
 | |
|       if (settings.length == 0) {
 | |
|         res.status(404).send(error.not_found.list);
 | |
|         return;
 | |
|       }
 | |
|       settings = settings[0];
 | |
|       if (!settings.strictSkip) {
 | |
|         res.status(409).send(error.settings);
 | |
|         return;
 | |
|       }
 | |
|       if (settings.userpass == "" || settings.userpass == userpass) {
 | |
|         if (
 | |
|           settings.skips.length + 1 >= settings.strictSkipNumber &&
 | |
|           !Functions.contains(settings.skips, guid)
 | |
|         ) {
 | |
|           Functions.checkTimeout(
 | |
|             "skip",
 | |
|             1,
 | |
|             channel_name,
 | |
|             channel_name,
 | |
|             false,
 | |
|             true,
 | |
|             undefined,
 | |
|             function() {
 | |
|               db.collection(channel_name).find({ now_playing: true }, function(
 | |
|                 err,
 | |
|                 np
 | |
|               ) {
 | |
|                 if (np.length != 1) {
 | |
|                   res.status(404).send(error.not_found.list);
 | |
|                   return;
 | |
|                 }
 | |
|                 List.change_song(
 | |
|                   channel_name,
 | |
|                   false,
 | |
|                   np[0].id,
 | |
|                   [settings],
 | |
|                   function() {
 | |
|                     res.status(200).send(error.no_error);
 | |
|                     return;
 | |
|                   }
 | |
|                 );
 | |
|                 _exports.sIO.to(channel_name).emit("chat", {
 | |
|                   from: guid,
 | |
|                   icon: false,
 | |
|                   msg: " skipped via API."
 | |
|                 });
 | |
|               });
 | |
|             },
 | |
|             "",
 | |
|             function() {
 | |
|               res.status(429).send(error.tooMany);
 | |
|               return;
 | |
|             }
 | |
|           );
 | |
|         } else if (!Functions.contains(settings.skips, guid)) {
 | |
|           db.collection(channel_name + "_settings").update(
 | |
|             { id: "config" },
 | |
|             { $push: { skips: guid } },
 | |
|             function(err, d) {
 | |
|               var to_skip =
 | |
|                 settings.strictSkipNumber - settings.skips.length - 1;
 | |
|               _exports.sIO
 | |
|                 .to(channel_name)
 | |
|                 .emit("chat", { from: guid, msg: " voted to skip via API." });
 | |
|               // VOTED TO SKIP
 | |
|               var to_send = error.more_skip_needed;
 | |
|               to_send.results = [to_skip];
 | |
|               res.status(202).send(to_send);
 | |
|               return;
 | |
|             }
 | |
|           );
 | |
|         } else {
 | |
|           //ALREADY SKIP
 | |
|           res.status(206).send(error.already_skip);
 | |
|           return;
 | |
|         }
 | |
|       } else {
 | |
|         // NOT AUTHENTICATED
 | |
|         res.status(403).send(error.not_authenticated);
 | |
|         return;
 | |
|       }
 | |
|     });
 | |
|   } else {
 | |
|     // WRONG API KEY
 | |
|     var toSend = error.not_authenticated;
 | |
|     toSend.status = 406;
 | |
|     res.status(406).send(toSend);
 | |
|     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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
| 
 | |
|   try {
 | |
|     if (
 | |
|       !req.body.hasOwnProperty("adminpass") ||
 | |
|       !req.body.hasOwnProperty("userpass") ||
 | |
|       !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("skip") ||
 | |
|       !req.body.hasOwnProperty("shuffle") ||
 | |
|       !req.body.hasOwnProperty("userpass_changed")
 | |
|     ) {
 | |
|       throw "Wrong format";
 | |
|     }
 | |
|     var token = "";
 | |
|     if (req.body.hasOwnProperty("token")) {
 | |
|       token = req.body.token;
 | |
|     }
 | |
| 
 | |
|     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 =
 | |
|       req.body.userpass == ""
 | |
|         ? ""
 | |
|         : crypto
 | |
|             .createHash("sha256")
 | |
|             .update(req.body.userpass, "utf8")
 | |
|             .digest("base64");
 | |
|     var userpass = req.body.userpass;
 | |
|     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.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" ||
 | |
|       typeof voting != "boolean" ||
 | |
|       typeof addsongs != "boolean" ||
 | |
|       typeof longsongs != "boolean" ||
 | |
|       typeof frontpage != "boolean" ||
 | |
|       typeof allvideos != "boolean" ||
 | |
|       typeof removeplay != "boolean" ||
 | |
|       typeof skipping != "boolean" ||
 | |
|       typeof shuffling != "boolean" ||
 | |
|       typeof userpass_changed != "boolean"
 | |
|     ) {
 | |
|       throw "Wrong format";
 | |
|     }
 | |
|   } catch (e) {
 | |
|     var result = {
 | |
|       adminpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("adminpass")
 | |
|           ? typeof req.body.adminpass
 | |
|           : undefined
 | |
|       },
 | |
|       userpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("userpass")
 | |
|           ? typeof req.body.userpass
 | |
|           : undefined
 | |
|       },
 | |
|       vote: {
 | |
|         expected: "boolean",
 | |
|         got: req.body.hasOwnProperty("vote") ? typeof req.body.vote : undefined
 | |
|       },
 | |
|       addsongs: {
 | |
|         expected: "boolean",
 | |
|         got: req.body.hasOwnProperty("addsongs")
 | |
|           ? typeof req.body.addsongs
 | |
|           : undefined
 | |
|       },
 | |
|       longsongs: {
 | |
|         expected: "boolean",
 | |
|         got: req.body.hasOwnProperty("longsongs")
 | |
|           ? typeof req.body.longsongs
 | |
|           : undefined
 | |
|       },
 | |
|       frontpage: {
 | |
|         expected: "boolean",
 | |
|         got: req.body.hasOwnProperty("frontpage")
 | |
|           ? typeof req.body.frontpage
 | |
|           : undefined
 | |
|       },
 | |
|       skip: {
 | |
|         expected: "boolean",
 | |
|         got: req.body.hasOwnProperty("skip") ? typeof req.body.skip : undefined
 | |
|       },
 | |
|       shuffle: {
 | |
|         expected: "boolean",
 | |
|         got: req.body.hasOwnProperty("shuffle")
 | |
|           ? typeof req.body.shuffle
 | |
|           : undefined
 | |
|       },
 | |
|       userpass_changed: {
 | |
|         expected: "boolean",
 | |
|         got: req.body.hasOwnProperty("userpass_changed")
 | |
|           ? typeof req.body.userpass_changed
 | |
|           : undefined
 | |
|       }
 | |
|     };
 | |
|     var to_send = error.formatting;
 | |
|     to_send.results = [result];
 | |
|     res.status(400).send(to_send);
 | |
|     return;
 | |
|   }
 | |
|   var cookie = req.cookies._uI;
 | |
|   Functions.getSessionAdminUser(cookie, channel_name, function(_u, _a) {
 | |
|     if (req.body.adminpass == "") {
 | |
|       adminpass = Functions.hash_pass(_a);
 | |
|     }
 | |
|     if (req.body.userpass == "") {
 | |
|       userpass = _u;
 | |
|     }
 | |
|     token_db
 | |
|       .collection("api_token")
 | |
|       .find({ token: token }, function(err, token_docs) {
 | |
|         var authorized = false;
 | |
|         var origin;
 | |
|         try {
 | |
|           origin = req.headers.referer.split("/")[2];
 | |
|         } catch (e) {
 | |
|           origin = "";
 | |
|         }
 | |
|         if (
 | |
|           token_docs.length == 1 &&
 | |
|           token_docs[0].token == token &&
 | |
|           (token_docs[0].origin == "*" ||
 | |
|             origin.indexOf(token_docs[0].origin) > -1)
 | |
|         ) {
 | |
|           authorized = true;
 | |
|         }
 | |
|         checkOveruseApiToken(authorized, token_docs, res, function() {
 | |
|           checkTimeout(guid, res, authorized, "CONFIG", function() {
 | |
|             if (token != "" && !authorized) {
 | |
|               //updateTimeout(guid, res, authorized, "CONFIG", function(err, docs) {
 | |
|               res.status(400).send(error.wrong_token);
 | |
|               return;
 | |
|               //});
 | |
|             } else {
 | |
|               validateLogin(
 | |
|                 adminpass,
 | |
|                 userpass,
 | |
|                 channel_name,
 | |
|                 "config",
 | |
|                 res,
 | |
|                 function(exists, conf) {
 | |
|                   if (!exists && conf.length == 0) {
 | |
|                     res.status(404).send(error.not_found.list);
 | |
|                     return;
 | |
|                   }
 | |
| 
 | |
|                   if (
 | |
|                     (!userpass_changed && frontpage) ||
 | |
|                     (userpass_changed && userpass == "")
 | |
|                   ) {
 | |
|                     userpass = "";
 | |
|                   } else if (userpass_changed && userpass != "") {
 | |
|                     frontpage = false;
 | |
|                   }
 | |
|                   var description = "";
 | |
| 
 | |
|                   var obj = {
 | |
|                     addsongs: addsongs,
 | |
|                     allvideos: allvideos,
 | |
|                     frontpage: frontpage,
 | |
|                     skip: skipping,
 | |
|                     vote: voting,
 | |
|                     removeplay: removeplay,
 | |
|                     shuffle: shuffling,
 | |
|                     longsongs: longsongs,
 | |
|                     adminpass: adminpass,
 | |
|                     desc: description
 | |
|                   };
 | |
|                   if (userpass_changed) {
 | |
|                     obj["userpass"] = userpass;
 | |
|                   } else if (frontpage) {
 | |
|                     obj["userpass"] = "";
 | |
|                   }
 | |
|                   db.collection(channel_name + "_settings").update(
 | |
|                     { views: { $exists: true } },
 | |
|                     {
 | |
|                       $set: obj
 | |
|                     },
 | |
|                     function(err, docs) {
 | |
|                       if (obj.adminpass !== "") obj.adminpass = true;
 | |
|                       if (obj.hasOwnProperty("userpass") && obj.userpass != "")
 | |
|                         obj.userpass = true;
 | |
|                       else obj.userpass = false;
 | |
|                       io.to(channel_name).emit("conf", [obj]);
 | |
| 
 | |
|                       db.collection("frontpage_lists").update(
 | |
|                         { _id: channel_name },
 | |
|                         {
 | |
|                           $set: {
 | |
|                             frontpage: frontpage,
 | |
|                             accessed: Functions.get_time()
 | |
|                           }
 | |
|                         },
 | |
|                         { upsert: true },
 | |
|                         function(err, docs) {
 | |
|                           if (authorized) {
 | |
|                             incrementToken(token);
 | |
|                           }
 | |
|                           //updateTimeout(guid, res, authorized, "CONFIG", function(err, docs) {
 | |
|                           var to_return = error.no_error;
 | |
|                           to_return.results = [obj];
 | |
|                           res.status(200).send(to_return);
 | |
|                           return;
 | |
|                           //});
 | |
|                         }
 | |
|                       );
 | |
|                     }
 | |
|                   );
 | |
|                 }
 | |
|               );
 | |
|             }
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|   });
 | |
| });
 | |
| 
 | |
| router.route("/api/list/:channel_name/:video_id").put(function(req, res) {
 | |
|   res.header("Access-Control-Allow-Origin", "*");
 | |
|   res.header(
 | |
|     "Access-Control-Allow-Headers",
 | |
|     "Origin, X-Requested-With, Content-Type, Accept"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   try {
 | |
|     if (
 | |
|       !req.body.hasOwnProperty("adminpass") ||
 | |
|       !req.body.hasOwnProperty("userpass") ||
 | |
|       !req.params.hasOwnProperty("channel_name") ||
 | |
|       !req.params.hasOwnProperty("video_id")
 | |
|     ) {
 | |
|       throw "Wrong format";
 | |
|     }
 | |
|     var token = "";
 | |
|     if (req.body.hasOwnProperty("token")) {
 | |
|       token = req.body.token;
 | |
|     }
 | |
|     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 =
 | |
|       req.body.userpass == ""
 | |
|         ? ""
 | |
|         : crypto
 | |
|             .createHash("sha256")
 | |
|             .update(req.body.userpass, "utf8")
 | |
|             .digest("base64");
 | |
|     var userpass = req.body.userpass;
 | |
|     var channel_name = cleanChannelName(req.params.channel_name);
 | |
|     var video_id = req.params.video_id;
 | |
|     if (typeof userpass != "string" || typeof adminpass != "string") {
 | |
|       throw "Wrong format";
 | |
|     }
 | |
|   } catch (e) {
 | |
|     var result = {
 | |
|       adminpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("adminpass")
 | |
|           ? typeof req.body.adminpass
 | |
|           : undefined
 | |
|       },
 | |
|       userpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("userpass")
 | |
|           ? typeof req.body.userpass
 | |
|           : undefined
 | |
|       }
 | |
|     };
 | |
|     var to_send = error.formatting;
 | |
|     to_send.results = [result];
 | |
|     res.status(400).send(to_send);
 | |
|     return;
 | |
|   }
 | |
|   var cookie = req.cookies._uI;
 | |
|   Functions.getSessionAdminUser(cookie, channel_name, function(_u, _a) {
 | |
|     if (req.body.adminpass == "") {
 | |
|       adminpass = Functions.hash_pass(_a);
 | |
|     }
 | |
|     if (req.body.userpass == "") {
 | |
|       userpass = _u;
 | |
|     }
 | |
|     token_db
 | |
|       .collection("api_token")
 | |
|       .find({ token: token }, function(err, token_docs) {
 | |
|         var authorized = false;
 | |
|         var origin;
 | |
|         try {
 | |
|           origin = req.headers.referer.split("/")[2];
 | |
|         } catch (e) {
 | |
|           origin = "";
 | |
|         }
 | |
|         if (
 | |
|           token_docs.length == 1 &&
 | |
|           token_docs[0].token == token &&
 | |
|           (token_docs[0].origin == "*" ||
 | |
|             origin.indexOf(token_docs[0].origin) > -1)
 | |
|         ) {
 | |
|           authorized = true;
 | |
|         }
 | |
|         checkOveruseApiToken(authorized, token_docs, res, function() {
 | |
|           checkTimeout(guid, res, authorized, "PUT", function() {
 | |
|             if (token != "" && !authorized) {
 | |
|               //updateTimeout(guid, res, authorized, "PUT", function(err, docs) {
 | |
|               res.status(400).send(error.wrong_token);
 | |
|               return;
 | |
|               //});
 | |
|             } else {
 | |
|               validateLogin(
 | |
|                 adminpass,
 | |
|                 userpass,
 | |
|                 channel_name,
 | |
|                 "vote",
 | |
|                 res,
 | |
|                 function(exists) {
 | |
|                   if (!exists) {
 | |
|                     res.status(404).send(error.not_found.list);
 | |
|                     return;
 | |
|                   }
 | |
|                   db.collection(channel_name).find(
 | |
|                     { id: video_id, now_playing: false },
 | |
|                     function(err, song) {
 | |
|                       if (
 | |
|                         song.length == 0 ||
 | |
|                         (song.hasOwnProperty("type") &&
 | |
|                           song.type == "suggested")
 | |
|                       ) {
 | |
|                         res.status(404).send(error.not_found.local);
 | |
|                         return;
 | |
|                       } else if (song[0].guids.indexOf(guid) > -1) {
 | |
|                         res.status(409).send(error.conflicting);
 | |
|                         return;
 | |
|                       } else {
 | |
|                         song[0].votes += 1;
 | |
|                         song[0].guids.push(guid);
 | |
|                         db.collection(channel_name).update(
 | |
|                           { id: video_id },
 | |
|                           {
 | |
|                             $inc: { votes: 1 },
 | |
|                             $set: {
 | |
|                               added: Functions.get_time(),
 | |
|                               type: "video"
 | |
|                             },
 | |
|                             $push: { guids: guid }
 | |
|                           },
 | |
|                           function(err, success) {
 | |
|                             if (authorized) {
 | |
|                               incrementToken(token);
 | |
|                             }
 | |
|                             io.to(channel_name).emit("channel", {
 | |
|                               type: "vote",
 | |
|                               value: video_id,
 | |
|                               time: Functions.get_time()
 | |
|                             });
 | |
|                             List.getNextSong(
 | |
|                               channel_name,
 | |
|                               undefined,
 | |
|                               function() {
 | |
|                                 //updateTimeout(guid, res, authorized, "PUT", function(err, docs) {
 | |
|                                 var to_return = error.no_error;
 | |
|                                 to_return.results = song;
 | |
|                                 res.status(200).send(to_return);
 | |
|                                 return;
 | |
|                                 //});
 | |
|                               }
 | |
|                             );
 | |
|                           }
 | |
|                         );
 | |
|                       }
 | |
|                     }
 | |
|                   );
 | |
|                 }
 | |
|               );
 | |
|             }
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|   });
 | |
| });
 | |
| 
 | |
| 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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   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 channel_name = cleanChannelName(req.params.channel_name);
 | |
|     var userpass;
 | |
|     if (req.body.hasOwnProperty("userpass")) {
 | |
|       req.body.userpass =
 | |
|         req.body.userpass == ""
 | |
|           ? ""
 | |
|           : crypto
 | |
|               .createHash("sha256")
 | |
|               .update(req.body.userpass, "utf8")
 | |
|               .digest("base64");
 | |
|       userpass = req.body.userpass;
 | |
|     } else {
 | |
|       userpass = "";
 | |
|     }
 | |
|     var token = "";
 | |
|     if (req.body.hasOwnProperty("token")) {
 | |
|       token = req.body.token;
 | |
|     }
 | |
|   } catch (e) {
 | |
|     var result = {
 | |
|       userpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("userpass")
 | |
|           ? typeof req.body.userpass
 | |
|           : undefined
 | |
|       }
 | |
|     };
 | |
|     var to_send = error.formatting;
 | |
|     to_send.results = [result];
 | |
|     res.status(400).send(to_send);
 | |
|     return;
 | |
|   }
 | |
|   var cookie = req.cookies._uI;
 | |
|   Functions.getSessionAdminUser(cookie, channel_name, function(_u, _a) {
 | |
|     if (req.body.userpass == "") {
 | |
|       //userpass = Functions.hash_pass(Functions.hash_pass(Functions.decrypt_string(_u)))
 | |
|       userpass = _u;
 | |
|     }
 | |
|     token_db
 | |
|       .collection("api_token")
 | |
|       .find({ token: token }, function(err, token_docs) {
 | |
|         var authorized = false;
 | |
|         var origin;
 | |
|         try {
 | |
|           origin = req.headers.referer.split("/")[2];
 | |
|         } catch (e) {
 | |
|           origin = "";
 | |
|         }
 | |
|         if (
 | |
|           token_docs.length == 1 &&
 | |
|           token_docs[0].token == token &&
 | |
|           (token_docs[0].origin == "*" ||
 | |
|             origin.indexOf(token_docs[0].origin) > -1)
 | |
|         ) {
 | |
|           authorized = true;
 | |
|         }
 | |
|         checkOveruseApiToken(authorized, token_docs, res, function() {
 | |
|           checkTimeout(guid, res, authorized, "POST", function() {
 | |
|             if (token != "" && !authorized) {
 | |
|               //updateTimeout(guid, res, authorized, "POST", function(err, docs) {
 | |
|               res.status(400).send(error.wrong_token);
 | |
|               return;
 | |
|               //});
 | |
|             } else {
 | |
|               db.collection(channel_name).find(
 | |
|                 { now_playing: true },
 | |
|                 projects.toShowChannel,
 | |
|                 function(err, list) {
 | |
|                   if (list.length > 0) {
 | |
|                     db.collection(channel_name + "_settings").find(
 | |
|                       { id: "config" },
 | |
|                       function(err, conf) {
 | |
|                         if (authorized) {
 | |
|                           incrementToken(token);
 | |
|                         }
 | |
|                         if (conf.length == 0) {
 | |
|                           res.status(404).send(error.not_found.list);
 | |
|                           return;
 | |
|                         } else if (
 | |
|                           conf[0].userpass != userpass &&
 | |
|                           conf[0].userpass != "" &&
 | |
|                           conf[0].userpass != undefined
 | |
|                         ) {
 | |
|                           res.status(403).send(error.not_authenticated);
 | |
|                           return;
 | |
|                         }
 | |
|                         //updateTimeout(guid, res, authorized, "POST", function(err, docs) {
 | |
|                         var to_return = error.no_error;
 | |
|                         if (list[0].source == undefined) {
 | |
|                           list[0].source = "youtube";
 | |
|                         }
 | |
|                         if (list[0].thumbnail == undefined) {
 | |
|                           list[0].thumbnail =
 | |
|                             "https://img.youtube.com/vi/" +
 | |
|                             list[0].id +
 | |
|                             "/mqdefault.jpg";
 | |
|                         }
 | |
|                         to_return.results = list;
 | |
|                         res.status(200).send(to_return);
 | |
|                         return;
 | |
|                         //});
 | |
|                       }
 | |
|                     );
 | |
|                   } else {
 | |
|                     res.status(404).send(error.not_found.list);
 | |
|                     return;
 | |
|                   }
 | |
|                 }
 | |
|               );
 | |
|             }
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|   });
 | |
| });
 | |
| 
 | |
| router.route("/api/search/: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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   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 channel_name = cleanChannelName(req.params.channel_name);
 | |
|     var userpass;
 | |
|     if (req.body.hasOwnProperty("userpass")) {
 | |
|       req.body.userpass =
 | |
|         req.body.userpass == ""
 | |
|           ? ""
 | |
|           : crypto
 | |
|               .createHash("sha256")
 | |
|               .update(req.body.userpass, "utf8")
 | |
|               .digest("base64");
 | |
|       userpass = req.body.userpass;
 | |
|     } else {
 | |
|       userpass = "";
 | |
|     }
 | |
|     var page = 1;
 | |
|     if (req.body.hasOwnProperty("page") && req.body.page > 0) {
 | |
|       page = req.body.page;
 | |
|     }
 | |
|     var searchQuery = "";
 | |
|     var searchByCategory = true;
 | |
|     if (req.body.hasOwnProperty("type")) {
 | |
|       searchByCategory = req.body.type == "category";
 | |
|     }
 | |
|     if (req.body.searchQuery == undefined || req.body.searchQuery == "") {
 | |
|       var to_send = error.formatting;
 | |
|       to_send.results = [result];
 | |
|       res.status(400).send(to_send);
 | |
|       return;
 | |
|     }
 | |
|     searchQuery = req.body.searchQuery.toLowerCase();
 | |
|     var token = "";
 | |
|     if (req.body.hasOwnProperty("token")) {
 | |
|       token = req.body.token;
 | |
|     }
 | |
|   } catch (e) {
 | |
|     var result = {
 | |
|       userpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("userpass")
 | |
|           ? typeof req.body.userpass
 | |
|           : undefined
 | |
|       }
 | |
|     };
 | |
|     var to_send = error.formatting;
 | |
|     to_send.results = [result];
 | |
|     res.status(400).send(to_send);
 | |
|     return;
 | |
|   }
 | |
|   var cookie = req.cookies._uI;
 | |
|   Functions.getSessionAdminUser(cookie, channel_name, function(_u, _a) {
 | |
|     if (req.body.userpass == "") {
 | |
|       //userpass = Functions.hash_pass(Functions.hash_pass(Functions.decrypt_string(_u)))
 | |
|       userpass = _u;
 | |
|     }
 | |
|     token_db
 | |
|       .collection("api_token")
 | |
|       .find({ token: token }, function(err, token_docs) {
 | |
|         var authorized = false;
 | |
|         var origin;
 | |
|         try {
 | |
|           origin = req.headers.referer.split("/")[2];
 | |
|         } catch (e) {
 | |
|           origin = "";
 | |
|         }
 | |
|         if (
 | |
|           token_docs.length == 1 &&
 | |
|           token_docs[0].token == token &&
 | |
|           (token_docs[0].origin == "*" ||
 | |
|             origin.indexOf(token_docs[0].origin) > -1)
 | |
|         ) {
 | |
|           authorized = true;
 | |
|         }
 | |
|         checkOveruseApiToken(authorized, token_docs, res, function() {
 | |
|           checkTimeout(guid, res, authorized, "POST", function() {
 | |
|             db.collection(channel_name + "_settings").find(
 | |
|               { id: "config" },
 | |
|               function(err, conf) {
 | |
|                 if (authorized) {
 | |
|                   incrementToken(token);
 | |
|                 }
 | |
|                 if (conf.length == 0) {
 | |
|                   res.status(404).send(error.not_found.list);
 | |
|                   return;
 | |
|                 } else if (
 | |
|                   conf[0].userpass != userpass &&
 | |
|                   conf[0].userpass != "" &&
 | |
|                   conf[0].userpass != undefined
 | |
|                 ) {
 | |
|                   res.status(403).send(error.not_authenticated);
 | |
|                   return;
 | |
|                 }
 | |
| 
 | |
|                 var querySubObject = {
 | |
|                   $regex: ".*" + searchQuery + ".*"
 | |
|                 };
 | |
|                 var queryObject = {};
 | |
|                 if (searchByCategory) {
 | |
|                   queryObject.tags = querySubObject;
 | |
|                 } else {
 | |
|                   queryObject.title = querySubObject;
 | |
|                   queryObject.title.$regex = searchQuery;
 | |
|                   queryObject.title.$options = "i";
 | |
|                 }
 | |
|                 var query = db.collection(channel_name).find(queryObject);
 | |
|                 paginate(query, { limit: 30, page: page }, function(
 | |
|                   err,
 | |
|                   result
 | |
|                 ) {
 | |
|                   if (result.items.length == 0) {
 | |
|                     res.status(404).send(error.not_found.local);
 | |
|                     return;
 | |
|                   }
 | |
|                   var to_return = error.no_error;
 | |
|                   to_return.results = {};
 | |
|                   if (result.hasNext) {
 | |
|                     to_return.results.next = result.page + 1;
 | |
|                   }
 | |
|                   if (result.hasPrevious) {
 | |
|                     to_return.results.prev = result.page - 1;
 | |
|                   }
 | |
|                   to_return.results.search_results = result.items;
 | |
| 
 | |
|                   res.status(200).send(to_return);
 | |
|                 });
 | |
|               }
 | |
|             );
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|   });
 | |
| });
 | |
| 
 | |
| 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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   var fetch_only = false;
 | |
|   if (req.body.hasOwnProperty("fetch_song")) {
 | |
|     fetch_only = true;
 | |
|   }
 | |
|   var token = "";
 | |
|   if (req.body.hasOwnProperty("token")) {
 | |
|     token = req.body.token;
 | |
|   }
 | |
|   try {
 | |
|     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("source"))
 | |
|     ) {
 | |
|       throw "Wrong format";
 | |
|     }
 | |
| 
 | |
|     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 userpass;
 | |
|     if (req.body.hasOwnProperty("userpass")) {
 | |
|       req.body.userpass =
 | |
|         req.body.userpass == ""
 | |
|           ? ""
 | |
|           : crypto
 | |
|               .createHash("sha256")
 | |
|               .update(req.body.userpass, "utf8")
 | |
|               .digest("base64");
 | |
|       userpass = req.body.userpass;
 | |
|     } else {
 | |
|       userpass = "";
 | |
|     }
 | |
|     var channel_name = cleanChannelName(req.params.channel_name);
 | |
|     var video_id = req.params.video_id;
 | |
|     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);
 | |
|       var tags = [];
 | |
|       if (req.body.tags != undefined) tags = req.body.tags.split(",");
 | |
|       var source = req.body.source;
 | |
|       if (source == "soundcloud" && !req.body.hasOwnProperty("thumbnail")) {
 | |
|         throw "Wrong format";
 | |
|       }
 | |
|       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" ||
 | |
|         isNaN(duration) ||
 | |
|         isNaN(start_time) ||
 | |
|         isNaN(end_time)
 | |
|       ) {
 | |
|         throw "Wrong format";
 | |
|       }
 | |
|     }
 | |
|   } catch (e) {
 | |
|     var result = {
 | |
|       adminpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("adminpass")
 | |
|           ? typeof req.body.adminpass
 | |
|           : undefined
 | |
|       },
 | |
|       userpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("userpass")
 | |
|           ? typeof req.body.userpass
 | |
|           : undefined
 | |
|       },
 | |
|       title: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("title")
 | |
|           ? typeof req.body.title
 | |
|           : undefined
 | |
|       },
 | |
|       start_time: {
 | |
|         expected: "number or string that can be cast to int",
 | |
|         got: !req.body.hasOwnProperty("start_time")
 | |
|           ? undefined
 | |
|           : isNaN(req.body.start_time)
 | |
|           ? "uncastable string"
 | |
|           : typeof req.body.start_time
 | |
|       },
 | |
|       end_time: {
 | |
|         expected: "number or string that can be cast to int",
 | |
|         got: !req.body.hasOwnProperty("end_time")
 | |
|           ? undefined
 | |
|           : isNaN(req.body.end_time)
 | |
|           ? "uncastable string"
 | |
|           : typeof req.body.end_time
 | |
|       },
 | |
|       duration: {
 | |
|         expected: "number or string that can be cast to int",
 | |
|         got: !req.body.hasOwnProperty("duration")
 | |
|           ? undefined
 | |
|           : isNaN(req.body.duration)
 | |
|           ? "uncastable string"
 | |
|           : typeof req.body.duration
 | |
|       }
 | |
|     };
 | |
|     var to_send = error.formatting;
 | |
|     to_send.results = [result];
 | |
|     res.status(400).send(to_send);
 | |
|     return;
 | |
|   }
 | |
|   var cookie = req.cookies._uI;
 | |
|   Functions.getSessionAdminUser(cookie, channel_name, function(_u, _a) {
 | |
|     if (req.body.adminpass == "") {
 | |
|       adminpass = Functions.hash_pass(_a);
 | |
|     }
 | |
|     if (req.body.userpass == "") {
 | |
|       userpass = _u;
 | |
|     }
 | |
|     token_db
 | |
|       .collection("api_token")
 | |
|       .find({ token: token }, function(err, token_docs) {
 | |
|         var authorized = false;
 | |
|         var origin;
 | |
|         try {
 | |
|           origin = req.headers.referer.split("/")[2];
 | |
|         } catch (e) {
 | |
|           origin = "";
 | |
|         }
 | |
|         if (
 | |
|           token_docs.length == 1 &&
 | |
|           token_docs[0].token == token &&
 | |
|           (token_docs[0].origin == "*" ||
 | |
|             origin.indexOf(token_docs[0].origin) > -1)
 | |
|         ) {
 | |
|           authorized = true;
 | |
|         }
 | |
|         checkOveruseApiToken(authorized, token_docs, res, function() {
 | |
|           checkTimeout(guid, res, authorized, "POST", function() {
 | |
|             if (token != "" && !authorized) {
 | |
|               //updateTimeout(guid, res, authorized, "POST", function(err, docs) {
 | |
|               res.status(400).send(error.wrong_token);
 | |
|               return;
 | |
|               //});
 | |
|             } else {
 | |
|               var type = fetch_only ? "fetch_song" : "add";
 | |
|               validateLogin(
 | |
|                 adminpass,
 | |
|                 userpass,
 | |
|                 channel_name,
 | |
|                 type,
 | |
|                 res,
 | |
|                 function(exists, conf, authenticated) {
 | |
|                   db.collection(channel_name).find({ id: video_id }, function(
 | |
|                     err,
 | |
|                     result
 | |
|                   ) {
 | |
|                     if (result.length == 0 || result[0].type == "suggested") {
 | |
|                       var song_type = authenticated ? "video" : "suggested";
 | |
|                       if (fetch_only && result.length == 0) {
 | |
|                         res.status(404).send(error.not_found.local);
 | |
|                         return;
 | |
|                       }
 | |
|                       db.collection(channel_name).find(
 | |
|                         { now_playing: true },
 | |
|                         function(err, now_playing) {
 | |
|                           var set_np = false;
 | |
|                           if (now_playing.length == 0 && authenticated) {
 | |
|                             set_np = true;
 | |
|                           }
 | |
|                           var new_song = {
 | |
|                             tags: tags,
 | |
|                             added: Functions.get_time(),
 | |
|                             guids: [guid],
 | |
|                             id: video_id,
 | |
|                             now_playing: set_np,
 | |
|                             title: title,
 | |
|                             votes: 1,
 | |
|                             duration: duration,
 | |
|                             start: parseInt(start_time),
 | |
|                             end: parseInt(end_time),
 | |
|                             type: song_type,
 | |
|                             source: source
 | |
|                           };
 | |
|                           var runFunction = Search.get_correct_info;
 | |
|                           if (source == "soundcloud") {
 | |
|                             if (
 | |
|                               req.body.thumbnail.indexOf(
 | |
|                                 "https://i1.sndcdn.com"
 | |
|                               ) > -1 ||
 | |
|                               req.body.thumbnail.indexOf(
 | |
|                                 "https://w1.sndcdn.com"
 | |
|                               ) > -1
 | |
|                             ) {
 | |
|                               new_song.thumbnail = req.body.thumbnail;
 | |
|                             } else {
 | |
|                               new_song.thumbnail =
 | |
|                                 "https://img.youtube.com/vi/404_notfound/mqdefault.jpg";
 | |
|                             }
 | |
|                             runFunction = function(
 | |
|                               new_song,
 | |
|                               foo_2,
 | |
|                               foo_3,
 | |
|                               callback
 | |
|                             ) {
 | |
|                               callback(new_song, true);
 | |
|                             };
 | |
|                           } else if (source == "youtube")
 | |
|                             new_song.thumbnail =
 | |
|                               "https://img.youtube.com/vi/" +
 | |
|                               new_song.id +
 | |
|                               "/mqdefault.jpg";
 | |
|                           runFunction(new_song, channel_name, false, function(
 | |
|                             element,
 | |
|                             found
 | |
|                           ) {
 | |
|                             if (!found) {
 | |
|                               res.status(404).send(error.not_found.youtube);
 | |
|                               return;
 | |
|                             }
 | |
|                             new_song = element;
 | |
|                             db.collection("frontpage_lists").find(
 | |
|                               { _id: channel_name },
 | |
|                               function(err, count) {
 | |
|                                 var create_frontpage_lists = false;
 | |
|                                 if (count.length == 0) {
 | |
|                                   create_frontpage_lists = true;
 | |
|                                 }
 | |
|                                 if (!exists) {
 | |
|                                   var configs = {
 | |
|                                     addsongs: false,
 | |
|                                     adminpass: "",
 | |
|                                     allvideos: true,
 | |
|                                     frontpage: true,
 | |
|                                     longsongs: false,
 | |
|                                     removeplay: false,
 | |
|                                     shuffle: true,
 | |
|                                     skip: false,
 | |
|                                     skips: [],
 | |
|                                     startTime: Functions.get_time(),
 | |
|                                     views: [],
 | |
|                                     vote: false,
 | |
|                                     desc: ""
 | |
|                                   };
 | |
|                                   db.collection(
 | |
|                                     channel_name + "_settings"
 | |
|                                   ).insert(configs, function(err, docs) {
 | |
|                                     io.to(channel_name).emit("conf", configs);
 | |
|                                   });
 | |
|                                 }
 | |
|                                 db.collection(channel_name).update(
 | |
|                                   { id: new_song.id },
 | |
|                                   new_song,
 | |
|                                   { upsert: true },
 | |
|                                   function(err, success) {
 | |
|                                     if (authorized) {
 | |
|                                       incrementToken(token);
 | |
|                                     }
 | |
|                                     if (create_frontpage_lists) {
 | |
|                                       db.collection("frontpage_lists").update(
 | |
|                                         {
 | |
|                                           _id: channel_name,
 | |
|                                           count: authenticated ? 1 : 0,
 | |
|                                           frontpage: true,
 | |
|                                           accessed: Functions.get_time(),
 | |
|                                           viewers: 1
 | |
|                                         },
 | |
|                                         { upsert: true },
 | |
|                                         function(err, docs) {
 | |
|                                           if (authenticated) {
 | |
|                                             io.to(channel_name).emit(
 | |
|                                               "channel",
 | |
|                                               { type: "added", value: new_song }
 | |
|                                             );
 | |
|                                           } else {
 | |
|                                             io.to(channel_name).emit(
 | |
|                                               "suggested",
 | |
|                                               new_song
 | |
|                                             );
 | |
|                                           }
 | |
|                                           postEnd(
 | |
|                                             channel_name,
 | |
|                                             configs,
 | |
|                                             new_song,
 | |
|                                             guid,
 | |
|                                             res,
 | |
|                                             authenticated,
 | |
|                                             authorized
 | |
|                                           );
 | |
|                                         }
 | |
|                                       );
 | |
|                                     } else if (set_np) {
 | |
|                                       var thumbnail =
 | |
|                                         req.body.thumbnail != undefined
 | |
|                                           ? req.body.thumbnail
 | |
|                                           : undefined;
 | |
|                                       Frontpage.update_frontpage(
 | |
|                                         channel_name,
 | |
|                                         video_id,
 | |
|                                         title,
 | |
|                                         thumbnail,
 | |
|                                         source,
 | |
|                                         function() {
 | |
|                                           io.to(channel_name).emit("np", {
 | |
|                                             np: [new_song],
 | |
|                                             conf: [conf]
 | |
|                                           });
 | |
|                                           postEnd(
 | |
|                                             channel_name,
 | |
|                                             configs,
 | |
|                                             new_song,
 | |
|                                             guid,
 | |
|                                             res,
 | |
|                                             authenticated,
 | |
|                                             authorized
 | |
|                                           );
 | |
|                                         }
 | |
|                                       );
 | |
|                                     } else {
 | |
|                                       db.collection("frontpage_lists").update(
 | |
|                                         { _id: channel_name },
 | |
|                                         {
 | |
|                                           $inc: { count: authenticated ? 1 : 0 }
 | |
|                                         },
 | |
|                                         function(err, docs) {
 | |
|                                           if (authenticated) {
 | |
|                                             io.to(channel_name).emit(
 | |
|                                               "channel",
 | |
|                                               { type: "added", value: new_song }
 | |
|                                             );
 | |
|                                           } else {
 | |
|                                             io.to(channel_name).emit(
 | |
|                                               "suggested",
 | |
|                                               new_song
 | |
|                                             );
 | |
|                                           }
 | |
|                                           postEnd(
 | |
|                                             channel_name,
 | |
|                                             configs,
 | |
|                                             new_song,
 | |
|                                             guid,
 | |
|                                             res,
 | |
|                                             authenticated,
 | |
|                                             authorized
 | |
|                                           );
 | |
|                                         }
 | |
|                                       );
 | |
|                                     }
 | |
|                                   }
 | |
|                                 );
 | |
|                               }
 | |
|                             );
 | |
|                           });
 | |
|                         }
 | |
|                       );
 | |
|                     } else if (fetch_only) {
 | |
|                       var to_return = error.no_error;
 | |
|                       to_return.results = result;
 | |
|                       res.status(200).send(to_return);
 | |
|                       return;
 | |
|                     } else {
 | |
|                       res.status(409).send(error.conflicting);
 | |
|                       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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   var channel_name = cleanChannelName(req.params.channel_name);
 | |
|   db.collection(channel_name).aggregate(
 | |
|     [
 | |
|       {
 | |
|         $match: {
 | |
|           type: {
 | |
|             $ne: "suggested"
 | |
|           }
 | |
|         }
 | |
|       },
 | |
|       {
 | |
|         $project: projects.project_object
 | |
|       },
 | |
|       { $sort: { now_playing: -1, votes: -1, added: 1, title: 1 } }
 | |
|     ],
 | |
|     function(err, docs) {
 | |
|       var ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress;
 | |
|       var guid = Functions.hash_pass(
 | |
|         req.get("User-Agent") + ip + req.headers["accept-language"]
 | |
|       );
 | |
|       //db.collection(channel_name).find({views: {$exists: false}}, projects.toShowChannel, function(err, docs) {
 | |
|       checkTimeout(guid, res, false, "GET", function() {
 | |
|         if (docs.length > 0) {
 | |
|           db.collection(channel_name + "_settings").find(
 | |
|             { id: "config" },
 | |
|             function(err, conf) {
 | |
|               if (conf.length == 0) {
 | |
|                 res.status(404).send(error.not_found.list);
 | |
|                 return;
 | |
|               } else if (
 | |
|                 conf[0].userpass != "" &&
 | |
|                 conf[0].userpass != undefined
 | |
|               ) {
 | |
|                 res.status(403).send(error.not_authenticated);
 | |
|                 return;
 | |
|               }
 | |
|               var to_return = error.no_error;
 | |
|               to_return.results = docs;
 | |
|               res.status(200).send(to_return);
 | |
|             }
 | |
|           );
 | |
|         } else {
 | |
|           res.status(404).send(error.not_found.list);
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|   );
 | |
| });
 | |
| 
 | |
| 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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   var ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress;
 | |
|   var guid = Functions.hash_pass(
 | |
|     req.get("User-Agent") + ip + req.headers["accept-language"]
 | |
|   );
 | |
| 
 | |
|   checkTimeout(guid, res, false, "GET", function() {
 | |
|     var channel_name = cleanChannelName(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,
 | |
|       projects.toShowChannel,
 | |
|       function(err, docs) {
 | |
|         db.collection(channel_name + "_settings").find(
 | |
|           { id: "config" },
 | |
|           function(err, conf) {
 | |
|             if (conf.length == 0) {
 | |
|               res.status(404).send(error.not_found.list);
 | |
|               return;
 | |
|             } else if (
 | |
|               conf[0].userpass != "" &&
 | |
|               conf[0].userpass != undefined
 | |
|             ) {
 | |
|               res.status(403).send(error.not_authenticated);
 | |
|               return;
 | |
|             }
 | |
|             if (docs.length == 0) {
 | |
|               res.status(404).send(error.not_found.local);
 | |
|               return;
 | |
|             }
 | |
|             var to_return = error.no_error;
 | |
|             if (docs[0].source == undefined) {
 | |
|               docs[0].source = "youtube";
 | |
|             }
 | |
|             if (docs[0].thumbnail == undefined) {
 | |
|               docs[0].thumbnail =
 | |
|                 "https://img.youtube.com/vi/" + docs[0].id + "/mqdefault.jpg";
 | |
|             }
 | |
|             to_return.results = docs;
 | |
|             res.status(200).send(to_return);
 | |
|             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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   var ip = req.headers["x-forwarded-for"] || req.connection.remoteAddress;
 | |
|   var guid = Functions.hash_pass(
 | |
|     req.get("User-Agent") + ip + req.headers["accept-language"]
 | |
|   );
 | |
| 
 | |
|   checkTimeout(guid, res, false, "GET", function() {
 | |
|     var channel_name = cleanChannelName(req.params.channel_name);
 | |
|     db.collection(channel_name + "_settings").aggregate(
 | |
|       [
 | |
|         {
 | |
|           $match: {
 | |
|             id: "config"
 | |
|           }
 | |
|         },
 | |
|         {
 | |
|           $project: projects.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;
 | |
|           } else {
 | |
|             conf.adminpass = false;
 | |
|           }
 | |
|           if (conf.userpass != "" && conf.userpass != undefined) {
 | |
|             conf.userpass = true;
 | |
|           } else {
 | |
|             conf.userpass = false;
 | |
|           }
 | |
|           var to_return = error.no_error;
 | |
|           to_return.results = [conf];
 | |
|           res.status(200).send(to_return);
 | |
|         } else if (
 | |
|           docs.length > 0 &&
 | |
|           docs[0].userpass != "" &&
 | |
|           docs[0].userpass != undefined
 | |
|         ) {
 | |
|           res.status(403).send(error.not_authenticated);
 | |
|           return;
 | |
|         } else {
 | |
|           res.status(404).send(error.not_found.list);
 | |
|           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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
| 
 | |
|   try {
 | |
|     var token = "";
 | |
|     if (req.body.hasOwnProperty("token")) {
 | |
|       token = req.body.token;
 | |
|     }
 | |
|     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 = cleanChannelName(req.params.channel_name);
 | |
|     var userpass;
 | |
|     if (req.body.hasOwnProperty("userpass")) {
 | |
|       req.body.userpass =
 | |
|         req.body.userpass == ""
 | |
|           ? ""
 | |
|           : crypto
 | |
|               .createHash("sha256")
 | |
|               .update(req.body.userpass, "utf8")
 | |
|               .digest("base64");
 | |
|       userpass = req.body.userpass;
 | |
|     } else {
 | |
|       userpass = "";
 | |
|     }
 | |
|   } catch (e) {
 | |
|     var result = {
 | |
|       userpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("userpass")
 | |
|           ? typeof req.body.userpass
 | |
|           : undefined
 | |
|       }
 | |
|     };
 | |
|     var to_send = error.formatting;
 | |
|     to_send.results = [result];
 | |
|     res.status(400).send(to_send);
 | |
|     return;
 | |
|   }
 | |
|   var cookie = req.cookies._uI;
 | |
|   Functions.getSessionAdminUser(cookie, channel_name, function(_u, _a) {
 | |
|     if (req.body.userpass == "") {
 | |
|       userpass = crypto
 | |
|         .createHash("sha256")
 | |
|         .update(Functions.decrypt_string("", _u), "utf8")
 | |
|         .digest("base64");
 | |
|     }
 | |
| 
 | |
|     token_db
 | |
|       .collection("api_token")
 | |
|       .find({ token: token }, function(err, token_docs) {
 | |
|         var authorized = false;
 | |
|         var origin;
 | |
|         try {
 | |
|           origin = req.headers.referer.split("/")[2];
 | |
|         } catch (e) {
 | |
|           origin = "";
 | |
|         }
 | |
|         if (
 | |
|           token_docs.length == 1 &&
 | |
|           token_docs[0].token == token &&
 | |
|           (token_docs[0].origin == "*" ||
 | |
|             origin.indexOf(token_docs[0].origin) > -1)
 | |
|         ) {
 | |
|           authorized = true;
 | |
|         }
 | |
|         checkOveruseApiToken(authorized, token_docs, res, function() {
 | |
|           checkTimeout(guid, res, authorized, "POST", function() {
 | |
|             if (token != "" && !authorized) {
 | |
|               //updateTimeout(guid, res, authorized, "DELETE", function(err, docs) {
 | |
|               res.status(400).send(error.wrong_token);
 | |
|               return;
 | |
|               //});
 | |
|             } else {
 | |
|               db.collection(channel_name + "_settings").aggregate(
 | |
|                 [
 | |
|                   {
 | |
|                     $match: {
 | |
|                       id: "config"
 | |
|                     }
 | |
|                   },
 | |
|                   {
 | |
|                     $project: projects.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;
 | |
|                     }
 | |
|                     if (authorized) {
 | |
|                       incrementToken(token);
 | |
|                     }
 | |
|                     //updateTimeout(guid, res, authorized, "POST", function(err, docs) {
 | |
|                     var to_return = error.no_error;
 | |
|                     to_return.results = [conf];
 | |
|                     res.status(200).send(to_return);
 | |
|                     //});
 | |
|                   } else if (docs.length > 0 && docs[0].userpass != userpass) {
 | |
|                     res.status(403).send(error.not_authenticated);
 | |
|                     return;
 | |
|                   } else {
 | |
|                     res.status(404).send(error.not_found.list);
 | |
|                     return;
 | |
|                   }
 | |
|                 }
 | |
|               );
 | |
|             }
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|   });
 | |
| });
 | |
| 
 | |
| function checkOveruseApiToken(authorized, token_docs, res, callback) {
 | |
|   if (!authorized || (authorized && token_docs[0].limit == 0)) {
 | |
|     callback();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   db.collection("timeout_api").find({ guid: token_docs[0].token }, function(
 | |
|     e,
 | |
|     doc
 | |
|   ) {
 | |
|     if (doc.length == 1) {
 | |
|       var this_doc = doc[0];
 | |
|       var date = new Date(this_doc.createdAt);
 | |
|       date.setSeconds(date.getSeconds() + 1);
 | |
|       var now = new Date();
 | |
|       var retry_in = (date.getTime() - now.getTime()) / 1000;
 | |
|       if (this_doc.used >= token_docs[0].limit && retry_in > 0) {
 | |
|         res.header({ "Retry-After": retry_in });
 | |
|         res.status(429).send(error.tooMany);
 | |
|         return;
 | |
|       } else {
 | |
|         var updateElement = {};
 | |
|         if (retry_in <= 0) {
 | |
|           updateElement["$set"] = { createdAt: new Date(), used: 1 };
 | |
|         } else {
 | |
|           updateElement["$inc"] = { used: 1 };
 | |
|         }
 | |
|         db.collection("timeout_api").update(
 | |
|           { guid: token_docs[0].token },
 | |
|           updateElement,
 | |
|           function(e, d) {
 | |
|             callback();
 | |
|           }
 | |
|         );
 | |
|       }
 | |
|     } else {
 | |
|       db.collection("timeout_api").update(
 | |
|         { guid: token_docs[0].token },
 | |
|         {
 | |
|           $set: {
 | |
|             guid: token_docs[0].token,
 | |
|             createdAt: new Date(),
 | |
|             type: "ALL"
 | |
|           },
 | |
|           $inc: { used: 1 }
 | |
|         },
 | |
|         { upsert: true },
 | |
|         function(e, d) {
 | |
|           callback();
 | |
|         }
 | |
|       );
 | |
|     }
 | |
|   });
 | |
| }
 | |
| 
 | |
| 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"
 | |
|   );
 | |
|   res.header({ "Content-Type": "application/json" });
 | |
|   try {
 | |
|     var token = "";
 | |
|     if (req.body.hasOwnProperty("token")) {
 | |
|       token = req.body.token;
 | |
|     }
 | |
|     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 = cleanChannelName(req.params.channel_name);
 | |
|     var userpass;
 | |
|     if (req.body.hasOwnProperty("userpass")) {
 | |
|       req.body.userpass =
 | |
|         req.body.userpass == ""
 | |
|           ? ""
 | |
|           : crypto
 | |
|               .createHash("sha256")
 | |
|               .update(req.body.userpass, "utf8")
 | |
|               .digest("base64");
 | |
|       userpass = req.body.userpass;
 | |
|     } else {
 | |
|       userpass = "";
 | |
|     }
 | |
| 
 | |
|     /*if(typeof(userpass) != "string") {
 | |
|             throw "Wrong format";
 | |
|         }*/
 | |
|   } catch (e) {
 | |
|     var result = {
 | |
|       userpass: {
 | |
|         expected: "string",
 | |
|         got: req.body.hasOwnProperty("userpass")
 | |
|           ? typeof req.body.userpass
 | |
|           : undefined
 | |
|       }
 | |
|     };
 | |
|     var to_send = error.formatting;
 | |
|     to_send.results = [result];
 | |
|     res.status(400).send(to_send);
 | |
| 
 | |
|     return;
 | |
|   }
 | |
|   var cookie = req.cookies._uI;
 | |
|   Functions.getSessionAdminUser(cookie, channel_name, function(_u, _a) {
 | |
|     if (req.body.userpass == "") {
 | |
|       //userpass = Functions.hash_pass(Functions.hash_pass(Functions.decrypt_string(_u)))
 | |
|       userpass = _u;
 | |
|     }
 | |
| 
 | |
|     token_db
 | |
|       .collection("api_token")
 | |
|       .find({ token: token }, function(err, token_docs) {
 | |
|         var authorized = false;
 | |
|         var origin;
 | |
|         try {
 | |
|           origin = req.headers.referer.split("/")[2];
 | |
|         } catch (e) {
 | |
|           origin = "";
 | |
|         }
 | |
|         if (
 | |
|           token_docs.length == 1 &&
 | |
|           token_docs[0].token == token &&
 | |
|           (token_docs[0].origin == "*" ||
 | |
|             origin.indexOf(token_docs[0].origin) > -1)
 | |
|         ) {
 | |
|           authorized = true;
 | |
|         }
 | |
|         checkOveruseApiToken(authorized, token_docs, res, function() {
 | |
|           checkTimeout(guid, res, authorized, "POST", function() {
 | |
|             if (token != "" && !authorized) {
 | |
|               //updateTimeout(guid, res, authorized, "POST", function(err, docs) {
 | |
|               res.status(400).send(error.wrong_token);
 | |
|               return;
 | |
|               //});
 | |
|             } else {
 | |
|               db.collection(channel_name).aggregate(
 | |
|                 [
 | |
|                   {
 | |
|                     $match: {
 | |
|                       type: {
 | |
|                         $ne: "suggested"
 | |
|                       }
 | |
|                     }
 | |
|                   },
 | |
|                   { $project: projects.project_object },
 | |
|                   { $sort: { now_playing: -1, votes: -1, added: 1, title: 1 } }
 | |
|                 ],
 | |
|                 function(err, list) {
 | |
|                   //db.collection(channel_name).find({views: {$exists: false}}, projects.toShowChannel, function(err, list) {
 | |
|                   if (list.length > 0) {
 | |
|                     db.collection(channel_name + "_settings").find(
 | |
|                       { id: "config" },
 | |
|                       function(err, conf) {
 | |
|                         if (conf.length == 0) {
 | |
|                           res.status(404).send(error.not_found.list);
 | |
|                           return;
 | |
|                         } else if (
 | |
|                           conf[0].userpass != userpass &&
 | |
|                           conf[0].userpass != "" &&
 | |
|                           conf[0].userpass != undefined
 | |
|                         ) {
 | |
|                           res.status(403).send(error.not_authenticated);
 | |
|                           return;
 | |
|                         }
 | |
|                         if (authorized) {
 | |
|                           incrementToken(token);
 | |
|                         }
 | |
|                         //updateTimeout(guid, res, authorized, "POST", function(err, docs) {
 | |
|                         var to_return = error.no_error;
 | |
|                         to_return.results = list;
 | |
|                         res.status(200).send(to_return);
 | |
|                         return;
 | |
|                         //});
 | |
|                       }
 | |
|                     );
 | |
|                   } else {
 | |
|                     res.status(404).send(error.not_found.list);
 | |
|                     return;
 | |
|                   }
 | |
|                 }
 | |
|               );
 | |
|             }
 | |
|           });
 | |
|         });
 | |
|       });
 | |
|   });
 | |
| });
 | |
| 
 | |
| function incrementToken(token) {
 | |
|   token_db
 | |
|     .collection("api_token")
 | |
|     .update({ token: token }, { $inc: { usage: 1 } }, function(err, doc) {});
 | |
| }
 | |
| 
 | |
| router.route("/api/color").post(function(req, res) {
 | |
|   try {
 | |
|     var origin = req
 | |
|       .get("origin")
 | |
|       .replace("https://", "")
 | |
|       .replace("http://", "");
 | |
|     var allowed = [
 | |
|       "client.localhost",
 | |
|       "localhost",
 | |
|       "zoff.me",
 | |
|       "client.zoff.me",
 | |
|       "zoff.no",
 | |
|       "client.zoff.no"
 | |
|     ];
 | |
|     if (allowed.indexOf(origin) < 0) {
 | |
|       throw "Wrong origin";
 | |
|     }
 | |
|   } catch (e) {
 | |
|     res.sendStatus(403);
 | |
|     return;
 | |
|   }
 | |
|   if (!req.body.hasOwnProperty("id") || typeof req.body.id != "string") {
 | |
|     res.sendStatus(400);
 | |
|     return;
 | |
|   }
 | |
|   List.sendColor(false, undefined, req.body.id, true, res);
 | |
| });
 | |
| 
 | |
| router.route("/api/imageblob").post(function(req, res) {
 | |
|   var Jimp = require("jimp");
 | |
|   try {
 | |
|     var origin = req
 | |
|       .get("origin")
 | |
|       .replace("https://", "")
 | |
|       .replace("http://", "");
 | |
|     var allowed = [
 | |
|       "client.localhost",
 | |
|       "localhost",
 | |
|       "zoff.me",
 | |
|       "client.zoff.me",
 | |
|       "zoff.no",
 | |
|       "client.zoff.no"
 | |
|     ];
 | |
|     if (allowed.indexOf(origin) < 0) {
 | |
|       throw "Wrong origin";
 | |
|     }
 | |
|   } catch (e) {
 | |
|     res.sendStatus(403);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Jimp.read(
 | |
|     "https://img.youtube.com/vi/" + req.body.id + "/mqdefault.jpg",
 | |
|     function(err, image) {
 | |
|       if (err) {
 | |
|         console.log(err);
 | |
|         res.sendStatus(404);
 | |
|         return;
 | |
|       }
 | |
|       image
 | |
|         .blur(50)
 | |
|         .write(
 | |
|           path.join(
 | |
|             pathThumbnails,
 | |
|             "/public/assets/images/thumbnails/" + req.body.id + ".jpg"
 | |
|           ),
 | |
|           function(e, r) {
 | |
|             res.status(200).send(req.body.id + ".jpg");
 | |
|             return;
 | |
|           }
 | |
|         );
 | |
|     }
 | |
|   );
 | |
| });
 | |
| 
 | |
| try {
 | |
|   var nodemailer = require("nodemailer");
 | |
|   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;
 | |
|   var recaptcha = new Recaptcha(RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY);
 | |
| 
 | |
|   router
 | |
|     .route("/api/apply")
 | |
|     .post(recaptcha.middleware.verify, function(req, res) {
 | |
|       if (req.body.email == "" || req.body.email == undefined) {
 | |
|         res.send("failed");
 | |
|         return;
 | |
|       }
 | |
|       if (req.recaptcha.error == null) {
 | |
|         var origin = "*";
 | |
|         if (req.body.origin != undefined && req.body.origin != "")
 | |
|           origin = req.body.origin;
 | |
|         var name = req.body.email;
 | |
|         var id = crypto
 | |
|           .createHash("sha256")
 | |
|           .update(uniqid())
 | |
|           .digest("base64");
 | |
|         var uniqid_link = crypto
 | |
|           .createHash("sha256")
 | |
|           .update(uniqid())
 | |
|           .digest("hex");
 | |
|         token_db
 | |
|           .collection("api_token")
 | |
|           .find({ name: name }, function(err, results_find) {
 | |
|             var token = "";
 | |
|             if (results_find.length > 0) {
 | |
|               token = results_find[0].token;
 | |
|             }
 | |
|             token_db
 | |
|               .collection("api_links")
 | |
|               .find({ token: token }, function(e, d) {
 | |
|                 if (
 | |
|                   results_find.length == 0 ||
 | |
|                   (d.length == 0 &&
 | |
|                     results_find.length > 0 &&
 | |
|                     !results_find[0].active)
 | |
|                 ) {
 | |
|                   token_db.collection("api_token").insert(
 | |
|                     {
 | |
|                       name: name,
 | |
|                       origin: origin,
 | |
|                       token: id,
 | |
|                       usage: 0,
 | |
|                       active: false,
 | |
|                       limit: 20
 | |
|                     },
 | |
|                     function(err, docs) {
 | |
|                       createApiLink(req, res, uniqid_link, id, name);
 | |
|                     }
 | |
|                   );
 | |
|                 } else {
 | |
|                   createApiLink(req, res, uniqid_link, token, name);
 | |
|                 }
 | |
|               });
 | |
|           });
 | |
|       } else {
 | |
|         res.send("failed");
 | |
|         return;
 | |
|       }
 | |
|     });
 | |
| 
 | |
|   function createApiLink(req, res, uniqid_link, id, name) {
 | |
|     token_db
 | |
|       .collection("api_links")
 | |
|       .insert({ id: uniqid_link, token: id, createdAt: new Date() }, function(
 | |
|         err,
 | |
|         docs
 | |
|       ) {
 | |
|         let transporter = nodemailer.createTransport(mailconfig);
 | |
|         transporter.verify(function(error, success) {
 | |
|           if (error) {
 | |
|             token_db
 | |
|               .collection("api_links")
 | |
|               .remove({ id: uniqid_link }, function(e, d) {
 | |
|                 res.send("failed");
 | |
|                 return;
 | |
|               });
 | |
|           } else {
 | |
|             var subject = "ZOFF: API-key";
 | |
|             var message =
 | |
|               "Hello,<br><br>Thanks for signing up for the API, here is your key: <a href='https://zoff.me/api/apply/" +
 | |
|               uniqid_link +
 | |
|               "'/>https://zoff.me/api/apply/" +
 | |
|               uniqid_link +
 | |
|               "</a><br><br>This link will expire in 1 day, so please write it down.<br><br><img src='https://zoff.me/assets/images/small-square.jpg' width='100' height='100' alt='zoff-logo' />";
 | |
|             var msg = {
 | |
|               from: mailconfig.from,
 | |
|               to: name,
 | |
|               subject: subject,
 | |
|               text: message,
 | |
|               html: message
 | |
|             };
 | |
|             transporter.sendMail(msg, (error, info) => {
 | |
|               if (error) {
 | |
|                 res.send("failed");
 | |
|                 transporter.close();
 | |
|                 return;
 | |
|               }
 | |
|               res.status(200).send("success");
 | |
|               transporter.close();
 | |
|               return;
 | |
|             });
 | |
|           }
 | |
|         });
 | |
|       });
 | |
|   }
 | |
| 
 | |
|   router
 | |
|     .route("/api/mail")
 | |
|     .post(recaptcha.middleware.verify, function(req, res) {
 | |
|       if (req.recaptcha.error == null) {
 | |
|         let transporter = nodemailer.createTransport(mailconfig);
 | |
| 
 | |
|         transporter.verify(function(error, success) {
 | |
|           if (error) {
 | |
|             res.sendStatus(500);
 | |
|             return;
 | |
|           } else {
 | |
|             var subject = "ZOFF: Contact form webpage";
 | |
|             if (req.body.error_report) {
 | |
|               subject = "ZOFF: Error report";
 | |
|             }
 | |
|             var from = req.body.from;
 | |
|             var message = req.body.message;
 | |
|             var msg = {
 | |
|               from: mailconfig.from,
 | |
|               to: mailconfig.to,
 | |
|               subject: subject,
 | |
|               text: message,
 | |
|               html: message,
 | |
|               replyTo: from
 | |
|             };
 | |
|             transporter.sendMail(msg, (error, info) => {
 | |
|               if (error) {
 | |
|                 res.status(500).send("failed");
 | |
|                 transporter.close();
 | |
|                 return;
 | |
|               }
 | |
|               res.status(200).send("success");
 | |
|               transporter.close();
 | |
|             });
 | |
|           }
 | |
|         });
 | |
|       } else {
 | |
|         res.status(500).send("failed");
 | |
|         return;
 | |
|       }
 | |
|     });
 | |
| } catch (e) {
 | |
|   console.log(
 | |
|     "(!) Missing file - /config/mailconfig.js Have a look at /config/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.status(500).send("failed");
 | |
|     return;
 | |
|   });
 | |
| }
 | |
| 
 | |
| function updateTimeout(guid, res, authorized, type, callback) {
 | |
|   if (authorized) {
 | |
|     callback(null, null);
 | |
|     return;
 | |
|   }
 | |
|   db.collection("timeout_api").update(
 | |
|     { type: type, guid: guid },
 | |
|     {
 | |
|       $set: {
 | |
|         createdAt: new Date(),
 | |
|         type: type,
 | |
|         guid: guid
 | |
|       }
 | |
|     },
 | |
|     { upsert: true },
 | |
|     function(err, docs) {
 | |
|       callback(err, docs);
 | |
|     }
 | |
|   );
 | |
| }
 | |
| 
 | |
| function checkTimeout(guid, res, authorized, type, callback) {
 | |
|   if (authorized) {
 | |
|     callback();
 | |
|     return;
 | |
|   }
 | |
|   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() + 1);
 | |
|         var now = new Date();
 | |
|         var retry_in = (date.getTime() - now.getTime()) / 1000;
 | |
|         if (retry_in > 0) {
 | |
|           res.header({ "Retry-After": retry_in });
 | |
|           var thisErrorString = JSON.stringify(error.tooMany);
 | |
|           var thisError = JSON.parse(thisErrorString);
 | |
|           thisError.error +=
 | |
|             " To get an API-key, visit https://zoff.me/api/apply.";
 | |
|           res.status(429).send(thisError);
 | |
|           return;
 | |
|         }
 | |
|       }
 | |
|       var now_date = new Date();
 | |
|       db.collection("timeout_api").update(
 | |
|         { type: type, guid: guid },
 | |
|         {
 | |
|           $set: {
 | |
|             createdAt: now_date,
 | |
|             type: type,
 | |
|             guid: guid
 | |
|           }
 | |
|         },
 | |
|         { upsert: true },
 | |
|         function(err, docs) {
 | |
|           callback();
 | |
|           return;
 | |
|         }
 | |
|       );
 | |
|     }
 | |
|   );
 | |
| }
 | |
| 
 | |
| function cleanChannelName(channel_name) {
 | |
|   var coll = Functions.removeEmojis(channel_name).toLowerCase();
 | |
|   //coll = coll.replace("_", "");
 | |
|   //coll = encodeURIComponent(coll).replace(/\W/g, '');
 | |
|   coll = Functions.encodeChannelName(channel_name);
 | |
|   coll = filter.clean(coll);
 | |
|   return coll;
 | |
| }
 | |
| 
 | |
| function validateLogin(adminpass, userpass, channel_name, type, res, callback) {
 | |
|   db.collection(channel_name + "_settings").find({ id: "config" }, 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.status(404).send(error.not_found.list);
 | |
|       return;
 | |
|     } else if (conf.length == 0) {
 | |
|       res.status(404).send(error.not_found.list);
 | |
|       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, true);
 | |
|     } else if (type == "add") {
 | |
|       callback(exists, conf, false);
 | |
|     } else {
 | |
|       res.status(403).send(error.not_authenticated);
 | |
|       return;
 | |
|     }
 | |
|   });
 | |
| }
 | |
| 
 | |
| function postEnd(
 | |
|   channel_name,
 | |
|   configs,
 | |
|   new_song,
 | |
|   guid,
 | |
|   res,
 | |
|   authenticated,
 | |
|   authorized
 | |
| ) {
 | |
|   if (configs != undefined) {
 | |
|     io.to(channel_name).emit("conf", configs);
 | |
|   }
 | |
|   List.getNextSong(channel_name, undefined, function() {
 | |
|     //updateTimeout(guid, res, authorized, "POST", function(err, docs) {
 | |
|     var to_return = error.no_error;
 | |
|     if (!authenticated) {
 | |
|       to_return = error.not_authenticated;
 | |
|       to_return.success = true;
 | |
|     }
 | |
|     to_return.results = [new_song];
 | |
|     res.status(authenticated ? 200 : 403).send(to_return);
 | |
|     return;
 | |
|     //});
 | |
|   });
 | |
| }
 | |
| 
 | |
| module.exports = _exports;
 |