mirror of https://github.com/calzoneman/sync.git
Work on SIO and SSL
This commit is contained in:
parent
4a2366eb06
commit
feabf35714
|
@ -27,13 +27,10 @@ function handleAuth(data, accept) {
|
||||||
var auth = data.cookie.auth;
|
var auth = data.cookie.auth;
|
||||||
db.users.verifyAuth(auth, function (err, user) {
|
db.users.verifyAuth(auth, function (err, user) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
console.log('VERIFIED: ' + user.name + ' => ' + user.global_rank);
|
|
||||||
data.user = {
|
data.user = {
|
||||||
name: user.name,
|
name: user.name,
|
||||||
global_rank: user.global_rank
|
global_rank: user.global_rank
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
console.log('Auth fail: ' + err);
|
|
||||||
}
|
}
|
||||||
accept(null, true);
|
accept(null, true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -83,74 +83,6 @@ var Server = function () {
|
||||||
root: path.join(__dirname, "../www")
|
root: path.join(__dirname, "../www")
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
/*
|
|
||||||
self.express.use(express.urlencoded());
|
|
||||||
self.express.use(express.json());
|
|
||||||
self.express.use(express.cookieParser());
|
|
||||||
|
|
||||||
// channel route
|
|
||||||
self.express.get("/r/:channel(*)", function (req, res, next) {
|
|
||||||
var c = req.params.channel;
|
|
||||||
if (!$util.isValidChannelName(c)) {
|
|
||||||
res.redirect("/" + c);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.logHTTP(req);
|
|
||||||
res.sendfile("channel.html", {
|
|
||||||
root: path.join(__dirname, "../www")
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// api route
|
|
||||||
self.api = require("./api")(self);
|
|
||||||
|
|
||||||
// index
|
|
||||||
self.express.get("/", function (req, res, next) {
|
|
||||||
self.logHTTP(req);
|
|
||||||
res.sendfile("index.html", {
|
|
||||||
root: path.join(__dirname, "../www")
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// default route
|
|
||||||
self.express.get("/:thing(*)", function (req, res, next) {
|
|
||||||
var opts = {
|
|
||||||
root: path.join(__dirname, "../www"),
|
|
||||||
maxAge: self.cfg["asset-cache-ttl"]
|
|
||||||
};
|
|
||||||
|
|
||||||
res.sendfile(req.params.thing, opts, function (e) {
|
|
||||||
if (e) {
|
|
||||||
self.logHTTP(req, e.status);
|
|
||||||
if (req.params.thing.match(/\.\.|(%25)?%2e(%25)?%2e/)) {
|
|
||||||
res.send("Don't try that again.");
|
|
||||||
Logger.syslog.log("WARNING: Attempted path traversal "+
|
|
||||||
"from IP " + self.getHTTPIP(req));
|
|
||||||
Logger.syslog.log("Path was: " + req.url);
|
|
||||||
ActionLog.record(self.getHTTPIP(req), "",
|
|
||||||
"path-traversal",
|
|
||||||
req.url);
|
|
||||||
} else if (e.status >= 500) {
|
|
||||||
Logger.errlog.log(err);
|
|
||||||
}
|
|
||||||
res.send(e.status);
|
|
||||||
} else {
|
|
||||||
self.logHTTP(req);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// fallback route
|
|
||||||
self.express.use(function (err, req, res, next) {
|
|
||||||
self.logHTTP(req, err.status);
|
|
||||||
if (err.status === 404) {
|
|
||||||
res.send(404);
|
|
||||||
} else {
|
|
||||||
next(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
// http/https/sio server init -----------------------------------------
|
// http/https/sio server init -----------------------------------------
|
||||||
if (Config.get("https.enabled")) {
|
if (Config.get("https.enabled")) {
|
||||||
|
@ -170,14 +102,7 @@ var Server = function () {
|
||||||
|
|
||||||
self.http = self.express.listen(Config.get("http.port"),
|
self.http = self.express.listen(Config.get("http.port"),
|
||||||
Config.get("http.host") || undefined);
|
Config.get("http.host") || undefined);
|
||||||
/*
|
|
||||||
self.ioWeb = express().listen(self.cfg["io-port"], self.cfg["io-host"]);
|
|
||||||
self.io = require("socket.io").listen(self.ioWeb);
|
|
||||||
self.io.set("log level", 1);
|
|
||||||
self.io.sockets.on("connection", function (sock) {
|
|
||||||
self.handleSocketConnection(sock);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
require("./io/ioserver").init(self);
|
require("./io/ioserver").init(self);
|
||||||
|
|
||||||
// background tasks init ----------------------------------------------
|
// background tasks init ----------------------------------------------
|
||||||
|
|
|
@ -16,6 +16,10 @@ var $util = require('../utilities');
|
||||||
* Handles a GET request for /account/edit
|
* Handles a GET request for /account/edit
|
||||||
*/
|
*/
|
||||||
function handleAccountEditPage(req, res) {
|
function handleAccountEditPage(req, res) {
|
||||||
|
if (webserver.redirectHttps(req, res)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logRequest(req);
|
logRequest(req);
|
||||||
var loginName = false;
|
var loginName = false;
|
||||||
if (req.cookies.auth) {
|
if (req.cookies.auth) {
|
||||||
|
@ -167,6 +171,10 @@ function handleChangeEmail(req, res) {
|
||||||
* Handles a GET request for /account/channels
|
* Handles a GET request for /account/channels
|
||||||
*/
|
*/
|
||||||
function handleAccountChannelPage(req, res) {
|
function handleAccountChannelPage(req, res) {
|
||||||
|
if (webserver.redirectHttps(req, res)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logRequest(req);
|
logRequest(req);
|
||||||
var loginName = false;
|
var loginName = false;
|
||||||
if (req.cookies.auth) {
|
if (req.cookies.auth) {
|
||||||
|
@ -315,6 +323,10 @@ function handleDeleteChannel(req, res) {
|
||||||
* Handles a GET request for /account/profile
|
* Handles a GET request for /account/profile
|
||||||
*/
|
*/
|
||||||
function handleAccountProfilePage(req, res) {
|
function handleAccountProfilePage(req, res) {
|
||||||
|
if (webserver.redirectHttps(req, res)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logRequest(req);
|
logRequest(req);
|
||||||
|
|
||||||
var loginName = false;
|
var loginName = false;
|
||||||
|
|
|
@ -73,6 +73,10 @@ function handleLogin(req, res) {
|
||||||
* Handles a GET request for /login
|
* Handles a GET request for /login
|
||||||
*/
|
*/
|
||||||
function handleLoginPage(req, res) {
|
function handleLoginPage(req, res) {
|
||||||
|
if (webserver.redirectHttps(req, res)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (req.cookies.auth) {
|
if (req.cookies.auth) {
|
||||||
var split = req.cookies.auth.split(":");
|
var split = req.cookies.auth.split(":");
|
||||||
if (split.length === 2) {
|
if (split.length === 2) {
|
||||||
|
@ -120,6 +124,10 @@ function handleLogout(req, res) {
|
||||||
* Handles a GET request for /register
|
* Handles a GET request for /register
|
||||||
*/
|
*/
|
||||||
function handleRegisterPage(req, res) {
|
function handleRegisterPage(req, res) {
|
||||||
|
if (webserver.redirectHttps(req, res)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (req.cookies.auth) {
|
if (req.cookies.auth) {
|
||||||
var split = req.cookies.auth.split(":");
|
var split = req.cookies.auth.split(":");
|
||||||
if (split.length === 2) {
|
if (split.length === 2) {
|
||||||
|
|
|
@ -4,16 +4,17 @@
|
||||||
* @author Calvin Montgomery <cyzon@cyzon.us>
|
* @author Calvin Montgomery <cyzon@cyzon.us>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var path = require('path');
|
var path = require("path");
|
||||||
var net = require('net');
|
var net = require("net");
|
||||||
var express = require('express');
|
var express = require("express");
|
||||||
var webroot = path.join(__dirname, '..', 'www');
|
var webroot = path.join(__dirname, "..", "www");
|
||||||
var sendJade = require('./jade').sendJade;
|
var sendJade = require("./jade").sendJade;
|
||||||
var Server = require('../server');
|
var Server = require("../server");
|
||||||
var $util = require('../utilities');
|
var $util = require("../utilities");
|
||||||
var Logger = require('../logger');
|
var Logger = require("../logger");
|
||||||
|
var Config = require("../config");
|
||||||
|
|
||||||
var httplog = new Logger.Logger(path.join(__dirname, '..', '..', 'http.log'));
|
var httplog = new Logger.Logger(path.join(__dirname, "..", "..", "http.log"));
|
||||||
|
|
||||||
var suspiciousPath = (/admin|adm|\.\.|\/etc\/passwd|\\x5c|%5c|0x5c|setup|install|php|pma|blog|sql|scripts|aspx?|database/ig);
|
var suspiciousPath = (/admin|adm|\.\.|\/etc\/passwd|\\x5c|%5c|0x5c|setup|install|php|pma|blog|sql|scripts|aspx?|database/ig);
|
||||||
/**
|
/**
|
||||||
|
@ -21,8 +22,8 @@ var suspiciousPath = (/admin|adm|\.\.|\/etc\/passwd|\\x5c|%5c|0x5c|setup|install
|
||||||
*/
|
*/
|
||||||
function isSuspicious(req) {
|
function isSuspicious(req) {
|
||||||
// ZmEu is a penetration script
|
// ZmEu is a penetration script
|
||||||
if (req.header('user-agent') &&
|
if (req.header("user-agent") &&
|
||||||
req.header('user-agent').toLowerCase() === 'zmeu') {
|
req.header("user-agent").toLowerCase() === "zmeu") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,9 +39,9 @@ function isSuspicious(req) {
|
||||||
*/
|
*/
|
||||||
function ipForRequest(req) {
|
function ipForRequest(req) {
|
||||||
var ip = req.ip;
|
var ip = req.ip;
|
||||||
if (ip === '127.0.0.1' || ip === '::1') {
|
if (ip === "127.0.0.1" || ip === "::1") {
|
||||||
var xforward = req.header('x-forwarded-for');
|
var xforward = req.header("x-forwarded-for");
|
||||||
if (typeof xforward !== 'string' || !net.isIP(xforward)) {
|
if (typeof xforward !== "string" || !net.isIP(xforward)) {
|
||||||
return ip;
|
return ip;
|
||||||
} else {
|
} else {
|
||||||
return xforward;
|
return xforward;
|
||||||
|
@ -61,34 +62,72 @@ function logRequest(req, status) {
|
||||||
ipForRequest(req),
|
ipForRequest(req),
|
||||||
req.route.method.toUpperCase(),
|
req.route.method.toUpperCase(),
|
||||||
req.path,
|
req.path,
|
||||||
status,
|
req.header("user-agent")
|
||||||
req.header('user-agent')
|
].join(" "));
|
||||||
].join(' '));
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirects a request to HTTPS if the server supports it
|
||||||
|
*/
|
||||||
|
function redirectHttps(req, res) {
|
||||||
|
if (!req.secure && Config.get("https.enabled")) {
|
||||||
|
var ssldomain = Config.get("https.domain");
|
||||||
|
var port = Config.get("https.port");
|
||||||
|
if (port !== 443) {
|
||||||
|
ssldomain += ":" + port;
|
||||||
|
}
|
||||||
|
res.redirect(ssldomain + req.path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirects a request to HTTP if the server supports it
|
||||||
|
*/
|
||||||
|
function redirectHttp(req, res) {
|
||||||
|
if (req.secure) {
|
||||||
|
var domain = Config.get("http.domain");
|
||||||
|
var port = Config.get("http.port");
|
||||||
|
if (port !== 80) {
|
||||||
|
domain += ":" + port;
|
||||||
|
}
|
||||||
|
console.log(domain);
|
||||||
|
res.redirect(domain + req.path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a GET request for /r/:channel - serves channel.html
|
* Handles a GET request for /r/:channel - serves channel.html
|
||||||
*/
|
*/
|
||||||
function handleChannel(req, res) {
|
function handleChannel(req, res) {
|
||||||
|
if (redirectHttp(req, res)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$util.isValidChannelName(req.params.channel)) {
|
if (!$util.isValidChannelName(req.params.channel)) {
|
||||||
logRequest(req, 404);
|
logRequest(req, 404);
|
||||||
res.status(404);
|
res.status(404);
|
||||||
res.send('Invalid channel name "' + req.params.channel + '"');
|
res.send("Invalid channel name '" + req.params.channel + "'");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logRequest(req);
|
logRequest(req);
|
||||||
|
|
||||||
var loginName = false;
|
var loginName = false;
|
||||||
if (req.cookies.auth) {
|
if (req.cookies.auth) {
|
||||||
loginName = req.cookies.auth.split(':')[0];
|
loginName = req.cookies.auth.split(":")[0];
|
||||||
}
|
}
|
||||||
var inst = Server.getServer();
|
|
||||||
var iourl = '';
|
var iourl = "";
|
||||||
sendJade(res, 'channel', {
|
sendJade(res, "channel", {
|
||||||
channelName: req.params.channel,
|
channelName: req.params.channel,
|
||||||
layout: 'hd',
|
|
||||||
loggedIn: loginName !== false,
|
loggedIn: loginName !== false,
|
||||||
loginName: loginName,
|
loginName: loginName,
|
||||||
/*ioUrl: 'http://' + inst.config.sio.domain + ':' + inst.config.sio.port*/
|
sioSource: Config.get("http.domain") + ":" + Config.get("io.port") +
|
||||||
|
"/socket.io/socket.io.js"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,18 +136,37 @@ function handleChannel(req, res) {
|
||||||
*/
|
*/
|
||||||
function handleIndex(req, res) {
|
function handleIndex(req, res) {
|
||||||
logRequest(req);
|
logRequest(req);
|
||||||
|
|
||||||
var loginName = false;
|
var loginName = false;
|
||||||
if (req.cookies.auth) {
|
if (req.cookies.auth) {
|
||||||
loginName = req.cookies.auth.split(':')[0];
|
loginName = req.cookies.auth.split(":")[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
sendJade(res, 'index', {
|
sendJade(res, "index", {
|
||||||
loggedIn: loginName !== false,
|
loggedIn: loginName !== false,
|
||||||
loginName: loginName,
|
loginName: loginName,
|
||||||
channels: Server.getServer().packChannelList(true)
|
channels: Server.getServer().packChannelList(true)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a request for the socket.io information
|
||||||
|
*/
|
||||||
|
function handleSocketConfig(req, res) {
|
||||||
|
logRequest(req);
|
||||||
|
|
||||||
|
res.type("application/javascript");
|
||||||
|
|
||||||
|
var io_url = Config.get("http.domain") + ":" + Config.get("io.port");
|
||||||
|
var web_url = Config.get("http.domain") + ":" + Config.get("http.port");
|
||||||
|
var ssl_url = Config.get("https.domain") + ":" + Config.get("https.port");
|
||||||
|
res.send("var IO_URL='"+io_url+"',WEB_URL='"+web_url+"',SSL_URL='" + ssl_url +
|
||||||
|
"',ALLOW_SSL="+Config.get("https.enabled")+";" +
|
||||||
|
(Config.get("https.enabled") ?
|
||||||
|
"if(location.protocol=='https:'||USEROPTS.secure_connection){" +
|
||||||
|
"IO_URL=WEB_URL=SSL_URL;}" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
/**
|
/**
|
||||||
* Initializes webserver callbacks
|
* Initializes webserver callbacks
|
||||||
|
@ -122,33 +180,38 @@ module.exports = {
|
||||||
/* Order here is important
|
/* Order here is important
|
||||||
* Since I placed /r/:channel above *, the function will
|
* Since I placed /r/:channel above *, the function will
|
||||||
* not apply to the /r/:channel route. This prevents
|
* not apply to the /r/:channel route. This prevents
|
||||||
* duplicate logging, since /r/:channel's callback does
|
* duplicate logging, since /r/:channel"s callback does
|
||||||
* its own logging
|
* its own logging
|
||||||
*/
|
*/
|
||||||
app.get('/r/:channel', handleChannel);
|
app.get("/r/:channel", handleChannel);
|
||||||
app.get('/', handleIndex);
|
app.get("/", handleIndex);
|
||||||
app.all('*', function (req, res, next) {
|
app.get("/sioconfig", handleSocketConfig);
|
||||||
|
app.all("*", function (req, res, next) {
|
||||||
if (isSuspicious(req)) {
|
if (isSuspicious(req)) {
|
||||||
logRequest(req, 403);
|
logRequest(req, 403);
|
||||||
res.status(403);
|
res.status(403);
|
||||||
if (req.header('user-agent').toLowerCase() === 'zmeu') {
|
if (req.header("user-agent").toLowerCase() === "zmeu") {
|
||||||
res.send('This server disallows requests from ZmEu.');
|
res.send("This server disallows requests from ZmEu.");
|
||||||
} else {
|
} else {
|
||||||
res.send('The request ' + req.route.method.toUpperCase() + ' ' +
|
res.send("The request " + req.route.method.toUpperCase() + " " +
|
||||||
req.path + ' looks pretty fishy to me. Double check that ' +
|
req.path + " looks pretty fishy to me. Double check that " +
|
||||||
'you typed it correctly.');
|
"you typed it correctly.");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logRequest(req);
|
logRequest(req);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
app.use(express.static('www'));
|
app.use(express.static("www"));
|
||||||
require('./auth').init(app);
|
require("./auth").init(app);
|
||||||
require('./account').init(app);
|
require("./account").init(app);
|
||||||
},
|
},
|
||||||
|
|
||||||
logRequest: logRequest,
|
logRequest: logRequest,
|
||||||
|
|
||||||
ipForRequest: ipForRequest
|
ipForRequest: ipForRequest,
|
||||||
|
|
||||||
|
redirectHttps: redirectHttps,
|
||||||
|
|
||||||
|
redirectHttp: redirectHttp
|
||||||
};
|
};
|
||||||
|
|
|
@ -155,18 +155,18 @@ html(lang="en")
|
||||||
ul.nav.nav-tabs
|
ul.nav.nav-tabs
|
||||||
li: a(href="#cs-miscoptions", data-toggle="tab") General Settings
|
li: a(href="#cs-miscoptions", data-toggle="tab") General Settings
|
||||||
li: a(href="#cs-adminoptions", data-toggle="tab") Admin Settings
|
li: a(href="#cs-adminoptions", data-toggle="tab") Admin Settings
|
||||||
li: a(href="#cs-chanlog", data-toggle="tab", onclick="javascript:socket.emit('readChanLog')") Channel Log
|
|
||||||
li: a(href="#cs-chatfilters", data-toggle="tab", onclick="javascript:socket.emit('requestChatFilters')") Chat Filters
|
|
||||||
li.dropdown
|
li.dropdown
|
||||||
a#cs-edit-dd-toggle(href="#", data-toggle="dropdown") Edit
|
a#cs-edit-dd-toggle(href="#", data-toggle="dropdown") Edit
|
||||||
span.caret
|
span.caret
|
||||||
ul.dropdown-menu
|
ul.dropdown-menu
|
||||||
li: a(href="#cs-motdeditor", data-toggle="tab", tabindex="-1") Edit MOTD
|
li: a(href="#cs-chatfilters", data-toggle="tab", onclick="javascript:socket.emit('requestChatFilters')") Chat Filters
|
||||||
li: a(href="#cs-csseditor", data-toggle="tab", tabindex="-1") Edit CSS
|
li: a(href="#cs-motdeditor", data-toggle="tab", tabindex="-1") MOTD
|
||||||
li: a(href="#cs-jseditor", data-toggle="tab", tabindex="-1") Edit Javascript
|
li: a(href="#cs-csseditor", data-toggle="tab", tabindex="-1") CSS
|
||||||
li: a(href="#cs-permedit", data-toggle="tab", tabindex="-1") Edit Permissions
|
li: a(href="#cs-jseditor", data-toggle="tab", tabindex="-1") Javascript
|
||||||
li: a(href="#cs-chanranks", data-toggle="tab", tabindex="-1", onclick="javascript:socket.emit('requestChannelRanks')") Edit moderators
|
li: a(href="#cs-permedit", data-toggle="tab", tabindex="-1") Permissions
|
||||||
|
li: a(href="#cs-chanranks", data-toggle="tab", tabindex="-1", onclick="javascript:socket.emit('requestChannelRanks')") Moderators
|
||||||
li: a(href="#cs-banlist", data-toggle="tab", tabindex="-1", onclick="javascript:socket.emit('requestBanlist')") Ban list
|
li: a(href="#cs-banlist", data-toggle="tab", tabindex="-1", onclick="javascript:socket.emit('requestBanlist')") Ban list
|
||||||
|
li: a(href="#cs-chanlog", data-toggle="tab", onclick="javascript:socket.emit('readChanLog')") Log
|
||||||
.modal-body
|
.modal-body
|
||||||
.tab-content
|
.tab-content
|
||||||
include channeloptions
|
include channeloptions
|
||||||
|
@ -185,17 +185,17 @@ html(lang="en")
|
||||||
button.btn.btn-default(type="button", data-dismiss="modal") Close
|
button.btn.btn-default(type="button", data-dismiss="modal") Close
|
||||||
include footer
|
include footer
|
||||||
mixin footer()
|
mixin footer()
|
||||||
script(src="/assets/js/iourl.js")
|
script(src=sioSource)
|
||||||
//script(src="#{ioUrl}/socket.io/socket.io.js")
|
script(src="/sioconfig")
|
||||||
//script(type="text/javascript").
|
|
||||||
// var IOSERVER = "#{ioUrl}";
|
|
||||||
// var SOCKET = io.connect(IOSERVER);
|
|
||||||
// $('#channeloptions').modal();
|
|
||||||
// $('#channeloptions a[href="#cs-miscoptions"]').tab('show');
|
|
||||||
script(src="/assets/js/data.js")
|
script(src="/assets/js/data.js")
|
||||||
script(src="/assets/js/util.js")
|
script(src="/assets/js/util.js")
|
||||||
script(src="/assets/js/player.js")
|
script(src="/assets/js/player.js")
|
||||||
script(src="/assets/js/paginator.js")
|
script(src="/assets/js/paginator.js")
|
||||||
script(src="/assets/js/ui.js")
|
script(src="/assets/js/ui.js")
|
||||||
script(src="/assets/js/callbacks.js")
|
script(src="/assets/js/callbacks.js")
|
||||||
script(src="https://www.youtube.com/iframe_api")
|
script(defer, src="https://www.youtube.com/iframe_api")
|
||||||
|
script(defer, src="//api.dmcdn.net/all.js")
|
||||||
|
script(defer, src="/assets/js/jwplayer.js")
|
||||||
|
script(defer, src="/assets/js/sc.js")
|
||||||
|
script(defer, src="/assets/js/froogaloop.min.js")
|
||||||
|
script(defer, src="/assets/js/swf.js")
|
||||||
|
|
Loading…
Reference in New Issue