forked from GNUsocial/gnu-social
Merge branch 'testing' of git@gitorious.org:statusnet/mainline into testing
This commit is contained in:
commit
536170d788
@ -82,4 +82,18 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this action read only?
|
||||||
|
*
|
||||||
|
* @param array $args other arguments
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
94
actions/apioauthaccesstoken.php
Normal file
94
actions/apioauthaccesstoken.php
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Exchange an authorized OAuth request token for an access token
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @copyright 2010 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')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchange an authorized OAuth request token for an access token
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ApiOauthAccessTokenAction extends ApiOauthAction
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class handler.
|
||||||
|
*
|
||||||
|
* @param array $args array of arguments
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
|
$datastore = new ApiStatusNetOAuthDataStore();
|
||||||
|
$server = new OAuthServer($datastore);
|
||||||
|
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||||
|
|
||||||
|
$server->add_signature_method($hmac_method);
|
||||||
|
|
||||||
|
$atok = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$req = OAuthRequest::from_request();
|
||||||
|
$atok = $server->fetch_access_token($req);
|
||||||
|
|
||||||
|
} catch (OAuthException $e) {
|
||||||
|
common_log(LOG_WARN, 'API OAuthException - ' . $e->getMessage());
|
||||||
|
common_debug(var_export($req, true));
|
||||||
|
$this->outputError($e->getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($atok)) {
|
||||||
|
common_debug('couldn\'t get access token.');
|
||||||
|
print "Token exchange failed. Has the request token been authorized?\n";
|
||||||
|
} else {
|
||||||
|
print $atok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function outputError($msg)
|
||||||
|
{
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Content-Type: text/html; charset=utf-8');
|
||||||
|
print $msg . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
376
actions/apioauthauthorize.php
Normal file
376
actions/apioauthauthorize.php
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Authorize an OAuth request token
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @copyright 2010 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')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorize an OAuth request token
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ApiOauthAuthorizeAction extends ApiOauthAction
|
||||||
|
{
|
||||||
|
var $oauth_token;
|
||||||
|
var $callback;
|
||||||
|
var $app;
|
||||||
|
var $nickname;
|
||||||
|
var $password;
|
||||||
|
var $store;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a read-only action?
|
||||||
|
*
|
||||||
|
* @return boolean false
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
common_debug("apioauthauthorize");
|
||||||
|
|
||||||
|
$this->nickname = $this->trimmed('nickname');
|
||||||
|
$this->password = $this->arg('password');
|
||||||
|
$this->oauth_token = $this->arg('oauth_token');
|
||||||
|
$this->callback = $this->arg('oauth_callback');
|
||||||
|
$this->store = new ApiStatusNetOAuthDataStore();
|
||||||
|
$this->app = $this->store->getAppByRequestToken($this->oauth_token);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle input, produce output
|
||||||
|
*
|
||||||
|
* Switches on request method; either shows the form or handles its input.
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
|
||||||
|
$this->handlePost();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// XXX: make better error messages
|
||||||
|
|
||||||
|
if (empty($this->oauth_token)) {
|
||||||
|
|
||||||
|
common_debug("No request token found.");
|
||||||
|
|
||||||
|
$this->clientError(_('Bad request.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->app)) {
|
||||||
|
common_debug('No app for that token.');
|
||||||
|
$this->clientError(_('Bad request.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $this->app->name;
|
||||||
|
common_debug("Requesting auth for app: " . $name);
|
||||||
|
|
||||||
|
$this->showForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePost()
|
||||||
|
{
|
||||||
|
common_debug("handlePost()");
|
||||||
|
|
||||||
|
// check 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 the user is doing this she
|
||||||
|
// probably doesn'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 authorized req token with the user and the app
|
||||||
|
|
||||||
|
$appUser = new Oauth_application_user();
|
||||||
|
|
||||||
|
$appUser->profile_id = $user->id;
|
||||||
|
$appUser->application_id = $this->app->id;
|
||||||
|
|
||||||
|
// Note: do not copy the access type from the application.
|
||||||
|
// The access type should always be 0 when the OAuth app
|
||||||
|
// user record has a request token associated with it.
|
||||||
|
// Access type gets assigned once an access token has been
|
||||||
|
// granted. The OAuth app user record then gets updated
|
||||||
|
// with the new access token and 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
|
||||||
|
|
||||||
|
// A callback specified in the app setup overrides whatever
|
||||||
|
// is passed in with the request.
|
||||||
|
|
||||||
|
common_debug("Req token is authorized - doing callback");
|
||||||
|
|
||||||
|
if (!empty($this->app->callback_url)) {
|
||||||
|
$this->callback = $this->app->callback_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->callback)) {
|
||||||
|
|
||||||
|
// XXX: Need better way to build this redirect url.
|
||||||
|
|
||||||
|
$target_url = $this->getCallback($this->callback,
|
||||||
|
array('oauth_token' => $this->oauth_token));
|
||||||
|
|
||||||
|
common_debug("Doing callback to $target_url");
|
||||||
|
|
||||||
|
common_redirect($target_url, 303);
|
||||||
|
} else {
|
||||||
|
common_debug("callback was empty!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise inform the user that the rt was authorized
|
||||||
|
|
||||||
|
$this->elementStart('p');
|
||||||
|
|
||||||
|
// XXX: Do OAuth 1.0a verifier code
|
||||||
|
|
||||||
|
$this->raw(sprintf(_("The request token %s has been authorized. " .
|
||||||
|
'Please exchange it for an access token.'),
|
||||||
|
$this->oauth_token));
|
||||||
|
|
||||||
|
$this->elementEnd('p');
|
||||||
|
|
||||||
|
} else if ($this->arg('deny')) {
|
||||||
|
|
||||||
|
$this->elementStart('p');
|
||||||
|
|
||||||
|
$this->raw(sprintf(_("The request token %s has been denied."),
|
||||||
|
$this->oauth_token));
|
||||||
|
|
||||||
|
$this->elementEnd('p');
|
||||||
|
} else {
|
||||||
|
$this->clientError(_('Unexpected form submission.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showForm($error=null)
|
||||||
|
{
|
||||||
|
$this->error = $error;
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showScripts()
|
||||||
|
{
|
||||||
|
parent::showScripts();
|
||||||
|
if (!common_logged_in()) {
|
||||||
|
$this->autofocus('nickname');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the page
|
||||||
|
*
|
||||||
|
* @return string title of the page
|
||||||
|
*/
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('An application would like to connect to your account');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the authorization form.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$this->elementStart('form', array('method' => 'post',
|
||||||
|
'id' => 'form_apioauthauthorize',
|
||||||
|
'class' => 'form_settings',
|
||||||
|
'action' => common_local_url('apioauthauthorize')));
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
$this->element('legend', array('id' => 'apioauthauthorize_allowdeny'),
|
||||||
|
_('Allow or deny access'));
|
||||||
|
|
||||||
|
$this->hidden('token', common_session_token());
|
||||||
|
$this->hidden('oauth_token', $this->oauth_token);
|
||||||
|
$this->hidden('oauth_callback', $this->callback);
|
||||||
|
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->elementStart('p');
|
||||||
|
if (!empty($this->app->icon)) {
|
||||||
|
$this->element('img', array('src' => $this->app->icon));
|
||||||
|
}
|
||||||
|
|
||||||
|
$access = ($this->app->access_type & Oauth_application::$writeAccess) ?
|
||||||
|
'access and update' : 'access';
|
||||||
|
|
||||||
|
$msg = _("The application <strong>%s</strong> by <strong>%s</strong> would like " .
|
||||||
|
"the ability to <strong>%s</strong> your account data.");
|
||||||
|
|
||||||
|
$this->raw(sprintf($msg,
|
||||||
|
$this->app->name,
|
||||||
|
$this->app->organization,
|
||||||
|
$access));
|
||||||
|
$this->elementEnd('p');
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
|
if (!common_logged_in()) {
|
||||||
|
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
$this->element('legend', null, _('Account'));
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->input('nickname', _('Nickname'));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->password('password', _('Password'));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->element('input', array('id' => 'deny_submit',
|
||||||
|
'class' => 'submit submit form_action-primary',
|
||||||
|
'name' => 'deny',
|
||||||
|
'type' => 'submit',
|
||||||
|
'value' => _('Deny')));
|
||||||
|
|
||||||
|
$this->element('input', array('id' => 'allow_submit',
|
||||||
|
'class' => 'submit submit form_action-secondary',
|
||||||
|
'name' => 'allow',
|
||||||
|
'type' => 'submit',
|
||||||
|
'value' => _('Allow')));
|
||||||
|
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
$this->elementEnd('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructions for using the form
|
||||||
|
*
|
||||||
|
* For "remembered" logins, we make the user re-login when they
|
||||||
|
* try to change settings. Different instructions for this case.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getInstructions()
|
||||||
|
{
|
||||||
|
return _('Allow or deny access to your account information.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A local menu
|
||||||
|
*
|
||||||
|
* Shows different login/register actions.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showLocalNav()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
99
actions/apioauthrequesttoken.php
Normal file
99
actions/apioauthrequesttoken.php
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Get an OAuth request token
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @copyright 2010 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')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an OAuth request token
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ApiOauthRequestTokenAction extends ApiOauthAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Take arguments for running
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST args
|
||||||
|
*
|
||||||
|
* @return boolean success flag
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
$this->callback = $this->arg('oauth_callback');
|
||||||
|
|
||||||
|
if (!empty($this->callback)) {
|
||||||
|
common_debug("callback: $this->callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class handler.
|
||||||
|
*
|
||||||
|
* @param array $args array of arguments
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
|
$datastore = new ApiStatusNetOAuthDataStore();
|
||||||
|
$server = new OAuthServer($datastore);
|
||||||
|
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||||
|
|
||||||
|
$server->add_signature_method($hmac_method);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$req = OAuthRequest::from_request();
|
||||||
|
$token = $server->fetch_request_token($req);
|
||||||
|
print $token;
|
||||||
|
} catch (OAuthException $e) {
|
||||||
|
common_log(LOG_WARN, 'API OAuthException - ' . $e->getMessage());
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Content-Type: text/html; charset=utf-8');
|
||||||
|
print $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -85,6 +85,11 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
$this->lat = $this->trimmed('lat');
|
$this->lat = $this->trimmed('lat');
|
||||||
$this->lon = $this->trimmed('long');
|
$this->lon = $this->trimmed('long');
|
||||||
|
|
||||||
|
// try to set the source attr from OAuth app
|
||||||
|
if (empty($this->source)) {
|
||||||
|
$this->source = $this->oauth_source;
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
|
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
|
||||||
$this->source = 'api';
|
$this->source = 'api';
|
||||||
}
|
}
|
||||||
|
264
actions/editapplication.php
Normal file
264
actions/editapplication.php
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Edit an OAuth Application
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category Applications
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @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 <zach@status.net>
|
||||||
|
* @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 $owner = 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);
|
||||||
|
$this->owner = User::staticGet($this->app->owner);
|
||||||
|
$cur = common_current_user();
|
||||||
|
|
||||||
|
if ($cur->id != $this->owner->id) {
|
||||||
|
$this->clientError(_('You are not the owner of this application.'), 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 app.
|
||||||
|
*
|
||||||
|
* @param array $args unused
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
$this->handlePost($args);
|
||||||
|
} else {
|
||||||
|
$this->showForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePost($args)
|
||||||
|
{
|
||||||
|
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||||
|
// length > post_max_size in php.ini
|
||||||
|
|
||||||
|
if (empty($_FILES)
|
||||||
|
&& empty($_POST)
|
||||||
|
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||||
|
) {
|
||||||
|
$msg = _('The server was unable to handle that much POST ' .
|
||||||
|
'data (%s bytes) due to its current configuration.');
|
||||||
|
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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('id' => $this->app->id)), 303);
|
||||||
|
} elseif ($this->arg('save')) {
|
||||||
|
$this->trySave();
|
||||||
|
} else {
|
||||||
|
$this->clientError(_('Unexpected form submission.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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('default_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 (mb_strlen($source_url) > 255) {
|
||||||
|
$this->showForm(_('Source URL is too long.'));
|
||||||
|
return;
|
||||||
|
} elseif ((mb_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 ((mb_strlen($homepage) > 0)
|
||||||
|
&& !Validate::uri($homepage,
|
||||||
|
array('allowed_schemes' => array('http', 'https'))))
|
||||||
|
{
|
||||||
|
$this->showForm(_('Homepage is not a valid URL.'));
|
||||||
|
return;
|
||||||
|
} elseif (mb_strlen($callback_url) > 255) {
|
||||||
|
$this->showForm(_('Callback is too long.'));
|
||||||
|
return;
|
||||||
|
} elseif (mb_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));
|
||||||
|
assert(!is_null($this->app));
|
||||||
|
|
||||||
|
$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;
|
||||||
|
|
||||||
|
common_debug("access_type = $access_type");
|
||||||
|
|
||||||
|
if ($access_type == 'r') {
|
||||||
|
$this->app->access_type = 1;
|
||||||
|
} else {
|
||||||
|
$this->app->access_type = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->app->update($orig);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
common_log_db_error($this->app, 'UPDATE', __FILE__);
|
||||||
|
$this->serverError(_('Could not update application.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->app->uploadLogo();
|
||||||
|
|
||||||
|
common_redirect(common_local_url('oauthappssettings'), 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
277
actions/newapplication.php
Normal file
277
actions/newapplication.php
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Register a new OAuth Application
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category Applications
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new application
|
||||||
|
*
|
||||||
|
* This is the form for adding a new application
|
||||||
|
*
|
||||||
|
* @category Application
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class NewApplicationAction extends OwnerDesignAction
|
||||||
|
{
|
||||||
|
var $msg;
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('New Application');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare to run
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
if (!common_logged_in()) {
|
||||||
|
$this->clientError(_('You must be logged in to register an application.'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the request
|
||||||
|
*
|
||||||
|
* On GET, show the form. On POST, try to save the app.
|
||||||
|
*
|
||||||
|
* @param array $args unused
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
$this->handlePost($args);
|
||||||
|
} else {
|
||||||
|
$this->showForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePost($args)
|
||||||
|
{
|
||||||
|
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||||
|
// length > post_max_size in php.ini
|
||||||
|
|
||||||
|
if (empty($_FILES)
|
||||||
|
&& empty($_POST)
|
||||||
|
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||||
|
) {
|
||||||
|
$msg = _('The server was unable to handle that much POST ' .
|
||||||
|
'data (%s bytes) due to its current configuration.');
|
||||||
|
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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('oauthappssettings'), 303);
|
||||||
|
} elseif ($this->arg('save')) {
|
||||||
|
$this->trySave();
|
||||||
|
} else {
|
||||||
|
$this->clientError(_('Unexpected form submission.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showForm($msg=null)
|
||||||
|
{
|
||||||
|
$this->msg = $msg;
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$form = new ApplicationEditForm($this);
|
||||||
|
$form->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPageNotice()
|
||||||
|
{
|
||||||
|
if ($this->msg) {
|
||||||
|
$this->element('p', 'error', $this->msg);
|
||||||
|
} else {
|
||||||
|
$this->element('p', 'instructions',
|
||||||
|
_('Use this form to register a new 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('default_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 (mb_strlen($callback_url) > 255) {
|
||||||
|
$this->showForm(_('Callback is too long.'));
|
||||||
|
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));
|
||||||
|
|
||||||
|
$app = new Oauth_application();
|
||||||
|
|
||||||
|
$app->query('BEGIN');
|
||||||
|
|
||||||
|
$app->name = $name;
|
||||||
|
$app->owner = $cur->id;
|
||||||
|
$app->description = $description;
|
||||||
|
$app->source_url = $source_url;
|
||||||
|
$app->organization = $organization;
|
||||||
|
$app->homepage = $homepage;
|
||||||
|
$app->callback_url = $callback_url;
|
||||||
|
$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
|
||||||
|
|
||||||
|
$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;
|
||||||
|
|
||||||
|
$this->app_id = $app->insert();
|
||||||
|
|
||||||
|
if (!$this->app_id) {
|
||||||
|
common_log_db_error($app, 'INSERT', __FILE__);
|
||||||
|
$this->serverError(_('Could not create application.'));
|
||||||
|
$app->query('ROLLBACK');
|
||||||
|
}
|
||||||
|
|
||||||
|
$app->uploadLogo();
|
||||||
|
|
||||||
|
$app->query('COMMIT');
|
||||||
|
|
||||||
|
common_redirect(common_local_url('oauthappssettings'), 303);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
166
actions/oauthappssettings.php
Normal file
166
actions/oauthappssettings.php
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* List the OAuth applications that a user has registered with this instance
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category Settings
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/settingsaction.php';
|
||||||
|
require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a user's registered OAuth applications
|
||||||
|
*
|
||||||
|
* @category Settings
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* @see SettingsAction
|
||||||
|
*/
|
||||||
|
|
||||||
|
class OauthappssettingsAction 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
|
||||||
|
*
|
||||||
|
* @return string Title of the page
|
||||||
|
*/
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('OAuth applications');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructions for use
|
||||||
|
*
|
||||||
|
* @return instructions for use
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getInstructions()
|
||||||
|
{
|
||||||
|
return _('Applications you have registered');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content area of the page
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$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->elementStart('p', array('id' => 'application_register'));
|
||||||
|
$this->element('a',
|
||||||
|
array('href' => common_local_url('newapplication'),
|
||||||
|
'class' => 'more'
|
||||||
|
),
|
||||||
|
'Register a new application');
|
||||||
|
$this->elementEnd('p');
|
||||||
|
|
||||||
|
$this->pagination(
|
||||||
|
$this->page > 1,
|
||||||
|
$cnt > APPS_PER_PAGE,
|
||||||
|
$this->page,
|
||||||
|
'oauthappssettings'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle posts to this form
|
||||||
|
*
|
||||||
|
* Based on the button that was pressed, muxes out to other functions
|
||||||
|
* to do the actual task requested.
|
||||||
|
*
|
||||||
|
* All sub-functions reload the form with a message -- success or failure.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handlePost()
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
212
actions/oauthconnectionssettings.php
Normal file
212
actions/oauthconnectionssettings.php
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* List a user's OAuth connected applications
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category Settings
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/connectsettingsaction.php';
|
||||||
|
require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show connected OAuth applications
|
||||||
|
*
|
||||||
|
* @category Settings
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* @see SettingsAction
|
||||||
|
*/
|
||||||
|
|
||||||
|
class OauthconnectionssettingsAction extends ConnectSettingsAction
|
||||||
|
{
|
||||||
|
|
||||||
|
var $page = null;
|
||||||
|
var $id = null;
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
$this->id = (int)$this->arg('id');
|
||||||
|
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the page
|
||||||
|
*
|
||||||
|
* @return string Title of the page
|
||||||
|
*/
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('Connected Applications');
|
||||||
|
}
|
||||||
|
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructions for use
|
||||||
|
*
|
||||||
|
* @return instructions for use
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getInstructions()
|
||||||
|
{
|
||||||
|
return _('You have allowed the following applications to access you account.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content area of the page
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$user = common_current_user();
|
||||||
|
$profile = $user->getProfile();
|
||||||
|
|
||||||
|
$offset = ($this->page - 1) * APPS_PER_PAGE;
|
||||||
|
$limit = APPS_PER_PAGE + 1;
|
||||||
|
|
||||||
|
$application = $profile->getApplications($offset, $limit);
|
||||||
|
|
||||||
|
$cnt == 0;
|
||||||
|
|
||||||
|
if (!empty($application)) {
|
||||||
|
$al = new ApplicationList($application, $user, $this, true);
|
||||||
|
$cnt = $al->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cnt == 0) {
|
||||||
|
$this->showEmptyListMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->pagination($this->page > 1, $cnt > APPS_PER_PAGE,
|
||||||
|
$this->page, 'connectionssettings',
|
||||||
|
array('nickname' => $this->user->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle posts to this form
|
||||||
|
*
|
||||||
|
* Based on the button that was pressed, muxes out to other functions
|
||||||
|
* to do the actual task requested.
|
||||||
|
*
|
||||||
|
* All sub-functions reload the form with a message -- success or failure.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handlePost()
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->arg('revoke')) {
|
||||||
|
$this->revokeAccess($this->id);
|
||||||
|
|
||||||
|
// XXX: Show some indicator to the user of what's been done.
|
||||||
|
|
||||||
|
$this->showPage();
|
||||||
|
} else {
|
||||||
|
$this->clientError(_('Unexpected form submission.'), 401);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function revokeAccess($appId)
|
||||||
|
{
|
||||||
|
$cur = common_current_user();
|
||||||
|
|
||||||
|
$app = Oauth_application::staticGet('id', $appId);
|
||||||
|
|
||||||
|
if (empty($app)) {
|
||||||
|
$this->clientError(_('No such application.'), 404);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$appUser = Oauth_application_user::getByKeys($cur, $app);
|
||||||
|
|
||||||
|
if (empty($appUser)) {
|
||||||
|
$this->clientError(_('You are not a user of that application.'), 401);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$orig = clone($appUser);
|
||||||
|
$appUser->access_type = 0; // No access
|
||||||
|
$result = $appUser->update();
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
common_log_db_error($orig, 'UPDATE', __FILE__);
|
||||||
|
$this->clientError(_('Unable to revoke access for app: ' . $app->id));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg = 'User %s (id: %d) revoked access to app %s (id: %d)';
|
||||||
|
common_log(LOG_INFO, sprintf($msg, $cur->nickname,
|
||||||
|
$cur->id, $app->name, $app->id));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function showEmptyListMessage()
|
||||||
|
{
|
||||||
|
$message = sprintf(_('You have not authorized any applications to use your account.'));
|
||||||
|
|
||||||
|
$this->elementStart('div', 'guide');
|
||||||
|
$this->raw(common_markup_to_html($message));
|
||||||
|
$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('oauthappssettings')),
|
||||||
|
'here.');
|
||||||
|
$this->elementEnd('p');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
328
actions/showapplication.php
Normal file
328
actions/showapplication.php
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Show an OAuth application
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category Application
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @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 <zach@status.net>
|
||||||
|
* @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 false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
$consumer = $this->application->getConsumer();
|
||||||
|
|
||||||
|
$this->elementStart('div', 'entity_profile vcard');
|
||||||
|
$this->element('h2', null, _('Application profile'));
|
||||||
|
$this->elementStart('dl', 'entity_depiction');
|
||||||
|
$this->element('dt', null, _('Icon'));
|
||||||
|
$this->elementStart('dd');
|
||||||
|
if (!empty($this->application->icon)) {
|
||||||
|
$this->element('img', array('src' => $this->application->icon,
|
||||||
|
'class' => 'photo logo'));
|
||||||
|
}
|
||||||
|
$this->elementEnd('dd');
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_fn');
|
||||||
|
$this->element('dt', null, _('Name'));
|
||||||
|
$this->elementStart('dd');
|
||||||
|
$this->element('a', array('href' => $this->application->source_url,
|
||||||
|
'class' => 'url fn'),
|
||||||
|
$this->application->name);
|
||||||
|
$this->elementEnd('dd');
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_org');
|
||||||
|
$this->element('dt', null, _('Organization'));
|
||||||
|
$this->elementStart('dd');
|
||||||
|
$this->element('a', array('href' => $this->application->homepage,
|
||||||
|
'class' => 'url'),
|
||||||
|
$this->application->organization);
|
||||||
|
$this->elementEnd('dd');
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_note');
|
||||||
|
$this->element('dt', null, _('Description'));
|
||||||
|
$this->element('dd', 'note', $this->application->description);
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_statistics');
|
||||||
|
$this->element('dt', null, _('Statistics'));
|
||||||
|
$this->elementStart('dd');
|
||||||
|
$defaultAccess = ($this->application->access_type & Oauth_application::$writeAccess)
|
||||||
|
? 'read-write' : 'read-only';
|
||||||
|
$profile = Profile::staticGet($this->application->owner);
|
||||||
|
|
||||||
|
$appUsers = new Oauth_application_user();
|
||||||
|
$appUsers->application_id = $this->application->id;
|
||||||
|
$userCnt = $appUsers->count();
|
||||||
|
|
||||||
|
$this->raw(sprintf(
|
||||||
|
_('created by %1$s - %2$s access by default - %3$d users'),
|
||||||
|
$profile->getBestName(),
|
||||||
|
$defaultAccess,
|
||||||
|
$userCnt
|
||||||
|
));
|
||||||
|
$this->elementEnd('dd');
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
$this->elementEnd('div');
|
||||||
|
|
||||||
|
$this->elementStart('div', 'entity_actions');
|
||||||
|
$this->element('h2', null, _('Application actions'));
|
||||||
|
$this->elementStart('ul');
|
||||||
|
$this->elementStart('li', 'entity_edit');
|
||||||
|
$this->element('a',
|
||||||
|
array('href' => common_local_url('editapplication',
|
||||||
|
array('id' => $this->application->id))),
|
||||||
|
'Edit');
|
||||||
|
$this->elementEnd('li');
|
||||||
|
|
||||||
|
$this->elementStart('li', 'entity_reset_keysecret');
|
||||||
|
$this->elementStart('form', array(
|
||||||
|
'id' => 'forma_reset_key',
|
||||||
|
'class' => 'form_reset_key',
|
||||||
|
'method' => 'POST',
|
||||||
|
'action' => common_local_url('showapplication',
|
||||||
|
array('id' => $this->application->id))));
|
||||||
|
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
$this->hidden('token', common_session_token());
|
||||||
|
$this->submit('reset', _('Reset key & secret'));
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
$this->elementEnd('form');
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
$this->elementEnd('div');
|
||||||
|
|
||||||
|
$this->elementStart('div', 'entity_data');
|
||||||
|
$this->element('h2', null, _('Application info'));
|
||||||
|
$this->elementStart('dl', 'entity_consumer_key');
|
||||||
|
$this->element('dt', null, _('Consumer key'));
|
||||||
|
$this->element('dd', null, $consumer->consumer_key);
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_consumer_secret');
|
||||||
|
$this->element('dt', null, _('Consumer secret'));
|
||||||
|
$this->element('dd', null, $consumer->consumer_secret);
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_request_token_url');
|
||||||
|
$this->element('dt', null, _('Request token URL'));
|
||||||
|
$this->element('dd', null, common_local_url('apioauthrequesttoken'));
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_access_token_url');
|
||||||
|
$this->element('dt', null, _('Access token URL'));
|
||||||
|
$this->element('dd', null, common_local_url('apioauthaccesstoken'));
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->elementStart('dl', 'entity_authorize_url');
|
||||||
|
$this->element('dt', null, _('Authorize URL'));
|
||||||
|
$this->element('dd', null, common_local_url('apioauthauthorize'));
|
||||||
|
$this->elementEnd('dl');
|
||||||
|
|
||||||
|
$this->element('p', 'note',
|
||||||
|
_('Note: We support hmac-sha1 signatures. We do not support the plaintext signature method.'));
|
||||||
|
$this->elementEnd('div');
|
||||||
|
|
||||||
|
$this->elementStart('p', array('id' => 'application_action'));
|
||||||
|
$this->element('a',
|
||||||
|
array('href' => common_local_url('oauthappssettings'),
|
||||||
|
'class' => 'more'),
|
||||||
|
'View your applications');
|
||||||
|
$this->elementEnd('p');
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -4,16 +4,17 @@
|
|||||||
*/
|
*/
|
||||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
class Consumer extends Memcached_DataObject
|
class Consumer extends Memcached_DataObject
|
||||||
{
|
{
|
||||||
###START_AUTOCODE
|
###START_AUTOCODE
|
||||||
/* the code below is auto generated do not remove the above tag */
|
/* the code below is auto generated do not remove the above tag */
|
||||||
|
|
||||||
public $__table = 'consumer'; // table name
|
public $__table = 'consumer'; // table name
|
||||||
public $consumer_key; // varchar(255) primary_key not_null
|
public $consumer_key; // varchar(255) primary_key not_null
|
||||||
|
public $consumer_secret; // varchar(255) not_null
|
||||||
public $seed; // char(32) not_null
|
public $seed; // char(32) not_null
|
||||||
public $created; // datetime() not_null
|
public $created; // datetime not_null
|
||||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||||
|
|
||||||
/* Static get */
|
/* Static get */
|
||||||
function staticGet($k,$v=null)
|
function staticGet($k,$v=null)
|
||||||
@ -21,4 +22,18 @@ class Consumer extends Memcached_DataObject
|
|||||||
|
|
||||||
/* the code above is auto generated do not remove the tag below */
|
/* the code above is auto generated do not remove the tag below */
|
||||||
###END_AUTOCODE
|
###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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
140
classes/Oauth_application.php
Normal file
140
classes/Oauth_application.php
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Table Definition for oauth_application
|
||||||
|
*/
|
||||||
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
|
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 $icon; // varchar(255) not_null
|
||||||
|
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 $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',$k,$v);
|
||||||
|
}
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOriginal($filename)
|
||||||
|
{
|
||||||
|
$imagefile = new ImageFile($this->id, Avatar::path($filename));
|
||||||
|
|
||||||
|
// XXX: Do we want to have a bunch of different size icons? homepage, stream, mini?
|
||||||
|
// or just one and control size via CSS? --Zach
|
||||||
|
|
||||||
|
$orig = clone($this);
|
||||||
|
$this->icon = Avatar::url($filename);
|
||||||
|
common_debug(common_log_objstring($this));
|
||||||
|
return $this->update($orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getByConsumerKey($key)
|
||||||
|
{
|
||||||
|
if (empty($key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$app = new Oauth_application();
|
||||||
|
$app->consumer_key = $key;
|
||||||
|
$app->limit(1);
|
||||||
|
$result = $app->find(true);
|
||||||
|
|
||||||
|
return empty($result) ? null : $app;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an image upload
|
||||||
|
*
|
||||||
|
* Does all the magic for handling an image upload, and crops the
|
||||||
|
* image by default.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function uploadLogo()
|
||||||
|
{
|
||||||
|
if ($_FILES['app_icon']['error'] ==
|
||||||
|
UPLOAD_ERR_OK) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
$imagefile = ImageFile::fromUpload('app_icon');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_debug("damn that sucks");
|
||||||
|
$this->showForm($e->getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = Avatar::filename($this->id,
|
||||||
|
image_type_to_extension($imagefile->type),
|
||||||
|
null,
|
||||||
|
'oauth-app-icon-'.common_timestamp());
|
||||||
|
|
||||||
|
$filepath = Avatar::path($filename);
|
||||||
|
|
||||||
|
move_uploaded_file($imagefile->filepath, $filepath);
|
||||||
|
|
||||||
|
$this->setOriginal($filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
44
classes/Oauth_application_user.php
Normal file
44
classes/Oauth_application_user.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Table Definition for oauth_application_user
|
||||||
|
*/
|
||||||
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
|
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 $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 $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);
|
||||||
|
}
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -352,6 +352,31 @@ class Profile extends Memcached_DataObject
|
|||||||
return $profile;
|
return $profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getApplications($offset = 0, $limit = null)
|
||||||
|
{
|
||||||
|
$qry =
|
||||||
|
'SELECT a.* ' .
|
||||||
|
'FROM oauth_application_user u, oauth_application a ' .
|
||||||
|
'WHERE u.profile_id = %d ' .
|
||||||
|
'AND a.id = u.application_id ' .
|
||||||
|
'AND u.access_type > 0 ' .
|
||||||
|
'ORDER BY u.created DESC ';
|
||||||
|
|
||||||
|
if ($offset > 0) {
|
||||||
|
if (common_config('db','type') == 'pgsql') {
|
||||||
|
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||||
|
} else {
|
||||||
|
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$application = new Oauth_application();
|
||||||
|
|
||||||
|
$cnt = $application->query(sprintf($qry, $this->id));
|
||||||
|
|
||||||
|
return $application;
|
||||||
|
}
|
||||||
|
|
||||||
function subscriptionCount()
|
function subscriptionCount()
|
||||||
{
|
{
|
||||||
$c = common_memcache();
|
$c = common_memcache();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
class Token extends Memcached_DataObject
|
class Token extends Memcached_DataObject
|
||||||
{
|
{
|
||||||
###START_AUTOCODE
|
###START_AUTOCODE
|
||||||
/* the code below is auto generated do not remove the above tag */
|
/* 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 $tok; // char(32) primary_key not_null
|
||||||
public $secret; // char(32) not_null
|
public $secret; // char(32) not_null
|
||||||
public $type; // tinyint(1) 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 $created; // datetime() not_null
|
||||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ code = K
|
|||||||
|
|
||||||
[consumer]
|
[consumer]
|
||||||
consumer_key = 130
|
consumer_key = 130
|
||||||
|
consumer_secret = 130
|
||||||
seed = 130
|
seed = 130
|
||||||
created = 142
|
created = 142
|
||||||
modified = 384
|
modified = 384
|
||||||
@ -348,6 +349,37 @@ created = 142
|
|||||||
tag = K
|
tag = K
|
||||||
notice_id = K
|
notice_id = K
|
||||||
|
|
||||||
|
[oauth_application]
|
||||||
|
id = 129
|
||||||
|
owner = 129
|
||||||
|
consumer_key = 130
|
||||||
|
name = 130
|
||||||
|
description = 2
|
||||||
|
icon = 130
|
||||||
|
source_url = 2
|
||||||
|
organization = 2
|
||||||
|
homepage = 2
|
||||||
|
callback_url = 130
|
||||||
|
type = 17
|
||||||
|
access_type = 17
|
||||||
|
created = 142
|
||||||
|
modified = 384
|
||||||
|
|
||||||
|
[oauth_application__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
|
[oauth_application_user]
|
||||||
|
profile_id = 129
|
||||||
|
application_id = 129
|
||||||
|
access_type = 17
|
||||||
|
token = 2
|
||||||
|
created = 142
|
||||||
|
modified = 384
|
||||||
|
|
||||||
|
[oauth_application_user__keys]
|
||||||
|
profile_id = K
|
||||||
|
application_id = K
|
||||||
|
|
||||||
[profile]
|
[profile]
|
||||||
id = 129
|
id = 129
|
||||||
nickname = 130
|
nickname = 130
|
||||||
@ -484,6 +516,8 @@ tok = 130
|
|||||||
secret = 130
|
secret = 130
|
||||||
type = 145
|
type = 145
|
||||||
state = 17
|
state = 17
|
||||||
|
verifier = 2
|
||||||
|
verified_callback = 2
|
||||||
created = 142
|
created = 142
|
||||||
modified = 384
|
modified = 384
|
||||||
|
|
||||||
|
@ -176,6 +176,7 @@ create table fave (
|
|||||||
|
|
||||||
create table consumer (
|
create table consumer (
|
||||||
consumer_key varchar(255) primary key comment 'unique identifier, root URL',
|
consumer_key varchar(255) primary key comment 'unique identifier, root URL',
|
||||||
|
consumer_secret varchar(255) not null comment 'secret value',
|
||||||
seed char(32) not null comment 'seed for new tokens by this consumer',
|
seed char(32) not null comment 'seed for new tokens by this consumer',
|
||||||
|
|
||||||
created datetime not null comment 'date this record was created',
|
created datetime not null comment 'date this record was created',
|
||||||
@ -188,6 +189,8 @@ create table token (
|
|||||||
secret char(32) not null comment 'secret value',
|
secret char(32) not null comment 'secret value',
|
||||||
type tinyint not null default 0 comment 'request or access',
|
type tinyint not null default 0 comment 'request or access',
|
||||||
state tinyint default 0 comment 'for requests, 0 = initial, 1 = authorized, 2 = used',
|
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',
|
created datetime not null comment 'date this record was created',
|
||||||
modified timestamp comment 'date this record was modified',
|
modified timestamp comment 'date this record was modified',
|
||||||
@ -207,6 +210,33 @@ create table nonce (
|
|||||||
constraint primary key (consumer_key, ts, nonce)
|
constraint primary key (consumer_key, ts, nonce)
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
/* These are used by JanRain OpenID library */
|
/* These are used by JanRain OpenID library */
|
||||||
|
|
||||||
create table oid_associations (
|
create table oid_associations (
|
||||||
|
@ -53,6 +53,9 @@ if (!defined('STATUSNET')) {
|
|||||||
|
|
||||||
class ApiAction extends Action
|
class ApiAction extends Action
|
||||||
{
|
{
|
||||||
|
const READ_ONLY = 1;
|
||||||
|
const READ_WRITE = 2;
|
||||||
|
|
||||||
var $format = null;
|
var $format = null;
|
||||||
var $user = null;
|
var $user = null;
|
||||||
var $auth_user = null;
|
var $auth_user = null;
|
||||||
@ -62,6 +65,8 @@ class ApiAction extends Action
|
|||||||
var $since_id = null;
|
var $since_id = null;
|
||||||
var $since = null;
|
var $since = null;
|
||||||
|
|
||||||
|
var $access = self::READ_ONLY; // read (default) or read-write
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialization.
|
* Initialization.
|
||||||
*
|
*
|
||||||
|
115
lib/apiauth.php
115
lib/apiauth.php
@ -28,7 +28,7 @@
|
|||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @author mEDI <medi@milaro.net>
|
* @author mEDI <medi@milaro.net>
|
||||||
* @author Sarven Capadisli <csarven@status.net>
|
* @author Sarven Capadisli <csarven@status.net>
|
||||||
* @author Zach Copley <zach@status.net>
|
* @author Zach Copley <zach@status.net>
|
||||||
* @copyright 2009 StatusNet, Inc.
|
* @copyright 2009 StatusNet, Inc.
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
@ -39,6 +39,7 @@ if (!defined('STATUSNET')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
require_once INSTALLDIR . '/lib/api.php';
|
require_once INSTALLDIR . '/lib/api.php';
|
||||||
|
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions extending this class will require auth
|
* Actions extending this class will require auth
|
||||||
@ -52,6 +53,9 @@ require_once INSTALLDIR . '/lib/api.php';
|
|||||||
|
|
||||||
class ApiAuthAction extends ApiAction
|
class ApiAuthAction extends ApiAction
|
||||||
{
|
{
|
||||||
|
var $access_token;
|
||||||
|
var $oauth_access_type;
|
||||||
|
var $oauth_source;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take arguments for running, and output basic auth header if needed
|
* Take arguments for running, and output basic auth header if needed
|
||||||
@ -67,12 +71,118 @@ class ApiAuthAction extends ApiAction
|
|||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
if ($this->requiresAuth()) {
|
if ($this->requiresAuth()) {
|
||||||
$this->checkBasicAuthUser();
|
|
||||||
|
$this->consumer_key = $this->arg('oauth_consumer_key');
|
||||||
|
$this->access_token = $this->arg('oauth_token');
|
||||||
|
|
||||||
|
if (!empty($this->access_token)) {
|
||||||
|
$this->checkOAuthRequest();
|
||||||
|
} else {
|
||||||
|
$this->checkBasicAuthUser();
|
||||||
|
// By default, all basic auth users have read and write access
|
||||||
|
|
||||||
|
$this->access = self::READ_WRITE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkOAuthRequest()
|
||||||
|
{
|
||||||
|
common_debug("We have an OAuth request.");
|
||||||
|
|
||||||
|
$datastore = new ApiStatusNetOAuthDataStore();
|
||||||
|
$server = new OAuthServer($datastore);
|
||||||
|
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||||
|
|
||||||
|
$server->add_signature_method($hmac_method);
|
||||||
|
|
||||||
|
ApiOauthAction::cleanRequest();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$req = OAuthRequest::from_request();
|
||||||
|
$server->verify_request($req);
|
||||||
|
|
||||||
|
$app = Oauth_application::getByConsumerKey($this->consumer_key);
|
||||||
|
|
||||||
|
if (empty($app)) {
|
||||||
|
|
||||||
|
// this should really not happen
|
||||||
|
common_log(LOG_WARN,
|
||||||
|
"Couldn't find the OAuth app for consumer key: $this->consumer_key");
|
||||||
|
|
||||||
|
throw new OAuthException('No application for that consumer key.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the source attr
|
||||||
|
|
||||||
|
$this->oauth_source = $app->name;
|
||||||
|
|
||||||
|
$appUser = Oauth_application_user::staticGet('token',
|
||||||
|
$this->access_token);
|
||||||
|
|
||||||
|
// XXX: check that app->id and appUser->application_id and consumer all
|
||||||
|
// match?
|
||||||
|
|
||||||
|
if (!empty($appUser)) {
|
||||||
|
|
||||||
|
// read or read-write
|
||||||
|
$this->oauth_access_type = $appUser->access_type;
|
||||||
|
|
||||||
|
// If access_type == 0 we have either a request token
|
||||||
|
// or a bad / revoked access token
|
||||||
|
|
||||||
|
if ($this->oauth_access_type != 0) {
|
||||||
|
|
||||||
|
// Set the read or read-write access for the api call
|
||||||
|
$this->access = ($appUser->access_type & Oauth_application::$writeAccess)
|
||||||
|
? self::READ_WRITE : self::READ_ONLY;
|
||||||
|
|
||||||
|
if (Event::handle('StartSetApiUser', array(&$user))) {
|
||||||
|
$this->auth_user = User::staticGet('id', $appUser->profile_id);
|
||||||
|
Event::handle('EndSetApiUser', array($user));
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg = "API OAuth authentication for user '%s' (id: %d) on behalf of " .
|
||||||
|
"application '%s' (id: %d).";
|
||||||
|
|
||||||
|
common_log(LOG_INFO, sprintf($msg,
|
||||||
|
$this->auth_user->nickname,
|
||||||
|
$this->auth_user->id,
|
||||||
|
$app->name,
|
||||||
|
$app->id));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new OAuthException('Bad access token.');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// also should not happen
|
||||||
|
throw new OAuthException('No user for that token.');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (OAuthException $e) {
|
||||||
|
common_log(LOG_WARN, 'API OAuthException - ' . $e->getMessage());
|
||||||
|
common_debug(var_export($req, true));
|
||||||
|
$this->showOAuthError($e->getMessage());
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showOAuthError($msg)
|
||||||
|
{
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Content-Type: text/html; charset=utf-8');
|
||||||
|
print $msg . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this API resource require authentication?
|
* Does this API resource require authentication?
|
||||||
*
|
*
|
||||||
@ -128,6 +238,7 @@ class ApiAuthAction extends ApiAction
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
122
lib/apioauth.php
Normal file
122
lib/apioauth.php
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Base action for OAuth API endpoints
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @copyright 2010 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')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/apioauthstore.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base action for API OAuth enpoints. Clean up the
|
||||||
|
* the request, and possibly some other common things
|
||||||
|
* here.
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ApiOauthAction extends Action
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Is this a read-only action?
|
||||||
|
*
|
||||||
|
* @return boolean false
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle input, produce output
|
||||||
|
*
|
||||||
|
* Switches on request method; either shows the form or handles its input.
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST data
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
self::cleanRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
static function cleanRequest()
|
||||||
|
{
|
||||||
|
// kill evil effects of magical slashing
|
||||||
|
|
||||||
|
if (get_magic_quotes_gpc() == 1) {
|
||||||
|
$_POST = array_map('stripslashes', $_POST);
|
||||||
|
$_GET = array_map('stripslashes', $_GET);
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip out the p param added in index.php
|
||||||
|
|
||||||
|
// XXX: should we strip anything else? Or alternatively
|
||||||
|
// only allow a known list of params?
|
||||||
|
|
||||||
|
unset($_GET['p']);
|
||||||
|
unset($_POST['p']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCallback($url, $params)
|
||||||
|
{
|
||||||
|
foreach ($params as $k => $v) {
|
||||||
|
$url = $this->appendQueryVar($url,
|
||||||
|
OAuthUtil::urlencode_rfc3986($k),
|
||||||
|
OAuthUtil::urlencode_rfc3986($v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendQueryVar($url, $k, $v) {
|
||||||
|
$url = preg_replace('/(.*)(\?|&)' . $k . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
|
||||||
|
$url = substr($url, 0, -1);
|
||||||
|
if (strpos($url, '?') === false) {
|
||||||
|
return ($url . '?' . $k . '=' . $v);
|
||||||
|
} else {
|
||||||
|
return ($url . '&' . $k . '=' . $v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
163
lib/apioauthstore.php
Normal file
163
lib/apioauthstore.php
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, 2009, StatusNet, 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('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/oauthstore.php';
|
||||||
|
|
||||||
|
class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
|
||||||
|
{
|
||||||
|
|
||||||
|
function lookup_consumer($consumer_key)
|
||||||
|
{
|
||||||
|
$con = Consumer::staticGet('consumer_key', $consumer_key);
|
||||||
|
|
||||||
|
if (!$con) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OAuthConsumer($con->consumer_key,
|
||||||
|
$con->consumer_secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAppByRequestToken($token_key)
|
||||||
|
{
|
||||||
|
// Look up the full req tokenx
|
||||||
|
|
||||||
|
$req_token = $this->lookup_token(null,
|
||||||
|
'request',
|
||||||
|
$token_key);
|
||||||
|
|
||||||
|
if (empty($req_token)) {
|
||||||
|
common_debug("couldn't get request token from oauth datastore");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up the full Token
|
||||||
|
|
||||||
|
$token = new Token();
|
||||||
|
$token->tok = $req_token->key;
|
||||||
|
$result = $token->find(true);
|
||||||
|
|
||||||
|
if (empty($result)) {
|
||||||
|
common_debug('Couldn\'t find req token in the token table.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up the app
|
||||||
|
|
||||||
|
$app = new Oauth_application();
|
||||||
|
$app->consumer_key = $token->consumer_key;
|
||||||
|
$result = $app->find(true);
|
||||||
|
|
||||||
|
if (!empty($result)) {
|
||||||
|
return $app;
|
||||||
|
} else {
|
||||||
|
common_debug("Couldn't find the app!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function new_access_token($token, $consumer)
|
||||||
|
{
|
||||||
|
common_debug('new_access_token("'.$token->key.'","'.$consumer->key.'")', __FILE__);
|
||||||
|
|
||||||
|
$rt = new Token();
|
||||||
|
$rt->consumer_key = $consumer->key;
|
||||||
|
$rt->tok = $token->key;
|
||||||
|
$rt->type = 0; // request
|
||||||
|
|
||||||
|
$app = Oauth_application::getByConsumerKey($consumer->key);
|
||||||
|
|
||||||
|
if (empty($app)) {
|
||||||
|
common_debug("empty app!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rt->find(true) && $rt->state == 1) { // authorized
|
||||||
|
common_debug('request token found.', __FILE__);
|
||||||
|
|
||||||
|
// find the associated user of the app
|
||||||
|
|
||||||
|
$appUser = new Oauth_application_user();
|
||||||
|
$appUser->application_id = $app->id;
|
||||||
|
$appUser->token = $rt->tok;
|
||||||
|
$result = $appUser->find(true);
|
||||||
|
|
||||||
|
if (!empty($result)) {
|
||||||
|
common_debug("Oath app user found.");
|
||||||
|
} else {
|
||||||
|
common_debug("Oauth app user not found. app id $app->id token $rt->tok");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// go ahead and make the access token
|
||||||
|
|
||||||
|
$at = new Token();
|
||||||
|
$at->consumer_key = $consumer->key;
|
||||||
|
$at->tok = common_good_rand(16);
|
||||||
|
$at->secret = common_good_rand(16);
|
||||||
|
$at->type = 1; // access
|
||||||
|
$at->created = DB_DataObject_Cast::dateTime();
|
||||||
|
|
||||||
|
if (!$at->insert()) {
|
||||||
|
$e = $at->_lastError;
|
||||||
|
common_debug('access token "'.$at->tok.'" not inserted: "'.$e->message.'"', __FILE__);
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
common_debug('access token "'.$at->tok.'" inserted', __FILE__);
|
||||||
|
// burn the old one
|
||||||
|
$orig_rt = clone($rt);
|
||||||
|
$rt->state = 2; // used
|
||||||
|
if (!$rt->update($orig_rt)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
common_debug('request token "'.$rt->tok.'" updated', __FILE__);
|
||||||
|
|
||||||
|
// update the token from req to access for the user
|
||||||
|
|
||||||
|
$orig = clone($appUser);
|
||||||
|
$appUser->token = $at->tok;
|
||||||
|
|
||||||
|
// It's at this point that we change the access type
|
||||||
|
// to whatever the application's access is. Request
|
||||||
|
// tokens should always have an access type of 0, and
|
||||||
|
// therefore be unuseable for making requests for
|
||||||
|
// protected resources.
|
||||||
|
|
||||||
|
$appUser->access_type = $app->access_type;
|
||||||
|
|
||||||
|
$result = $appUser->update($orig);
|
||||||
|
|
||||||
|
if (empty($result)) {
|
||||||
|
common_debug('couldn\'t update OAuth app user.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, good
|
||||||
|
|
||||||
|
return new OAuthToken($at->tok, $at->secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
338
lib/applicationeditform.php
Normal file
338
lib/applicationeditform.php
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Form for editing an application
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category Form
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @copyright 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/form.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for editing an application
|
||||||
|
*
|
||||||
|
* @category Form
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ApplicationEditForm extends Form
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* group for user to join
|
||||||
|
*/
|
||||||
|
|
||||||
|
var $application = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param Action $out output channel
|
||||||
|
* @param User_group $group group to join
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __construct($out=null, $application=null)
|
||||||
|
{
|
||||||
|
parent::__construct($out);
|
||||||
|
|
||||||
|
$this->application = $application;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the form
|
||||||
|
*
|
||||||
|
* @return string ID of the form
|
||||||
|
*/
|
||||||
|
|
||||||
|
function id()
|
||||||
|
{
|
||||||
|
if ($this->application) {
|
||||||
|
return 'form_application_edit-' . $this->application->id;
|
||||||
|
} else {
|
||||||
|
return 'form_application_add';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP method used to submit the form
|
||||||
|
*
|
||||||
|
* For image data we need to send multipart/form-data
|
||||||
|
* so we set that here too
|
||||||
|
*
|
||||||
|
* @return string the method to use for submitting
|
||||||
|
*/
|
||||||
|
|
||||||
|
function method()
|
||||||
|
{
|
||||||
|
$this->enctype = 'multipart/form-data';
|
||||||
|
return 'post';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class of the form
|
||||||
|
*
|
||||||
|
* @return string of the form class
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formClass()
|
||||||
|
{
|
||||||
|
return 'form_settings';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action of the form
|
||||||
|
*
|
||||||
|
* @return string URL of the action
|
||||||
|
*/
|
||||||
|
|
||||||
|
function action()
|
||||||
|
{
|
||||||
|
$cur = common_current_user();
|
||||||
|
|
||||||
|
if (!empty($this->application)) {
|
||||||
|
return common_local_url('editapplication',
|
||||||
|
array('id' => $this->application->id));
|
||||||
|
} else {
|
||||||
|
return common_local_url('newapplication');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the form
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formLegend()
|
||||||
|
{
|
||||||
|
$this->out->element('legend', null, _('Edit application'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data elements of the form
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formData()
|
||||||
|
{
|
||||||
|
if ($this->application) {
|
||||||
|
$id = $this->application->id;
|
||||||
|
$icon = $this->application->icon;
|
||||||
|
$name = $this->application->name;
|
||||||
|
$description = $this->application->description;
|
||||||
|
$source_url = $this->application->source_url;
|
||||||
|
$organization = $this->application->organization;
|
||||||
|
$homepage = $this->application->homepage;
|
||||||
|
$callback_url = $this->application->callback_url;
|
||||||
|
$this->type = $this->application->type;
|
||||||
|
$this->access_type = $this->application->access_type;
|
||||||
|
} else {
|
||||||
|
$id = '';
|
||||||
|
$icon = '';
|
||||||
|
$name = '';
|
||||||
|
$description = '';
|
||||||
|
$source_url = '';
|
||||||
|
$organization = '';
|
||||||
|
$homepage = '';
|
||||||
|
$callback_url = '';
|
||||||
|
$this->type = '';
|
||||||
|
$this->access_type = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->hidden('token', common_session_token());
|
||||||
|
|
||||||
|
$this->out->elementStart('ul', 'form_data');
|
||||||
|
|
||||||
|
$this->out->elementStart('li', array('id' => 'application_icon'));
|
||||||
|
|
||||||
|
if (!empty($icon)) {
|
||||||
|
$this->out->element('img', array('src' => $icon));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->element('label', array('for' => 'app_icon'),
|
||||||
|
_('Icon'));
|
||||||
|
$this->out->element('input', array('name' => 'app_icon',
|
||||||
|
'type' => 'file',
|
||||||
|
'id' => 'app_icon'));
|
||||||
|
$this->out->element('p', 'form_guide', _('Icon for this application'));
|
||||||
|
$this->out->element('input', array('name' => 'MAX_FILE_SIZE',
|
||||||
|
'type' => 'hidden',
|
||||||
|
'id' => 'MAX_FILE_SIZE',
|
||||||
|
'value' => ImageFile::maxFileSizeInt()));
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
|
||||||
|
$this->out->elementStart('li');
|
||||||
|
|
||||||
|
$this->out->hidden('application_id', $id);
|
||||||
|
|
||||||
|
$this->out->input('name', _('Name'),
|
||||||
|
($this->out->arg('name')) ? $this->out->arg('name') : $name);
|
||||||
|
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
|
||||||
|
$this->out->elementStart('li');
|
||||||
|
|
||||||
|
$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->elementStart('li');
|
||||||
|
$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 for the homepage of the organization'));
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
|
||||||
|
$this->out->elementStart('li');
|
||||||
|
$this->out->input('callback_url', ('Callback URL'),
|
||||||
|
($this->out->arg('callback_url')) ? $this->out->arg('callback_url') : $callback_url,
|
||||||
|
_('URL to redirect to after authentication'));
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
|
||||||
|
$this->out->elementStart('li', array('id' => 'application_types'));
|
||||||
|
|
||||||
|
$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->application->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', array('id' => 'default_access_types'));
|
||||||
|
|
||||||
|
$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');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action elements
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formActions()
|
||||||
|
{
|
||||||
|
$this->out->submit('cancel', _('Cancel'), 'submit form_action-primary',
|
||||||
|
'cancel', _('Cancel'));
|
||||||
|
$this->out->submit('save', _('Save'), 'submit form_action-secondary',
|
||||||
|
'save', _('Save'));
|
||||||
|
}
|
||||||
|
}
|
168
lib/applicationlist.php
Normal file
168
lib/applicationlist.php
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Widget to show a list of OAuth applications
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: 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/>.
|
||||||
|
*
|
||||||
|
* @category Application
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/widget.php';
|
||||||
|
|
||||||
|
define('APPS_PER_PAGE', 20);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Widget to show a list of OAuth applications
|
||||||
|
*
|
||||||
|
* @category Application
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
function __construct($application, $owner=null, $action=null, $connections = false)
|
||||||
|
{
|
||||||
|
parent::__construct($action);
|
||||||
|
|
||||||
|
$this->application = $application;
|
||||||
|
$this->owner = $owner;
|
||||||
|
$this->action = $action;
|
||||||
|
$this->connections = $connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
$this->out->elementStart('ul', 'applications');
|
||||||
|
|
||||||
|
$cnt = 0;
|
||||||
|
|
||||||
|
while ($this->application->fetch()) {
|
||||||
|
$cnt++;
|
||||||
|
if($cnt > APPS_PER_PAGE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$this->showapplication();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
|
||||||
|
return $cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showApplication()
|
||||||
|
{
|
||||||
|
|
||||||
|
$user = common_current_user();
|
||||||
|
|
||||||
|
$this->out->elementStart('li', array('class' => 'application',
|
||||||
|
'id' => 'oauthclient-' . $this->application->id));
|
||||||
|
|
||||||
|
$this->out->elementStart('span', 'vcard author');
|
||||||
|
if (!$this->connections) {
|
||||||
|
$this->out->elementStart('a',
|
||||||
|
array('href' => common_local_url('showapplication',
|
||||||
|
array('id' => $this->application->id)),
|
||||||
|
'class' => 'url'));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->out->elementStart('a', array('href' => $this->application->source_url,
|
||||||
|
'class' => 'url'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->application->icon)) {
|
||||||
|
$this->out->element('img', array('src' => $this->application->icon,
|
||||||
|
'class' => 'photo avatar'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->element('span', 'fn', $this->application->name);
|
||||||
|
$this->out->elementEnd('a');
|
||||||
|
$this->out->elementEnd('span');
|
||||||
|
|
||||||
|
$this->out->raw(' by ');
|
||||||
|
|
||||||
|
$this->out->element('a', array('href' => $this->application->homepage,
|
||||||
|
'class' => 'url'),
|
||||||
|
$this->application->organization);
|
||||||
|
|
||||||
|
$this->out->element('p', 'note', $this->application->description);
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
|
||||||
|
if ($this->connections) {
|
||||||
|
$appUser = Oauth_application_user::getByKeys($this->owner, $this->application);
|
||||||
|
|
||||||
|
if (empty($appUser)) {
|
||||||
|
common_debug("empty appUser!");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementStart('li');
|
||||||
|
|
||||||
|
$access = ($this->application->access_type & Oauth_application::$writeAccess)
|
||||||
|
? 'read-write' : 'read-only';
|
||||||
|
|
||||||
|
$txt = 'Approved ' . common_date_string($appUser->modified) .
|
||||||
|
" - $access access.";
|
||||||
|
|
||||||
|
$this->out->raw($txt);
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
|
||||||
|
$this->out->elementStart('li', 'entity_revoke');
|
||||||
|
$this->out->elementStart('form', array('id' => 'form_revoke_app',
|
||||||
|
'class' => 'form_revoke_app',
|
||||||
|
'method' => 'POST',
|
||||||
|
'action' =>
|
||||||
|
common_local_url('oauthconnectionssettings')));
|
||||||
|
$this->out->elementStart('fieldset');
|
||||||
|
$this->out->hidden('id', $this->application->id);
|
||||||
|
$this->out->hidden('token', common_session_token());
|
||||||
|
$this->out->submit('revoke', _('Revoke'));
|
||||||
|
$this->out->elementEnd('fieldset');
|
||||||
|
$this->out->elementEnd('form');
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override this in subclasses. */
|
||||||
|
|
||||||
|
function showOwnerControls()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -115,6 +115,11 @@ class ConnectSettingsNav extends Widget
|
|||||||
array(_('SMS'),
|
array(_('SMS'),
|
||||||
_('Updates by SMS'));
|
_('Updates by SMS'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$menu['oauthconnectionssettings'] = array(
|
||||||
|
_('Connections'),
|
||||||
|
_('Authorized connected applications')
|
||||||
|
);
|
||||||
|
|
||||||
foreach ($menu as $menuaction => $menudesc) {
|
foreach ($menu as $menuaction => $menudesc) {
|
||||||
$this->action->menuItem(common_local_url($menuaction),
|
$this->action->menuItem(common_local_url($menuaction),
|
||||||
@ -131,4 +136,3 @@ class ConnectSettingsNav extends Widget
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,6 +211,8 @@ $default =
|
|||||||
'uploads' => true,
|
'uploads' => true,
|
||||||
'filecommand' => '/usr/bin/file',
|
'filecommand' => '/usr/bin/file',
|
||||||
),
|
),
|
||||||
|
'application' =>
|
||||||
|
array('desclimit' => null),
|
||||||
'group' =>
|
'group' =>
|
||||||
array('maxaliases' => 3,
|
array('maxaliases' => 3,
|
||||||
'desclimit' => null),
|
'desclimit' => null),
|
||||||
|
@ -88,7 +88,7 @@ abstract class IoMaster
|
|||||||
$sn = new Status_network();
|
$sn = new Status_network();
|
||||||
$sn->find();
|
$sn->find();
|
||||||
while ($sn->fetch()) {
|
while ($sn->fetch()) {
|
||||||
$hosts[] = $sn->hostname;
|
$hosts[] = $sn->getServerName();
|
||||||
}
|
}
|
||||||
return $hosts;
|
return $hosts;
|
||||||
}
|
}
|
||||||
|
@ -140,8 +140,8 @@ class Router
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
|
|
||||||
foreach (array('profile', 'avatar', 'password', 'im',
|
foreach (array('profile', 'avatar', 'password', 'im', 'oauthconnections',
|
||||||
'email', 'sms', 'userdesign', 'other') as $s) {
|
'oauthapps', 'email', 'sms', 'userdesign', 'other') as $s) {
|
||||||
$m->connect('settings/'.$s, array('action' => $s.'settings'));
|
$m->connect('settings/'.$s, array('action' => $s.'settings'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,6 +641,27 @@ class Router
|
|||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$m->connect('settings/oauthapps/show/:id',
|
||||||
|
array('action' => 'showapplication'),
|
||||||
|
array('id' => '[0-9]+')
|
||||||
|
);
|
||||||
|
$m->connect('settings/oauthapps/new',
|
||||||
|
array('action' => 'newapplication')
|
||||||
|
);
|
||||||
|
$m->connect('settings/oauthapps/edit/:id',
|
||||||
|
array('action' => 'editapplication'),
|
||||||
|
array('id' => '[0-9]+')
|
||||||
|
);
|
||||||
|
|
||||||
|
$m->connect('api/oauth/request_token',
|
||||||
|
array('action' => 'apioauthrequesttoken'));
|
||||||
|
|
||||||
|
$m->connect('api/oauth/access_token',
|
||||||
|
array('action' => 'apioauthaccesstoken'));
|
||||||
|
|
||||||
|
$m->connect('api/oauth/authorize',
|
||||||
|
array('action' => 'apioauthauthorize'));
|
||||||
|
|
||||||
foreach (array('subscriptions', 'subscribers') as $a) {
|
foreach (array('subscriptions', 'subscribers') as $a) {
|
||||||
$m->connect(':nickname/'.$a.'/:tag',
|
$m->connect(':nickname/'.$a.'/:tag',
|
||||||
array('action' => $a),
|
array('action' => $a),
|
||||||
|
22
tests/oauth/README
Normal file
22
tests/oauth/README
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Some very rough test scripts for hitting up the OAuth endpoints.
|
||||||
|
|
||||||
|
Note: this works best if you register an OAuth application, leaving
|
||||||
|
the callback URL blank.
|
||||||
|
|
||||||
|
Put your instance info and consumer key and secret in oauth.ini
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
--------------
|
||||||
|
|
||||||
|
php getrequesttoken.php
|
||||||
|
|
||||||
|
Gets a request token, token secret and a url to authorize it. Once
|
||||||
|
you authorize the request token you can exchange it for an access token...
|
||||||
|
|
||||||
|
php exchangetokens.php --oauth_token=b9a79548a88c1aa9a5bea73103c6d41d --token_secret=4a47d9337fc0202a14ab552e17a3b657
|
||||||
|
|
||||||
|
Once you have your access token, go ahead and try a protected API
|
||||||
|
resource:
|
||||||
|
|
||||||
|
php verifycreds.php --oauth_token=cf2de7665f0dda0a82c2dc39b01be7f9 --token_secret=4524c3b712200138e1a4cff2e9ca83d8
|
||||||
|
|
105
tests/oauth/exchangetokens.php
Executable file
105
tests/oauth/exchangetokens.php
Executable file
@ -0,0 +1,105 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, 2009, StatusNet, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/extlib/OAuth.php';
|
||||||
|
|
||||||
|
$ini = parse_ini_file("oauth.ini");
|
||||||
|
|
||||||
|
$test_consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
|
||||||
|
|
||||||
|
$at_endpoint = $ini['apiroot'] . $ini['access_token_url'];
|
||||||
|
|
||||||
|
$shortoptions = 't:s:';
|
||||||
|
$longoptions = array('oauth_token=', 'token_secret=');
|
||||||
|
|
||||||
|
$helptext = <<<END_OF_ETOKENS_HELP
|
||||||
|
exchangetokens.php [options]
|
||||||
|
Exchange an authorized OAuth request token for an access token
|
||||||
|
|
||||||
|
-t --oauth_token authorized request token
|
||||||
|
-s --token_secret authorized request token secret
|
||||||
|
|
||||||
|
END_OF_ETOKENS_HELP;
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/scripts/commandline.inc';
|
||||||
|
|
||||||
|
$token = null;
|
||||||
|
$token_secret = null;
|
||||||
|
|
||||||
|
if (have_option('t', 'oauth_token')) {
|
||||||
|
$token = get_option_value('oauth_token');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (have_option('s', 'token_secret')) {
|
||||||
|
$token_secret = get_option_value('s', 'token_secret');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($token)) {
|
||||||
|
print "Please specify a request token.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($token_secret)) {
|
||||||
|
print "Please specify a request token secret.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rt = new OAuthToken($token, $token_secret);
|
||||||
|
common_debug("Exchange request token = " . var_export($rt, true));
|
||||||
|
|
||||||
|
$parsed = parse_url($at_endpoint);
|
||||||
|
$params = array();
|
||||||
|
parse_str($parsed['query'], $params);
|
||||||
|
|
||||||
|
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||||
|
|
||||||
|
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, $rt, "GET", $at_endpoint, $params);
|
||||||
|
$req_req->sign_request($hmac_method, $test_consumer, $rt);
|
||||||
|
|
||||||
|
$r = httpRequest($req_req->to_url());
|
||||||
|
|
||||||
|
common_debug("Exchange request token = " . var_export($rt, true));
|
||||||
|
common_debug("Exchange tokens URL: " . $req_req->to_url());
|
||||||
|
|
||||||
|
$body = $r->getBody();
|
||||||
|
|
||||||
|
$token_stuff = array();
|
||||||
|
parse_str($body, $token_stuff);
|
||||||
|
|
||||||
|
print 'Access token : ' . $token_stuff['oauth_token'] . "\n";
|
||||||
|
print 'Access token secret : ' . $token_stuff['oauth_token_secret'] . "\n";
|
||||||
|
|
||||||
|
function httpRequest($url)
|
||||||
|
{
|
||||||
|
$request = HTTPClient::start();
|
||||||
|
|
||||||
|
$request->setConfig(array(
|
||||||
|
'follow_redirects' => true,
|
||||||
|
'connect_timeout' => 120,
|
||||||
|
'timeout' => 120,
|
||||||
|
'ssl_verify_peer' => false,
|
||||||
|
'ssl_verify_host' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
return $request->get($url);
|
||||||
|
}
|
||||||
|
|
71
tests/oauth/getrequesttoken.php
Executable file
71
tests/oauth/getrequesttoken.php
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, 2009, StatusNet, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/scripts/commandline.inc';
|
||||||
|
require_once INSTALLDIR . '/extlib/OAuth.php';
|
||||||
|
|
||||||
|
$ini = parse_ini_file("oauth.ini");
|
||||||
|
|
||||||
|
$test_consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
|
||||||
|
|
||||||
|
$rt_endpoint = $ini['apiroot'] . $ini['request_token_url'];
|
||||||
|
|
||||||
|
$parsed = parse_url($rt_endpoint);
|
||||||
|
$params = array();
|
||||||
|
|
||||||
|
parse_str($parsed['query'], $params);
|
||||||
|
|
||||||
|
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||||
|
|
||||||
|
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, NULL, "GET", $rt_endpoint, $params);
|
||||||
|
$req_req->sign_request($hmac_method, $test_consumer, NULL);
|
||||||
|
|
||||||
|
$r = httpRequest($req_req->to_url());
|
||||||
|
|
||||||
|
$body = $r->getBody();
|
||||||
|
|
||||||
|
$token_stuff = array();
|
||||||
|
parse_str($body, $token_stuff);
|
||||||
|
|
||||||
|
$authurl = $ini['apiroot'] . $ini['authorize_url'] . '?oauth_token=' . $token_stuff['oauth_token'];
|
||||||
|
|
||||||
|
print 'Request token : ' . $token_stuff['oauth_token'] . "\n";
|
||||||
|
print 'Request token secret : ' . $token_stuff['oauth_token_secret'] . "\n";
|
||||||
|
print "Authorize URL : $authurl\n";
|
||||||
|
|
||||||
|
//var_dump($req_req);
|
||||||
|
|
||||||
|
function httpRequest($url)
|
||||||
|
{
|
||||||
|
$request = HTTPClient::start();
|
||||||
|
|
||||||
|
$request->setConfig(array(
|
||||||
|
'follow_redirects' => true,
|
||||||
|
'connect_timeout' => 120,
|
||||||
|
'timeout' => 120,
|
||||||
|
'ssl_verify_peer' => false,
|
||||||
|
'ssl_verify_host' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
return $request->get($url);
|
||||||
|
}
|
||||||
|
|
10
tests/oauth/oauth.ini
Normal file
10
tests/oauth/oauth.ini
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
; Setup OAuth info here
|
||||||
|
apiroot = "http://YOURSTATUSNET/api"
|
||||||
|
|
||||||
|
request_token_url = "/oauth/request_token"
|
||||||
|
authorize_url = "/oauth/authorize"
|
||||||
|
access_token_url = "/oauth/access_token"
|
||||||
|
|
||||||
|
consumer_key = "b748968e9bea81a53f3a3c15aa0c686f"
|
||||||
|
consumer_secret = "5434e18cce05d9e53cdd48029a62fa41"
|
||||||
|
|
101
tests/oauth/verifycreds.php
Executable file
101
tests/oauth/verifycreds.php
Executable file
@ -0,0 +1,101 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, 2009, StatusNet, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/extlib/OAuth.php';
|
||||||
|
|
||||||
|
$shortoptions = 'o:s:';
|
||||||
|
$longoptions = array('oauth_token=', 'token_secret=');
|
||||||
|
|
||||||
|
$helptext = <<<END_OF_VERIFY_HELP
|
||||||
|
verifycreds.php [options]
|
||||||
|
Use an access token to verify credentials thru the api
|
||||||
|
|
||||||
|
-o --oauth_token access token
|
||||||
|
-s --token_secret access token secret
|
||||||
|
|
||||||
|
END_OF_VERIFY_HELP;
|
||||||
|
|
||||||
|
$token = null;
|
||||||
|
$token_secret = null;
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/scripts/commandline.inc';
|
||||||
|
|
||||||
|
if (have_option('o', 'oauth_token')) {
|
||||||
|
$token = get_option_value('oauth_token');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (have_option('s', 'token_secret')) {
|
||||||
|
$token_secret = get_option_value('s', 'token_secret');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($token)) {
|
||||||
|
print "Please specify an access token.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($token_secret)) {
|
||||||
|
print "Please specify an access token secret.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ini = parse_ini_file("oauth.ini");
|
||||||
|
|
||||||
|
$test_consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
|
||||||
|
|
||||||
|
$endpoint = $ini['apiroot'] . '/account/verify_credentials.xml';
|
||||||
|
|
||||||
|
print "$endpoint\n";
|
||||||
|
|
||||||
|
$at = new OAuthToken($token, $token_secret);
|
||||||
|
|
||||||
|
$parsed = parse_url($endpoint);
|
||||||
|
$params = array();
|
||||||
|
parse_str($parsed['query'], $params);
|
||||||
|
|
||||||
|
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||||
|
|
||||||
|
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, $at, "GET", $endpoint, $params);
|
||||||
|
$req_req->sign_request($hmac_method, $test_consumer, $at);
|
||||||
|
|
||||||
|
$r = httpRequest($req_req->to_url());
|
||||||
|
|
||||||
|
$body = $r->getBody();
|
||||||
|
|
||||||
|
print "$body\n";
|
||||||
|
|
||||||
|
//print $req_req->to_url() . "\n\n";
|
||||||
|
|
||||||
|
function httpRequest($url)
|
||||||
|
{
|
||||||
|
$request = HTTPClient::start();
|
||||||
|
|
||||||
|
$request->setConfig(array(
|
||||||
|
'follow_redirects' => true,
|
||||||
|
'connect_timeout' => 120,
|
||||||
|
'timeout' => 120,
|
||||||
|
'ssl_verify_peer' => false,
|
||||||
|
'ssl_verify_host' => false
|
||||||
|
));
|
||||||
|
|
||||||
|
return $request->get($url);
|
||||||
|
}
|
||||||
|
|
@ -177,7 +177,8 @@ font-weight:bold;
|
|||||||
#form_password_recover legend,
|
#form_password_recover legend,
|
||||||
#form_password_change legend,
|
#form_password_change legend,
|
||||||
.form_entity_block legend,
|
.form_entity_block legend,
|
||||||
#form_filter_bytag legend {
|
#form_filter_bytag legend,
|
||||||
|
#apioauthauthorize_allowdeny {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -906,10 +907,15 @@ list-style-type:none;
|
|||||||
}
|
}
|
||||||
.application img,
|
.application img,
|
||||||
#showapplication .entity_profile img,
|
#showapplication .entity_profile img,
|
||||||
#editapplication .form_data #application_icon img {
|
.form_data #application_icon img,
|
||||||
|
#apioauthauthorize .form_data img {
|
||||||
max-width:96px;
|
max-width:96px;
|
||||||
max-height:96px;
|
max-height:96px;
|
||||||
}
|
}
|
||||||
|
#apioauthauthorize .form_data img {
|
||||||
|
margin-right:18px;
|
||||||
|
float:left;
|
||||||
|
}
|
||||||
#showapplication .entity_profile {
|
#showapplication .entity_profile {
|
||||||
width:68%;
|
width:68%;
|
||||||
}
|
}
|
||||||
@ -938,9 +944,9 @@ margin-left:1.795%;
|
|||||||
font-family:monospace;
|
font-family:monospace;
|
||||||
font-size:1.3em;
|
font-size:1.3em;
|
||||||
}
|
}
|
||||||
#editapplication .form_data #application_types label.radio,
|
.form_data #application_types label.radio,
|
||||||
#editapplication .form_data #default_access_types label.radio {
|
.form_data #default_access_types label.radio {
|
||||||
width:15%;
|
width:14.5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTICE */
|
/* NOTICE */
|
||||||
|
Loading…
Reference in New Issue
Block a user