-
-
Notifications
You must be signed in to change notification settings - Fork 946
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
web: provide 'show password' button #10337
Changes from 67 commits
3146e5a
fe52f44
e505f27
5090621
035bda4
2d0117d
22cb5b7
8b4e036
db96e1a
8946b81
30beca9
5d84082
a7e3dca
2d254d6
3f95020
a056703
fc00bde
7123b2c
5d4c380
66cefcc
875fc5c
c84be1d
b08dcc2
272fdc5
23665d1
cacdf64
085debf
f19ed14
ac4ba5d
98503f6
2d94b16
34de6bf
ca42506
2a96900
9acebec
8248163
ee37e92
e1d565d
3d532d4
fffc8c7
3fae9e5
09803fe
5752497
61eb9fa
3ff20ca
5b132c8
2488eb9
312f364
fcab990
10bfc4e
c49185d
7b208d9
75b605f
186e1bf
be9b44a
44e4a5a
833317c
db059d9
fec46df
720f175
e70c5a1
7a4fdc8
5a340a5
492d00d
99fd1a9
587ec68
0b05d43
067d4e4
a6eb120
3bc1a78
7719cfc
c5a65f7
f4c8624
a09afd3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,7 @@ class IdentificationChallenge(Challenge): | |
|
||
user_fields = ListField(child=CharField(), allow_empty=True, allow_null=True) | ||
password_fields = BooleanField() | ||
allow_show_password = BooleanField(default=False) | ||
application_pre = CharField(required=False) | ||
flow_designation = ChoiceField(FlowDesignation.choices) | ||
|
||
|
@@ -199,6 +200,8 @@ def get_challenge(self) -> Challenge: | |
"primary_action": self.get_primary_action(), | ||
"user_fields": current_stage.user_fields, | ||
"password_fields": bool(current_stage.password_stage), | ||
"allow_show_password": bool(current_stage.password_stage) | ||
and current_stage.password_stage.allow_show_password, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't normally argue with |
||
"show_source_labels": current_stage.show_source_labels, | ||
"flow_designation": self.executor.flow.designation, | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Generated by Django 5.0.6 on 2024-07-02 18:14 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("authentik_stages_password", "0008_replace_inbuilt"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="passwordstage", | ||
name="allow_show_password", | ||
field=models.BooleanField( | ||
default=False, | ||
help_text="When enabled, provides a 'show password' button with the password input field.", | ||
), | ||
), | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,13 +5,14 @@ import "@goauthentik/elements/forms/FormElement"; | |
import { BaseStage } from "@goauthentik/flow/stages/base"; | ||
|
||
import { msg, str } from "@lit/localize"; | ||
import { CSSResult, PropertyValues, TemplateResult, css, html, nothing } from "lit"; | ||
import { customElement } from "lit/decorators.js"; | ||
import { CSSResult, PropertyValues, TemplateResult, css, html, nothing, render } from "lit"; | ||
import { customElement, query } from "lit/decorators.js"; | ||
|
||
import PFAlert from "@patternfly/patternfly/components/Alert/alert.css"; | ||
import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||
import PFForm from "@patternfly/patternfly/components/Form/form.css"; | ||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; | ||
import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-group.css"; | ||
import PFLogin from "@patternfly/patternfly/components/Login/login.css"; | ||
import PFTitle from "@patternfly/patternfly/components/Title/title.css"; | ||
import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||
|
@@ -44,23 +45,39 @@ export class IdentificationStage extends BaseStage< | |
> { | ||
form?: HTMLFormElement; | ||
|
||
@query("ak-stage-identification-password") | ||
passwordField!: HTMLInputElement; | ||
|
||
@query("ak-stage-identification-toggle-password-visibility") | ||
visibilityToggle!: HTMLButtonElement; | ||
|
||
static get styles(): CSSResult[] { | ||
return [PFBase, PFAlert, PFLogin, PFForm, PFFormControl, PFTitle, PFButton].concat(css` | ||
return [ | ||
PFBase, | ||
PFAlert, | ||
PFInputGroup, | ||
PFLogin, | ||
PFForm, | ||
PFFormControl, | ||
PFTitle, | ||
PFButton, | ||
/* login page's icons */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although this is in response to my adding PFInputGroup, I moved this comment out of the CSS; there's no reason to ship it with what the user sees. |
||
.pf-c-login__main-footer-links-item button { | ||
background-color: transparent; | ||
border: 0; | ||
display: flex; | ||
align-items: stretch; | ||
} | ||
.pf-c-login__main-footer-links-item img { | ||
fill: var(--pf-c-login__main-footer-links-item-link-svg--Fill); | ||
width: 100px; | ||
max-width: var(--pf-c-login__main-footer-links-item-link-svg--Width); | ||
height: 100%; | ||
max-height: var(--pf-c-login__main-footer-links-item-link-svg--Height); | ||
} | ||
`); | ||
css` | ||
.pf-c-login__main-footer-links-item button { | ||
background-color: transparent; | ||
border: 0; | ||
display: flex; | ||
align-items: stretch; | ||
} | ||
.pf-c-login__main-footer-links-item img { | ||
fill: var(--pf-c-login__main-footer-links-item-link-svg--Fill); | ||
width: 100px; | ||
max-width: var(--pf-c-login__main-footer-links-item-link-svg--Width); | ||
height: 100%; | ||
max-height: var(--pf-c-login__main-footer-links-item-link-svg--Height); | ||
} | ||
`, | ||
]; | ||
} | ||
|
||
updated(changedProperties: PropertyValues<this>) { | ||
|
@@ -70,6 +87,35 @@ export class IdentificationStage extends BaseStage< | |
} | ||
} | ||
|
||
// See `ak-stage-password` for comments and documentation. | ||
togglePasswordVisibility(ev: PointerEvent) { | ||
ev.stopPropagation(); | ||
ev.preventDefault(); | ||
if (!this.passwordField) { | ||
return; | ||
} | ||
this.passwordField.type = this.passwordField.type === "password" ? "text" : "password"; | ||
this.renderPasswordVisibilityFeatures(); | ||
} | ||
|
||
renderPasswordVisibilityFeatures() { | ||
if (!this.visibilityToggle) { | ||
return; | ||
} | ||
const show = this.passwordField.type === "password"; | ||
this.visibilityToggle?.setAttribute( | ||
"aria-label", | ||
show ? msg("Show password") : msg("Hide password"), | ||
); | ||
this.visibilityToggle?.querySelector("i")?.remove(); | ||
render( | ||
show | ||
? html`<i class="fas fa-eye" aria-hidden="true"></i>` | ||
: html`<i class="fas fa-eye-slash" aria-hidden="true"></i>`, | ||
this.visibilityToggle, | ||
); | ||
} | ||
|
||
autoRedirect(): void { | ||
if (!this.challenge) return; | ||
// we only want to auto-redirect to a source if there's only one source | ||
|
@@ -256,15 +302,30 @@ export class IdentificationStage extends BaseStage< | |
class="pf-c-form__group" | ||
.errors=${(this.challenge.responseErrors || {})["password"]} | ||
> | ||
<input | ||
type="password" | ||
name="password" | ||
placeholder="${msg("Password")}" | ||
autocomplete="current-password" | ||
class="pf-c-form-control" | ||
required | ||
value=${PasswordManagerPrefill.password || ""} | ||
/> | ||
<div class="pf-c-input-group"> | ||
<input | ||
id="ak-stage-identification-password" | ||
type="password" | ||
name="password" | ||
placeholder="${msg("Password")}" | ||
autocomplete="current-password" | ||
class="pf-c-form-control" | ||
required | ||
value=${PasswordManagerPrefill.password || ""} | ||
/> | ||
${this.challenge.allowShowPassword | ||
? html` <button | ||
class="pf-c-button pf-m-control" | ||
type="button" | ||
id="ak-stage-identification-toggle-password-visibility" | ||
aria-label=${msg("Show password")} | ||
@click=${(ev: PointerEvent) => | ||
this.togglePasswordVisibility(ev)} | ||
> | ||
<i class="fas fa-eye" aria-hidden="true"></i> | ||
</button>` | ||
: nothing} | ||
</div> | ||
</ak-form-element> | ||
` | ||
: nothing} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Genuinely surprised codespell didn't throw a fit here.