mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-04 20:52:43 +01:00
7805b217ad
Summary: Depends on D20022. Ref T13222. Since you can easily lock yourself out of your account by swapping to a bad number, prevent contact number edits while "contact number" MFA (today, always SMS) is enabled. (Another approach would be to bind factors to specific contact numbers, and then prevent that number from being edited or disabled while SMS MFA was attached to it. However, I think that's a bit more complicated and a little more unwieldy, and ends up in about the same place as this. I'd consider it more strongly in the future if we had like 20 users say "I have 9 phones" but I doubt this is a real use case.) Test Plan: - With SMS MFA, tried to edit my primary contact number, disable it, and promote another number to become primary. Got a sensible error message in all cases. - After removing SMS MFA, did all that stuff with no issues. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13222 Differential Revision: https://secure.phabricator.com/D20023
96 lines
2.5 KiB
PHP
96 lines
2.5 KiB
PHP
<?php
|
|
|
|
final class PhabricatorAuthContactNumberNumberTransaction
|
|
extends PhabricatorAuthContactNumberTransactionType {
|
|
|
|
const TRANSACTIONTYPE = 'number';
|
|
|
|
public function generateOldValue($object) {
|
|
return $object->getContactNumber();
|
|
}
|
|
|
|
public function generateNewValue($object, $value) {
|
|
$number = new PhabricatorPhoneNumber($value);
|
|
return $number->toE164();
|
|
}
|
|
|
|
public function applyInternalEffects($object, $value) {
|
|
$object->setContactNumber($value);
|
|
}
|
|
|
|
public function getTitle() {
|
|
$old = $this->getOldValue();
|
|
$new = $this->getNewValue();
|
|
|
|
return pht(
|
|
'%s changed this contact number from %s to %s.',
|
|
$this->renderAuthor(),
|
|
$this->renderOldValue(),
|
|
$this->renderNewValue());
|
|
}
|
|
|
|
public function validateTransactions($object, array $xactions) {
|
|
$errors = array();
|
|
|
|
$current_value = $object->getContactNumber();
|
|
if ($this->isEmptyTextTransaction($current_value, $xactions)) {
|
|
$errors[] = $this->newRequiredError(
|
|
pht('Contact numbers must have a contact number.'));
|
|
return $errors;
|
|
}
|
|
|
|
$max_length = $object->getColumnMaximumByteLength('contactNumber');
|
|
foreach ($xactions as $xaction) {
|
|
$new_value = $xaction->getNewValue();
|
|
$new_length = strlen($new_value);
|
|
if ($new_length > $max_length) {
|
|
$errors[] = $this->newInvalidError(
|
|
pht(
|
|
'Contact numbers can not be longer than %s characters.',
|
|
new PhutilNumber($max_length)),
|
|
$xaction);
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
new PhabricatorPhoneNumber($new_value);
|
|
} catch (Exception $ex) {
|
|
$errors[] = $this->newInvalidError(
|
|
pht(
|
|
'Contact number is invalid: %s',
|
|
$ex->getMessage()),
|
|
$xaction);
|
|
continue;
|
|
}
|
|
|
|
$new_value = $this->generateNewValue($object, $new_value);
|
|
|
|
$unique_key = id(clone $object)
|
|
->setContactNumber($new_value)
|
|
->newUniqueKey();
|
|
|
|
$other = id(new PhabricatorAuthContactNumberQuery())
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
->withUniqueKeys(array($unique_key))
|
|
->executeOne();
|
|
|
|
if ($other) {
|
|
if ($other->getID() !== $object->getID()) {
|
|
$errors[] = $this->newInvalidError(
|
|
pht('Contact number is already in use.'),
|
|
$xaction);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$mfa_error = $this->newContactNumberMFAError($object, $xaction);
|
|
if ($mfa_error) {
|
|
$errors[] = $mfa_error;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
}
|