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
- }
- }
-
- // 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;
+ 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;
}
-
- // 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()
$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);
+ }
}
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;
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;
+ }
+
+ 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);
_m('A plugin that maps a single status_network to an email domain.'));
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);
+
+ $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;
+ }
+
+ 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(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;
+ }
+
+ 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);
+
+ $user = User::staticGet('email', $email);
+
+ if (empty($user)) {
+ throw new ClientException(_('No such user.'));
+ }
+ }
}
// The way addPlugin() works, this global variable gets disappeared.
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Log into a site globally
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category DomainStatusNetwork
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @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);
+}
+
+/**
+ * Login to a site
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @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 GlobalApiAction
+{
+ var $password;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $password = $this->trimmed('password');
+
+ if (empty($password)) {
+ throw new ClientException(_('No password.'));
+ }
+
+ $this->password = $password;
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ 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;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Recover a password
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category DomainStatusNetwork
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @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 <evan@status.net>
+ * @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;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Register a user to a site by their email address
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category DomainStatusNetwork
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @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 to globally register a new user
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @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 GlobalApiAction
+{
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+
+ function prepare($argarray)
+ {
+ 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;
+ }
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ function handle($argarray=null)
+ {
+ try {
+ DomainStatusNetworkPlugin::registerEmail($this->email, true);
+ $this->showSuccess();
+ } catch (ClientException $e) {
+ $this->showError($e->getMessage(), $e->getCode());
+ } catch (Exception $e) {
+ common_log(LOG_ERR, $e->getMessage());
+ $this->showError(_('An internal error occurred.'), 500);
+ }
+
+ return;
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Installer class for domain-based multi-homing systems
- *
- * PHP version 5
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @category DomainStatusNetwork
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @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);
-}
-
-/**
- * Installer class for domain-based multi-homing systems
- *
- * @category DomainStatusNetwork
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class DomainStatusNetworkInstaller extends Installer
-{
- protected $domain = null;
- protected $rootname = null;
- protected $sitedb = null;
- protected $rootpass = null;
- protected $nickname = null;
- protected $sn = null;
-
- public $verbose = false;
-
- function __construct($domain)
- {
- $this->domain = $domain;
- }
-
- /**
- * Go for it!
- * @return boolean success
- */
- function main()
- {
- // We don't check prereqs. Check 'em before setting up a
- // multi-home system, kthxbi
- if ($this->prepare()) {
- return $this->handle();
- } else {
- $this->showHelp();
- return false;
- }
- }
-
- /**
- * Get our input parameters...
- * @return boolean success
- */
- function prepare()
- {
- $config = $this->getConfig();
-
- $this->nickname = DomainStatusNetworkPlugin::nicknameForDomain($this->domain);
-
- // XXX make this configurable
-
- $this->sitename = sprintf('The %s Status Network', $this->domain);
-
- $this->server = $this->nickname.'.'.$config['WILDCARD'];
- $this->path = null;
- $this->fancy = true;
-
- $datanick = $this->databaseize($this->nickname);
-
- $this->host = $config['DBHOSTNAME'];
- $this->database = $datanick.$config['DBBASE'];
- $this->dbtype = 'mysql'; // XXX: support others... someday
- $this->username = $datanick.$config['USERBASE'];
-
- // Max size for MySQL
-
- if (strlen($this->username) > 16) {
- $this->username = sprintf('%s%08x', substr($this->username, 0, 8), crc32($this->username));
- }
-
- $pwgen = $config['PWDGEN'];
-
- $password = `$pwgen`;
-
- $this->password = trim($password);
-
- // For setting up the database
-
- $this->rootname = $config['ADMIN'];
- $this->rootpass = $config['ADMINPASS'];
- $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;
- $this->adminPass = null;
- $this->adminEmail = null;
- $this->adminUpdates = null;
-
- /** Should we skip writing the configuration file? */
- $this->skipConfig = true;
-
- if (!$this->validateDb()) {
- return false;
- }
-
- return true;
- }
-
- function handle()
- {
- return $this->doInstall();
- }
-
- function setupDatabase()
- {
- $this->updateStatus('Creating database...');
- $this->createDatabase();
- parent::setupDatabase();
- $this->updateStatus('Creating file directories...');
- $this->createDirectories();
- $this->updateStatus('Saving status network...');
- $this->saveStatusNetwork();
- $this->updateStatus('Checking schema for plugins...');
- $this->checkSchema();
- }
-
- function saveStatusNetwork()
- {
- Status_network::setupDB($this->sitehost,
- $this->rootname,
- $this->rootpass,
- $this->sitedb, array());
-
- $sn = new Status_network();
-
- $sn->nickname = $this->nickname;
- $sn->dbhost = $this->host;
- $sn->dbuser = $this->username;
- $sn->dbpass = $this->password;
- $sn->dbname = $this->database;
- $sn->sitename = $this->sitename;
-
- $result = $sn->insert();
-
- if (!$result) {
- throw new ServerException("Could not create status_network: " . print_r($sn, true));
- }
-
- // Re-fetch; stupid auto-increment integer isn't working
-
- $sn = Status_network::staticGet('nickname', $sn->nickname);
-
- if (empty($sn)) {
- throw new ServerException("Created {$this->nickname} status_network and could not find it again.");
- }
-
- // Set default tags
-
- $tags = $this->tags;
-
- // Add domain tag
-
- $tags[] = 'domain='.$this->domain;
-
- $sn->setTags($tags);
-
- $this->sn = $sn;
- }
-
- function checkSchema()
- {
- $config = $this->getConfig();
-
- Status_network::$wildcard = $config['WILDCARD'];
-
- 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');
- }
-
- function getStatusNetwork()
- {
- return $this->sn;
- }
-
- function createDirectories()
- {
- $config = $this->getConfig();
-
- foreach (array('AVATARBASE', 'BACKGROUNDBASE', 'FILEBASE') as $key) {
- $base = $config[$key];
- $dirname = $base.'/'.$this->nickname;
-
- // Make sure our bits are set
- $mask = umask(0);
- mkdir($dirname, 0770, true);
- umask($mask);
-
- // If you set the setuid bit on your base dirs this should be
- // unnecessary, but just in case. You must be root for this
- // to work.
-
- if (array_key_exists('WEBUSER', $config)) {
- chown($dirname, $config['WEBUSER']);
- }
- if (array_key_exists('WEBGROUP', $config)) {
- chgrp($dirname, $config['WEBGROUP']);
- }
- }
- }
-
- function createDatabase()
- {
- // Create the New DB
- $res = mysql_connect($this->host, $this->rootname, $this->rootpass);
- if (!$res) {
- throw new ServerException("Cannot connect to {$this->host} as {$this->rootname}.");
- }
-
- mysql_query("CREATE DATABASE ". mysql_real_escape_string($this->database), $res);
-
- $return = mysql_select_db($this->database, $res);
-
- if (!$return) {
- throw new ServerException("Unable to connect to {$this->database} on {$this->host}.");
- }
-
- foreach (array('localhost', '%') as $src) {
- mysql_query("GRANT ALL ON " .
- mysql_real_escape_string($this->database).".* TO '" .
- $this->username . "'@'".$src."' ".
- "IDENTIFIED BY '".$this->password."'", $res);
- }
-
- mysql_close($res);
- }
-
- function getConfig()
- {
- static $config;
-
- $cfg_file = "/etc/statusnet/setup.cfg";
-
- if (empty($config)) {
- $result = parse_ini_file($cfg_file);
-
- $config = array();
- foreach ($result as $key => $value) {
- $key = str_replace('export ', '', $key);
- $config[$key] = $value;
- }
- }
-
- return $config;
- }
-
- function showHelp()
- {
- }
-
- function warning($message, $submessage='')
- {
- print $this->html2text($message) . "\n";
- if ($submessage != '') {
- print " " . $this->html2text($submessage) . "\n";
- }
- print "\n";
- }
-
- function updateStatus($status, $error=false)
- {
- if ($this->verbose || $error) {
- if ($error) {
- print "ERROR: ";
- }
- print $this->html2text($status);
- print "\n";
- }
- }
-
- private function html2text($html)
- {
- // break out any links for text legibility
- $breakout = preg_replace('/<a[^>+]\bhref="(.*)"[^>]*>(.*)<\/a>/',
- '\2 <\1>',
- $html);
- return html_entity_decode(strip_tags($breakout), ENT_QUOTES, 'UTF-8');
- }
-
- function databaseize($nickname)
- {
- $nickname = str_replace('-', '_', $nickname);
- return $nickname;
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Installer class for domain-based multi-homing systems
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category DomainStatusNetwork
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @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);
+}
+
+/**
+ * Installer class for domain-based multi-homing systems
+ *
+ * @category DomainStatusNetwork
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class DomainStatusNetworkInstaller extends Installer
+{
+ protected $domain = null;
+ protected $rootname = null;
+ protected $sitedb = null;
+ protected $rootpass = null;
+ protected $nickname = null;
+ protected $sn = null;
+
+ public $verbose = false;
+
+ function __construct($domain)
+ {
+ $this->domain = $domain;
+ }
+
+ /**
+ * Go for it!
+ * @return boolean success
+ */
+ function main()
+ {
+ // We don't check prereqs. Check 'em before setting up a
+ // multi-home system, kthxbi
+ if ($this->prepare()) {
+ return $this->handle();
+ } else {
+ $this->showHelp();
+ return false;
+ }
+ }
+
+ /**
+ * Get our input parameters...
+ * @return boolean success
+ */
+ function prepare()
+ {
+ $config = $this->getConfig();
+
+ $this->nickname = DomainStatusNetworkPlugin::nicknameForDomain($this->domain);
+
+ // XXX make this configurable
+
+ $this->sitename = sprintf('The %s Status Network', $this->domain);
+
+ $this->server = $this->nickname.'.'.$config['WILDCARD'];
+ $this->path = null;
+ $this->fancy = true;
+
+ $datanick = $this->databaseize($this->nickname);
+
+ $this->host = $config['DBHOSTNAME'];
+ $this->database = $datanick.$config['DBBASE'];
+ $this->dbtype = 'mysql'; // XXX: support others... someday
+ $this->username = $datanick.$config['USERBASE'];
+
+ // Max size for MySQL
+
+ if (strlen($this->username) > 16) {
+ $this->username = sprintf('%s%08x', substr($this->username, 0, 8), crc32($this->username));
+ }
+
+ $pwgen = $config['PWDGEN'];
+
+ $password = `$pwgen`;
+
+ $this->password = trim($password);
+
+ // For setting up the database
+
+ $this->rootname = $config['ADMIN'];
+ $this->rootpass = $config['ADMINPASS'];
+ $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;
+ $this->adminPass = null;
+ $this->adminEmail = null;
+ $this->adminUpdates = null;
+
+ /** Should we skip writing the configuration file? */
+ $this->skipConfig = true;
+
+ if (!$this->validateDb()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ function handle()
+ {
+ return $this->doInstall();
+ }
+
+ function setupDatabase()
+ {
+ $this->updateStatus('Creating database...');
+ $this->createDatabase();
+ parent::setupDatabase();
+ $this->updateStatus('Creating file directories...');
+ $this->createDirectories();
+ $this->updateStatus('Saving status network...');
+ $this->saveStatusNetwork();
+ $this->updateStatus('Checking schema for plugins...');
+ $this->checkSchema();
+ }
+
+ function saveStatusNetwork()
+ {
+ Status_network::setupDB($this->sitehost,
+ $this->rootname,
+ $this->rootpass,
+ $this->sitedb, array());
+
+ $sn = new Status_network();
+
+ $sn->nickname = $this->nickname;
+ $sn->dbhost = $this->host;
+ $sn->dbuser = $this->username;
+ $sn->dbpass = $this->password;
+ $sn->dbname = $this->database;
+ $sn->sitename = $this->sitename;
+
+ $result = $sn->insert();
+
+ if (!$result) {
+ throw new ServerException("Could not create status_network: " . print_r($sn, true));
+ }
+
+ // Re-fetch; stupid auto-increment integer isn't working
+
+ $sn = Status_network::staticGet('nickname', $sn->nickname);
+
+ if (empty($sn)) {
+ throw new ServerException("Created {$this->nickname} status_network and could not find it again.");
+ }
+
+ // Set default tags
+
+ $tags = $this->tags;
+
+ // Add domain tag
+
+ $tags[] = 'domain='.$this->domain;
+
+ $sn->setTags($tags);
+
+ $this->sn = $sn;
+ }
+
+ function checkSchema()
+ {
+ $config = $this->getConfig();
+
+ Status_network::$wildcard = $config['WILDCARD'];
+
+ 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');
+ }
+
+ function getStatusNetwork()
+ {
+ return $this->sn;
+ }
+
+ function createDirectories()
+ {
+ $config = $this->getConfig();
+
+ foreach (array('AVATARBASE', 'BACKGROUNDBASE', 'FILEBASE') as $key) {
+ $base = $config[$key];
+ $dirname = $base.'/'.$this->nickname;
+
+ // Make sure our bits are set
+ $mask = umask(0);
+ mkdir($dirname, 0770, true);
+ umask($mask);
+
+ // If you set the setuid bit on your base dirs this should be
+ // unnecessary, but just in case. You must be root for this
+ // to work.
+
+ if (array_key_exists('WEBUSER', $config)) {
+ chown($dirname, $config['WEBUSER']);
+ }
+ if (array_key_exists('WEBGROUP', $config)) {
+ chgrp($dirname, $config['WEBGROUP']);
+ }
+ }
+ }
+
+ function createDatabase()
+ {
+ // Create the New DB
+ $res = mysql_connect($this->host, $this->rootname, $this->rootpass);
+ if (!$res) {
+ throw new ServerException("Cannot connect to {$this->host} as {$this->rootname}.");
+ }
+
+ mysql_query("CREATE DATABASE ". mysql_real_escape_string($this->database), $res);
+
+ $return = mysql_select_db($this->database, $res);
+
+ if (!$return) {
+ throw new ServerException("Unable to connect to {$this->database} on {$this->host}.");
+ }
+
+ foreach (array('localhost', '%') as $src) {
+ mysql_query("GRANT ALL ON " .
+ mysql_real_escape_string($this->database).".* TO '" .
+ $this->username . "'@'".$src."' ".
+ "IDENTIFIED BY '".$this->password."'", $res);
+ }
+
+ mysql_close($res);
+ }
+
+ function getConfig()
+ {
+ static $config;
+
+ $cfg_file = "/etc/statusnet/setup.cfg";
+
+ if (empty($config)) {
+ $result = parse_ini_file($cfg_file);
+
+ $config = array();
+ foreach ($result as $key => $value) {
+ $key = str_replace('export ', '', $key);
+ $config[$key] = $value;
+ }
+ }
+
+ return $config;
+ }
+
+ function showHelp()
+ {
+ }
+
+ function warning($message, $submessage='')
+ {
+ print $this->html2text($message) . "\n";
+ if ($submessage != '') {
+ print " " . $this->html2text($submessage) . "\n";
+ }
+ print "\n";
+ }
+
+ function updateStatus($status, $error=false)
+ {
+ if ($this->verbose || $error) {
+ if ($error) {
+ print "ERROR: ";
+ }
+ print $this->html2text($status);
+ print "\n";
+ }
+ }
+
+ private function html2text($html)
+ {
+ // break out any links for text legibility
+ $breakout = preg_replace('/<a[^>+]\bhref="(.*)"[^>]*>(.*)<\/a>/',
+ '\2 <\1>',
+ $html);
+ return html_entity_decode(strip_tags($breakout), ENT_QUOTES, 'UTF-8');
+ }
+
+ function databaseize($nickname)
+ {
+ $nickname = str_replace('-', '_', $nickname);
+ return $nickname;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * An action that requires an API key
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category DomainStatusNetwork
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @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 <evan@status.net>
+ * @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.'), 403);
+ }
+
+ $apikey = $this->trimmed('apikey');
+
+ if (empty($apikey)) {
+ throw new ClientException(_('No API key.'), 403);
+ }
+
+ $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.'), 403);
+ }
+
+ $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, $code=400)
+ {
+ $this->showOutput(array('error' => $message), $code);
+ }
+
+ function showSuccess($values=null, $code=200)
+ {
+ if (empty($values)) {
+ $values = array();
+ }
+ $values['success'] = 1;
+ $this->showOutput($values, $code);
+ }
+
+ 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");
+ }
+}
$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));
+ $confirmUrl = common_local_url('register', array('code' => $confirm->code));
-print $confirmUrl."\n";
+ print $confirmUrl."\n";
+
+} catch (Exception $e) {
+ print "ERROR: " . $e->getMessage() . "\n";
+}