]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
client side of distributed subscription almost complete
authorEvan Prodromou <evan@prodromou.name>
Tue, 27 May 2008 11:42:19 +0000 (07:42 -0400)
committerEvan Prodromou <evan@prodromou.name>
Tue, 27 May 2008 11:42:19 +0000 (07:42 -0400)
darcs-hash:20080527114219-84dde-784ddf4d4650c17bc7a1e3e01219c6948dfc9b3d.gz

13 files changed:
actions/accesstoken.php
actions/finishremotesubscribe.php [new file with mode: 0644]
actions/remotesubscribe.php [new file with mode: 0644]
actions/requesttoken.php
actions/showstream.php
actions/userauthorization.php
actions/xrds.php
db/stoica.sql
doc/README
doc/TODO
doc/openmicroblogging.txt
lib/omb.php
lib/util.php

index e28a9334542f83e214191c2c36a6840d4ec32c6d..6bb0e1561b3d3bfd3aee8159facd50f072a3794c 100644 (file)
@@ -22,6 +22,13 @@ if (!defined('LACONICA')) { exit(1); }
 class AccesstokenAction extends Action {
        function handle($args) {
                parent::handle($args);
-               common_server_error(_t('Not yet implemented.'));
+               try {
+                       $req = OAuthRequest::from_request();
+                       $server = common_oauth_server();
+                       $token = $server->fetch_access_token($req);
+                       print $token;
+               } catch (OAuthException $e) {
+                       common_server_error($e->getMessage());
+               }
        }
 }
diff --git a/actions/finishremotesubscribe.php b/actions/finishremotesubscribe.php
new file mode 100644 (file)
index 0000000..b509326
--- /dev/null
@@ -0,0 +1,221 @@
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2008, Controlez-Vous, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('LACONICA')) { exit(1); }
+
+require_once(INSTALLDIR.'/lib/omb.php');
+require_once('Auth/Yadis/Yadis.php');
+
+class FinishremotesubscribeAction extends Action {
+       
+       function handle($args) {
+               
+               parent::handle($args);
+
+               if (common_logged_in()) {
+                       common_user_error(_t('You can use the local subscription!'));
+                   return;
+               }
+               
+               $nonce = $this->trimmed('nonce');
+               
+               if (!$omb) {
+                       common_user_error(_t('No nonce returned!'));
+                       return;
+               }
+               
+               $omb = $_SESSION[$nonce];
+               
+               if (!$omb) {
+                       common_user_error(_t('Not expecting this response!'));
+                       return;
+               }
+
+               $req = OAuthRequest::from_request();
+
+               $token = $req->get_parameter('oauth_token');
+
+               # I think this is the success metric
+               
+               if ($token != $omb['token']) {
+                       common_user_error(_t('Not authorized.'));
+                       return;
+               }
+               
+               $version = $req->get_parameter('omb_version');
+               
+               if ($version != OMB_VERSION_01) {
+                       common_user_error(_t('Unknown version of OMB protocol.'));
+                       return;
+               }
+               
+               $nickname = $req->get_parameter('omb_listener_nickname');
+               
+               if (!$nickname) {
+                       common_user_error(_t('No nickname provided by remote server.'));
+                       return;
+               }
+
+               $profile_url = $req->get_parameter('omb_listener_profile');
+               
+               if (!$profile_url) {
+                       common_user_error(_t('No profile URL returned by server.'));
+                       return;
+               }
+
+               if (!Validate::uri($profile_url, array('allowed_schemes' => array('http', 'https')))) {
+                       common_user_error(_t('Invalid profile URL returned by server.'));
+                       return;
+               }
+
+               $user = User::staticGet('uri', $omb['listenee']);
+               
+               if (!$user) {
+                       common_user_error(_t('User being listened to doesn\'t exist.'));
+                       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) {
+                       common_user_error(_t('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 ($fullname) {
+                       $profile->fullname = $fullname;
+               }
+               if ($homepage) {
+                       $profile->homepage = $homepage;
+               }
+               if ($bio) {
+                       $profile->bio = $bio;
+               }
+               if ($location) {
+                       $profile->location = $location;
+               }
+               
+               if ($exists) {
+                       $profile->update($orig_profile);
+               } else {
+                       $profile->created = DB_DataObject_Cast::dateTime(); # current time
+                       $id = $profile->insert();
+                       $remote->id = $id;
+               }
+
+               if ($avatar_url) {
+                       $this->add_avatar($avatar_url);
+               }
+
+               $remote->postnoticeurl = $omb[OMB_ENDPOINT_POSTNOTICE];
+               $remote->updateprofileurl = $omb[OMB_ENDPOINT_UPDATEPROFILE];
+
+               if ($exists) {
+                       $remote->update($orig_remote);
+               } else {
+                       $remote->created = DB_DataObject_Cast::dateTime(); # current time
+                       $remote->insert;
+               }
+               
+               $sub = new Subscription();
+               $sub->subscriber = $remote->id;
+               $sub->subscribed = $user->id;
+               $sub->token = $newtok;
+               $sub->secret = $newsecret;
+               $sub->created = DB_DataObject_Cast::dateTime(); # current time
+               
+               if (!$sub->insert()) {
+                       common_user_error(_t('Couldn\'t insert new subscription.'));
+                       return;
+               }
+
+               # Clear the data
+               unset($_SESSION[$nonce]);
+               
+               # If we show subscriptions in reverse chron order, this should
+               # show up close to the top of the page
+               
+               common_redirect(common_local_url('subscribed', array('nickname' =>
+                                                                                                                        $user->nickname)));
+       }
+       
+       function access_token($omb) {
+               
+               $con = omb_oauth_consumer();
+               $tok = new OAuthToken($omb['token'], $omb['secret']);
+
+               $url = $omb[OAUTH_ENDPOINT_ACCESS][0];
+               
+               # 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, NULL);
+               
+               # We re-use this tool's fetcher, since it's pretty good
+               
+               $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
+               $result = $fetcher->post($req->get_normalized_http_url(),
+                                                                $req->to_postdata());
+               
+               if ($result->status != 200) {
+                       return NULL;
+               }
+
+               parse_str($result->body, $return);
+               
+               return array($return['oauth_token'], $return['oauth_token_secret']);
+       }
+}
\ No newline at end of file
diff --git a/actions/remotesubscribe.php b/actions/remotesubscribe.php
new file mode 100644 (file)
index 0000000..68f5f0f
--- /dev/null
@@ -0,0 +1,248 @@
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2008, Controlez-Vous, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('LACONICA')) { exit(1); }
+
+require_once(INSTALLDIR.'/lib/omb.php');
+require_once('Auth/Yadis/Yadis.php');
+
+class RemotesubscribeAction extends Action {
+       
+       function handle($args) {
+               
+               parent::handle($args);
+
+               if (common_logged_in()) {
+                       common_user_error(_t('You can use the local subscription!'));
+                   return;
+               }
+
+               if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+                       $this->remote_subscription();
+               } else {
+                       $this->show_form();
+               }
+       }
+
+       function show_form($err=NULL) {
+               common_show_header(_t('Remote subscribe'));
+               if ($err) {
+                       common_element('div', 'error', $err);
+               }
+               common_element_start('form', array('id' => 'remotesubscribe', 'method' => 'POST',
+                                                                                  'action' => common_local_url('remotesubscribe')));
+               common_input('profile', _t('Profile URL'));
+               common_submit('submit', _t('Subscribe'));
+               common_element_end('form');
+       }
+       
+       function remote_subscription() {
+               $user = $this->get_user();
+               
+               if (!$user) {
+                       $this->show_form(_t('No such user!'));
+                       return;
+               }
+               
+               $profile = $this->trimmed('profile');
+               
+               if (!$profile) {
+                       $this->show_form(_t('No such user!'));
+                       return;
+               }
+               
+               if (!Validate::uri($profile, array('allowed_schemes' => array('http', 'https')))) {
+                       $this->show_form(_t('Invalid profile URL (bad format)'));
+                       return;
+               }
+               
+               $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
+               $yadis = Auth_Yadis_Yadis::discover($profile, $fetcher);
+               
+               if (!$yadis) {
+                       $this->show_form(_t('Not a valid profile URL (no YADIS document).'));
+                       return;
+               }
+               
+               $omb = $this->getOmb($yadis);
+               
+               if (!$omb) {
+                       $this->show_form(_t('Not a valid profile URL (incorrect services).'));
+                       return;
+               }
+               
+               list($token, $secret) = $this->request_token($omb);
+               
+               if (!$token || !$secret) {
+                       $this->show_form(_t('Couldn\'t get a request token.'));
+                       return;
+               }
+               
+               $this->request_authorization($user, $omb, $token, $secret);
+       }
+       
+       function get_user() {
+               $user = NULL;
+               $nickname = $this->trimmed('nickname');
+               if ($nickname) {
+                       $user = User::staticGet('nickname', $nickname);
+               }
+               return $user;
+       }
+
+       function getOmb($yadis) {
+           static $endpoints = array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE,
+                                                                 OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE,
+                                                                 OAUTH_ENDPOINT_ACCESS);
+               $omb = array();
+               $services = $yadis->services(); # ordered by priority
+               foreach ($services as $service) {
+                       $types = $service->matchTypes($endpoints);
+                       foreach ($types as $type) {
+                               # We take the first one, since it's the highest priority
+                               if (!array_key_exists($type, $omb)) {
+                                       # URIs is an array, priority-ordered
+                                       $omb[$type] = $service->getURIs();
+                                       # Special handling for request
+                                       if ($type == OAUTH_ENDPOINT_REQUEST) {
+                                               $nodes = $service->getElements('LocalID');
+                                               if (!$nodes) {
+                                                       # error
+                                                       return NULL;
+                                               }
+                                               $omb['listener'] = $service->parser->content($nodes[0]);
+                                       }
+                               }
+                       }
+               }
+               foreach ($endpoints as $ep) {
+                       if (!array_key_exists($ep, $omb)) {
+                               return NULL;
+                       }
+               }
+               if (!array_key_exists('listener', $omb)) {
+                       return NULL;
+               }
+               return $omb;
+       }
+       
+       function request_token($omb) {
+               $con = omb_oauth_consumer();
+
+               $url = $omb[OAUTH_ENDPOINT_REQUEST][0];
+               
+               # 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, NULL, "POST", $url, $params);
+               
+               $req->set_parameter('omb_listener', $omb['listener']);
+               $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, NULL);
+               
+               # We re-use this tool's fetcher, since it's pretty good
+               
+               $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
+               $result = $fetcher->post($req->get_normalized_http_url(),
+                                                                $req->to_postdata());
+               
+               if ($result->status != 200) {
+                       return NULL;
+               }
+
+               parse_str($result->body, $return);
+               
+               return array($return['oauth_token'], $return['oauth_token_secret']);
+       }
+       
+       function request_authorization($user, $omb, $token, $secret) {
+               global $config; # for license URL
+               
+               $con = omb_oauth_consumer();
+               $tok = new OAuthToken($token, $secret);
+               
+               $url = $omb[OAUTH_ENDPOINT_AUTHORIZE][0];
+               
+               # 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, 'GET', $url, $params);
+               
+               # We send over a ton of information. This lets the other
+               # server store info about our user, and it lets the current
+               # user decide if they really want to authorize the subscription.
+               
+               $req->set_parameter('omb_version', OMB_VERSION_01);
+               $req->set_parameter('omb_listener', $omb['listener']);
+               $req->set_parameter('omb_listenee', $user->uri);
+               $req->set_parameter('omb_listenee_profile', common_profile_url($user->nickname));
+               $req->set_parameter('omb_listenee_nickname', $user->nickname);
+               $req->set_parameter('omb_listenee_license', $config['license']['url']);
+               $profile = $user->getProfile();
+               if ($profile->fullname) {
+                       $req->set_parameter('omb_listenee_fullname', $profile->fullname);
+               }
+               if ($profile->homepage) {
+                       $req->set_parameter('omb_listenee_homepage', $profile->homepage);
+               }
+               if ($profile->bio) {
+                       $req->set_parameter('omb_listenee_bio', $profile->bio);
+               }
+               if ($profile->location) {
+                       $req->set_parameter('omb_listenee_location', $profile->location);
+               }
+               $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
+               if ($avatar) {
+                       $req->set_parameter('omb_listenee_avatar', $avatar->url);
+               }
+
+               $nonce = $this->make_nonce();
+               
+               $req->set_parameter('oauth_callback', common_local_url('finishremotesubscribe',
+                                                                                                                          array('nonce' => $nonce)));
+                                                       
+               # XXX: test to see if endpoint accepts this signature method
+
+               $req->sign_request(omb_hmac_sha1(), $con, $tok);
+               
+               # store all our info here
+
+               $omb['listenee'] = $user->nickname;
+               $omb['token'] = $token;
+               $omb['secret'] = $secret;
+               
+               $_SESSION[$nonce] = $omb;
+               
+               # Redirect to authorization service
+               
+               common_redirect($req->to_url());
+               return;
+       }
+}
\ No newline at end of file
index 731d260ffd2b36ca5d7314373f409bb931eecd1b..92b4c423422f53c66cd1f97acbe466e1cc1427e4 100644 (file)
 
 if (!defined('LACONICA')) { exit(1); }
 
+require_once(INSTALLDIR.'/lib/omb.php');
+
 class RequesttokenAction extends Action {
        function handle($args) {
                parent::handle($args);
-               common_server_error(_t('Not yet implemented.'));
+               try {
+                       $req = OAuthRequest::from_request();
+                       $server = common_oauth_server();
+                       $token = $server->fetch_request_token($req);
+                       print $token;
+               } catch (OAuthException $e) {
+                       common_server_error($e->getMessage());
+               }
        }
 }
index 3de9a6e23bd4f4f85e1a7d387719f26ab1b5957b..7ac036de6303cde666e752a821fcbf4193f8fb92 100644 (file)
@@ -68,6 +68,10 @@ class ShowstreamAction extends StreamAction {
                                                                                                                                                           $user->nickname)),
                                                                         'type' => 'application/rss+xml',
                                                                         'title' => _t('Notice feed for ') . $user->nickname));
+               # for remote subscriptions etc.
+               common_element('meta', array('http-equiv' => 'X-XRDS-Location',
+                                                                        'content' => common_local_url('xrds', array('nickname' =>
+                                                                                                                                                          $user->nickname))));
        }
        
        function no_such_user() {
index 5b8a8bdc8095b9c99d86fbc4fc801f9715c8f21e..cc7ec85a51c5937dc926eb414ba3e77274f7cf77 100644 (file)
@@ -22,6 +22,60 @@ if (!defined('LACONICA')) { exit(1); }
 class UserauthorizationAction extends Action {
        function handle($args) {
                parent::handle($args);
-               common_server_error(_t('Not yet implemented.'));
+               
+               if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+                       $this->send_authorization();
+               } else {
+                       try {
+                               $req = $this->get_request();
+                               $server = common_oauth_server();
+                               list($consumer, $token) = $server->verify_request($req);
+                       } catch (OAuthException $e) {
+                               $this->clear_request();
+                               common_server_error($e->getMessage());
+                               return;
+                       }
+                       
+                       if (common_logged_in()) {
+                               $this->show_form($req);
+                       } else {
+                               common_return_to(common_local_url('userauthorization'));
+                               common_redirect(common_local_url('login'));
+                       }
+               }
+       }
+       
+       function store_request($req) {
+               common_ensure_session();
+               $_SESSION['userauthorizationrequest'] = $req;
+       }
+       
+       function get_request() {
+               common_ensure_session();                
+               $req = $_SESSION['userauthorizationrequest'];
+               if (!$req) {
+                       # XXX: may have an uncaught exception
+                       $req = OAuthRequest::from_request();
+                       $this->store_request($req);
+               }
+               return $req;
+       }
+       
+       function show_form($req) {
+               common_show_header(_t('Authorize subscription'));
+
+               common_show_footer();
+       }
+       
+       function send_authorization() {
+               $req = $this->get_request();
+               if (!$req) {
+                       common_user_error(_t('No authorization request!'));
+                       return;
+               }
+               
+               if ($this->boolean('authorize')) {
+                       
+               }
        }
 }
index 6b4c3cdf514f1392c5964a388c7ca3fac2a44bf1..d59928e91cea04cba93993f779faaa2d4c20ea78 100644 (file)
@@ -107,7 +107,9 @@ class XrdsAction extends Action {
        
        function show_service($type, $uri, $params=NULL, $sigs=NULL, $localId=NULL) {
                common_element_start('Service');
-               common_element('URI', NULL, $uri);
+               if ($uri) {
+                       common_element('URI', NULL, $uri);
+               }
                common_element('Type', NULL, $type);
                if ($params) {
                        foreach ($params as $param) {
index e9aa1f998e0c1eca91472e33e03ddc7f6f346f83..6a460b350df3d54e4664c104ead76b230bfd7eea 100644 (file)
@@ -56,6 +56,7 @@ create table subscription (
     subscriber integer not null comment 'profile listening',
     subscribed integer not null comment 'profile being listened to',
     token varchar(255) comment 'authorization token',
+    secret varchar(255) comment 'token secret',
     created datetime not null comment 'date this record was created',
     modified timestamp comment 'date this record was modified',
 
index 7bde309169a32aa28f52bb72496b379e4cf6c92e..4190b637af884e95c65232940f5fc3f82b1472ce 100644 (file)
@@ -9,5 +9,6 @@ This package requires PHP 5.x and the following PHP Pear libraries:
   use the openidenabled.com libraries for OpenID auth sometime in the
   future. Note that this is no longer distributed separately; it's only
   in the openidenabled.com OpenID PHP tarball.
-  
+- OAuth.php from http://oauth.googlecode.com/svn/code/php/
+
   
index c5f692b43be15a5c5315160b1aa1e4354bc86008..9428bc0d901f0977236f42ce252f133423c8fa9c 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
 + public stream link in top menu
 + dump, fix, undump database
 + release 0.2
-- YADIS document link on showstream
-- YADIS document
++ YADIS document link on showstream
++ YADIS document
 - subscribe remote
 - add subscriber remote
-- send remote notice
+- server side of user authorization
+- server side of request token
+- server side of access token
+- OAuth store
+- log of consumers who ask for access
 - receive remote notice
+- send remote notice
+- subscribe form for not-logged-in users on showstream
 - pretty URLs
 - doc action
 - about doc
@@ -76,6 +82,7 @@
 - add a next page link to public
 - add a next page link to all
 - AGPL notification
+- Check licenses of all libraries for compatibility
 - gettext
 - release 0.3
 - license per notice
index 6fd3b7cecf4cf96b39c3e48e97e0c67a9f14203d..097291640d41481ad7be2cb68d8e0c9a6752f07f 100644 (file)
@@ -60,7 +60,7 @@ notice URI
 Initiation
 ==========
 
-The user submits their profile URL [*] to the remote service somehow --
+The user submits their profile URL [*]_ to the remote service somehow --
 for example, with an HTML form on the remote service's Web site. 
 
 .. [*] For OAuth Discovery, this is the "protected resource". It may
@@ -96,11 +96,12 @@ Authorization
 The remote service must go through the OAuth 1.0 dance to get
 authorization to post notices and update profiles.
 
-In all OAuth, the consumer key should be blank (''), unless the remote
-server and local service have negotiated another key. Such negotiation
-is out-of-scope for this document, and we assume an "open" network of
-microblogging services. But if you want to have that kind of network,
-do it with this key.
+In all OAuth, the consumer key should be the root URL for the
+microblogging service, if available. The secret should be the blank
+string (''), unless the remote server and local service have negotiated
+another key. Such negotiation is out-of-scope for this document, and we
+assume an "open" network of microblogging services. But if you want to
+have that kind of network, do it with this key.
 
 The remote service MUST do OAuth for every new listener, regardless of
 whether they've already received authorization for posting to the
@@ -253,17 +254,17 @@ The local service makes no guarantees about the delivery of the notice
 to anyone.
 
 The remote service SHOULD NOT send a message with the same notice URL
-to the same postNotice URL more than once. [2]_ If the request returns
+to the same postNotice URL more than once. [*]_ If the request returns
 a 403 Unauthorized message, the remote service SHOULD NOT post
 messages to the same URL again with the same listenee, until another
-listener has gone through the OAuth dance. [3]_
+listener has gone through the OAuth dance. [*]_
 
-.. [2] A half-assed optimization. A local service may have a lot of
+.. [*] A half-assed optimization. A local service may have a lot of
    listeners listening to the same listenee. It would be pointless to
    have the remote service post the same notice 100 times to the same
    service. However, if the local service wants fine-grained control,
    it can have a different postNotice URL for each listener.
-.. [3] If there's one postNotice URL per listener, the 403 message
+.. [*] If there's one postNotice URL per listener, the 403 message
    means the listener has told the local service not to allow posting
    any more ("unsubscribed"). If there's one postNotice URL per local
    service, it means that the count of listeners has dropped to 0.
index 0267ae5970a1bf6503d42f1eeb803fef378fd9bc..b68d08abf93da388739aecae726c60e9e84536b3 100644 (file)
 
 if (!defined('LACONICA')) { exit(1); }
 
+require_once('OAuth.php');
+
 define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/');
 define('OMB_NAMESPACE', 'http://openmicroblogging.org/protocol/0.1');
+define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1');
 define('OAUTH_DISCOVERY', 'http://oauth.net/discovery/1.0');
 
 define('OMB_ENDPOINT_UPDATEPROFILE', OMB_NAMESPACE.'updateProfile');
+define('OMB_ENDPOINT_POSTNOTICE', OMB_NAMESPACE.'postNotice');
 define('OAUTH_ENDPOINT_REQUEST', OAUTH_NAMESPACE.'endpoint/request');
 define('OAUTH_ENDPOINT_AUTHORIZE', OAUTH_NAMESPACE.'endpoint/authorize');
 define('OAUTH_ENDPOINT_ACCESS', OAUTH_NAMESPACE.'endpoint/access');
@@ -32,3 +36,18 @@ 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');
           
+function omb_oauth_consumer() {
+       static $con = null;
+       if (!$con) {
+               $con = new OAuthConsumer(common_root_url(), '');
+       }
+       return $con;
+}
+
+function omb_hmac_sha1() {
+       static $hmac_method = NULL;
+       if (!$hmac_method) {
+               $hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
+       }
+       return $hmac_method;
+}
\ No newline at end of file
index 64fa230d201b7bd75122352557d338663a2d25d3..31a2cbd4f79b067821cec6b30ef58892a2870f24 100644 (file)
@@ -439,6 +439,14 @@ function common_mint_tag($extra) {
          $config['tag']['date'].':'.$config['tag']['prefix'].$extra;
 }
 
+# Should make up a reasonable root URL
+
+function common_root_url() {
+       global $config;
+       $pathpart = ($config['site']['path']) ? $config['site']['path']."/" : '';
+       return "http://".$config['site']['server'].'/'.$pathpart;
+}
+
 // XXX: set up gettext
 
 function _t($str) {