From 73251c7629a95a90b37c81aa415a17335b200ca9 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 16 May 2011 13:25:26 -0700 Subject: [PATCH 01/16] Script to cancel an email registration --- .../scripts/cancelemailregistration.php | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 plugins/EmailRegistration/scripts/cancelemailregistration.php diff --git a/plugins/EmailRegistration/scripts/cancelemailregistration.php b/plugins/EmailRegistration/scripts/cancelemailregistration.php new file mode 100644 index 0000000000..e6430e850f --- /dev/null +++ b/plugins/EmailRegistration/scripts/cancelemailregistration.php @@ -0,0 +1,55 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..')); + +$shortoptions = 'd'; +$longoptions = array('dryrun'); + +$helptext = << + +Options: +-d --dryrun Don't actually delete the email registration and confirmation code + +Cancel an email registration code + +END_OF_REGISTEREMAILUSER_HELP; + +require_once INSTALLDIR.'/scripts/commandline.inc'; + +if (count($args) == 0) { + show_help(); +} + +$email = $args[0]; + +$confirm = Confirm_address::getAddress($email, EmailRegistrationPlugin::CONFIRMTYPE); + +if (!empty($confirm)) { + if (have_option('d', 'dryrun')) { + print "[Dry run mode] Deleted confirmation code {$confirm->code} for {$confirm->address}.\n"; + } else { + $confirm->delete(); + print "Deleted confirmation code {$confirm->code} for {$confirm->address}.\n"; + } +} else { + print "Couldn't find an email registration code for {$email}.\n"; +} From c2f735a84ecba2a7bb27ad8499268cb3a8c73689 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 May 2011 06:03:36 -0700 Subject: [PATCH 02/16] rev to alpha3 --- lib/framework.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/framework.php b/lib/framework.php index b0b50fc961..ed5c94730e 100644 --- a/lib/framework.php +++ b/lib/framework.php @@ -20,7 +20,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } define('STATUSNET_BASE_VERSION', '1.0.0'); -define('STATUSNET_LIFECYCLE', 'alpha2'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' +define('STATUSNET_LIFECYCLE', 'alpha3'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' define('STATUSNET_VERSION', STATUSNET_BASE_VERSION . STATUSNET_LIFECYCLE); define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility From 9c4c2c710f9c1da86c7cc98885c56c366bc71936 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 May 2011 06:08:42 -0700 Subject: [PATCH 03/16] remove stray newlines that were causing problems with the build --- locale/eo/LC_MESSAGES/statusnet.po | 2 +- plugins/Directory/locale/mk/LC_MESSAGES/Directory.po | 2 +- plugins/Directory/locale/tl/LC_MESSAGES/Directory.po | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/locale/eo/LC_MESSAGES/statusnet.po b/locale/eo/LC_MESSAGES/statusnet.po index 465b154cd4..016e657a8b 100644 --- a/locale/eo/LC_MESSAGES/statusnet.po +++ b/locale/eo/LC_MESSAGES/statusnet.po @@ -8912,7 +8912,7 @@ msgstr "" "\n" "%4$s\n" "\n" -"Ne respondu al ĉi tiu retpoŝtadreso; respondo ne atingos lin.\n" +"Ne respondu al ĉi tiu retpoŝtadreso; respondo ne atingos lin." #. TRANS: Subject for favorite notification e-mail. #. TRANS: %1$s is the adding user's long name, %2$s is the adding user's nickname. diff --git a/plugins/Directory/locale/mk/LC_MESSAGES/Directory.po b/plugins/Directory/locale/mk/LC_MESSAGES/Directory.po index a9eda1b74d..5a050234f1 100644 --- a/plugins/Directory/locale/mk/LC_MESSAGES/Directory.po +++ b/plugins/Directory/locale/mk/LC_MESSAGES/Directory.po @@ -127,7 +127,7 @@ msgstr "" "* Проверете дали сите зборови се напишани како што треба.\n" "* Обидете се со други клучни зборови.\n" "* Обидете се со поопшти клучни зборови.\n" -"* Обидете се помалку клучни зборови.\n" +"* Обидете се помалку клучни зборови." #. TRANS: Menu item text for user directory. msgctxt "MENU" diff --git a/plugins/Directory/locale/tl/LC_MESSAGES/Directory.po b/plugins/Directory/locale/tl/LC_MESSAGES/Directory.po index 1002ef420e..dc181fc065 100644 --- a/plugins/Directory/locale/tl/LC_MESSAGES/Directory.po +++ b/plugins/Directory/locale/tl/LC_MESSAGES/Directory.po @@ -128,7 +128,7 @@ msgstr "" "* Tiyakin na tama ang pagbabanghay ng lahat ng mga salita.\n" "* Sumubok ng ibang mga susing-salita.\n" "* Sumubok ng mas pangkalahatang mga susing-salita.\n" -"* Sumubok ng mas kakaunting mga susing-salita.\n" +"* Sumubok ng mas kakaunting mga susing-salita." #. TRANS: Menu item text for user directory. msgctxt "MENU" From 5a86900a348da23e2ca6d626b94465949cc6c29d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 May 2011 06:09:37 -0700 Subject: [PATCH 04/16] minor alpha version for i18n build errors --- lib/framework.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/framework.php b/lib/framework.php index ed5c94730e..f9a9d85bdc 100644 --- a/lib/framework.php +++ b/lib/framework.php @@ -20,7 +20,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } define('STATUSNET_BASE_VERSION', '1.0.0'); -define('STATUSNET_LIFECYCLE', 'alpha3'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' +define('STATUSNET_LIFECYCLE', 'alpha4'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' define('STATUSNET_VERSION', STATUSNET_BASE_VERSION . STATUSNET_LIFECYCLE); define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility From 86a7889012a65c737d80e86848a620397b459b25 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 23 May 2011 12:30:34 -0400 Subject: [PATCH 05/16] render question description in QnA plugin --- plugins/QnA/classes/QnA_Answer.php | 2 +- plugins/QnA/classes/QnA_Question.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/QnA/classes/QnA_Answer.php b/plugins/QnA/classes/QnA_Answer.php index d200c7b45a..1a415f4af4 100644 --- a/plugins/QnA/classes/QnA_Answer.php +++ b/plugins/QnA/classes/QnA_Answer.php @@ -219,7 +219,7 @@ class QnA_Answer extends Managed_DataObject $out->elementStart('p', array('class' => implode(' ', $cls))); $out->elementStart('span', 'answer-content'); - $out->raw(QnAPlugin::shorten($answer->content, $notice)); + $out->raw(common_render_text($answer->content)); $out->elementEnd('span'); if (!empty($answer->revisions)) { diff --git a/plugins/QnA/classes/QnA_Question.php b/plugins/QnA/classes/QnA_Question.php index 77d5a57fb1..e2430087c0 100644 --- a/plugins/QnA/classes/QnA_Question.php +++ b/plugins/QnA/classes/QnA_Question.php @@ -227,7 +227,7 @@ class QnA_Question extends Managed_DataObject if (!empty($question->description)) { $out->elementStart('span', 'question-description'); - $out->raw(QnAPlugin::shorten($question->description, $notice)); + $out->raw(common_render_text($question->description)); $out->elementEnd('span'); } From cb090ab48dd827cd328a500d26f6b41fec73860e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 23 May 2011 12:37:29 -0400 Subject: [PATCH 06/16] increment alpha version revision --- lib/framework.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/framework.php b/lib/framework.php index f9a9d85bdc..9adaf7f838 100644 --- a/lib/framework.php +++ b/lib/framework.php @@ -20,7 +20,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } define('STATUSNET_BASE_VERSION', '1.0.0'); -define('STATUSNET_LIFECYCLE', 'alpha4'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' +define('STATUSNET_LIFECYCLE', 'alpha5'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' define('STATUSNET_VERSION', STATUSNET_BASE_VERSION . STATUSNET_LIFECYCLE); define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility From 32f47004df3bc795a3cbdc380ceaaf9159436a36 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 25 May 2011 12:51:21 -0400 Subject: [PATCH 07/16] get correct profile for friends timeline --- actions/apitimelinefriends.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/actions/apitimelinefriends.php b/actions/apitimelinefriends.php index 279265a30e..33248203bc 100644 --- a/actions/apitimelinefriends.php +++ b/actions/apitimelinefriends.php @@ -289,7 +289,13 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction { $notices = array(); - $stream = new InboxNoticeStream($this->user); + $profile = null; + + if (isset($this->auth_user)) { + $profile = $this->auth_user->getProfile(); + } + + $stream = new InboxNoticeStream($this->user, $profile); $notice = $stream->getNotices(($this->page-1) * $this->count, $this->count, From a838891c0ebf271a71e367975a778d2bc35b75ff Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 25 May 2011 13:04:35 -0400 Subject: [PATCH 08/16] set the current user in api actions --- lib/apiauth.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/apiauth.php b/lib/apiauth.php index 42d32dd624..1e2a6101d6 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -204,6 +204,8 @@ class ApiAuthAction extends ApiAction } } $this->auth_user = $user; + global $_cur; + $_cur = $this->auth_user; Event::handle('EndSetApiUser', array($user)); } From d7a16929b9fbfdbb52faab82f2560904b6b10c3e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 25 May 2011 14:01:22 -0400 Subject: [PATCH 09/16] Set the current user on API calls --- lib/apiauth.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/apiauth.php b/lib/apiauth.php index 1e2a6101d6..1061e6b68c 100644 --- a/lib/apiauth.php +++ b/lib/apiauth.php @@ -204,9 +204,12 @@ class ApiAuthAction extends ApiAction } } $this->auth_user = $user; + // FIXME: setting the value returned by common_current_user() + // There should probably be a better method for this. common_set_user() + // does lots of session stuff. global $_cur; $_cur = $this->auth_user; - Event::handle('EndSetApiUser', array($user)); + Event::handle('EndSetApiUser', array($user)); } $msg = "API OAuth authentication for user '%s' (id: %d) on behalf of " . From 7f1a30dc40ac772247425a49498d7f5d4550e01f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 1 Jun 2011 10:53:46 -0400 Subject: [PATCH 10/16] allow setting some initial tags on a new network --- .../domainstatusnetworkinstaller.php | 18 +++++++++++++++++- scripts/setup.cfg.sample | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php b/plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php index b2042abe94..efa7784955 100644 --- a/plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php +++ b/plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php @@ -120,6 +120,14 @@ class DomainStatusNetworkInstaller extends Installer $this->sitehost = $config['DBHOST']; $this->sitedb = $config['SITEDB']; + $tagstr = $config['TAGS']; + + if (!empty($tagstr)) { + $this->tags = preg_split('/[\s,]+/', $tagstr); + } else { + $this->tags = array(); + } + // Explicitly empty $this->adminNick = null; @@ -185,7 +193,15 @@ class DomainStatusNetworkInstaller extends Installer throw new ServerException("Created {$this->nickname} status_network and could not find it again."); } - $sn->setTags(array('domain='.$this->domain)); + // Set default tags + + $tags = $this->tags; + + // Add domain tag + + $tags[] = 'domain='.$this->domain; + + $sn->setTags($tags); $this->sn = $sn; } diff --git a/scripts/setup.cfg.sample b/scripts/setup.cfg.sample index 049cd3e859..3296bbe043 100644 --- a/scripts/setup.cfg.sample +++ b/scripts/setup.cfg.sample @@ -18,3 +18,4 @@ export MAILSUBJECT="Your new StatusNet site" export POSTINSTALL=/etc/statusnet/morestuff.sh export WEBUSER=www-data export WEBGROUP=www-data +export TAGS=tag1,tag2,tag3 From 9a11003c08e66b39adb714138a895608196568e6 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 2 Jun 2011 10:04:00 -0400 Subject: [PATCH 11/16] add oauth_token_association to core.php so it gets set up correctly --- actions/apioauthauthorize.php | 30 ----------------------------- classes/Oauth_token_association.php | 19 ++++++++++++++++++ db/core.php | 2 ++ 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/actions/apioauthauthorize.php b/actions/apioauthauthorize.php index d76ae060f2..3a83fd27fc 100644 --- a/actions/apioauthauthorize.php +++ b/actions/apioauthauthorize.php @@ -196,12 +196,6 @@ class ApiOauthAuthorizeAction extends Action ) ); - // XXX: Make sure we have a oauth_token_association table. The table - // is now in the main schema, but because it is being added with - // a point release, it's unlikely to be there. This code can be - // removed as of 1.0. - $this->ensureOauthTokenAssociationTable(); - $tokenAssoc = new Oauth_token_association(); $tokenAssoc->profile_id = $user->id; @@ -295,30 +289,6 @@ class ApiOauthAuthorizeAction extends Action } } - // XXX Remove this function when we hit 1.0 - function ensureOauthTokenAssociationTable() - { - $schema = Schema::get(); - - $reqTokenCols = array( - new ColumnDef('profile_id', 'integer', null, true, 'PRI'), - new ColumnDef('application_id', 'integer', null, true, 'PRI'), - new ColumnDef('token', 'varchar', 255, true, 'PRI'), - new ColumnDef('created', 'datetime', null, false), - new ColumnDef( - 'modified', - 'timestamp', - null, - false, - null, - 'CURRENT_TIMESTAMP', - 'on update CURRENT_TIMESTAMP' - ) - ); - - $schema->ensureTable('oauth_token_association', $reqTokenCols); - } - /** * Show body - override to add a special CSS class for the authorize * page's "desktop mode" (minimal display) diff --git a/classes/Oauth_token_association.php b/classes/Oauth_token_association.php index 66be22b5d3..40527fa742 100644 --- a/classes/Oauth_token_association.php +++ b/classes/Oauth_token_association.php @@ -39,4 +39,23 @@ class Oauth_token_association extends Memcached_DataObject return empty($result) ? null : $oau; } + + public static function schemaDef() + { + return array( + 'description' => 'Associate an application ID and profile ID with an OAuth token', + 'fields' => array( + 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'associated user'), + 'application_id' => array('type' => 'int', 'not null' => true, 'description' => 'the application'), + 'token' => array('type' => 'varchar', 'length' => '255', 'not null' => true, 'description' => 'token used for this association'), + 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'), + 'modified' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was modified'), + ), + 'primary key' => array('profile_id', 'application_id', 'token'), + 'foreign keys' => array( + 'oauth_token_association_profile_fkey' => array('profile_id', array('profile' => 'id')), + 'oauth_token_association_application_fkey' => array('application_id', array('application' => 'id')), + ) + ); + } } diff --git a/db/core.php b/db/core.php index 626672bf5f..fe9f4735d9 100644 --- a/db/core.php +++ b/db/core.php @@ -1110,3 +1110,5 @@ $schema['schema_version'] = array( $schema['group_join_queue'] = Group_join_queue::schemaDef(); $schema['subscription_queue'] = Subscription_queue::schemaDef(); + +$schema['oauth_token_association'] = Oauth_token_association::schemaDef(); From e1791525e818d7d4276da0fe7e7c526fe8794e7c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 2 Jun 2011 13:58:53 -0400 Subject: [PATCH 12/16] initialize schema_version table after install --- .../domainstatusnetworkinstaller.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php b/plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php index efa7784955..b2e988b5e1 100644 --- a/plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php +++ b/plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php @@ -214,6 +214,21 @@ class DomainStatusNetworkInstaller extends Installer StatusNet::switchSite($this->nickname); + // We need to initialize the schema_version stuff to make later setup easier + + $schema = array(); + require INSTALLDIR.'/db/core.php'; + $tableDefs = $schema; + + $schema = Schema::get(); + $schemaUpdater = new SchemaUpdater($schema); + + foreach ($tableDefs as $table => $def) { + $schemaUpdater->register($table, $def); + } + + $schemaUpdater->checkSchema(); + Event::handle('CheckSchema'); } From 606875f1c9a6aa8cc348c84203c3d41b165399f6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 2 Jun 2011 11:20:08 -0700 Subject: [PATCH 13/16] Change modified to use timestamp type instead of datetime --- classes/Oauth_token_association.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/Oauth_token_association.php b/classes/Oauth_token_association.php index 40527fa742..06c9fee1c3 100644 --- a/classes/Oauth_token_association.php +++ b/classes/Oauth_token_association.php @@ -49,7 +49,7 @@ class Oauth_token_association extends Memcached_DataObject 'application_id' => array('type' => 'int', 'not null' => true, 'description' => 'the application'), 'token' => array('type' => 'varchar', 'length' => '255', 'not null' => true, 'description' => 'token used for this association'), 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'), - 'modified' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was modified'), + 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), ), 'primary key' => array('profile_id', 'application_id', 'token'), 'foreign keys' => array( From 321060ca712923b8284fef395e481b9464654545 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 2 Jun 2011 18:18:46 -0700 Subject: [PATCH 14/16] Script to update (pull) OStatus profiles info and avatars --- scripts/update_ostatus_profiles.php | 327 ++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 scripts/update_ostatus_profiles.php diff --git a/scripts/update_ostatus_profiles.php b/scripts/update_ostatus_profiles.php new file mode 100644 index 0000000000..0d56423f58 --- /dev/null +++ b/scripts/update_ostatus_profiles.php @@ -0,0 +1,327 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); + +$shortoptions = 'u:a'; +$longoptions = array('uri=', 'all'); + +$helptext = <<isGroup()) { + $self = $this->localGroup(); + } else { + $self = $this->localProfile(); + } + if (!$self) { + throw new ServerException(sprintf( + // TRANS: Server exception. %s is a URI. + _m('Tried to update avatar for unsaved remote profile %s.'), + $this->uri)); + } + + // @fixme this should be better encapsulated + // ripped from oauthstore.php (for old OMB client) + $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); + try { + if (!copy($url, $temp_filename)) { + // TRANS: Server exception. %s is a URL. + 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)); + } 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 + // problems later on: + // + // http://status.net/open-source/issues/2663 + chmod(Avatar::path($filename), 0644); + + $self->setOriginal($filename); + + $orig = clone($this); + $this->avatar = $url; + $this->update($orig); + } + + /** + * Look up and if necessary create an Ostatus_profile for the remote entity + * with the given profile page URL. This should never return null -- you + * will either get an object or an exception will be thrown. + * + * @param string $profile_url + * @return Ostatus_profile + * @throws Exception on various error conditions + * @throws OStatusShadowException if this reference would obscure a local user/group + */ + public static function updateProfileURL($profile_url, $hints=array()) + { + $oprofile = null; + + $hints['profileurl'] = $profile_url; + + // Fetch the URL + // XXX: HTTP caching + + $client = new HTTPClient(); + $client->setHeader('Accept', 'text/html,application/xhtml+xml'); + $response = $client->get($profile_url); + + if (!$response->isOk()) { + // TRANS: Exception. %s is a profile URL. + throw new Exception(sprintf(_m('Could not reach profile page %s.'),$profile_url)); + } + + // Check if we have a non-canonical URL + + $finalUrl = $response->getUrl(); + + if ($finalUrl != $profile_url) { + $hints['profileurl'] = $finalUrl; + } + + // Try to get some hCard data + + $body = $response->getBody(); + + $hcardHints = DiscoveryHints::hcardHints($body, $finalUrl); + + if (!empty($hcardHints)) { + $hints = array_merge($hints, $hcardHints); + } + + // Check if they've got an LRDD header + + $lrdd = LinkHeader::getLink($response, 'lrdd', 'application/xrd+xml'); + + if (!empty($lrdd)) { + + $xrd = Discovery::fetchXrd($lrdd); + $xrdHints = DiscoveryHints::fromXRD($xrd); + + $hints = array_merge($hints, $xrdHints); + } + + // If discovery found a feedurl (probably from LRDD), use it. + + if (array_key_exists('feedurl', $hints)) { + return self::ensureFeedURL($hints['feedurl'], $hints); + } + + // Get the feed URL from HTML + + $discover = new FeedDiscovery(); + + $feedurl = $discover->discoverFromHTML($finalUrl, $body); + + if (!empty($feedurl)) { + $hints['feedurl'] = $feedurl; + return self::ensureFeedURL($feedurl, $hints); + } + + // TRANS: Exception. %s is a URL. + throw new Exception(sprintf(_m('Could not find a feed URL for profile page %s.'),$finalUrl)); + } + + /** + * Look up, and if necessary create, an Ostatus_profile for the remote + * entity with the given webfinger address. + * This should never return null -- you will either get an object or + * an exception will be thrown. + * + * @param string $addr webfinger address + * @return Ostatus_profile + * @throws Exception on error conditions + * @throws OStatusShadowException if this reference would obscure a local user/group + */ + public static function updateWebfinger($addr) + { + $disco = new Discovery(); + + try { + $xrd = $disco->lookup($addr); + } catch (Exception $e) { + // Save negative cache entry so we don't waste time looking it up again. + // @fixme distinguish temporary failures? + self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), null); + // TRANS: Exception. + throw new Exception(_m('Not a valid webfinger address.')); + } + + $hints = array('webfinger' => $addr); + + $dhints = DiscoveryHints::fromXRD($xrd); + + $hints = array_merge($hints, $dhints); + + // If there's an Hcard, let's grab its info + if (array_key_exists('hcard', $hints)) { + if (!array_key_exists('profileurl', $hints) || + $hints['hcard'] != $hints['profileurl']) { + $hcardHints = DiscoveryHints::fromHcardUrl($hints['hcard']); + $hints = array_merge($hcardHints, $hints); + } + } + + // If we got a feed URL, try that + if (array_key_exists('feedurl', $hints)) { + try { + common_log(LOG_INFO, "Discovery on acct:$addr with feed URL " . $hints['feedurl']); + $oprofile = self::ensureFeedURL($hints['feedurl'], $hints); + self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri); + return $oprofile; + } catch (Exception $e) { + common_log(LOG_WARNING, "Failed creating profile from feed URL '$feedUrl': " . $e->getMessage()); + // keep looking + } + } + + // If we got a profile page, try that! + if (array_key_exists('profileurl', $hints)) { + try { + common_log(LOG_INFO, "Discovery on acct:$addr with profile URL $profileUrl"); + $oprofile = self::ensureProfileURL($hints['profileurl'], $hints); + self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri); + return $oprofile; + } catch (OStatusShadowException $e) { + // We've ended up with a remote reference to a local user or group. + // @fixme ideally we should be able to say who it was so we can + // go back and refer to it the regular way + throw $e; + } catch (Exception $e) { + common_log(LOG_WARNING, "Failed creating profile from profile URL '$profileUrl': " . $e->getMessage()); + // keep looking + // + // @fixme this means an error discovering from profile page + // may give us a corrupt entry using the webfinger URI, which + // will obscure the correct page-keyed profile later on. + } + } + throw new Exception(sprintf(_m('Could not find a valid profile for "%s".'),$addr)); + } +} + +function pullOstatusProfile($uri) { + + $oprofile = null; + + if (Validate::email($uri)) { + $oprofile = LooseOstatusProfile::updateWebfinger($uri); + } else if (Validate::uri($uri)) { + $oprofile = LooseOstatusProfile::updateProfileURL($uri); + } else { + print "Sorry, we could not reach the address: $uri\n"; + return false; + } + + return $oprofile; +} + +$quiet = have_option('q', 'quiet'); + +$lop = new LooseOstatusProfile(); + +if (have_option('u', 'uri')) { + $lop->uri = get_option_value('u', 'uri'); +} else if (!have_option('a', 'all')) { + show_help(); + exit(1); +} + +$cnt = $lop->find(); + +if (!empty($cnt)) { + if (!$quiet) { echo "Found {$cnt} OStatus profiles:\n"; } +} else { + if (have_option('u', 'uri')) { + if (!$quiet) { echo "Couldn't find an existing OStatus profile with that URI.\n"; } + } else { + if (!$quiet) { echo "Couldn't find any existing OStatus profiles.\n"; } + } + exit(0); +} + +while($lop->fetch()) { + if (!$quiet) { echo "Updating OStatus profile '{$lop->uri}' ... "; } + try { + $oprofile = pullOstatusProfile($lop->uri); + + if (!empty($oprofile)) { + $orig = clone($lop); + $lop->avatar = $oprofile->avatar; + $lop->update($orig); + $lop->updateAvatar($oprofile->avatar); + if (!$quiet) { print "Done.\n"; } + } + } catch (Exception $e) { + if (!$quiet) { print $e->getMessage() . "\n"; } + common_log(LOG_WARN, $e->getMessage(), __FILE__); + // continue on error + } +} + +if (!$quiet) { echo "OK.\n"; } From 895447f3dc274b8c813a6870deedda5910b63c3f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 6 Jun 2011 06:08:17 +0000 Subject: [PATCH 15/16] Upgrade anti-framing, anti-clickjacking code --- lib/action.php | 7 +++++-- lib/htmloutputter.php | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/action.php b/lib/action.php index 3492873c59..81aa8eb12c 100644 --- a/lib/action.php +++ b/lib/action.php @@ -334,9 +334,12 @@ class Action extends HTMLOutputter // lawsuit $this->inlineScript('var _peopletagAC = "' . common_local_url('peopletagautocomplete') . '";'); $this->showScriptMessages(); - // Frame-busting code to avoid clickjacking attacks. + // Anti-framing code to avoid clickjacking attacks in older browsers. + // This will show a blank page if the page is being framed, which is + // consistent with the behavior of the 'X-Frame-Options: SAMEORIGIN' + // header, which prevents framing in newer browser. if (common_config('javascript', 'bustframes')) { - $this->inlineScript('if (window.top !== window.self) { window.top.location.href = window.self.location.href; }'); + $this->inlineScript('if (window.top !== window.self) { document.write = ""; window.top.location = window.self.location; setTimeout(function () { document.body.innerHTML = ""; }, 1); window.self.onload = function () { document.body.innerHTML = ""; }; }'); } Event::handle('EndShowStatusNetScripts', array($this)); Event::handle('EndShowLaconicaScripts', array($this)); diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 3b3c1913a1..e358b2be5d 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -108,6 +108,13 @@ class HTMLOutputter extends XMLOutputter header('Content-Type: '.$type); + // Output anti-framing headers to prevent clickjacking (respected by newer + // browsers). + if (common_config('javascript', 'bustframes')) { + header('X-XSS-Protection 1; mode=block'); // detect XSS Reflection attacks + header('X-Frame-Options: SAMEORIGIN'); // no rendering if origin mismatch + } + $this->extraHeaders(); if (preg_match("/.*\/.*xml/", $type)) { // Required for XML documents From 8b9a5f550b9118f41ebe9eefb45cbb61d615f210 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 6 Jun 2011 13:18:56 -0700 Subject: [PATCH 16/16] Update design settings CSS output --- classes/Design.php | 6 +++--- js/userdesign.go.js | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/classes/Design.php b/classes/Design.php index f4834c714e..464e244b1a 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -1,7 +1,7 @@ contentcolor); if (!empty($ccolor)) { - $css .= '#content, #site_nav_local_views .current a { background-color: #'; + $css .= '#content { background-color: #'; $css .= $ccolor->hexValue() . '} '."\n"; } $sbcolor = Design::toWebColor($this->sidebarcolor); if (!empty($sbcolor)) { - $css .= '#aside_primary { background-color: #'. $sbcolor->hexValue() . ' }' . "\n"; + $css .= '#aside_primary_wrapper, #site_nav_local_views_wrapper { background-color: #'. $sbcolor->hexValue() . ' }' . "\n"; } $tcolor = Design::toWebColor($this->textcolor); diff --git a/js/userdesign.go.js b/js/userdesign.go.js index eb4dece095..f6c696759d 100644 --- a/js/userdesign.go.js +++ b/js/userdesign.go.js @@ -2,7 +2,7 @@ * * @package StatusNet * @author Sarven Capadisli - * @copyright 2009 StatusNet, Inc. + * @copyright 2009-2011 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/ */ @@ -16,7 +16,7 @@ $(document).ready(function() { $(E).val(rgb2hex($('#content').css('background-color'))); break; case 3: - $(E).val(rgb2hex($('#aside_primary').css('background-color'))); + $(E).val(rgb2hex($('#aside_primary_wrapper, #site_nav_local_views_wrapper').css('background-color'))); break; case 4: $(E).val(rgb2hex($('html body').css('color'))); @@ -45,10 +45,10 @@ $(document).ready(function() { $('body').css({'background-color':C}); break; case 2: - $('#content, #site_nav_local_views .current a').css({'background-color':C}); + $('#content').css({'background-color':C}); break; case 3: - $('#aside_primary').css({'background-color':C}); + $('#aside_primary_wrapper, #site_nav_local_views_wrapper').css({'background-color':C}); break; case 4: $('html body').css({'color':C});