From ce004083d9c3c22cacaf059aae3cfd725fda6936 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 18 Aug 2009 14:15:55 -0400 Subject: [PATCH 01/11] IPv4 and IPv6 addresses are picked up in URLs Added ".onion" as a possible TLD --- lib/util.php | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/util.php b/lib/util.php index c8e318efec..5ecee69156 100644 --- a/lib/util.php +++ b/lib/util.php @@ -417,11 +417,31 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) { '(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|irc)://'. '|'. '(?:mailto|aim|tel|xmpp):'. + ')?'. + '('. + '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4 + '|(?:'. + '([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,6}|'. //IPv6 + '([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}|'. + '([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}|'. + '([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}|'. + '([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}|'. + '([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}|'. + '(([0-9a-f]{1,4}:){1,7}|:):|'. + ':(:[0-9a-f]{1,4}){1,7}|'. + '((([0-9a-f]{1,4}:){6})(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|'. + '(([0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|'. + '([0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,3}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,2}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,1}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '(([0-9a-f]{1,4}:){1,5}|:):(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + ':(:[0-9a-f]{1,4}){1,5}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}'. + ')|'. + '(?:[^.\s/:]+\.)+'. //DNS + '(?:museum|travel|onion|[a-z]{2,4})'. ')'. - '[^.\s]+\.[^\s]+'. - '|'. - '(?:[^.\s/:]+\.)+'. - '(?:museum|travel|[a-z]{2,4})'. '(?:[:/][^\s]*)?'. ')'. '#ix'; From 486167ad8e4011292587d4a1ed569a18d50b4a27 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 18 Aug 2009 22:18:01 +0000 Subject: [PATCH 02/11] Kick user out if she doesn't have FB cookies --- plugins/FBConnect/FBConnectAuth.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/plugins/FBConnect/FBConnectAuth.php b/plugins/FBConnect/FBConnectAuth.php index a3e2cdadcd..5b9d604e36 100644 --- a/plugins/FBConnect/FBConnectAuth.php +++ b/plugins/FBConnect/FBConnectAuth.php @@ -38,20 +38,14 @@ class FBConnectauthAction extends Action function prepare($args) { parent::prepare($args); - try { + $this->fbuid = getFacebook()->get_loggedin_user(); - $this->fbuid = getFacebook()->get_loggedin_user(); - - if ($this->fbuid > 0) { - $this->fb_fields = $this->getFacebookFields($this->fbuid, - array('first_name', 'last_name', 'name')); - } else { - common_debug("No Facebook User found."); - } - - } catch (Exception $e) { - common_log(LOG_WARNING, 'Problem getting Facebook uid: ' . - $e->getMessage()); + if ($this->fbuid > 0) { + $this->fb_fields = $this->getFacebookFields($this->fbuid, + array('first_name', 'last_name', 'name')); + } else { + $this->clientError(_('You must be logged into Facebook to ' . + 'use Facebook Connect.')); } return true; From c049931dc735d7767c5199d2d2816edb5f0487a2 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 18 Aug 2009 22:59:14 +0000 Subject: [PATCH 03/11] Return null if all columns in the compound primary key aren't specified --- classes/Foreign_link.php | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/classes/Foreign_link.php b/classes/Foreign_link.php index c0b356eced..ae8c22fd84 100644 --- a/classes/Foreign_link.php +++ b/classes/Foreign_link.php @@ -29,34 +29,38 @@ class Foreign_link extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - // XXX: This only returns a 1->1 single obj mapping. Change? Or make - // a getForeignUsers() that returns more than one? --Zach static function getByUserID($user_id, $service) { + if (empty($user_id) || empty($service)) { + return null; + } + $flink = new Foreign_link(); + $flink->service = $service; $flink->user_id = $user_id; $flink->limit(1); - if ($flink->find(true)) { - return $flink; - } + $result = $flink->find(true); + + return empty($result) ? null : $flink; - return null; } static function getByForeignID($foreign_id, $service) { - $flink = new Foreign_link(); - $flink->service = $service; - $flink->foreign_id = $foreign_id; - $flink->limit(1); + if (empty($foreign_id) || empty($service)) { + return null; + } else { + $flink = new Foreign_link(); + $flink->service = $service; + $flink->foreign_id = $foreign_id; + $flink->limit(1); - if ($flink->find(true)) { - return $flink; + $result = $flink->find(true); + + return empty($result) ? null : $flink; } - - return null; } function set_flags($noticesend, $noticerecv, $replysync, $friendsync) @@ -66,7 +70,7 @@ class Foreign_link extends Memcached_DataObject } else { $this->noticesync &= ~FOREIGN_NOTICE_SEND; } - + if ($noticerecv) { $this->noticesync |= FOREIGN_NOTICE_RECV; } else { From 8507017c246bef32f58d58db7d0b639f7f8f8668 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 18 Aug 2009 23:41:24 +0000 Subject: [PATCH 04/11] Better logging --- plugins/FBConnect/FBConnectAuth.php | 45 ++++++++++++++++--------- plugins/FBConnect/FBConnectPlugin.php | 12 ++++--- plugins/FBConnect/FBConnectSettings.php | 6 ++-- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/plugins/FBConnect/FBConnectAuth.php b/plugins/FBConnect/FBConnectAuth.php index 5b9d604e36..6191d9ea64 100644 --- a/plugins/FBConnect/FBConnectAuth.php +++ b/plugins/FBConnect/FBConnectAuth.php @@ -31,7 +31,6 @@ require_once INSTALLDIR . '/plugins/FBConnect/FBConnectPlugin.php'; class FBConnectauthAction extends Action { - var $fbuid = null; var $fb_fields = null; @@ -44,6 +43,11 @@ class FBConnectauthAction extends Action $this->fb_fields = $this->getFacebookFields($this->fbuid, array('first_name', 'last_name', 'name')); } else { + list($proxy, $ip) = common_client_ip(); + + common_log(LOG_WARNING, 'Facebook Connect Plugin - ' . + "Failed auth attempt, proxy = $proxy, ip = $ip."); + $this->clientError(_('You must be logged into Facebook to ' . 'use Facebook Connect.')); } @@ -63,8 +67,9 @@ class FBConnectauthAction extends Action if (!empty($flink)) { // User already has a linked Facebook account and shouldn't be here - common_debug('There is already a local user (' . $flink->user_id . - ') linked with this Facebook (' . $this->fbuid . ').'); + common_debug('Facebook Connect Plugin - ' . + 'There is already a local user (' . $flink->user_id . + ') linked with this Facebook (' . $this->fbuid . ').'); // We don't want these cookies getFacebook()->clear_cookie_state(); @@ -95,7 +100,8 @@ class FBConnectauthAction extends Action } else if ($this->arg('connect')) { $this->connectNewUser(); } else { - common_debug(print_r($this->args, true), __FILE__); + common_debug('Facebook Connect Plugin - ' . + print_r($this->args, true)); $this->showForm(_('Something weird happened.'), $this->trimmed('newname')); } @@ -205,7 +211,6 @@ class FBConnectauthAction extends Action function createNewUser() { - if (common_config('site', 'closed')) { $this->clientError(_('Registration not allowed.')); return; @@ -268,7 +273,8 @@ class FBConnectauthAction extends Action common_set_user($user); common_real_login(true); - common_debug("Registered new user $user->id from Facebook user $this->fbuid"); + common_debug('Facebook Connect Plugin - ' . + "Registered new user $user->id from Facebook user $this->fbuid"); common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)), 303); @@ -286,8 +292,9 @@ class FBConnectauthAction extends Action $user = User::staticGet('nickname', $nickname); - if ($user) { - common_debug("Legit user to connect to Facebook: $nickname"); + if (!empty($user)) { + common_debug('Facebook Connect Plugin - ' . + "Legit user to connect to Facebook: $nickname"); } $result = $this->flinkUser($user->id, $this->fbuid); @@ -297,7 +304,8 @@ class FBConnectauthAction extends Action return; } - common_debug("Connected Facebook user $this->fbuid to local user $user->id"); + common_debug('Facebook Connnect Plugin - ' . + "Connected Facebook user $this->fbuid to local user $user->id"); common_set_user($user); common_real_login(true); @@ -311,12 +319,13 @@ class FBConnectauthAction extends Action $result = $this->flinkUser($user->id, $this->fbuid); - if (!$result) { + if (empty($result)) { $this->serverError(_('Error connecting user to Facebook.')); return; } - common_debug("Connected Facebook user $this->fbuid to local user $user->id"); + common_debug('Facebook Connect Plugin - ' . + "Connected Facebook user $this->fbuid to local user $user->id"); // Return to Facebook connection settings tab common_redirect(common_local_url('FBConnectSettings'), 303); @@ -324,16 +333,18 @@ class FBConnectauthAction extends Action function tryLogin() { - common_debug("Trying Facebook Login..."); + common_debug('Facebook Connect Plugin - ' . + "Trying login for Facebook user $this->fbuid."); $flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_CONNECT_SERVICE); - if ($flink) { + if (!empty($flink)) { $user = $flink->getUser(); if (!empty($user)) { - common_debug("Logged in Facebook user $flink->foreign_id as user $user->id ($user->nickname)"); + common_debug('Facebook Connect Plugin - ' . + "Logged in Facebook user $flink->foreign_id as user $user->id ($user->nickname)"); common_set_user($user); common_real_login(true); @@ -342,7 +353,8 @@ class FBConnectauthAction extends Action } else { - common_debug("No flink found for fbuid: $this->fbuid"); + common_debug('Facebook Connect Plugin - ' . + "No flink found for fbuid: $this->fbuid - new user"); $this->showForm(null, $this->bestNewNickname()); } @@ -438,7 +450,8 @@ class FBConnectauthAction extends Action return reset($infos); } catch (Exception $e) { - common_log(LOG_WARNING, "Facebook client failure when requesting " . + common_log(LOG_WARNING, 'Facebook Connect Plugin - ' . + "Facebook client failure when requesting " . join(",", $fields) . " on uid " . $fb_uid . " : ". $e->getMessage()); return null; diff --git a/plugins/FBConnect/FBConnectPlugin.php b/plugins/FBConnect/FBConnectPlugin.php index fd16d2bf1e..c1bd1c0944 100644 --- a/plugins/FBConnect/FBConnectPlugin.php +++ b/plugins/FBConnect/FBConnectPlugin.php @@ -214,7 +214,7 @@ class FBConnectPlugin extends Plugin $fbuid = $facebook->get_loggedin_user(); } catch (Exception $e) { - common_log(LOG_WARNING, + common_log(LOG_WARNING, 'Facebook Connect Plugin - ' . 'Problem getting Facebook user: ' . $e->getMessage()); } @@ -342,7 +342,7 @@ class FBConnectPlugin extends Plugin } function onStartLogout($action) - { +{ $action->logout(); $fbuid = $this->loggedIn(); @@ -351,8 +351,9 @@ class FBConnectPlugin extends Plugin $facebook = getFacebook(); $facebook->expire_session(); } catch (Exception $e) { - common_log(LOG_WARNING, 'Could\'t logout of Facebook: ' . - $e->getMessage()); + common_log(LOG_WARNING, 'Facebook Connect Plugin - ' . + 'Could\'t logout of Facebook: ' . + $e->getMessage()); } } @@ -376,7 +377,8 @@ class FBConnectPlugin extends Plugin } } catch (Exception $e) { - common_log(LOG_WARNING, "Facebook client failure requesting profile pic!"); + common_log(LOG_WARNING, 'Facebook Connect Plugin - ' . + "Facebook client failure requesting profile pic!"); } return $url; diff --git a/plugins/FBConnect/FBConnectSettings.php b/plugins/FBConnect/FBConnectSettings.php index 034ecebae2..d1bea0854e 100644 --- a/plugins/FBConnect/FBConnectSettings.php +++ b/plugins/FBConnect/FBConnectSettings.php @@ -186,9 +186,9 @@ class FBConnectSettingsAction extends ConnectSettingsAction $facebook->clear_cookie_state(); } catch (Exception $e) { - common_log(LOG_WARNING, - 'Couldn\'t clear Facebook cookies: ' . - $e->getMessage()); + common_log(LOG_WARNING, 'Facebook Connect Plugin - ' . + 'Couldn\'t clear Facebook cookies: ' . + $e->getMessage()); } $this->showForm(_('You have disconnected from Facebook.'), true); From f4e4a8dd8a0dab47909b132e1af17739739bb12a Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Tue, 18 Aug 2009 20:40:16 -0400 Subject: [PATCH 05/11] Removed all the redundant logic in common_replace_urls_callback Modified the regex so that strings such as /usr/share/perl5/HTML/Mason/ApacheHandler.pm as not turned into links --- lib/util.php | 90 ++++++++++++---------------------------------------- 1 file changed, 20 insertions(+), 70 deletions(-) diff --git a/lib/util.php b/lib/util.php index 5ecee69156..ba37606789 100644 --- a/lib/util.php +++ b/lib/util.php @@ -412,32 +412,32 @@ function common_render_text($text) function common_replace_urls_callback($text, $callback, $notice_id = null) { // Start off with a regex $regex = '#'. - '(?:'. + '(?:^|\s+)('. '(?:'. '(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|irc)://'. '|'. '(?:mailto|aim|tel|xmpp):'. ')?'. - '('. + '(?:'. '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4 '|(?:'. - '([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,6}|'. //IPv6 - '([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}|'. - '([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}|'. - '([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}|'. - '([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}|'. - '([0-9a-f]{1,4}:){1,6}(:[0-9a-f]{1,4}){1,1}|'. - '(([0-9a-f]{1,4}:){1,7}|:):|'. - ':(:[0-9a-f]{1,4}){1,7}|'. - '((([0-9a-f]{1,4}:){6})(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|'. - '(([0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|'. - '([0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. - '([0-9a-f]{1,4}:){1,1}(:[0-9a-f]{1,4}){1,4}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. - '([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,3}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. - '([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,2}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. - '([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,1}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. - '(([0-9a-f]{1,4}:){1,5}|:):(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. - ':(:[0-9a-f]{1,4}){1,5}:(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}'. + '(?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,6}|'. //IPv6 + '(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|'. + '(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|'. + '(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|'. + '(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|'. + '(?:[0-9a-f]{1,4}:){1,6}(?::[0-9a-f]{1,4}){1,1}|'. + '(?:(?:[0-9a-f]{1,4}:){1,7}|:):|'. + ':(?::[0-9a-f]{1,4}){1,7}|'. + '(?:(?:(?:[0-9a-f]{1,4}:){6})(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|'. + '(?:(?:[0-9a-f]{1,4}:){5}[0-9a-f]{1,4}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})|'. + '(?:[0-9a-f]{1,4}:){5}:[0-9a-f]{1,4}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '(?:[0-9a-f]{1,4}:){1,1}(?::[0-9a-f]{1,4}){1,4}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,3}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,2}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,1}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + '(?:(?:[0-9a-f]{1,4}:){1,5}|:):(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}|'. + ':(?::[0-9a-f]{1,4}){1,5}:(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}'. ')|'. '(?:[^.\s/:]+\.)+'. //DNS '(?:museum|travel|onion|[a-z]{2,4})'. @@ -446,59 +446,9 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) { ')'. '#ix'; preg_match_all($regex, $text, $matches); - // Then clean up what the regex left behind $offset = 0; - foreach($matches[0] as $orig_url) { - $url = htmlspecialchars_decode($orig_url); - - // Make sure we didn't pick up an email address - if (preg_match('#^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$#i', $url)) continue; - - // Remove surrounding punctuation - $url = trim($url, '.?!,;:\'"`([<'); - - // Remove surrounding parens and the like - preg_match('/[)\]>]+$/', $url, $trailing); - if (isset($trailing[0])) { - preg_match_all('/[(\[<]/', $url, $opened); - preg_match_all('/[)\]>]/', $url, $closed); - $unopened = count($closed[0]) - count($opened[0]); - - // Make sure not to take off more closing parens than there are at the end - $unopened = ($unopened > mb_strlen($trailing[0])) ? mb_strlen($trailing[0]):$unopened; - - $url = ($unopened > 0) ? mb_substr($url, 0, $unopened * -1):$url; - } - - // Remove trailing punctuation again (in case there were some inside parens) - $url = rtrim($url, '.?!,;:\'"`'); - - // Make sure we didn't capture part of the next sentence - preg_match('#((?:[^.\s/]+\.)+)(museum|travel|[a-z]{2,4})#i', $url, $url_parts); - - // Were the parts capitalized any? - $last_part = (mb_strtolower($url_parts[2]) !== $url_parts[2]) ? true:false; - $prev_part = (mb_strtolower($url_parts[1]) !== $url_parts[1]) ? true:false; - - // If the first part wasn't cap'd but the last part was, we captured too much - if ((!$prev_part && $last_part)) { - $url = mb_substr($url, 0 , mb_strpos($url, '.'.$url_parts['2'], 0)); - } - - // Capture the new TLD - preg_match('#((?:[^.\s/]+\.)+)(museum|travel|[a-z]{2,4})#i', $url, $url_parts); - - $tlds = array('ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu', 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'er', 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe', 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua', 'ug', 'uk', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm', 'zw'); - - if (!in_array($url_parts[2], $tlds)) continue; - - // Make sure we didn't capture a hash tag - if (strpos($url, '#') === 0) continue; - - // Put the url back the way we found it. - $url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url); - + foreach($matches[1] as $url) { // Call user specified func if (empty($notice_id)) { $modified_url = call_user_func($callback, $url); From d332603c2e7e388f516a9676ca2e05bbbcf500c7 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 18 Aug 2009 17:59:57 -0700 Subject: [PATCH 06/11] Updated Twitter bridge section --- README | 58 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/README b/README index 023061b805..c13e28791d 100644 --- a/README +++ b/README @@ -553,25 +553,53 @@ our kind of hacky home-grown DB-based queue solution. See the "queues" config section below for how to configure to use STOMP. As of this writing, the software has been tested with ActiveMQ ( -Twitter Friends Syncing ------------------------ +Twitter Bridge +-------------- -As of Laconica 0.6.3, users may set a flag in their settings ("Subscribe -to my Twitter friends here" under the Twitter tab) to have Laconica -attempt to locate and subscribe to "friends" (people they "follow") on -Twitter who also have accounts on your Laconica system, and who have -previously set up a link for automatically posting notices to Twitter. +* OAuth -Optionally, there is a script (./scripts/synctwitterfriends.php), meant -to be run periodically from a job scheduler (e.g.: cron under Unix), to -look for new additions to users' friends lists. Note that the friends -syncing only subscribes users to each other, it does not unsubscribe -users when they stop following each other on Twitter. +As of 0.8.1, OAuth is used to to access protected resources on Twitter +instead of HTTP Basic Auth. To use Twitter bridging you will need +to register your instance of Laconica as an application on Twitter +(http://twitter.com/apps), and update the following variables in your +config.php with the consumer key and secret Twitter generates for you: -Sample cron job: + $config['twitter']['consumer_key'] = 'YOURKEY'; + $config['twitter']['consumer_secret'] = 'YOURSECRET'; -# Update Twitter friends subscriptions every half hour -0,30 * * * * /path/to/php /path/to/laconica/scripts/synctwitterfriends.php>&/dev/null +When registering your application with Twitter set the type to "Browser" +and your Callback URL to: + + http://example.org/mublog/twitter/authorization + +The default access type should be, "Read & Write". + +* Importing statuses from Twitter + +To allow your users to import their friends' Twitter statuses, you will +need to enable the bidirectional Twitter bridge in config.php: + + $config['twitterbridge']['enabled'] = true; + +and run the TwitterStatusFetcher daemon (scripts/twitterstatusfetcher.php). +Additionally, you will want to set the integration source variable, +which will keep notices posted to Twitter via Laconica from looping +back. The integration source should be set to the name of your +application, exactly as you specified it on the settings page for your +Laconica application on Twitter, e.g.: + + $config['integration']['source'] = 'YourApp'; + +* Twitter Friends Syncing + +Users may set a flag in their settings ("Subscribe to my Twitter friends +here" under the Twitter tab) to have Laconica attempt to locate and +subscribe to "friends" (people they "follow") on Twitter who also have +accounts on your Laconica system, and who have previously set up a link +for automatically posting notices to Twitter. + +As of 0.8.0, this is no longer accomplished via a cron job. Instead you +must run the SyncTwitterFriends daemon (scripts/synctwitterfreinds.php). Built-in Facebook Application ----------------------------- From b4c345392372ca39e0a5061b281df2074575e9d7 Mon Sep 17 00:00:00 2001 From: Christopher Vollick Date: Wed, 19 Aug 2009 09:22:06 -0400 Subject: [PATCH 07/11] Resolve Group Aliases in showgroup.php For Example, let's say 'alias' was an alias for the group 'group'. Previously, if you went to '/group/group' it'd work, but '/group/alias' it'd say "No Such Group". This was untrue. Now it checks aliases when it can't find a group with a given name. If it finds one it redirects you to the original group. --- actions/showgroup.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/actions/showgroup.php b/actions/showgroup.php index 4d8ba5fa8d..b0cc1dbc7d 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -130,8 +130,18 @@ class ShowgroupAction extends GroupDesignAction $this->group = User_group::staticGet('nickname', $nickname); if (!$this->group) { - $this->clientError(_('No such group'), 404); - return false; + $alias = Group_alias::staticGet('alias', $nickname); + if ($alias) { + $args = array('id' => $alias->group_id); + if ($this->page != 1) { + $args['page'] = $this->page; + } + common_redirect(common_local_url('groupbyid', $args), 301); + return false; + } else { + $this->clientError(_('No such group'), 404); + return false; + } } common_set_returnto($this->selfUrl()); From 986d95b31eeb4a56cb39f308b1e5a5aac2b2d04b Mon Sep 17 00:00:00 2001 From: Francois Marier Date: Thu, 20 Aug 2009 17:46:26 +1200 Subject: [PATCH 08/11] Fix the default value of ['server']['path'] when running from command line scripts The logic in _sn_to_path() doesn't make sense when not running via a remote server. Default to the empty string if running from the command line and ['server']['path'] is not set manually in config.php --- lib/common.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common.php b/lib/common.php index 3fc047af94..6c4b856e00 100644 --- a/lib/common.php +++ b/lib/common.php @@ -82,7 +82,7 @@ if (isset($server)) { if (isset($path)) { $_path = $path; } else { - $_path = array_key_exists('SCRIPT_NAME', $_SERVER) ? + $_path = (array_key_exists('SERVER_NAME', $_SERVER) && array_key_exists('SCRIPT_NAME', $_SERVER)) ? _sn_to_path($_SERVER['SCRIPT_NAME']) : null; } From 418a5a95ab4831ec905dd849fa2632dec24b96da Mon Sep 17 00:00:00 2001 From: Marcel van der Boom Date: Wed, 19 Aug 2009 08:34:17 +0200 Subject: [PATCH 09/11] Change the notice type defines all into class constants and adapt all files. --- actions/shownotice.php | 2 +- classes/Notice.php | 23 ++++++++++++----------- lib/search_engines.php | 2 +- lib/unqueuemanager.php | 4 ++-- lib/util.php | 4 ++-- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/actions/shownotice.php b/actions/shownotice.php index 8f2ffd6b90..fb15dddcfd 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -190,7 +190,7 @@ class ShownoticeAction extends OwnerDesignAction { parent::handle($args); - if ($this->notice->is_local == 0) { + if ($this->notice->is_local == Notice::REMOTE_OMB) { if (!empty($this->notice->url)) { common_redirect($this->notice->url, 301); } else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) { diff --git a/classes/Notice.php b/classes/Notice.php index ebd5e1efd5..442eb00fdb 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -29,10 +29,6 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; define('NOTICE_CACHE_WINDOW', 61); -define('NOTICE_LOCAL_PUBLIC', 1); -define('NOTICE_REMOTE_OMB', 0); -define('NOTICE_LOCAL_NONPUBLIC', -1); - define('MAX_BOXCARS', 128); class Notice extends Memcached_DataObject @@ -62,7 +58,11 @@ class Notice extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - const GATEWAY = -2; + /* Notice types */ + const LOCAL_PUBLIC = 1; + const REMOTE_OMB = 0; + const LOCAL_NONPUBLIC = -1; + const GATEWAY = -2; function getProfile() { @@ -134,7 +134,7 @@ class Notice extends Memcached_DataObject } static function saveNew($profile_id, $content, $source=null, - $is_local=1, $reply_to=null, $uri=null, $created=null) { + $is_local=Notice::LOCAL_PUBLIC, $reply_to=null, $uri=null, $created=null) { $profile = Profile::staticGet($profile_id); @@ -177,7 +177,7 @@ class Notice extends Memcached_DataObject if (($blacklist && in_array($profile_id, $blacklist)) || ($source && $autosource && in_array($source, $autosource))) { - $notice->is_local = -1; + $notice->is_local = Notice::LOCAL_NONPUBLIC; } else { $notice->is_local = $is_local; } @@ -509,7 +509,7 @@ class Notice extends Memcached_DataObject function blowPublicCache($blowLast=false) { - if ($this->is_local == 1) { + if ($this->is_local == Notice::LOCAL_PUBLIC) { $cache = common_memcache(); if ($cache) { $cache->delete(common_cache_key('public')); @@ -775,10 +775,11 @@ class Notice extends Memcached_DataObject } if (common_config('public', 'localonly')) { - $notice->whereAdd('is_local = 1'); + $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC); } else { - # -1 == blacklisted - $notice->whereAdd('is_local != -1'); + # -1 == blacklisted, -2 == gateway (i.e. Twitter) + $notice->whereAdd('is_local !='. Notice::LOCAL_NONPUBLIC); + $notice->whereAdd('is_local !='. Notice::GATEWAY); } if ($since_id != 0) { diff --git a/lib/search_engines.php b/lib/search_engines.php index 772f41883b..7c26363fc5 100644 --- a/lib/search_engines.php +++ b/lib/search_engines.php @@ -120,7 +120,7 @@ class MySQLSearch extends SearchEngine } else if ('identica_notices' === $this->table) { // Don't show imported notices - $this->target->whereAdd('notice.is_local != ' . NOTICE_GATEWAY); + $this->target->whereAdd('notice.is_local != ' . Notice::GATEWAY); if (strtolower($q) != $q) { $this->target->whereAdd("( MATCH(content) AGAINST ('" . addslashes($q) . diff --git a/lib/unqueuemanager.php b/lib/unqueuemanager.php index 5154610725..a10ca339a7 100644 --- a/lib/unqueuemanager.php +++ b/lib/unqueuemanager.php @@ -79,7 +79,7 @@ class UnQueueManager function _isLocal($notice) { - return ($notice->is_local == NOTICE_LOCAL_PUBLIC || - $notice->is_local == NOTICE_LOCAL_NONPUBLIC); + return ($notice->is_local == Notice::LOCAL_PUBLIC || + $notice->is_local == Notice::LOCAL_NONPUBLIC); } } \ No newline at end of file diff --git a/lib/util.php b/lib/util.php index ba37606789..748c8332f0 100644 --- a/lib/util.php +++ b/lib/util.php @@ -854,8 +854,8 @@ function common_enqueue_notice($notice) $transports[] = 'jabber'; } - if ($notice->is_local == NOTICE_LOCAL_PUBLIC || - $notice->is_local == NOTICE_LOCAL_NONPUBLIC) { + if ($notice->is_local == Notice::LOCAL_PUBLIC || + $notice->is_local == Notice::LOCAL_NONPUBLIC) { $transports = array_merge($transports, $localTransports); if ($xmpp) { $transports[] = 'public'; From 0535b439445cdfbbefb4fe2b22d4791260e2adec Mon Sep 17 00:00:00 2001 From: mEDI Date: Tue, 18 Aug 2009 22:55:42 +0200 Subject: [PATCH 10/11] add $config['attachments']['path'] to the config.php.sample --- config.php.sample | 1 + 1 file changed, 1 insertion(+) diff --git a/config.php.sample b/config.php.sample index 1dc123aafe..0fc5163b7a 100644 --- a/config.php.sample +++ b/config.php.sample @@ -261,5 +261,6 @@ $config['sphinx']['port'] = 3312; // $config['attachments']['user_quota'] = 50000000; // $config['attachments']['monthly_quota'] = 15000000; // $config['attachments']['uploads'] = true; +// $config['attachments']['path'] = "/file/"; // $config['oohembed']['endpoint'] = 'http://oohembed.com/oohembed/'; From a8d35451823b01c074d5417a138d4968331a8130 Mon Sep 17 00:00:00 2001 From: Eric Helgeson Date: Thu, 20 Aug 2009 14:25:50 -0500 Subject: [PATCH 11/11] var empty check did not function as expected. made script executable --- scripts/fixup_utf8.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 scripts/fixup_utf8.php diff --git a/scripts/fixup_utf8.php b/scripts/fixup_utf8.php old mode 100644 new mode 100755 index 8c9a9127fd..f952af8d39 --- a/scripts/fixup_utf8.php +++ b/scripts/fixup_utf8.php @@ -42,7 +42,7 @@ class UTF8FixerUpper { $this->args = $args; - if (array_key_exists('max_date', $args)) { + if (!empty($args['max_date'])) { $this->max_date = strftime('%Y-%m-%d %H:%M:%S', strtotime($args['max_date'])); } else { $this->max_date = strftime('%Y-%m-%d %H:%M:%S', time());