mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-03 04:02:43 +01:00
d6b882a804
Summary: Ref T6822. Test Plan: `grep` Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: hach-que, Korvin, epriestley Maniphest Tasks: T6822 Differential Revision: https://secure.phabricator.com/D11370
276 lines
6.8 KiB
PHP
276 lines
6.8 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @task restrictions Domain Restrictions
|
|
* @task email Email About Email
|
|
*/
|
|
final class PhabricatorUserEmail extends PhabricatorUserDAO {
|
|
|
|
protected $userPHID;
|
|
protected $address;
|
|
protected $isVerified;
|
|
protected $isPrimary;
|
|
protected $verificationCode;
|
|
|
|
const MAX_ADDRESS_LENGTH = 128;
|
|
|
|
protected function getConfiguration() {
|
|
return array(
|
|
self::CONFIG_COLUMN_SCHEMA => array(
|
|
'address' => 'sort128',
|
|
'isVerified' => 'bool',
|
|
'isPrimary' => 'bool',
|
|
'verificationCode' => 'text64?',
|
|
),
|
|
self::CONFIG_KEY_SCHEMA => array(
|
|
'address' => array(
|
|
'columns' => array('address'),
|
|
'unique' => true,
|
|
),
|
|
'userPHID' => array(
|
|
'columns' => array('userPHID', 'isPrimary'),
|
|
),
|
|
),
|
|
) + parent::getConfiguration();
|
|
}
|
|
|
|
public function getVerificationURI() {
|
|
return '/emailverify/'.$this->getVerificationCode().'/';
|
|
}
|
|
|
|
public function save() {
|
|
if (!$this->verificationCode) {
|
|
$this->setVerificationCode(Filesystem::readRandomCharacters(24));
|
|
}
|
|
return parent::save();
|
|
}
|
|
|
|
|
|
/* -( Domain Restrictions )------------------------------------------------ */
|
|
|
|
|
|
/**
|
|
* @task restrictions
|
|
*/
|
|
public static function isValidAddress($address) {
|
|
if (strlen($address) > self::MAX_ADDRESS_LENGTH) {
|
|
return false;
|
|
}
|
|
|
|
// Very roughly validate that this address isn't so mangled that a
|
|
// reasonable piece of code might completely misparse it. In particular,
|
|
// the major risks are:
|
|
//
|
|
// - `PhutilEmailAddress` needs to be able to extract the domain portion
|
|
// from it.
|
|
// - Reasonable mail adapters should be hard-pressed to interpret one
|
|
// address as several addresses.
|
|
//
|
|
// To this end, we're roughly verifying that there's some normal text, an
|
|
// "@" symbol, and then some more normal text.
|
|
|
|
$email_regex = '(^[a-z0-9_+.!-]+@[a-z0-9_+:.-]+\z)i';
|
|
if (!preg_match($email_regex, $address)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* @task restrictions
|
|
*/
|
|
public static function describeValidAddresses() {
|
|
return pht(
|
|
"Email addresses should be in the form 'user@domain.com'. The maximum ".
|
|
"length of an email address is %d character(s).",
|
|
new PhutilNumber(self::MAX_ADDRESS_LENGTH));
|
|
}
|
|
|
|
|
|
/**
|
|
* @task restrictions
|
|
*/
|
|
public static function isAllowedAddress($address) {
|
|
if (!self::isValidAddress($address)) {
|
|
return false;
|
|
}
|
|
|
|
$allowed_domains = PhabricatorEnv::getEnvConfig('auth.email-domains');
|
|
if (!$allowed_domains) {
|
|
return true;
|
|
}
|
|
|
|
$addr_obj = new PhutilEmailAddress($address);
|
|
|
|
$domain = $addr_obj->getDomainName();
|
|
if (!$domain) {
|
|
return false;
|
|
}
|
|
|
|
$lower_domain = phutil_utf8_strtolower($domain);
|
|
foreach ($allowed_domains as $allowed_domain) {
|
|
$lower_allowed = phutil_utf8_strtolower($allowed_domain);
|
|
if ($lower_allowed === $lower_domain) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* @task restrictions
|
|
*/
|
|
public static function describeAllowedAddresses() {
|
|
$domains = PhabricatorEnv::getEnvConfig('auth.email-domains');
|
|
if (!$domains) {
|
|
return null;
|
|
}
|
|
|
|
if (count($domains) == 1) {
|
|
return 'Email address must be @'.head($domains);
|
|
} else {
|
|
return 'Email address must be at one of: '.
|
|
implode(', ', $domains);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if this install requires email verification.
|
|
*
|
|
* @return bool True if email addresses must be verified.
|
|
*
|
|
* @task restrictions
|
|
*/
|
|
public static function isEmailVerificationRequired() {
|
|
// NOTE: Configuring required email domains implies required verification.
|
|
return PhabricatorEnv::getEnvConfig('auth.require-email-verification') ||
|
|
PhabricatorEnv::getEnvConfig('auth.email-domains');
|
|
}
|
|
|
|
|
|
/* -( Email About Email )-------------------------------------------------- */
|
|
|
|
|
|
/**
|
|
* Send a verification email from $user to this address.
|
|
*
|
|
* @param PhabricatorUser The user sending the verification.
|
|
* @return this
|
|
* @task email
|
|
*/
|
|
public function sendVerificationEmail(PhabricatorUser $user) {
|
|
$username = $user->getUsername();
|
|
|
|
$address = $this->getAddress();
|
|
$link = PhabricatorEnv::getProductionURI($this->getVerificationURI());
|
|
|
|
|
|
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
|
|
|
$signature = null;
|
|
if (!$is_serious) {
|
|
$signature = <<<EOSIGNATURE
|
|
Get Well Soon,
|
|
Phabricator
|
|
EOSIGNATURE;
|
|
}
|
|
|
|
$body = <<<EOBODY
|
|
Hi {$username},
|
|
|
|
Please verify that you own this email address ({$address}) by clicking this
|
|
link:
|
|
|
|
{$link}
|
|
|
|
{$signature}
|
|
EOBODY;
|
|
|
|
id(new PhabricatorMetaMTAMail())
|
|
->addRawTos(array($address))
|
|
->setForceDelivery(true)
|
|
->setSubject('[Phabricator] Email Verification')
|
|
->setBody($body)
|
|
->setRelatedPHID($user->getPHID())
|
|
->saveAndSend();
|
|
|
|
return $this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Send a notification email from $user to this address, informing the
|
|
* recipient that this is no longer their account's primary address.
|
|
*
|
|
* @param PhabricatorUser The user sending the notification.
|
|
* @param PhabricatorUserEmail New primary email address.
|
|
* @return this
|
|
* @task email
|
|
*/
|
|
public function sendOldPrimaryEmail(
|
|
PhabricatorUser $user,
|
|
PhabricatorUserEmail $new) {
|
|
$username = $user->getUsername();
|
|
|
|
$old_address = $this->getAddress();
|
|
$new_address = $new->getAddress();
|
|
|
|
$body = <<<EOBODY
|
|
Hi {$username},
|
|
|
|
This email address ({$old_address}) is no longer your primary email address.
|
|
Going forward, Phabricator will send all email to your new primary email
|
|
address ({$new_address}).
|
|
|
|
EOBODY;
|
|
|
|
id(new PhabricatorMetaMTAMail())
|
|
->addRawTos(array($old_address))
|
|
->setForceDelivery(true)
|
|
->setSubject('[Phabricator] Primary Address Changed')
|
|
->setBody($body)
|
|
->setFrom($user->getPHID())
|
|
->setRelatedPHID($user->getPHID())
|
|
->saveAndSend();
|
|
}
|
|
|
|
|
|
/**
|
|
* Send a notification email from $user to this address, informing the
|
|
* recipient that this is now their account's new primary email address.
|
|
*
|
|
* @param PhabricatorUser The user sending the verification.
|
|
* @return this
|
|
* @task email
|
|
*/
|
|
public function sendNewPrimaryEmail(PhabricatorUser $user) {
|
|
$username = $user->getUsername();
|
|
|
|
$new_address = $this->getAddress();
|
|
|
|
$body = <<<EOBODY
|
|
Hi {$username},
|
|
|
|
This is now your primary email address ({$new_address}). Going forward,
|
|
Phabricator will send all email here.
|
|
|
|
EOBODY;
|
|
|
|
id(new PhabricatorMetaMTAMail())
|
|
->addRawTos(array($new_address))
|
|
->setForceDelivery(true)
|
|
->setSubject('[Phabricator] Primary Address Changed')
|
|
->setBody($body)
|
|
->setFrom($user->getPHID())
|
|
->setRelatedPHID($user->getPHID())
|
|
->saveAndSend();
|
|
|
|
return $this;
|
|
}
|
|
|
|
}
|