mirror of
https://github.com/Spengreb/sync.git
synced 2026-06-10 15:22:04 +00:00
Protect /api/v1 mutations with CSRF for cookie auth while exempting cbt_ bearer bot tokens and wiring UI X-CSRF-Token headers
This commit is contained in:
parent
12696452aa
commit
6eeee342d7
4 changed files with 49 additions and 1 deletions
|
|
@ -37,7 +37,9 @@ exports.init = function csrfInit (domain) {
|
||||||
|
|
||||||
exports.verify = function csrfVerify(req) {
|
exports.verify = function csrfVerify(req) {
|
||||||
var secret = req.signedCookies._csrf;
|
var secret = req.signedCookies._csrf;
|
||||||
var token = req.body._csrf || req.query._csrf;
|
var token = (req.body && req.body._csrf) ||
|
||||||
|
(req.query && req.query._csrf) ||
|
||||||
|
req.header('x-csrf-token');
|
||||||
|
|
||||||
if (!tokens.verify(secret, token)) {
|
if (!tokens.verify(secret, token)) {
|
||||||
throw new CSRFError('Invalid CSRF token');
|
throw new CSRFError('Invalid CSRF token');
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,30 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const csrf = require('../../csrf');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
function isMutatingMethod(method) {
|
||||||
|
return method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE';
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasBotBearerToken(req) {
|
||||||
|
const authHeader = req.headers && req.headers.authorization;
|
||||||
|
return typeof authHeader === 'string' && /^Bearer\s+cbt_/.test(authHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
router.use((req, res, next) => {
|
||||||
|
if (!isMutatingMethod(req.method) || hasBotBearerToken(req)) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
csrf.verify(req);
|
||||||
|
next();
|
||||||
|
} catch (_err) {
|
||||||
|
return res.status(403).json({ error: 'Invalid CSRF token' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.use('/channels/:channel/bots', require('./bots'));
|
router.use('/channels/:channel/bots', require('./bots'));
|
||||||
router.use('/channels/:channel/emotes', require('./emotes'));
|
router.use('/channels/:channel/emotes', require('./emotes'));
|
||||||
router.use('/channels/:channel/playlist', require('./playlist'));
|
router.use('/channels/:channel/playlist', require('./playlist'));
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,12 @@ mixin head()
|
||||||
var DEFAULT_THEME = '#{DEFAULT_THEME}';
|
var DEFAULT_THEME = '#{DEFAULT_THEME}';
|
||||||
var CHANNELPATH = '#{channelPath}';
|
var CHANNELPATH = '#{channelPath}';
|
||||||
var CHANNELNAME = '#{channelName}';
|
var CHANNELNAME = '#{channelName}';
|
||||||
|
var CSRF_TOKEN = '#{csrfToken}';
|
||||||
else
|
else
|
||||||
script(type="text/javascript").
|
script(type="text/javascript").
|
||||||
var DEFAULT_THEME = '#{DEFAULT_THEME}';
|
var DEFAULT_THEME = '#{DEFAULT_THEME}';
|
||||||
var CHANNELPATH = '#{channelPath}';
|
var CHANNELPATH = '#{channelPath}';
|
||||||
|
var CSRF_TOKEN = '#{csrfToken}';
|
||||||
|
|
||||||
script(src="/js/theme.js")
|
script(src="/js/theme.js")
|
||||||
//[if lt IE 9]
|
//[if lt IE 9]
|
||||||
|
|
|
||||||
21
www/js/ui.js
21
www/js/ui.js
|
|
@ -1257,6 +1257,27 @@ $("#resize-video-smaller").on('click', function () {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$.ajaxPrefilter(function (options, _originalOptions, _jqXHR) {
|
||||||
|
var url = String(options.url || '');
|
||||||
|
if (!/\/api\/v1\//.test(url)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var method = String(options.type || options.method || 'GET').toUpperCase();
|
||||||
|
if (method === 'GET' || method === 'HEAD' || method === 'OPTIONS') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.headers = options.headers || {};
|
||||||
|
if (options.headers.Authorization || options.headers.authorization) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof CSRF_TOKEN === 'string' && CSRF_TOKEN.length > 0) {
|
||||||
|
options.headers['X-CSRF-Token'] = CSRF_TOKEN;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var CSTBots = (function () {
|
var CSTBots = (function () {
|
||||||
function apiBase() {
|
function apiBase() {
|
||||||
return '/api/v1/channels/' + CHANNEL.name;
|
return '/api/v1/channels/' + CHANNEL.name;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue