EndShowFeedLink: after showing an individual feed
- $action: action being executed
- $feed: feed to show
+
+StartShowNoticeForm: before showing the notice form (before <form>)
+- $action: action being executed
+
+EndShowNoticeForm: after showing the notice form (after <form>)
+- $action: action being executed
be escaped.
logo: URL of an image file to use as the logo for the site. Overrides
the logo in the theme, if any.
+ssllogo: URL of an image file to use as the logo on SSL pages. If unset,
+ theme logo is used instead.
ssl: Whether to use SSL and https:// URLs for some or all pages.
Possible values are 'always' (use it for all pages), 'never'
(don't use it for any pages), or 'sometimes' (use it for
which means to use the site path + '/theme'.
ssl: Whether to use SSL for theme elements. Default is null, which means
guess based on site SSL settings.
+sslserver: SSL server to use when page is HTTPS-encrypted. If
+ unspecified, site ssl server and so on will be used.
+sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
javascript
----------
which means to use the site path + '/js/'.
ssl: Whether to use SSL for JavaScript files. Default is null, which means
guess based on site SSL settings.
+sslserver: SSL server to use when page is HTTPS-encrypted. If
+ unspecified, site ssl server and so on will be used.
+sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
xmpp
----
filecommand: command to use for determining the type of a file. May be
skipped if fileinfo extension is installed. Defaults to
'/usr/bin/file'.
+sslserver: if specified, this server will be used when creating HTTPS
+ URLs. Otherwise, the site SSL server will be used, with /file/ path.
+sslpath: if this and the sslserver are specified, this path will be used
+ when creating HTTPS URLs. Otherwise, the attachments|path value
+ will be used.
group
-----
subdir of install dir.
path: path to backgrounds. Default is sub-path of install path; note
that you may need to change this if you change site-path too.
-ssl: Whether or not to use HTTPS for background files. Defaults to
- null, meaning to guess from site-wide SSL settings.
+sslserver: SSL server to use when page is HTTPS-encrypted. If
+ unspecified, site ssl server and so on will be used.
+sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
ping
----
/**
* StatusNet, the distributed open-source microblogging tool
*
- * Exchange an authorized OAuth request token for an access token
+ * Action for getting OAuth token credentials (exchange an authorized
+ * request token for an access token)
*
* PHP version 5
*
require_once INSTALLDIR . '/lib/apioauth.php';
/**
- * Exchange an authorized OAuth request token for an access token
+ * Action for getting OAuth token credentials (exchange an authorized
+ * request token for an access token)
*
* @category API
* @package StatusNet
class ApiOauthAccessTokenAction extends ApiOauthAction
{
+ protected $reqToken = null;
+ protected $verifier = null;
/**
* Class handler.
$atok = null;
+ // XXX: Insist that oauth_token and oauth_verifier be populated?
+ // Spec doesn't say they MUST be.
+
try {
+
$req = OAuthRequest::from_request();
+
+ $this->reqToken = $req->get_parameter('oauth_token');
+ $this->verifier = $req->get_parameter('oauth_verifier');
+
$atok = $server->fetch_access_token($req);
} catch (OAuthException $e) {
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
common_debug(var_export($req, true));
- $this->outputError($e->getMessage());
- return;
+ $code = $e->getCode();
+ $this->clientError($e->getMessage(), empty($code) ? 401 : $code, 'text');
}
if (empty($atok)) {
- common_debug('couldn\'t get access token.');
- print "Token exchange failed. Has the request token been authorized?\n";
+
+ // Token exchange failed -- log it
+
+ list($proxy, $ip) = common_client_ip();
+
+ $msg = sprintf(
+ 'API OAuth - Failure exchanging request token for access token, '
+ . 'request token = %s, verifier = %s, IP = %s, proxy = %s',
+ $this->reqToken,
+ $this->verifier,
+ $ip,
+ $proxy
+ );
+
+ common_log(LOG_WARNING, $msg);
+
+ $this->clientError(_("Invalid request token or verifier.", 400, 'text'));
+
} else {
- print $atok;
+ $this->showAccessToken($atok);
}
}
- function outputError($msg)
+ /*
+ * Display OAuth token credentials
+ *
+ * @param OAuthToken token the access token
+ */
+
+ function showAccessToken($token)
{
- header('HTTP/1.1 401 Unauthorized');
- header('Content-Type: text/html; charset=utf-8');
- print $msg . "\n";
+ header('Content-Type: application/x-www-form-urlencoded');
+ print $token;
}
}
-
}
require_once INSTALLDIR . '/lib/apioauth.php';
+require_once INSTALLDIR . '/lib/info.php';
/**
* Authorize an OAuth request token
* @link http://status.net/
*/
-class ApiOauthAuthorizeAction extends ApiOauthAction
+class ApiOauthAuthorizeAction extends Action
{
- var $oauth_token;
+ var $oauthTokenParam;
+ var $reqToken;
var $callback;
var $app;
var $nickname;
{
parent::prepare($args);
- $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);
+ $this->nickname = $this->trimmed('nickname');
+ $this->password = $this->arg('password');
+ $this->oauthTokenParam = $this->arg('oauth_token');
+ $this->callback = $this->arg('oauth_callback');
+ $this->store = new ApiStatusNetOAuthDataStore();
+
+ try {
+ $this->app = $this->store->getAppByRequestToken($this->oauthTokenParam);
+ } catch (Exception $e) {
+ $this->clientError($e->getMessage());
+ }
return true;
}
} else {
- if (empty($this->oauth_token)) {
+ // Make sure a oauth_token parameter was provided
+ if (empty($this->oauthTokenParam)) {
$this->clientError(_('No oauth_token parameter provided.'));
- return;
+ } else {
+
+ // Check to make sure the token exists
+ $this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
+
+ if (empty($this->reqToken)) {
+ $this->serverError(
+ _('Invalid request token.')
+ );
+ } else {
+
+ // Check to make sure we haven't already authorized the token
+ if ($this->reqToken->state != 0) {
+ $this->clientError("Invalid request token.");
+ }
+ }
}
+ // make sure there's an app associated with this token
if (empty($this->app)) {
- $this->clientError(_('Invalid token.'));
- return;
+ $this->clientError(_('Invalid request token.'));
}
$name = $this->app->name;
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
- $this->showForm(_('There was a problem with your session token. '.
- 'Try again, please.'));
+ $this->showForm(
+ _('There was a problem with your session token. Try again, please.'));
return;
}
$user = null;
if (!common_logged_in()) {
+
+ // XXX Force credentials check?
+
+ // XXX OpenID
+
$user = common_check_user($this->nickname, $this->password);
if (empty($user)) {
$this->showForm(_("Invalid nickname / password!"));
if ($this->arg('allow')) {
- // mark the req token as authorized
+ // fetch the token
+ $this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
- $this->store->authorize_token($this->oauth_token);
+ // mark the req token as authorized
+ try {
+ $this->store->authorize_token($this->oauthTokenParam);
+ } catch (Exception $e) {
+ $this->serverError($e->getMessage());
+ }
// Check to see if there was a previous token associated
// with this user/app and kill it. If the user is doing this she
if (!$result) {
common_log_db_error($appUser, 'DELETE', __FILE__);
- throw new ServerException(_('Database error deleting OAuth application user.'));
- return;
+ $this->serverError(_('Database error deleting OAuth application user.'));
}
}
// granted. The OAuth app user record then gets updated
// with the new access token and access type.
- $appUser->token = $this->oauth_token;
+ $appUser->token = $this->oauthTokenParam;
$appUser->created = common_sql_now();
$result = $appUser->insert();
if (!$result) {
common_log_db_error($appUser, 'INSERT', __FILE__);
- throw new ServerException(_('Database error inserting OAuth application user.'));
- return;
+ $this->serverError(_('Database error inserting OAuth application user.'));
}
- // if we have a callback redirect and provide the token
+ // If we have a callback redirect and provide the token
- // A callback specified in the app setup overrides whatever
+ // Note: A callback specified in the app setup overrides whatever
// is passed in with the request.
if (!empty($this->app->callback_url)) {
if (!empty($this->callback)) {
- $target_url = $this->getCallback($this->callback,
- array('oauth_token' => $this->oauth_token));
+ $targetUrl = $this->getCallback(
+ $this->callback,
+ array(
+ 'oauth_token' => $this->oauthTokenParam,
+ 'oauth_verifier' => $this->reqToken->verifier // 1.0a
+ )
+ );
+
+ // Redirect the user to the provided OAuth callback
+ common_redirect($targetUrl, 303);
- common_redirect($target_url, 303);
} else {
- common_debug("callback was empty!");
+ common_log(
+ LOG_INFO,
+ "No oauth_callback parameter provided for application ID "
+ . $this->app->id
+ . " when authorizing request token."
+ );
}
- // 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')) {
-
- $datastore = new ApiStatusNetOAuthDataStore();
- $datastore->revoke_token($this->oauth_token, 0);
+ // Otherwise, inform the user that the rt was authorized
+ $this->showAuthorized();
- $this->elementStart('p');
+ } else if ($this->arg('cancel')) {
- $this->raw(sprintf(_("The request token %s has been denied and revoked."),
- $this->oauth_token));
+ try {
+ $this->store->revoke_token($this->oauthTokenParam, 0);
+ $this->showCanceled();
+ } catch (Exception $e) {
+ $this->ServerError($e->getMessage());
+ }
- $this->elementEnd('p');
} else {
$this->clientError(_('Unexpected form submission.'));
- return;
}
}
_('Allow or deny access'));
$this->hidden('token', common_session_token());
- $this->hidden('oauth_token', $this->oauth_token);
+ $this->hidden('oauth_token', $this->oauthTokenParam);
$this->hidden('oauth_callback', $this->callback);
$this->elementStart('ul', 'form_data');
}
- $this->element('input', array('id' => 'deny_submit',
+ $this->element('input', array('id' => 'cancel_submit',
'class' => 'submit submit form_action-primary',
- 'name' => 'deny',
+ 'name' => 'cancel',
'type' => 'submit',
- 'value' => _('Deny')));
+ 'value' => _('Cancel')));
$this->element('input', array('id' => 'allow_submit',
'class' => 'submit submit form_action-secondary',
function getInstructions()
{
- return _('Allow or deny access to your account information.');
+ return _('Authorize access to your account information.');
}
/**
// NOP
}
+ /*
+ * Show a nice message confirming the authorization
+ * operation was canceled.
+ *
+ * @return nothing
+ */
+
+ function showCanceled()
+ {
+ $info = new InfoAction(
+ _('Authorization canceled.'),
+ sprintf(
+ _('The request token %s has been revoked.'),
+ $this->oauthTokenParm
+ )
+ );
+
+ $info->showPage();
+ }
+
+ /*
+ * Show a nice message that the authorization was successful.
+ * If the operation is out-of-band, show a pin.
+ *
+ * @return nothing
+ */
+
+ function showAuthorized()
+ {
+ $title = sprintf(
+ _("You have successfully authorized %s."),
+ $this->app->name
+ );
+
+ $msg = sprintf(
+ _('Please return to %s and enter the following security code to complete the process.'),
+ $this->app->name
+ );
+
+ if ($this->reqToken->verified_callback == 'oob') {
+ $pin = new ApiOauthPinAction($title, $msg, $this->reqToken->verifier);
+ $pin->showPage();
+ } else {
+
+ // NOTE: This would only happen if an application registered as
+ // a web application but sent in 'oob' for the oauth_callback
+ // parameter. Usually web apps will send in a callback and
+ // not use the pin-based workflow.
+
+ $info = new InfoAction(
+ $title,
+ $msg,
+ $this->oauthTokenParam,
+ $this->reqToken->verifier
+ );
+
+ $info->showPage();
+ }
+ }
+
+ /*
+ * Properly format the callback URL and parameters so it's
+ * suitable for a redirect in the OAuth dance
+ *
+ * @param string $url the URL
+ * @param array $params an array of parameters
+ *
+ * @return string $url a URL to use for redirecting to
+ */
+
+ function getCallback($url, $params)
+ {
+ foreach ($params as $k => $v) {
+ $url = $this->appendQueryVar(
+ $url,
+ OAuthUtil::urlencode_rfc3986($k),
+ OAuthUtil::urlencode_rfc3986($v)
+ );
+ }
+
+ return $url;
+ }
+
+ /*
+ * Append a new query parameter after any existing query
+ * parameters.
+ *
+ * @param string $url the URL
+ * @prarm string $k the parameter name
+ * @param string $v value of the paramter
+ *
+ * @return string $url the new URL with added parameter
+ */
+
+ 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);
+ }
+ }
}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Action for displaying an OAuth verifier pin
+ *
+ * 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 Action
+ * @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') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/lib/info.php';
+
+/**
+ * Class for displaying an OAuth verifier pin
+ *
+ * XXX: I'm pretty sure we don't need to check the logged in state here. -- Zach
+ *
+ * @category Action
+ * @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 ApiOauthPinAction extends InfoAction
+{
+ function __construct($title, $message, $verifier)
+ {
+ $this->verifier = $verifier;
+ $this->title = $title;
+ parent::__construct($title, $message);
+ }
+
+ /**
+ * Display content.
+ *
+ * @return nothing
+ */
+ function showContent()
+ {
+ $this->element('div', array('class' => 'info'), $this->message);
+ $this->element('div', array('id' => 'oauth_pin'), $this->verifier);
+ }
+}
/**
* StatusNet, the distributed open-source microblogging tool
*
- * Get an OAuth request token
+ * Issue temporary OAuth credentials (a request token)
*
* PHP version 5
*
require_once INSTALLDIR . '/lib/apioauth.php';
/**
- * Get an OAuth request token
+ * Issue temporary OAuth credentials (a request token)
*
* @category API
* @package StatusNet
{
parent::prepare($args);
- $this->callback = $this->arg('oauth_callback');
-
- if (!empty($this->callback)) {
- common_debug("callback: $this->callback");
- }
+ // XXX: support "force_login" parameter like Twitter? (Forces the user to enter
+ // their credentials to ensure the correct users account is authorized.)
return true;
}
/**
- * Class handler.
+ * Handle a request for temporary OAuth credentials
+ *
+ * Make sure the request is kosher, then emit a set of temporary
+ * credentials -- AKA an unauthorized request token.
*
* @param array $args array of arguments
*
* @return void
*/
+
function handle($args)
{
parent::handle($args);
$server->add_signature_method($hmac_method);
try {
- $req = OAuthRequest::from_request();
+
+ $req = OAuthRequest::from_request();
+
+ // verify callback
+ if (!$this->verifyCallback($req->get_parameter('oauth_callback'))) {
+ throw new OAuthException(
+ "You must provide a valid URL or 'oob' in oauth_callback.",
+ 400
+ );
+ }
+
+ // check signature and issue a new request token
$token = $server->fetch_request_token($req);
- print $token;
+
+ common_log(
+ LOG_INFO,
+ sprintf(
+ "API OAuth - Issued request token %s for consumer %s with oauth_callback %s",
+ $token->key,
+ $req->get_parameter('oauth_consumer_key'),
+ "'" . $req->get_parameter('oauth_callback') ."'"
+ )
+ );
+
+ // return token to the client
+ $this->showRequestToken($token);
+
} catch (OAuthException $e) {
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
- header('HTTP/1.1 401 Unauthorized');
- header('Content-Type: text/html; charset=utf-8');
- print $e->getMessage() . "\n";
+
+ // Return 401 for for bad credentials or signature problems,
+ // and 400 for missing or unsupported parameters
+
+ $code = $e->getCode();
+ $this->clientError($e->getMessage(), empty($code) ? 401 : $code, 'text');
+ }
+ }
+
+ /*
+ * Display temporary OAuth credentials
+ */
+
+ function showRequestToken($token)
+ {
+ header('Content-Type: application/x-www-form-urlencoded');
+ print $token;
+ print '&oauth_callback_confirmed=true';
+ }
+
+ /* Make sure the callback parameter contains either a real URL
+ * or the string 'oob'.
+ *
+ * @todo Check for evil/banned URLs here
+ *
+ * @return boolean true or false
+ */
+
+ function verifyCallback($callback)
+ {
+ if ($callback == "oob") {
+ common_debug("OAuth request token requested for out of bounds client.");
+
+ // XXX: Should we throw an error if a client is registered as a
+ // web application but requests the pin based workflow? For now I'm
+ // allowing the workflow to proceed and issuing a pin. --Zach
+
+ return true;
+ } else {
+ return Validate::uri(
+ $callback,
+ array('allowed_schemes' => array('http', 'https'))
+ );
}
}
$themeChanged = ($this->trimmed('theme') != $oldtheme);
}
- static $settings = array('theme', 'logo');
+ static $settings = array('theme', 'logo', 'ssllogo');
$values = array();
function restoreDefaults()
{
$this->deleteSetting('site', 'logo');
+ $this->deleteSetting('site', 'ssllogo');
$this->deleteSetting('site', 'theme');
$settings = array(
/**
* Save the custom theme if the user uploaded one.
- *
+ *
* @return mixed custom theme name, if succesful, or null if no theme upload.
* @throws ClientException for invalid theme archives
* @throws ServerException if trouble saving the theme files
$this->clientError(_('Invalid logo URL.'));
}
+ if (!empty($values['ssllogo']) &&
+ !Validate::uri($values['ssllogo'], array('allowed_schemes' => array('https')))) {
+ $this->clientError(_('Invalid SSL logo URL.'));
+ }
+
if (!in_array($values['theme'], Theme::listAvailable())) {
$this->clientError(sprintf(_("Theme not available: %s."), $values['theme']));
}
$this->input('logo', _('Site logo'), 'Logo for the site (full URL)');
$this->unli();
+ $this->li();
+ $this->input('ssllogo', _('SSL logo'), 'Logo to show on SSL pages');
+ $this->unli();
+
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
static function url($filename)
{
- $path = common_config('background', 'path');
-
- if ($path[strlen($path)-1] != '/') {
- $path .= '/';
- }
+ if (StatusNet::isHTTPS()) {
+
+ $sslserver = common_config('background', 'sslserver');
+
+ if (empty($sslserver)) {
+ // XXX: this assumes that background dir == site dir + /background/
+ // not true if there's another server
+ if (is_string(common_config('site', 'sslserver')) &&
+ mb_strlen(common_config('site', 'sslserver')) > 0) {
+ $server = common_config('site', 'sslserver');
+ } else if (common_config('site', 'server')) {
+ $server = common_config('site', 'server');
+ }
+ $path = common_config('site', 'path') . '/background/';
+ } else {
+ $server = $sslserver;
+ $path = common_config('background', 'sslpath');
+ if (empty($path)) {
+ $path = common_config('background', 'path');
+ }
+ }
- if ($path[0] != '/') {
- $path = '/'.$path;
- }
+ $protocol = 'https';
- $server = common_config('background', 'server');
+ } else {
- if (empty($server)) {
- $server = common_config('site', 'server');
- }
+ $path = common_config('background', 'path');
- $ssl = common_config('background', 'ssl');
+ $server = common_config('background', 'server');
- if (is_null($ssl)) { // null -> guess
- if (common_config('site', 'ssl') == 'always' &&
- !common_config('background', 'server')) {
- $ssl = true;
- } else {
- $ssl = false;
+ if (empty($server)) {
+ $server = common_config('site', 'server');
}
+
+ $protocol = 'http';
}
- $protocol = ($ssl) ? 'https' : 'http';
+ if ($path[strlen($path)-1] != '/') {
+ $path .= '/';
+ }
+
+ if ($path[0] != '/') {
+ $path = '/'.$path;
+ }
return $protocol.'://'.$server.$path.$filename;
}
// TRANS: Client exception thrown if a file upload does not have a valid name.
throw new ClientException(_("Invalid filename."));
}
- if(common_config('site','private')) {
+
+ if (common_config('site','private')) {
return common_local_url('getfile',
array('filename' => $filename));
- } else {
- $path = common_config('attachments', 'path');
+ }
- if ($path[strlen($path)-1] != '/') {
- $path .= '/';
- }
+ if (StatusNet::isHTTPS()) {
+
+ $sslserver = common_config('attachments', 'sslserver');
- if ($path[0] != '/') {
- $path = '/'.$path;
+ if (empty($sslserver)) {
+ // XXX: this assumes that background dir == site dir + /file/
+ // not true if there's another server
+ if (is_string(common_config('site', 'sslserver')) &&
+ mb_strlen(common_config('site', 'sslserver')) > 0) {
+ $server = common_config('site', 'sslserver');
+ } else if (common_config('site', 'server')) {
+ $server = common_config('site', 'server');
+ }
+ $path = common_config('site', 'path') . '/file/';
+ } else {
+ $server = $sslserver;
+ $path = common_config('attachments', 'sslpath');
+ if (empty($path)) {
+ $path = common_config('attachments', 'path');
+ }
}
+ $protocol = 'https';
+
+ } else {
+
+ $path = common_config('attachments', 'path');
$server = common_config('attachments', 'server');
if (empty($server)) {
$ssl = common_config('attachments', 'ssl');
- if (is_null($ssl)) { // null -> guess
- if (common_config('site', 'ssl') == 'always' &&
- !common_config('attachments', 'server')) {
- $ssl = true;
- } else {
- $ssl = false;
- }
- }
-
$protocol = ($ssl) ? 'https' : 'http';
+ }
- return $protocol.'://'.$server.$path.$filename;
+ if ($path[strlen($path)-1] != '/') {
+ $path .= '/';
}
+
+ if ($path[0] != '/') {
+ $path = '/'.$path;
+ }
+
+ return $protocol.'://'.$server.$path.$filename;
}
function getEnclosure(){
}
$start = microtime(true);
- $result = parent::_query($string);
+ $fail = false;
+ try {
+ $result = parent::_query($string);
+ } catch (Exception $e) {
+ $fail = $e;
+ }
$delta = microtime(true) - $start;
$limit = common_config('db', 'log_slow_queries');
if (($limit > 0 && $delta >= $limit) || common_config('db', 'log_queries')) {
$clean = $this->sanitizeQuery($string);
- common_log(LOG_DEBUG, sprintf("DB query (%0.3fs): %s", $delta, $clean));
+ if ($fail) {
+ $msg = sprintf("FAILED DB query (%0.3fs): %s - %s", $delta, $fail->getMessage(), $clean);
+ } else {
+ $msg = sprintf("DB query (%0.3fs): %s", $delta, $clean);
+ }
+ common_log(LOG_DEBUG, $msg);
+ }
+
+ if ($fail) {
+ throw $fail;
}
return $result;
}
function delete()
{
if ($this->id) {
+
// Safe to delete in bulk for now
+
$related = array('Group_inbox',
'Group_block',
'Group_member',
'Related_group');
+
Event::handle('UserGroupDeleteRelated', array($this, &$related));
+
foreach ($related as $cls) {
+
$inst = new $cls();
$inst->group_id = $this->id;
- $inst->delete();
+
+ if ($inst->find()) {
+ while ($inst->fetch()) {
+ $dup = clone($inst);
+ $dup->delete();
+ }
+ }
}
// And related groups in the other direction...
if ($local) {
$local->delete();
}
+
+ // blow the cached ids
+ self::blow('user_group:notice_ids:%d', $this->id);
+
} else {
common_log(LOG_WARN, "Ambiguous user_group->delete(); skipping related tables.");
}
/* Generic exception class
*/
-class OAuthException extends Exception {/*{{{*/
+class OAuthException extends Exception {
// pass
-}/*}}}*/
+}
-class OAuthConsumer {/*{{{*/
+class OAuthConsumer {
public $key;
public $secret;
- function __construct($key, $secret, $callback_url=NULL) {/*{{{*/
+ function __construct($key, $secret, $callback_url=NULL) {
$this->key = $key;
$this->secret = $secret;
$this->callback_url = $callback_url;
- }/*}}}*/
+ }
- function __toString() {/*{{{*/
+ function __toString() {
return "OAuthConsumer[key=$this->key,secret=$this->secret]";
- }/*}}}*/
-}/*}}}*/
+ }
+}
-class OAuthToken {/*{{{*/
+class OAuthToken {
// access tokens and request tokens
public $key;
public $secret;
* key = the token
* secret = the token secret
*/
- function __construct($key, $secret) {/*{{{*/
+ function __construct($key, $secret) {
$this->key = $key;
$this->secret = $secret;
- }/*}}}*/
+ }
/**
* generates the basic string serialization of a token that a server
* would respond to request_token and access_token calls with
*/
- function to_string() {/*{{{*/
- return "oauth_token=" . OAuthUtil::urlencode_rfc3986($this->key) .
- "&oauth_token_secret=" . OAuthUtil::urlencode_rfc3986($this->secret);
- }/*}}}*/
+ function to_string() {
+ return "oauth_token=" .
+ OAuthUtil::urlencode_rfc3986($this->key) .
+ "&oauth_token_secret=" .
+ OAuthUtil::urlencode_rfc3986($this->secret);
+ }
- function __toString() {/*{{{*/
+ function __toString() {
return $this->to_string();
- }/*}}}*/
-}/*}}}*/
-
-class OAuthSignatureMethod {/*{{{*/
- public function check_signature(&$request, $consumer, $token, $signature) {
- $built = $this->build_signature($request, $consumer, $token);
- return $built == $signature;
-
- // Check for zero length, although unlikely here
- if (strlen($built) == 0 || strlen($signature) == 0) {
- return false;
- }
-
- if (strlen($built) != strlen($signature)) {
- return false;
- }
+ }
+}
- $result = 0;
+/**
+ * A class for implementing a Signature Method
+ * See section 9 ("Signing Requests") in the spec
+ */
+abstract class OAuthSignatureMethod {
+ /**
+ * Needs to return the name of the Signature Method (ie HMAC-SHA1)
+ * @return string
+ */
+ abstract public function get_name();
- // Avoid a timing leak with a (hopefully) time insensitive compare
- for ($i = 0; $i < strlen($signature); $i++) {
- $result |= ord($built{$i}) ^ ord($signature{$i});
- }
+ /**
+ * Build up the signature
+ * NOTE: The output of this function MUST NOT be urlencoded.
+ * the encoding is handled in OAuthRequest when the final
+ * request is serialized
+ * @param OAuthRequest $request
+ * @param OAuthConsumer $consumer
+ * @param OAuthToken $token
+ * @return string
+ */
+ abstract public function build_signature($request, $consumer, $token);
- return $result == 0;
+ /**
+ * Verifies that a given signature is correct
+ * @param OAuthRequest $request
+ * @param OAuthConsumer $consumer
+ * @param OAuthToken $token
+ * @param string $signature
+ * @return bool
+ */
+ public function check_signature($request, $consumer, $token, $signature) {
+ $built = $this->build_signature($request, $consumer, $token);
+ return $built == $signature;
}
-}/*}}}*/
-
-class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {/*{{{*/
- function get_name() {/*{{{*/
+}
+
+/**
+ * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
+ * where the Signature Base String is the text and the key is the concatenated values (each first
+ * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
+ * character (ASCII code 38) even if empty.
+ * - Chapter 9.2 ("HMAC-SHA1")
+ */
+class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
+ function get_name() {
return "HMAC-SHA1";
- }/*}}}*/
+ }
- public function build_signature($request, $consumer, $token) {/*{{{*/
+ public function build_signature($request, $consumer, $token) {
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
$key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
$key = implode('&', $key_parts);
- return base64_encode( hash_hmac('sha1', $base_string, $key, true));
- }/*}}}*/
-}/*}}}*/
+ return base64_encode(hash_hmac('sha1', $base_string, $key, true));
+ }
+}
-class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {/*{{{*/
- public function get_name() {/*{{{*/
+/**
+ * The PLAINTEXT method does not provide any security protection and SHOULD only be used
+ * over a secure channel such as HTTPS. It does not use the Signature Base String.
+ * - Chapter 9.4 ("PLAINTEXT")
+ */
+class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
+ public function get_name() {
return "PLAINTEXT";
- }/*}}}*/
+ }
- public function build_signature($request, $consumer, $token) {/*{{{*/
- $sig = array(
- OAuthUtil::urlencode_rfc3986($consumer->secret)
+ /**
+ * oauth_signature is set to the concatenated encoded values of the Consumer Secret and
+ * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
+ * empty. The result MUST be encoded again.
+ * - Chapter 9.4.1 ("Generating Signatures")
+ *
+ * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
+ * OAuthRequest handles this!
+ */
+ public function build_signature($request, $consumer, $token) {
+ $key_parts = array(
+ $consumer->secret,
+ ($token) ? $token->secret : ""
);
- if ($token) {
- array_push($sig, OAuthUtil::urlencode_rfc3986($token->secret));
- } else {
- array_push($sig, '');
- }
-
- $raw = implode("&", $sig);
- // for debug purposes
- $request->base_string = $raw;
-
- return OAuthUtil::urlencode_rfc3986($raw);
- }/*}}}*/
-}/*}}}*/
+ $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
+ $key = implode('&', $key_parts);
+ $request->base_string = $key;
-class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {/*{{{*/
- public function get_name() {/*{{{*/
+ return $key;
+ }
+}
+
+/**
+ * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
+ * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
+ * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
+ * verified way to the Service Provider, in a manner which is beyond the scope of this
+ * specification.
+ * - Chapter 9.3 ("RSA-SHA1")
+ */
+abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
+ public function get_name() {
return "RSA-SHA1";
- }/*}}}*/
-
- protected function fetch_public_cert(&$request) {/*{{{*/
- // not implemented yet, ideas are:
- // (1) do a lookup in a table of trusted certs keyed off of consumer
- // (2) fetch via http using a url provided by the requester
- // (3) some sort of specific discovery code based on request
- //
- // either way should return a string representation of the certificate
- throw Exception("fetch_public_cert not implemented");
- }/*}}}*/
-
- protected function fetch_private_cert(&$request) {/*{{{*/
- // not implemented yet, ideas are:
- // (1) do a lookup in a table of trusted certs keyed off of consumer
- //
- // either way should return a string representation of the certificate
- throw Exception("fetch_private_cert not implemented");
- }/*}}}*/
-
- public function build_signature(&$request, $consumer, $token) {/*{{{*/
+ }
+
+ // Up to the SP to implement this lookup of keys. Possible ideas are:
+ // (1) do a lookup in a table of trusted certs keyed off of consumer
+ // (2) fetch via http using a url provided by the requester
+ // (3) some sort of specific discovery code based on request
+ //
+ // Either way should return a string representation of the certificate
+ protected abstract function fetch_public_cert(&$request);
+
+ // Up to the SP to implement this lookup of keys. Possible ideas are:
+ // (1) do a lookup in a table of trusted certs keyed off of consumer
+ //
+ // Either way should return a string representation of the certificate
+ protected abstract function fetch_private_cert(&$request);
+
+ public function build_signature($request, $consumer, $token) {
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
-
+
// Fetch the private key cert based on the request
$cert = $this->fetch_private_cert($request);
$privatekeyid = openssl_get_privatekey($cert);
// Sign using the key
- $ok = openssl_sign($base_string, $signature, $privatekeyid);
+ $ok = openssl_sign($base_string, $signature, $privatekeyid);
// Release the key resource
openssl_free_key($privatekeyid);
-
+
return base64_encode($signature);
- } /*}}}*/
+ }
- public function check_signature(&$request, $consumer, $token, $signature) {/*{{{*/
+ public function check_signature($request, $consumer, $token, $signature) {
$decoded_sig = base64_decode($signature);
$base_string = $request->get_signature_base_string();
-
+
// Fetch the public key cert based on the request
$cert = $this->fetch_public_cert($request);
$publickeyid = openssl_get_publickey($cert);
// Check the computed signature against the one passed in the query
- $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
+ $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
// Release the key resource
openssl_free_key($publickeyid);
-
+
return $ok == 1;
- } /*}}}*/
-}/*}}}*/
+ }
+}
-class OAuthRequest {/*{{{*/
- private $parameters;
- private $http_method;
- private $http_url;
+class OAuthRequest {
+ protected $parameters;
+ protected $http_method;
+ protected $http_url;
// for debug purposes
public $base_string;
public static $version = '1.0';
+ public static $POST_INPUT = 'php://input';
- function __construct($http_method, $http_url, $parameters=NULL) {/*{{{*/
- @$parameters or $parameters = array();
+ function __construct($http_method, $http_url, $parameters=NULL) {
+ $parameters = ($parameters) ? $parameters : array();
+ $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
$this->parameters = $parameters;
$this->http_method = $http_method;
$this->http_url = $http_url;
- }/*}}}*/
+ }
/**
* attempt to build up a request from what was passed to the server
*/
- public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {/*{{{*/
- $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https';
- @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI'];
- @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
-
- $request_headers = OAuthRequest::get_headers();
+ public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
+ $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
+ ? 'http'
+ : 'https';
+ $http_url = ($http_url) ? $http_url : $scheme .
+ '://' . $_SERVER['HTTP_HOST'] .
+ ':' .
+ $_SERVER['SERVER_PORT'] .
+ $_SERVER['REQUEST_URI'];
+ $http_method = ($http_method) ? $http_method : $_SERVER['REQUEST_METHOD'];
+
+ // We weren't handed any parameters, so let's find the ones relevant to
+ // this request.
+ // If you run XML-RPC or similar you should use this to provide your own
+ // parsed parameter-list
+ if (!$parameters) {
+ // Find request headers
+ $request_headers = OAuthUtil::get_headers();
+
+ // Parse the query-string to find GET parameters
+ $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
+
+ // It's a POST request of the proper content-type, so parse POST
+ // parameters and add those overriding any duplicates from GET
+ if ($http_method == "POST"
+ && isset($request_headers['Content-Type'])
+ && strstr($request_headers['Content-Type'],
+ 'application/x-www-form-urlencoded')
+ ) {
+ $post_data = OAuthUtil::parse_parameters(
+ file_get_contents(self::$POST_INPUT)
+ );
+ $parameters = array_merge($parameters, $post_data);
+ }
- // let the library user override things however they'd like, if they know
- // which parameters to use then go for it, for example XMLRPC might want to
- // do this
- if ($parameters) {
- $req = new OAuthRequest($http_method, $http_url, $parameters);
- } else {
- // collect request parameters from query string (GET) and post-data (POST) if appropriate (note: POST vars have priority)
- $req_parameters = $_GET;
- if ($http_method == "POST" &&
- ( @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") || @strstr($_ENV["CONTENT_TYPE"], "application/x-www-form-urlencoded") )) {
- $req_parameters = array_merge($req_parameters, $_POST);
+ // We have a Authorization-header with OAuth data. Parse the header
+ // and add those overriding any duplicates from GET or POST
+ if (isset($request_headers['Authorization']) && substr($request_headers['Authorization'], 0, 6) == 'OAuth ') {
+ $header_parameters = OAuthUtil::split_header(
+ $request_headers['Authorization']
+ );
+ $parameters = array_merge($parameters, $header_parameters);
}
- // next check for the auth header, we need to do some extra stuff
- // if that is the case, namely suck in the parameters from GET or POST
- // so that we can include them in the signature
- if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
- $header_parameters = OAuthRequest::split_header($request_headers['Authorization']);
- $parameters = array_merge($req_parameters, $header_parameters);
- $req = new OAuthRequest($http_method, $http_url, $parameters);
- } else $req = new OAuthRequest($http_method, $http_url, $req_parameters);
}
- return $req;
- }/*}}}*/
+ return new OAuthRequest($http_method, $http_url, $parameters);
+ }
/**
* pretty much a helper function to set up the request
*/
- public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {/*{{{*/
- @$parameters or $parameters = array();
+ public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
+ $parameters = ($parameters) ? $parameters : array();
$defaults = array("oauth_version" => OAuthRequest::$version,
"oauth_nonce" => OAuthRequest::generate_nonce(),
"oauth_timestamp" => OAuthRequest::generate_timestamp(),
"oauth_consumer_key" => $consumer->key);
+ if ($token)
+ $defaults['oauth_token'] = $token->key;
+
$parameters = array_merge($defaults, $parameters);
- if ($token) {
- $parameters['oauth_token'] = $token->key;
- }
return new OAuthRequest($http_method, $http_url, $parameters);
- }/*}}}*/
+ }
- public function set_parameter($name, $value) {/*{{{*/
- $this->parameters[$name] = $value;
- }/*}}}*/
+ public function set_parameter($name, $value, $allow_duplicates = true) {
+ if ($allow_duplicates && isset($this->parameters[$name])) {
+ // We have already added parameter(s) with this name, so add to the list
+ if (is_scalar($this->parameters[$name])) {
+ // This is the first duplicate, so transform scalar (string)
+ // into an array so we can add the duplicates
+ $this->parameters[$name] = array($this->parameters[$name]);
+ }
- public function get_parameter($name) {/*{{{*/
+ $this->parameters[$name][] = $value;
+ } else {
+ $this->parameters[$name] = $value;
+ }
+ }
+
+ public function get_parameter($name) {
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
- }/*}}}*/
+ }
- public function get_parameters() {/*{{{*/
+ public function get_parameters() {
return $this->parameters;
- }/*}}}*/
+ }
+
+ public function unset_parameter($name) {
+ unset($this->parameters[$name]);
+ }
/**
- * Returns the normalized parameters of the request
- *
- * This will be all (except oauth_signature) parameters,
- * sorted first by key, and if duplicate keys, then by
- * value.
- *
- * The returned string will be all the key=value pairs
- * concated by &.
- *
+ * The request parameters, sorted and concatenated into a normalized string.
* @return string
*/
- public function get_signable_parameters() {/*{{{*/
+ public function get_signable_parameters() {
// Grab all parameters
$params = $this->parameters;
-
+
// Remove oauth_signature if present
+ // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
if (isset($params['oauth_signature'])) {
unset($params['oauth_signature']);
}
-
- // Urlencode both keys and values
- $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
- $values = OAuthUtil::urlencode_rfc3986(array_values($params));
- $params = array_combine($keys, $values);
-
- // Sort by keys (natsort)
- uksort($params, 'strcmp');
- // Generate key=value pairs
- $pairs = array();
- foreach ($params as $key=>$value ) {
- if (is_array($value)) {
- // If the value is an array, it's because there are multiple
- // with the same key, sort them, then add all the pairs
- natsort($value);
- foreach ($value as $v2) {
- $pairs[] = $key . '=' . $v2;
- }
- } else {
- $pairs[] = $key . '=' . $value;
- }
- }
-
- // Return the pairs, concated with &
- return implode('&', $pairs);
- }/*}}}*/
+ return OAuthUtil::build_http_query($params);
+ }
/**
* Returns the base string of this request
* and the parameters (normalized), each urlencoded
* and the concated with &.
*/
- public function get_signature_base_string() {/*{{{*/
+ public function get_signature_base_string() {
$parts = array(
$this->get_normalized_http_method(),
$this->get_normalized_http_url(),
$parts = OAuthUtil::urlencode_rfc3986($parts);
return implode('&', $parts);
- }/*}}}*/
+ }
/**
* just uppercases the http method
*/
- public function get_normalized_http_method() {/*{{{*/
+ public function get_normalized_http_method() {
return strtoupper($this->http_method);
- }/*}}}*/
+ }
/**
* parses the url and rebuilds it to be
* scheme://host/path
*/
- public function get_normalized_http_url() {/*{{{*/
+ public function get_normalized_http_url() {
$parts = parse_url($this->http_url);
- $port = isset($parts['port']) ? $parts['port'] : null;
- $scheme = $parts['scheme'];
- $host = $parts['host'];
- $path = @$parts['path'];
-
- $port or $port = ($scheme == 'https') ? '443' : '80';
+ $scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http';
+ $port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80');
+ $host = (isset($parts['host'])) ? $parts['host'] : '';
+ $path = (isset($parts['path'])) ? $parts['path'] : '';
if (($scheme == 'https' && $port != '443')
|| ($scheme == 'http' && $port != '80')) {
$host = "$host:$port";
}
return "$scheme://$host$path";
- }/*}}}*/
+ }
/**
* builds a url usable for a GET request
*/
- public function to_url() {/*{{{*/
- $out = $this->get_normalized_http_url() . "?";
- $out .= $this->to_postdata();
+ public function to_url() {
+ $post_data = $this->to_postdata();
+ $out = $this->get_normalized_http_url();
+ if ($post_data) {
+ $out .= '?'.$post_data;
+ }
return $out;
- }/*}}}*/
+ }
/**
* builds the data one would send in a POST request
- *
- * TODO(morten.fangel):
- * this function might be easily replaced with http_build_query()
- * and corrections for rfc3986 compatibility.. but not sure
*/
- public function to_postdata() {/*{{{*/
- $total = array();
- foreach ($this->parameters as $k => $v) {
- if (is_array($v)) {
- foreach ($v as $va) {
- $total[] = OAuthUtil::urlencode_rfc3986($k) . "[]=" . OAuthUtil::urlencode_rfc3986($va);
- }
- } else {
- $total[] = OAuthUtil::urlencode_rfc3986($k) . "=" . OAuthUtil::urlencode_rfc3986($v);
- }
- }
- $out = implode("&", $total);
- return $out;
- }/*}}}*/
+ public function to_postdata() {
+ return OAuthUtil::build_http_query($this->parameters);
+ }
/**
* builds the Authorization: header
*/
- public function to_header() {/*{{{*/
- $out ='Authorization: OAuth realm=""';
+ public function to_header($realm=null) {
+ $first = true;
+ if($realm) {
+ $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
+ $first = false;
+ } else
+ $out = 'Authorization: OAuth';
+
$total = array();
foreach ($this->parameters as $k => $v) {
if (substr($k, 0, 5) != "oauth") continue;
- if (is_array($v)) throw new OAuthException('Arrays not supported in headers');
- $out .= ',' . OAuthUtil::urlencode_rfc3986($k) . '="' . OAuthUtil::urlencode_rfc3986($v) . '"';
+ if (is_array($v)) {
+ throw new OAuthException('Arrays not supported in headers');
+ }
+ $out .= ($first) ? ' ' : ',';
+ $out .= OAuthUtil::urlencode_rfc3986($k) .
+ '="' .
+ OAuthUtil::urlencode_rfc3986($v) .
+ '"';
+ $first = false;
}
return $out;
- }/*}}}*/
+ }
- public function __toString() {/*{{{*/
+ public function __toString() {
return $this->to_url();
- }/*}}}*/
+ }
- public function sign_request($signature_method, $consumer, $token) {/*{{{*/
- $this->set_parameter("oauth_signature_method", $signature_method->get_name());
+ public function sign_request($signature_method, $consumer, $token) {
+ $this->set_parameter(
+ "oauth_signature_method",
+ $signature_method->get_name(),
+ false
+ );
$signature = $this->build_signature($signature_method, $consumer, $token);
- $this->set_parameter("oauth_signature", $signature);
- }/*}}}*/
+ $this->set_parameter("oauth_signature", $signature, false);
+ }
- public function build_signature($signature_method, $consumer, $token) {/*{{{*/
+ public function build_signature($signature_method, $consumer, $token) {
$signature = $signature_method->build_signature($this, $consumer, $token);
return $signature;
- }/*}}}*/
+ }
/**
* util function: current timestamp
*/
- private static function generate_timestamp() {/*{{{*/
+ private static function generate_timestamp() {
return time();
- }/*}}}*/
+ }
/**
* util function: current nonce
*/
- private static function generate_nonce() {/*{{{*/
+ private static function generate_nonce() {
$mt = microtime();
$rand = mt_rand();
return md5($mt . $rand); // md5s look nicer than numbers
- }/*}}}*/
-
- /**
- * util function for turning the Authorization: header into
- * parameters, has to do some unescaping
- */
- private static function split_header($header) {/*{{{*/
- $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
- $offset = 0;
- $params = array();
- while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
- $match = $matches[0];
- $header_name = $matches[2][0];
- $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
- $params[$header_name] = OAuthUtil::urldecode_rfc3986( $header_content );
- $offset = $match[1] + strlen($match[0]);
- }
-
- if (isset($params['realm'])) {
- unset($params['realm']);
- }
-
- return $params;
- }/*}}}*/
-
- /**
- * helper to try to sort out headers for people who aren't running apache
- */
- private static function get_headers() {/*{{{*/
- if (function_exists('apache_request_headers')) {
- // we need this to get the actual Authorization: header
- // because apache tends to tell us it doesn't exist
- return apache_request_headers();
- }
- // otherwise we don't have apache and are just going to have to hope
- // that $_SERVER actually contains what we need
- $out = array();
- foreach ($_SERVER as $key => $value) {
- if (substr($key, 0, 5) == "HTTP_") {
- // this is chaos, basically it is just there to capitalize the first
- // letter of every word that is not an initial HTTP and strip HTTP
- // code from przemek
- $key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))));
- $out[$key] = $value;
- }
- }
- return $out;
- }/*}}}*/
-}/*}}}*/
+ }
+}
-class OAuthServer {/*{{{*/
+class OAuthServer {
protected $timestamp_threshold = 300; // in seconds, five minutes
- protected $version = 1.0; // hi blaine
+ protected $version = '1.0'; // hi blaine
protected $signature_methods = array();
protected $data_store;
- function __construct($data_store) {/*{{{*/
+ function __construct($data_store) {
$this->data_store = $data_store;
- }/*}}}*/
+ }
+
+ public function add_signature_method($signature_method) {
+ $this->signature_methods[$signature_method->get_name()] =
+ $signature_method;
+ }
- public function add_signature_method($signature_method) {/*{{{*/
- $this->signature_methods[$signature_method->get_name()] =
- $signature_method;
- }/*}}}*/
-
// high level functions
/**
* process a request_token request
* returns the request token on success
*/
- public function fetch_request_token(&$request) {/*{{{*/
+ public function fetch_request_token(&$request) {
$this->get_version($request);
$consumer = $this->get_consumer($request);
$this->check_signature($request, $consumer, $token);
- $new_token = $this->data_store->new_request_token($consumer);
+ // Rev A change
+ $callback = $request->get_parameter('oauth_callback');
+ $new_token = $this->data_store->new_request_token($consumer, $callback);
return $new_token;
- }/*}}}*/
+ }
/**
* process an access_token request
* returns the access token on success
*/
- public function fetch_access_token(&$request) {/*{{{*/
+ public function fetch_access_token(&$request) {
$this->get_version($request);
$consumer = $this->get_consumer($request);
// requires authorized request token
$token = $this->get_token($request, $consumer, "request");
-
$this->check_signature($request, $consumer, $token);
- $new_token = $this->data_store->new_access_token($token, $consumer);
+ // Rev A change
+ $verifier = $request->get_parameter('oauth_verifier');
+ $new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
return $new_token;
- }/*}}}*/
+ }
/**
* verify an api call, checks all the parameters
*/
- public function verify_request(&$request) {/*{{{*/
+ public function verify_request(&$request) {
$this->get_version($request);
$consumer = $this->get_consumer($request);
$token = $this->get_token($request, $consumer, "access");
$this->check_signature($request, $consumer, $token);
return array($consumer, $token);
- }/*}}}*/
+ }
// Internals from here
/**
* version 1
*/
- private function get_version(&$request) {/*{{{*/
+ private function get_version(&$request) {
$version = $request->get_parameter("oauth_version");
if (!$version) {
- $version = 1.0;
+ // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
+ // Chapter 7.0 ("Accessing Protected Ressources")
+ $version = '1.0';
}
- if ($version && $version != $this->version) {
+ if ($version !== $this->version) {
throw new OAuthException("OAuth version '$version' not supported");
}
return $version;
- }/*}}}*/
+ }
/**
* figure out the signature with some defaults
*/
- private function get_signature_method(&$request) {/*{{{*/
- $signature_method =
- @$request->get_parameter("oauth_signature_method");
+ private function get_signature_method($request) {
+ $signature_method = $request instanceof OAuthRequest
+ ? $request->get_parameter("oauth_signature_method")
+ : NULL;
+
if (!$signature_method) {
- $signature_method = "PLAINTEXT";
+ // According to chapter 7 ("Accessing Protected Ressources") the signature-method
+ // parameter is required, and we can't just fallback to PLAINTEXT
+ throw new OAuthException('No signature method parameter. This parameter is required');
}
- if (!in_array($signature_method,
+
+ if (!in_array($signature_method,
array_keys($this->signature_methods))) {
throw new OAuthException(
- "Signature method '$signature_method' not supported try one of the following: " . implode(", ", array_keys($this->signature_methods))
- );
+ "Signature method '$signature_method' not supported " .
+ "try one of the following: " .
+ implode(", ", array_keys($this->signature_methods))
+ );
}
return $this->signature_methods[$signature_method];
- }/*}}}*/
+ }
/**
* try to find the consumer for the provided request's consumer key
*/
- private function get_consumer(&$request) {/*{{{*/
- $consumer_key = @$request->get_parameter("oauth_consumer_key");
+ private function get_consumer($request) {
+ $consumer_key = $request instanceof OAuthRequest
+ ? $request->get_parameter("oauth_consumer_key")
+ : NULL;
+
if (!$consumer_key) {
throw new OAuthException("Invalid consumer key");
}
}
return $consumer;
- }/*}}}*/
+ }
/**
* try to find the token for the provided request's token key
*/
- private function get_token(&$request, $consumer, $token_type="access") {/*{{{*/
- $token_field = @$request->get_parameter('oauth_token');
+ private function get_token($request, $consumer, $token_type="access") {
+ $token_field = $request instanceof OAuthRequest
+ ? $request->get_parameter('oauth_token')
+ : NULL;
+
$token = $this->data_store->lookup_token(
$consumer, $token_type, $token_field
);
throw new OAuthException("Invalid $token_type token: $token_field");
}
return $token;
- }/*}}}*/
+ }
/**
* all-in-one function to check the signature on a request
* should guess the signature method appropriately
*/
- private function check_signature(&$request, $consumer, $token) {/*{{{*/
+ private function check_signature($request, $consumer, $token) {
// this should probably be in a different method
- $timestamp = @$request->get_parameter('oauth_timestamp');
- $nonce = @$request->get_parameter('oauth_nonce');
+ $timestamp = $request instanceof OAuthRequest
+ ? $request->get_parameter('oauth_timestamp')
+ : NULL;
+ $nonce = $request instanceof OAuthRequest
+ ? $request->get_parameter('oauth_nonce')
+ : NULL;
$this->check_timestamp($timestamp);
$this->check_nonce($consumer, $token, $nonce, $timestamp);
$signature_method = $this->get_signature_method($request);
- $signature = $request->get_parameter('oauth_signature');
+ $signature = $request->get_parameter('oauth_signature');
$valid_sig = $signature_method->check_signature(
- $request,
- $consumer,
- $token,
+ $request,
+ $consumer,
+ $token,
$signature
);
if (!$valid_sig) {
throw new OAuthException("Invalid signature");
}
- }/*}}}*/
+ }
/**
* check that the timestamp is new enough
*/
- private function check_timestamp($timestamp) {/*{{{*/
+ private function check_timestamp($timestamp) {
+ if( ! $timestamp )
+ throw new OAuthException(
+ 'Missing timestamp parameter. The parameter is required'
+ );
+
// verify that timestamp is recentish
$now = time();
- if ($now - $timestamp > $this->timestamp_threshold) {
- throw new OAuthException("Expired timestamp, yours $timestamp, ours $now");
+ if (abs($now - $timestamp) > $this->timestamp_threshold) {
+ throw new OAuthException(
+ "Expired timestamp, yours $timestamp, ours $now"
+ );
}
- }/*}}}*/
+ }
/**
* check that the nonce is not repeated
*/
- private function check_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
+ private function check_nonce($consumer, $token, $nonce, $timestamp) {
+ if( ! $nonce )
+ throw new OAuthException(
+ 'Missing nonce parameter. The parameter is required'
+ );
+
// verify that the nonce is uniqueish
- $found = $this->data_store->lookup_nonce($consumer, $token, $nonce, $timestamp);
+ $found = $this->data_store->lookup_nonce(
+ $consumer,
+ $token,
+ $nonce,
+ $timestamp
+ );
if ($found) {
throw new OAuthException("Nonce already used: $nonce");
}
- }/*}}}*/
-
-
+ }
-}/*}}}*/
+}
-class OAuthDataStore {/*{{{*/
- function lookup_consumer($consumer_key) {/*{{{*/
+class OAuthDataStore {
+ function lookup_consumer($consumer_key) {
// implement me
- }/*}}}*/
+ }
- function lookup_token($consumer, $token_type, $token) {/*{{{*/
+ function lookup_token($consumer, $token_type, $token) {
// implement me
- }/*}}}*/
+ }
- function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
+ function lookup_nonce($consumer, $token, $nonce, $timestamp) {
// implement me
- }/*}}}*/
+ }
- function new_request_token($consumer) {/*{{{*/
+ function new_request_token($consumer, $callback = null) {
// return a new token attached to this consumer
- }/*}}}*/
+ }
- function new_access_token($token, $consumer) {/*{{{*/
+ function new_access_token($token, $consumer, $verifier = null) {
// return a new access token attached to this consumer
// for the user associated with this token if the request token
// is authorized
// should also invalidate the request token
- }/*}}}*/
-
-}/*}}}*/
-
-
-/* A very naive dbm-based oauth storage
- */
-class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/
- private $dbh;
+ }
- function __construct($path = "oauth.gdbm") {/*{{{*/
- $this->dbh = dba_popen($path, 'c', 'gdbm');
- }/*}}}*/
+}
+
+class OAuthUtil {
+ public static function urlencode_rfc3986($input) {
+ if (is_array($input)) {
+ return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
+ } else if (is_scalar($input)) {
+ return str_replace(
+ '+',
+ ' ',
+ str_replace('%7E', '~', rawurlencode($input))
+ );
+ } else {
+ return '';
+ }
+}
- function __destruct() {/*{{{*/
- dba_close($this->dbh);
- }/*}}}*/
- function lookup_consumer($consumer_key) {/*{{{*/
- $rv = dba_fetch("consumer_$consumer_key", $this->dbh);
- if ($rv === FALSE) {
- return NULL;
- }
- $obj = unserialize($rv);
- if (!($obj instanceof OAuthConsumer)) {
- return NULL;
- }
- return $obj;
- }/*}}}*/
+ // This decode function isn't taking into consideration the above
+ // modifications to the encoding process. However, this method doesn't
+ // seem to be used anywhere so leaving it as is.
+ public static function urldecode_rfc3986($string) {
+ return urldecode($string);
+ }
- function lookup_token($consumer, $token_type, $token) {/*{{{*/
- $rv = dba_fetch("${token_type}_${token}", $this->dbh);
- if ($rv === FALSE) {
- return NULL;
- }
- $obj = unserialize($rv);
- if (!($obj instanceof OAuthToken)) {
- return NULL;
+ // Utility function for turning the Authorization: header into
+ // parameters, has to do some unescaping
+ // Can filter out any non-oauth parameters if needed (default behaviour)
+ // May 28th, 2010 - method updated to tjerk.meesters for a speed improvement.
+ // see http://code.google.com/p/oauth/issues/detail?id=163
+ public static function split_header($header, $only_allow_oauth_parameters = true) {
+ $params = array();
+ if (preg_match_all('/('.($only_allow_oauth_parameters ? 'oauth_' : '').'[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches)) {
+ foreach ($matches[1] as $i => $h) {
+ $params[$h] = OAuthUtil::urldecode_rfc3986(empty($matches[3][$i]) ? $matches[4][$i] : $matches[3][$i]);
+ }
+ if (isset($params['realm'])) {
+ unset($params['realm']);
+ }
}
- return $obj;
- }/*}}}*/
+ return $params;
+ }
- function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
- if (dba_exists("nonce_$nonce", $this->dbh)) {
- return TRUE;
+ // helper to try to sort out headers for people who aren't running apache
+ public static function get_headers() {
+ if (function_exists('apache_request_headers')) {
+ // we need this to get the actual Authorization: header
+ // because apache tends to tell us it doesn't exist
+ $headers = apache_request_headers();
+
+ // sanitize the output of apache_request_headers because
+ // we always want the keys to be Cased-Like-This and arh()
+ // returns the headers in the same case as they are in the
+ // request
+ $out = array();
+ foreach ($headers AS $key => $value) {
+ $key = str_replace(
+ " ",
+ "-",
+ ucwords(strtolower(str_replace("-", " ", $key)))
+ );
+ $out[$key] = $value;
+ }
} else {
- dba_insert("nonce_$nonce", "1", $this->dbh);
- return FALSE;
+ // otherwise we don't have apache and are just going to have to hope
+ // that $_SERVER actually contains what we need
+ $out = array();
+ if( isset($_SERVER['CONTENT_TYPE']) )
+ $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
+ if( isset($_ENV['CONTENT_TYPE']) )
+ $out['Content-Type'] = $_ENV['CONTENT_TYPE'];
+
+ foreach ($_SERVER as $key => $value) {
+ if (substr($key, 0, 5) == "HTTP_") {
+ // this is chaos, basically it is just there to capitalize the first
+ // letter of every word that is not an initial HTTP and strip HTTP
+ // code from przemek
+ $key = str_replace(
+ " ",
+ "-",
+ ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
+ );
+ $out[$key] = $value;
+ }
+ }
}
- }/*}}}*/
-
- function new_token($consumer, $type="request") {/*{{{*/
- $key = md5(time());
- $secret = time() + time();
- $token = new OAuthToken($key, md5(md5($secret)));
- if (!dba_insert("${type}_$key", serialize($token), $this->dbh)) {
- throw new OAuthException("doooom!");
+ return $out;
+ }
+
+ // This function takes a input like a=b&a=c&d=e and returns the parsed
+ // parameters like this
+ // array('a' => array('b','c'), 'd' => 'e')
+ public static function parse_parameters( $input ) {
+ if (!isset($input) || !$input) return array();
+
+ $pairs = explode('&', $input);
+
+ $parsed_parameters = array();
+ foreach ($pairs as $pair) {
+ $split = explode('=', $pair, 2);
+ $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
+ $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
+
+ if (isset($parsed_parameters[$parameter])) {
+ // We have already recieved parameter(s) with this name, so add to the list
+ // of parameters with this name
+
+ if (is_scalar($parsed_parameters[$parameter])) {
+ // This is the first duplicate, so transform scalar (string) into an array
+ // so we can add the duplicates
+ $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
+ }
+
+ $parsed_parameters[$parameter][] = $value;
+ } else {
+ $parsed_parameters[$parameter] = $value;
+ }
}
- return $token;
- }/*}}}*/
+ return $parsed_parameters;
+ }
- function new_request_token($consumer) {/*{{{*/
- return $this->new_token($consumer, "request");
- }/*}}}*/
+ public static function build_http_query($params) {
+ if (!$params) return '';
- function new_access_token($token, $consumer) {/*{{{*/
+ // Urlencode both keys and values
+ $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
+ $values = OAuthUtil::urlencode_rfc3986(array_values($params));
+ $params = array_combine($keys, $values);
- $token = $this->new_token($consumer, 'access');
- dba_delete("request_" . $token->key, $this->dbh);
- return $token;
- }/*}}}*/
-}/*}}}*/
-
-class OAuthUtil {/*{{{*/
- public static function urlencode_rfc3986($input) {/*{{{*/
- if (is_array($input)) {
- return array_map(array('OAuthUtil','urlencode_rfc3986'), $input);
- } else if (is_scalar($input)) {
- return str_replace('+', ' ',
- str_replace('%7E', '~', rawurlencode($input)));
- } else {
- return '';
- }
- }/*}}}*/
-
+ // Parameters are sorted by name, using lexicographical byte value ordering.
+ // Ref: Spec: 9.1.1 (1)
+ uksort($params, 'strcmp');
- // This decode function isn't taking into consideration the above
- // modifications to the encoding process. However, this method doesn't
- // seem to be used anywhere so leaving it as is.
- public static function urldecode_rfc3986($string) {/*{{{*/
- return rawurldecode($string);
- }/*}}}*/
-}/*}}}*/
+ $pairs = array();
+ foreach ($params as $parameter => $value) {
+ if (is_array($value)) {
+ // If two or more parameters share the same name, they are sorted by their value
+ // Ref: Spec: 9.1.1 (1)
+ // June 12th, 2010 - changed to sort because of issue 164 by hidetaka
+ sort($value, SORT_STRING);
+ foreach ($value as $duplicate_value) {
+ $pairs[] = $parameter . '=' . $duplicate_value;
+ }
+ } else {
+ $pairs[] = $parameter . '=' . $value;
+ }
+ }
+ // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
+ // Each name-value pair is separated by an '&' character (ASCII code 38)
+ return implode('&', $pairs);
+ }
+}
?>
$this->element('link', array('rel' => 'shortcut icon',
'href' => Theme::path('favicon.ico')));
} else {
+ // favicon.ico should be HTTPS if the rest of the page is
$this->element('link', array('rel' => 'shortcut icon',
- 'href' => common_path('favicon.ico')));
+ 'href' => common_path('favicon.ico', StatusNet::isHTTPS())));
}
if (common_config('site', 'mobile')) {
Event::handle('EndShowSiteNotice', array($this));
}
if (common_logged_in()) {
- $this->showNoticeForm();
+ if (Event::handle('StartShowNoticeForm', array($this))) {
+ $this->showNoticeForm();
+ Event::handle('EndShowNoticeForm', array($this));
+ }
} else {
$this->showAnonymousMessage();
}
}
$this->elementStart('a', array('class' => 'url home bookmark',
'href' => $url));
- if (common_config('site', 'logo') || file_exists(Theme::file('logo.png'))) {
+
+ if (StatusNet::isHTTPS()) {
+ $logoUrl = common_config('site', 'ssllogo');
+ if (empty($logoUrl)) {
+ // if logo is an uploaded file, try to fall back to HTTPS file URL
+ $httpUrl = common_config('site', 'logo');
+ if (!empty($httpUrl)) {
+ $f = File::staticGet('url', $httpUrl);
+ if (!empty($f) && !empty($f->filename)) {
+ // this will handle the HTTPS case
+ $logoUrl = File::url($f->filename);
+ }
+ }
+ }
+ } else {
+ $logoUrl = common_config('site', 'logo');
+ }
+
+ if (empty($logoUrl) && file_exists(Theme::file('logo.png'))) {
+ // This should handle the HTTPS case internally
+ $logoUrl = Theme::path('logo.png');
+ }
+
+ if (!empty($logoUrl)) {
$this->element('img', array('class' => 'logo photo',
- 'src' => (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png'),
+ 'src' => $logoUrl,
'alt' => common_config('site', 'name')));
}
+
$this->text(' ');
$this->element('span', array('class' => 'fn org'), common_config('site', 'name'));
$this->elementEnd('a');
case 'cc': // fall through
default:
$this->elementStart('p');
+
+ $image = common_config('license', 'image');
+ $sslimage = common_config('license', 'sslimage');
+
+ if (StatusNet::isHTTPS()) {
+ if (!empty($sslimage)) {
+ $url = $sslimage;
+ } else if (preg_match('#^http://i.creativecommons.org/#', $image)) {
+ // CC support HTTPS on their images
+ $url = preg_replace('/^http/', 'https', $image);
+ } else {
+ // Better to show mixed content than no content
+ $url = $image;
+ }
+ } else {
+ $url = $image;
+ }
+
$this->element('img', array('id' => 'license_cc',
- 'src' => common_config('license', 'image'),
+ 'src' => $url,
'alt' => common_config('license', 'title'),
'width' => '80',
'height' => '15'));
// Do not emit error header for JSONP
if (!isset($this->callback)) {
- header('HTTP/1.1 '.$code.' '.$status_string);
+ header('HTTP/1.1 ' . $code . ' ' . $status_string);
}
- if ($format == 'xml') {
+ switch($format) {
+ case 'xml':
$this->initDocument('xml');
$this->elementStart('hash');
$this->element('error', null, $msg);
$this->element('request', null, $_SERVER['REQUEST_URI']);
$this->elementEnd('hash');
$this->endDocument('xml');
- } elseif ($format == 'json'){
+ break;
+ case 'json':
$this->initDocument('json');
$error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']);
print(json_encode($error_array));
$this->endDocument('json');
- } else {
-
+ break;
+ case 'text':
+ header('Content-Type: text/plain; charset=utf-8');
+ print $msg;
+ break;
+ default:
// If user didn't request a useful format, throw a regular client error
throw new ClientException($msg, $code);
}
if (!defined('STATUSNET')) {
exit(1);
}
-
+require_once INSTALLDIR . '/lib/apiaction.php';
require_once INSTALLDIR . '/lib/apioauthstore.php';
/**
- * Base action for API OAuth enpoints. Clean up the
- * the request, and possibly some other common things
- * here.
+ * Base action for API OAuth enpoints. Clean up the
+ * request. Some other common functions.
*
* @category API
* @package StatusNet
* @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
+class ApiOauthAction extends ApiAction
{
/**
* Is this a read-only action?
self::cleanRequest();
}
+ /*
+ * Clean up the request so the OAuth library doesn't find
+ * any extra parameters or anything else it's not expecting.
+ * I'm looking at you, p parameter.
+ */
+
static function cleanRequest()
{
// kill evil effects of magical slashing
}
// 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']);
- }
+ unset($_REQUEST['p']);
- function getCallback($url, $params)
- {
- foreach ($params as $k => $v) {
- $url = $this->appendQueryVar($url,
- OAuthUtil::urlencode_rfc3986($k),
- OAuthUtil::urlencode_rfc3986($v));
+ $queryArray = explode('&', $_SERVER['QUERY_STRING']);
+
+ for ($i = 0; $i < sizeof($queryArray); $i++) {
+ if (substr($queryArray[$i], 0, 2) == 'p=') {
+ unset($queryArray[$i]);
+ }
}
- return $url;
+ $_SERVER['QUERY_STRING'] = implode('&', $queryArray);
}
- 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);
- }
- }
}
}
}
- function new_access_token($token, $consumer)
+ function new_access_token($token, $consumer, $verifier)
{
- common_debug('new_access_token("'.$token->key.'","'.$consumer->key.'")', __FILE__);
+ common_debug(
+ 'new_access_token("' . $token->key . '","' . $consumer->key. '","' . $verifier . '")',
+ __FILE__
+ );
$rt = new Token();
+
$rt->consumer_key = $consumer->key;
- $rt->tok = $token->key;
- $rt->type = 0; // request
+ $rt->tok = $token->key;
+ $rt->type = 0; // request
$app = Oauth_application::getByConsumerKey($consumer->key);
+ assert(!empty($app));
- if (empty($app)) {
- common_debug("empty app!");
- }
+ if ($rt->find(true) && $rt->state == 1 && $rt->verifier == $verifier) { // authorized
- 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;
+ $appUser->token = $rt->tok;
+
$result = $appUser->find(true);
if (!empty($result)) {
- common_debug("Oath app user found.");
+ common_debug("Ouath 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->consumer_key = $consumer->key;
+ $at->tok = common_good_rand(16);
+ $at->secret = common_good_rand(16);
+ $at->type = 1; // access
+ $at->verifier = $verifier;
+ $at->verified_callback = $rt->verified_callback; // 1.0a
$at->created = DB_DataObject_Cast::dateTime();
if (!$at->insert()) {
throw new Exception(_('Failed to delete revoked token.'));
}
}
+
+ /*
+ * Create a new request token. Overrided to support OAuth 1.0a callback
+ *
+ * @param OAuthConsumer $consumer the OAuth Consumer for this token
+ * @param string $callback the verified OAuth callback URL
+ *
+ * @return OAuthToken $token a new unauthorized OAuth request token
+ */
+
+ function new_request_token($consumer, $callback)
+ {
+ $t = new Token();
+ $t->consumer_key = $consumer->key;
+ $t->tok = common_good_rand(16);
+ $t->secret = common_good_rand(16);
+ $t->type = 0; // request
+ $t->state = 0; // unauthorized
+ $t->verified_callback = $callback;
+
+ if ($callback === 'oob') {
+ // six digit pin
+ $t->verifier = mt_rand(0, 9999999);
+ } else {
+ $t->verifier = common_good_rand(8);
+ }
+
+ $t->created = DB_DataObject_Cast::dateTime();
+ if (!$t->insert()) {
+ return null;
+ } else {
+ return new OAuthToken($t->tok, $t->secret);
+ }
+ }
+
+
}
* @link http://status.net/
*
* StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
+ * Copyright (C) 2008-2010 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
exit(1);
}
-require_once INSTALLDIR.'/lib/error.php';
+require_once INSTALLDIR . '/lib/error.php';
/**
* Class for displaying HTTP client errors
$this->showPage();
}
+
+ /**
+ * To specify additional HTTP headers for the action
+ *
+ * @return void
+ */
+ function extraHeaders()
+ {
+ $status_string = @self::$status[$this->code];
+ header('HTTP/1.1 '.$this->code.' '.$status_string);
+ }
+
+ /**
+ * Page title.
+ *
+ * @return page title
+ */
+
+ function title()
+ {
+ return @self::$status[$this->code];
+ }
}
}
$menu['oauthconnectionssettings'] = array(
- // TRANS: Menu item for OAth connection settings.
+ // TRANS: Menu item for OuAth connection settings.
_m('MENU','Connections'),
- // TRANS: Tooltip for connected applications (Connections through OAth) menu item.
+ // TRANS: Tooltip for connected applications (Connections through OAuth) menu item.
_('Authorized connected applications')
);
'path' => $_path,
'logfile' => null,
'logo' => null,
+ 'ssllogo' => null,
'logdebug' => false,
'fancy' => false,
'locale_path' => INSTALLDIR.'/locale',
array('server' => null,
'dir' => INSTALLDIR . '/file/',
'path' => $_path . '/file/',
+ 'sslserver' => null,
+ 'sslpath' => null,
'ssl' => null,
'supported' => array('image/png',
'image/jpeg',
exit(1);
}
+require_once INSTALLDIR . '/lib/info.php';
+
/**
* Base class for displaying HTTP errors
*
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*/
-class ErrorAction extends Action
+class ErrorAction extends InfoAction
{
static $status = array();
function __construct($message, $code, $output='php://output', $indent=null)
{
- parent::__construct($output, $indent);
+ parent::__construct(null, $message, $output, $indent);
$this->code = $code;
$this->message = $message;
$this->prepare($_REQUEST);
}
- /**
- * To specify additional HTTP headers for the action
- *
- * @return void
- */
- function extraHeaders()
- {
- $status_string = @self::$status[$this->code];
- header('HTTP/1.1 '.$this->code.' '.$status_string);
- }
-
- /**
- * Display content.
- *
- * @return nothing
- */
- function showContent()
- {
- $this->element('div', array('class' => 'error'), $this->message);
- }
-
- /**
- * Page title.
- *
- * @return page title
- */
-
- function title()
- {
- return @self::$status[$this->code];
- }
-
- function isReadOnly($args)
- {
- return true;
- }
-
function showPage()
{
if ($this->minimal) {
exit();
}
- // Overload a bunch of stuff so the page isn't too bloated
-
- function showBody()
+ /**
+ * Display content.
+ *
+ * @return nothing
+ */
+ function showContent()
{
- $this->elementStart('body', array('id' => 'error'));
- $this->elementStart('div', array('id' => 'wrap'));
- $this->showHeader();
- $this->showCore();
- $this->showFooter();
- $this->elementEnd('div');
- $this->elementEnd('body');
+ $this->element('div', array('class' => 'error'), $this->message);
}
- function showCore()
- {
- $this->elementStart('div', array('id' => 'core'));
- $this->showContentBlock();
- $this->elementEnd('div');
- }
- function showHeader()
- {
- $this->elementStart('div', array('id' => 'header'));
- $this->showLogo();
- $this->showPrimaryNav();
- $this->elementEnd('div');
- }
}
*/
function script($src, $type='text/javascript')
{
- if(Event::handle('StartScriptElement', array($this,&$src,&$type))) {
+ if (Event::handle('StartScriptElement', array($this,&$src,&$type))) {
$url = parse_url($src);
- if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment']))
- {
+ if (empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment'])) {
+
+ // XXX: this seems like a big assumption
+
if (strpos($src, 'plugins/') === 0 || strpos($src, 'local/') === 0) {
- $src = common_path($src) . '?version=' . STATUSNET_VERSION;
+ $src = common_path($src, StatusNet::isHTTPS()) . '?version=' . STATUSNET_VERSION;
- }else{
+ } else {
- $path = common_config('javascript', 'path');
+ if (StatusNet::isHTTPS()) {
- if (empty($path)) {
- $path = common_config('site', 'path') . '/js/';
- }
+ $sslserver = common_config('javascript', 'sslserver');
- if ($path[strlen($path)-1] != '/') {
- $path .= '/';
- }
+ if (empty($sslserver)) {
+ if (is_string(common_config('site', 'sslserver')) &&
+ mb_strlen(common_config('site', 'sslserver')) > 0) {
+ $server = common_config('site', 'sslserver');
+ } else if (common_config('site', 'server')) {
+ $server = common_config('site', 'server');
+ }
+ $path = common_config('site', 'path') . '/js/';
+ } else {
+ $server = $sslserver;
+ $path = common_config('javascript', 'sslpath');
+ if (empty($path)) {
+ $path = common_config('javascript', 'path');
+ }
+ }
- if ($path[0] != '/') {
- $path = '/'.$path;
- }
+ $protocol = 'https';
- $server = common_config('javascript', 'server');
+ } else {
- if (empty($server)) {
- $server = common_config('site', 'server');
- }
+ $path = common_config('javascript', 'path');
- $ssl = common_config('javascript', 'ssl');
+ if (empty($path)) {
+ $path = common_config('site', 'path') . '/js/';
+ }
- if (is_null($ssl)) { // null -> guess
- if (common_config('site', 'ssl') == 'always' &&
- !common_config('javascript', 'server')) {
- $ssl = true;
- } else {
- $ssl = false;
+ $server = common_config('javascript', 'server');
+
+ if (empty($server)) {
+ $server = common_config('site', 'server');
}
+
+ $protocol = 'http';
}
- $protocol = ($ssl) ? 'https' : 'http';
+ if ($path[strlen($path)-1] != '/') {
+ $path .= '/';
+ }
+
+ if ($path[0] != '/') {
+ $path = '/'.$path;
+ }
$src = $protocol.'://'.$server.$path.$src . '?version=' . STATUSNET_VERSION;
}
}
$this->element('script', array('type' => $type,
- 'src' => $src),
- ' ');
+ 'src' => $src),
+ ' ');
Event::handle('EndScriptElement', array($this,$src,$type));
}
if(file_exists(Theme::file($src,$theme))){
$src = Theme::path($src, $theme);
}else{
- $src = common_path($src);
+ $src = common_path($src, StatusNet::isHTTPS());
}
$src.= '?version=' . STATUSNET_VERSION;
}
--- /dev/null
+<?php
+
+/**
+ * Information action
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, 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);
+}
+
+/**
+ * Base class for displaying dialog box like messages to the user
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see ErrorAction
+ */
+
+class InfoAction extends Action
+{
+ var $message = null;
+
+ function __construct($title, $message, $output='php://output', $indent=null)
+ {
+ parent::__construct($output, $indent);
+
+ $this->message = $message;
+ $this->title = $title;
+
+ // XXX: hack alert: usually we aren't going to
+ // call this page directly, but because it's
+ // an action it needs an args array anyway
+ $this->prepare($_REQUEST);
+ }
+
+ /**
+ * Page title.
+ *
+ * @return page title
+ */
+
+ function title()
+ {
+ return empty($this->title) ? '' : $this->title;
+ }
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ // Overload a bunch of stuff so the page isn't too bloated
+
+ function showBody()
+ {
+ $this->elementStart('body', array('id' => 'error'));
+ $this->elementStart('div', array('id' => 'wrap'));
+ $this->showHeader();
+ $this->showCore();
+ $this->showFooter();
+ $this->elementEnd('div');
+ $this->elementEnd('body');
+ }
+
+ function showCore()
+ {
+ $this->elementStart('div', array('id' => 'core'));
+ $this->showContentBlock();
+ $this->elementEnd('div');
+ }
+
+ function showHeader()
+ {
+ $this->elementStart('div', array('id' => 'header'));
+ $this->showLogo();
+ $this->showPrimaryNav();
+ $this->elementEnd('div');
+ }
+
+ /**
+ * Display content.
+ *
+ * @return nothing
+ */
+ function showContent()
+ {
+ $this->element('div', array('class' => 'info'), $this->message);
+ }
+
+}
}
}
+ function getTokenByKey($token_key)
+ {
+ $t = new Token();
+ $t->tok = $token_key;
+ if ($t->find(true)) {
+ return $t;
+ } else {
+ return null;
+ }
+ }
+
// http://oauth.net/core/1.0/#nonce
// "The Consumer SHALL then generate a Nonce value that is unique for
// all requests with that timestamp."
function add_avatar($profile, $url)
{
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
- copy($url, $temp_filename);
- $imagefile = new ImageFile($profile->id, $temp_filename);
- $filename = Avatar::filename($profile->id,
- image_type_to_extension($imagefile->type),
- null,
- common_timestamp());
- rename($temp_filename, Avatar::path($filename));
+ try {
+ copy($url, $temp_filename);
+ $imagefile = new ImageFile($profile->id, $temp_filename);
+ $filename = Avatar::filename($profile->id,
+ image_type_to_extension($imagefile->type),
+ null,
+ common_timestamp());
+ rename($temp_filename, Avatar::path($filename));
+ } catch (Exception $e) {
+ unlink($temp_filename);
+ throw $e;
+ }
return $profile->setOriginal($filename);
}
$this->showPage();
}
+
+ /**
+ * To specify additional HTTP headers for the action
+ *
+ * @return void
+ */
+ function extraHeaders()
+ {
+ $status_string = @self::$status[$this->code];
+ header('HTTP/1.1 '.$this->code.' '.$status_string);
+ }
+
+ /**
+ * Page title.
+ *
+ * @return page title
+ */
+
+ function title()
+ {
+ return @self::$status[$this->code];
+ }
+
}
* @category Exception
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
- * @copyright 2008 StatusNet, Inc.
+ * @copyright 2008-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/
*/
return $sites;
}
-
/**
* Fire initialization events for all instantiated plugins.
*/
{
return self::$is_api;
}
-
+
public function setApi($mode)
{
self::$is_api = $mode;
}
}
}
+
+ /**
+ * Are we running from the web with HTTPS?
+ *
+ * @return boolean true if we're running with HTTPS; else false
+ */
+
+ static function isHTTPS()
+ {
+ // There are some exceptions to this; add them here!
+ return $_SERVER['HTTPS'];
+ }
}
class NoConfigException extends Exception
* Themes are directories with some expected sub-directories and files
* in them. They're found in either local/theme (for locally-installed themes)
* or theme/ subdir of installation dir.
- *
+ *
* Note that the 'local' directory can be overridden as $config['local']['path']
* and $config['local']['dir'] etc.
*
/**
* Build a full URL to the given theme's base directory, possibly
* using an offsite theme server path.
- *
+ *
* @param string $group configuration section name to pull paths from
* @param string $fallbackSubdir default subdirectory under INSTALLDIR
* @param string $name theme name
- *
+ *
* @return string URL
- *
+ *
* @todo consolidate code with that for other customizable paths
*/
protected function relativeThemePath($group, $fallbackSubdir, $name)
{
- $path = common_config($group, 'path');
+ if (StatusNet::isHTTPS()) {
- if (empty($path)) {
- $path = common_config('site', 'path') . '/';
- if ($fallbackSubdir) {
- $path .= $fallbackSubdir . '/';
+ $sslserver = common_config($group, 'sslserver');
+
+ if (empty($sslserver)) {
+ if (is_string(common_config('site', 'sslserver')) &&
+ mb_strlen(common_config('site', 'sslserver')) > 0) {
+ $server = common_config('site', 'sslserver');
+ } else if (common_config('site', 'server')) {
+ $server = common_config('site', 'server');
+ }
+ $path = common_config('site', 'path') . '/';
+ if ($fallbackSubdir) {
+ $path .= $fallbackSubdir . '/';
+ }
+ } else {
+ $server = $sslserver;
+ $path = common_config($group, 'sslpath');
+ if (empty($path)) {
+ $path = common_config($group, 'path');
+ }
}
- }
- if ($path[strlen($path)-1] != '/') {
- $path .= '/';
- }
+ $protocol = 'https';
- if ($path[0] != '/') {
- $path = '/'.$path;
- }
+ } else {
- $server = common_config($group, 'server');
+ $path = common_config($group, 'path');
- if (empty($server)) {
- $server = common_config('site', 'server');
- }
+ if (empty($path)) {
+ $path = common_config('site', 'path') . '/';
+ if ($fallbackSubdir) {
+ $path .= $fallbackSubdir . '/';
+ }
+ }
- $ssl = common_config($group, 'ssl');
+ $server = common_config($group, 'server');
- if (is_null($ssl)) { // null -> guess
- if (common_config('site', 'ssl') == 'always' &&
- !common_config($group, 'server')) {
- $ssl = true;
- } else {
- $ssl = false;
+ if (empty($server)) {
+ $server = common_config('site', 'server');
}
+
+ $protocol = 'http';
}
- $protocol = ($ssl) ? 'https' : 'http';
+ if ($path[strlen($path)-1] != '/') {
+ $path .= '/';
+ }
- $path = $protocol . '://'.$server.$path.$name;
- return $path;
+ if ($path[0] != '/') {
+ $path = '/'.$path;
+ }
+
+ return $protocol.'://'.$server.$path.$name;
}
/**
/**
* Pull data from the theme's theme.ini file.
* @fixme calling getFile will fall back to default theme, this may be unsafe.
- *
+ *
* @return associative array of strings
*/
function getMetadata()
function onUserRightsCheck($profile, $right, &$result)
{
- if ($right == Right::SILENCEUSER || $right == Right::SANDBOXUSER) {
+ if ($right == Right::SILENCEUSER) {
// Hrm.... really we should confirm that the *other* user isn't privleged. :)
if ($profile->hasRole('modhelper')) {
$result = true;
}
} else {
$this->user = User::staticGet('uri', $this->uri);
+ if (empty($this->user)) {
+ // try and get it by profile url
+ $profile = Profile::staticGet('profileurl', $this->uri);
+ if (!empty($profile)) {
+ $this->user = User::staticGet('id', $profile->id);
+ }
+ }
}
+
if (!$this->user) {
$this->clientError(_m('No such user.'), 404);
return false;
// @fixme this should be better encapsulated
// ripped from oauthstore.php (for old OMB client)
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
- if (!copy($url, $temp_filename)) {
- throw new ServerException(sprintf(_m("Unable to fetch avatar from %s."), $url));
- }
+ try {
+ if (!copy($url, $temp_filename)) {
+ throw new ServerException(sprintf(_m("Unable to fetch avatar from %s."), $url));
+ }
- if ($this->isGroup()) {
- $id = $this->group_id;
- } else {
- $id = $this->profile_id;
- }
- // @fixme should we be using different ids?
- $imagefile = new ImageFile($id, $temp_filename);
- $filename = Avatar::filename($id,
- image_type_to_extension($imagefile->type),
- null,
- common_timestamp());
- rename($temp_filename, Avatar::path($filename));
+ if ($this->isGroup()) {
+ $id = $this->group_id;
+ } else {
+ $id = $this->profile_id;
+ }
+ // @fixme should we be using different ids?
+ $imagefile = new ImageFile($id, $temp_filename);
+ $filename = Avatar::filename($id,
+ image_type_to_extension($imagefile->type),
+ null,
+ common_timestamp());
+ rename($temp_filename, Avatar::path($filename));
+ } catch (Exception $e) {
+ unlink($temp_filename);
+ throw $e;
+ }
// @fixme hardcoded chmod is lame, but seems to be necessary to
// keep from accidentally saving images from command-line (queues)
// that can't be read from web server, which causes hard-to-notice
function handle()
{
- $nick = $this->user->nickname;
+ $nick = $this->user->nickname;
+ $profile = $this->user->getProfile();
if (empty($this->xrd)) {
$xrd = new XRD();
if (empty($xrd->subject)) {
$xrd->subject = Discovery::normalize($this->uri);
}
- $xrd->alias[] = $this->user->uri;
+
+ // Possible aliases for the user
+
+ $uris = array($this->user->uri, $profile->profileurl);
+
+ // FIXME: Webfinger generation code should live somewhere on its own
+
+ $path = common_config('site', 'path');
+
+ if (empty($path)) {
+ $uris[] = sprintf('acct:%s@%s', $nick, common_config('site', 'server'));
+ }
+
+ foreach ($uris as $uri) {
+ if ($uri != $xrd->subject) {
+ $xrd->alias[] = $uri;
+ }
+ }
+
$xrd->links[] = array('rel' => Discovery::PROFILEPAGE,
'type' => 'text/html',
- 'href' => $this->user->uri);
+ 'href' => $profile->profileurl);
$xrd->links[] = array('rel' => Discovery::UPDATESFROM,
'href' => common_local_url('ApiTimelineUser',
// XFN
$xrd->links[] = array('rel' => 'http://gmpg.org/xfn/11',
'type' => 'text/html',
- 'href' => $this->user->uri);
+ 'href' => $profile->profileurl);
// FOAF
$xrd->links[] = array('rel' => 'describedby',
'type' => 'application/rdf+xml',
/**
* StatusNet, the distributed open-source microblogging tool
*
- * Plugin that requires the user to have a validated email address before they can post notices
+ * Plugin that requires the user to have a validated email address before they
+ * can post notices
*
* PHP version 5
*
exit(1);
}
+/**
+ * Plugin for requiring a validated email before posting.
+ *
+ * Enable this plugin using addPlugin('RequireValidatedEmail');
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @copyright 2009-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/
+ */
+
class RequireValidatedEmailPlugin extends Plugin
{
- // Users created before this time will be grandfathered in
- // without the validation requirement.
- public $grandfatherCutoff=null;
-
- // If OpenID plugin is installed, users with a verified OpenID
- // association whose provider URL matches one of these regexes
- // will be considered to be sufficiently valid for our needs.
- //
- // For example, to trust WikiHow and Wikipedia OpenID users:
- //
- // addPlugin('RequireValidatedEmailPlugin', array(
- // 'trustedOpenIDs' => array(
- // '!^http://\w+\.wikihow\.com/!',
- // '!^http://\w+\.wikipedia\.org/!',
- // ),
- // ));
- public $trustedOpenIDs=array();
-
- function __construct()
- {
- parent::__construct();
- }
+ /**
+ * Users created before this time will be grandfathered in
+ * without the validation requirement.
+ */
+
+ public $grandfatherCutoff = null;
+
+ /**
+ * If OpenID plugin is installed, users with a verified OpenID
+ * association whose provider URL matches one of these regexes
+ * will be considered to be sufficiently valid for our needs.
+ *
+ * For example, to trust WikiHow and Wikipedia OpenID users:
+ *
+ * addPlugin('RequireValidatedEmailPlugin', array(
+ * 'trustedOpenIDs' => array(
+ * '!^http://\w+\.wikihow\.com/!',
+ * '!^http://\w+\.wikipedia\.org/!',
+ * ),
+ * ));
+ */
+
+ public $trustedOpenIDs = array();
/**
* Event handler for notice saves; rejects the notice
* if user's address isn't validated.
*
- * @param Notice $notice
+ * @param Notice $notice The notice being saved
+ *
* @return bool hook result code
*/
+
function onStartNoticeSave($notice)
{
$user = User::staticGet('id', $notice->profile_id);
if (!empty($user)) { // it's a remote notice
if (!$this->validated($user)) {
- throw new ClientException(_m("You must validate your email address before posting."));
+ $msg = _m("You must validate your email address before posting.");
+ throw new ClientException($msg);
}
}
return true;
* Event handler for registration attempts; rejects the registration
* if email field is missing.
*
- * @param RegisterAction $action
+ * @param Action $action Action being executed
+ *
* @return bool hook result code
*/
function onStartRegistrationTry($action)
* Check if a user has a validated email address or has been
* otherwise grandfathered in.
*
- * @param User $user
+ * @param User $user User to valide
+ *
* @return bool
*/
protected function validated($user)
// The email field is only stored after validation...
// Until then you'll find them in confirm_address.
$knownGood = !empty($user->email) ||
- $this->grandfathered($user) ||
- $this->hasTrustedOpenID($user);
+ $this->grandfathered($user) ||
+ $this->hasTrustedOpenID($user);
// Give other plugins a chance to override, if they can validate
// that somebody's ok despite a non-validated email.
- Event::handle('RequireValidatedEmailPlugin_Override', array($user, &$knownGood));
+
+ // FIXME: This isn't how to do it! Use Start*/End* instead
+
+ Event::handle('RequireValidatedEmailPlugin_Override',
+ array($user, &$knownGood));
return $knownGood;
}
* Check if a user was created before the grandfathering cutoff.
* If so, we won't need to check for validation.
*
- * @param User $user
- * @return bool
+ * @param User $user User to check
+ *
+ * @return bool true if user is grandfathered
*/
protected function grandfathered($user)
{
if ($this->grandfatherCutoff) {
$created = strtotime($user->created . " GMT");
- $cutoff = strtotime($this->grandfatherCutoff);
+ $cutoff = strtotime($this->grandfatherCutoff);
if ($created < $cutoff) {
return true;
}
* Override for RequireValidatedEmail plugin. If we have a user who's
* not validated an e-mail, but did come from a trusted provider,
* we'll consider them ok.
+ *
+ * @param User $user User to check
+ *
+ * @return bool true if user has a trusted OpenID.
*/
+
function hasTrustedOpenID($user)
{
if ($this->trustedOpenIDs && class_exists('User_openid')) {
foreach ($this->trustedOpenIDs as $regex) {
$oid = new User_openid();
+
$oid->user_id = $user->id;
+
$oid->find();
while ($oid->fetch()) {
if (preg_match($regex, $oid->canonical)) {
return false;
}
+ /**
+ * Add version information for this plugin.
+ *
+ * @param array &$versions Array of associative arrays of version data
+ *
+ * @return boolean hook value
+ */
+
function onPluginVersion(&$versions)
{
- $versions[] = array('name' => 'Require Validated Email',
- 'version' => STATUSNET_VERSION,
- 'author' => 'Craig Andrews, Evan Prodromou, Brion Vibber',
- 'homepage' => 'http://status.net/wiki/Plugin:RequireValidatedEmail',
- 'rawdescription' =>
- _m('The Require Validated Email plugin disables posting for accounts that do not have a validated email address.'));
+ $versions[] =
+ array('name' => 'Require Validated Email',
+ 'version' => STATUSNET_VERSION,
+ 'author' => 'Craig Andrews, '.
+ 'Evan Prodromou, '.
+ 'Brion Vibber',
+ 'homepage' =>
+ 'http://status.net/wiki/Plugin:RequireValidatedEmail',
+ 'rawdescription' =>
+ _m('Disables posting without a validated email address.'));
+ return true;
+ }
+
+ /**
+ * Hide the notice form if the user isn't able to post.
+ *
+ * @param Action $action action being shown
+ *
+ * @return boolean hook value
+ */
+
+ function onStartShowNoticeForm($action)
+ {
+ $user = common_current_user();
+ if (!empty($user)) { // it's a remote notice
+ if (!$this->validated($user)) {
+ return false;
+ }
+ }
return true;
}
}
// @fixme this should be better encapsulated
// ripped from OStatus via oauthstore.php (for old OMB client)
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
- if (!copy($url, $temp_filename)) {
- throw new ServerException(sprintf(_m("Unable to fetch avatar from %s."), $url));
- }
-
- $profile = $user->getProfile();
- $id = $profile->id;
- // @fixme should we be using different ids?
+ try {
+ if (!copy($url, $temp_filename)) {
+ throw new ServerException(sprintf(_m("Unable to fetch avatar from %s."), $url));
+ }
- $imagefile = new ImageFile($id, $temp_filename);
- $filename = Avatar::filename($id,
- image_type_to_extension($imagefile->type),
- null,
- common_timestamp());
- rename($temp_filename, Avatar::path($filename));
+ $profile = $user->getProfile();
+ $id = $profile->id;
+ // @fixme should we be using different ids?
+
+ $imagefile = new ImageFile($id, $temp_filename);
+ $filename = Avatar::filename($id,
+ image_type_to_extension($imagefile->type),
+ null,
+ common_timestamp());
+ rename($temp_filename, Avatar::path($filename));
+ } catch (Exception $e) {
+ unlink($temp_filename);
+ throw $e;
+ }
$profile->setOriginal($filename);
}
}
// @fixme this should be better encapsulated
// ripped from oauthstore.php (for old OMB client)
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
- if (!copy($url, $temp_filename)) {
- throw new ServerException(sprintf(_m("Unable to fetch avatar from %s."), $url));
- }
+ try {
+ if (!copy($url, $temp_filename)) {
+ throw new ServerException(sprintf(_m("Unable to fetch avatar from %s."), $url));
+ }
- $id = $dest->id;
- // @fixme should we be using different ids?
- $imagefile = new ImageFile($id, $temp_filename);
- $filename = Avatar::filename($id,
- image_type_to_extension($imagefile->type),
- null,
- common_timestamp());
- rename($temp_filename, Avatar::path($filename));
+ $id = $dest->id;
+ // @fixme should we be using different ids?
+ $imagefile = new ImageFile($id, $temp_filename);
+ $filename = Avatar::filename($id,
+ image_type_to_extension($imagefile->type),
+ null,
+ common_timestamp());
+ rename($temp_filename, Avatar::path($filename));
+ } catch (Exception $e) {
+ unlink($temp_filename);
+ throw $e;
+ }
// @fixme hardcoded chmod is lame, but seems to be necessary to
// keep from accidentally saving images from command-line (queues)
// that can't be read from web server, which causes hard-to-notice
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.
+These instructions assume you understand the basics of how OAuth
+works. You may want to read up about it first. Here are some good
+resources for learning about OAuth:
-Put your instance info and consumer key and secret in oauth.ini
+ http://hueniverse.com/oauth/
+ http://tools.ietf.org/html/rfc5849
-Example usage:
---------------
+To use these scripts (and OAuth in general) first you will need to
+register and OAuth client application with your StatusNet instance:
-php getrequesttoken.php
+ http://example.status.net/settings/oauthapps
-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...
+oauth.ini
+---------
-php exchangetokens.php --oauth_token=b9a79548a88c1aa9a5bea73103c6d41d --token_secret=4a47d9337fc0202a14ab552e17a3b657
+Using oauth.ini.sample as a guide, put your StatusNet OAuth endpoints
+and consumer key and secret in a file called oauth.ini and save it
+in the same directory as these scripts.
-Once you have your access token, go ahead and try a protected API
-resource:
+fetch_temp_creds.php
+--------------------
-php verifycreds.php --oauth_token=cf2de7665f0dda0a82c2dc39b01be7f9 --token_secret=4524c3b712200138e1a4cff2e9ca83d8
+Will fetch a request token, token secret and a URL to authorize the
+token. Once you authorize the request token, you can exchange it
+for an access token.
+
+example usage:
+
+ $ php fetch_temp_creds.php
+ Request Token
+ - oauth_token = 89d481e376edc622f08da5791e6a4446
+ - oauth_token_secret = 6d028bcd1ea125cbed7da2f254219885
+ Authorize URL
+ http://example.status.net/api/oauth/authorize?oauth_token=89d481e376edc622f08da5791e6a4446
+
+ Now paste the Authorize URL into your browser and authorize your temporary credentials.
+
+fetch_token_creds.php
+---------------------
+
+After you have authorized your request token, you will be presented
+with a verifier code, or pin, in your browser, which you will need
+to get an access token. Make sure you copy it into a text buffer
+or write it down or something. Then call fetch_token_credentials.php
+to exchange your temporary credentials for real token credentials.
+
+example usage:
+
+ $ php fetch_token_creds.php -t 89d481e376edc622f08da5791e6a4446 -s 6d028bcd1ea125cbed7da2f254219885 -v 305162
+ Access Token
+ - oauth_token = 9b354df102d8e2b4621122c85d8d045c
+ - oauth_token_secret = 1800a88f1574b47d595214a74e5b1ec5
+
+
+oauth_verify_credentials.php
+----------------------------
+
+Now you should have real token credentials (an OAuth access token)
+and you can access protected API resources. This is an example
+script that calls /api/account/verify_credentials.xml.
+
+example usage:
+
+ $ php oauth_verify_creds.php -t 80305cd15c5c69834364ac02d7f9178c -s 673e3b2978b1b92c8edbfe172505fee1
+ <?xml version="1.0" encoding="UTF-8"?>
+ <user xmlns:statusnet="http://status.net/schema/api/1/">
+ <id>23</id>
+ <name>zach</name>
+ <screen_name>zach</screen_name>
+ <location></location>
+ <description></description>
+ <profile_image_url>http://example.status.net/theme/default/default-avatar-stream.png</profile_image_url>
+ <url></url>
+ <protected>false</protected>
+ <followers_count>0</followers_count>
+ <profile_background_color></profile_background_color>
+ <profile_text_color></profile_text_color>
+ <profile_link_color></profile_link_color>
+ <profile_sidebar_fill_color></profile_sidebar_fill_color>
+ <profile_sidebar_border_color></profile_sidebar_border_color>
+ <friends_count>0</friends_count>
+ <created_at>Thu Sep 30 23:11:00 +0000 2010</created_at>
+ <favourites_count>0</favourites_count>
+ <utc_offset>0</utc_offset>
+ <time_zone>UTC</time_zone>
+ <profile_background_image_url></profile_background_image_url>
+ <profile_background_tile>false</profile_background_tile>
+ <statuses_count>4</statuses_count>
+ <following>true</following>
+ <statusnet:blocking>false</statusnet:blocking>
+ <notifications>true</notifications>
+ <status>
+ <text>gar</text>
+ <truncated>false</truncated>
+ <created_at>Wed Oct 06 23:40:14 +0000 2010</created_at>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <source>web</source>
+ <id>7</id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <in_reply_to_screen_name></in_reply_to_screen_name>
+ <geo></geo>
+ <favorited>false</favorited>
+ <statusnet:html>gar</statusnet:html>
+ </status>
+ <statusnet:profile_url>http://example.status.net/statusnet/zach</statusnet:profile_url>
+ </user>
+
+oauth_post_notice.php
+---------------------
+
+This is another test script that lets you post a notice via OAuth.
+
+example usage:
+
+ $ php oauth_post_notice.php -t 80305cd15c5c69834364ac02d7f9178c -s 673e3b2978b1b92c8edbfe172505fee1 -u 'Test test test...'
+ <?xml version="1.0" encoding="UTF-8"?>
+ <status xmlns:statusnet="http://status.net/schema/api/1/">
+ <text>Test test test...</text>
+ <truncated>false</truncated>
+ <created_at>Fri Oct 08 02:37:35 +0000 2010</created_at>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <source><a href="http://banana.com" rel="nofollow">Banana</a></source>
+ <id>8</id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <in_reply_to_screen_name></in_reply_to_screen_name>
+ <geo></geo>
+ <favorited>false</favorited>
+ <user>
+ <id>23</id>
+ <name>zach</name>
+ <screen_name>zach</screen_name>
+ <location></location>
+ <description></description>
+ <profile_image_url>http://example.status.net/statusnet/theme/default/default-avatar-stream.png</profile_image_url>
+ <url></url>
+ <protected>false</protected>
+ <followers_count>0</followers_count>
+ <profile_background_color></profile_background_color>
+ <profile_text_color></profile_text_color>
+ <profile_link_color></profile_link_color>
+ <profile_sidebar_fill_color></profile_sidebar_fill_color>
+ <profile_sidebar_border_color></profile_sidebar_border_color>
+ <friends_count>0</friends_count>
+ <created_at>Thu Sep 30 23:11:00 +0000 2010</created_at>
+ <favourites_count>0</favourites_count>
+ <utc_offset>0</utc_offset>
+ <time_zone>UTC</time_zone>
+ <profile_background_image_url></profile_background_image_url>
+ <profile_background_tile>false</profile_background_tile>
+ <statuses_count>5</statuses_count>
+ <following>true</following>
+ <statusnet:blocking>false</statusnet:blocking>
+ <notifications>true</notifications>
+ <statusnet:profile_url>http://example.status.net/statusnet/zach</statusnet:profile_url>
+ </user>
+ <statusnet:html>Test test test...</statusnet:html>
+ </status>
+++ /dev/null
-#!/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);
-}
-
--- /dev/null
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2010, 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");
+
+// Check to make sure we have everything we need from the ini file
+foreach(array('consumer_key', 'consumer_secret', 'apiroot', 'request_token_url') as $inikey) {
+ if (empty($ini[$inikey])) {
+ print "You forgot to specify a $inikey in your oauth.ini file.\n";
+ exit(1);
+ }
+}
+
+$consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
+$endpoint = $ini['apiroot'] . $ini['request_token_url'];
+$parsed = parse_url($endpoint);
+$params = array();
+
+parse_str($parsed['query'], $params);
+$params['oauth_callback'] = 'oob'; // out-of-band
+
+$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
+
+try {
+ $req = OAuthRequest::from_consumer_and_token(
+ $consumer,
+ null,
+ "POST",
+ $endpoint,
+ $params
+ );
+ $req->sign_request($hmac_method, $consumer, NULL);
+ $r = httpRequest($endpoint, $req->to_postdata());
+} catch (Exception $e) {
+ // oh noez
+ print $e->getMessage();
+ print "\nOAuth Request:\n";
+ var_dump($req);
+ exit(1);
+}
+
+$body = $r->getBody();
+$tokenStuff = array();
+
+parse_str($body, $tokenStuff);
+
+$tok = $tokenStuff['oauth_token'];
+$confirmed = $tokenStuff['oauth_callback_confirmed'];
+
+if (empty($tokenStuff['oauth_token'])
+ || empty($tokenStuff['oauth_token_secret'])
+ || empty($confirmed)
+ || $confirmed != 'true')
+{
+ print "Error! HTTP response body: $body\n";
+ exit(1);
+}
+
+$authurl = $ini['apiroot'] . $ini['authorize_url'] . '?oauth_token=' . $tok;
+
+print "Request Token\n";
+print ' - oauth_token = ' . $tokenStuff['oauth_token'] . "\n";
+print ' - oauth_token_secret = ' . $tokenStuff['oauth_token_secret'] . "\n";
+print "Authorize URL\n $authurl\n\n";
+print "Now paste the Authorize URL into your browser and authorize your temporary credentials.\n";
+
+function httpRequest($endpoint, $poststr)
+{
+ $request = HTTPClient::start();
+
+ $request->setConfig(
+ array(
+ 'follow_redirects' => true,
+ 'connect_timeout' => 120,
+ 'timeout' => 120,
+ 'ssl_verify_peer' => false,
+ 'ssl_verify_host' => false
+ )
+ );
+
+ // Turn signed request query string back into an array
+ parse_str($poststr, $postdata);
+ return $request->post($endpoint, null, $postdata);
+}
--- /dev/null
+#!/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");
+
+// Check to make sure we have everything we need from the ini file
+foreach(array('consumer_key', 'consumer_secret', 'apiroot', 'access_token_url') as $inikey) {
+ if (empty($ini[$inikey])) {
+ print "You forgot to specify a $inikey in your oauth.ini file.\n";
+ exit(1);
+ }
+}
+
+$consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
+
+$endpoint = $ini['apiroot'] . $ini['access_token_url'];
+
+$shortoptions = 't:s:v:';
+$longoptions = array('oauth_token=', 'oauth_token_secret=', 'oauth_verifier=');
+
+$helptext = <<<END_OF_ETOKENS_HELP
+ fetch_token_creds.php [options]
+
+ Exchange authorized OAuth temporary credentials for token credentials
+ (an authorized request token for an access token)
+
+ -t --oauth_token authorized request token
+ -s --oauth_token_secret authorized request token secret
+ -v --oauth_verifier authorized request token verifier
+
+
+END_OF_ETOKENS_HELP;
+
+require_once INSTALLDIR . '/scripts/commandline.inc';
+
+$token = $secret = $verifier = null;
+
+if (have_option('t', 'oauth_token')) {
+ $token = get_option_value('t', 'oauth_token');
+}
+
+if (have_option('s', 'oauth_token_secret')) {
+ $secret = get_option_value('s', 'oauth_token_secret');
+}
+
+if (have_option('v', 'oauth_verifier')) {
+ $verifier = get_option_value('v', 'oauth_verifier');
+}
+
+if (empty($token)) {
+ print "Please specify the request token (--help for help).\n";
+ exit(1);
+}
+
+if (empty($secret)) {
+ print "Please specify the request token secret (--help for help).\n";
+ exit(1);
+}
+
+if (empty($verifier)) {
+ print "Please specify the request token verifier (--help for help).\n";
+ exit(1);
+}
+
+$rtok = new OAuthToken($token, $secret);
+$parsed = parse_url($endpoint);
+parse_str($parsed['query'], $params);
+
+$params['oauth_verifier'] = $verifier; // 1.0a
+
+$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
+
+try {
+
+ $oauthReq = OAuthRequest::from_consumer_and_token(
+ $consumer,
+ $rtok,
+ "POST",
+ $endpoint,
+ $params
+ );
+
+ $oauthReq->sign_request($hmac_method, $consumer, $rtok);
+
+ $httpReq = httpRequest($endpoint, $oauthReq->to_postdata());
+ $body = $httpReq->getBody();
+
+} catch (Exception $e) {
+ // oh noez
+ print $e->getMessage();
+ print "\nOAuth Request:\n";
+ var_dump($oauthReq);
+ exit(1);
+}
+
+$tokenStuff = array();
+parse_str($body, $tokenStuff);
+
+if (empty($tokenStuff['oauth_token']) || empty($tokenStuff['oauth_token_secret'])) {
+ print "Error! HTTP response body: $body\n";
+ exit(1);
+}
+
+print "Access Token\n";
+print ' - oauth_token = ' . $tokenStuff['oauth_token'] . "\n";
+print ' - oauth_token_secret = ' . $tokenStuff['oauth_token_secret'] . "\n";
+
+function httpRequest($endpoint, $poststr)
+{
+ $request = HTTPClient::start();
+
+ $request->setConfig(
+ array(
+ 'follow_redirects' => true,
+ 'connect_timeout' => 120,
+ 'timeout' => 120,
+ 'ssl_verify_peer' => false,
+ 'ssl_verify_host' => false
+ )
+ );
+
+ parse_str($poststr, $postdata);
+ return $request->post($endpoint, null, $postdata);
+}
+
+++ /dev/null
-#!/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);
-}
-
+++ /dev/null
-; 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"
-
--- /dev/null
+; Setup OAuth info here
+apiroot = "https://YOURSTATUSNET/api"
+
+request_token_url = "/oauth/request_token"
+authorize_url = "/oauth/authorize"
+access_token_url = "/oauth/access_token"
+
+consumer_key = "b748968e9bea81a53f3a3c15aa0c686f"
+consumer_secret = "5434e18cce05d9e53cdd48029a62fa41"
+
--- /dev/null
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2010, 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 = 't:s:u:';
+$longoptions = array('oauth_token=', 'token_secret=', 'update=');
+
+$helptext = <<<END_OF_VERIFY_HELP
+ oauth_post_notice.php [options]
+ Update your status via OAuth
+
+ -t --oauth_token access token
+ -s --oauth_token_secret access token secret
+ -u --update status update
+
+
+END_OF_VERIFY_HELP;
+
+$token = null;
+$token_secret = null;
+$update = null;
+
+require_once INSTALLDIR . '/scripts/commandline.inc';
+
+if (have_option('t', 'oauth_token')) {
+ $token = get_option_value('t', 'oauth_token');
+}
+
+if (have_option('s', 'oauth_token_secret')) {
+ $token_secret = get_option_value('s', 'oauth_token_secret');
+}
+
+if (have_option('u', 'update')) {
+ $update = get_option_value('u', 'update');
+}
+
+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);
+}
+
+if (empty($update)) {
+ print "You forgot to update your status!\n";
+ exit(1);
+}
+
+$ini = parse_ini_file("oauth.ini");
+$consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
+$endpoint = $ini['apiroot'] . '/statuses/update.xml';
+
+$atok = new OAuthToken($token, $token_secret);
+
+$parsed = parse_url($endpoint);
+parse_str($parsed['query'], $params);
+
+$params['status'] = $update;
+
+$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
+
+try {
+
+ $oauthReq = OAuthRequest::from_consumer_and_token(
+ $consumer,
+ $atok,
+ 'POST',
+ $endpoint,
+ $params
+ );
+
+ $oauthReq->sign_request($hmac_method, $consumer, $atok);
+
+ $httpReq = httpRequest($endpoint, $oauthReq->to_postdata());
+
+ print $httpReq->getBody();
+
+} catch (Exception $e) {
+ print "Error! . $e->getMessage() . 'HTTP reponse body: " . $httpReq->getBody();
+ exit(1);
+}
+
+function httpRequest($endpoint, $poststr)
+{
+ $request = HTTPClient::start();
+
+ $request->setConfig(
+ array(
+ 'follow_redirects' => true,
+ 'connect_timeout' => 120,
+ 'timeout' => 120,
+ 'ssl_verify_peer' => false,
+ 'ssl_verify_host' => false
+ )
+ );
+
+ // Turn signed request query string back into an array
+ parse_str($poststr, $postdata);
+ return $request->post($endpoint, null, $postdata);
+}
+
--- /dev/null
+#!/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 = 't:s:';
+$longoptions = array('oauth_token=', 'oauth_token_secret=');
+
+$helptext = <<<END_OF_VERIFY_HELP
+ oauth_verify_creds.php [options]
+ Access /api/account/verify_credentials.xml with OAuth
+
+ -t --oauth_token access token
+ -s --oauth_token_secret access token secret
+
+END_OF_VERIFY_HELP;
+
+$token = null;
+$token_secret = null;
+
+require_once INSTALLDIR . '/scripts/commandline.inc';
+
+if (have_option('t', 'oauth_token')) {
+ $token = get_option_value('t', 'oauth_token');
+}
+
+if (have_option('s', 'token_secret')) {
+ $token_secret = get_option_value('s', 'oauth_token_secret');
+}
+
+if (empty($token)) {
+ print "Please specify an access token (--help for help).\n";
+ exit(1);
+}
+
+if (empty($token_secret)) {
+ print "Please specify an access token secret (--help for help).\n";
+ exit(1);
+}
+
+$ini = parse_ini_file("oauth.ini");
+$consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
+$endpoint = $ini['apiroot'] . '/account/verify_credentials.xml';
+
+$atok = new OAuthToken($token, $token_secret);
+$parsed = parse_url($endpoint);
+
+parse_str($parsed['query'], $params);
+
+try {
+
+ $hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
+
+ $oauthReq = OAuthRequest::from_consumer_and_token(
+ $consumer,
+ $atok,
+ "GET",
+ $endpoint,
+ $params
+ );
+
+ $oauthReq->sign_request($hmac_method, $consumer, $atok);
+
+ $httpReq = httpRequest($oauthReq->to_url());
+
+} catch (Exception $e) {
+ print "Error! HTTP response body: " . $httpReq->getBody();
+ exit(1);
+}
+
+print $httpReq->getBody();
+
+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);
+}
+++ /dev/null
-#!/usr/bin/env php
-<?php
-/*
- * StatusNet - a distributed open-source microblogging tool
- * Copyright (C) 2010, 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:u:';
-$longoptions = array('oauth_token=', 'token_secret=', 'update=');
-
-$helptext = <<<END_OF_VERIFY_HELP
- statusupdate.php [options]
- Update your status using OAuth
-
- -o --oauth_token access token
- -s --token_secret access token secret
- -u --update status update
-
-
-END_OF_VERIFY_HELP;
-
-$token = null;
-$token_secret = null;
-$update = 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 (have_option('u', 'update')) {
- $update = get_option_value('u', 'update');
-}
-
-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);
-}
-
-if (empty($update)) {
- print "You forgot to update your status!\n";
- exit(1);
-}
-
-$ini = parse_ini_file("oauth.ini");
-
-$test_consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
-
-$endpoint = $ini['apiroot'] . '/statuses/update.xml';
-
-print "$endpoint\n";
-
-$at = new OAuthToken($token, $token_secret);
-
-$parsed = parse_url($endpoint);
-$params = array();
-parse_str($parsed['query'], $params);
-
-$params['status'] = $update;
-
-$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
-
-$req_req = OAuthRequest::from_consumer_and_token($test_consumer, $at, 'POST', $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->post($url);
-}
-
+++ /dev/null
-#!/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);
-}
-