From 17294a46270edd9716b9df44e495319944943e26 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 6 Jun 2011 12:25:26 -0400 Subject: [PATCH 1/5] move email registration code to DomainStatusNetworkPlugin --- .../DomainStatusNetworkPlugin.php | 26 +++++++++++ .../scripts/installforemail.php | 43 ++++++------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php b/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php index 9390a6e083..68679f53bf 100644 --- a/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php +++ b/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php @@ -195,6 +195,32 @@ class DomainStatusNetworkPlugin extends Plugin _m('A plugin that maps a single status_network to an email domain.')); return true; } + + static function registerEmail($email, $sendWelcome, $template) + { + $domain = self::toDomain($email); + + $sn = self::siteForDomain($domain); + + if (empty($sn)) { + $installer = new DomainStatusNetworkInstaller($domain); + + // Do the thing + $installer->main(); + + $sn = $installer->getStatusNetwork(); + + $config = $installer->getConfig(); + + Status_network::$wildcard = $config['WILDCARD']; + } + + StatusNet::switchSite($sn->nickname); + + $confirm = EmailRegistrationPlugin::registerEmail($email); + + return $confirm; + } } // The way addPlugin() works, this global variable gets disappeared. diff --git a/plugins/DomainStatusNetwork/scripts/installforemail.php b/plugins/DomainStatusNetwork/scripts/installforemail.php index 98ce620c28..f773094a74 100644 --- a/plugins/DomainStatusNetwork/scripts/installforemail.php +++ b/plugins/DomainStatusNetwork/scripts/installforemail.php @@ -39,39 +39,24 @@ require_once INSTALLDIR.'/scripts/commandline.inc'; $email = $args[0]; -$domain = DomainStatusNetworkPlugin::toDomain($email); +$sendWelcome = have_option('w', 'welcome'); -$sn = DomainStatusNetworkPlugin::siteForDomain($domain); - -if (empty($sn)) { - $installer = new DomainStatusNetworkInstaller($domain); - - $installer->verbose = have_option('v', 'verbose'); - - // Do the thing - $installer->main(); - - $sn = $installer->getStatusNetwork(); - - $config = $installer->getConfig(); - - Status_network::$wildcard = $config['WILDCARD']; +if ($sendWelcome && have_option('t', 'template')) { + $template = get_option_value('t', 'template'); } -StatusNet::switchSite($sn->nickname); +try { -$confirm = EmailRegistrationPlugin::registerEmail($email); + $confirm = DomainStatusNetworkPlugin::registerEmail($email); -if (have_option('w', 'welcome')) { - if (have_option('t', 'template')) { - // use the provided template - EmailRegistrationPlugin::sendConfirmEmail($confirm, get_option_value('t', 'template')); - } else { - // use the default template - EmailRegistrationPlugin::sendConfirmEmail($confirm); + if ($sendWelcome) { + EmailRegistrationPlugin::sendConfirmEmail($confirm, $template); } + + $confirmUrl = common_local_url('register', array('code' => $confirm->code)); + + print $confirmUrl."\n"; + +} catch (Exception $e) { + print "ERROR: " . $e->getMessage() . "\n"; } - -$confirmUrl = common_local_url('register', array('code' => $confirm->code)); - -print $confirmUrl."\n"; From 1b0bafc6cc887202b695473eb059747d9524a946 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 7 Jun 2011 11:22:19 -0400 Subject: [PATCH 2/5] Move recoverpassword functionality to User --- actions/recoverpassword.php | 108 ++++-------------------------------- classes/User.php | 93 +++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 96 deletions(-) diff --git a/actions/recoverpassword.php b/actions/recoverpassword.php index 47a947dc0c..8d731cb871 100644 --- a/actions/recoverpassword.php +++ b/actions/recoverpassword.php @@ -273,109 +273,25 @@ class RecoverpasswordAction extends Action function recoverPassword() { $nore = $this->trimmed('nicknameoremail'); + if (!$nore) { // TRANS: Form instructions for password recovery form. $this->showForm(_('Enter a nickname or email address.')); return; } - $user = User::staticGet('email', common_canonical_email($nore)); - - if (!$user) { - try { - $user = User::staticGet('nickname', common_canonical_nickname($nore)); - } catch (NicknameException $e) { - // invalid - } + try { + User::recoverPassword($nore); + $this->mode = 'sent'; + // TRANS: User notification after an e-mail with instructions was sent from the password recovery form. + $this->msg = _('Instructions for recovering your password ' . + 'have been sent to the email address registered to your ' . + 'account.'); + $this->success = true; + $this->showPage(); + } catch (Exception $e) { + $this->success = false; } - - // See if it's an unconfirmed email address - - if (!$user) { - // Warning: it may actually be legit to have multiple folks - // who have claimed, but not yet confirmed, the same address. - // We'll only send to the first one that comes up. - $confirm_email = new Confirm_address(); - $confirm_email->address = common_canonical_email($nore); - $confirm_email->address_type = 'email'; - $confirm_email->find(); - if ($confirm_email->fetch()) { - $user = User::staticGet($confirm_email->user_id); - } else { - $confirm_email = null; - } - } else { - $confirm_email = null; - } - - if (!$user) { - // TRANS: Information on password recovery form if no known username or e-mail address was specified. - $this->showForm(_('No user with that email address or username.')); - return; - } - - // Try to get an unconfirmed email address if they used a user name - - if (!$user->email && !$confirm_email) { - $confirm_email = new Confirm_address(); - $confirm_email->user_id = $user->id; - $confirm_email->address_type = 'email'; - $confirm_email->find(); - if (!$confirm_email->fetch()) { - $confirm_email = null; - } - } - - if (!$user->email && !$confirm_email) { - // TRANS: Client error displayed on password recovery form if a user does not have a registered e-mail address. - $this->clientError(_('No registered email address for that user.')); - return; - } - - // Success! We have a valid user and a confirmed or unconfirmed email address - - $confirm = new Confirm_address(); - $confirm->code = common_confirmation_code(128); - $confirm->address_type = 'recover'; - $confirm->user_id = $user->id; - $confirm->address = (!empty($user->email)) ? $user->email : $confirm_email->address; - - if (!$confirm->insert()) { - common_log_db_error($confirm, 'INSERT', __FILE__); - // TRANS: Server error displayed if e-mail address confirmation fails in the database on the password recovery form. - $this->serverError(_('Error saving address confirmation.')); - return; - } - - // @todo FIXME: needs i18n. - $body = "Hey, $user->nickname."; - $body .= "\n\n"; - $body .= 'Someone just asked for a new password ' . - 'for this account on ' . common_config('site', 'name') . '.'; - $body .= "\n\n"; - $body .= 'If it was you, and you want to confirm, use the URL below:'; - $body .= "\n\n"; - $body .= "\t".common_local_url('recoverpassword', - array('code' => $confirm->code)); - $body .= "\n\n"; - $body .= 'If not, just ignore this message.'; - $body .= "\n\n"; - $body .= 'Thanks for your time, '; - $body .= "\n"; - $body .= common_config('site', 'name'); - $body .= "\n"; - - $headers = _mail_prepare_headers('recoverpassword', $user->nickname, $user->nickname); - // TRANS: Subject for password recovery e-mail. - mail_to_user($user, _('Password recovery requested'), $body, $headers, $confirm->address); - - $this->mode = 'sent'; - // TRANS: User notification after an e-mail with instructions was sent from the password recovery form. - $this->msg = _('Instructions for recovering your password ' . - 'have been sent to the email address registered to your ' . - 'account.'); - $this->success = true; - $this->showPage(); } function resetPassword() diff --git a/classes/User.php b/classes/User.php index 9f79549327..2d1253b7f7 100644 --- a/classes/User.php +++ b/classes/User.php @@ -1008,4 +1008,97 @@ class User extends Memcached_DataObject $skip = array('_profile'); return array_diff($vars, $skip); } + + static function recoverPassword($nore) + { + $user = User::staticGet('email', common_canonical_email($nore)); + + if (!$user) { + try { + $user = User::staticGet('nickname', common_canonical_nickname($nore)); + } catch (NicknameException $e) { + // invalid + } + } + + // See if it's an unconfirmed email address + + if (!$user) { + // Warning: it may actually be legit to have multiple folks + // who have claimed, but not yet confirmed, the same address. + // We'll only send to the first one that comes up. + $confirm_email = new Confirm_address(); + $confirm_email->address = common_canonical_email($nore); + $confirm_email->address_type = 'email'; + $confirm_email->find(); + if ($confirm_email->fetch()) { + $user = User::staticGet($confirm_email->user_id); + } else { + $confirm_email = null; + } + } else { + $confirm_email = null; + } + + if (!$user) { + // TRANS: Information on password recovery form if no known username or e-mail address was specified. + throw new ClientError(_('No user with that email address or username.')); + return; + } + + // Try to get an unconfirmed email address if they used a user name + + if (!$user->email && !$confirm_email) { + $confirm_email = new Confirm_address(); + $confirm_email->user_id = $user->id; + $confirm_email->address_type = 'email'; + $confirm_email->find(); + if (!$confirm_email->fetch()) { + $confirm_email = null; + } + } + + if (!$user->email && !$confirm_email) { + // TRANS: Client error displayed on password recovery form if a user does not have a registered e-mail address. + throw new ClientException(_('No registered email address for that user.')); + return; + } + + // Success! We have a valid user and a confirmed or unconfirmed email address + + $confirm = new Confirm_address(); + $confirm->code = common_confirmation_code(128); + $confirm->address_type = 'recover'; + $confirm->user_id = $user->id; + $confirm->address = (!empty($user->email)) ? $user->email : $confirm_email->address; + + if (!$confirm->insert()) { + common_log_db_error($confirm, 'INSERT', __FILE__); + // TRANS: Server error displayed if e-mail address confirmation fails in the database on the password recovery form. + throw new ServerException(_('Error saving address confirmation.')); + return; + } + + // @todo FIXME: needs i18n. + $body = "Hey, $user->nickname."; + $body .= "\n\n"; + $body .= 'Someone just asked for a new password ' . + 'for this account on ' . common_config('site', 'name') . '.'; + $body .= "\n\n"; + $body .= 'If it was you, and you want to confirm, use the URL below:'; + $body .= "\n\n"; + $body .= "\t".common_local_url('recoverpassword', + array('code' => $confirm->code)); + $body .= "\n\n"; + $body .= 'If not, just ignore this message.'; + $body .= "\n\n"; + $body .= 'Thanks for your time, '; + $body .= "\n"; + $body .= common_config('site', 'name'); + $body .= "\n"; + + $headers = _mail_prepare_headers('recoverpassword', $user->nickname, $user->nickname); + // TRANS: Subject for password recovery e-mail. + mail_to_user($user, _('Password recovery requested'), $body, $headers, $confirm->address); + } } From 59c980cea849c1c7ccae7a70df509c33540d35e4 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 7 Jun 2011 12:06:02 -0400 Subject: [PATCH 3/5] first pass at actions for initializing a network --- .../DomainStatusNetworkPlugin.php | 61 +++++++++ .../actions/globallogin.php | 76 +++++++++++ .../actions/globalregister.php | 118 ++++++++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 plugins/DomainStatusNetwork/actions/globallogin.php create mode 100644 plugins/DomainStatusNetwork/actions/globalregister.php diff --git a/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php b/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php index 68679f53bf..876443aa3f 100644 --- a/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php +++ b/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php @@ -196,6 +196,23 @@ class DomainStatusNetworkPlugin extends Plugin return true; } + static function userExists($email) + { + $domain = self::toDomain($email); + + $sn = self::siteForDomain($domain); + + if (empty($sn)) { + return false; + } + + StatusNet::switchSite($sn->nickname); + + $user = User::staticGet('email', $email); + + return !empty($user); + } + static function registerEmail($email, $sendWelcome, $template) { $domain = self::toDomain($email); @@ -221,6 +238,50 @@ class DomainStatusNetworkPlugin extends Plugin return $confirm; } + + static function login($email, $password) + { + $domain = self::toDomain($email); + + $sn = self::siteForDomain($domain); + + if (empty($sn)) { + throw new ClientException(_("No such site.")); + } + + StatusNet::switchSite($sn->nickname); + + $user = common_check_user($email, $password); + + if (empty($user)) { + // TRANS: Form validation error displayed when trying to log in with incorrect credentials. + throw new ClientException(_('Incorrect username or password.')); + } + + $loginToken = Login_token::makeNew($user); + + if (empty($loginToken)) { + throw new ServerException(_('Cannot log in.')); + } + + $url = common_local_url('otp', array('user_id' => $loginToken->user_id, + 'token' => $loginToken->token)); + + return $url; + } + + static function recoverPassword($email) + { + $domain = self::toDomain($email); + + $sn = self::siteForDomain($domain); + + if (empty($sn)) { + throw new NoSuchUserException(array('email' => $email)); + } + + StatusNet::switchSite($sn->nickname); + } // The way addPlugin() works, this global variable gets disappeared. diff --git a/plugins/DomainStatusNetwork/actions/globallogin.php b/plugins/DomainStatusNetwork/actions/globallogin.php new file mode 100644 index 0000000000..034d719a2f --- /dev/null +++ b/plugins/DomainStatusNetwork/actions/globallogin.php @@ -0,0 +1,76 @@ +. + * + * @category DomainStatusNetwork + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + // This check helps protect against security problems; + // your code file can't be executed directly from the web. + exit(1); +} + +/** + * Class comment + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +class GlobalLoginAction extends Action +{ + /** + * For initializing members of the class. + * + * @param array $argarray misc. arguments + * + * @return boolean true + */ + + function prepare($argarray) + { + parent::prepare($argarray); + return true; + } + + /** + * Handler method + * + * @param array $argarray is ignored since it's now passed in in prepare() + * + * @return void + */ + + function handle($argarray=null) + { + return; + } +} diff --git a/plugins/DomainStatusNetwork/actions/globalregister.php b/plugins/DomainStatusNetwork/actions/globalregister.php new file mode 100644 index 0000000000..ad223808ff --- /dev/null +++ b/plugins/DomainStatusNetwork/actions/globalregister.php @@ -0,0 +1,118 @@ +. + * + * @category DomainStatusNetwork + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + // This check helps protect against security problems; + // your code file can't be executed directly from the web. + exit(1); +} + +/** + * Class comment + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +class GlobalRegisterAction extends Action +{ + /** + * For initializing members of the class. + * + * @param array $argarray misc. arguments + * + * @return boolean true + */ + + function prepare($argarray) + { + parent::prepare($argarray); + return true; + } + + /** + * Handler method + * + * @param array $argarray is ignored since it's now passed in in prepare() + * + * @return void + */ + + function handle($argarray=null) + { + return; + } + + /** + * Return true if read only. + * + * MAY override + * + * @param array $args other arguments + * + * @return boolean is read only action? + */ + + function isReadOnly($args) + { + return false; + } + + /** + * Return last modified, if applicable. + * + * MAY override + * + * @return string last modified http header + */ + function lastModified() + { + // For comparison with If-Last-Modified + // If not applicable, return null + return null; + } + + /** + * Return etag, if applicable. + * + * MAY override + * + * @return string etag http header + */ + + function etag() + { + return null; + } +} From 2d72a64841ebaae889b723d5e259095cdc1b6389 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 10 Jun 2011 15:51:30 -0400 Subject: [PATCH 4/5] First pass at complete global API --- .../DomainStatusNetworkPlugin.php | 33 ++++- .../actions/globallogin.php | 24 +++- .../actions/globalrecover.php | 85 +++++++++++++ .../actions/globalregister.php | 56 ++------- .../domainstatusnetworkinstaller.php | 0 .../lib/globalapiaction.php | 118 ++++++++++++++++++ 6 files changed, 268 insertions(+), 48 deletions(-) create mode 100644 plugins/DomainStatusNetwork/actions/globalrecover.php rename plugins/DomainStatusNetwork/{ => lib}/domainstatusnetworkinstaller.php (100%) create mode 100644 plugins/DomainStatusNetwork/lib/globalapiaction.php diff --git a/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php b/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php index 876443aa3f..efb1aae4d8 100644 --- a/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php +++ b/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php @@ -97,8 +97,16 @@ class DomainStatusNetworkPlugin extends Plugin switch ($cls) { + case 'GlobalregisterAction': + case 'GloballoginAction': + case 'GlobalrecoverAction': + include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; + return false; case 'DomainStatusNetworkInstaller': - include_once $dir . '/' . strtolower($cls) . '.php'; + include_once $dir . '/lib/' . strtolower($cls) . '.php'; + return false; + case 'GlobalApiAction': + include_once $dir . '/lib/' . strtolower($cls) . '.php'; return false; default: return true; @@ -138,6 +146,17 @@ class DomainStatusNetworkPlugin extends Plugin return true; } + function onRouterInitialized($m) + { + if (common_config('globalapi', 'enabled')) { + foreach (array('register', 'login', 'recover') as $method) { + $m->connect('api/statusnet/global/'.$method, + array('action' => 'global'.$method)); + } + } + return true; + } + static function nicknameForDomain($domain) { $registered = self::registeredDomain($domain); @@ -261,12 +280,16 @@ class DomainStatusNetworkPlugin extends Plugin $loginToken = Login_token::makeNew($user); if (empty($loginToken)) { - throw new ServerException(_('Cannot log in.')); + throw new ServerException(sprintf(_('Could not create new login token for user %s'), $user->nickname)); } $url = common_local_url('otp', array('user_id' => $loginToken->user_id, 'token' => $loginToken->token)); + if (empty($url)) { + throw new ServerException(sprintf(_('Could not create new OTP URL for user %s'), $user->nickname)); + } + return $url; } @@ -282,6 +305,12 @@ class DomainStatusNetworkPlugin extends Plugin StatusNet::switchSite($sn->nickname); + $user = User::staticGet('email', $email); + + if (empty($user)) { + throw new ClientException(_('No such user.')); + } + } } // The way addPlugin() works, this global variable gets disappeared. diff --git a/plugins/DomainStatusNetwork/actions/globallogin.php b/plugins/DomainStatusNetwork/actions/globallogin.php index 034d719a2f..f843392f44 100644 --- a/plugins/DomainStatusNetwork/actions/globallogin.php +++ b/plugins/DomainStatusNetwork/actions/globallogin.php @@ -35,7 +35,7 @@ if (!defined('STATUSNET')) { } /** - * Class comment + * Login to a site * * @category Action * @package StatusNet @@ -45,8 +45,10 @@ if (!defined('STATUSNET')) { * @link http://status.net/ */ -class GlobalLoginAction extends Action +class GloballoginAction extends GlobalApiAction { + var $password; + /** * For initializing members of the class. * @@ -58,6 +60,15 @@ class GlobalLoginAction extends Action function prepare($argarray) { parent::prepare($argarray); + + $password = $this->trimmed('password'); + + if (empty($password)) { + throw new ClientException(_('No password.')); + } + + $this->password = $password; + return true; } @@ -71,6 +82,15 @@ class GlobalLoginAction extends Action function handle($argarray=null) { + try { + $url = DomainStatusNetworkPlugin::login($email, $password); + $this->showSuccess(array('url' => $url)); + } catch (ClientException $ce) { + $this->showError($ce->getMessage()); + } catch (Exception $e) { + common_log(LOG_ERR, $e->getMessage()); + $this->showError(_('An internal error occurred.')); + } return; } } diff --git a/plugins/DomainStatusNetwork/actions/globalrecover.php b/plugins/DomainStatusNetwork/actions/globalrecover.php new file mode 100644 index 0000000000..9b688cbe70 --- /dev/null +++ b/plugins/DomainStatusNetwork/actions/globalrecover.php @@ -0,0 +1,85 @@ +. + * + * @category DomainStatusNetwork + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + // This check helps protect against security problems; + // your code file can't be executed directly from the web. + exit(1); +} + +/** + * Recover a password + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +class GlobalrecoverAction extends GlobalApiAction +{ + /** + * For initializing members of the class. + * + * @param array $argarray misc. arguments + * + * @return boolean true + */ + + function prepare($argarray) + { + parent::prepare($argarray); + return true; + } + + /** + * Handler method + * + * @param array $argarray is ignored since it's now passed in in prepare() + * + * @return void + */ + + function handle($argarray=null) + { + try { + DomainStatusNetworkPlugin::recoverPassword($email); + $this->showSuccess(); + } catch (ClientException $ce) { + $this->showError($ce->getMessage()); + } catch (Exception $e) { + common_log(LOG_ERR, $e->getMessage()); + $this->showError(_('An internal error occurred.')); + } + return; + } +} diff --git a/plugins/DomainStatusNetwork/actions/globalregister.php b/plugins/DomainStatusNetwork/actions/globalregister.php index ad223808ff..42dd207f4e 100644 --- a/plugins/DomainStatusNetwork/actions/globalregister.php +++ b/plugins/DomainStatusNetwork/actions/globalregister.php @@ -35,7 +35,7 @@ if (!defined('STATUSNET')) { } /** - * Class comment + * An action to globally register a new user * * @category Action * @package StatusNet @@ -45,7 +45,7 @@ if (!defined('STATUSNET')) { * @link http://status.net/ */ -class GlobalRegisterAction extends Action +class GlobalregisterAction extends GlobalApiAction { /** * For initializing members of the class. @@ -71,48 +71,16 @@ class GlobalRegisterAction extends Action function handle($argarray=null) { + try { + DomainStatusNetworkPlugin::registerEmail($this->email, true); + $this->showSuccess(); + } catch (ClientException $e) { + $this->showError($e->getMessage()); + } catch (Exception $e) { + common_log(LOG_ERR, $e->getMessage()); + $this->showError(_('An internal error occurred.')); + } + return; } - - /** - * Return true if read only. - * - * MAY override - * - * @param array $args other arguments - * - * @return boolean is read only action? - */ - - function isReadOnly($args) - { - return false; - } - - /** - * Return last modified, if applicable. - * - * MAY override - * - * @return string last modified http header - */ - function lastModified() - { - // For comparison with If-Last-Modified - // If not applicable, return null - return null; - } - - /** - * Return etag, if applicable. - * - * MAY override - * - * @return string etag http header - */ - - function etag() - { - return null; - } } diff --git a/plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php b/plugins/DomainStatusNetwork/lib/domainstatusnetworkinstaller.php similarity index 100% rename from plugins/DomainStatusNetwork/domainstatusnetworkinstaller.php rename to plugins/DomainStatusNetwork/lib/domainstatusnetworkinstaller.php diff --git a/plugins/DomainStatusNetwork/lib/globalapiaction.php b/plugins/DomainStatusNetwork/lib/globalapiaction.php new file mode 100644 index 0000000000..ef77d89cfe --- /dev/null +++ b/plugins/DomainStatusNetwork/lib/globalapiaction.php @@ -0,0 +1,118 @@ +. + * + * @category DomainStatusNetwork + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + // This check helps protect against security problems; + // your code file can't be executed directly from the web. + exit(1); +} + +/** + * An action that requires an API key + * + * @category General + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +class GlobalApiAction extends Action +{ + var $email; + + /** + * Check for an API key, and throw an exception if it's not set + * + * @param array $args URL and POST params + * + * @return boolean continuation flag + */ + + function prepare($args) + { + StatusNet::setApi(true); // reduce exception reports to aid in debugging + + parent::prepare($args); + + if (!common_config('globalapi', 'enabled')) { + throw new ClientException(_('Global API not enabled.')); + } + + $apikey = $this->trimmed('apikey'); + + if (empty($apikey)) { + throw new ClientException(_('No API key.')); + } + + $expected = common_config('globalapi', 'key'); + + if ($expected != $apikey) { + // FIXME: increment a counter by IP address to prevent brute-force + // attacks on the key. + throw new ClientException(_('Bad API key.')); + } + + $email = common_canonical_email($this->trimmed('email')); + + if (empty($email)) { + throw new ClientException(_('No email address.')); + } + + if (!Validate::email($email, common_config('email', 'check_domain'))) { + throw new ClientException(_('Invalid email address.')); + } + + $this->email = $email; + + return true; + } + + function showError($message) + { + $this->showOutput(array('error' => $message)); + } + + function showSuccess($values=null) + { + if (empty($values)) { + $values = array(); + } + $values['success'] = 1; + $this->showOutput($values); + } + + function showOutput($values) + { + header('Content-Type: application/json; charset=utf-8'); + print(json_encode($values)); + } +} From 625e63a30340592766029718b3c9e5101eede036 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 10 Jun 2011 16:50:06 -0400 Subject: [PATCH 5/5] Make errors work correctly --- .../DomainStatusNetworkPlugin.php | 9 ++++++ .../actions/globalregister.php | 17 ++++++++--- .../lib/globalapiaction.php | 29 ++++++++++++++----- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php b/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php index efb1aae4d8..a923ac4c30 100644 --- a/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php +++ b/plugins/DomainStatusNetwork/DomainStatusNetworkPlugin.php @@ -157,6 +157,15 @@ class DomainStatusNetworkPlugin extends Plugin return true; } + function onLoginAction($action, &$login) { + $this->debug($action); + if (in_array($action, array('globalregister', 'globallogin', 'globalrecover'))) { + $login = true; + return false; + } + return true; + } + static function nicknameForDomain($domain) { $registered = self::registeredDomain($domain); diff --git a/plugins/DomainStatusNetwork/actions/globalregister.php b/plugins/DomainStatusNetwork/actions/globalregister.php index 42dd207f4e..ed9bfc3c2c 100644 --- a/plugins/DomainStatusNetwork/actions/globalregister.php +++ b/plugins/DomainStatusNetwork/actions/globalregister.php @@ -57,8 +57,17 @@ class GlobalregisterAction extends GlobalApiAction function prepare($argarray) { - parent::prepare($argarray); - return true; + try { + parent::prepare($argarray); + return true; + } catch (ClientException $e) { + $this->showError($e->getMessage(), $e->getCode()); + return false; + } catch (Exception $e) { + common_log(LOG_ERR, $e->getMessage()); + $this->showError(_('An internal error occurred.'), 500); + return false; + } } /** @@ -75,10 +84,10 @@ class GlobalregisterAction extends GlobalApiAction DomainStatusNetworkPlugin::registerEmail($this->email, true); $this->showSuccess(); } catch (ClientException $e) { - $this->showError($e->getMessage()); + $this->showError($e->getMessage(), $e->getCode()); } catch (Exception $e) { common_log(LOG_ERR, $e->getMessage()); - $this->showError(_('An internal error occurred.')); + $this->showError(_('An internal error occurred.'), 500); } return; diff --git a/plugins/DomainStatusNetwork/lib/globalapiaction.php b/plugins/DomainStatusNetwork/lib/globalapiaction.php index ef77d89cfe..cd0c7f9526 100644 --- a/plugins/DomainStatusNetwork/lib/globalapiaction.php +++ b/plugins/DomainStatusNetwork/lib/globalapiaction.php @@ -64,13 +64,13 @@ class GlobalApiAction extends Action parent::prepare($args); if (!common_config('globalapi', 'enabled')) { - throw new ClientException(_('Global API not enabled.')); + throw new ClientException(_('Global API not enabled.'), 403); } $apikey = $this->trimmed('apikey'); if (empty($apikey)) { - throw new ClientException(_('No API key.')); + throw new ClientException(_('No API key.'), 403); } $expected = common_config('globalapi', 'key'); @@ -78,7 +78,7 @@ class GlobalApiAction extends Action if ($expected != $apikey) { // FIXME: increment a counter by IP address to prevent brute-force // attacks on the key. - throw new ClientException(_('Bad API key.')); + throw new ClientException(_('Bad API key.'), 403); } $email = common_canonical_email($this->trimmed('email')); @@ -96,23 +96,36 @@ class GlobalApiAction extends Action return true; } - function showError($message) + function showError($message, $code=400) { - $this->showOutput(array('error' => $message)); + $this->showOutput(array('error' => $message), $code); } - function showSuccess($values=null) + function showSuccess($values=null, $code=200) { if (empty($values)) { $values = array(); } $values['success'] = 1; - $this->showOutput($values); + $this->showOutput($values, $code); } - function showOutput($values) + function showOutput($values, $code) { + if (array_key_exists($code, ClientErrorAction::$status)) { + $status_string = ClientErrorAction::$status[$code]; + } else if (array_key_exists($code, ServerErrorAction::$status)) { + $status_string = ServerErrorAction::$status[$code]; + } else { + // bad code! + $code = 500; + $status_string = ServerErrorAction::$status[$code]; + } + + header('HTTP/1.1 '.$code.' '.$status_string); + header('Content-Type: application/json; charset=utf-8'); print(json_encode($values)); + print("\n"); } }