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());
}
}
}
?>
This diff is collapsed.
<?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;
}
}
?>
This diff is collapsed.
......@@ -34,6 +34,7 @@ if (!defined('LACONICA')) {
}
require_once INSTALLDIR.'/lib/omb.php';
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
/**
* Request token action class.
......@@ -49,17 +50,17 @@ class RequesttokenAction extends Action
{
/**
* Is read only?
*
*
* @return boolean false
*/
function isReadOnly($args)
function isReadOnly()
{
return false;
}
/**
* Class handler.
*
*
* @param array $args array of arguments
*
* @return void
......@@ -68,14 +69,12 @@ class RequesttokenAction extends Action
{
parent::handle($args);
try {
common_remove_magic_from_request();
$req = OAuthRequest::from_request('POST', common_local_url('requesttoken'));
$server = omb_oauth_server();
$token = $server->fetch_request_token($req);
print $token;
} catch (OAuthException $e) {
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
omb_oauth_server());
$srv->writeRequestToken();
} catch (Exception $e) {
$this->serverError($e->getMessage());
}
}
}
?>
<?php
/*
/**
* Handle an updateprofile 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,167 +28,37 @@
* 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';
/**
* Handle an updateprofile 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 UpdateprofileAction extends Action
{
function handle($args)
{
parent::handle($args);
try {
common_remove_magic_from_request();
$req = OAuthRequest::from_request('POST', common_local_url('updateprofile'));
# Note: server-to-server function!
$server = omb_oauth_server();
list($consumer, $token) = $server->verify_request($req);
if ($this->update_profile($req, $consumer, $token)) {
header('HTTP/1.1 200 OK');
header('Content-type: text/plain');
print "omb_version=".OMB_VERSION_01;
}
} catch (OAuthException $e) {
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
omb_oauth_server());
$srv->handleUpdateProfile();
} catch (Exception $e) {
$this->serverError($e->getMessage());
return;
}
}
function update_profile($req, $consumer, $token)
{
$version = $req->get_parameter('omb_version');
if ($version != OMB_VERSION_01) {
$this->clientError(_('Unsupported OMB version'), 400);
return false;
}
# First, check to see if listenee exists
$listenee = $req->get_parameter('omb_listenee');
$remote = Remote_profile::staticGet('uri', $listenee);
if (!$remote) {
$this->clientError(_('Profile unknown'), 404);
return false;
}
# Second, check to see if they should be able to post updates!
# We see if there are any subscriptions to that remote user with
# the given token.
$sub = new Subscription();
$sub->subscribed = $remote->id;
$sub->token = $token->key;
if (!$sub->find(true)) {
$this->clientError(_('You did not send us that profile'), 403);
return false;
}
$profile = Profile::staticGet('id', $remote->id);
if (!$profile) {
# This one is our fault
$this->serverError(_('Remote profile with no matching profile'), 500);
return false;
}
$nickname = $req->get_parameter('omb_listenee_nickname');
if ($nickname && !Validate::string($nickname, array('min_length' => 1,
'max_length' => 64,
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
$this->clientError(_('Nickname must have only lowercase letters and numbers and no spaces.'));
return false;
}
$license = $req->get_parameter('omb_listenee_license');
if ($license && !common_valid_http_url($license)) {
$this->clientError(sprintf(_("Invalid license URL '%s'"), $license));
return false;
}
$profile_url = $req->get_parameter('omb_listenee_profile');
if ($profile_url && !common_valid_http_url($profile_url)) {
$this->clientError(sprintf(_("Invalid profile URL '%s'."), $profile_url));
return false;
}
# optional stuff
$fullname = $req->get_parameter('omb_listenee_fullname');
if ($fullname && mb_strlen($fullname) > 255) {
$this->clientError(_("Full name is too long (max 255 chars)."));
return false;
}
$homepage = $req->get_parameter('omb_listenee_homepage');
if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) {
$this->clientError(sprintf(_("Invalid homepage '%s'"), $homepage));
return false;
}
$bio = $req->get_parameter('omb_listenee_bio');
if ($bio && mb_strlen($bio) > 140) {
$this->clientError(_("Bio is too long (max 140 chars)."));
return false;
}
$location = $req->get_parameter('omb_listenee_location');
if ($location && mb_strlen($location) > 255) {
$this->clientError(_("Location is too long (max 255 chars)."));
return false;
}
$avatar = $req->get_parameter('omb_listenee_avatar');
if ($avatar) {
if (!common_valid_http_url($avatar) || strlen($avatar) > 255) {
$this->clientError(sprintf(_("Invalid avatar URL '%s'"), $avatar));
return false;
}
$size = @getimagesize($avatar);
if (!$size) {
$this->clientError(sprintf(_("Can't read avatar URL '%s'"), $avatar));
return false;
}
if ($size[0] != AVATAR_PROFILE_SIZE || $size[1] != AVATAR_PROFILE_SIZE) {
$this->clientError(sprintf(_("Wrong size image at '%s'"), $avatar));
return false;
}
if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG,
IMAGETYPE_PNG))) {
$this->clientError(sprintf(_("Wrong image type for '%s'"), $avatar));
return false;
}
}
$orig_profile = clone($profile);
/* Use values even if they are an empty string. Parsing an empty string in
updateProfile is the specified way of clearing a parameter in OMB. */
if (!is_null($nickname)) {
$profile->nickname = $nickname;
}
if (!is_null($profile_url)) {
$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 (!$profile->update($orig_profile)) {
$this->serverError(_('Could not save new profile info'), 500);
return false;
} else {
if ($avatar) {
$temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar');
copy($avatar, $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));
if (!$profile->setOriginal($filename)) {
$this->serverError(_('Could not save avatar info'), 500);
return false;
}
}
return true;
}
}
}
?>
This diff is collapsed.
......@@ -34,6 +34,8 @@ if (!defined('LACONICA')) {
}
require_once INSTALLDIR.'/lib/omb.php';
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php';
/**
* XRDS for OpenID
......@@ -52,7 +54,7 @@ class XrdsAction extends Action
*
* @return boolean true
*/
function isReadOnly($args)
function isReadOnly()
{
return true;
}
......@@ -85,89 +87,31 @@ class XrdsAction extends Action
*/
function showXrds($user)
{
header('Content-Type: application/xrds+xml');
$this->startXML();
$this->elementStart('XRDS', array('xmlns' => 'xri://$xrds'));
$srv = new OMB_Service_Provider(profile_to_omb_profile($user->uri,
$user->getProfile()));
/* Use libomb’s default XRDS Writer. */
$xrds_writer = null;
$srv->writeXRDS(new Laconica_XRDS_Mapper(), $xrds_writer);
}
}
$this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'xml:id' => 'oauth',
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0'));
$this->element('Type', null, 'xri://$xrds*simple');
$this->showService(OAUTH_ENDPOINT_REQUEST,
common_local_url('requesttoken'),
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
array(OAUTH_HMAC_SHA1),
$user->uri);
$this->showService(OAUTH_ENDPOINT_AUTHORIZE,
common_local_url('userauthorization'),
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
array(OAUTH_HMAC_SHA1));
$this->showService(OAUTH_ENDPOINT_ACCESS,
common_local_url('accesstoken'),
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
array(OAUTH_HMAC_SHA1));
$this->showService(OAUTH_ENDPOINT_RESOURCE,
null,
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
array(OAUTH_HMAC_SHA1));
$this->elementEnd('XRD');
class Laconica_XRDS_Mapper implements OMB_XRDS_Mapper
{
protected $urls;
// XXX: decide whether to include user's ID/nickname in postNotice URL
$this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'xml:id' => 'omb',
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0'));
$this->element('Type', null, 'xri://$xrds*simple');
$this->showService(OMB_ENDPOINT_POSTNOTICE,
common_local_url('postnotice'));
$this->showService(OMB_ENDPOINT_UPDATEPROFILE,
common_local_url('updateprofile'));
$this->elementEnd('XRD');
$this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'version' => '2.0'));
$this->element('Type', null, 'xri://$xrds*simple');
$this->showService(OAUTH_DISCOVERY,
'#oauth');
$this->showService(OMB_NAMESPACE,
'#omb');
$this->elementEnd('XRD');
$this->elementEnd('XRDS');
$this->endXML();
public function __construct()
{
$this->urls = array(
OAUTH_ENDPOINT_REQUEST => 'requesttoken',
OAUTH_ENDPOINT_AUTHORIZE => 'userauthorization',
OAUTH_ENDPOINT_ACCESS => 'accesstoken',
OMB_ENDPOINT_POSTNOTICE => 'postnotice',
OMB_ENDPOINT_UPDATEPROFILE => 'updateprofile');
}
/**
* Show service.
*
* @param string $type XRDS type
* @param string $uri URI
* @param array $params type parameters, null by default
* @param array $sigs type signatures, null by default
* @param string $localId local ID, null by default
*
* @return void
*/
function showService($type, $uri, $params=null, $sigs=null, $localId=null)
public function getURL($action)
{
$this->elementStart('Service');
if ($uri) {
$this->element('URI', null, $uri);
}
$this->element('Type', null, $type);
if ($params) {
foreach ($params as $param) {
$this->element('Type', null, $param);
}
}
if ($sigs) {
foreach ($sigs as $sig) {
$this->element('Type', null, $sig);
}
}
if ($localId) {
$this->element('LocalID', null, $localId);
}
$this->elementEnd('Service');
return common_local_url($this->urls[$action]);
}
}
?>
<?php
require_once 'xrds_mapper.php';
require_once 'constants.php';
/**
* Map XRDS actions to URLs using base URLs.
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
*
* PHP version 5
*
* LICENSE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* 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/>.
*
* @package OMB
* @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
**/
class OMB_Base_URL_XRDS_Mapper implements OMB_XRDS_Mapper {
protected $urls;
public function __construct($oauth_base, $omb_base) {
$this->urls = array(
OAUTH_ENDPOINT_REQUEST => $oauth_base . 'requesttoken',
OAUTH_ENDPOINT_AUTHORIZE => $oauth_base . 'userauthorization',
OAUTH_ENDPOINT_ACCESS => $oauth_base . 'accesstoken',
OMB_ENDPOINT_POSTNOTICE => $omb_base . 'postnotice',
OMB_ENDPOINT_UPDATEPROFILE => $omb_base . 'updateprofile');
}
public function getURL($action) {
return $this->urls[$action];
}
}
?>
<?php
/**
* Constants for libomb
*
* This file contains constant definitions for libomb. The defined constants
* are service and namespace URIs for OAuth and OMB as used in XRDS.
*
* PHP version 5
*
* LICENSE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* 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/>.
*
* @package OMB
* @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
**/
/**
* The OMB constants.
**/
define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1');
/* The OMB version supported by this libomb version. */
define('OMB_VERSION', OMB_VERSION_01);
define('OMB_ENDPOINT_UPDATEPROFILE', OMB_VERSION . '/updateProfile');
define('OMB_ENDPOINT_POSTNOTICE', OMB_VERSION . '/postNotice');
/**
* The OAuth constants.
**/
define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/');
define('OAUTH_ENDPOINT_REQUEST', OAUTH_NAMESPACE.'endpoint/request');
define('OAUTH_ENDPOINT_AUTHORIZE', OAUTH_NAMESPACE.'endpoint/authorize');
define('OAUTH_ENDPOINT_ACCESS', OAUTH_NAMESPACE.'endpoint/access');
define('OAUTH_ENDPOINT_RESOURCE', OAUTH_NAMESPACE.'endpoint/resource');
define('OAUTH_AUTH_HEADER', OAUTH_NAMESPACE.'parameters/auth-header');
define('OAUTH_POST_BODY', OAUTH_NAMESPACE.'parameters/post-body');
define('OAUTH_HMAC_SHA1', OAUTH_NAMESPACE.'signature/HMAC-SHA1');
define('OAUTH_DISCOVERY', 'http://oauth.net/discovery/1.0');
?>
<?php
require_once 'OAuth.php';
/**
* Data access interface
*
* This interface specifies data access methods libomb needs. It
* should be implemented by libomb users.
* OMB_Datastore is libomb’s main interface to the application’s data.
*
* It is the user’s duty to signal and handle errors. libomb does not check
* return values nor handle exceptions. It is suggested to use exceptions.
* Note that lookup_token and getProfile return null if the requested object
* is not available. This is NOT an error and should not raise an exception.
* Same applies for lookup_nonce which returns a boolean value. These methods
* may nevertheless throw an exception, for example in case of a storage error.
*
* Objects corresponding to this interface are used in OMB_Service_Provider and
* OMB_Service_Consumer.
*
* OMB_Datastore extends OAuthDataStore with two OAuth-related methods for token
* revoking and authorizing and all OMB-related methods.
* Refer to OAuth.php for a complete specification of OAuth-related methods.
*
* Note that it’s implemented as a class since OAuthDataStore is as well a
* class, though only declaring methods.
*
* PHP version 5
*
* LICENSE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* 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/>.
*
* @package OMB
* @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
**/
class OMB_Datastore extends OAuthDataStore {
/*********
* OAUTH *
*********/
/**