X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=actions%2Fuserauthorization.php;h=6208113981d313ec4e87c8570c018ab05f58b3cb;hb=2dc50d7e3768548c78f095903388d53a5bee373f;hp=6a49af82583e88bb4893dda0dcc313390f98abda;hpb=d251e624a9885fdd5ca9a3de446071606c1ac54d;p=quix0rs-gnu-social.git diff --git a/actions/userauthorization.php b/actions/userauthorization.php index 6a49af8258..6208113981 100644 --- a/actions/userauthorization.php +++ b/actions/userauthorization.php @@ -23,40 +23,50 @@ require_once(INSTALLDIR.'/lib/omb.php'); define('TIMESTAMP_THRESHOLD', 300); class UserauthorizationAction extends Action { + function handle($args) { parent::handle($args); - + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + # CSRF protection + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $req = $this->get_stored_request(); + $this->show_form(_('There was a problem with your session token. Try again, please.'), $req); + return; + } # We've shown the form, now post user's choice $this->send_authorization(); } else { + if (!common_logged_in()) { + # Go log in, and then come back + common_debug('saving URL for returnto', __FILE__); + $argsclone = $_GET; + unset($argsclone['action']); + common_set_returnto(common_local_url('userauthorization', $argsclone)); + common_debug('redirecting to login', __FILE__); + common_redirect(common_local_url('login')); + return; + } try { - common_debug('userauthorization.php - fetching request'); - # We get called after login if we have a stored request - $req = $this->get_stored_request(); + # this must be a new request + common_debug('getting new request', __FILE__); + $req = $this->get_new_request(); if (!$req) { - # this must be a new request - $req = $this->get_new_request(); - # XXX: only validate new requests, since nonce is one-time use - $this->validate_request($req); - } - if (!$req) { - common_server_error(_t('No request found!')); + $this->client_error(_('No request found!')); } + common_debug('validating request', __FILE__); + # XXX: only validate new requests, since nonce is one-time use + $this->validate_request($req); + common_debug('showing form', __FILE__); + $this->store_request($req); + $this->show_form($req); } catch (OAuthException $e) { $this->clear_request(); - common_server_error($e->getMessage()); + $this->client_error($e->getMessage()); return; } - - if (common_logged_in()) { - $this->show_form($req); - } else { - # Go log in, and then come back - $this->store_request($req); - common_set_returnto(common_local_url('userauthorization')); - common_redirect(common_local_url('login')); - } + } } @@ -70,12 +80,12 @@ class UserauthorizationAction extends Action { $bio = $req->get_parameter('omb_listenee_bio'); $location = $req->get_parameter('omb_listenee_location'); $avatar = $req->get_parameter('omb_listenee_avatar'); - - common_show_header(_t('Authorize subscription')); - common_element('p', _t('Please check these details to make sure '. - 'that you want to subscribe to this user\'s notices. '. - 'If you didn\'t just ask to subscribe to someone\'s notices, '. - 'click "Cancel".')); + + common_show_header(_('Authorize subscription')); + common_element('p', NULL, _('Please check these details to make sure '. + 'that you want to subscribe to this user\'s notices. '. + 'If you didn\'t just ask to subscribe to someone\'s notices, '. + 'click "Cancel".')); common_element_start('div', 'profile'); if ($avatar) { common_element('img', array('src' => $avatar, @@ -109,29 +119,34 @@ class UserauthorizationAction extends Action { $license); common_element_end('div'); common_element_end('div'); - common_element_start('form', array('method' => 'POST', + common_element_start('form', array('method' => 'post', 'id' => 'userauthorization', 'name' => 'userauthorization', 'action' => common_local_url('userauthorization'))); - common_submit('accept', _t('Accept')); - common_submit('reject', _t('Reject')); + common_hidden('token', common_session_token()); + common_submit('accept', _('Accept')); + common_submit('reject', _('Reject')); common_element_end('form'); common_show_footer(); } - + function send_authorization() { $req = $this->get_stored_request(); - + if (!$req) { - common_user_error(_t('No authorization request!')); + common_user_error(_('No authorization request!')); return; } $callback = $req->get_parameter('oauth_callback'); if ($this->arg('accept')) { - $this->authorize_token($req); - $this->save_remote_profile($req); + if (!$this->authorize_token($req)) { + $this->client_error(_('Error authorizing token')); + } + if (!$this->save_remote_profile($req)) { + $this->client_error(_('Error saving remote profile')); + } if (!$callback) { $this->show_accept_message($req->get_parameter('oauth_token')); } else { @@ -179,15 +194,22 @@ class UserauthorizationAction extends Action { } function authorize_token(&$req) { - $consumer_key = @$req->get_parameter('oauth_consumer_key'); - $token_field = @$req->get_parameter('oauth_token'); + $consumer_key = $req->get_parameter('oauth_consumer_key'); + $token_field = $req->get_parameter('oauth_token'); + common_debug('consumer key = "'.$consumer_key.'"', __FILE__); + common_debug('token field = "'.$token_field.'"', __FILE__); $rt = new Token(); $rt->consumer_key = $consumer_key; $rt->tok = $token_field; - if ($rt->find(TRUE)) { + $rt->type = 0; + $rt->state = 0; + common_debug('request token to look up: "'.print_r($rt,TRUE).'"'); + if ($rt->find(true)) { + common_debug('found request token to authorize', __FILE__); $orig_rt = clone($rt); $rt->state = 1; # Authorized but not used if ($rt->update($orig_rt)) { + common_debug('updated request token so it is authorized', __FILE__); return true; } } @@ -195,22 +217,23 @@ class UserauthorizationAction extends Action { } # XXX: refactor with similar code in finishremotesubscribe.php - + function save_remote_profile(&$req) { # FIXME: we should really do this when the consumer comes - # back for an access token. If they never do, we've got stuff in a + # back for an access token. If they never do, we've got stuff in a # weird state. - + + $nickname = $req->get_parameter('omb_listenee_nickname'); $fullname = $req->get_parameter('omb_listenee_fullname'); - $profile_url = $req->get_parameter('omb_listenee_profile'); + $profile_url = $req->get_parameter('omb_listenee_profile'); $homepage = $req->get_parameter('omb_listenee_homepage'); $bio = $req->get_parameter('omb_listenee_bio'); $location = $req->get_parameter('omb_listenee_location'); $avatar_url = $req->get_parameter('omb_listenee_avatar'); - + $listenee = $req->get_parameter('omb_listenee'); $remote = Remote_profile::staticGet('uri', $listenee); - + if ($remote) { $exists = true; $profile = Profile::staticGet($remote->id); @@ -219,13 +242,13 @@ class UserauthorizationAction extends Action { } else { $exists = false; $remote = new Remote_profile(); - $remote->uri = $omb['listener']; + $remote->uri = $listenee; $profile = new Profile(); } $profile->nickname = $nickname; $profile->profileurl = $profile_url; - + if ($fullname) { $profile->fullname = $fullname; } @@ -238,24 +261,33 @@ class UserauthorizationAction extends Action { if ($location) { $profile->location = $location; } - + if ($exists) { $profile->update($orig_profile); } else { $profile->created = DB_DataObject_Cast::dateTime(); # current time $id = $profile->insert(); + if (!$id) { + return FALSE; + } $remote->id = $id; } - if ($avatar_url) { - $this->add_avatar($avatar_url); - } - if ($exists) { - $remote->update($orig_remote); + if (!$remote->update($orig_remote)) { + return FALSE; + } } else { $remote->created = DB_DataObject_Cast::dateTime(); # current time - $remote->insert(); + if (!$remote->insert()) { + return FALSE; + } + } + + if ($avatar_url) { + if (!$this->add_avatar($profile, $avatar_url)) { + return FALSE; + } } $user = common_current_user(); @@ -268,17 +300,24 @@ class UserauthorizationAction extends Action { $sub->subscribed = $remote->id; $sub->token = $token->key; # NOTE: request token, not valid for use! $sub->created = DB_DataObject_Cast::dateTime(); # current time - + if (!$sub->insert()) { - common_user_error(_t('Couldn\'t insert new subscription.')); - return; + return FALSE; } + + return TRUE; } - + + function add_avatar($profile, $url) { + $temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar'); + copy($url, $temp_filename); + return $profile->setOriginal($temp_filename); + } + function show_accept_message($tok) { - common_show_header(_t('Subscription authorized')); - common_element('p', NULL, - _t('The subscription has been authorized, but no '. + common_show_header(_('Subscription authorized')); + common_element('p', NULL, + _('The subscription has been authorized, but no '. 'callback URL was passed. Check with the site\'s instructions for '. 'details on how to authorize the subscription. Your subscription token is:')); common_element('blockquote', 'token', $tok); @@ -286,47 +325,57 @@ class UserauthorizationAction extends Action { } function show_reject_message($tok) { - common_show_header(_t('Subscription rejected')); - common_element('p', NULL, - _t('The subscription has been rejected, but no '. + common_show_header(_('Subscription rejected')); + common_element('p', NULL, + _('The subscription has been rejected, but no '. 'callback URL was passed. Check with the site\'s instructions for '. 'details on how to fully reject the subscription.')); common_show_footer(); } - + function store_request($req) { common_ensure_session(); $_SESSION['userauthorizationrequest'] = $req; } - - function clear_request($req) { + + function clear_request() { common_ensure_session(); unset($_SESSION['userauthorizationrequest']); } - + function get_stored_request() { - common_ensure_session(); + common_ensure_session(); $req = $_SESSION['userauthorizationrequest']; return $req; } function get_new_request() { $req = OAuthRequest::from_request(); + return $req; } - + # Throws an OAuthException if anything goes wrong - - function validate_request($req) { + + function validate_request(&$req) { # OAuth stuff -- have to copy from OAuth.php since they're # all private methods, and there's no user-authentication method + common_debug('checking version', __FILE__); $this->check_version($req); + common_debug('getting datastore', __FILE__); $datastore = omb_oauth_datastore(); + common_debug('getting consumer', __FILE__); $consumer = $this->get_consumer($datastore, $req); + common_debug('getting token', __FILE__); $token = $this->get_token($datastore, $req, $consumer); + common_debug('checking timestamp', __FILE__); $this->check_timestamp($req); + common_debug('checking nonce', __FILE__); $this->check_nonce($datastore, $req, $consumer, $token); + common_debug('checking signature', __FILE__); $this->check_signature($req, $consumer, $token); + common_debug('validating omb stuff', __FILE__); $this->validate_omb($req); + common_debug('done validating', __FILE__); return true; } @@ -344,16 +393,32 @@ class UserauthorizationAction extends Action { if ($version != OMB_VERSION_01) { throw new OAuthException("OpenMicroBlogging version '$version' not supported"); } - $user = User::staticGet('uri', $req->get_parameter('omb_listener')); + $listener = $req->get_parameter('omb_listener'); + $user = User::staticGet('uri', $listener); if (!$user) { throw new OAuthException("Listener URI '$listener' not found here"); } + $cur = common_current_user(); + if ($cur->id != $user->id) { + throw new OAuthException("Can't add for another user!"); + } $listenee = $req->get_parameter('omb_listenee'); - if (!Validate::uri($listenee)) { - throw new OAuthException("Listenee URI '$listenee' not a valid URI"); - } else if (strlen($listenee) > 255) { + if (!Validate::uri($listenee) && + !common_valid_tag($listenee)) { + throw new OAuthException("Listenee URI '$listenee' not a recognizable URI"); + } + if (strlen($listenee) > 255) { throw new OAuthException("Listenee URI '$listenee' too long"); } + $remote = Remote_profile::staticGet('uri', $listenee); + if ($remote) { + $sub = new Subscription(); + $sub->subscriber = $user->id; + $sub->subscribed = $remote->id; + if ($sub->find(TRUE)) { + throw new OAuthException("Already subscribed to user!"); + } + } $nickname = $req->get_parameter('omb_listenee_nickname'); if (!Validate::string($nickname, array('min_length' => 1, 'max_length' => 64, @@ -386,18 +451,31 @@ class UserauthorizationAction extends Action { throw new OAuthException("Location too long '$location'"); } $avatar = $req->get_parameter('omb_listenee_avatar'); - if ($avatar && (!common_valid_http_url($avatar) || strlen($avatar) > 255)) { - throw new OAuthException("Invalid avatar '$avatar'"); + if ($avatar) { + if (!common_valid_http_url($avatar) || strlen($avatar) > 255) { + throw new OAuthException("Invalid avatar URL '$avatar'"); + } + $size = @getimagesize($avatar); + if (!$size) { + throw new OAuthException("Can't read avatar URL '$avatar'"); + } + if ($size[0] != AVATAR_PROFILE_SIZE || $size[1] != AVATAR_PROFILE_SIZE) { + throw new OAuthException("Wrong size image at '$avatar'"); + } + if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG, + IMAGETYPE_PNG))) { + throw new OAuthException("Wrong image type for '$avatar'"); + } } $callback = $req->get_parameter('oauth_callback'); - if ($avatar && common_valid_http_url($callback)) { + if ($callback && !common_valid_http_url($callback)) { throw new OAuthException("Invalid callback URL '$callback'"); } } - + # Snagged from OAuthServer - - function check_version($req) { + + function check_version(&$req) { $version = $req->get_parameter("oauth_version"); if (!$version) { $version = 1.0; @@ -409,13 +487,13 @@ class UserauthorizationAction extends Action { } # Snagged from OAuthServer - + function get_consumer($datastore, $req) { $consumer_key = @$req->get_parameter("oauth_consumer_key"); if (!$consumer_key) { throw new OAuthException("Invalid consumer key"); } - + $consumer = $datastore->lookup_consumer($consumer_key); if (!$consumer) { throw new OAuthException("Invalid consumer"); @@ -424,8 +502,8 @@ class UserauthorizationAction extends Action { } # Mostly cadged from OAuthServer - - function get_token(&$req, $consumer, $datastore) {/*{{{*/ + + function get_token($datastore, &$req, $consumer) {/*{{{*/ $token_field = @$req->get_parameter('oauth_token'); $token = $datastore->lookup_token($consumer, 'request', $token_field); if (!$token) { @@ -433,7 +511,7 @@ class UserauthorizationAction extends Action { } return $token; } - + function check_timestamp(&$req) { $timestamp = @$req->get_parameter('oauth_timestamp'); $now = time(); @@ -452,19 +530,19 @@ class UserauthorizationAction extends Action { } return true; } - + function check_signature(&$req, $consumer, $token) { $signature_method = $this->get_signature_method($req); - $signature = $req->get_parameter('oauth_signature'); - $valid_sig = $signature_method->check_signature($req, - $consumer, - $token, + $signature = $req->get_parameter('oauth_signature'); + $valid_sig = $signature_method->check_signature($req, + $consumer, + $token, $signature); if (!$valid_sig) { throw new OAuthException("Invalid signature"); } } - + function get_signature_method(&$req) { $signature_method = @$req->get_parameter("oauth_signature_method"); if (!$signature_method) {