This repository has been archived by the owner on Dec 20, 2023. It is now read-only.
forked from pirxpilot/liftie
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SC-598 CHORE Disable unused html routes, XSS vuln averted
- Loading branch information
Showing
1 changed file
with
159 additions
and
147 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,207 +1,219 @@ | ||
var sorter = require('./sorter'); | ||
var canonical = require('./canonical'); | ||
var plan = require('./plan'); | ||
var serviceWorker = require('./service-worker'); | ||
var headers = require('./headers'); | ||
// var sorter = require("./sorter"); | ||
var canonical = require("./canonical"); | ||
// var plan = require("./plan"); | ||
// var serviceWorker = require("./service-worker"); | ||
// var headers = require("./headers"); | ||
|
||
module.exports = routes; | ||
|
||
function title(suffix) { | ||
var t = 'Liftie'; | ||
if(suffix && suffix.length) { | ||
t += ' | ' + suffix; | ||
} | ||
return t; | ||
} | ||
|
||
|
||
function renderResorts(req, res, next) { | ||
var opts = req.opts || {}; | ||
|
||
req.data.get(req.requested, function(err, items) { | ||
var template = opts.template || 'index'; | ||
|
||
if (err) { | ||
return next(err); | ||
} | ||
if (opts.openSingle && items.length === 1) { | ||
items[0].open = true; // if single resort requested, always mark it as open | ||
res.locals.title = items[0].name; | ||
if (template !== 'widget') { | ||
res.locals.single = true; | ||
} | ||
} else { | ||
items = sorter(items, req.cookies); | ||
} | ||
res.locals.addToTrip = plan; | ||
|
||
res.render(template, { | ||
title: title(res.locals.title), | ||
all: req.data.all(), | ||
tags: req.data.tags(), | ||
resorts: items, | ||
}); | ||
}); | ||
} | ||
// Nearly the whole file has been commented out, see comment in line 198! | ||
|
||
// function title(suffix) { | ||
// var t = "Liftie"; | ||
// if (suffix && suffix.length) { | ||
// t += " | " + suffix; | ||
// } | ||
// return t; | ||
// } | ||
|
||
// function renderResorts(req, res, next) { | ||
// var opts = req.opts || {}; | ||
// | ||
// req.data.get(req.requested, function (err, items) { | ||
// var template = opts.template || "index"; | ||
// | ||
// if (err) { | ||
// return next(err); | ||
// } | ||
// if (opts.openSingle && items.length === 1) { | ||
// items[0].open = true; // if single resort requested, always mark it as open | ||
// res.locals.title = items[0].name; | ||
// if (template !== "widget") { | ||
// res.locals.single = true; | ||
// } | ||
// } else { | ||
// items = sorter(items, req.cookies); | ||
// } | ||
// res.locals.addToTrip = plan; | ||
// | ||
// res.render(template, { | ||
// title: title(res.locals.title), | ||
// all: req.data.all(), | ||
// tags: req.data.tags(), | ||
// resorts: items, | ||
// }); | ||
// }); | ||
// } | ||
|
||
/** | ||
* Handles 2 types of URIs: | ||
* / - display all resorts | ||
* /resort/<name> - display a specific resort | ||
* /?resorts=<name1>,<name2>... - display resorts on the list | ||
*/ | ||
function index(req, res, next) { | ||
req.requested = req.params.resort || req.query.resorts; | ||
req.opts = { | ||
openSingle: true | ||
}; | ||
next(); | ||
} | ||
// function index(req, res, next) { | ||
// req.requested = req.params.resort || req.query.resorts; | ||
// req.opts = { | ||
// openSingle: true, | ||
// }; | ||
// next(); | ||
// } | ||
|
||
/** | ||
* Display a single resort as a widget | ||
*/ | ||
function widget(req, res, next) { | ||
var requested = req.params.resort; | ||
if (req.query.style === 'naked') { | ||
res.locals.widgetStyle = 'naked'; | ||
} | ||
req.opts = { | ||
openSingle: true, | ||
template: 'widget' | ||
}; | ||
req.requested = requested.split(',')[0]; // only one resort allowed | ||
next(); | ||
} | ||
// function widget(req, res, next) { | ||
// var requested = req.params.resort; | ||
// if (req.query.style === "naked") { | ||
// res.locals.widgetStyle = "naked"; | ||
// } | ||
// req.opts = { | ||
// openSingle: true, | ||
// template: "widget", | ||
// }; | ||
// req.requested = requested.split(",")[0]; // only one resort allowed | ||
// next(); | ||
// } | ||
|
||
/** | ||
* Handles | ||
* /stars - display starred subset of resorts | ||
*/ | ||
function stars(req, res, next) { | ||
req.requested = req.cookies['resorts-starred']; | ||
res.locals.title = 'Stars'; | ||
next(); | ||
} | ||
// function stars(req, res, next) { | ||
// req.requested = req.cookies["resorts-starred"]; | ||
// res.locals.title = "Stars"; | ||
// next(); | ||
// } | ||
|
||
/** | ||
* Handles /tag/<tag> URIs | ||
*/ | ||
function tag(req, res, next) { | ||
res.locals.title = req.tag.label; | ||
next(); | ||
} | ||
|
||
function about(req, res) { | ||
res.render('about', { | ||
title: title('About') | ||
}); | ||
} | ||
|
||
function sitemap(req, res) { | ||
res.contentType('application/xml'); | ||
res.render('sitemap', { | ||
resorts: req.data.all(true) | ||
}); | ||
} | ||
|
||
function absent(req, res, next) { | ||
req.requested = req.data.filtered(function(resort) { | ||
var hasLists = resort.lifts && resort.lifts.status && Object.keys(resort.lifts.status).length; | ||
return !hasLists; | ||
}); | ||
res.locals.title = 'Absent'; | ||
next(); | ||
} | ||
|
||
function confused(req, res, next) { | ||
req.requested = req.data.filtered(function(resort) { | ||
return resort.opening && resort.lifts.stats && resort.lifts.stats.open; | ||
}); | ||
res.locals.title = 'Confused'; | ||
next(); | ||
} | ||
|
||
function closed(req, res, next) { | ||
req.requested = req.data.filtered(function(resort) { | ||
return resort.opening; | ||
}); | ||
res.locals.title = 'Closed'; | ||
next(); | ||
} | ||
|
||
function stats(req, res) { | ||
var t = req.tag; | ||
res.render('stats', { | ||
title: title('Statistics'), | ||
sectionLink: t ? '/tag/' + t.slug : '/', | ||
sectionTitle: t ? t.label : 'All Lifts', | ||
stats: req.data.stats(req.requested) | ||
}); | ||
} | ||
// function tag(req, res, next) { | ||
// res.locals.title = req.tag.label; | ||
// next(); | ||
// } | ||
|
||
// function about(req, res) { | ||
// res.render("about", { | ||
// title: title("About"), | ||
// }); | ||
// } | ||
|
||
// function sitemap(req, res) { | ||
// res.contentType("application/xml"); | ||
// res.render("sitemap", { | ||
// resorts: req.data.all(true), | ||
// }); | ||
// } | ||
|
||
// function absent(req, res, next) { | ||
// req.requested = req.data.filtered(function (resort) { | ||
// var hasLists = | ||
// resort.lifts && | ||
// resort.lifts.status && | ||
// Object.keys(resort.lifts.status).length; | ||
// return !hasLists; | ||
// }); | ||
// res.locals.title = "Absent"; | ||
// next(); | ||
// } | ||
|
||
// function confused(req, res, next) { | ||
// req.requested = req.data.filtered(function (resort) { | ||
// return resort.opening && resort.lifts.stats && resort.lifts.stats.open; | ||
// }); | ||
// res.locals.title = "Confused"; | ||
// next(); | ||
// } | ||
|
||
// function closed(req, res, next) { | ||
// req.requested = req.data.filtered(function (resort) { | ||
// return resort.opening; | ||
// }); | ||
// res.locals.title = "Closed"; | ||
// next(); | ||
// } | ||
|
||
// function stats(req, res) { | ||
// var t = req.tag; | ||
// res.render("stats", { | ||
// title: title("Statistics"), | ||
// sectionLink: t ? "/tag/" + t.slug : "/", | ||
// sectionTitle: t ? t.label : "All Lifts", | ||
// stats: req.data.stats(req.requested), | ||
// }); | ||
// } | ||
|
||
function api(req, res, next) { | ||
req.data.get(req.params.resort, function(err, resorts) { | ||
if(err) { | ||
req.data.get(req.params.resort, function (err, resorts) { | ||
if (err) { | ||
return next(err); | ||
} | ||
if(resorts.length !== 1) { | ||
return res.send(404, 'Invalid resort name: ' + req.params.resort); | ||
if (resorts.length !== 1) { | ||
return res.send(404, "Invalid resort name: " + req.params.resort); | ||
} | ||
// do not cache API responses | ||
res.header('Cache-Control', 'no-cache, max-age=0, must-revalidate'); | ||
res.header("Cache-Control", "no-cache, max-age=0, must-revalidate"); | ||
res.send(resorts[0]); | ||
}); | ||
} | ||
|
||
function meta(req, res, next) { | ||
req.data.meta(function(err, resorts) { | ||
if(err) { | ||
req.data.meta(function (err, resorts) { | ||
if (err) { | ||
return next(err); | ||
} | ||
res.header('Cache-Control', 'public, max-age=86400'); // good for 24hours | ||
res.header("Cache-Control", "public, max-age=86400"); // good for 24hours | ||
res.send(resorts); | ||
}); | ||
} | ||
|
||
function routes(app) { | ||
|
||
function reqData(req, res, next) { | ||
req.data = app.data; | ||
next(); | ||
} | ||
|
||
app.param('tag', function(req, res, next, t) { | ||
app.param("tag", function (req, res, next, t) { | ||
var data = app.data, | ||
tags = data.tags(), | ||
requested = tags[t] && tags[t].members; | ||
if(!requested) { | ||
if (!requested) { | ||
t = canonical(t); | ||
if(tags[t]) { | ||
if (tags[t]) { | ||
// permanent redirect to canonical form of the tag | ||
return res.redirect(301, '/tag/' + t); | ||
return res.redirect(301, "/tag/" + t); | ||
} | ||
return res.send(404, 'Invalid tag name: ' + req.params.tag); | ||
return res.send(404, "Invalid tag name: " + req.params.tag); | ||
} | ||
req.requested = requested; | ||
req.tag = tags[t]; | ||
res.locals.tag = t; | ||
next(); | ||
}); | ||
|
||
app.get('/', reqData, headers, index, renderResorts); | ||
app.get('/resort/:resort', reqData, headers, index, renderResorts); | ||
app.get('/widget/resort/:resort', reqData, headers, widget, renderResorts); | ||
app.get('/tag/:tag', reqData, headers, tag, renderResorts); | ||
app.get('/stars', reqData, headers, stars, renderResorts); | ||
app.get('/api/resort/:resort', reqData, api); | ||
app.get('/api/meta', reqData, meta); | ||
app.get('/sitemap.xml', reqData, sitemap); | ||
app.get('/about', headers, about); | ||
app.get('/absent', reqData, headers, absent, renderResorts); | ||
app.get('/confused', reqData, headers, confused, renderResorts); | ||
app.get('/closed', reqData, headers, closed, renderResorts); | ||
app.get('/stats/:tag', reqData, headers, stats); | ||
app.get('/stats', reqData, headers, stats); | ||
app.get('/sw.js', serviceWorker); | ||
app.get("/api/resort/:resort", reqData, api); | ||
app.get("/api/meta", reqData, meta); | ||
|
||
// We (FATMAP) don't need the html version of this site, since we only use | ||
// the API as part of our live status service. There's a theoretical XSS | ||
// injection attack inherent in rendering html that has been scraped from | ||
// external sources, so we're disabling the html pages entirely. | ||
// See https://strava.atlassian.net/browse/SC-598 | ||
// | ||
// app.get('/', reqData, headers, index, renderResorts); | ||
// app.get('/resort/:resort', reqData, headers, index, renderResorts); | ||
// app.get('/widget/resort/:resort', reqData, headers, widget, renderResorts); | ||
// app.get('/tag/:tag', reqData, headers, tag, renderResorts); | ||
// app.get('/stars', reqData, headers, stars, renderResorts); | ||
// app.get('/absent', reqData, headers, absent, renderResorts); | ||
// app.get('/confused', reqData, headers, confused, renderResorts); | ||
// app.get('/closed', reqData, headers, closed, renderResorts); | ||
// | ||
// These are probably less risky but also unnecessary so might as well turn them off too: | ||
// app.get("/sitemap.xml", reqData, sitemap); | ||
// app.get("/about", headers, about); | ||
// app.get("/stats/:tag", reqData, headers, stats); | ||
// app.get("/stats", reqData, headers, stats); | ||
// app.get("/sw.js", serviceWorker); | ||
} |