This commit is contained in:
Hannes Mannerheim 2016-12-30 13:25:38 +01:00
parent 474376938b
commit 4dea81c506
5 changed files with 93 additions and 0 deletions

View File

@ -422,6 +422,16 @@ class QvitterPlugin extends Plugin {
}
/**
* Remove CSRF cookie on logout
*
*/
function onEndLogout($action) {
common_set_cookie('Qvitter-CSRF', '', 0);
return true;
}
/**
* Add script to default ui, to be able to toggle Qvitter with one click
@ -1285,6 +1295,24 @@ class QvitterPlugin extends Plugin {
*/
public function onEndSetApiUser($user) {
// if we're POST:ing and are logged in using a regular session (i.e. not basic auth or oauth)
// check that we have a correct csrf cookie and header, otherwise deny
if(common_logged_in() && $_SERVER['REQUEST_METHOD'] === 'POST') {
if(!isset($_COOKIE['Qvitter-CSRF'])) {
throw new ServerException(_('Error setting user. Missing authorization cookie data. Please logout and login again.'));
}
$csrf_token = sha1(common_config('qvitter', 'appid').session_id());
if($_COOKIE['Qvitter-CSRF'] != $csrf_token) {
throw new ServerException(_('Error setting user. Invalid authorization cookie data. Please logout and login again.'));
}
if(!isset($_SERVER['HTTP_X_QVITTER_CSRF'])) {
throw new ServerException(_('Error setting user. Missing authorization header data. Please logout and login again.'));
}
if($_SERVER['HTTP_X_QVITTER_CSRF'] != $csrf_token) {
throw new ServerException(_('Error setting user. Invalid authorization header data. Please logout and login again.'));
}
}
// cleanup sessions, to allow for simultaneous http-requests,
// e.g. if posting a notice takes a very long time
Session::cleanup();

View File

@ -45,6 +45,15 @@ class QvitterAction extends ApiAction
{
parent::prepare($args);
// if we're logged in but we have missing or incorrect csrf cookie, logout
if(common_logged_in()) {
$csrf_token = sha1(common_config('qvitter', 'appid').session_id());
if(!isset($_COOKIE['Qvitter-CSRF']) || $_COOKIE['Qvitter-CSRF'] != $csrf_token) {
header('Location: '.common_path('').'main/logout');
die();
}
}
$user = common_current_user();
return true;

View File

@ -112,6 +112,17 @@ class QvitterLoginAction extends FormAction
common_rememberme($user);
}
// make sure we have a unique app id for this Qvitter installation in config
// to use for creating a csrf token
if(common_config('qvitter', 'appid') == false) {
Config::save('qvitter', 'appid', sha1(common_random_hexstr(16)));
}
// set csrf-cookie
$csrf_token = sha1(common_config('qvitter', 'appid').session_id());
common_set_cookie('Qvitter-CSRF', $csrf_token, time() + 60*60*24*30); // 1 month
$url = common_get_returnto();
if ($url) {

View File

@ -334,6 +334,9 @@ function postUpdateBookmarks(newBookmarks) {
$.ajax({ url: window.apiRoot + 'qvitter/update_bookmarks.json',
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
bookmarks: bookmarksString
},
@ -358,6 +361,9 @@ function postNewLinkColor(newLinkColor) {
$.ajax({ url: window.apiRoot + 'qvitter/update_link_color.json',
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
linkcolor: newLinkColor
},
@ -383,6 +389,9 @@ function postNewBackgroundColor(newBackgroundColor) {
$.ajax({ url: window.apiRoot + 'qvitter/update_background_color.json',
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
backgroundcolor: newBackgroundColor
},
@ -412,6 +421,9 @@ function postSetProfilePref(namespace, topic, data, callback) {
$.ajax({ url: window.apiRoot + 'qvitter/set_profile_pref.json',
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
namespace: namespace,
topic: topic,
@ -448,6 +460,9 @@ function APIFollowOrUnfollowUser(followOrUnfollow,user_id,this_element,actionOnS
$.ajax({ url: window.apiRoot + postRequest,
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
user_id: user_id
},
@ -485,6 +500,9 @@ function APIBlockOrUnblockUser(blockOrUnblock,user_id,actionOnSuccess) {
$.ajax({ url: window.apiRoot + postRequest,
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
id: user_id
},
@ -515,6 +533,9 @@ function APISandboxCreateOrDestroy(createOrDestroy,userId,actionOnSuccess) {
$.ajax({ url: window.apiRoot + 'qvitter/sandbox/' + createOrDestroy + '.json',
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
id: userId
},
@ -545,6 +566,9 @@ function APISilenceCreateOrDestroy(createOrDestroy,userId,actionOnSuccess) {
$.ajax({ url: window.apiRoot + 'qvitter/silence/' + createOrDestroy + '.json',
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
id: userId
},
@ -577,6 +601,9 @@ function APIJoinOrLeaveGroup(joinOrLeave,group_id,this_element,actionOnSuccess)
$.ajax({ url: window.apiRoot + 'statusnet/groups/' + joinOrLeave + '.json',
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
id: group_id
},
@ -608,6 +635,9 @@ function postQueetToAPI(queetText_txt, in_reply_to_status_id, postToGroups, acti
$.ajax({ url: window.apiRoot + 'qvitter/statuses/update.json',
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
status: queetText_txt,
source: 'Qvitter',
@ -643,6 +673,9 @@ function postActionToAPI(action, actionOnSuccess) {
$.ajax({ url: window.apiRoot + action,
cache: false,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-Qvitter-CSRF', getCookieValue('Qvitter-CSRF'));
},
data: {
source: 'Qvitter'
},

View File

@ -37,6 +37,18 @@
· ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
/* ·
·
· Get cookie by name
·
· @param a: cookie name
·
· · · · · · · · · */
function getCookieValue(a) {
var b = document.cookie.match('(^|;)\\s*' + a + '\\s*=\\s*([^;]+)');
return b ? b.pop() : '';
}
/* ·
·