We are no longer offering accounts on this server. Consider https://gitlab.freedesktop.org/ as a place to host projects.

Commit ec88d265 authored by Adrian Lang's avatar Adrian Lang

Replace own OMB stack with libomb.

parent ee9bfa71
<?php
/**
* Access token class.
* Access token class
*
* PHP version 5
*
......@@ -32,10 +32,11 @@ if (!defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
require_once INSTALLDIR.'/lib/omb.php';
/**
* Access token class.
* Access token class
*
* @category Action
* @package Laconica
......@@ -47,28 +48,23 @@ require_once INSTALLDIR.'/lib/omb.php';
class AccesstokenAction extends Action
{
/**
* Class handler.
* Class handler
*
* @param array $args query arguments
*
* @return boolean false if user doesn't exist
*/
* @return nothing
*
**/
function handle($args)
{
parent::handle($args);
try {
common_debug('getting request from env variables', __FILE__);
common_remove_magic_from_request();
$req = OAuthRequest::from_request('POST', common_local_url('accesstoken'));
common_debug('getting a server', __FILE__);
$server = omb_oauth_server();
common_debug('fetching the access token', __FILE__);
$token = $server->fetch_access_token($req);
common_debug('got this token: "'.print_r($token, true).'"', __FILE__);
common_debug('printing the access token', __FILE__);
print $token;
} catch (OAuthException $e) {
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
omb_oauth_server());
$srv->writeAccessToken();
} catch (Exception $e) {
$this->serverError($e->getMessage());
}
}
}
?>
<?php
/*
/**
* Handler for remote subscription finish callback
*
* PHP version 5
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Robin Millette <millette@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2008, 2009, Control Yourself, Inc.
*
......@@ -15,285 +26,116 @@
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
**/
if (!defined('LACONICA')) { exit(1); }
if (!defined('LACONICA')) {
exit(1);
}
require_once(INSTALLDIR.'/lib/omb.php');
require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
require_once INSTALLDIR.'/lib/omb.php';
/**
* Handler for remote subscription finish callback
*
* When a remote user subscribes a local user, a redirect to this action is
* issued after the remote user authorized his service to subscribe.
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Robin Millette <millette@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*/
class FinishremotesubscribeAction extends Action
{
/**
* Class handler.
*
* @param array $args query arguments
*
* @return nothing
*
**/
function handle($args)
{
parent::handle($args);
if (common_logged_in()) {
$this->clientError(_('You can use the local subscription!'));
return;
}
$omb = $_SESSION['oauth_authorization_request'];
/* Restore session data. RemotesubscribeAction should have stored
this entry. */
$service = unserialize($_SESSION['oauth_authorization_request']);
if (!$omb) {
if (!$service) {
$this->clientError(_('Not expecting this response!'));
return;
}
common_debug('stored request: '.print_r($omb,true), __FILE__);
common_remove_magic_from_request();
$req = OAuthRequest::from_request('POST', common_local_url('finishuserauthorization'));
common_debug('stored request: '. print_r($service, true), __FILE__);
$token = $req->get_parameter('oauth_token');
# I think this is the success metric
if ($token != $omb['token']) {
$this->clientError(_('Not authorized.'));
return;
}
$version = $req->get_parameter('omb_version');
if ($version != OMB_VERSION_01) {
$this->clientError(_('Unknown version of OMB protocol.'));
return;
}
$nickname = $req->get_parameter('omb_listener_nickname');
if (!$nickname) {
$this->clientError(_('No nickname provided by remote server.'));
return;
}
$profile_url = $req->get_parameter('omb_listener_profile');
if (!$profile_url) {
$this->clientError(_('No profile URL returned by server.'));
return;
}
if (!Validate::uri($profile_url, array('allowed_schemes' => array('http', 'https')))) {
$this->clientError(_('Invalid profile URL returned by server.'));
return;
}
if ($profile_url == common_local_url('showstream', array('nickname' => $nickname))) {
$this->clientError(_('You can use the local subscription!'));
return;
}
common_debug('listenee: "'.$omb['listenee'].'"', __FILE__);
$user = User::staticGet('nickname', $omb['listenee']);
/* Create user objects for both users. Do it early for request
validation. */
$listenee = $service->getListeneeURI();
$user = User::staticGet('uri', $listenee);
if (!$user) {
$this->clientError(_('User being listened to doesn\'t exist.'));
return;
}
$other = User::staticGet('uri', $omb['listener']);
$other = User::staticGet('uri', $service->getListenerURI());
if ($other) {
$this->clientError(_('You can use the local subscription!'));
return;
}
$fullname = $req->get_parameter('omb_listener_fullname');
$homepage = $req->get_parameter('omb_listener_homepage');
$bio = $req->get_parameter('omb_listener_bio');
$location = $req->get_parameter('omb_listener_location');
$avatar_url = $req->get_parameter('omb_listener_avatar');
list($newtok, $newsecret) = $this->access_token($omb);
if (!$newtok || !$newsecret) {
$this->clientError(_('Couldn\'t convert request tokens to access tokens.'));
return;
}
# XXX: possible attack point; subscribe and return someone else's profile URI
$remote = Remote_profile::staticGet('uri', $omb['listener']);
if ($remote) {
$exists = true;
$profile = Profile::staticGet($remote->id);
$orig_remote = clone($remote);
$orig_profile = clone($profile);
# XXX: compare current postNotice and updateProfile URLs to the ones
# stored in the DB to avoid (possibly...) above attack
} else {
$exists = false;
$remote = new Remote_profile();
$remote->uri = $omb['listener'];
$profile = new Profile();
}
$profile->nickname = $nickname;
$profile->profileurl = $profile_url;
if (!is_null($fullname)) {
$profile->fullname = $fullname;
}
if (!is_null($homepage)) {
$profile->homepage = $homepage;
}
if (!is_null($bio)) {
$profile->bio = $bio;
}
if (!is_null($location)) {
$profile->location = $location;
}
if ($exists) {
$profile->update($orig_profile);
} else {
$profile->created = DB_DataObject_Cast::dateTime(); # current time
$id = $profile->insert();
if (!$id) {
$this->serverError(_('Error inserting new profile'));
return;
}
$remote->id = $id;
}
if ($avatar_url) {
if (!$this->add_avatar($profile, $avatar_url)) {
$this->serverError(_('Error inserting avatar'));
return;
}
}
$remote->postnoticeurl = $omb['post_notice_url'];
$remote->updateprofileurl = $omb['update_profile_url'];
if ($exists) {
if (!$remote->update($orig_remote)) {
$this->serverError(_('Error updating remote profile'));
/* Perform the handling itself via libomb. */
try {
$service->finishAuthorization($listenee);
} catch (OAuthException $e) {
if ($e->getMessage() == 'The authorized token does not equal the ' .
'submitted token.') {
$this->clientError(_('Not authorized.'));
return;
}
} else {
$remote->created = DB_DataObject_Cast::dateTime(); # current time
if (!$remote->insert()) {
$this->serverError(_('Error inserting remote profile'));
} else {
$this->clientError(_('Couldn\'t convert request token to ' .
'access token.'));
return;
}
}
if ($user->hasBlocked($profile)) {
$this->clientError(_('That user has blocked you from subscribing.'));
} catch (OMB_RemoteServiceException $e) {
$this->clientError(_('Unknown version of OMB protocol.'));
return;
} catch (Exception $e) {
common_debug('Got exception ' . print_r($e, true), __FILE__);
$this->clientError($e->getMessage());
return;
}
$sub = new Subscription();
/* The service URLs are not accessible from datastore, so setting them
after insertion of the profile. */
$remote = Remote_profile::staticGet('uri', $service->getListenerURI());
$sub->subscriber = $remote->id;
$sub->subscribed = $user->id;
$orig_remote = clone($remote);
$sub_exists = false;
$remote->postnoticeurl =
$service->getServiceURI(OMB_ENDPOINT_POSTNOTICE);
$remote->updateprofileurl =
$service->getServiceURI(OMB_ENDPOINT_UPDATEPROFILE);
if ($sub->find(true)) {
$sub_exists = true;
$orig_sub = clone($sub);
} else {
$sub_exists = false;
$sub->created = DB_DataObject_Cast::dateTime(); # current time
}
$sub->token = $newtok;
$sub->secret = $newsecret;
if ($sub_exists) {
$result = $sub->update($orig_sub);
} else {
$result = $sub->insert();
}
if (!$result) {
common_log_db_error($sub, ($sub_exists) ? 'UPDATE' : 'INSERT', __FILE__);
$this->clientError(_('Couldn\'t insert new subscription.'));
return;
if (!$remote->update($orig_remote)) {
$this->serverError(_('Error updating remote profile'));
return;
}
# Notify user, if necessary
mail_subscribe_notify_profile($user, $profile);
# Clear the data
/* Clear the session data. */
unset($_SESSION['oauth_authorization_request']);
# If we show subscriptions in reverse chron order, this should
# show up close to the top of the page
/* If we show subscriptions in reverse chronological order, the new one
should show up close to the top of the page. */
common_redirect(common_local_url('subscribers', array('nickname' =>
$user->nickname)),
303);
}
function add_avatar($profile, $url)
{
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
copy($url, $temp_filename);
$imagefile = new ImageFile($profile->id, $temp_filename);
$filename = Avatar::filename($profile->id,
image_type_to_extension($imagefile->type),
null,
common_timestamp());
rename($temp_filename, Avatar::path($filename));
return $profile->setOriginal($filename);
}
function access_token($omb)
{
common_debug('starting request for access token', __FILE__);
$con = omb_oauth_consumer();
$tok = new OAuthToken($omb['token'], $omb['secret']);
common_debug('using request token "'.$tok.'"', __FILE__);
$url = $omb['access_token_url'];
common_debug('using access token url "'.$url.'"', __FILE__);
# XXX: Is this the right thing to do? Strip off GET params and make them
# POST params? Seems wrong to me.
$parsed = parse_url($url);
$params = array();
parse_str($parsed['query'], $params);
$req = OAuthRequest::from_consumer_and_token($con, $tok, "POST", $url, $params);
$req->set_parameter('omb_version', OMB_VERSION_01);
# XXX: test to see if endpoint accepts this signature method
$req->sign_request(omb_hmac_sha1(), $con, $tok);
# We re-use this tool's fetcher, since it's pretty good
common_debug('posting to access token url "'.$req->get_normalized_http_url().'"', __FILE__);
common_debug('posting request data "'.$req->to_postdata().'"', __FILE__);
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(),
array('User-Agent: Laconica/' . LACONICA_VERSION));
common_debug('got result: "'.print_r($result,true).'"', __FILE__);
if ($result->status != 200) {
return null;
}
parse_str($result->body, $return);
return array($return['oauth_token'], $return['oauth_token_secret']);
}
}
<?php
/*
/**
* Handle postnotice action
*
* PHP version 5
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Robin Millette <millette@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2008, 2009, Control Yourself, Inc.
*
......@@ -17,75 +28,49 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('LACONICA')) { exit(1); }
if (!defined('LACONICA')) {
exit(1);
}
require_once(INSTALLDIR.'/lib/omb.php');
require_once INSTALLDIR.'/lib/omb.php';
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
/**
* Handler for postnotice action
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Robin Millette <millette@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*/
class PostnoticeAction extends Action
{
function handle($args)
{
parent::handle($args);
if (!$this->checkNotice()) {
return;
}
try {
common_remove_magic_from_request();
$req = OAuthRequest::from_request('POST', common_local_url('postnotice'));
# Note: server-to-server function!
$server = omb_oauth_server();
list($consumer, $token) = $server->verify_request($req);
if ($this->save_notice($req, $consumer, $token)) {
print "omb_version=".OMB_VERSION_01;
}
} catch (OAuthException $e) {
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
omb_oauth_server());
$srv->handlePostNotice();
} catch (Exception $e) {
$this->serverError($e->getMessage());
return;
}
}
function save_notice(&$req, &$consumer, &$token)
function checkNotice()
{
$version = $req->get_parameter('omb_version');
if ($version != OMB_VERSION_01) {
$this->clientError(_('Unsupported OMB version'), 400);
return false;
}
# First, check to see
$listenee = $req->get_parameter('omb_listenee');
$remote_profile = Remote_profile::staticGet('uri', $listenee);
if (!$remote_profile) {
$this->clientError(_('Profile unknown'), 403);
return false;
}
$sub = Subscription::staticGet('token', $token->key);
if (!$sub) {
$this->clientError(_('No such subscription'), 403);
return false;
}
$content = $req->get_parameter('omb_notice_content');
$content_shortened = common_shorten_links($content);
if (mb_strlen($content_shortened) > 140) {
$content = common_shorten_links($_POST['omb_notice_content']);
if (mb_strlen($content) > 140) {
$this->clientError(_('Invalid notice content'), 400);
return false;
}
$notice_uri = $req->get_parameter('omb_notice');
if (!Validate::uri($notice_uri) &&
!common_valid_tag($notice_uri)) {
$this->clientError(_('Invalid notice uri'), 400);
return false;
}
$notice_url = $req->get_parameter('omb_notice_url');
if ($notice_url && !common_valid_http_url($notice_url)) {
$this->clientError(_('Invalid notice url'), 400);
return false;
}
$notice = Notice::staticGet('uri', $notice_uri);
if (!$notice) {
$notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri);
if (is_string($notice)) {
common_server_serror($notice, 500);
return false;
}
common_broadcast_notice($notice, true);
}
return true;
}
}
?>
<?php
/*
/**
* Handler for remote subscription
*
* PHP version 5
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Robin Millette <millette@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2008, 2009, Control Yourself, Inc.
*
......@@ -15,11 +26,26 @@
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
**/
if (!defined('LACONICA')) { exit(1); }
if (!defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/omb.php';
require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
require_once INSTALLDIR.'/extlib/libomb/profile.php';
require_once(INSTALLDIR.'/lib/omb.php');
/**
* Handler for remote subscription
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Robin Millette <millette@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*/
class RemotesubscribeAction extends Action
{
......@@ -36,7 +62,7 @@ class RemotesubscribeAction extends Action
return false;
}
$this->nickname = $this->trimmed('nickname');
$this->nickname = $this->trimmed('nickname');
$this->profile_url = $this->trimmed('profile_url');
return true;
......@@ -47,7 +73,7 @@ class RemotesubscribeAction extends Action
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
# CSRF protection
/* Use a session token for CSRF protection. */
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$this->showForm(_('There was a problem with your session token. '.
......@@ -90,8 +116,8 @@ class RemotesubscribeAction extends Action