From 3f74f446033aaa1c0e7a1d6965f7558ad2c1cbf4 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 14 Oct 2010 16:25:43 -0700 Subject: [PATCH 01/13] Fix for ticket #2828: apostrophe in site name set in installer created a broken config.php. Now running values through var_export() before putting them into the config.php, ensuring strings will be properly quoted. --- lib/installer.php | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/installer.php b/lib/installer.php index c046eadea3..a9d8090110 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -391,6 +391,30 @@ abstract class Installer return $db; } + /** + * Return a parseable PHP literal for the given value. + * This will include quotes for strings, etc. + * + * @param mixed $val + * @return string + */ + function phpVal($val) + { + return var_export($val, true); + } + + /** + * Return an array of parseable PHP literal for the given values. + * These will include quotes for strings, etc. + * + * @param mixed $val + * @return array + */ + function phpVals($map) + { + return array_map(array($this, 'phpVal'), $map); + } + /** * Write a stock configuration file. * @@ -400,24 +424,32 @@ abstract class Installer */ function writeConf() { + $vals = $this->phpVals(array( + 'sitename' => $this->sitename, + 'server' => $this->server, + 'path' => $this->path, + 'db_database' => $this->db['database'], + 'db_type' => $this->db['type'], + )); + // assemble configuration file in a string $cfg = "sitename}';\n\n". + "\$config['site']['name'] = {$vals['sitename']};\n\n". // site location - "\$config['site']['server'] = '{$this->server}';\n". - "\$config['site']['path'] = '{$this->path}'; \n\n". + "\$config['site']['server'] = {$vals['server']};\n". + "\$config['site']['path'] = {$vals['path']}; \n\n". // checks if fancy URLs are enabled ($this->fancy ? "\$config['site']['fancy'] = true;\n\n":''). // database - "\$config['db']['database'] = '{$this->db['database']}';\n\n". + "\$config['db']['database'] = {$vals['db_database']};\n\n". ($this->db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":''). - "\$config['db']['type'] = '{$this->db['type']}';\n\n"; + "\$config['db']['type'] = {$vals['db_type']};\n\n"; // Normalize line endings for Windows servers $cfg = str_replace("\n", PHP_EOL, $cfg); From 56403c4beb939b71bf4412746eeaf6419afd7fea Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 14 Oct 2010 16:47:56 -0700 Subject: [PATCH 02/13] Fix for ticket #2828, part II: apostrophe in site name set in installer created a broken config.php. The previous commit fixed the base installer to properly quote its strings when creating config.php... but you'd actually end up with double-escaping if you had magic_quotes_gpc on. Magic quotes are evil and lame, but we gotta deal with em. :P Updated the web installer code to check for magic quotes, and to grab its variables consistently through the same interface. --- install.php | 83 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/install.php b/install.php index 158d51fa33..9b0d19882c 100644 --- a/install.php +++ b/install.php @@ -45,14 +45,62 @@ require INSTALLDIR . '/lib/installer.php'; * Helper class for building form */ class Posted { + /** + * HTML-friendly escaped string for the POST param of given name, or empty. + * @param string $name + * @return string + */ function value($name) + { + return htmlspecialchars($this->string($name)); + } + + /** + * The given POST parameter value, forced to a string. + * Missing value will give ''. + * + * @param string $name + * @return string + */ + function string($name) + { + return strval($this->raw($name)); + } + + /** + * The given POST parameter value, in its original form. + * Magic quotes are stripped, if provided. + * Missing value will give null. + * + * @param string $name + * @return mixed + */ + function raw($name) { if (isset($_POST[$name])) { - return htmlspecialchars(strval($_POST[$name])); + return $this->dequote($_POST[$name]); } else { - return ''; + return null; } } + + /** + * If necessary, strip magic quotes from the given value. + * + * @param mixed $val + * @return mixed + */ + function dequote($val) + { + if (get_magic_quotes_gpc()) { + if (is_string($val)) { + return stripslashes($val); + } else if (is_array($val)) { + return array_map(array($this, 'dequote'), $val); + } + } + return $val; + } } /** @@ -107,11 +155,7 @@ class WebInstaller extends Installer global $dbModules; $post = new Posted(); $dbRadios = ''; - if (isset($_POST['dbtype'])) { - $dbtype = $_POST['dbtype']; - } else { - $dbtype = null; - } + $dbtype = $post->raw('dbtype'); foreach (self::$dbModules as $type => $info) { if ($this->checkExtension($info['check_module'])) { if ($dbtype == null || $dbtype == $type) { @@ -245,19 +289,20 @@ STR; */ function prepare() { - $this->host = $_POST['host']; - $this->dbtype = $_POST['dbtype']; - $this->database = $_POST['database']; - $this->username = $_POST['dbusername']; - $this->password = $_POST['dbpassword']; - $this->sitename = $_POST['sitename']; - $this->fancy = !empty($_POST['fancy']); + $post = new Posted(); + $this->host = $post->string('host'); + $this->dbtype = $post->string('dbtype'); + $this->database = $post->string('database'); + $this->username = $post->string('dbusername'); + $this->password = $post->string('dbpassword'); + $this->sitename = $post->string('sitename'); + $this->fancy = (bool)$post->string('fancy'); - $this->adminNick = strtolower($_POST['admin_nickname']); - $this->adminPass = $_POST['admin_password']; - $adminPass2 = $_POST['admin_password2']; - $this->adminEmail = $_POST['admin_email']; - $this->adminUpdates = $_POST['admin_updates']; + $this->adminNick = strtolower($post->string('admin_nickname')); + $this->adminPass = $post->string('admin_password'); + $adminPass2 = $post->string('admin_password2'); + $this->adminEmail = $post->string('admin_email'); + $this->adminUpdates = $post->string('admin_updates'); $this->server = $_SERVER['HTTP_HOST']; $this->path = substr(dirname($_SERVER['PHP_SELF']), 1); From 793ec16ed4a8cacee6420629a02d3bf26344f17d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 14 Oct 2010 16:57:04 -0700 Subject: [PATCH 03/13] Fix ticket #2829: we have more subdirs to pull than just avatars now; updated the upgrade directions. --- README | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README b/README index 6b351f143d..e3748293fb 100644 --- a/README +++ b/README @@ -683,8 +683,9 @@ instructions; read to the end first before trying them. 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 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 From 9b9ba297913fdfa62d9e6d37afa5ec17341442e3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 15 Oct 2010 13:46:21 -0400 Subject: [PATCH 04/13] add SSL servers and paths to pathadminpanel.php --- actions/pathsadminpanel.php | 100 ++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 28 deletions(-) diff --git a/actions/pathsadminpanel.php b/actions/pathsadminpanel.php index 0c83aa29ec..e073b0a2aa 100644 --- a/actions/pathsadminpanel.php +++ b/actions/pathsadminpanel.php @@ -92,16 +92,17 @@ class PathsadminpanelAction extends AdminPanelAction function saveSettings() { static $settings = array( - 'site' => array('path', 'locale_path', 'ssl', 'sslserver'), - 'theme' => array('server', 'dir', 'path'), - 'avatar' => array('server', 'dir', 'path'), - 'background' => array('server', 'dir', 'path') - ); + 'site' => array('path', 'locale_path', 'ssl', 'sslserver'), + 'theme' => array('server', 'dir', 'path', 'sslserver', 'sslpath'), + 'avatar' => array('server', 'dir', 'path'), + 'background' => array('server', 'dir', 'path', 'sslserver', 'sslpath'), + 'attachments' => array('server', 'dir', 'path', 'sslserver', 'sslpath') + ); - // XXX: If we're only going to have one boolean on thi page we - // can remove some of the boolean processing code --Z + // XXX: If we're only going to have one boolean on thi page we + // can remove some of the boolean processing code --Z - static $booleans = array('site' => array('fancy')); + static $booleans = array('site' => array('fancy')); $values = array(); @@ -131,13 +132,13 @@ class PathsadminpanelAction extends AdminPanelAction } } - foreach ($booleans as $section => $parts) { - foreach ($parts as $setting) { + foreach ($booleans as $section => $parts) { + foreach ($parts as $setting) { Config::save($section, $setting, $values[$section][$setting]); } - } + } - $config->query('COMMIT'); + $config->query('COMMIT'); return; } @@ -230,11 +231,11 @@ class PathsAdminPanelForm extends AdminForm function formData() { - $this->out->elementStart('fieldset', array('id' => 'settings_paths_locale')); + $this->out->elementStart('fieldset', array('id' => 'settings_paths_locale')); $this->out->element('legend', null, _('Site'), 'site'); $this->out->elementStart('ul', 'form_data'); - $this->li(); + $this->li(); $this->input('server', _('Server'), _('Site\'s server hostname.')); $this->unli(); @@ -243,14 +244,14 @@ class PathsAdminPanelForm extends AdminForm $this->unli(); $this->li(); - $this->input('locale_path', _('Path to locales'), _('Directory path to locales'), 'site'); + $this->input('locale_path', _('Locale Directory'), _('Directory path to locales'), 'site'); $this->unli(); - $this->li(); + $this->li(); $this->out->checkbox('fancy', _('Fancy URLs'), (bool) $this->value('fancy'), _('Use fancy (more readable and memorable) URLs?')); - $this->unli(); + $this->unli(); $this->out->elementEnd('ul'); $this->out->elementEnd('fieldset'); @@ -261,15 +262,23 @@ class PathsAdminPanelForm extends AdminForm $this->out->elementStart('ul', 'form_data'); $this->li(); - $this->input('server', _('Theme server'), 'Server for themes', 'theme'); + $this->input('server', _('Server'), _('Server for themes'), 'theme'); $this->unli(); $this->li(); - $this->input('path', _('Theme path'), 'Web path to themes', 'theme'); + $this->input('path', _('Path'), _('Web path to themes'), 'theme'); $this->unli(); $this->li(); - $this->input('dir', _('Theme directory'), 'Directory where themes are located', 'theme'); + $this->input('sslserver', _('SSL server'), _('SSL server for themes (default: SSL server)'), 'theme'); + $this->unli(); + + $this->li(); + $this->input('sslpath', _('SSL path'), _('SSL path to themes (default: /theme/)'), 'theme'); + $this->unli(); + + $this->li(); + $this->input('dir', _('Directory'), _('Directory where themes are located'), 'theme'); $this->unli(); $this->out->elementEnd('ul'); @@ -297,20 +306,57 @@ class PathsAdminPanelForm extends AdminForm $this->out->elementEnd('fieldset'); $this->out->elementStart('fieldset', array('id' => - 'settings_design_background-paths')); + 'settings_design_background-paths')); $this->out->element('legend', null, _('Backgrounds')); $this->out->elementStart('ul', 'form_data'); $this->li(); - $this->input('server', _('Background server'), 'Server for backgrounds', 'background'); + $this->input('server', _('Server'), 'Server for backgrounds', 'background'); $this->unli(); $this->li(); - $this->input('path', _('Background path'), 'Web path to backgrounds', 'background'); + $this->input('path', _('Path'), 'Web path to backgrounds', 'background'); $this->unli(); $this->li(); - $this->input('dir', _('Background directory'), 'Directory where backgrounds are located', 'background'); + $this->input('sslserver', _('SSL server'), 'Server for backgrounds on SSL pages', 'background'); + $this->unli(); + + $this->li(); + $this->input('sslpath', _('SSL path'), 'Web path to backgrounds on SSL pages', 'background'); + $this->unli(); + + $this->li(); + $this->input('dir', _('Directory'), 'Directory where backgrounds are located', 'background'); + $this->unli(); + + $this->out->elementEnd('ul'); + $this->out->elementEnd('fieldset'); + + $this->out->elementStart('fieldset', array('id' => + 'settings_design_attachments-paths')); + + $this->out->element('legend', null, _('Attachments')); + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + $this->input('server', _('Server'), 'Server for attachments', 'attachments'); + $this->unli(); + + $this->li(); + $this->input('path', _('Path'), 'Web path to attachments', 'attachments'); + $this->unli(); + + $this->li(); + $this->input('sslserver', _('SSL server'), 'Server for attachments on SSL pages', 'attachments'); + $this->unli(); + + $this->li(); + $this->input('sslpath', _('SSL path'), 'Web path to attachments on SSL pages', 'attachments'); + $this->unli(); + + $this->li(); + $this->input('dir', _('Directory'), 'Directory where attachments are located', 'attachments'); $this->unli(); $this->out->elementEnd('ul'); @@ -320,12 +366,11 @@ class PathsAdminPanelForm extends AdminForm $this->out->element('legend', null, _('SSL')); $this->out->elementStart('ul', 'form_data'); $this->li(); + $ssl = array('never' => _('Never'), 'sometimes' => _('Sometimes'), 'always' => _('Always')); - common_debug("site ssl = " . $this->value('site', 'ssl')); - $this->out->dropdown('site-ssl', _('Use SSL'), $ssl, _('When to use SSL'), false, $this->value('ssl', 'site')); @@ -349,7 +394,7 @@ class PathsAdminPanelForm extends AdminForm function formActions() { $this->out->submit('save', _('Save'), 'submit', - 'save', _('Save paths')); + 'save', _('Save paths')); } /** @@ -370,5 +415,4 @@ class PathsAdminPanelForm extends AdminForm { $this->out->input("$section-$setting", $title, $this->value($setting, $section), $instructions); } - } From 1d6d0cbcbdef6a926faa1ca6d9270fcf23b57a6d Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Sat, 16 Oct 2010 14:15:02 +0200 Subject: [PATCH 05/13] Use common case instead of WARNING in all caps. Spotted by The Evil IP address. --- plugins/OpenID/openidadminpanel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OpenID/openidadminpanel.php b/plugins/OpenID/openidadminpanel.php index ce4806cc89..38df183fef 100644 --- a/plugins/OpenID/openidadminpanel.php +++ b/plugins/OpenID/openidadminpanel.php @@ -257,7 +257,7 @@ class OpenIDAdminPanelForm extends AdminForm $this->out->checkbox( 'openidonly', _m('Enable OpenID-only mode'), (bool) $this->value('openidonly', 'site'), - _m('Require all users to login via OpenID. WARNING: disables password authentication for all users!'), + _m('Require all users to login via OpenID. Warning: disables password authentication for all users!'), 'true' ); $this->unli(); From 77191f455a670af6d747f6d1881fa0c3a1ee5b4b Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Sat, 16 Oct 2010 14:20:30 +0200 Subject: [PATCH 06/13] Change incorrect use of e.g. to i.e. Spotted by The Evil IP address. --- .../OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php b/plugins/OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php index 611f5e5c7b..f0f6144e01 100644 --- a/plugins/OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php +++ b/plugins/OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php @@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class OpenExternalLinkTargetPlugin extends Plugin { function onEndShowScripts($action) @@ -57,7 +56,7 @@ class OpenExternalLinkTargetPlugin extends Plugin 'author' => 'Sarven Capadisli', 'homepage' => 'http://status.net/wiki/Plugin:OpenExternalLinkTarget', 'rawdescription' => - _m('Opens external links (e.g., with rel=external) on a new window or tab.')); + _m('Opens external links (i.e. with rel=external) on a new window or tab.')); return true; } } From 31415b5853952e50f1ac7be816f4bb669884142c Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Sat, 16 Oct 2010 14:31:41 +0200 Subject: [PATCH 07/13] Update translator documentation. --- actions/apidirectmessage.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/actions/apidirectmessage.php b/actions/apidirectmessage.php index e7ea38dfa1..4e2ec5eb08 100644 --- a/actions/apidirectmessage.php +++ b/actions/apidirectmessage.php @@ -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; } From 505ac6eba0e671e8823b5102de3caa0e0040c2cf Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Sat, 16 Oct 2010 14:38:12 +0200 Subject: [PATCH 08/13] * add plural support where missing * update translator documentation. --- actions/apidirectmessagenew.php | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/actions/apidirectmessagenew.php b/actions/apidirectmessagenew.php index 44e205ebb0..c126cd312f 100644 --- a/actions/apidirectmessagenew.php +++ b/actions/apidirectmessagenew.php @@ -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); } } - } - From 7c05b0dafc609e978040e5612f6f6a86b0bb6420 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 18 Oct 2010 11:29:52 -0400 Subject: [PATCH 09/13] options to nofollow external links in notices --- actions/showfavorites.php | 14 ++++++- actions/shownotice.php | 2 +- actions/showstream.php | 2 +- lib/default.php | 3 +- lib/dofollowlistitem.php | 88 +++++++++++++++++++++++++++++++++++++++ lib/util.php | 14 ++++++- 6 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 lib/dofollowlistitem.php diff --git a/actions/showfavorites.php b/actions/showfavorites.php index d8042e91c7..77b73711d2 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -227,7 +227,7 @@ class ShowfavoritesAction extends OwnerDesignAction function showContent() { - $nl = new NoticeList($this->notice, $this); + $nl = new FavoritesNoticeList($this->notice, $this); $cnt = $nl->show(); if (0 == $cnt) { @@ -244,3 +244,15 @@ class ShowfavoritesAction extends OwnerDesignAction } } +class FavoritesNoticeList extends NoticeList +{ + function newListItem($notice) + { + return new FavoritesNoticeListItem($notice, $this->out); + } +} + +// All handled by superclass +class FavoritesNoticeListItem extends DoFollowListItem +{ +} diff --git a/actions/shownotice.php b/actions/shownotice.php index c5180568b3..5fc863486c 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -311,7 +311,7 @@ class ShownoticeAction extends OwnerDesignAction } } -class SingleNoticeItem extends NoticeListItem +class SingleNoticeItem extends DoFollowListItem { /** * recipe function for displaying a single notice. diff --git a/actions/showstream.php b/actions/showstream.php index e9f117afc4..be61a7ce0d 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -275,7 +275,7 @@ class ProfileNoticeList extends NoticeList } } -class ProfileNoticeListItem extends NoticeListItem +class ProfileNoticeListItem extends DoFollowListItem { function showAuthor() { diff --git a/lib/default.php b/lib/default.php index fb032930b2..3750881303 100644 --- a/lib/default.php +++ b/lib/default.php @@ -317,7 +317,8 @@ $default = 'nofollow' => array('subscribers' => true, 'members' => true, - 'peopletag' => true), + 'peopletag' => true, + 'external' => 'always'), // Options: 'sometimes', 'never', default = 'always' 'http' => // HTTP client settings when contacting other sites array('ssl_cafile' => false, // To enable SSL cert validation, point to a CA bundle (eg '/usr/lib/ssl/certs/ca-certificates.crt') 'curl' => false, // Use CURL backend for HTTP fetches if available. (If not, PHP's socket streams will be used.) diff --git a/lib/dofollowlistitem.php b/lib/dofollowlistitem.php new file mode 100644 index 0000000000..80e2d0b0a7 --- /dev/null +++ b/lib/dofollowlistitem.php @@ -0,0 +1,88 @@ +. + * + * @category UI + * @package StatusNet + * @author Evan Prodromou + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/noticelist.php'; + +/** + * StatusNet, the distributed open-source microblogging tool + * + * Widget superclass for notice list items that remove rel=nofollow + * + * When nofollow|external = 'sometimes', notices get rendered and saved + * with rel=nofollow for external links. We want to remove that relationship + * on some pages (profile, single notice, faves). This superclass for + * some noticelistitems will strip that bit of code out when showing + * notice content + * + * @category UI + * @package StatusNet + * @author Evan Prodromou + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +class DoFollowListItem extends NoticeListItem +{ + /** + * show the content of the notice + * + * Trims out the rel=nofollow for external links + * if nofollow|external = 'sometimes' + * + * @return void + */ + + function showContent() + { + // FIXME: URL, image, video, audio + $this->out->elementStart('p', array('class' => 'entry-content')); + + if (!empty($this->notice->rendered)) { + $html = $this->notice->rendered; + } else { + $html = common_render_content($this->notice->content, $this->notice); + } + + if (common_config('nofollow', 'external') == 'sometimes') { + // remove the nofollow part + // XXX: cache the results here + + $html = preg_replace('/rel="(.*)nofollow ?/', 'rel="\1', $html); + } + + $this->out->raw($html); + + $this->out->elementEnd('p'); + } +} \ No newline at end of file diff --git a/lib/util.php b/lib/util.php index c05fcf15a2..5a94182bda 100644 --- a/lib/util.php +++ b/lib/util.php @@ -145,7 +145,6 @@ function common_switch_locale($language=null) textdomain("statusnet"); } - function common_timezone() { if (common_logged_in()) { @@ -860,7 +859,8 @@ function common_linkify($url) { $longurl = $url; } } - $attrs = array('href' => $canon, 'title' => $longurl, 'rel' => 'external'); + + $attrs = array('href' => $canon, 'title' => $longurl); $is_attachment = false; $attachment_id = null; @@ -896,6 +896,16 @@ function common_linkify($url) { $attrs['id'] = "attachment-{$attachment_id}"; } + // Whether to nofollow + + $nf = common_config('nofollow', 'external'); + + if ($nf == 'never') { + $attrs['rel'] = 'external'; + } else { + $attrs['rel'] = 'nofollow external'; + } + return XMLStringer::estring('a', $attrs, $url); } From 47ac8458ca4891020ce5667718b5cad0fa485756 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 18 Oct 2010 11:41:18 -0400 Subject: [PATCH 10/13] default for nofollow external is sometimes --- lib/default.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/default.php b/lib/default.php index 3750881303..a19453fce4 100644 --- a/lib/default.php +++ b/lib/default.php @@ -318,7 +318,7 @@ $default = array('subscribers' => true, 'members' => true, 'peopletag' => true, - 'external' => 'always'), // Options: 'sometimes', 'never', default = 'always' + 'external' => 'sometimes'), // Options: 'sometimes', 'never', default = 'sometimes' 'http' => // HTTP client settings when contacting other sites array('ssl_cafile' => false, // To enable SSL cert validation, point to a CA bundle (eg '/usr/lib/ssl/certs/ca-certificates.crt') 'curl' => false, // Use CURL backend for HTTP fetches if available. (If not, PHP's socket streams will be used.) From 671712f0f617298dbf686df5707f232af8e053e2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 18 Oct 2010 11:41:33 -0400 Subject: [PATCH 11/13] document API and nofollow config options --- README | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README b/README index e3748293fb..35c510e2b8 100644 --- a/README +++ b/README @@ -1502,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 ======= From edf8990aa99a8d8df4334e271f4033e887d0a276 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 15 Oct 2010 15:01:55 -0700 Subject: [PATCH 12/13] fix notice on non-https views --- lib/statusnet.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/statusnet.php b/lib/statusnet.php index 301994508d..33bf32b10e 100644 --- a/lib/statusnet.php +++ b/lib/statusnet.php @@ -377,7 +377,7 @@ class StatusNet static function isHTTPS() { // There are some exceptions to this; add them here! - return $_SERVER['HTTPS']; + return !empty($_SERVER['HTTPS']); } } From e04a6ef93ef7706671ba14f5108690bfe12c1592 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 18 Oct 2010 11:27:22 -0700 Subject: [PATCH 13/13] Make HTTP timeout configurable on OStatus's remote-tests.php (needs to be pumped up a fair amount when doing Salmon pings with queues off on the test boxes, especially without the fast math library) --- plugins/OStatus/tests/remote-tests.php | 44 ++++++++++++++++++++------ 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/plugins/OStatus/tests/remote-tests.php b/plugins/OStatus/tests/remote-tests.php index 64c60a8a4c..7888ec7c5d 100644 --- a/plugins/OStatus/tests/remote-tests.php +++ b/plugins/OStatus/tests/remote-tests.php @@ -4,7 +4,7 @@ if (php_sapi_name() != 'cli') { die('not for web'); } -define('TIMEOUT', 60); // ssslllloowwwww salmon if queues are off +define('HTTP_TIMEOUT', 60); // ssslllloowwwww salmon if queues are off define('INSTALLDIR', dirname(dirname(dirname(dirname(__FILE__))))); set_include_path(INSTALLDIR . '/extlib' . PATH_SEPARATOR . get_include_path()); @@ -63,14 +63,15 @@ class OStatusTester extends TestBase /** * @param string $a base URL of test site A (eg http://localhost/mublog) * @param string $b base URL of test site B (eg http://localhost/mublog2) + * @param int $timeout HTTP timeout value (needs to be long if Salmon is slow) */ - function __construct($a, $b) { + function __construct($a, $b, $timeout=60) { $this->a = $a; $this->b = $b; $base = 'test' . mt_rand(1, 1000000); - $this->pub = new SNTestClient($this->a, 'pub' . $base, 'pw-' . mt_rand(1, 1000000)); - $this->sub = new SNTestClient($this->b, 'sub' . $base, 'pw-' . mt_rand(1, 1000000)); + $this->pub = new SNTestClient($this->a, 'pub' . $base, 'pw-' . mt_rand(1, 1000000), $timeout); + $this->sub = new SNTestClient($this->b, 'sub' . $base, 'pw-' . mt_rand(1, 1000000), $timeout); } function run() @@ -166,11 +167,12 @@ class OStatusTester extends TestBase class SNTestClient extends TestBase { - function __construct($base, $username, $password) + function __construct($base, $username, $password, $timeout=60) { $this->basepath = $base; $this->username = $username; $this->password = $password; + $this->timeout = $timeout; $this->fullname = ucfirst($username) . ' Smith'; $this->homepage = 'http://example.org/' . $username; @@ -190,7 +192,7 @@ class SNTestClient extends TestBase { $url = $this->basepath . '/' . $path; - $http = new HTTP_Request2($url, 'POST', array('timeout' => TIMEOUT)); + $http = new HTTP_Request2($url, 'POST', array('timeout' => $this->timeout)); if ($auth) { $http->setAuth($this->username, $this->password, HTTP_Request2::AUTH_BASIC); } @@ -217,7 +219,7 @@ class SNTestClient extends TestBase protected function web($path, $form, $params=array()) { $url = $this->basepath . '/' . $path; - $http = new HTTP_Request2($url, 'GET', array('timeout' => TIMEOUT)); + $http = new HTTP_Request2($url, 'GET', array('timeout' => $this->timeout)); $response = $http->send(); $dom = $this->checkWeb($url, 'GET', $response); @@ -534,10 +536,29 @@ class SNTestClient extends TestBase } -$args = array_slice($_SERVER['argv'], 1); +// @fixme switch to commandline.inc? +$timeout = HTTP_TIMEOUT; + +$args = array(); +$options = array(); +foreach (array_slice($_SERVER['argv'], 1) as $arg) { + if (substr($arg, 0, 2) == '--') { + $bits = explode('=', substr($arg, 2), 2); + if (count($bits == 2)) { + list($key, $val) = $bits; + $options[$key] = $val; + } else { + list($key) = $bits; + $options[$key] = true; + } + } else { + $args[] = $arg; + } +} if (count($args) < 2) { print << +remote-tests.php [options] + --timeout=## change HTTP timeout from default {$timeout}s url1: base URL of a StatusNet instance url2: base URL of another StatusNet instance @@ -551,6 +572,9 @@ exit(1); $a = $args[0]; $b = $args[1]; +if (isset($options['timeout'])) { + $timeout = intval($options['timeout']); +} -$tester = new OStatusTester($a, $b); +$tester = new OStatusTester($a, $b, $timeout); $tester->run();