Explorar o código

Show backup code on intermediate confirmation page

Implements https://github.com/composer/packagist/pull/1031#issuecomment-540546934

Also includes a new checkbox icon used for the confirmation button
Colin O'Dell %!s(int64=5) %!d(string=hai) anos
pai
achega
1ab1f28e5d

+ 21 - 1
src/Packagist/WebBundle/Controller/UserController.php

@@ -329,13 +329,33 @@ class UserController extends Controller
                 $this->addFlash('success', 'Two-factor authentication has been enabled.');
                 $this->get('session')->set('backup_code', $backupCode);
 
-                return $this->redirectToRoute('user_2fa_configure', array('name' => $user->getUsername()));
+                return $this->redirectToRoute('user_2fa_confirm', array('name' => $user->getUsername()));
             }
         }
 
         return array('user' => $user, 'provisioningUri' => $authenticator->getQRContent($user), 'secret' => $enableRequest->getSecret(), 'form' => $form->createView());
     }
 
+    /**
+     * @Template()
+     * @Route("/users/{name}/2fa/confirm", name="user_2fa_confirm", methods={"GET"})
+     * @ParamConverter("user", options={"mapping": {"name": "username"}})
+     */
+    public function confirmTwoFactorAuthAction(User $user)
+    {
+        if ($user->getId() !== $this->getUser()->getId()) {
+            throw new AccessDeniedException('You cannot change this user\'s two-factor authentication settings');
+        }
+
+        $backupCode = $this->get('session')->remove('backup_code');
+
+        if (empty($backupCode)) {
+            return $this->redirectToRoute('user_2fa_configure', ['name' => $user->getUsername()]);
+        }
+
+        return array('user' => $user, 'backup_code' => $backupCode);
+    }
+
     /**
      * @Template()
      * @Route("/users/{name}/2fa/disable", name="user_2fa_disable", methods={"GET"})

+ 4 - 0
src/Packagist/WebBundle/Resources/public/css/main.css

@@ -1630,6 +1630,9 @@ svg.chart {
     text-align: center;
     overflow-wrap: break-word;
 }
+.two-factor-backup-code {
+    font-size: 3em;
+}
 
 
 [class^="icon-"]:before,
@@ -1648,6 +1651,7 @@ svg.chart {
     speak: none;
 }
 
+.icon-check:before { content: '\2611'; } /* '☑' */
 .icon-tools:before { content: '\2692'; } /* '⚒' */
 .icon-cogs:before { content: '\26ef'; } /* '⛯' */
 .icon-mail:before { content: '\2709'; } /* '✉' */

+ 6 - 0
src/Packagist/WebBundle/Resources/public/font/config.json

@@ -173,6 +173,12 @@
       "css": "mobile",
       "code": 128241,
       "src": "entypo"
+    },
+    {
+      "uid": "dd6c6b221a1088ff8a9b9cd32d0b3dd5",
+      "css": "check",
+      "code": 9745,
+      "src": "fontawesome"
     }
   ]
 }

BIN=BIN
src/Packagist/WebBundle/Resources/public/font/fontello.eot


+ 2 - 0
src/Packagist/WebBundle/Resources/public/font/fontello.svg

@@ -6,6 +6,8 @@
 <font id="fontello" horiz-adv-x="1000" >
 <font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
 <missing-glyph horiz-adv-x="1000" />
+<glyph glyph-name="check" unicode="&#x2611;" d="M786 331v-177q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q35 0 65-14 9-4 10-13 2-10-5-16l-27-28q-6-5-13-5-1 0-5 1-13 3-25 3h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v141q0 8 5 13l36 35q6 6 13 6 3 0 7-2 11-4 11-16z m129 273l-455-454q-13-14-31-14t-32 14l-240 240q-14 13-14 31t14 32l61 62q14 13 32 13t32-13l147-147 361 361q13 13 31 13t32-13l62-61q13-14 13-32t-13-32z" horiz-adv-x="928.6" />
+
 <glyph glyph-name="tools" unicode="&#x2692;" d="M155 506q-8-8-11-22t-3-25-2-11q-2-2-17-15t-19-17q-16-14-28 4l-70 76q-11 12 2 24 2 2 18 14t20 16q6 6 27 6t37 14q14 14 18 38t10 30q2 0 9 7t26 22 41 31q134 90 186 96 122 0 148-2 12 0-8-8-120-52-152-76-80-56-36-114 34-46 38-48 8-8-2-14-2-2-38-35t-38-35q-14-8-18-4-42 48-71 60t-67-12z m286-26l410-476q18-22-2-38l-48-42q-22-14-38 4l-414 472q-8 8 0 20l72 62q12 8 20-2z m554 202q16-104-16-166-50-88-154-62-56 12-100-32l-82-78-68 78 68 70q24 24 31 53t6 65 5 58q12 56 140 112 12 6 18-3t2-15q-12-12-46-80-14-10-12-35t40-53q58-40 96 22 6 12 26 41t22 33q4 10 13 9t11-17z m-858-684l254 248 76-86-246-242q-20-20-38-4l-46 46q-22 18 0 38z" horiz-adv-x="1000" />
 
 <glyph glyph-name="cogs" unicode="&#x26ef;" d="M0 245l0 97 94 8q8 30 23 55l-60 74 68 69 74-61q26 16 55 23l8 94 97 0 10-94q29-7 55-23l74 61 68-69-60-74q16-25 23-55l94-8 0-97-94-10q-7-29-23-55l60-72-68-70-74 60q-26-15-55-23l-10-94-97 0-8 94q-29 8-55 23l-74-60-68 70 60 72q-15 26-23 55z m221 49q0-37 26-64t64-26 63 26 26 64-26 63-63 26-64-26-26-63z m318 238l8 72 70-2q8 22 20 39l-37 57 54 45 49-49q20 10 41 14l14 66 72-8-2-68q22-8 39-22l57 39 45-54-49-49q10-20 12-43l68-14-8-70-68 0q-8-20-22-37l39-59-56-45-47 49q-22-8-43-12l-14-66-70 6 0 70q-20 8-37 20l-59-37-45 54 49 49q-8 20-12 41z m31-445l6 50 49 0q6 16 14 28l-26 43 37 33 36-37q13 8 29 10l10 48 48-5 0-49q16-6 28-16l41 27 31-41-35-35q6-13 10-29l47-12-6-51-49 0q-4-15-14-27l28-43-40-33-35 37q-13-8-29-10l-10-49-49 6 0 51q-13 4-27 14l-41-28-31 41 35 36q-6 13-8 29z m118 13q-4-21 8-36t32-17 34 9 17 34-10 35-31 18l-6 0q-17 0-31-12t-13-31z m17 451q-4-27 14-48t45-25 48 15 23 45-14 48-44 24l-7 0q-26 0-44-17t-21-42z" horiz-adv-x="1000" />

BIN=BIN
src/Packagist/WebBundle/Resources/public/font/fontello.ttf


BIN=BIN
src/Packagist/WebBundle/Resources/public/font/fontello.woff


+ 53 - 0
src/Packagist/WebBundle/Resources/views/user/confirm_two_factor_auth.html.twig

@@ -0,0 +1,53 @@
+{% extends "PackagistWebBundle:user:packages.html.twig" %}
+
+{% import "PackagistWebBundle::macros.html.twig" as macros %}
+
+{% block content %}
+    {% set isActualUser = app.user and app.user.username is same as(user.username) %}
+
+    <h2 class="title">
+        {{ user.username }}
+        {%- if not isActualUser %}
+            <small>
+                member since: {{ user.createdAt|date('M d, Y') }}
+                {%- if is_granted('ROLE_ADMIN') %}
+                    <a href="mailto:{{ user.email }}">{{ user.email }}</a>
+                {%- endif %}
+            </small>
+        {%- endif %}
+    </h2>
+
+    <section class="row">
+        {% if isActualUser %}
+            <section class="col-md-3">
+                {{ knp_menu_render('profile_menu', {currentClass: 'active', allow_safe_labels: true}) }}
+            </section>
+        {% endif %}
+
+        <section class="col-md-6">
+            <h3>Save your backup code</h3>
+
+            <div class="well well-lg">
+                <p>A backup code will let you access your account if your phone is lost, stolen, or you otherwise can't generate codes via your authenticator app.  We ask that you save this unique, one-time use backup code in a safe place:</p>
+
+                <kbd class="two-factor-backup-code">{{ backup_code }}</kbd>
+
+                <p class="text-danger"><strong>Without access to your authenticator app or backup code, you will permanently lose access to your account.</strong></p>
+
+                <p>To use the backup code, simply enter it during two-factor authentication where you'd normally enter a generated code.</p>
+
+                <p>
+                    Please take a moment to put this code in a safe place.
+                    <strong>This code will not be shown again!</strong>
+                </p>
+            </div>
+
+            <p>
+                <a href="{{path('user_2fa_configure', {name: user.username})}}" class="btn btn-success btn-lg">
+                    <span class="icon-check"></span>
+                    I have saved the backup code
+                </a>
+            </p>
+        </section>
+    </section>
+{% endblock %}