We are no longer offering accounts on this server. Consider https://gitlab.freedesktop.org/ as a place to host projects.

Commit 53d45d7f authored by Brion Vibber's avatar Brion Vibber

Merge branch '0.9.x'

parents 9a35e48e 39cfdf0d
......@@ -1136,3 +1136,9 @@ StartShowFeedLink: before showing an individual feed item
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
......@@ -2,8 +2,8 @@
README
------
StatusNet 0.9.5 "What's The Frequency, Kenneth?"
10 September 2010
StatusNet 0.9.6 "Man on the Moon"
19 October 2010
This is the README file for StatusNet, the Open Source microblogging
platform. It includes installation instructions, descriptions of
......@@ -96,8 +96,8 @@ for additional terms.
New this version
================
This is a security, bug and feature release since version 0.9.4 released on
16 August 2010.
This is a security, bug and feature release since version 0.9.5 released on
10 September 2010.
For best compatibility with client software and site federation, and a lot of
bug fixes, it is highly recommended that all public sites upgrade to the new
......@@ -105,24 +105,24 @@ version.
Notable changes this version:
- Change of license for default themes and documentation from
AGPLv3 to CC-By 3.0 Unported.
- An experimental TinyMCE plugin to do in-browser rich editing of
status updates. Does not support StatusNet syntax like @-replies or
#hashtags very well.
- An experimental plugin to add titles to notices.
- A plugin to support the Echo <http://aboutecho.com/> commenting
system.
- A plugin to support the Disqus <http://disqus.com/> commenting system.
- Changes to OStatus support to make StatusNet work for the Social Web
Acid Test Level 0 <http://federatedsocialweb.net/wiki/SWAT0>.
- Themes now support a theme.ini file for theme configuration, including
defining a "base" theme.
- Improved two-way Twitter integration, including support for
repeats and retweets, replies, and faves going both ways across the
bridge, as well as better parsing of Twitter statuses.
A full changelog is available at http://status.net/wiki/StatusNet_0.9.5.
- Site moderators can now delete groups.
- New themes: clean, shiny, mnml, victorian
- New YammerImport plugin allows site admins to import non-private profiles and
message from an authenticated Yammer site.
- New experimental plugins: AnonFavorites, SlicedFavorites, GroupFavorited,
ForceGroup, ShareNotice
- OAuth upgraded to 1.0a
- Localization updates now include plugins, thanks to TranslateWiki.net!
- SSL link generation should be more consistent; alternate SSL URLs can be
set in the admin UI for more parts of the system.
- Experimental backupuser.php, restoreuser.php command-line scripts to
dump/restore a user's complete activity stream. Can be used to transfer
accounts manually between sites, or to save a backup before deleting.
- Unicode fixes for OStatus notices
- Header metadata on notice pages to aid in manual reposting on Facebook
- Lots of little fixes...
A full changelog is available at http://status.net/wiki/StatusNet_0.9.6.
Prerequisites
=============
......@@ -235,9 +235,9 @@ especially if you've previously installed PHP/MySQL packages.
1. Unpack the tarball you downloaded on your Web server. Usually a
command like this will work:
tar zxf statusnet-0.9.5.tar.gz
tar zxf statusnet-0.9.6.tar.gz
...which will make a statusnet-0.9.5 subdirectory in your current
...which will make a statusnet-0.9.6 subdirectory in your current
directory. (If you don't have shell access on your Web server, you
may have to unpack the tarball on your local computer and FTP the
files to the server.)
......@@ -245,7 +245,7 @@ especially if you've previously installed PHP/MySQL packages.
2. Move the tarball to a directory of your choosing in your Web root
directory. Usually something like this will work:
mv statusnet-0.9.5 /var/www/statusnet
mv statusnet-0.9.6 /var/www/statusnet
This will make your StatusNet instance available in the statusnet path of
your server, like "http://example.net/statusnet". "microblog" or
......@@ -660,7 +660,7 @@ with this situation.
If you've been using StatusNet 0.7, 0.6, 0.5 or lower, or if you've
been tracking the "git" version of the software, you will probably
want to upgrade and keep your existing data. There is no automated
upgrade procedure in StatusNet 0.9.5. Try these step-by-step
upgrade procedure in StatusNet 0.9.6. Try these step-by-step
instructions; read to the end first before trying them.
0. Download StatusNet and set up all the prerequisites as if you were
......@@ -681,10 +681,11 @@ instructions; read to the end first before trying them.
5. Once all writing processes to your site are turned off, make a
final backup of the Web directory and database.
6. Move your StatusNet directory to a backup spot, like "statusnet.bak".
7. Unpack your StatusNet 0.9.5 tarball and move it to "statusnet" or
7. Unpack your StatusNet 0.9.6 tarball and move it to "statusnet" or
wherever your code used to be.
8. Copy the config.php file and avatar directory from your old
directory to your new directory.
8. Copy the config.php file and the contents of the avatar/, background/,
file/, and local/ subdirectories from your old directory to your new
directory.
9. Copy htaccess.sample to .htaccess in the new directory. Change the
RewriteBase to use the correct path.
10. Rebuild the database. (You can safely skip this step and go to #12
......@@ -852,6 +853,8 @@ notice: A plain string that will appear on every page. A good place
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
......@@ -1111,6 +1114,9 @@ path: Path part of theme URLs, before the theme name. Relative to the
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
----------
......@@ -1122,6 +1128,9 @@ path: Path part of Javascript URLs. Defaults to null,
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
----
......@@ -1349,6 +1358,11 @@ ssl: whether to use HTTPS for file URLs. Defaults to null, meaning to
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
-----
......@@ -1405,8 +1419,9 @@ dir: directory to write backgrounds too. Default is '/background/'
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
----
......@@ -1487,6 +1502,33 @@ disallow: Array of (virtual) directories to disallow. Default is 'main',
'search', 'message', 'settings', 'admin'. Ignored when site
is private, in which case the entire site ('/') is disallowed.
api
---
Options for the Twitter-like API.
realm: HTTP Basic Auth realm (see http://tools.ietf.org/html/rfc2617
for details). Some third-party tools like ping.fm want this to be
'Identi.ca API', so set it to that if you want to. default = null,
meaning 'something based on the site name'.
nofollow
--------
We optionally put 'rel="nofollow"' on some links in some pages. The
following configuration settings let you fine-tune how or when things
are nofollowed. See http://en.wikipedia.org/wiki/Nofollow for more
information on what 'nofollow' means.
subscribers: whether to nofollow links to subscribers on the profile
and personal pages. Default is true.
members: links to members on the group page. Default true.
peopletag: links to people listed in the peopletag page. Default true.
external: external links in notices. One of three values: 'sometimes',
'always', 'never'. If 'sometimes', then external links are not
nofollowed on profile, notice, and favorites page. Default is
'sometimes'.
Plugins
=======
......@@ -1544,7 +1586,7 @@ repository (see below), and you get a compilation error ("unexpected
T_STRING") in the browser, check to see that you don't have any
conflicts in your code.
If you upgraded to StatusNet 0.9.5 without reading the "Notice
If you upgraded to StatusNet 0.9.x without reading the "Notice
inboxes" section above, and all your users' 'Personal' tabs are empty,
read the "Notice inboxes" section above.
......@@ -1655,6 +1697,10 @@ if anyone's been overlooked in error.
* mEDI
* Brett Taylor
* Brigitte Schuster
* Siebrand Mazeland and the amazing volunteer translators at TranslateWiki.net
* Brion Vibber, StatusNet, Inc.
* James Walker, StatusNet, Inc.
* Samantha Doherty, designer, StatusNet, Inc.
Thanks also to the developers of our upstream library code and to the
thousands of people who have tried out Identi.ca, installed StatusNet,
......
......@@ -74,6 +74,7 @@ class ApiDirectMessageAction extends ApiAuthAction
$this->user = $this->auth_user;
if (empty($this->user)) {
// TRANS: Client error given when a user was not found (404).
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
......@@ -86,10 +87,12 @@ class ApiDirectMessageAction extends ApiAuthAction
// Action was called by /api/direct_messages/sent.format
$this->title = sprintf(
// TRANS: %s is a user nickname.
_("Direct messages from %s"),
$this->user->nickname
);
$this->subtitle = sprintf(
// TRANS: %s is a user nickname.
_("All the direct messages sent from %s"),
$this->user->nickname
);
......@@ -98,10 +101,12 @@ class ApiDirectMessageAction extends ApiAuthAction
$this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id;
} else {
$this->title = sprintf(
// TRANS: %s is a user nickname.
_("Direct messages to %s"),
$this->user->nickname
);
$this->subtitle = sprintf(
// TRANS: %s is a user nickname.
_("All the direct messages sent to %s"),
$this->user->nickname
);
......@@ -153,6 +158,7 @@ class ApiDirectMessageAction extends ApiAuthAction
$this->showJsonDirectMessages();
break;
default:
// TRANS: Client error given when an API method was not found (404).
$this->clientError(_('API method not found.'), $code = 404);
break;
}
......
......@@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiDirectMessageNewAction extends ApiAuthAction
{
var $other = null;
......@@ -63,7 +62,6 @@ class ApiDirectMessageNewAction extends ApiAuthAction
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
......@@ -99,7 +97,6 @@ class ApiDirectMessageNewAction extends ApiAuthAction
*
* @return void
*/
function handle($args)
{
parent::handle($args);
......@@ -116,6 +113,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction
if (empty($this->content)) {
$this->clientError(
// TRANS: Client error (406).
_('No message text!'),
406,
$this->format
......@@ -123,9 +121,10 @@ class ApiDirectMessageNewAction extends ApiAuthAction
} else {
$content_shortened = common_shorten_links($this->content);
if (Message::contentTooLong($content_shortened)) {
// TRANS: Client error displayed when message content is too long.
// TRANS: %d is the maximum number of characters for a message.
$this->clientError(
sprintf(
_('That\'s too long. Max message size is %d chars.'),
sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()),
Message::maxContent()
),
406,
......@@ -136,10 +135,12 @@ class ApiDirectMessageNewAction extends ApiAuthAction
}
if (empty($this->other)) {
// TRANS: Client error displayed if a recipient user could not be found (403).
$this->clientError(_('Recipient user not found.'), 403, $this->format);
return;
} else if (!$this->user->mutuallySubscribed($this->other)) {
$this->clientError(
// TRANS: Client error displayed trying to direct message another user who's not a friend (403).
_('Can\'t send direct messages to users who aren\'t your friend.'),
403,
$this->format
......@@ -149,10 +150,9 @@ class ApiDirectMessageNewAction extends ApiAuthAction
// Note: sending msgs to yourself is allowed by Twitter
$errmsg = 'Don\'t send a message to yourself; ' .
'just say it to yourself quietly instead.';
$this->clientError(_($errmsg), 403, $this->format);
// TRANS: Client error displayed trying to direct message self (403).
$this->clientError(_('Do not send a message to yourself; ' .
'just say it to yourself quietly instead.'), 403, $this->format);
return;
}
......@@ -176,6 +176,4 @@ class ApiDirectMessageNewAction extends ApiAuthAction
$this->showSingleJsondirectMessage($message);
}
}
}
......@@ -2,7 +2,8 @@
/**
* 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
*
......@@ -34,7 +35,8 @@ if (!defined('STATUSNET')) {
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
......@@ -45,6 +47,8 @@ require_once INSTALLDIR . '/lib/apioauth.php';
class ApiOauthAccessTokenAction extends ApiOauthAction
{
protected $reqToken = null;
protected $verifier = null;
/**
* Class handler.
......@@ -65,30 +69,58 @@ class ApiOauthAccessTokenAction extends ApiOauthAction
$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;
}
}
......@@ -32,6 +32,7 @@ if (!defined('STATUSNET')) {
}
require_once INSTALLDIR . '/lib/apioauth.php';
require_once INSTALLDIR . '/lib/info.php';
/**
* Authorize an OAuth request token
......@@ -43,9 +44,10 @@ require_once INSTALLDIR . '/lib/apioauth.php';
* @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;
......@@ -67,12 +69,17 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
{
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;
}
......@@ -97,14 +104,30 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
} 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;
......@@ -120,8 +143,8 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
$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;
}
......@@ -130,6 +153,11 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
$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!"));
......@@ -141,9 +169,15 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
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
......@@ -156,8 +190,7 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
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.'));
}
}
......@@ -175,20 +208,19 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
// 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)) {
......@@ -197,40 +229,40 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
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');