2FA: Ability to see original QR code again

This commit is contained in:
Noah Petherbridge 2023-11-15 18:01:34 -08:00
parent ebd63bcb0d
commit f0373285eb
3 changed files with 174 additions and 100 deletions

View File

@ -70,6 +70,9 @@ func Setup2FA() http.HandlerFunc {
} }
} }
// Are they (re)viewing their original QR code?
var isPairingSecondDevice bool
// POST form actions. // POST form actions.
if r.Method == http.MethodPost { if r.Method == http.MethodPost {
var intent = r.PostFormValue("intent") var intent = r.PostFormValue("intent")
@ -84,9 +87,16 @@ func Setup2FA() http.HandlerFunc {
// Valid? // Valid?
if !valid { if !valid {
session.FlashError(w, r, "The passcode you submitted didn't seem correct. Try a new six-digit code.") session.FlashError(w, r, "The passcode you submitted didn't seem correct. Try a new six-digit code.")
// If they were reconfiguring a second device, go back to the re-setup screen.
if tf.Enabled {
isPairingSecondDevice = true
break
} else {
templates.Redirect(w, r.URL.Path) templates.Redirect(w, r.URL.Path)
return return
} }
}
// OK! // OK!
tf.Enabled = true tf.Enabled = true
@ -120,13 +130,25 @@ func Setup2FA() http.HandlerFunc {
session.Flash(w, r, "Your 2FA settings have been cleared and disabled.") session.Flash(w, r, "Your 2FA settings have been cleared and disabled.")
} }
} }
case "resetup":
// View the original QR code to set up a new device.
var password = r.PostFormValue("password")
if err := currentUser.CheckPassword(password); err != nil {
session.FlashError(w, r, "Couldn't access your 2FA QR code: the password you entered is incorrect.")
} else {
session.Flash(w, r, "Password accepted. Your 2FA QR code and setup steps will be displayed below.")
isPairingSecondDevice = true
}
default: default:
session.FlashError(w, r, "Unknown intent: %s", intent) session.FlashError(w, r, "Unknown intent: %s", intent)
} }
// All POST requests redirect away except resetup.
if !isPairingSecondDevice {
templates.Redirect(w, r.URL.Path) templates.Redirect(w, r.URL.Path)
return return
} }
}
// Generate the QR code. // Generate the QR code.
qrCode, err := tf.QRCodeAsDataURL(key) qrCode, err := tf.QRCodeAsDataURL(key)
@ -138,6 +160,7 @@ func Setup2FA() http.HandlerFunc {
"TwoFactor": tf, "TwoFactor": tf,
"Key": key, "Key": key,
"QRCode": qrCode, "QRCode": qrCode,
"IsPairingSecondDevice": isPairingSecondDevice,
} }
if err := tmpl.Execute(w, r, vars); err != nil { if err := tmpl.Execute(w, r, vars); err != nil {

View File

@ -134,7 +134,7 @@
{{end}} {{end}}
<!-- New Feature: Two Factor Auth --> <!-- New Feature: Two Factor Auth -->
{{if not .TwoFactorEnabled}} <!--
<div class="card block"> <div class="card block">
<header class="card-header has-background-success-dark"> <header class="card-header has-background-success-dark">
<p class="card-header-title has-text-light"> <p class="card-header-title has-text-light">
@ -162,7 +162,7 @@
</p> </p>
</div> </div>
</div> </div>
{{end}} -->
<div class="card block"> <div class="card block">
<header class="card-header has-background-link"> <header class="card-header has-background-link">

View File

@ -38,7 +38,13 @@
the time-limited six-digit code to log in. the time-limited six-digit code to log in.
</p> </p>
<h4>Backup Codes</h4> <!-- Are they reconfiguring their 2FA app (viewing the barcode)? -->
{{if .IsPairingSecondDevice}}
{{template "2fa-setup" .}}
<hr>
{{end}}
<h4 class="mt-4">Backup Codes</h4>
<p> <p>
In case you lose access to your Authenticator App, please print off or write down these In case you lose access to your Authenticator App, please print off or write down these
@ -72,7 +78,12 @@
</button> </button>
</form> </form>
<h4 class="has-text-danger mt-4">Disable Two-Factor Auth</h4> <hr>
<h4 class="has-text-danger mt-4">
<i class="fa fa-exclamation-triangle mr-1"></i>
Disable Two-Factor Auth
</h4>
<p> <p>
If you wish to <strong>disable</strong> two-factor authentication for your account, please enter If you wish to <strong>disable</strong> two-factor authentication for your account, please enter
@ -95,6 +106,43 @@
Disable Two-Factor Authentication Disable Two-Factor Authentication
</button> </button>
</form> </form>
<hr>
<h4 class="has-text-warning mt-4">
<i class="fa fa-qrcode mr-1"></i>
Set Up Another Device
</h4>
<p>
If you wish to <strong>set up another authenticator device</strong> and view your original
QR code, you may do so by entering your current account password below. This may be useful
if you have bought a new phone or want to migrate your authenticator to a different device,
so that you may access the original QR code and configure the new authenticator.
</p>
<p>
<strong>Note:</strong> this will not change your 2FA security key or backup codes. If you
have lost your old authenticator, it will be more secure to <strong>disable and then set up
2FA from scratch</strong>, which will generate a new secret key and backup codes.
</p>
<form action="{{.Request.URL.Path}}" method="POST">
{{InputCSRF}}
<input type="hidden" name="intent" value="resetup">
<div class="field">
<label class="label" for="password">Your account password:</label>
<input type="password" class="input"
name="password"
placeholder="Password"
required>
</div>
<button type="submit" class="button is-warning">
View my original 2FA QR code
</button>
</form>
</div> </div>
</div> </div>
</div> </div>
@ -144,15 +192,25 @@
setting up your Authenticator App. setting up your Authenticator App.
</p> </p>
<h2>Set up your Authenticator App</h2> {{template "2fa-setup" .}}
</div>
</div>
</div>
</div>
{{end}}<!-- Setup -->
<p> </div>
{{end}}
{{define "2fa-setup"}}
<h2>Set up your Authenticator App</h2>
<p>
To set up Two-Factor Auth, you'll need to download and install a compatible To set up Two-Factor Auth, you'll need to download and install a compatible
Authenticator App on your device. Some suggestions for apps that are compatible Authenticator App on your device. Some suggestions for apps that are compatible
with {{PrettyTitle}} are as follows: with {{PrettyTitle}} are as follows:
</p> </p>
<ul> <ul>
<li> <li>
<strong>Google Authenticator:</strong> <strong>Google Authenticator:</strong>
for <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2" target="_blank"> for <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2" target="_blank">
@ -169,23 +227,23 @@
available for <i class="fab fa-android"></i> Android and <i class="fab fa-apple"></i> iOS available for <i class="fab fa-android"></i> Android and <i class="fab fa-apple"></i> iOS
as well as Windows, macOS and Linux computers. as well as Windows, macOS and Linux computers.
</li> </li>
</ul> </ul>
<h3>Add {{PrettyTitle}} to your Authenticator App</h3> <h3>Add {{PrettyTitle}} to your Authenticator App</h3>
<p> <p>
When you have your Authenticator App ready, click on its "Add a new site" button and scan When you have your Authenticator App ready, click on its "Add a new site" button and scan
the following QR code to enroll your device for {{PrettyTitle}}: the following QR code to enroll your device for {{PrettyTitle}}:
</p> </p>
{{ToHTML .QRCode}} {{ToHTML .QRCode}}
<p> <p>
Alternatively (if you can't scan the QR code), you may copy and paste this secret text Alternatively (if you can't scan the QR code), you may copy and paste this secret text
in to your Authenticator app: in to your Authenticator app:
</p> </p>
<div class="columns is-mobile"> <div class="columns is-mobile">
<div class="column is-half-tablet pr-1"> <div class="column is-half-tablet pr-1">
<input type="text" class="input" <input type="text" class="input"
id="totp-secret" id="totp-secret"
@ -201,21 +259,21 @@
<i class="fa fa-copy mr-1"></i> Copy <i class="fa fa-copy mr-1"></i> Copy
</button> </button>
</div> </div>
</div> </div>
<h3>Test your Authenticator App</h3> <h3>Test your Authenticator App</h3>
<p> <p>
After scanning the QR code (or copying the secret key) into your Authenticator app, you After scanning the QR code (or copying the secret key) into your Authenticator app, you
should be able to generate temporary six-digit authentication codes. should be able to generate temporary six-digit authentication codes.
</p> </p>
<p> <p>
Test that you have enrolled your authenticator correctly by entering the current six-digit Test that you have enrolled your authenticator correctly by entering the current six-digit
code below: code below:
</p> </p>
<form action="{{.Request.URL.Path}}" method="POST"> <form action="{{.Request.URL.Path}}" method="POST">
{{InputCSRF}} {{InputCSRF}}
<input type="hidden" name="intent" value="setup-verify"> <input type="hidden" name="intent" value="setup-verify">
<div class="field"> <div class="field">
@ -232,14 +290,7 @@
</div> </div>
<button type="submit" class="button is-primary">Confirm &amp; Continue</button> <button type="submit" class="button is-primary">Confirm &amp; Continue</button>
</form> </form>
</div>
</div>
</div>
</div>
{{end}}<!-- Setup -->
</div>
{{end}} {{end}}
{{define "scripts"}} {{define "scripts"}}
<script> <script>