Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/auth/controller/email/PhabricatorEmailLoginController.php b/src/applications/auth/controller/email/PhabricatorEmailLoginController.php
index 2fe6d8aa38..4c32a5a4f7 100644
--- a/src/applications/auth/controller/email/PhabricatorEmailLoginController.php
+++ b/src/applications/auth/controller/email/PhabricatorEmailLoginController.php
@@ -1,136 +1,147 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorEmailLoginController extends PhabricatorAuthController {
public function shouldRequireLogin() {
return false;
}
public function processRequest() {
$request = $this->getRequest();
if (!PhabricatorEnv::getEnvConfig('auth.password-auth-enabled')) {
return new Aphront400Response();
}
$e_email = true;
$e_captcha = true;
$errors = array();
if ($request->isFormPost()) {
$e_email = null;
$e_captcha = 'Again';
$captcha_ok = AphrontFormRecaptchaControl::processCaptcha($request);
if (!$captcha_ok) {
$errors[] = "Captcha response is incorrect, try again.";
$e_captcha = 'Invalid';
}
$email = $request->getStr('email');
if (!strlen($email)) {
$errors[] = "You must provide an email address.";
$e_email = 'Required';
}
if (!$errors) {
// NOTE: Don't validate the email unless the captcha is good; this makes
// it expensive to fish for valid email addresses while giving the user
// a better error if they goof their email.
$target_user = id(new PhabricatorUser())->loadOneWhere(
'email = %s',
$email);
if (!$target_user) {
$errors[] = "There is no account associated with that email address.";
$e_email = "Invalid";
}
if (!$errors) {
- $etoken = $target_user->generateEmailToken();
+ $uri = $target_user->getEmailLoginURI();
+ $body = <<<EOBODY
+Condolences on forgetting your password. You can use this link to reset it:
+
+ {$uri}
+
+After you set a new password, consider writing it down on a sticky note and
+attaching it to your monitor so you don't forget again! Choosing a very short,
+easy-to-remember password like "cat" or "1234" might also help.
+
+Best Wishes,
+Phabricator
+
+EOBODY;
$mail = new PhabricatorMetaMTAMail();
$mail->setSubject('[Phabricator] Password Reset');
$mail->setFrom($target_user->getPHID());
$mail->addTos(
array(
$target_user->getPHID(),
));
- $mail->setBody(
- "here is your link ".
- PhabricatorEnv::getURI('/login/etoken/'.$etoken.'/').'?email='.phutil_escape_uri($target_user->getEmail()));
+ $mail->setBody($body);
$mail->saveAndSend();
$view = new AphrontRequestFailureView();
$view->setHeader('Check Your Email');
$view->appendChild(
'<p>An email has been sent with a link you can use to login.</p>');
return $this->buildStandardPageResponse(
$view,
array(
'title' => 'Email Sent',
));
}
}
}
$email_auth = new AphrontFormView();
$email_auth
->setAction('/login/email/')
->setUser($request->getUser())
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Email')
->setName('email')
->setValue($request->getStr('email'))
->setError($e_email))
->appendChild(
id(new AphrontFormRecaptchaControl())
->setLabel('Captcha')
->setError($e_captcha))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Send Email'));
$error_view = null;
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setTitle('Login Error');
$error_view->setErrors($errors);
}
$panel = new AphrontPanelView();
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild('<h1>Forgot Password / Email Login</h1>');
$panel->appendChild($email_auth);
return $this->buildStandardPageResponse(
array(
$error_view,
$panel,
),
array(
'title' => 'Create New Account',
));
}
}
diff --git a/src/applications/auth/controller/email/__init__.php b/src/applications/auth/controller/email/__init__.php
index fbec05c968..1022165205 100644
--- a/src/applications/auth/controller/email/__init__.php
+++ b/src/applications/auth/controller/email/__init__.php
@@ -1,26 +1,25 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/400');
phutil_require_module('phabricator', 'applications/auth/controller/base');
phutil_require_module('phabricator', 'applications/metamta/storage/mail');
phutil_require_module('phabricator', 'applications/people/storage/user');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/recaptcha');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/control/text');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phabricator', 'view/page/failure');
-phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorEmailLoginController.php');
diff --git a/src/applications/people/controller/edit/PhabricatorPeopleEditController.php b/src/applications/people/controller/edit/PhabricatorPeopleEditController.php
index f2b2b68f01..a98563d129 100644
--- a/src/applications/people/controller/edit/PhabricatorPeopleEditController.php
+++ b/src/applications/people/controller/edit/PhabricatorPeopleEditController.php
@@ -1,476 +1,473 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorPeopleEditController extends PhabricatorPeopleController {
public function shouldRequireAdmin() {
return true;
}
private $id;
private $view;
public function willProcessRequest(array $data) {
$this->id = idx($data, 'id');
$this->view = idx($data, 'view');
}
public function processRequest() {
$request = $this->getRequest();
$admin = $request->getUser();
if ($this->id) {
$user = id(new PhabricatorUser())->load($this->id);
if (!$user) {
return new Aphront404Response();
}
} else {
$user = new PhabricatorUser();
}
$views = array(
'basic' => 'Basic Information',
- 'password' => 'Reset Password',
'role' => 'Edit Role',
'cert' => 'Conduit Certificate',
);
if (!$user->getID()) {
$view = 'basic';
} else if (isset($views[$this->view])) {
$view = $this->view;
} else {
$view = 'basic';
}
$content = array();
if ($request->getStr('saved')) {
$notice = new AphrontErrorView();
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
$notice->setTitle('Changed Saved');
$notice->appendChild('<p>Your changes were saved.</p>');
$content[] = $notice;
}
switch ($view) {
case 'basic':
$response = $this->processBasicRequest($user);
break;
- case 'password':
- $response = $this->processPasswordRequest($user);
- break;
case 'role':
$response = $this->processRoleRequest($user);
break;
case 'cert':
$response = $this->processCertificateRequest($user);
break;
}
if ($response instanceof AphrontResponse) {
return $response;
}
$content[] = $response;
if ($user->getID()) {
$side_nav = new AphrontSideNavView();
$side_nav->appendChild($content);
foreach ($views as $key => $name) {
$side_nav->addNavItem(
phutil_render_tag(
'a',
array(
'href' => '/people/edit/'.$user->getID().'/'.$key.'/',
'class' => ($key == $view)
? 'aphront-side-nav-selected'
: null,
),
phutil_escape_html($name)));
}
$content = $side_nav;
}
return $this->buildStandardPageResponse(
$content,
array(
'title' => 'Edit User',
));
}
private function processBasicRequest(PhabricatorUser $user) {
$request = $this->getRequest();
$admin = $request->getUser();
$e_username = true;
$e_realname = true;
$e_email = true;
$errors = array();
+ $welcome_checked = true;
+
$request = $this->getRequest();
if ($request->isFormPost()) {
+ $welcome_checked = $request->getInt('welcome');
+
if (!$user->getID()) {
$user->setUsername($request->getStr('username'));
+ $user->setEmail($request->getStr('email'));
+
+ if ($request->getStr('role') == 'agent') {
+ $user->setIsSystemAgent(true);
+ }
}
$user->setRealName($request->getStr('realname'));
- $user->setEmail($request->getStr('email'));
if (!strlen($user->getUsername())) {
$errors[] = "Username is required.";
$e_username = 'Required';
} else if (!preg_match('/^[a-z0-9]+$/', $user->getUsername())) {
$errors[] = "Username must consist of only numbers and letters.";
$e_username = 'Invalid';
} else {
$e_username = null;
}
if (!strlen($user->getRealName())) {
$errors[] = 'Real name is required.';
$e_realname = 'Required';
} else {
$e_realname = null;
}
if (!strlen($user->getEmail())) {
$errors[] = 'Email is required.';
$e_email = 'Required';
} else {
$e_email = null;
}
if (!$errors) {
try {
+ $is_new = !$user->getID();
+
$user->save();
- $log = PhabricatorUserLog::newLog(
- $admin,
- $user,
- PhabricatorUserLog::ACTION_CREATE);
- $log->save();
+ if ($is_new) {
+ $log = PhabricatorUserLog::newLog(
+ $admin,
+ $user,
+ PhabricatorUserLog::ACTION_CREATE);
+ $log->save();
+
+ if ($welcome_checked) {
+ $admin_username = $admin->getUserName();
+ $admin_realname = $admin->getRealName();
+ $user_username = $user->getUserName();
+
+ $base_uri = PhabricatorEnv::getProductionURI('/');
+
+ $uri = $user->getEmailLoginURI();
+ $body = <<<EOBODY
+Welcome to Phabricator!
+
+{$admin_username} ({$admin_realname}) has created an account for you.
+
+ Username: {$user_username}
+
+To login to Phabricator, follow this link and set a password:
+
+ {$uri}
+
+After you have set a password, you can login in the future by going here:
+
+ {$base_uri}
+
+Love,
+Phabricator
+
+EOBODY;
+ $mail = id(new PhabricatorMetaMTAMail())
+ ->addTos(array($user->getPHID()))
+ ->setSubject('[Phabricator] Welcome to Phabricator')
+ ->setBody($body)
+ ->setFrom($admin->getPHID())
+ ->saveAndSend();
+ }
+ }
$response = id(new AphrontRedirectResponse())
->setURI('/people/edit/'.$user->getID().'/?saved=true');
return $response;
} catch (AphrontQueryDuplicateKeyException $ex) {
$errors[] = 'Username and email must be unique.';
$same_username = id(new PhabricatorUser())
->loadOneWhere('username = %s', $user->getUsername());
$same_email = id(new PhabricatorUser())
->loadOneWhere('email = %s', $user->getEmail());
if ($same_username) {
$e_username = 'Duplicate';
}
if ($same_email) {
$e_email = 'Duplicate';
}
}
}
}
$error_view = null;
if ($errors) {
$error_view = id(new AphrontErrorView())
->setTitle('Form Errors')
->setErrors($errors);
}
$form = new AphrontFormView();
$form->setUser($admin);
if ($user->getID()) {
$form->setAction('/people/edit/'.$user->getID().'/');
} else {
$form->setAction('/people/edit/');
}
if ($user->getID()) {
$is_immutable = true;
} else {
$is_immutable = false;
}
$form
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Username')
->setName('username')
->setValue($user->getUsername())
->setError($e_username)
->setDisabled($is_immutable)
->setCaption('Usernames are permanent and can not be changed later!'))
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Real Name')
->setName('realname')
->setValue($user->getRealName())
->setError($e_realname))
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Email')
->setName('email')
+ ->setDisabled($is_immutable)
->setValue($user->getEmail())
- ->setError($e_email))
+ ->setError($e_email));
+
+ if (!$user->getID()) {
+ $form
+ ->appendChild(
+ id(new AphrontFormSelectControl())
+ ->setLabel('Role')
+ ->setName('role')
+ ->setValue('user')
+ ->setOptions(
+ array(
+ 'user' => 'Normal User',
+ 'agent' => 'System Agent',
+ ))
+ ->setCaption(
+ 'You can create a "system agent" account for bots, scripts, '.
+ 'etc.'))
+ ->appendChild(
+ id(new AphrontFormCheckboxControl())
+ ->addCheckbox(
+ 'welcome',
+ 1,
+ 'Send "Welcome to Phabricator" email.',
+ $welcome_checked));
+ } else {
+ $form->appendChild(
+ id(new AphrontFormStaticControl())
+ ->setLabel('Role')
+ ->setValue(
+ $user->getIsSystemAgent()
+ ? 'System Agent'
+ : 'Normal User'));
+ }
+
+ $form
->appendChild(
id(new AphrontFormSubmitControl())
- ->setValue('Save')
- ->addCancelButton('/people/'));
+ ->setValue('Save'));
$panel = new AphrontPanelView();
if ($user->getID()) {
$panel->setHeader('Edit User');
} else {
$panel->setHeader('Create New User');
}
$panel->appendChild($form);
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
return array($error_view, $panel);
}
- private function processPasswordRequest(PhabricatorUser $user) {
- $request = $this->getRequest();
- $admin = $request->getUser();
-
- $e_password = true;
- $errors = array();
-
- if ($request->isFormPost()) {
- if (strlen($request->getStr('password'))) {
- $user->setPassword($request->getStr('password'));
- $e_password = null;
- } else {
- $errors[] = 'Password is required.';
- $e_password = 'Required';
- }
-
- if (!$errors) {
- $user->save();
-
- $log = PhabricatorUserLog::newLog(
- $admin,
- $user,
- PhabricatorUserLog::ACTION_RESET_PASSWORD);
- $log->save();
-
- return id(new AphrontRedirectResponse())
- ->setURI($request->getRequestURI()->alter('saved', 'true'));
- }
- }
-
- $error_view = null;
- if ($errors) {
- $error_view = id(new AphrontErrorView())
- ->setTitle('Form Errors')
- ->setErrors($errors);
- }
-
-
- $form = id(new AphrontFormView())
- ->setUser($admin)
- ->setAction($request->getRequestURI()->alter('saved', null))
- ->appendChild(
- '<p class="aphront-form-instructions">Submitting this form will '.
- 'change this user\'s password. They will no longer be able to login '.
- 'with their old password.</p>')
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel('New Password')
- ->setName('password')
- ->setError($e_password))
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue('Reset Password'));
-
-
- $panel = new AphrontPanelView();
- $panel->setHeader('Reset Password');
- $panel->setWidth(AphrontPanelView::WIDTH_FORM);
- $panel->appendChild($form);
-
- return array($error_view, $panel);
- }
-
private function processRoleRequest(PhabricatorUser $user) {
$request = $this->getRequest();
$admin = $request->getUser();
$is_self = ($user->getID() == $admin->getID());
$errors = array();
if ($request->isFormPost()) {
$log_template = PhabricatorUserLog::newLog(
$admin,
$user,
null);
$logs = array();
if ($is_self) {
$errors[] = "You can not edit your own role.";
} else {
$new_admin = (bool)$request->getBool('is_admin');
$old_admin = (bool)$user->getIsAdmin();
if ($new_admin != $old_admin) {
$log = clone $log_template;
$log->setAction(PhabricatorUserLog::ACTION_ADMIN);
$log->setOldValue($old_admin);
$log->setNewValue($new_admin);
$user->setIsAdmin($new_admin);
$logs[] = $log;
}
$new_disabled = (bool)$request->getBool('is_disabled');
$old_disabled = (bool)$user->getIsDisabled();
if ($new_disabled != $old_disabled) {
$log = clone $log_template;
$log->setAction(PhabricatorUserLog::ACTION_DISABLE);
$log->setOldValue($old_disabled);
$log->setNewValue($new_disabled);
$user->setIsDisabled($new_disabled);
$logs[] = $log;
}
-
- $new_agent = (bool)$request->getBool('is_agent');
- $old_agent = (bool)$user->getIsSystemAgent();
- if ($new_agent != $old_agent) {
- // TODO: Get rid of this, move it to the create flow.
- $user->setIsSystemAgent($new_agent);
- }
}
if (!$errors) {
$user->save();
foreach ($logs as $log) {
$log->save();
}
return id(new AphrontRedirectResponse())
->setURI($request->getRequestURI()->alter('saved', 'true'));
}
}
$error_view = null;
if ($errors) {
$error_view = id(new AphrontErrorView())
->setTitle('Form Errors')
->setErrors($errors);
}
$form = id(new AphrontFormView())
->setUser($admin)
->setAction($request->getRequestURI()->alter('saved', null));
if ($is_self) {
$form->appendChild(
'<p class="aphront-form-instructions">NOTE: You can not edit your own '.
'role.</p>');
}
$form
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'is_admin',
1,
'Admin: wields absolute power.',
$user->getIsAdmin())
->setDisabled($is_self))
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'is_disabled',
1,
'Disabled: can not login.',
$user->getIsDisabled())
- ->setDisabled($is_self))
- ->appendChild(
- id(new AphrontFormCheckboxControl())
- ->addCheckbox(
- 'is_agent',
- 1,
- 'Agent: system agent (robot).',
- $user->getIsSystemAgent())
->setDisabled($is_self));
if (!$is_self) {
$form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Edit Role'));
}
$panel = new AphrontPanelView();
$panel->setHeader('Edit Role');
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild($form);
return array($error_view, $panel);
}
private function processCertificateRequest($user) {
$request = $this->getRequest();
$admin = $request->getUser();
$form = new AphrontFormView();
$form
->setUser($admin)
->setAction($request->getRequestURI())
->appendChild(
'<p class="aphront-form-instructions">You can use this certificate '.
'to write scripts or bots which interface with Phabricator over '.
'Conduit.</p>');
if ($user->getIsSystemAgent()) {
$form
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Username')
->setValue($user->getUsername()))
->appendChild(
id(new AphrontFormTextAreaControl())
->setLabel('Certificate')
->setValue($user->getConduitCertificate()));
} else {
$form->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Certificate')
->setValue(
- 'You may only view the certificates for System Agents. Mark '.
- 'this account as a "system agent" in the "Edit Role" tab to '.
- 'view the corresponding certificate.'));
+ 'You may only view the certificates of System Agents.'));
}
$panel = new AphrontPanelView();
$panel->setHeader('Conduit Certificate');
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild($form);
return array($panel);
}
}
diff --git a/src/applications/people/controller/edit/__init__.php b/src/applications/people/controller/edit/__init__.php
index 5c631230d4..b64ccccd5c 100644
--- a/src/applications/people/controller/edit/__init__.php
+++ b/src/applications/people/controller/edit/__init__.php
@@ -1,28 +1,31 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/redirect');
+phutil_require_module('phabricator', 'applications/metamta/storage/mail');
phutil_require_module('phabricator', 'applications/people/controller/base');
phutil_require_module('phabricator', 'applications/people/storage/log');
phutil_require_module('phabricator', 'applications/people/storage/user');
+phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/checkbox');
+phutil_require_module('phabricator', 'view/form/control/select');
phutil_require_module('phabricator', 'view/form/control/static');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/control/text');
phutil_require_module('phabricator', 'view/form/control/textarea');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phabricator', 'view/layout/sidenav');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorPeopleEditController.php');
diff --git a/src/applications/people/storage/user/PhabricatorUser.php b/src/applications/people/storage/user/PhabricatorUser.php
index a1f9ef916b..ab88cdc35e 100644
--- a/src/applications/people/storage/user/PhabricatorUser.php
+++ b/src/applications/people/storage/user/PhabricatorUser.php
@@ -1,293 +1,300 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorUser extends PhabricatorUserDAO {
const SESSION_TABLE = 'phabricator_session';
protected $phid;
protected $userName;
protected $realName;
protected $email;
protected $passwordSalt;
protected $passwordHash;
protected $profileImagePHID;
protected $consoleEnabled = 0;
protected $consoleVisible = 0;
protected $consoleTab = '';
protected $conduitCertificate;
protected $isSystemAgent = 0;
protected $isAdmin = 0;
protected $isDisabled = 0;
private $preferences = null;
public function getProfileImagePHID() {
return nonempty(
$this->profileImagePHID,
PhabricatorEnv::getEnvConfig('user.default-profile-image-phid'));
}
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PhabricatorPHIDConstants::PHID_TYPE_USER);
}
public function setPassword($password) {
if (!$this->getPHID()) {
throw new Exception(
"You can not set a password for an unsaved user because their PHID ".
"is a salt component in the password hash.");
}
if (!strlen($password)) {
$this->setPasswordHash('');
} else {
$this->setPasswordSalt(md5(mt_rand()));
$hash = $this->hashPassword($password);
$this->setPasswordHash($hash);
}
return $this;
}
public function save() {
if (!$this->conduitCertificate) {
$this->conduitCertificate = $this->generateConduitCertificate();
}
return parent::save();
}
private function generateConduitCertificate() {
$entropy = Filesystem::readRandomBytes(256);
$entropy = base64_encode($entropy);
$entropy = substr($entropy, 0, 255);
return $entropy;
}
public function comparePassword($password) {
if (!strlen($password)) {
return false;
}
if (!strlen($this->getPasswordHash())) {
return false;
}
$password = $this->hashPassword($password);
return ($password === $this->getPasswordHash());
}
private function hashPassword($password) {
$password = $this->getUsername().
$password.
$this->getPHID().
$this->getPasswordSalt();
for ($ii = 0; $ii < 1000; $ii++) {
$password = md5($password);
}
return $password;
}
const CSRF_CYCLE_FREQUENCY = 3600;
const CSRF_TOKEN_LENGTH = 16;
const EMAIL_CYCLE_FREQUENCY = 86400;
const EMAIL_TOKEN_LENGTH = 24;
public function getCSRFToken($offset = 0) {
return $this->generateToken(
time() + (self::CSRF_CYCLE_FREQUENCY * $offset),
self::CSRF_CYCLE_FREQUENCY,
PhabricatorEnv::getEnvConfig('phabricator.csrf-key'),
self::CSRF_TOKEN_LENGTH);
}
public function validateCSRFToken($token) {
for ($ii = -1; $ii <= 1; $ii++) {
$valid = $this->getCSRFToken($ii);
if ($token == $valid) {
return true;
}
}
return false;
}
private function generateToken($epoch, $frequency, $key, $len) {
$time_block = floor($epoch / $frequency);
$vec = $this->getPHID().$this->passwordHash.$key.$time_block;
return substr(sha1($vec), 0, $len);
}
/**
* Issue a new session key to this user. Phabricator supports different
* types of sessions (like "web" and "conduit") and each session type may
* have multiple concurrent sessions (this allows a user to be logged in on
* multiple browsers at the same time, for instance).
*
* Note that this method is transport-agnostic and does not set cookies or
* issue other types of tokens, it ONLY generates a new session key.
*
* You can configure the maximum number of concurrent sessions for various
* session types in the Phabricator configuration.
*
* @param string Session type, like "web".
* @return string Newly generated session key.
*/
public function establishSession($session_type) {
$conn_w = $this->establishConnection('w');
if (strpos($session_type, '-') !== false) {
throw new Exception("Session type must not contain hyphen ('-')!");
}
// We allow multiple sessions of the same type, so when a caller requests
// a new session of type "web", we give them the first available session in
// "web-1", "web-2", ..., "web-N", up to some configurable limit. If none
// of these sessions is available, we overwrite the oldest session and
// reissue a new one in its place.
$session_limit = 1;
switch ($session_type) {
case 'web':
$session_limit = PhabricatorEnv::getEnvConfig('auth.sessions.web');
break;
case 'conduit':
$session_limit = PhabricatorEnv::getEnvConfig('auth.sessions.conduit');
break;
default:
throw new Exception("Unknown session type '{$session_type}'!");
}
$session_limit = (int)$session_limit;
if ($session_limit <= 0) {
throw new Exception(
"Session limit for '{$session_type}' must be at least 1!");
}
// Load all the currently active sessions.
$sessions = queryfx_all(
$conn_w,
'SELECT type, sessionStart FROM %T WHERE userPHID = %s AND type LIKE %>',
PhabricatorUser::SESSION_TABLE,
$this->getPHID(),
$session_type.'-');
// Choose which 'type' we'll actually establish, i.e. what number we're
// going to append to the basic session type. To do this, just check all
// the numbers sequentially until we find an available session.
$establish_type = null;
$sessions = ipull($sessions, null, 'type');
for ($ii = 1; $ii <= $session_limit; $ii++) {
if (empty($sessions[$session_type.'-'.$ii])) {
$establish_type = $session_type.'-'.$ii;
break;
}
}
// If we didn't find an available session, choose the oldest session and
// overwrite it.
if (!$establish_type) {
$sessions = isort($sessions, 'sessionStart');
$oldest = reset($sessions);
$establish_type = $oldest['type'];
}
// Consume entropy to generate a new session key, forestalling the eventual
// heat death of the universe.
$entropy = Filesystem::readRandomBytes(20);
$session_key = sha1($entropy);
queryfx(
$conn_w,
'INSERT INTO %T '.
'(userPHID, type, sessionKey, sessionStart)'.
' VALUES '.
'(%s, %s, %s, UNIX_TIMESTAMP()) '.
'ON DUPLICATE KEY UPDATE '.
'sessionKey = VALUES(sessionKey), '.
'sessionStart = VALUES(sessionStart)',
self::SESSION_TABLE,
$this->getPHID(),
$establish_type,
$session_key);
$log = PhabricatorUserLog::newLog(
$this,
$this,
PhabricatorUserLog::ACTION_LOGIN);
$log->setDetails(
array(
'session_type' => $session_type,
'session_issued' => $establish_type,
));
$log->setSession($session_key);
$log->save();
return $session_key;
}
- public function generateEmailToken($offset = 0) {
+ private function generateEmailToken($offset = 0) {
return $this->generateToken(
time() + ($offset * self::EMAIL_CYCLE_FREQUENCY),
self::EMAIL_CYCLE_FREQUENCY,
PhabricatorEnv::getEnvConfig('phabricator.csrf-key').$this->getEmail(),
self::EMAIL_TOKEN_LENGTH);
}
public function validateEmailToken($token) {
for ($ii = -1; $ii <= 1; $ii++) {
$valid = $this->generateEmailToken($ii);
if ($token == $valid) {
return true;
}
}
return false;
}
+ public function getEmailLoginURI() {
+ $token = $this->generateEmailToken();
+ $uri = PhabricatorEnv::getProductionURI('/login/etoken/'.$token.'/');
+ $uri = new PhutilURI($uri);
+ return $uri->alter('email', $this->getEmail());
+ }
+
public function loadPreferences() {
if ($this->preferences) {
return $this->preferences;
}
$preferences = id(new PhabricatorUserPreferences())->loadOneWhere(
'userPHID = %s',
$this->getPHID());
if (!$preferences) {
$preferences = new PhabricatorUserPreferences();
$preferences->setUserPHID($this->getPHID());
$default_dict = array(
PhabricatorUserPreferences::PREFERENCE_TITLES => 'glyph',
PhabricatorUserPreferences::PREFERENCE_MONOSPACED => '');
$preferences->setPreferences($default_dict);
}
$this->preferences = $preferences;
return $preferences;
}
}
diff --git a/src/applications/people/storage/user/__init__.php b/src/applications/people/storage/user/__init__.php
index e3a2672545..c75b225dbb 100644
--- a/src/applications/people/storage/user/__init__.php
+++ b/src/applications/people/storage/user/__init__.php
@@ -1,21 +1,22 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/people/storage/base');
phutil_require_module('phabricator', 'applications/people/storage/log');
phutil_require_module('phabricator', 'applications/people/storage/preferences');
phutil_require_module('phabricator', 'applications/phid/constants');
phutil_require_module('phabricator', 'applications/phid/storage/phid');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phutil', 'filesystem');
+phutil_require_module('phutil', 'parser/uri');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorUser.php');

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 3, 3:43 PM (5 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
165984
Default Alt Text
(34 KB)

Event Timeline