cloud-ide-auth 1.0.50 → 1.0.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,862 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, Injectable, Component, signal, DestroyRef, input } from '@angular/core';
4
+ import { MLogin, customEncrypt, cidePath, hostManagerRoutesUrl, authRoutesUrl, MResetPassword, MEntitySwitch, generateObjectFromString, MEntityByDomain, generateStringFromObject, coreRoutesUrl, MForgotPassword, validateRequestModal, MReLogin } from 'cloud-ide-lms-model';
5
+ import { BehaviorSubject, of, catchError as catchError$1 } from 'rxjs';
6
+ import { RouterOutlet, Router, ActivatedRoute } from '@angular/router';
7
+ import * as i1 from '@angular/forms';
8
+ import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
9
+ import { CommonModule } from '@angular/common';
10
+ import { map, catchError } from 'rxjs/operators';
11
+ import { CideInputComponent, CideEleButtonComponent, CideEleThemeToggleComponent, CideEleFloatingContainerService } from 'cloud-ide-element';
12
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
13
+ import { CideLytSharedWrapperComponent } from 'cloud-ide-layout';
14
+ import { AUTH_SERVICE_TOKEN, APP_STATE_SERVICE_TOKEN } from 'cloud-ide-shared';
15
+
16
+ class CloudIdeAuthService {
17
+ auth_user_mst = new BehaviorSubject({});
18
+ _auth_token = "";
19
+ // Storage keys
20
+ TOKEN_STORAGE_KEY = 'cide_auth_token';
21
+ USER_STORAGE_KEY = 'cide_auth_user';
22
+ // Modern Angular v20 dependency injection pattern
23
+ http = inject(HttpClient);
24
+ constructor() {
25
+ // Modern Angular v20 pattern: Use constructor for initialization only
26
+ this.loadAuthDataFromStorage();
27
+ }
28
+ /**
29
+ * Check if localStorage is available (browser environment)
30
+ */
31
+ isLocalStorageAvailable() {
32
+ try {
33
+ return typeof window !== 'undefined' && typeof localStorage !== 'undefined';
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ // Getter and setter for auth_token with localStorage persistence
40
+ get auth_token() {
41
+ return this._auth_token;
42
+ }
43
+ set auth_token(value) {
44
+ this._auth_token = value;
45
+ if (!this.isLocalStorageAvailable()) {
46
+ return;
47
+ }
48
+ if (value) {
49
+ localStorage.setItem(this.TOKEN_STORAGE_KEY, value);
50
+ }
51
+ else {
52
+ localStorage.removeItem(this.TOKEN_STORAGE_KEY);
53
+ }
54
+ }
55
+ // View-only token for public APIs
56
+ VIEW_ONLY_TOKEN_STORAGE_KEY = 'cloud_ide_view_only_token';
57
+ _view_only_token = '';
58
+ get view_only_token() {
59
+ return this._view_only_token;
60
+ }
61
+ set view_only_token(value) {
62
+ this._view_only_token = value;
63
+ if (!this.isLocalStorageAvailable()) {
64
+ return;
65
+ }
66
+ if (value) {
67
+ localStorage.setItem(this.VIEW_ONLY_TOKEN_STORAGE_KEY, value);
68
+ }
69
+ else {
70
+ localStorage.removeItem(this.VIEW_ONLY_TOKEN_STORAGE_KEY);
71
+ }
72
+ }
73
+ // Load authentication data from localStorage on service initialization
74
+ loadAuthDataFromStorage() {
75
+ if (!this.isLocalStorageAvailable()) {
76
+ return;
77
+ }
78
+ try {
79
+ // Load token
80
+ const storedToken = localStorage.getItem(this.TOKEN_STORAGE_KEY);
81
+ if (storedToken) {
82
+ this._auth_token = storedToken;
83
+ }
84
+ // Load view-only token
85
+ const storedViewOnlyToken = localStorage.getItem(this.VIEW_ONLY_TOKEN_STORAGE_KEY);
86
+ if (storedViewOnlyToken) {
87
+ this._view_only_token = storedViewOnlyToken;
88
+ }
89
+ // Load user data
90
+ const storedUserData = localStorage.getItem(this.USER_STORAGE_KEY);
91
+ if (storedUserData) {
92
+ const userData = JSON.parse(storedUserData);
93
+ this.auth_user_mst.next(userData);
94
+ }
95
+ }
96
+ catch (error) {
97
+ // Silent error handling for auth data loading
98
+ }
99
+ }
100
+ // Store user data in localStorage
101
+ storeUserData(userData) {
102
+ if (userData) {
103
+ this.auth_user_mst.next(userData);
104
+ if (this.isLocalStorageAvailable()) {
105
+ localStorage.setItem(this.USER_STORAGE_KEY, JSON.stringify(userData));
106
+ }
107
+ }
108
+ }
109
+ signIn(body) {
110
+ // Create a copy to avoid mutating the original
111
+ const loginPayload = new MLogin(body);
112
+ if (loginPayload?.user_password) {
113
+ if (loginPayload?.user_password?.length <= 6) {
114
+ // MPIN - no encryption needed for MPIN
115
+ loginPayload.custom_login_method = "mpin";
116
+ loginPayload.mpin_pin = loginPayload?.user_password;
117
+ loginPayload.user_password = "";
118
+ }
119
+ else {
120
+ // Password - encrypt before sending
121
+ loginPayload.custom_login_method = "pass";
122
+ loginPayload.user_password = customEncrypt(loginPayload.user_password);
123
+ }
124
+ }
125
+ return this.http?.post(cidePath?.join([hostManagerRoutesUrl?.cideSuiteHost, authRoutesUrl?.module, authRoutesUrl?.signIn]), loginPayload);
126
+ }
127
+ forgotPassword(body) {
128
+ return this.http?.post(cidePath?.join([hostManagerRoutesUrl?.cideSuiteHost, authRoutesUrl?.module, authRoutesUrl?.forgotPassword]), body);
129
+ }
130
+ resetPassword(body) {
131
+ const payload = new MResetPassword(body);
132
+ if (payload?.Validate) {
133
+ payload?.Validate();
134
+ }
135
+ // Encrypt password before sending
136
+ if (payload.user_password) {
137
+ payload.user_password = customEncrypt(payload.user_password);
138
+ }
139
+ return this.http?.post(cidePath?.join([hostManagerRoutesUrl?.cideSuiteHost, authRoutesUrl?.module, authRoutesUrl?.resetPassword]), payload);
140
+ }
141
+ // Sign out the user and clear all stored auth data
142
+ signOut() {
143
+ // Clear token and user data from memory
144
+ this._auth_token = "";
145
+ this.auth_user_mst.next({});
146
+ // Clear stored data
147
+ if (this.isLocalStorageAvailable()) {
148
+ localStorage.removeItem(this.TOKEN_STORAGE_KEY);
149
+ localStorage.removeItem(this.USER_STORAGE_KEY);
150
+ }
151
+ }
152
+ // Check if user is authenticated
153
+ isAuthenticated() {
154
+ return !!this._auth_token;
155
+ }
156
+ // Get current user data
157
+ getCurrentUser() {
158
+ return this.auth_user_mst.getValue();
159
+ }
160
+ // Check if token is expired
161
+ isTokenExpired() {
162
+ try {
163
+ if (!this._auth_token) {
164
+ return true;
165
+ }
166
+ // Extract the payload from the JWT token
167
+ const tokenParts = this._auth_token.split('.');
168
+ if (tokenParts.length !== 3) {
169
+ return true; // Not a valid JWT token
170
+ }
171
+ const payload = JSON.parse(atob(tokenParts[1]));
172
+ // Check expiration time
173
+ const expiration = payload.exp * 1000; // Convert seconds to milliseconds
174
+ return Date.now() >= expiration;
175
+ }
176
+ catch (error) {
177
+ return true; // Assume expired if there's an error
178
+ }
179
+ }
180
+ // Refresh auth data if needed based on stored data
181
+ refreshAuthState() {
182
+ // If we have a token but no user data, try to load user data
183
+ if (this._auth_token && this.auth_user_mst && Object.keys(this.auth_user_mst.getValue()).length === 0 && this.isLocalStorageAvailable()) {
184
+ const storedUserData = localStorage.getItem(this.USER_STORAGE_KEY);
185
+ if (storedUserData) {
186
+ try {
187
+ const userData = JSON.parse(storedUserData);
188
+ this.auth_user_mst.next(userData);
189
+ }
190
+ catch (error) {
191
+ // Silent error handling for parsing user data
192
+ }
193
+ }
194
+ }
195
+ // If token is expired, sign out
196
+ if (this.isTokenExpired()) {
197
+ this.signOut();
198
+ }
199
+ }
200
+ /**
201
+ * Switch entity for logged-in user
202
+ * Creates a new auth_logs entry and updates the entity mapping
203
+ * @param entityId - Entity ID to switch to
204
+ * @returns Observable with new token and entity data
205
+ */
206
+ switchEntity(entityId) {
207
+ const payload = new MEntitySwitch({
208
+ syen_id: entityId
209
+ });
210
+ return this.http?.post(cidePath?.join([hostManagerRoutesUrl?.cideSuiteHost, authRoutesUrl?.module, authRoutesUrl?.switchEntity]), payload);
211
+ }
212
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CloudIdeAuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
213
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CloudIdeAuthService, providedIn: 'root' });
214
+ }
215
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CloudIdeAuthService, decorators: [{
216
+ type: Injectable,
217
+ args: [{
218
+ providedIn: 'root'
219
+ }]
220
+ }], ctorParameters: () => [] });
221
+
222
+ class CloudIdeAuthComponent {
223
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CloudIdeAuthComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
224
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: CloudIdeAuthComponent, isStandalone: true, selector: "cide-auth-wrapper", ngImport: i0, template: `
225
+ <router-outlet></router-outlet>
226
+ `, isInline: true, styles: [""], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
227
+ }
228
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CloudIdeAuthComponent, decorators: [{
229
+ type: Component,
230
+ args: [{ selector: 'cide-auth-wrapper', standalone: true, imports: [RouterOutlet], template: `
231
+ <router-outlet></router-outlet>
232
+ ` }]
233
+ }] });
234
+
235
+ var cloudIdeAuth_component = /*#__PURE__*/Object.freeze({
236
+ __proto__: null,
237
+ CloudIdeAuthComponent: CloudIdeAuthComponent
238
+ });
239
+
240
+ class EntityDetectionService {
241
+ http = inject(HttpClient);
242
+ /**
243
+ * Extract and normalize domain from current URL
244
+ * @returns Normalized domain string (without www. prefix, lowercase)
245
+ */
246
+ getDomainFromUrl() {
247
+ if (typeof window === 'undefined') {
248
+ return '';
249
+ }
250
+ const hostname = window.location.hostname;
251
+ // Remove 'www.' prefix if present and convert to lowercase
252
+ return hostname.replace(/^www\./, '').toLowerCase();
253
+ }
254
+ /**
255
+ * Extract entity ID from route parameters (object-to-string format)
256
+ * @param routeParams - Route parameters object (e.g., { query: 'suwrklfs' })
257
+ * @returns Entity ID string or null
258
+ */
259
+ getEntityIdFromRoute(routeParams) {
260
+ if (!routeParams || !routeParams['query']) {
261
+ return null;
262
+ }
263
+ try {
264
+ const queryData = generateObjectFromString(routeParams['query']);
265
+ return queryData?.syen_id || null;
266
+ }
267
+ catch (error) {
268
+ console.warn('Failed to decode route parameter:', error);
269
+ return null;
270
+ }
271
+ }
272
+ /**
273
+ * Lookup entity ID by domain using API
274
+ * @param domain - Domain string to lookup
275
+ * @returns Observable of entity ID string or null
276
+ */
277
+ lookupEntityByDomain(domain) {
278
+ if (!domain) {
279
+ return of(null);
280
+ }
281
+ const domainPayload = new MEntityByDomain({ domain });
282
+ const query = generateStringFromObject(domainPayload);
283
+ const url = cidePath.join([
284
+ hostManagerRoutesUrl.cideSuiteHost,
285
+ coreRoutesUrl.module,
286
+ coreRoutesUrl.entityByDomain,
287
+ query
288
+ ]);
289
+ return this.http.get(url).pipe(map((response) => {
290
+ if (response?.success && response?.data?._id) {
291
+ return response.data._id;
292
+ }
293
+ return null;
294
+ }), catchError((error) => {
295
+ console.warn('Domain lookup failed:', error);
296
+ return of(null);
297
+ }));
298
+ }
299
+ /**
300
+ * Detect entity ID using priority:
301
+ * 1. Domain lookup (primary)
302
+ * 2. Route parameter (fallback)
303
+ * @param routeParams - Optional route parameters for fallback
304
+ * @returns Observable of entity ID string or null
305
+ */
306
+ detectEntityId(routeParams) {
307
+ // First, try domain lookup
308
+ const domain = this.getDomainFromUrl();
309
+ if (domain) {
310
+ return this.lookupEntityByDomain(domain).pipe(map((entityId) => {
311
+ // If domain lookup succeeds, return the entity ID
312
+ if (entityId) {
313
+ return entityId;
314
+ }
315
+ // If domain lookup fails, try route parameter fallback
316
+ return this.getEntityIdFromRoute(routeParams);
317
+ }));
318
+ }
319
+ // If no domain, try route parameter fallback
320
+ const routeEntityId = this.getEntityIdFromRoute(routeParams);
321
+ return of(routeEntityId);
322
+ }
323
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EntityDetectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
324
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EntityDetectionService, providedIn: 'root' });
325
+ }
326
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EntityDetectionService, decorators: [{
327
+ type: Injectable,
328
+ args: [{
329
+ providedIn: 'root'
330
+ }]
331
+ }] });
332
+
333
+ class CideAuthForgotPasswordComponent {
334
+ forgotPassswordForm;
335
+ erro_message = signal('', ...(ngDevMode ? [{ debugName: "erro_message" }] : []));
336
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
337
+ entityId = signal(null, ...(ngDevMode ? [{ debugName: "entityId" }] : []));
338
+ authService = inject(CloudIdeAuthService);
339
+ router = inject(Router);
340
+ activatedRoute = inject(ActivatedRoute);
341
+ entityDetectionService = inject(EntityDetectionService);
342
+ constructor() {
343
+ this.forgotPassswordForm = new FormGroup({
344
+ custom_forgot_password_method: new FormControl('username'),
345
+ user_username: new FormControl('', [Validators.required, Validators.minLength(8), Validators.maxLength(20)]),
346
+ user_emailid: new FormControl(''),
347
+ user_mobileno: new FormControl(),
348
+ });
349
+ }
350
+ ngOnInit() {
351
+ // Detect entity ID from domain or route parameter
352
+ const routeParams = this.activatedRoute.snapshot.params;
353
+ this.entityDetectionService.detectEntityId(routeParams).pipe(takeUntilDestroyed()).subscribe({
354
+ next: (entityId) => {
355
+ if (entityId) {
356
+ this.entityId.set(entityId);
357
+ console.log('Entity ID detected:', entityId);
358
+ }
359
+ // Navigate to clean URL (remove :query param) if it exists
360
+ if (routeParams['query']) {
361
+ this.router.navigate(['auth', 'forgot-password'], {
362
+ queryParams: this.activatedRoute.snapshot.queryParams,
363
+ replaceUrl: true
364
+ });
365
+ }
366
+ },
367
+ error: (error) => {
368
+ console.warn('Entity detection failed:', error);
369
+ }
370
+ });
371
+ }
372
+ onForgotPasssword() {
373
+ // Mark all fields as touched to show validation errors
374
+ this.forgotPassswordForm.markAllAsTouched();
375
+ // Clear previous error messages
376
+ this.erro_message.set('');
377
+ // Check if form has basic Angular validators passed
378
+ if (!this.forgotPassswordForm.valid) {
379
+ const usernameControl = this.forgotPassswordForm.get('user_username');
380
+ if (usernameControl?.errors?.['required']) {
381
+ this.erro_message.set('Username is required');
382
+ }
383
+ else if (usernameControl?.errors?.['minlength']) {
384
+ this.erro_message.set('Username must be at least 8 characters');
385
+ }
386
+ else if (usernameControl?.errors?.['maxlength']) {
387
+ this.erro_message.set('Username must be at most 20 characters');
388
+ }
389
+ else {
390
+ this.erro_message.set('Please fill in all required fields correctly');
391
+ }
392
+ setTimeout(() => {
393
+ this.erro_message.set('');
394
+ }, 3000);
395
+ return;
396
+ }
397
+ // Create the model and validate using custom validation
398
+ const formValue = {
399
+ ...this.forgotPassswordForm.value,
400
+ syen_id: this.entityId() || undefined
401
+ };
402
+ const forgotPasswordPayload = new MForgotPassword(formValue);
403
+ const validate = validateRequestModal(forgotPasswordPayload);
404
+ if (validate !== true) {
405
+ // Custom validation failed
406
+ this.loading.set(false);
407
+ const errorKey = validate.first;
408
+ // Get the error message from errorLogger using the first key
409
+ const errorMessage = validate.errorLogger?.[errorKey] || 'Validation failed. Please check your input.';
410
+ this.erro_message.set(errorMessage);
411
+ console.error('Forgot password validation error:', validate);
412
+ setTimeout(() => {
413
+ this.erro_message.set('');
414
+ }, 3000);
415
+ return;
416
+ }
417
+ // All validations passed, make API call
418
+ this.loading.set(true);
419
+ this.authService.forgotPassword(forgotPasswordPayload)?.subscribe({
420
+ next: (response) => {
421
+ this.loading.set(false);
422
+ if (response?.success === true) {
423
+ this.erro_message.set('');
424
+ this.router.navigate(['auth', 'sign-in']);
425
+ }
426
+ else {
427
+ // API returned success: false
428
+ const errorMessage = response?.message || 'Failed to process forgot password request. Please try again.';
429
+ this.erro_message.set(errorMessage);
430
+ console.error('Forgot password API error:', response);
431
+ setTimeout(() => {
432
+ this.erro_message.set('');
433
+ }, 3000);
434
+ }
435
+ },
436
+ error: (response) => {
437
+ this.loading.set(false);
438
+ const errorMessage = response?.error?.message || 'Failed to process forgot password request. Please try again.';
439
+ this.erro_message.set(errorMessage);
440
+ console.error('Forgot password error:', response);
441
+ setTimeout(() => {
442
+ this.erro_message.set('');
443
+ }, 3000);
444
+ }
445
+ });
446
+ }
447
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideAuthForgotPasswordComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
448
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: CideAuthForgotPasswordComponent, isStandalone: true, selector: "cide-auth-forgot-password", ngImport: i0, template: "<!-- https://play.tailwindcss.com/lfO85drpUy -->\n<!-- Main Div Outer Div-->\n<div class=\"cide-font-poppins tw-flex tw-min-h-screen tw-w-full tw-bg-gray-50 tw-py-3 tw-relative\">\n <!-- Theme Toggle - Top Right Corner -->\n <div class=\"tw-absolute tw-top-4 tw-right-4 tw-z-50\">\n <cide-ele-theme-toggle size=\"small\"></cide-ele-theme-toggle>\n </div>\n <!-- Forrm Wrapper -->\n <div class=\"tw-m-auto tw-w-96 tw-rounded-2xl tw-bg-white tw-py-6 tw-shadow-xl\">\n <!-- Logo Wrapper -->\n <div class=\"tw-m-auto tw-h-32 tw-w-64 tw-text-center\">\n <img src=\"https://console.cloudidesys.com/assets/Cloud%20IDE%20Logo%20Dark.png\" class=\"tw-m-auto tw-h-full\"\n alt=\"Cloud IDE Logo\" />\n </div> <!-- Entity name here -->\n <div class=\"tw-my-2 tw-text-center tw-text-xl tw-font-semibold\">Forgot Password</div>\n <!-- Error Logger -->\n @if (erro_message()) {\n <div class=\"tw-w-full tw-select-none tw-py-1 tw-mx-auto tw-mb-2 tw-max-w-80 tw-text-center tw-text-sm tw-text-red-600 dark:tw-text-red-400\">\n {{erro_message()}}\n </div>\n }\n \n <!-- section for controls -->\n <form [formGroup]=\"forgotPassswordForm\" (ngSubmit)=\"onForgotPasssword()\" novalidate>\n <div class=\"tw-m-auto tw-pb-3 tw-pt-3\">\n <!-- Username -->\n <div class=\"tw-m-auto tw-w-80 tw-mb-4\">\n <cide-ele-input \n id=\"user_username\" \n formControlName=\"user_username\"\n placeholder=\"Enter your username\"\n [required]=\"true\">\n </cide-ele-input>\n @if (forgotPassswordForm.get('user_username')?.invalid && forgotPassswordForm.get('user_username')?.touched) {\n <div class=\"tw-text-xs tw-text-red-600 tw-mt-1\">\n @if (forgotPassswordForm.get('user_username')?.errors?.['required']) {\n Username is required\n } @else if (forgotPassswordForm.get('user_username')?.errors?.['minlength']) {\n Username must be at least 8 characters\n } @else if (forgotPassswordForm.get('user_username')?.errors?.['maxlength']) {\n Username must be at most 20 characters\n }\n </div>\n }\n </div>\n <!-- Forgot Password button -->\n <div class=\"tw-w-80 tw-m-auto tw-mt-3\">\n <button \n type=\"submit\"\n cideEleButton \n id=\"reset_password_link_button\" \n [loading]=\"loading()\" \n [disabled]=\"loading()\">\n Reset Password\n </button>\n </div>\n </div>\n </form>\n </div>\n </div>", styles: [""], dependencies: [{ kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }, { kind: "component", type: CideEleThemeToggleComponent, selector: "cide-ele-theme-toggle", inputs: ["size"] }] });
449
+ }
450
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideAuthForgotPasswordComponent, decorators: [{
451
+ type: Component,
452
+ args: [{ selector: 'cide-auth-forgot-password', standalone: true, imports: [CideInputComponent, ReactiveFormsModule, CommonModule, CideEleButtonComponent, CideEleThemeToggleComponent], template: "<!-- https://play.tailwindcss.com/lfO85drpUy -->\n<!-- Main Div Outer Div-->\n<div class=\"cide-font-poppins tw-flex tw-min-h-screen tw-w-full tw-bg-gray-50 tw-py-3 tw-relative\">\n <!-- Theme Toggle - Top Right Corner -->\n <div class=\"tw-absolute tw-top-4 tw-right-4 tw-z-50\">\n <cide-ele-theme-toggle size=\"small\"></cide-ele-theme-toggle>\n </div>\n <!-- Forrm Wrapper -->\n <div class=\"tw-m-auto tw-w-96 tw-rounded-2xl tw-bg-white tw-py-6 tw-shadow-xl\">\n <!-- Logo Wrapper -->\n <div class=\"tw-m-auto tw-h-32 tw-w-64 tw-text-center\">\n <img src=\"https://console.cloudidesys.com/assets/Cloud%20IDE%20Logo%20Dark.png\" class=\"tw-m-auto tw-h-full\"\n alt=\"Cloud IDE Logo\" />\n </div> <!-- Entity name here -->\n <div class=\"tw-my-2 tw-text-center tw-text-xl tw-font-semibold\">Forgot Password</div>\n <!-- Error Logger -->\n @if (erro_message()) {\n <div class=\"tw-w-full tw-select-none tw-py-1 tw-mx-auto tw-mb-2 tw-max-w-80 tw-text-center tw-text-sm tw-text-red-600 dark:tw-text-red-400\">\n {{erro_message()}}\n </div>\n }\n \n <!-- section for controls -->\n <form [formGroup]=\"forgotPassswordForm\" (ngSubmit)=\"onForgotPasssword()\" novalidate>\n <div class=\"tw-m-auto tw-pb-3 tw-pt-3\">\n <!-- Username -->\n <div class=\"tw-m-auto tw-w-80 tw-mb-4\">\n <cide-ele-input \n id=\"user_username\" \n formControlName=\"user_username\"\n placeholder=\"Enter your username\"\n [required]=\"true\">\n </cide-ele-input>\n @if (forgotPassswordForm.get('user_username')?.invalid && forgotPassswordForm.get('user_username')?.touched) {\n <div class=\"tw-text-xs tw-text-red-600 tw-mt-1\">\n @if (forgotPassswordForm.get('user_username')?.errors?.['required']) {\n Username is required\n } @else if (forgotPassswordForm.get('user_username')?.errors?.['minlength']) {\n Username must be at least 8 characters\n } @else if (forgotPassswordForm.get('user_username')?.errors?.['maxlength']) {\n Username must be at most 20 characters\n }\n </div>\n }\n </div>\n <!-- Forgot Password button -->\n <div class=\"tw-w-80 tw-m-auto tw-mt-3\">\n <button \n type=\"submit\"\n cideEleButton \n id=\"reset_password_link_button\" \n [loading]=\"loading()\" \n [disabled]=\"loading()\">\n Reset Password\n </button>\n </div>\n </div>\n </form>\n </div>\n </div>" }]
453
+ }], ctorParameters: () => [] });
454
+
455
+ var forgotPassword_component = /*#__PURE__*/Object.freeze({
456
+ __proto__: null,
457
+ CideAuthForgotPasswordComponent: CideAuthForgotPasswordComponent
458
+ });
459
+
460
+ /**
461
+ * Service to handle re-login functionality when 401 errors occur
462
+ */
463
+ class ReLoginService {
464
+ http = inject(HttpClient);
465
+ authService = inject(CloudIdeAuthService);
466
+ // Observable to control re-login dialog visibility
467
+ showReLoginSubject = new BehaviorSubject(false);
468
+ showReLogin$ = this.showReLoginSubject.asObservable();
469
+ // Signal for re-login state
470
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
471
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
472
+ /**
473
+ * Show re-login dialog
474
+ */
475
+ showReLogin() {
476
+ // Only show if we have a token (session expired scenario)
477
+ if (this.authService.auth_token) {
478
+ this.showReLoginSubject.next(true);
479
+ }
480
+ }
481
+ /**
482
+ * Hide re-login dialog
483
+ */
484
+ hideReLogin() {
485
+ this.showReLoginSubject.next(false);
486
+ this.error.set(null);
487
+ }
488
+ /**
489
+ * Perform re-login with MPIN or password
490
+ */
491
+ reLogin(payload) {
492
+ this.isLoading.set(true);
493
+ this.error.set(null);
494
+ // Create a copy to avoid mutating the original
495
+ const reLoginPayload = {
496
+ ...payload,
497
+ token: this.authService.auth_token
498
+ };
499
+ // Encrypt password if provided (MPIN doesn't need encryption)
500
+ if (reLoginPayload.user_password && reLoginPayload.custom_login_method === 'pass') {
501
+ reLoginPayload.user_password = customEncrypt(reLoginPayload.user_password);
502
+ }
503
+ const url = cidePath.join([
504
+ hostManagerRoutesUrl.cideSuiteHost,
505
+ authRoutesUrl.module,
506
+ authRoutesUrl.createReLoginSession
507
+ ]);
508
+ return this.http.post(url, reLoginPayload).pipe(catchError$1((response) => {
509
+ this.isLoading.set(false);
510
+ const errorMessage = response?.error?.message || 'Re-login failed';
511
+ this.error.set(errorMessage);
512
+ return of({
513
+ success: false,
514
+ message: errorMessage
515
+ });
516
+ }));
517
+ }
518
+ /**
519
+ * Handle successful re-login
520
+ */
521
+ handleReLoginSuccess(response) {
522
+ if (response.success && response.token) {
523
+ // Update auth token
524
+ this.authService.auth_token = response.token;
525
+ // Update user data if available
526
+ if (response.data) {
527
+ const userData = response.data;
528
+ this.authService.storeUserData(userData);
529
+ }
530
+ // Hide re-login dialog
531
+ this.hideReLogin();
532
+ this.isLoading.set(false);
533
+ }
534
+ else {
535
+ this.error.set(response.message || 'Re-login failed');
536
+ this.isLoading.set(false);
537
+ }
538
+ }
539
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ReLoginService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
540
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ReLoginService, providedIn: 'root' });
541
+ }
542
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ReLoginService, decorators: [{
543
+ type: Injectable,
544
+ args: [{
545
+ providedIn: 'root'
546
+ }]
547
+ }] });
548
+
549
+ /**
550
+ * Service to manage re-login component in floating container
551
+ */
552
+ class ReLoginFloatingService {
553
+ containerService = inject(CideEleFloatingContainerService);
554
+ reLoginService = inject(ReLoginService);
555
+ destroyRef = inject(DestroyRef);
556
+ containerId = null;
557
+ constructor() {
558
+ // Register the component when service is initialized
559
+ this.registerReLoginComponent();
560
+ // Subscribe to re-login service to show/hide dialog
561
+ this.reLoginService.showReLogin$
562
+ .pipe(takeUntilDestroyed(this.destroyRef))
563
+ .subscribe((shouldShow) => {
564
+ if (shouldShow && !this.containerId) {
565
+ this.show();
566
+ }
567
+ else if (!shouldShow && this.containerId) {
568
+ this.hide();
569
+ }
570
+ });
571
+ }
572
+ /**
573
+ * Register re-login component with floating container service
574
+ */
575
+ async registerReLoginComponent() {
576
+ if (this.containerService.isComponentRegistered('re-login')) {
577
+ return;
578
+ }
579
+ try {
580
+ const module = await Promise.resolve().then(function () { return reLogin_component; });
581
+ if (!module.CideAuthReLoginComponent) {
582
+ throw new Error('Component class not found in module');
583
+ }
584
+ this.containerService.registerComponent('re-login', module.CideAuthReLoginComponent);
585
+ }
586
+ catch (error) {
587
+ console.error('Failed to register re-login component:', error);
588
+ }
589
+ }
590
+ /**
591
+ * Show re-login in floating container
592
+ */
593
+ async show() {
594
+ // Ensure component is registered
595
+ if (!this.containerService.isComponentRegistered('re-login')) {
596
+ await this.registerReLoginComponent();
597
+ }
598
+ const config = {
599
+ id: 're-login-container',
600
+ title: 'Re-Login Required',
601
+ icon: 'lock',
602
+ backdrop: true,
603
+ width: '420px',
604
+ height: 'auto',
605
+ minWidth: '400px',
606
+ minHeight: '200px',
607
+ resizable: false,
608
+ draggable: true,
609
+ closable: false, // Prevent closing - user must re-login
610
+ minimizable: false,
611
+ maximizable: false,
612
+ componentId: 're-login',
613
+ componentConfig: {
614
+ inputs: {},
615
+ outputs: {}
616
+ }
617
+ };
618
+ this.containerId = this.containerService.show(config);
619
+ return this.containerId;
620
+ }
621
+ /**
622
+ * Hide re-login floating container
623
+ */
624
+ hide() {
625
+ if (this.containerId) {
626
+ this.containerService.hide(this.containerId);
627
+ this.containerId = null;
628
+ }
629
+ }
630
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ReLoginFloatingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
631
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ReLoginFloatingService, providedIn: 'root' });
632
+ }
633
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ReLoginFloatingService, decorators: [{
634
+ type: Injectable,
635
+ args: [{
636
+ providedIn: 'root'
637
+ }]
638
+ }], ctorParameters: () => [] });
639
+
640
+ class CideAuthReLoginComponent extends CideLytSharedWrapperComponent {
641
+ shared_wrapper_setup_param = input({
642
+ sypg_page_code: "auth_relogin_dialog"
643
+ }, ...(ngDevMode ? [{ debugName: "shared_wrapper_setup_param" }] : []));
644
+ reLoginService = inject(ReLoginService);
645
+ destroyRef = inject(DestroyRef);
646
+ isLoading = this.reLoginService.isLoading;
647
+ error = this.reLoginService.error;
648
+ reLoginForm = new FormGroup({
649
+ custom_login_method: new FormControl('pass'),
650
+ user_password: new FormControl('')
651
+ });
652
+ constructor() {
653
+ super();
654
+ }
655
+ ngOnInit() {
656
+ super.ngOnInit();
657
+ // Set default login method to password
658
+ this.reLoginForm.patchValue({
659
+ custom_login_method: 'pass'
660
+ });
661
+ }
662
+ ngOnDestroy() {
663
+ // Cleanup handled by takeUntilDestroyed
664
+ }
665
+ onSubmit() {
666
+ if (this.reLoginForm.valid) {
667
+ const formValue = this.reLoginForm.value;
668
+ const passwordValue = formValue.user_password || '';
669
+ // Auto-detect MPIN vs Password based on length (same as login screen)
670
+ // If length <= 6, treat as MPIN, otherwise as password
671
+ let customLoginMethod = 'pass';
672
+ let userPassword = passwordValue;
673
+ let mpinPin = undefined;
674
+ if (passwordValue && passwordValue.length <= 6) {
675
+ customLoginMethod = 'mpin';
676
+ mpinPin = passwordValue;
677
+ userPassword = undefined;
678
+ }
679
+ const payload = new MReLogin({
680
+ custom_login_method: customLoginMethod,
681
+ user_password: userPassword,
682
+ mpin_pin: mpinPin
683
+ });
684
+ this.reLoginService.reLogin(payload)
685
+ .pipe(takeUntilDestroyed(this.destroyRef))
686
+ .subscribe({
687
+ next: (response) => {
688
+ this.reLoginService.handleReLoginSuccess(response);
689
+ },
690
+ error: () => {
691
+ // Error is handled in the service
692
+ }
693
+ });
694
+ }
695
+ }
696
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideAuthReLoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
697
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: CideAuthReLoginComponent, isStandalone: true, selector: "cide-auth-re-login", inputs: { shared_wrapper_setup_param: { classPropertyName: "shared_wrapper_setup_param", publicName: "shared_wrapper_setup_param", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
698
+ <div class="tw-w-full tw-max-w-md tw-mx-auto tw-p-6">
699
+ <div class="tw-text-center tw-mb-6">
700
+ <h2 class="tw-text-2xl tw-font-semibold tw-text-gray-900 tw-mb-2">Session Expired</h2>
701
+ <p class="tw-text-sm tw-text-gray-600">Please re-authenticate to continue</p>
702
+ </div>
703
+
704
+ @if (error()) {
705
+ <div class="tw-mb-4 tw-p-3 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-lg">
706
+ <p class="tw-text-sm tw-text-red-600">{{ error() }}</p>
707
+ </div>
708
+ }
709
+
710
+ <form [formGroup]="reLoginForm" (ngSubmit)="onSubmit()">
711
+ <div class="tw-space-y-4">
712
+ <!-- Single input field for both password and MPIN -->
713
+ <div>
714
+ <cide-ele-input
715
+ id="user_password_mpin"
716
+ formControlName="user_password"
717
+ type="password"
718
+ placeholder="Enter your password or MPIN"
719
+ [required]="true">
720
+ </cide-ele-input>
721
+ </div>
722
+
723
+ <div class="tw-flex tw-gap-3 tw-pt-4">
724
+ <button
725
+ type="submit"
726
+ cideEleButton
727
+ variant="primary"
728
+ [loading]="isLoading()"
729
+ [disabled]="!reLoginForm.valid || isLoading()"
730
+ class="tw-flex-1">
731
+ Re-Login
732
+ </button>
733
+ </div>
734
+ </div>
735
+ </form>
736
+ </div>
737
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: CideInputComponent, selector: "cide-ele-input", inputs: ["fill", "label", "labelHide", "disabled", "clearInput", "labelPlacement", "labelDir", "placeholder", "leadingIcon", "trailingIcon", "helperText", "helperTextCollapse", "hideHelperAndErrorText", "errorText", "maxlength", "minlength", "required", "autocapitalize", "autocomplete", "type", "width", "id", "ngModel", "option", "min", "max", "step", "size"], outputs: ["ngModelChange"] }, { kind: "component", type: CideEleButtonComponent, selector: "button[cideEleButton], a[cideEleButton], cide-ele-button", inputs: ["label", "variant", "size", "type", "shape", "elevation", "disabled", "id", "loading", "fullWidth", "leftIcon", "rightIcon", "customClass", "tooltip", "ariaLabel", "testId", "routerLink", "routerExtras", "preventDoubleClick", "animated"], outputs: ["btnClick", "doubleClick"] }] });
738
+ }
739
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CideAuthReLoginComponent, decorators: [{
740
+ type: Component,
741
+ args: [{ selector: 'cide-auth-re-login', standalone: true, imports: [
742
+ CommonModule,
743
+ ReactiveFormsModule,
744
+ CideInputComponent,
745
+ CideEleButtonComponent
746
+ ], template: `
747
+ <div class="tw-w-full tw-max-w-md tw-mx-auto tw-p-6">
748
+ <div class="tw-text-center tw-mb-6">
749
+ <h2 class="tw-text-2xl tw-font-semibold tw-text-gray-900 tw-mb-2">Session Expired</h2>
750
+ <p class="tw-text-sm tw-text-gray-600">Please re-authenticate to continue</p>
751
+ </div>
752
+
753
+ @if (error()) {
754
+ <div class="tw-mb-4 tw-p-3 tw-bg-red-50 tw-border tw-border-red-200 tw-rounded-lg">
755
+ <p class="tw-text-sm tw-text-red-600">{{ error() }}</p>
756
+ </div>
757
+ }
758
+
759
+ <form [formGroup]="reLoginForm" (ngSubmit)="onSubmit()">
760
+ <div class="tw-space-y-4">
761
+ <!-- Single input field for both password and MPIN -->
762
+ <div>
763
+ <cide-ele-input
764
+ id="user_password_mpin"
765
+ formControlName="user_password"
766
+ type="password"
767
+ placeholder="Enter your password or MPIN"
768
+ [required]="true">
769
+ </cide-ele-input>
770
+ </div>
771
+
772
+ <div class="tw-flex tw-gap-3 tw-pt-4">
773
+ <button
774
+ type="submit"
775
+ cideEleButton
776
+ variant="primary"
777
+ [loading]="isLoading()"
778
+ [disabled]="!reLoginForm.valid || isLoading()"
779
+ class="tw-flex-1">
780
+ Re-Login
781
+ </button>
782
+ </div>
783
+ </div>
784
+ </form>
785
+ </div>
786
+ ` }]
787
+ }], ctorParameters: () => [], propDecorators: { shared_wrapper_setup_param: [{ type: i0.Input, args: [{ isSignal: true, alias: "shared_wrapper_setup_param", required: false }] }] } });
788
+
789
+ var reLogin_component = /*#__PURE__*/Object.freeze({
790
+ __proto__: null,
791
+ CideAuthReLoginComponent: CideAuthReLoginComponent
792
+ });
793
+
794
+ const authRoutes = {
795
+ path: "auth", // localhost:4200/auth/sign-in
796
+ loadComponent: () => Promise.resolve().then(function () { return cloudIdeAuth_component; }).then(c => c.CloudIdeAuthComponent),
797
+ children: [
798
+ {
799
+ path: "",
800
+ pathMatch: 'full',
801
+ redirectTo: 'sign-in'
802
+ },
803
+ {
804
+ path: "sign-in/:query",
805
+ loadComponent: () => import('./cloud-ide-auth-sign-in.component-Cliki-yE.mjs').then(c => c.CideAuthSignInComponent)
806
+ },
807
+ {
808
+ path: "sign-in",
809
+ loadComponent: () => import('./cloud-ide-auth-sign-in.component-Cliki-yE.mjs').then(c => c.CideAuthSignInComponent)
810
+ },
811
+ {
812
+ path: "forgot-password/:query",
813
+ loadComponent: () => Promise.resolve().then(function () { return forgotPassword_component; }).then(c => c.CideAuthForgotPasswordComponent)
814
+ },
815
+ {
816
+ path: "forgot-password",
817
+ loadComponent: () => Promise.resolve().then(function () { return forgotPassword_component; }).then(c => c.CideAuthForgotPasswordComponent)
818
+ },
819
+ {
820
+ path: "reset-password/:rout_token/:query",
821
+ loadComponent: () => import('./cloud-ide-auth-reset-password.component-BsNMRc4d.mjs').then(c => c.CideAuthResetPasswordComponent)
822
+ },
823
+ {
824
+ path: "reset-password/:rout_token",
825
+ loadComponent: () => import('./cloud-ide-auth-reset-password.component-BsNMRc4d.mjs').then(c => c.CideAuthResetPasswordComponent)
826
+ }
827
+ ]
828
+ };
829
+
830
+ const authGuard = (route, state) => {
831
+ const authService = inject(AUTH_SERVICE_TOKEN);
832
+ const appState = inject(APP_STATE_SERVICE_TOKEN);
833
+ const router = inject(Router);
834
+ // Check if user is authenticated using current state (without refreshing first)
835
+ const isAuthenticated = appState.isUserAuthenticated() && !authService.isTokenExpired();
836
+ // Defer state refresh to next change detection cycle to avoid ExpressionChangedAfterItHasBeenCheckedError
837
+ Promise.resolve().then(() => {
838
+ // Refresh auth state to make sure it's current
839
+ authService.refreshAuthState();
840
+ // Refresh app state from localStorage to ensure synchronization
841
+ appState.refreshFromLocalStorage();
842
+ });
843
+ if (isAuthenticated) {
844
+ return true;
845
+ }
846
+ // Redirect to login page with the intended destination
847
+ router.navigate(['/auth/sign-in'], {
848
+ queryParams: { returnUrl: state.url }
849
+ });
850
+ return false;
851
+ };
852
+
853
+ /*
854
+ * Public API Surface of cloud-ide-auth
855
+ */
856
+
857
+ /**
858
+ * Generated bundle index. Do not edit.
859
+ */
860
+
861
+ export { CloudIdeAuthService as C, EntityDetectionService as E, ReLoginService as R, CloudIdeAuthComponent as a, CideAuthForgotPasswordComponent as b, ReLoginFloatingService as c, CideAuthReLoginComponent as d, authRoutes as e, authGuard as f };
862
+ //# sourceMappingURL=cloud-ide-auth-cloud-ide-auth-JvYoNJol.mjs.map