Changeset View
Changeset View
Standalone View
Standalone View
src/applications/auth/factor/PhabricatorAuthFactorTOTP.php
| Show All 16 Lines | return pht( | ||||
| 'authenticate, you will enter a code shown on your phone.'); | 'authenticate, you will enter a code shown on your phone.'); | ||||
| } | } | ||||
| public function processAddFactorForm( | public function processAddFactorForm( | ||||
| AphrontFormView $form, | AphrontFormView $form, | ||||
| AphrontRequest $request, | AphrontRequest $request, | ||||
| PhabricatorUser $user) { | PhabricatorUser $user) { | ||||
| $key = $request->getStr('totpkey'); | $key = $request->getStr('totpkey'); | ||||
| if (!strlen($key)) { | if (!strlen($key)) { | ||||
| // TODO: When the user submits a key, we should require that it be | // TODO: When the user submits a key, we should require that it be | ||||
| // one we generated for them, so there's no way an attacker can ever | // one we generated for them, so there's no way an attacker can ever | ||||
| // force a key they control onto an account. However, it's clumsy to | // force a key they control onto an account. However, it's clumsy to | ||||
| // do this right now. Once we have one-time tokens for SMS and email, | // do this right now. Once we have one-time tokens for SMS and email, | ||||
| // we should be able to put it on that infrastructure. | // we should be able to put it on that infrastructure. | ||||
| $key = self::generateNewTOTPKey(); | $key = self::generateNewTOTPKey(); | ||||
| Show All 30 Lines | $form->appendRemarkupInstructions( | ||||
| pht( | pht( | ||||
| 'First, download an authenticator application on your phone. Two '. | 'First, download an authenticator application on your phone. Two '. | ||||
| 'applications which work well are **Authy** and **Google '. | 'applications which work well are **Authy** and **Google '. | ||||
| 'Authenticator**, but any other TOTP application should also work.')); | 'Authenticator**, but any other TOTP application should also work.')); | ||||
| $form->appendInstructions( | $form->appendInstructions( | ||||
| pht( | pht( | ||||
| 'Launch the application on your phone, and add a new entry for '. | 'Launch the application on your phone, and add a new entry for '. | ||||
| 'this Phabricator install. When prompted, enter the key shown '. | 'this Phabricator install. When prompted, scan the QR code or '. | ||||
| 'below into the application.')); | 'manually enter the key shown below into the application.')); | ||||
| $prod_uri = new PhutilURI(PhabricatorEnv::getProductionURI('/')); | |||||
| $issuer = $prod_uri->getDomain(); | |||||
| $uri = urisprintf( | |||||
| 'otpauth://totp/%s:%s?secret=%s&issuer=%s', | |||||
| $issuer, | |||||
| $user->getUsername(), | |||||
| $key, | |||||
| $issuer); | |||||
| $qrcode = $this->renderQRCode($uri); | |||||
| $form->appendChild($qrcode); | |||||
| $form->appendChild( | $form->appendChild( | ||||
| id(new AphrontFormStaticControl()) | id(new AphrontFormStaticControl()) | ||||
| ->setLabel(pht('Key')) | ->setLabel(pht('Key')) | ||||
| ->setValue(phutil_tag('strong', array(), $key))); | ->setValue(phutil_tag('strong', array(), $key))); | ||||
| $form->appendInstructions( | $form->appendInstructions( | ||||
| pht( | pht( | ||||
| ▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | $code = ((ord($hash[$offset + 0]) & 0x7F) << 24) | | ||||
| ((ord($hash[$offset + 3]) ) ); | ((ord($hash[$offset + 3]) ) ); | ||||
| $code = ($code % 1000000); | $code = ($code % 1000000); | ||||
| $code = str_pad($code, 6, '0', STR_PAD_LEFT); | $code = str_pad($code, 6, '0', STR_PAD_LEFT); | ||||
| return $code; | return $code; | ||||
| } | } | ||||
| /** | |||||
| * @phutil-external-symbol class QRcode | |||||
| */ | |||||
| private function renderQRCode($uri) { | |||||
| $root = dirname(phutil_get_library_root('phabricator')); | |||||
| require_once $root.'/externals/phpqrcode/phpqrcode.php'; | |||||
| $lines = QRcode::text($uri); | |||||
| $total_width = 240; | |||||
| $cell_size = floor($total_width / count($lines)); | |||||
| $rows = array(); | |||||
| foreach ($lines as $line) { | |||||
| $cells = array(); | |||||
| for ($ii = 0; $ii < strlen($line); $ii++) { | |||||
| if ($line[$ii] == '1') { | |||||
| $color = '#000'; | |||||
| } else { | |||||
| $color = '#fff'; | |||||
| } | |||||
| $cells[] = phutil_tag( | |||||
| 'td', | |||||
| array( | |||||
| 'width' => $cell_size, | |||||
| 'height' => $cell_size, | |||||
| 'style' => 'background: '.$color, | |||||
| ), | |||||
| ''); | |||||
| } | |||||
| $rows[] = phutil_tag('tr', array(), $cells); | |||||
| } | |||||
| return phutil_tag( | |||||
| 'table', | |||||
| array( | |||||
| 'style' => 'margin: 24px auto;', | |||||
| ), | |||||
| $rows); | |||||
| } | |||||
btrahan: Well, now I have seen one of those QR things drawn in PHP. | |||||
| } | } | ||||
Well, now I have seen one of those QR things drawn in PHP.