From 0e852def6ae5aa529cca0aef1187152fb5a880be Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 21 Jan 2010 16:42:50 -0800 Subject: XMPP queued output & initial retooling of DB queue manager to support non-Notice objects. Queue handlers for XMPP individual & firehose output now send their XML stanzas to another output queue instead of connecting directly to the chat server. This lets us have as many general processing threads as we need, while all actual XMPP input and output go through a single daemon with a single connection open. This avoids problems with multiple connected resources: * multiple windows shown in some chat clients (psi, gajim, kopete) * extra load on server * incoming message delivery forwarding issues Database changes: * queue_item drops 'notice_id' in favor of a 'frame' blob. This is based on Craig Andrews' work branch to generalize queues to take any object, but conservatively leaving out the serialization for now. Table updater (preserves any existing queued items) in db/rc3to09.sql Code changes to watch out for: * Queue handlers should now define a handle() method instead of handle_notice() * QueueDaemon and XmppDaemon now share common i/o (IoMaster) and respawning thread management (RespawningDaemon) infrastructure. * The polling XmppConfirmManager has been dropped, as the message is queued directly when saving IM settings. * Enable $config['queue']['debug_memory'] to output current memory usage at each run through the event loop to watch for memory leaks To do: * Adapt XMPP i/o to component connection mode for multi-site support. * XMPP input can also be broken out to a queue, which would allow the actual notice save etc to be handled by general queue threads. * Make sure there are no problems with simply pushing serialized Notice objects to queues. * Find a way to improve interactive performance of the database-backed queue handler; polling is pretty painful to XMPP. * Possibly redo the way QueueHandlers are injected into a QueueManager. The grouping used to split out the XMPP output queue is a bit awkward. --- db/08to09.sql | 16 ++++++++++++++++ db/rc3to09.sql | 16 ++++++++++++++++ db/statusnet.sql | 5 ++--- 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 db/rc3to09.sql (limited to 'db') diff --git a/db/08to09.sql b/db/08to09.sql index d9c25bc72..b10e47dbc 100644 --- a/db/08to09.sql +++ b/db/08to09.sql @@ -94,3 +94,19 @@ create table user_location_prefs ( constraint primary key (user_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; +create table queue_item_new ( + id integer auto_increment primary key comment 'unique identifier', + frame blob not null comment 'data: object reference or opaque string', + transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...', + created datetime not null comment 'date this record was created', + claimed datetime comment 'date this item was claimed', + + index queue_item_created_idx (created) + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +insert into queue_item_new (frame,transport,created,claimed) + select notice_id,transport,created,claimed from queue_item; +alter table queue_item rename to queue_item_old; +alter table queue_item_new rename to queue_item; + diff --git a/db/rc3to09.sql b/db/rc3to09.sql new file mode 100644 index 000000000..02dc7a6e2 --- /dev/null +++ b/db/rc3to09.sql @@ -0,0 +1,16 @@ +create table queue_item_new ( + id integer auto_increment primary key comment 'unique identifier', + frame blob not null comment 'data: object reference or opaque string', + transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...', + created datetime not null comment 'date this record was created', + claimed datetime comment 'date this item was claimed', + + index queue_item_created_idx (created) + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +insert into queue_item_new (frame,transport,created,claimed) + select notice_id,transport,created,claimed from queue_item; +alter table queue_item rename to queue_item_old; +alter table queue_item_new rename to queue_item; + diff --git a/db/statusnet.sql b/db/statusnet.sql index cb33ccf33..a9ed66cb4 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -244,13 +244,12 @@ create table remember_me ( ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; create table queue_item ( - - notice_id integer not null comment 'notice queued' references notice (id), + id integer auto_increment primary key comment 'unique identifier', + frame blob not null comment 'data: object reference or opaque string', transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...', created datetime not null comment 'date this record was created', claimed datetime comment 'date this item was claimed', - constraint primary key (notice_id, transport), index queue_item_created_idx (created) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; -- cgit v1.2.3-54-g00ecf From c0b832d19fc478d67752a6692bf71f178346e14a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 10 Nov 2009 17:10:56 -0800 Subject: Add new OAuth application tables and DataObjects. Also add a new column for consumer secret to consumer table. --- classes/Consumer.php | 5 +++-- classes/Oauth_application.php | 33 +++++++++++++++++++++++++++++++++ classes/Oauth_application_user.php | 24 ++++++++++++++++++++++++ db/statusnet.sql | 26 ++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 2 deletions(-) create mode 100755 classes/Oauth_application.php create mode 100755 classes/Oauth_application_user.php (limited to 'db') diff --git a/classes/Consumer.php b/classes/Consumer.php index d5b7b7e33..d17f183a8 100644 --- a/classes/Consumer.php +++ b/classes/Consumer.php @@ -11,9 +11,10 @@ class Consumer extends Memcached_DataObject public $__table = 'consumer'; // table name public $consumer_key; // varchar(255) primary_key not_null + public $consumer_secret; // varchar(255) not_null public $seed; // char(32) not_null - public $created; // datetime() not_null - public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP + public $created; // datetime not_null + public $modified; // timestamp not_null default_CURRENT_TIMESTAMP /* Static get */ function staticGet($k,$v=null) diff --git a/classes/Oauth_application.php b/classes/Oauth_application.php new file mode 100755 index 000000000..6ad2db6dd --- /dev/null +++ b/classes/Oauth_application.php @@ -0,0 +1,33 @@ + Date: Thu, 12 Nov 2009 19:34:13 -0800 Subject: Changed the OAuth app tables to refer to profiles instead of users. Added an owner column to oauth_application. --- classes/Oauth_application.php | 23 ++++++++++++----------- classes/Oauth_application_user.php | 14 +++++++------- db/statusnet.sql | 9 +++++---- 3 files changed, 24 insertions(+), 22 deletions(-) mode change 100755 => 100644 classes/Oauth_application.php mode change 100755 => 100644 classes/Oauth_application_user.php (limited to 'db') diff --git a/classes/Oauth_application.php b/classes/Oauth_application.php old mode 100755 new mode 100644 index 6ad2db6dd..e2862bf97 --- a/classes/Oauth_application.php +++ b/classes/Oauth_application.php @@ -2,32 +2,33 @@ /** * Table Definition for oauth_application */ -require_once 'classes/Memcached_DataObject'; +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Oauth_application extends Memcached_DataObject +class Oauth_application extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ public $__table = 'oauth_application'; // table name public $id; // int(4) primary_key not_null + public $owner; // int(4) not_null public $consumer_key; // varchar(255) not_null public $name; // varchar(255) not_null - public $description; // varchar(255) + public $description; // varchar(255) public $icon; // varchar(255) not_null - public $source_url; // varchar(255) - public $organization; // varchar(255) - public $homepage; // varchar(255) + public $source_url; // varchar(255) + public $organization; // varchar(255) + public $homepage; // varchar(255) public $callback_url; // varchar(255) not_null - public $type; // tinyint(1) - public $access_type; // tinyint(1) + public $type; // tinyint(1) + public $access_type; // tinyint(1) public $created; // datetime not_null public $modified; // timestamp not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=null) - { return Memcached_DataObject::staticGet('Oauth_application_user',$k,$v); } - + function staticGet($k,$v=NULL) { + return Memcached_DataObject::staticGet('Oauth_application',$k,$v); + } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE } diff --git a/classes/Oauth_application_user.php b/classes/Oauth_application_user.php old mode 100755 new mode 100644 index a8922f5e7..9e45ece25 --- a/classes/Oauth_application_user.php +++ b/classes/Oauth_application_user.php @@ -2,23 +2,23 @@ /** * Table Definition for oauth_application_user */ -require_once 'classes/Memcached_DataObject'; +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Oauth_application_user extends Memcached_DataObject +class Oauth_application_user extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ public $__table = 'oauth_application_user'; // table name - public $user_id; // int(4) primary_key not_null + public $profile_id; // int(4) primary_key not_null public $application_id; // int(4) primary_key not_null - public $access_type; // tinyint(1) + public $access_type; // tinyint(1) public $created; // datetime not_null /* Static get */ - function staticGet($k,$v=null) - { return Memcached_DataObject::staticGet('Oauth_application_user',$k,$v); } - + function staticGet($k,$v=NULL) { + return Memcached_DataObject::staticGet('Oauth_application_user',$k,$v); + } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE } diff --git a/db/statusnet.sql b/db/statusnet.sql index be0d14092..03e6115e5 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -210,6 +210,7 @@ create table nonce ( create table oauth_application ( id integer auto_increment primary key comment 'unique identifier', + owner integer not null comment 'owner of the application' references profile (id), consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key), name varchar(255) not null comment 'name of the application', description varchar(255) comment 'description of the application', @@ -219,18 +220,18 @@ create table oauth_application ( homepage varchar(255) comment 'homepage for the organization', callback_url varchar(255) not null comment 'url to redirect to after authentication', type tinyint default 0 comment 'type of app, 0 = browser, 1 = desktop', - access_type tinyint default 0 comment 'default access type, 0 = read-write, 1 = read-only', + access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified' ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; create table oauth_application_user ( - user_id integer not null comment 'id of the application user' references user (id), + profile_id integer not null comment 'user of the application' references profile (id), application_id integer not null comment 'id of the application' references oauth_application (id), - access_type tinyint default 0 comment 'access type, 0 = read-write, 1 = read-only', + access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked', created datetime not null comment 'date this record was created', - constraint primary key (user_id, application_id) + constraint primary key (profile_id, application_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; /* These are used by JanRain OpenID library */ -- cgit v1.2.3-54-g00ecf From 3c2b05d222a55cd1e148f3f887bf55e924898f1b Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 16 Nov 2009 16:58:49 -0800 Subject: Workflow for registering new OAuth apps pretty much done. --- actions/apps.php | 63 +++++++- actions/editapplication.php | 246 ++++++++++++++++++++++++++++ actions/newapplication.php | 133 ++++++++++----- actions/oauthconnectionssettings.php | 13 ++ actions/showapplication.php | 306 +++++++++++++++++++++++++++++++++++ classes/Consumer.php | 16 +- classes/Oauth_application.php | 44 +++++ db/statusnet.sql | 2 +- lib/applicationeditform.php | 135 +++++++++++++--- lib/applicationlist.php | 46 ++++-- lib/default.php | 2 + lib/router.php | 25 ++- 12 files changed, 949 insertions(+), 82 deletions(-) create mode 100644 actions/editapplication.php create mode 100644 actions/showapplication.php (limited to 'db') diff --git a/actions/apps.php b/actions/apps.php index d4cea1e3e..e6500599f 100644 --- a/actions/apps.php +++ b/actions/apps.php @@ -31,7 +31,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } -require_once INSTALLDIR . '/lib/connectsettingsaction.php'; +require_once INSTALLDIR . '/lib/settingsaction.php'; +require_once INSTALLDIR . '/lib/applicationlist.php'; /** * Show a user's registered OAuth applications @@ -45,8 +46,23 @@ require_once INSTALLDIR . '/lib/connectsettingsaction.php'; * @see SettingsAction */ -class AppsAction extends ConnectSettingsAction +class AppsAction extends SettingsAction { + var $page = 0; + + function prepare($args) + { + parent::prepare($args); + $this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1; + + if (!common_logged_in()) { + $this->clientError(_('You must be logged in to list your applications.')); + return false; + } + + return true; + } + /** * Title of the page * @@ -79,6 +95,49 @@ class AppsAction extends ConnectSettingsAction { $user = common_current_user(); + $offset = ($this->page - 1) * APPS_PER_PAGE; + $limit = APPS_PER_PAGE + 1; + + $application = new Oauth_application(); + $application->owner = $user->id; + $application->limit($offset, $limit); + $application->orderBy('created DESC'); + $application->find(); + + $cnt = 0; + + if ($application) { + $al = new ApplicationList($application, $user, $this); + $cnt = $al->show(); + if (0 == $cnt) { + $this->showEmptyListMessage(); + } + } + + $this->element('a', + array('href' => common_local_url( + 'newapplication', + array('nickname' => $user->nickname) + ) + ), + 'Register a new application ยป'); + + $this->pagination( + $this->page > 1, + $cnt > APPS_PER_PAGE, + $this->page, + 'apps', + array('nickname' => $user->nickname) + ); + } + + function showEmptyListMessage() + { + $message = sprintf(_('You have not registered any applications yet.')); + + $this->elementStart('div', 'guide'); + $this->raw(common_markup_to_html($message)); + $this->elementEnd('div'); } /** diff --git a/actions/editapplication.php b/actions/editapplication.php new file mode 100644 index 000000000..3af482844 --- /dev/null +++ b/actions/editapplication.php @@ -0,0 +1,246 @@ +. + * + * @category Applications + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +/** + * Edit the details of an OAuth application + * + * This is the form for editing an application + * + * @category Application + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class EditApplicationAction extends OwnerDesignAction +{ + var $msg = null; + + var $app = null; + + function title() + { + return _('Edit Application'); + } + + /** + * Prepare to run + */ + + function prepare($args) + { + parent::prepare($args); + + if (!common_logged_in()) { + $this->clientError(_('You must be logged in to edit an application.')); + return false; + } + + $id = (int)$this->arg('id'); + $this->app = Oauth_application::staticGet($id); + + if (!$this->app) { + $this->clientError(_('No such application.')); + return false; + } + + return true; + } + + /** + * Handle the request + * + * On GET, show the form. On POST, try to save the group. + * + * @param array $args unused + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + + // CSRF protection + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->clientError(_('There was a problem with your session token.')); + return; + } + + $cur = common_current_user(); + + if ($this->arg('cancel')) { + common_redirect(common_local_url('showapplication', + array( + 'nickname' => $cur->nickname, + 'id' => $this->app->id) + ), 303); + } elseif ($this->arg('save')) { + $this->trySave(); + } else { + $this->clientError(_('Unexpected form submission.')); + } + } else { + $this->showForm(); + } + } + + function showForm($msg=null) + { + $this->msg = $msg; + $this->showPage(); + } + + function showContent() + { + $form = new ApplicationEditForm($this, $this->app); + $form->show(); + } + + function showPageNotice() + { + if (!empty($this->msg)) { + $this->element('p', 'error', $this->msg); + } else { + $this->element('p', 'instructions', + _('Use this form to edit your application.')); + } + } + + function trySave() + { + $name = $this->trimmed('name'); + $description = $this->trimmed('description'); + $source_url = $this->trimmed('source_url'); + $organization = $this->trimmed('organization'); + $homepage = $this->trimmed('homepage'); + $callback_url = $this->trimmed('callback_url'); + $type = $this->arg('app_type'); + $access_type = $this->arg('access_type'); + + if (empty($name)) { + $this->showForm(_('Name is required.')); + return; + } elseif (mb_strlen($name) > 255) { + $this->showForm(_('Name is too long (max 255 chars).')); + return; + } elseif (empty($description)) { + $this->showForm(_('Description is required.')); + return; + } elseif (Oauth_application::descriptionTooLong($description)) { + $this->showForm(sprintf( + _('Description is too long (max %d chars).'), + Oauth_application::maxDescription())); + return; + } elseif (empty($source_url)) { + $this->showForm(_('Source URL is required.')); + return; + } elseif ((strlen($source_url) > 0) + && !Validate::uri( + $source_url, + array('allowed_schemes' => array('http', 'https')) + ) + ) + { + $this->showForm(_('Source URL is not valid.')); + return; + } elseif (empty($organization)) { + $this->showForm(_('Organization is required.')); + return; + } elseif (mb_strlen($organization) > 255) { + $this->showForm(_('Organization is too long (max 255 chars).')); + return; + } elseif (empty($homepage)) { + $this->showForm(_('Organization homepage is required.')); + return; + } elseif ((strlen($homepage) > 0) + && !Validate::uri( + $homepage, + array('allowed_schemes' => array('http', 'https')) + ) + ) + { + $this->showForm(_('Homepage is not a valid URL.')); + return; + } elseif (empty($callback_url)) { + $this->showForm(_('Callback is required.')); + return; + } elseif (strlen($callback_url) > 0 + && !Validate::uri( + $source_url, + array('allowed_schemes' => array('http', 'https')) + ) + ) + { + $this->showForm(_('Callback URL is not valid.')); + return; + } + + $cur = common_current_user(); + + // Checked in prepare() above + + assert(!is_null($cur)); + + $orig = clone($this->app); + + $this->app->name = $name; + $this->app->description = $description; + $this->app->source_url = $source_url; + $this->app->organization = $organization; + $this->app->homepage = $homepage; + $this->app->callback_url = $callback_url; + $this->app->type = $type; + + if ($access_type == 'r') { + $this->app->setAccessFlags(true, false); + } else { + $this->app->setAccessFlags(true, true); + } + + $result = $this->app->update($orig); + + if (!$result) { + common_log_db_error($app, 'UPDATE', __FILE__); + $this->serverError(_('Could not update application.')); + } + + common_redirect(common_local_url('apps', + array('nickname' => $cur->nickname)), 303); + } + +} + diff --git a/actions/newapplication.php b/actions/newapplication.php index a78a856b1..9d8635270 100644 --- a/actions/newapplication.php +++ b/actions/newapplication.php @@ -43,7 +43,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @link http://status.net/ */ -class NewApplicationAction extends Action +class NewApplicationAction extends OwnerDesignAction { var $msg; @@ -61,7 +61,7 @@ class NewApplicationAction extends Action parent::prepare($args); if (!common_logged_in()) { - $this->clientError(_('You must be logged in to create a group.')); + $this->clientError(_('You must be logged in to register an application.')); return false; } @@ -81,8 +81,19 @@ class NewApplicationAction extends Action function handle($args) { parent::handle($args); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { - $this->trySave(); + + $cur = common_current_user(); + + if ($this->arg('cancel')) { + common_redirect(common_local_url('apps', + array('nickname' => $cur->nickname)), 303); + } elseif ($this->arg('save')) { + $this->trySave(); + } else { + $this->clientError(_('Unexpected form submission.')); + } } else { $this->showForm(); } @@ -112,55 +123,73 @@ class NewApplicationAction extends Action function trySave() { - $name = $this->trimmed('name'); - $description = $this->trimmed('description'); - $source_url = $this->trimmed('source_url'); - $organization = $this->trimmed('organization'); - $homepage = $this->trimmed('application'); - $callback_url = $this->trimmed('callback_url'); - $this->type = $this->trimmed('type'); - $this->access_type = $this->trimmed('access_type'); - - if (!is_null($name) && mb_strlen($name) > 255) { + $name = $this->trimmed('name'); + $description = $this->trimmed('description'); + $source_url = $this->trimmed('source_url'); + $organization = $this->trimmed('organization'); + $homepage = $this->trimmed('homepage'); + $callback_url = $this->trimmed('callback_url'); + $type = $this->arg('app_type'); + $access_type = $this->arg('access_type'); + + if (empty($name)) { + $this->showForm(_('Name is required.')); + return; + } elseif (mb_strlen($name) > 255) { $this->showForm(_('Name is too long (max 255 chars).')); return; - } else if (User_group::descriptionTooLong($description)) { + } elseif (empty($description)) { + $this->showForm(_('Description is required.')); + return; + } elseif (Oauth_application::descriptionTooLong($description)) { $this->showForm(sprintf( - _('description is too long (max %d chars).'), + _('Description is too long (max %d chars).'), Oauth_application::maxDescription())); return; - } elseif (!is_null($source_url) - && (strlen($source_url) > 0) + } elseif (empty($source_url)) { + $this->showForm(_('Source URL is required.')); + return; + } elseif ((strlen($source_url) > 0) && !Validate::uri( $source_url, array('allowed_schemes' => array('http', 'https')) ) - ) + ) { $this->showForm(_('Source URL is not valid.')); return; - } elseif (!is_null($homepage) - && (strlen($homepage) > 0) + } elseif (empty($organization)) { + $this->showForm(_('Organization is required.')); + return; + } elseif (mb_strlen($organization) > 255) { + $this->showForm(_('Organization is too long (max 255 chars).')); + return; + } elseif (empty($homepage)) { + $this->showForm(_('Organization homepage is required.')); + return; + } elseif ((strlen($homepage) > 0) && !Validate::uri( $homepage, array('allowed_schemes' => array('http', 'https')) ) - ) + ) { $this->showForm(_('Homepage is not a valid URL.')); - return; - } elseif (!is_null($callback_url) - && (strlen($callback_url) > 0) + return; + } elseif (empty($callback_url)) { + $this->showForm(_('Callback is required.')); + return; + } elseif (strlen($callback_url) > 0 && !Validate::uri( $source_url, array('allowed_schemes' => array('http', 'https')) ) - ) + ) { $this->showForm(_('Callback URL is not valid.')); return; } - + $cur = common_current_user(); // Checked in prepare() above @@ -171,31 +200,53 @@ class NewApplicationAction extends Action $app->query('BEGIN'); - $app->name = $name; - $app->owner = $cur->id; - $app->description = $description; - $app->source_url = $souce_url; + $app->name = $name; + $app->owner = $cur->id; + $app->description = $description; + $app->source_url = $source_url; $app->organization = $organization; - $app->homepage = $homepage; + $app->homepage = $homepage; $app->callback_url = $callback_url; - $app->type = $type; - $app->access_type = $access_type; - + $app->type = $type; + + // Yeah, I dunno why I chose bit flags. I guess so I could + // copy this value directly to Oauth_application_user + // access_type which I think does need bit flags -- Z + + if ($access_type == 'r') { + $app->setAccessFlags(true, false); + } else { + $app->setAccessFlags(true, true); + } + + $app->created = common_sql_now(); + // generate consumer key and secret - - $app->created = common_sql_now(); + + $consumer = Consumer::generateNew(); + + $result = $consumer->insert(); + + if (!$result) { + common_log_db_error($consumer, 'INSERT', __FILE__); + $this->serverError(_('Could not create application.')); + } + + $app->consumer_key = $consumer->consumer_key; $result = $app->insert(); if (!$result) { - common_log_db_error($group, 'INSERT', __FILE__); + common_log_db_error($app, 'INSERT', __FILE__); $this->serverError(_('Could not create application.')); + $app->query('ROLLBACK'); } - - $group->query('COMMIT'); - common_redirect($group->homeUrl(), 303); - + $app->query('COMMIT'); + + common_redirect(common_local_url('apps', + array('nickname' => $cur->nickname)), 303); + } } diff --git a/actions/oauthconnectionssettings.php b/actions/oauthconnectionssettings.php index 6ec9f7027..e4b5af158 100644 --- a/actions/oauthconnectionssettings.php +++ b/actions/oauthconnectionssettings.php @@ -132,4 +132,17 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction $this->elementEnd('div'); } + function showSections() + { + $cur = common_current_user(); + + $this->element('h2', null, 'Developers'); + $this->elementStart('p'); + $this->raw(_('Developers can edit the registration settings for their applications ')); + $this->element('a', + array('href' => common_local_url('apps', array('nickname' => $cur->nickname))), + 'here.'); + $this->elementEnd('p'); + } + } diff --git a/actions/showapplication.php b/actions/showapplication.php new file mode 100644 index 000000000..6b8eff4a6 --- /dev/null +++ b/actions/showapplication.php @@ -0,0 +1,306 @@ +. + * + * @category Application + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +/** + * Show an OAuth application + * + * @category Application + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class ShowApplicationAction extends OwnerDesignAction +{ + /** + * Application to show + */ + + var $application = null; + + /** + * User who owns the app + */ + + var $owner = null; + + + var $msg = null; + + var $success = null; + + /** + * Load attributes based on database arguments + * + * Loads all the DB stuff + * + * @param array $args $_REQUEST array + * + * @return success flag + */ + + function prepare($args) + { + parent::prepare($args); + + $id = (int)$this->arg('id'); + + $this->application = Oauth_application::staticGet($id); + $this->owner = User::staticGet($this->application->owner); + + if (!common_logged_in()) { + $this->clientError(_('You must be logged in to view an application.')); + return false; + } + + if (empty($this->application)) { + $this->clientError(_('No such application.'), 404); + return false; + } + + $cur = common_current_user(); + + if ($cur->id != $this->owner->id) { + $this->clientError(_('You are not the owner of this application.'), 401); + } + + return true; + } + + /** + * Handle the request + * + * Shows info about the app + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + + // CSRF protection + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->clientError(_('There was a problem with your session token.')); + return; + } + + if ($this->arg('reset')) { + $this->resetKey(); + } + } else { + $this->showPage(); + } + } + + /** + * Title of the page + * + * @return string title of the page + */ + + function title() + { + if (!empty($this->application->name)) { + return 'Application: ' . $this->application->name; + } + } + + function showPageNotice() + { + if (!empty($this->msg)) { + $this->element('div', ($this->success) ? 'success' : 'error', $this->msg); + } + } + + function showContent() + { + + $cur = common_current_user(); + + $this->elementStart('div', 'entity_actions'); + + $this->element('a', + array('href' => + common_local_url( + 'editapplication', + array( + 'nickname' => $this->owner->nickname, + 'id' => $this->application->id + ) + ) + ), 'Edit application'); + + $this->elementStart('form', array( + 'id' => 'forma_reset_key', + 'class' => 'form_reset_key', + 'method' => 'POST', + 'action' => common_local_url('showapplication', + array('nickname' => $cur->nickname, + 'id' => $this->application->id)))); + + $this->elementStart('fieldset'); + $this->hidden('token', common_session_token()); + $this->submit('reset', _('Reset Consumer key/secret')); + $this->elementEnd('fieldset'); + $this->elementEnd('form'); + + $this->elementEnd('div'); + + $consumer = $this->application->getConsumer(); + + $this->elementStart('div', 'entity-application'); + + $this->elementStart('ul', 'entity_application_details'); + + $this->elementStart('li', 'entity_application_name'); + $this->element('span', array('class' => 'big'), $this->application->name); + $this->raw(sprintf(_(' by %1$s'), $this->application->organization)); + $this->elementEnd('li'); + + $this->element('li', 'entity_application_description', $this->application->description); + + $this->elementStart('li', 'entity_application_statistics'); + + $defaultAccess = ($this->application->access_type & Oauth_application::$writeAccess) + ? 'read-write' : 'read-only'; + $profile = Profile::staticGet($this->application->owner); + $userCnt = 0; // XXX: count how many users use the app + + $this->raw(sprintf( + _('Created by %1$s - %2$s access by default - %3$d users.'), + $profile->getBestName(), + $defaultAccess, + $userCnt + )); + + $this->elementEnd('li'); + + $this->elementEnd('ul'); + + $this->elementStart('dl', 'entity_consumer_key'); + $this->element('dt', null, _('Consumer key')); + $this->element('dd', 'label', $consumer->consumer_key); + $this->elementEnd('dl'); + + $this->elementStart('dl', 'entity_consumer_secret'); + $this->element('dt', null, _('Consumer secret')); + $this->element('dd', 'label', $consumer->consumer_secret); + $this->elementEnd('dl'); + + $this->elementStart('dl', 'entity_request_token_url'); + $this->element('dt', null, _('Request token URL')); + $this->element('dd', 'label', common_local_url('oauthrequesttoken')); + $this->elementEnd('dl'); + + $this->elementStart('dl', 'entity_access_token_url'); + $this->element('dt', null, _('Access token URL')); + $this->element('dd', 'label', common_local_url('oauthaccesstoken')); + $this->elementEnd('dl'); + + $this->elementStart('dl', 'entity_authorize_url'); + $this->element('dt', null, _('Authorize URL')); + $this->element('dd', 'label', common_local_url('oauthauthorize')); + $this->elementEnd('dl'); + + $this->element('p', 'oauth-signature-note', + '*We support hmac-sha1 signatures. We do not support the plaintext signature method.'); + + $this->elementEnd('div'); + + $this->elementStart('div', 'entity-list-apps'); + $this->element('a', + array( + 'href' => common_local_url( + 'apps', + array('nickname' => $this->owner->nickname) + ) + ), + 'View your applications'); + $this->elementEnd('div'); + } + + function resetKey() + { + $this->application->query('BEGIN'); + + $consumer = $this->application->getConsumer(); + $result = $consumer->delete(); + + if (!$result) { + common_log_db_error($consumer, 'DELETE', __FILE__); + $this->success = false; + $this->msg = ('Unable to reset consumer key and secret.'); + $this->showPage(); + return; + } + + $consumer = Consumer::generateNew(); + + $result = $consumer->insert(); + + if (!$result) { + common_log_db_error($consumer, 'INSERT', __FILE__); + $this->application->query('ROLLBACK'); + $this->success = false; + $this->msg = ('Unable to reset consumer key and secret.'); + $this->showPage(); + return; + } + + $orig = clone($this->application); + $this->application->consumer_key = $consumer->consumer_key; + $result = $this->application->update($orig); + + if (!$result) { + common_log_db_error($application, 'UPDATE', __FILE__); + $this->application->query('ROLLBACK'); + $this->success = false; + $this->msg = ('Unable to reset consumer key and secret.'); + $this->showPage(); + return; + } + + $this->application->query('COMMIT'); + + $this->success = true; + $this->msg = ('Consumer key and secret reset.'); + $this->showPage(); + } + +} + diff --git a/classes/Consumer.php b/classes/Consumer.php index d17f183a8..ad64a8491 100644 --- a/classes/Consumer.php +++ b/classes/Consumer.php @@ -4,7 +4,7 @@ */ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Consumer extends Memcached_DataObject +class Consumer extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -22,4 +22,18 @@ class Consumer extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + static function generateNew() + { + $cons = new Consumer(); + $rand = common_good_rand(16); + + $cons->seed = $rand; + $cons->consumer_key = md5(time() + $rand); + $cons->consumer_secret = md5(md5(time() + time() + $rand)); + $cons->created = common_sql_now(); + + return $cons; + } + } diff --git a/classes/Oauth_application.php b/classes/Oauth_application.php index e2862bf97..ef1bbf6d9 100644 --- a/classes/Oauth_application.php +++ b/classes/Oauth_application.php @@ -31,4 +31,48 @@ class Oauth_application extends Memcached_DataObject } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + // Bit flags + public static $readAccess = 1; + public static $writeAccess = 2; + + public static $browser = 1; + public static $desktop = 2; + + function getConsumer() + { + return Consumer::staticGet('consumer_key', $this->consumer_key); + } + + static function maxDesc() + { + $desclimit = common_config('application', 'desclimit'); + // null => use global limit (distinct from 0!) + if (is_null($desclimit)) { + $desclimit = common_config('site', 'textlimit'); + } + return $desclimit; + } + + static function descriptionTooLong($desc) + { + $desclimit = self::maxDesc(); + return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit)); + } + + function setAccessFlags($read, $write) + { + if ($read) { + $this->access_type |= self::$readAccess; + } else { + $this->access_type &= ~self::$readAccess; + } + + if ($write) { + $this->access_type |= self::$writeAccess; + } else { + $this->access_type &= ~self::$writeAccess; + } + } + } diff --git a/db/statusnet.sql b/db/statusnet.sql index 03e6115e5..a2740b60c 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -219,7 +219,7 @@ create table oauth_application ( organization varchar(255) comment 'name of the organization running the application', homepage varchar(255) comment 'homepage for the organization', callback_url varchar(255) not null comment 'url to redirect to after authentication', - type tinyint default 0 comment 'type of app, 0 = browser, 1 = desktop', + type tinyint default 0 comment 'type of app, 1 = browser, 2 = desktop', access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified' diff --git a/lib/applicationeditform.php b/lib/applicationeditform.php index 3fd45876a..ed187ba0b 100644 --- a/lib/applicationeditform.php +++ b/lib/applicationeditform.php @@ -100,11 +100,16 @@ class ApplicationEditForm extends Form function action() { - if ($this->application) { + $cur = common_current_user(); + + if (!empty($this->application)) { return common_local_url('editapplication', - array('id' => $this->application->id)); + array('id' => $this->application->id, + 'nickname' => $cur->nickname) + ); } else { - return common_local_url('newapplication'); + return common_local_url('newapplication', + array('nickname' => $cur->nickname)); } } @@ -116,7 +121,7 @@ class ApplicationEditForm extends Form function formLegend() { - $this->out->element('legend', null, _('Register a new application')); + $this->out->element('legend', null, _('Edit application')); } /** @@ -130,7 +135,7 @@ class ApplicationEditForm extends Form if ($this->application) { $id = $this->application->id; $name = $this->application->name; - $description = $this->application->description; + $description = $this->application->description; $source_url = $this->application->source_url; $organization = $this->application->organization; $homepage = $this->application->homepage; @@ -151,34 +156,46 @@ class ApplicationEditForm extends Form $this->out->elementStart('ul', 'form_data'); $this->out->elementStart('li'); - + $this->out->hidden('application_id', $id); + $this->out->hidden('token', common_session_token()); + $this->out->input('name', _('Name'), ($this->out->arg('name')) ? $this->out->arg('name') : $name); - + $this->out->elementEnd('li'); - + $this->out->elementStart('li'); - $this->out->input('description', _('Description'), - ($this->out->arg('Description')) ? $this->out->arg('discription') : $description); + + $maxDesc = Oauth_application::maxDesc(); + if ($maxDesc > 0) { + $descInstr = sprintf(_('Describe your application in %d chars'), + $maxDesc); + } else { + $descInstr = _('Describe your application'); + } + $this->out->textarea('description', _('Description'), + ($this->out->arg('description')) ? $this->out->arg('description') : $description, + $descInstr); + $this->out->elementEnd('li'); - + $this->out->elementStart('li'); $this->out->input('source_url', _('Source URL'), ($this->out->arg('source_url')) ? $this->out->arg('source_url') : $source_url, _('URL of the homepage of this application')); - $this->out->elementEnd('li'); + $this->out->elementEnd('li'); $this->out->elementStart('li'); - $this->out->input('Organization', _('Organization'), - ($this->out->arg('organization')) ? $this->out->arg('organization') : $orgranization, + $this->out->input('organization', _('Organization'), + ($this->out->arg('organization')) ? $this->out->arg('organization') : $organization, _('Organization responsible for this application')); $this->out->elementEnd('li'); $this->out->elementStart('li'); $this->out->input('homepage', _('Homepage'), ($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage, - _('URL of the homepage of the organization')); + _('URL for the homepage of the organization')); $this->out->elementEnd('li'); $this->out->elementStart('li'); @@ -188,17 +205,86 @@ class ApplicationEditForm extends Form $this->out->elementEnd('li'); $this->out->elementStart('li'); - $this->out->input('type', _('Application type'), - ($this->out->arg('type')) ? $this->out->arg('type') : $type, - _('Type of application, browser or desktop')); + + $attrs = array('name' => 'app_type', + 'type' => 'radio', + 'id' => 'app_type-browser', + 'class' => 'radio', + 'value' => Oauth_application::$browser); + + // Default to Browser + + if ($this->application->type == Oauth_application::$browser + || empty($this->applicaiton->type)) { + $attrs['checked'] = 'checked'; + } + + $this->out->element('input', $attrs); + + $this->out->element('label', array('for' => 'app_type-browser', + 'class' => 'radio'), + _('Browser')); + + $attrs = array('name' => 'app_type', + 'type' => 'radio', + 'id' => 'app_type-dekstop', + 'class' => 'radio', + 'value' => Oauth_application::$desktop); + + if ($this->application->type == Oauth_application::$desktop) { + $attrs['checked'] = 'checked'; + } + + $this->out->element('input', $attrs); + + $this->out->element('label', array('for' => 'app_type-desktop', + 'class' => 'radio'), + _('Desktop')); + $this->out->element('p', 'form_guide', _('Type of application, browser or desktop')); $this->out->elementEnd('li'); - + $this->out->elementStart('li'); - $this->out->input('access_type', _('Default access'), - ($this->out->arg('access_type')) ? $this->out->arg('access_type') : $access_type, - _('Default access for this application: read-write, or read-only')); + + $attrs = array('name' => 'default_access_type', + 'type' => 'radio', + 'id' => 'default_access_type-r', + 'class' => 'radio', + 'value' => 'r'); + + // default to read-only access + + if ($this->application->access_type & Oauth_application::$readAccess + || empty($this->application->access_type)) { + $attrs['checked'] = 'checked'; + } + + $this->out->element('input', $attrs); + + $this->out->element('label', array('for' => 'default_access_type-ro', + 'class' => 'radio'), + _('Read-only')); + + $attrs = array('name' => 'default_access_type', + 'type' => 'radio', + 'id' => 'default_access_type-rw', + 'class' => 'radio', + 'value' => 'rw'); + + if ($this->application->access_type & Oauth_application::$readAccess + && $this->application->access_type & Oauth_application::$writeAccess + ) { + $attrs['checked'] = 'checked'; + } + + $this->out->element('input', $attrs); + + $this->out->element('label', array('for' => 'default_access_type-rw', + 'class' => 'radio'), + _('Read-write')); + $this->out->element('p', 'form_guide', _('Default access for this application: read-only, or read-write')); + $this->out->elementEnd('li'); - + $this->out->elementEnd('ul'); } @@ -210,6 +296,7 @@ class ApplicationEditForm extends Form function formActions() { - $this->out->submit('submit', _('Save')); + $this->out->submit('save', _('Save')); + $this->out->submit('cancel', _('Cancel')); } } diff --git a/lib/applicationlist.php b/lib/applicationlist.php index fed784bb6..3141ea974 100644 --- a/lib/applicationlist.php +++ b/lib/applicationlist.php @@ -20,7 +20,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @category Public + * @category Application * @package StatusNet * @author Zach Copley * @copyright 2008-2009 StatusNet, Inc. @@ -39,7 +39,7 @@ define('APPS_PER_PAGE', 20); /** * Widget to show a list of OAuth applications * - * @category Public + * @category Application * @package StatusNet * @author Zach Copley * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 @@ -50,10 +50,10 @@ class ApplicationList extends Widget { /** Current application, application query */ var $application = null; - + /** Owner of this list */ var $owner = null; - + /** Action object using us. */ var $action = null; @@ -87,14 +87,42 @@ class ApplicationList extends Widget function showApplication() { - $this->out->elementStart('li', array('class' => 'application', - 'id' => 'oauthclient-' . $this->application->id)); $user = common_current_user(); - $this->out->raw($this->application->name); - - $this->out->elementEnd('li'); + $this->out->elementStart('li', array('class' => 'application', + 'id' => 'oauthclient-' . $this->application->id)); + + $this->out->elementStart('a', + array('href' => common_local_url( + 'showapplication', + array( + 'nickname' => $user->nickname, + 'id' => $this->application->id + ) + ), + 'class' => 'url') + ); + + $this->out->raw($this->application->name); + $this->out->elementEnd('a'); + + $this->out->raw(' by '); + + $this->out->elementStart('a', + array( + 'href' => $this->application->homepage, + 'class' => 'url' + ) + ); + $this->out->raw($this->application->organization); + $this->out->elementEnd('a'); + + $this->out->elementStart('p', 'note'); + $this->out->raw($this->application->description); + $this->out->elementEnd('p'); + + $this->out->elementEnd('li'); } /* Override this in subclasses. */ diff --git a/lib/default.php b/lib/default.php index e3a043de1..b6ee72279 100644 --- a/lib/default.php +++ b/lib/default.php @@ -211,6 +211,8 @@ $default = 'uploads' => true, 'filecommand' => '/usr/bin/file', ), + 'application' => + array('desclimit' => null), 'group' => array('maxaliases' => 3, 'desclimit' => null), diff --git a/lib/router.php b/lib/router.php index 7b65ae215..a8dbbf6d0 100644 --- a/lib/router.php +++ b/lib/router.php @@ -641,13 +641,30 @@ class Router array('nickname' => '[a-zA-Z0-9]{1,64}')); } - $m->connect('apps/new', array('action' => 'newapplication')); - - $m->connect(':nickname/apps/edit', + $m->connect(':nickname/apps', + array('action' => 'apps'), + array('nickname' => '['.NICKNAME_FMT.']{1,64}')); + $m->connect(':nickname/apps/show/:id', + array('action' => 'showapplication'), + array('nickname' => '['.NICKNAME_FMT.']{1,64}', + 'id' => '[0-9]+') + ); + $m->connect(':nickname/apps/new', + array('action' => 'newapplication'), + array('nickname' => '['.NICKNAME_FMT.']{1,64}')); + $m->connect(':nickname/apps/edit/:id', array('action' => 'editapplication'), - array('nickname' => '['.NICKNAME_FMT.']{1,64}') + array('nickname' => '['.NICKNAME_FMT.']{1,64}', + 'id' => '[0-9]+') ); + $m->connect('oauth/request_token', + array('action' => 'oauthrequesttoken')); + $m->connect('oauth/access_token', + array('action' => 'oauthaccesstoken')); + $m->connect('oauth/authorize', + array('action' => 'oauthauthorize')); + foreach (array('subscriptions', 'subscribers') as $a) { $m->connect(':nickname/'.$a.'/:tag', array('action' => $a), -- cgit v1.2.3-54-g00ecf From c473a39a7da07fbe5b80fec4c08111a554691c3a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sun, 10 Jan 2010 23:03:30 -0800 Subject: Associate request tokens with OAuth apps and app users --- actions/apioauthauthorize.php | 64 +++++++++++++++++++++++++++++--------- classes/Oauth_application_user.php | 24 +++++++++++++- classes/statusnet.ini | 4 +++ db/statusnet.sql | 5 ++- 4 files changed, 81 insertions(+), 16 deletions(-) (limited to 'db') diff --git a/actions/apioauthauthorize.php b/actions/apioauthauthorize.php index 895a0c6e5..48d5087ef 100644 --- a/actions/apioauthauthorize.php +++ b/actions/apioauthauthorize.php @@ -125,19 +125,12 @@ class ApiOauthAuthorizeAction extends Action parent::handle($args); if ($_SERVER['REQUEST_METHOD'] == 'POST') { - /* 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. '. - 'Try again, please.')); - return; - } $this->handlePost(); } else { - common_debug('ApiOauthAuthorize::handle()'); + // XXX: make better error messages if (empty($this->oauth_token)) { @@ -160,7 +153,7 @@ class ApiOauthAuthorizeAction extends Action function handlePost() { - /* Use a session token for CSRF protection. */ + // check session token for CSRF protection. $token = $this->trimmed('token'); @@ -175,25 +168,66 @@ class ApiOauthAuthorizeAction extends Action return; } - // is the user already logged in? - // check creds + $user = null; + if (!common_logged_in()) { $user = common_check_user($this->nickname, $this->password); if (empty($user)) { $this->showForm(_("Invalid nickname / password!")); return; } - } + } else { + $user = common_current_user(); + } if ($this->arg('allow')) { + // mark the req token as authorized + $this->store->authorize_token($this->oauth_token); + // Check to see if there was a previous token associated + // with this user/app and kill it. If you're doing this you + // probably don't want any old tokens anyway. + + $appUser = Oauth_application_user::getByKeys($user, $this->app); + + if (!empty($appUser)) { + $result = $appUser->delete(); + + if (!$result) { + common_log_db_error($appUser, 'DELETE', __FILE__); + throw new ServerException(_('DB error deleting OAuth app user.')); + return; + } + } + + // associated the new req token with the user and the app + + $appUser = new Oauth_application_user(); + + $appUser->profile_id = $user->id; + $appUser->application_id = $this->app->id; + $appUser->access_type = $this->app->access_type; + $appUser->token = $this->oauth_token; + $appUser->created = common_sql_now(); + + $result = $appUser->insert(); + + if (!$result) { + common_log_db_error($appUser, 'INSERT', __FILE__); + throw new ServerException(_('DB error inserting OAuth app user.')); + return; + } + // if we have a callback redirect and provide the token if (!empty($this->callback)) { + + // XXX: Need better way to build this redirect url. + $target_url = $this->callback . '?oauth_token=' . $this->oauth_token; common_redirect($target_url, 303); } @@ -202,7 +236,7 @@ class ApiOauthAuthorizeAction extends Action $this->elementStart('p'); - // XXX: Do verifier code? + // XXX: Do OAuth 1.0a verifier code? $this->raw(sprintf(_("The request token %s has been authorized. " . 'Please exchange it for an access token.'), @@ -233,7 +267,9 @@ class ApiOauthAuthorizeAction extends Action function showScripts() { parent::showScripts(); - // $this->autofocus('nickname'); + if (!common_logged_in()) { + $this->autofocus('nickname'); + } } /** diff --git a/classes/Oauth_application_user.php b/classes/Oauth_application_user.php index 9e45ece25..e4c018f21 100644 --- a/classes/Oauth_application_user.php +++ b/classes/Oauth_application_user.php @@ -13,12 +13,34 @@ class Oauth_application_user extends Memcached_DataObject public $profile_id; // int(4) primary_key not_null public $application_id; // int(4) primary_key not_null public $access_type; // tinyint(1) + public $token; // varchar(255) + public $secret; // varchar(255) + public $verifier; // varchar(255) public $created; // datetime not_null + public $modified; // timestamp not_null default_CURRENT_TIMESTAMP /* Static get */ function staticGet($k,$v=NULL) { - return Memcached_DataObject::staticGet('Oauth_application_user',$k,$v); + return Memcached_DataObject::staticGet('Oauth_application_user',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + static function getByKeys($user, $app) + { + if (empty($user) || empty($app)) { + return null; + } + + $oau = new Oauth_application_user(); + + $oau->profile_id = $user->id; + $oau->application_id = $app->id; + $oau->limit(1); + + $result = $oau->find(true); + + return empty($result) ? null : $oau; + } + } diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 0cbe60a5a..43f6c4466 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -372,7 +372,11 @@ id = N profile_id = 129 application_id = 129 access_type = 17 +token = 2 +secret = 2 +verifier = 2 created = 142 +modified = 384 [oauth_application_user__keys] profile_id = K diff --git a/db/statusnet.sql b/db/statusnet.sql index a2740b60c..eb4706067 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -229,8 +229,11 @@ create table oauth_application_user ( profile_id integer not null comment 'user of the application' references profile (id), application_id integer not null comment 'id of the application' references oauth_application (id), access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked', + token varchar(255) comment 'authorization token', + secret varchar(255) comment 'token secret', + verifier varchar(255) not null comment 'verification code', created datetime not null comment 'date this record was created', - + modified timestamp comment 'date this record was modified', constraint primary key (profile_id, application_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; -- cgit v1.2.3-54-g00ecf From c2337ab47c183ab9758f5db8632ac9cd480a282a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 11 Jan 2010 12:17:36 -0800 Subject: Decided we didn't need to keep the token secret in the Oauth_application_user record --- classes/Oauth_application_user.php | 1 - classes/statusnet.ini | 1 - db/statusnet.sql | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) (limited to 'db') diff --git a/classes/Oauth_application_user.php b/classes/Oauth_application_user.php index e4c018f21..a05371f56 100644 --- a/classes/Oauth_application_user.php +++ b/classes/Oauth_application_user.php @@ -14,7 +14,6 @@ class Oauth_application_user extends Memcached_DataObject public $application_id; // int(4) primary_key not_null public $access_type; // tinyint(1) public $token; // varchar(255) - public $secret; // varchar(255) public $verifier; // varchar(255) public $created; // datetime not_null public $modified; // timestamp not_null default_CURRENT_TIMESTAMP diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 43f6c4466..b358bbf60 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -373,7 +373,6 @@ profile_id = 129 application_id = 129 access_type = 17 token = 2 -secret = 2 verifier = 2 created = 142 modified = 384 diff --git a/db/statusnet.sql b/db/statusnet.sql index eb4706067..c3160bcf8 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -229,8 +229,7 @@ create table oauth_application_user ( profile_id integer not null comment 'user of the application' references profile (id), application_id integer not null comment 'id of the application' references oauth_application (id), access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked', - token varchar(255) comment 'authorization token', - secret varchar(255) comment 'token secret', + token varchar(255) comment 'request or access token', verifier varchar(255) not null comment 'verification code', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified', -- cgit v1.2.3-54-g00ecf From 7694955cd654becf8f03dc4eca271d8188141596 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 13 Jan 2010 01:16:42 +0000 Subject: Callback URL can be null --- db/statusnet.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'db') diff --git a/db/statusnet.sql b/db/statusnet.sql index c3160bcf8..b1867e7f0 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -218,7 +218,7 @@ create table oauth_application ( source_url varchar(255) comment 'application homepage - used for source link', organization varchar(255) comment 'name of the organization running the application', homepage varchar(255) comment 'homepage for the organization', - callback_url varchar(255) not null comment 'url to redirect to after authentication', + callback_url varchar(255) comment 'url to redirect to after authentication', type tinyint default 0 comment 'type of app, 1 = browser, 2 = desktop', access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write', created datetime not null comment 'date this record was created', -- cgit v1.2.3-54-g00ecf From d33040089d660d897183df8e94c2a65bb8c8c85f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 13 Jan 2010 21:14:22 +0000 Subject: Remove verifier from Oauth_application_user (not needed there) --- classes/Oauth_application_user.php | 1 - classes/statusnet.ini | 1 - db/statusnet.sql | 1 - 3 files changed, 3 deletions(-) (limited to 'db') diff --git a/classes/Oauth_application_user.php b/classes/Oauth_application_user.php index 618d68133..57986281f 100644 --- a/classes/Oauth_application_user.php +++ b/classes/Oauth_application_user.php @@ -14,7 +14,6 @@ class Oauth_application_user extends Memcached_DataObject public $application_id; // int(4) primary_key not_null public $access_type; // tinyint(1) public $token; // varchar(255) - public $verifier; // varchar(255) public $created; // datetime not_null public $modified; // timestamp not_null default_CURRENT_TIMESTAMP diff --git a/classes/statusnet.ini b/classes/statusnet.ini index b358bbf60..2b5f2c225 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -373,7 +373,6 @@ profile_id = 129 application_id = 129 access_type = 17 token = 2 -verifier = 2 created = 142 modified = 384 diff --git a/db/statusnet.sql b/db/statusnet.sql index b1867e7f0..3a74f9d7a 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -230,7 +230,6 @@ create table oauth_application_user ( application_id integer not null comment 'id of the application' references oauth_application (id), access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked', token varchar(255) comment 'request or access token', - verifier varchar(255) not null comment 'verification code', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified', constraint primary key (profile_id, application_id) -- cgit v1.2.3-54-g00ecf From 6efbf2777ac1ba934829a8e9ae381ca280621c0c Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 13 Jan 2010 21:31:19 +0000 Subject: Add verifier and verified callback to token for OAuth 1.0a --- classes/Token.php | 6 ++++-- classes/statusnet.ini | 2 ++ db/statusnet.sql | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'db') diff --git a/classes/Token.php b/classes/Token.php index 1fabd72f1..a129d1fd1 100644 --- a/classes/Token.php +++ b/classes/Token.php @@ -4,7 +4,7 @@ */ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Token extends Memcached_DataObject +class Token extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -14,7 +14,9 @@ class Token extends Memcached_DataObject public $tok; // char(32) primary_key not_null public $secret; // char(32) not_null public $type; // tinyint(1) not_null - public $state; // tinyint(1) + public $state; // tinyint(1) + public $verifier; // varchar(255) + public $verified_callback; // varchar(255) public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 2b5f2c225..6203650a6 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -516,6 +516,8 @@ tok = 130 secret = 130 type = 145 state = 17 +verifier = 2 +verified_callback = 2 created = 142 modified = 384 diff --git a/db/statusnet.sql b/db/statusnet.sql index 3a74f9d7a..17de4fd0d 100644 --- a/db/statusnet.sql +++ b/db/statusnet.sql @@ -189,6 +189,8 @@ create table token ( secret char(32) not null comment 'secret value', type tinyint not null default 0 comment 'request or access', state tinyint default 0 comment 'for requests, 0 = initial, 1 = authorized, 2 = used', + verifier varchar(255) comment 'verifier string for OAuth 1.0a', + verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified', -- cgit v1.2.3-54-g00ecf From ad6f0501ff24cb287dedd21271d58c91e64b6b43 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 26 Jan 2010 09:25:39 -0800 Subject: Site metadata tags in status_network: single 'tags' field, pipe-separated. $sn->tags() returns tag list as array; $sn->hasTag('blah') to check for a particular tag only Could be used to control things in config file: $sn = Status_network::setupSite($_server, $_path, $_wildcard); if (!$sn) { die("No such site"); } if ($sn->hasTag('individual')) { /* blah */ } Note memcached keys are unchanged; if tags are changed from an external tool clear: statusnet::status_network:: for s 'nickname', 'hostname', and 'pathname' --- classes/Status_network.php | 20 ++++++++++++++++++++ db/site.sql | 2 ++ 2 files changed, 22 insertions(+) (limited to 'db') diff --git a/classes/Status_network.php b/classes/Status_network.php index 445f8a5a3..f1314d615 100644 --- a/classes/Status_network.php +++ b/classes/Status_network.php @@ -39,6 +39,7 @@ class Status_network extends DB_DataObject public $logo; // varchar(255) public $created; // datetime() not_null public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP + public $tags; // text /* Static get */ function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Status_network',$k,$v); } @@ -245,4 +246,23 @@ class Status_network extends DB_DataObject return $this->nickname . '.' . self::$wildcard; } } + + /** + * Return site meta-info tags as an array + * @return array of strings + */ + function getTags() + { + return array_filter(explode("|", strval($this->tags))); + } + + /** + * Check if this site record has a particular meta-info tag attached. + * @param string $tag + * @return bool + */ + function hasTag($tag) + { + return in_array($tag, $this->getTags()); + } } diff --git a/db/site.sql b/db/site.sql index a9f64e5a5..791303bd5 100644 --- a/db/site.sql +++ b/db/site.sql @@ -14,6 +14,8 @@ create table status_network ( sitename varchar(255) comment 'display name', theme varchar(255) comment 'theme name', logo varchar(255) comment 'site logo', + + tags text comment 'site meta-info tags (pipe-separated)', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified' -- cgit v1.2.3-54-g00ecf From 47645228da4a9af8ffb0dc1f11c1da995f4791cb Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 27 Jan 2010 13:58:55 -0800 Subject: Add new oauth tables and modifications to 'consumer' table for rc4 --- db/rc3to09.sql | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'db') diff --git a/db/rc3to09.sql b/db/rc3to09.sql index 02dc7a6e2..8342c4bc6 100644 --- a/db/rc3to09.sql +++ b/db/rc3to09.sql @@ -14,3 +14,35 @@ insert into queue_item_new (frame,transport,created,claimed) alter table queue_item rename to queue_item_old; alter table queue_item_new rename to queue_item; +alter table consumer + add consumer_secret varchar(255) not null comment 'secret value', + add verifier varchar(255) comment 'verifier string for OAuth 1.0a', + add verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a'; + +create table oauth_application ( + id integer auto_increment primary key comment 'unique identifier', + owner integer not null comment 'owner of the application' references profile (id), + consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key), + name varchar(255) not null comment 'name of the application', + description varchar(255) comment 'description of the application', + icon varchar(255) not null comment 'application icon', + source_url varchar(255) comment 'application homepage - used for source link', + organization varchar(255) comment 'name of the organization running the application', + homepage varchar(255) comment 'homepage for the organization', + callback_url varchar(255) comment 'url to redirect to after authentication', + type tinyint default 0 comment 'type of app, 1 = browser, 2 = desktop', + access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified' +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table oauth_application_user ( + profile_id integer not null comment 'user of the application' references profile (id), + application_id integer not null comment 'id of the application' references oauth_application (id), + access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked', + token varchar(255) comment 'request or access token', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified', + constraint primary key (profile_id, application_id) +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + -- cgit v1.2.3-54-g00ecf From 9a54745fcd252e27cc664da7cee67b48d0f4f501 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 27 Jan 2010 13:59:58 -0800 Subject: Rename rc3to09.sql to rc3torc4.sql to avoid confusion if we add a last-minute change after this! --- db/rc3to09.sql | 48 ------------------------------------------------ db/rc3torc4.sql | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 48 deletions(-) delete mode 100644 db/rc3to09.sql create mode 100644 db/rc3torc4.sql (limited to 'db') diff --git a/db/rc3to09.sql b/db/rc3to09.sql deleted file mode 100644 index 8342c4bc6..000000000 --- a/db/rc3to09.sql +++ /dev/null @@ -1,48 +0,0 @@ -create table queue_item_new ( - id integer auto_increment primary key comment 'unique identifier', - frame blob not null comment 'data: object reference or opaque string', - transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...', - created datetime not null comment 'date this record was created', - claimed datetime comment 'date this item was claimed', - - index queue_item_created_idx (created) - -) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; - -insert into queue_item_new (frame,transport,created,claimed) - select notice_id,transport,created,claimed from queue_item; -alter table queue_item rename to queue_item_old; -alter table queue_item_new rename to queue_item; - -alter table consumer - add consumer_secret varchar(255) not null comment 'secret value', - add verifier varchar(255) comment 'verifier string for OAuth 1.0a', - add verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a'; - -create table oauth_application ( - id integer auto_increment primary key comment 'unique identifier', - owner integer not null comment 'owner of the application' references profile (id), - consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key), - name varchar(255) not null comment 'name of the application', - description varchar(255) comment 'description of the application', - icon varchar(255) not null comment 'application icon', - source_url varchar(255) comment 'application homepage - used for source link', - organization varchar(255) comment 'name of the organization running the application', - homepage varchar(255) comment 'homepage for the organization', - callback_url varchar(255) comment 'url to redirect to after authentication', - type tinyint default 0 comment 'type of app, 1 = browser, 2 = desktop', - access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write', - created datetime not null comment 'date this record was created', - modified timestamp comment 'date this record was modified' -) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; - -create table oauth_application_user ( - profile_id integer not null comment 'user of the application' references profile (id), - application_id integer not null comment 'id of the application' references oauth_application (id), - access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked', - token varchar(255) comment 'request or access token', - created datetime not null comment 'date this record was created', - modified timestamp comment 'date this record was modified', - constraint primary key (profile_id, application_id) -) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; - diff --git a/db/rc3torc4.sql b/db/rc3torc4.sql new file mode 100644 index 000000000..8342c4bc6 --- /dev/null +++ b/db/rc3torc4.sql @@ -0,0 +1,48 @@ +create table queue_item_new ( + id integer auto_increment primary key comment 'unique identifier', + frame blob not null comment 'data: object reference or opaque string', + transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...', + created datetime not null comment 'date this record was created', + claimed datetime comment 'date this item was claimed', + + index queue_item_created_idx (created) + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +insert into queue_item_new (frame,transport,created,claimed) + select notice_id,transport,created,claimed from queue_item; +alter table queue_item rename to queue_item_old; +alter table queue_item_new rename to queue_item; + +alter table consumer + add consumer_secret varchar(255) not null comment 'secret value', + add verifier varchar(255) comment 'verifier string for OAuth 1.0a', + add verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a'; + +create table oauth_application ( + id integer auto_increment primary key comment 'unique identifier', + owner integer not null comment 'owner of the application' references profile (id), + consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key), + name varchar(255) not null comment 'name of the application', + description varchar(255) comment 'description of the application', + icon varchar(255) not null comment 'application icon', + source_url varchar(255) comment 'application homepage - used for source link', + organization varchar(255) comment 'name of the organization running the application', + homepage varchar(255) comment 'homepage for the organization', + callback_url varchar(255) comment 'url to redirect to after authentication', + type tinyint default 0 comment 'type of app, 1 = browser, 2 = desktop', + access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified' +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table oauth_application_user ( + profile_id integer not null comment 'user of the application' references profile (id), + application_id integer not null comment 'id of the application' references oauth_application (id), + access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked', + token varchar(255) comment 'request or access token', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified', + constraint primary key (profile_id, application_id) +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + -- cgit v1.2.3-54-g00ecf From 07d50a012af70d9bd35a26f645d791ae7ba29986 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 27 Jan 2010 17:34:13 -0800 Subject: fix update script -- read the diff wrong and put a couple fields on wrong table (whoops) --- db/rc3torc4.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'db') diff --git a/db/rc3torc4.sql b/db/rc3torc4.sql index 8342c4bc6..917c1f1c4 100644 --- a/db/rc3torc4.sql +++ b/db/rc3torc4.sql @@ -15,7 +15,9 @@ alter table queue_item rename to queue_item_old; alter table queue_item_new rename to queue_item; alter table consumer - add consumer_secret varchar(255) not null comment 'secret value', + add consumer_secret varchar(255) not null comment 'secret value'; + +alter table token add verifier varchar(255) comment 'verifier string for OAuth 1.0a', add verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a'; -- cgit v1.2.3-54-g00ecf