This commit is contained in:
Lorenzo Maturano 2026-08-10 21:01:04 -03:00 committed by GitHub
commit 96dca3007e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 30 additions and 4 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
(()=>{"use strict";var e,v={},m={};function r(e){var o=m[e];if(void 0!==o)return o.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(o,t,i,f)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,f]=e[n],s=!0,u=0;u<t.length;u++)(!1&f||a>=f)&&Object.keys(r.O).every(b=>r.O[b](t[u]))?t.splice(u--,1):(s=!1,f<a&&(a=f));if(s){e.splice(n--,1);var d=i();void 0!==d&&(o=d)}}return o}f=f||0;for(var n=e.length;n>0&&e[n-1][2]>f;n--)e[n]=e[n-1];e[n]=[t,i,f]},r.d=(e,o)=>{for(var t in o)r.o(o,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:o[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((o,t)=>(r.f[t](e,o),o),[])),r.u=e=>e+"."+{17:"da5e0b6abb96d103",190:"0e6572086349bd7c",193:"5eec0042e2c6f1a7",853:"e46ed60b577aec33"}[e]+".js",r.miniCssF=e=>{},r.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),(()=>{var e={},o="RTLApp:";r.l=(t,i,f,n)=>{if(e[t])e[t].push(i);else{var a,s;if(void 0!==f)for(var u=document.getElementsByTagName("script"),d=0;d<u.length;d++){var l=u[d];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==o+f){a=l;break}}a||(s=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",o+f),a.src=r.tu(t)),e[t]=[i];var c=(h,b)=>{a.onerror=a.onload=null,clearTimeout(p);var g=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),g&&g.forEach(_=>_(b)),h)return h(b)},p=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),s&&document.head.appendChild(a)}}})(),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:o=>o},typeof trustedTypes<"u"&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={121:0};r.f.j=(i,f)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)f.push(n[2]);else if(121!=i){var a=new Promise((l,c)=>n=e[i]=[l,c]);f.push(n[2]=a);var s=r.p+r.u(i),u=new Error;r.l(s,l=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var c=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;u.message="Loading chunk "+i+" failed.\n("+c+": "+p+")",u.name="ChunkLoadError",u.type=c,u.request=p,n[1](u)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var o=(i,f)=>{var u,d,[n,a,s]=f,l=0;if(n.some(p=>0!==e[p])){for(u in a)r.o(a,u)&&(r.m[u]=a[u]);if(s)var c=s(r)}for(i&&i(f);l<n.length;l++)r.o(e,d=n[l])&&e[d]&&e[d][0](),e[d]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(o.bind(null,0)),t.push=o.bind(null,t.push.bind(t))})()})();

View file

@ -0,0 +1 @@
(()=>{"use strict";var e,v={},m={};function r(e){var f=m[e];if(void 0!==f)return f.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(f,t,i,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,o]=e[n],s=!0,u=0;u<t.length;u++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[u]))?t.splice(u--,1):(s=!1,o<a&&(a=o));if(s){e.splice(n--,1);var d=i();void 0!==d&&(f=d)}}return f}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,i,o]},r.d=(e,f)=>{for(var t in f)r.o(f,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:f[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((f,t)=>(r.f[t](e,f),f),[])),r.u=e=>e+"."+{17:"da5e0b6abb96d103",190:"0e6572086349bd7c",193:"5eec0042e2c6f1a7",853:"e46ed60b577aec33"}[e]+".js",r.miniCssF=e=>{},r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),(()=>{var e={},f="RTLApp:";r.l=(t,i,o,n)=>{if(e[t])e[t].push(i);else{var a,s;if(void 0!==o)for(var u=document.getElementsByTagName("script"),d=0;d<u.length;d++){var l=u[d];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==f+o){a=l;break}}a||(s=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",f+o),a.src=r.tu(t)),e[t]=[i];var c=(h,b)=>{a.onerror=a.onload=null,clearTimeout(p);var g=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),g&&g.forEach(_=>_(b)),h)return h(b)},p=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),s&&document.head.appendChild(a)}}})(),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:f=>f},typeof trustedTypes<"u"&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={121:0};r.f.j=(i,o)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)o.push(n[2]);else if(121!=i){var a=new Promise((l,c)=>n=e[i]=[l,c]);o.push(n[2]=a);var s=r.p+r.u(i),u=new Error;r.l(s,l=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var c=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;u.message="Loading chunk "+i+" failed.\n("+c+": "+p+")",u.name="ChunkLoadError",u.type=c,u.request=p,n[1](u)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var f=(i,o)=>{var u,d,[n,a,s]=o,l=0;if(n.some(p=>0!==e[p])){for(u in a)r.o(a,u)&&(r.m[u]=a[u]);if(s)var c=s(r)}for(i&&i(o);l<n.length;l++)r.o(e,d=n[l])&&e[d]&&e[d][0](),e[d]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();

View file

@ -0,0 +1,20 @@
# Release Notes — 0.15.11
This document collects the changes that go into the 0.15.11 release. Each PR merged for
this release should add its entry under the appropriate section below.
## Enhancements
- **2FA login: password managers can offer the one-time code**
([#1673](https://github.com/Ride-The-Lightning/RTL/pull/1673), fixes
[#1674](https://github.com/Ride-The-Lightning/RTL/issues/1674)).
The token input in the two-factor login dialog had no `autocomplete` attribute, and its
`id`, `name` and label were all `token`. A password manager had no data to find the
field. Bitwarden, for example, accepts a field only if the field has
`autocomplete="one-time-code"`, or if it contains a word from the `TotpFieldNames` list,
which does not include `token`. RTL also makes this dialog only after you send the
password, so the field is not in the page during the first autofill operation. Users
typed each code by hand. The input now has `autocomplete="one-time-code"`, the standard
value for this field, which password managers and browsers read directly. The change is
in the frontend only, and the token check does not change. A new test in
`login-2fa-token.component.spec.ts` guards the attribute.

View file

@ -10,7 +10,7 @@
<form #tokenForm="ngForm" fxLayout="column" fxFlex="100" (ngSubmit)="onVerifyToken()">
<mat-form-field>
<mat-label>Token</mat-label>
<input autoFocus matInput type="text" id="token" name="token" tabindex="2" required [(ngModel)]="token">
<input autoFocus matInput type="text" id="token" name="token" autocomplete="one-time-code" tabindex="2" required [(ngModel)]="token">
<mat-error *ngIf="!token">Token is required.</mat-error>
</mat-form-field>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="end center" class="mt-1">

View file

@ -1,5 +1,6 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { By } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { StoreModule } from '@ngrx/store';
@ -41,6 +42,11 @@ describe('LoginTokenComponent', () => {
expect(component).toBeTruthy();
});
it('should advertise the token input as a one-time code', () => {
const tokenInput = fixture.debugElement.query(By.css('input#token')).nativeElement;
expect(tokenInput.getAttribute('autocomplete')).toBe('one-time-code');
});
afterEach(() => {
TestBed.resetTestingModule();
});