11import { LightDMMessageType , LightDMPromptType , LightDMUser , lightdm } from 'nody-greeter-types/index' ;
22
3- export interface UILoginElements {
4- loginForm : HTMLFormElement ;
5- loginInput : HTMLInputElement ;
6- passwordInput : HTMLInputElement ;
7- loginButton : HTMLButtonElement ;
8- }
9-
10- export interface UILockScreenElements {
11- lockForm : HTMLFormElement ;
12- displayName : HTMLHeadingElement ;
13- loginName : HTMLHeadingElement ;
14- passwordInput : HTMLInputElement ;
15- unlockButton : HTMLButtonElement ;
3+ export interface AuthenticatorEvents {
4+ /**
5+ * This event gets called when the login process starts without error.
6+ */
7+ authenticationStart : ( ) => void ;
8+
9+ /**
10+ * This event gets called when the login process completes without error.
11+ */
12+ authenticationComplete : ( ) => void ;
13+
14+ /**
15+ * This event gets called when the login process fails due to an authentication failure (wrong username or password).
16+ */
17+ authenticationFailure : ( ) => void ;
18+
19+ /**
20+ * This event gets called when LightDM wants to display an error message or when an error occurs in the Authenticator class.
21+ * @param message The error message.
22+ */
23+ errorMessage : ( message : string ) => void ;
24+
25+ /**
26+ * This event gets called when LightDM wants to display an info message.
27+ * @param message The info message.
28+ */
29+ infoMessage : ( message : string ) => void ;
1630}
1731
1832export class Authenticator {
19- private _loginElements : UILoginElements ;
20- private _lockScreenElements : UILockScreenElements ;
21-
2233 private _authenticating : boolean = false ;
2334 private _authenticated : boolean = false ;
35+
36+ private _authEvents : AuthenticatorEvents | null = null ;
37+
2438 private _username : string = "" ;
2539 private _password : string = "" ;
2640 private _session : string = "ubuntu" ; // always start with ubuntu.desktop X11 session
2741
28- private _isLockScreen : boolean = false ;
29- private _activeSession : LightDMUser | undefined ;
42+ public static readonly MAX_LEN_USERNAME = 32 ;
43+ public static readonly MAX_LEN_PASSWORD = 128 ;
3044
3145 public constructor ( ) {
32- this . _loginElements = {
33- loginForm : document . getElementById ( 'login-form' ) as HTMLFormElement ,
34- loginInput : document . getElementById ( 'login' ) as HTMLInputElement ,
35- passwordInput : document . getElementById ( 'password' ) as HTMLInputElement ,
36- loginButton : document . getElementById ( 'login-button' ) as HTMLButtonElement ,
37- } ;
38-
39- this . _lockScreenElements = {
40- lockForm : document . getElementById ( 'lock-form' ) as HTMLFormElement ,
41- displayName : document . getElementById ( 'active-user-session-display-name' ) as HTMLHeadingElement ,
42- loginName : document . getElementById ( 'active-user-session-login-name' ) as HTMLHeadingElement ,
43- passwordInput : document . getElementById ( 'active-user-session-password' ) as HTMLInputElement ,
44- unlockButton : document . getElementById ( 'unlock-button' ) as HTMLButtonElement ,
45- } ;
46-
47- // Check for any active sessions
48- this . _activeSession = lightdm . users . find ( ( user : LightDMUser ) => user . logged_in ) ;
49-
50- if ( this . _activeSession !== undefined ) {
51- // Active session found, show lock screen form
52- this . _isLockScreen = true ;
53- this . _username = this . _activeSession . username ;
54- this . _initLockScreenForm ( ) ;
55- }
56- else {
57- // No active session found, show login form
58- this . _initLoginForm ( ) ;
59- }
60-
6146 // Initialize LightDM event listeners
6247 this . _initLightDMListeners ( ) ;
6348 }
6449
65- private _initLoginForm ( ) : void {
66- // This event gets called when the user clicks the login button or submits the login form in any other way
67- this . _loginElements . loginForm . addEventListener ( 'submit' , ( event : Event ) => {
68- event . preventDefault ( ) ;
69- this . _username = this . _loginElements . loginInput . value . trim ( ) ;
70- this . _password = this . _loginElements . passwordInput . value . trim ( ) ;
71- this . _login ( ) ;
72- } ) ;
73-
74- // Display the login form
75- this . _loginElements . loginForm . style . display = "block" ;
76- this . _loginElements . loginInput . focus ( ) ;
77- }
78-
79- private _initLockScreenForm ( ) : void {
80- // Populate lock screen data
81- this . _lockScreenElements . displayName . innerText = this . _activeSession ?. display_name ?? this . _activeSession ?. username ?? "User" ;
82- this . _lockScreenElements . loginName . innerText = this . _activeSession ?. username ?? "user" ;
83-
84- // This event gets called when the user clicks the unlock button or submits the lock screen form in any other way
85- this . _lockScreenElements . lockForm . addEventListener ( 'submit' , ( event : Event ) => {
86- event . preventDefault ( ) ;
87- this . _password = this . _lockScreenElements . passwordInput . value . trim ( ) ;
88- this . _login ( ) ;
89- } ) ;
90-
91- // Display the lock screen form
92- this . _lockScreenElements . lockForm . style . display = "block" ;
93- this . _lockScreenElements . passwordInput . focus ( ) ;
94- }
95-
9650 private _initLightDMListeners ( ) : void {
9751 // This event gets called when LightDM asks for more authentication data
9852 lightdm . show_prompt . connect ( ( message : string , type : LightDMPromptType ) => {
@@ -122,9 +76,15 @@ export class Authenticator {
12276 switch ( type ) {
12377 case LightDMMessageType . Info :
12478 console . log ( `LightDM info message: ${ message } ` ) ;
79+ if ( this . _authEvents ) {
80+ this . _authEvents . infoMessage ( message ) ;
81+ }
12582 break ;
12683 case LightDMMessageType . Error :
12784 console . error ( `LightDM error message: ${ message } ` ) ;
85+ if ( this . _authEvents ) {
86+ this . _authEvents . errorMessage ( message ) ;
87+ }
12888 break ;
12989 default :
13090 console . warn ( `Unknown lightDM message type: ${ type } , message: ${ message } ` ) ;
@@ -144,96 +104,77 @@ export class Authenticator {
144104 if ( lightdm . is_authenticated ) {
145105 this . _authenticated = true ;
146106 console . log ( "LightDM authentication successful! Starting session..." ) ;
107+ if ( this . _authEvents ) {
108+ this . _authEvents . authenticationComplete ( ) ;
109+ }
147110 lightdm . start_session ( this . _session ?? null ) ;
148111 }
149112 else {
150113 console . log ( "LightDM authentication failed. User not found or password incorrect." ) ;
151114 this . _stopAuthentication ( ) ;
152- this . _wigglePasswordInput ( ) ;
115+ if ( this . _authEvents ) {
116+ this . _authEvents . authenticationFailure ( ) ;
117+ }
153118 }
154119 }
155120 catch ( err ) {
156121 console . error ( err ) ;
122+ if ( this . _authEvents ) {
123+ this . _authEvents . errorMessage ( String ( err ) ) ;
124+ }
157125 }
158126 } ) ;
159127 }
160128
161- private _clearAuth ( ) : void {
162- if ( ! this . _isLockScreen ) {
163- this . _username = "" ;
164- }
165- this . _password = "" ;
129+ /**
130+ * Check if the authentication process has started.
131+ * @returns True if the authentication process has started, false otherwise.
132+ */
133+ public get authenticating ( ) : boolean {
134+ return this . _authenticating ;
166135 }
167136
168- private _disableForm ( ) : void {
169- const uiElementsObject = this . _isLockScreen ? this . _lockScreenElements : this . _loginElements ;
170- for ( const element of Object . values ( uiElementsObject ) ) {
171- if ( "disabled" in element && typeof element . disabled === "boolean" ) { // check if element has disabled property and disable every element that has it
172- element . disabled = true ;
173- }
174- }
175-
176- // Unfocus the focused element
177- if ( document . activeElement ) {
178- ( document . activeElement as HTMLElement ) . blur ( ) ;
179- }
137+ /**
138+ * Check if the authentication process has completed.
139+ * @returns True if the authentication process has completed, false otherwise.
140+ */
141+ public get authenticated ( ) : boolean {
142+ return this . _authenticated ;
180143 }
181144
182- private _enableForm ( focusElement : HTMLInputElement | null = null ) : void {
183- const uiElementsObject = this . _isLockScreen ? this . _lockScreenElements : this . _loginElements ;
184- for ( const element of Object . values ( uiElementsObject ) ) {
185- if ( "disabled" in element && typeof element . disabled === "boolean" ) { // check if element has disabled property and enable every element that has it
186- element . disabled = false ;
187- }
188- }
189-
190- if ( ! focusElement ) {
191- focusElement = this . _getInputToFocusOn ( ) ;
192- }
193- focusElement . focus ( ) ;
145+ /**
146+ * Get the username that is currently being authenticated.
147+ * @returns The username that is currently being authenticated.
148+ */
149+ public get username ( ) : string {
150+ return this . _username ;
194151 }
195152
196- private _wigglePasswordInput ( clearInput : boolean = true ) : void {
197- const passwordInput = this . _isLockScreen ? this . _lockScreenElements . passwordInput : this . _loginElements . passwordInput ;
198- passwordInput . classList . add ( 'wiggle' ) ;
199- setTimeout ( ( ) => {
200- passwordInput . classList . remove ( 'wiggle' ) ;
201- } , 800 ) ; // overdo the animation a bit to make sure it's finished before we remove the class
202-
203- if ( clearInput ) {
204- passwordInput . value = "" ;
205- passwordInput . focus ( ) ;
206- }
153+ /**
154+ * Configure the callback functions that are called on certain events.
155+ * @param authEvents The callback functions that are called on certain events.
156+ * @returns void
157+ */
158+ public set authEvents ( authEvents : AuthenticatorEvents ) {
159+ this . _authEvents = authEvents ;
207160 }
208161
209- private _getInputToFocusOn ( ) : HTMLInputElement {
210- if ( this . _isLockScreen ) {
211- return this . _lockScreenElements . passwordInput ;
212- }
213- else {
214- if ( this . _loginElements . loginInput . value . trim ( ) === "" ) {
215- return this . _loginElements . loginInput ;
216- }
217- return this . _loginElements . passwordInput ;
218- }
162+ private _clearAuth ( ) : void {
163+ this . _username = "" ;
164+ this . _password = "" ;
219165 }
220166
221167 private _stopAuthentication ( ) : void {
222168 lightdm . cancel_authentication ( ) ;
223169 this . _authenticating = false ;
224170 this . _authenticated = false ;
225171 this . _clearAuth ( ) ;
226- this . _enableForm ( ) ;
227172 }
228173
229174 private _startAuthentication ( ) : void {
230175 try {
231176 console . log ( "Starting LightDM authentication..." ) ;
232177 lightdm . cancel_authentication ( ) ;
233- if ( this . _username === "" || this . _password === "" ) {
234- console . log ( "Username or password is empty. Stopping authentication." ) ;
235- return this . _stopAuthentication ( ) ;
236- }
237178 this . _authenticating = true ;
238179 lightdm . authenticate ( this . _username ) ; // provide username to skip the username prompt
239180 }
@@ -242,12 +183,29 @@ export class Authenticator {
242183 }
243184 }
244185
245- private _login ( ) : void {
186+ /**
187+ * Start the login process. The authenticationStart auth event will be called when the login process starts without error.
188+ * @param username The username to log in with.
189+ * @param password The password to log in with.
190+ * @returns void
191+ */
192+ public login ( username : string , password : string ) : void {
193+ this . _username = username . substring ( 0 , Authenticator . MAX_LEN_USERNAME ) . trim ( ) ;
194+ this . _password = password . substring ( 0 , Authenticator . MAX_LEN_PASSWORD ) ; // do not trim password as it could contain spaces at the beginning or end
195+
246196 if ( this . _authenticating || this . _authenticated ) {
197+ console . warn ( "Login() was called while already authenticating or authenticated. Stopping authentication." ) ;
247198 return ;
248199 }
249200
250- this . _disableForm ( ) ;
201+ if ( this . _username === "" || this . _password === "" ) {
202+ console . log ( "Login() was called while username or password is empty. Stopping authentication." ) ;
203+ return ;
204+ }
205+
206+ if ( this . _authEvents ) {
207+ this . _authEvents . authenticationStart ( ) ;
208+ }
251209 this . _startAuthentication ( ) ;
252210 }
253211}
0 commit comments