@acorex/connectivity 20.2.0-next.1 → 20.2.0-next.3

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.
@@ -1,19 +1,19 @@
1
- import { AXP_ROOT_CONFIG_TOKEN, AXPFilterOperatorMiddlewareService, AXPFileStorageService, AXPFileStorageStatus, AXPRegionalService } from '@acorex/platform/common';
1
+ import { AXP_ROOT_CONFIG_TOKEN, AXPFilterOperatorMiddlewareService, AXPFileStorageService, AXPFileStorageStatus } from '@acorex/platform/common';
2
2
  import { AXPEntityResolver, AXPEntityStorageService } from '@acorex/platform/layout/entity';
3
3
  import * as i1 from '@angular/common/http';
4
4
  import { HttpParams, HttpClient, HttpHeaders } from '@angular/common/http';
5
5
  import * as i0 from '@angular/core';
6
6
  import { inject, Injectable, NgModule } from '@angular/core';
7
7
  import { kebabCase } from 'lodash-es';
8
- import { firstValueFrom, map, BehaviorSubject, tap, filter, take, of, switchMap, delay, catchError } from 'rxjs';
8
+ import { firstValueFrom, catchError, of, map, BehaviorSubject, tap, filter, take, switchMap, delay } from 'rxjs';
9
9
  import * as i2 from '@acorex/platform/auth';
10
- import { AXPSessionService, AXPAuthModule, AXP_APPLICATION_LOADER, AXP_PERMISSION_LOADER, AXP_FEATURE_LOADER } from '@acorex/platform/auth';
10
+ import { AXPAuthStrategy, AXPSessionService, JwtUtil, TimeUtil, PkceUtil, AXPAuthModule, AXP_TENANT_LOADER, AXP_APPLICATION_LOADER, AXP_PERMISSION_LOADER, AXP_FEATURE_LOADER } from '@acorex/platform/auth';
11
11
  import { STRATEGY_CONFIG_TOKEN } from '@acorex/platform/widgets';
12
12
  import * as i1$1 from 'angular-oauth2-oidc';
13
13
  import { OAuthService, OAuthModule } from 'angular-oauth2-oidc';
14
14
  import { AXM_AUTH_CONFIG_TOKEN } from '@acorex/modules/auth';
15
- import { AXUSLocaleProfile, AXIRLocaleProfile } from '@acorex/core/locale';
16
- import { AXTranslationService } from '@acorex/core/translation';
15
+ import { Router } from '@angular/router';
16
+ import { AXCUtilsModule, AXCExternalAuthorizationService } from '@acorex/connectivity/utils';
17
17
 
18
18
  class AXCApiEntityStorageService {
19
19
  constructor(http) {
@@ -131,13 +131,152 @@ class AXCApiEntityStorageService {
131
131
  };
132
132
  });
133
133
  }
134
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXCApiEntityStorageService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
135
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXCApiEntityStorageService }); }
134
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCApiEntityStorageService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
135
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCApiEntityStorageService }); }
136
136
  }
137
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXCApiEntityStorageService, decorators: [{
137
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCApiEntityStorageService, decorators: [{
138
138
  type: Injectable
139
139
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
140
140
 
141
+ class AXCFileStorageApiService extends AXPFileStorageService {
142
+ constructor() {
143
+ super(...arguments);
144
+ this.http = inject(HttpClient);
145
+ //#region ---- API Endpoints ----
146
+ this.baseUrl = '/api/file-storage';
147
+ //#endregion
148
+ //#region ---- Fallback Data ----
149
+ this.fallbackFileInfo = {
150
+ fileId: 'fallback-file-id',
151
+ refId: 'fallback-ref-id',
152
+ refType: 'fallback-ref-type',
153
+ category: 'fallback-category',
154
+ size: 0,
155
+ mimeType: 'application/octet-stream',
156
+ uploadedAt: new Date(),
157
+ isPublic: true,
158
+ isPrimary: false,
159
+ status: AXPFileStorageStatus.Temporary,
160
+ name: 'fallback-file',
161
+ binary: new File([''], 'fallback-file'),
162
+ };
163
+ }
164
+ //#endregion
165
+ async save(request) {
166
+ try {
167
+ const formData = new FormData();
168
+ formData.append('file', request.file);
169
+ formData.append('refId', request.refId);
170
+ formData.append('refType', request.refType);
171
+ formData.append('category', request.category);
172
+ if (request.name) {
173
+ formData.append('name', request.name);
174
+ }
175
+ if (request.path) {
176
+ formData.append('path', request.path);
177
+ }
178
+ if (request.isPrimary !== undefined) {
179
+ formData.append('isPrimary', request.isPrimary.toString());
180
+ }
181
+ if (request.status) {
182
+ formData.append('status', request.status);
183
+ }
184
+ if (request.metadata) {
185
+ formData.append('metadata', JSON.stringify(request.metadata));
186
+ }
187
+ return await firstValueFrom(this.http.post(`${this.baseUrl}/save`, formData).pipe(catchError(() => of(this.fallbackFileInfo))));
188
+ }
189
+ catch {
190
+ return this.fallbackFileInfo;
191
+ }
192
+ }
193
+ async update(request) {
194
+ try {
195
+ const updateData = {
196
+ metadata: request.metadata,
197
+ };
198
+ if (request.path !== undefined) {
199
+ updateData.path = request.path;
200
+ }
201
+ if (request.isPrimary !== undefined) {
202
+ updateData.isPrimary = request.isPrimary;
203
+ }
204
+ return await firstValueFrom(this.http.put(`${this.baseUrl}/update/${request.fileId}`, updateData).pipe(catchError(() => of(this.fallbackFileInfo))));
205
+ }
206
+ catch {
207
+ return this.fallbackFileInfo;
208
+ }
209
+ }
210
+ async find(request) {
211
+ try {
212
+ let params = new HttpParams();
213
+ if (request.refId) {
214
+ params = params.set('refId', request.refId);
215
+ }
216
+ if (request.refType) {
217
+ params = params.set('refType', request.refType);
218
+ }
219
+ if (request.category) {
220
+ params = params.set('category', request.category);
221
+ }
222
+ if (request.mimeType) {
223
+ params = params.set('mimeType', request.mimeType);
224
+ }
225
+ if (request.isPublic !== undefined) {
226
+ params = params.set('isPublic', request.isPublic.toString());
227
+ }
228
+ if (request.isPrimary !== undefined) {
229
+ params = params.set('isPrimary', request.isPrimary.toString());
230
+ }
231
+ if (request.uploadedAtRange) {
232
+ params = params.set('uploadedAtFrom', request.uploadedAtRange.from.toISOString());
233
+ params = params.set('uploadedAtTo', request.uploadedAtRange.to.toISOString());
234
+ }
235
+ return await firstValueFrom(this.http.get(`${this.baseUrl}/find`, { params }).pipe(catchError(() => of([]))));
236
+ }
237
+ catch {
238
+ return [];
239
+ }
240
+ }
241
+ async getInfo(fileId) {
242
+ try {
243
+ return await firstValueFrom(this.http.get(`${this.baseUrl}/info/${fileId}`).pipe(catchError(() => of(this.fallbackFileInfo))));
244
+ }
245
+ catch {
246
+ return this.fallbackFileInfo;
247
+ }
248
+ }
249
+ async remove(fileId) {
250
+ try {
251
+ await firstValueFrom(this.http.delete(`${this.baseUrl}/remove/${fileId}`).pipe(catchError(() => of(void 0))));
252
+ }
253
+ catch {
254
+ // Silently fail in fallback mode
255
+ }
256
+ }
257
+ async commit(fileId) {
258
+ try {
259
+ await firstValueFrom(this.http.post(`${this.baseUrl}/commit/${fileId}`, {}).pipe(catchError(() => of(void 0))));
260
+ }
261
+ catch {
262
+ // Silently fail in fallback mode
263
+ }
264
+ }
265
+ async markForDeletion(fileId) {
266
+ try {
267
+ await firstValueFrom(this.http.post(`${this.baseUrl}/mark-for-deletion/${fileId}`, {}).pipe(catchError(() => of(void 0))));
268
+ }
269
+ catch {
270
+ // Silently fail in fallback mode
271
+ }
272
+ }
273
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCFileStorageApiService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
274
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCFileStorageApiService }); }
275
+ }
276
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCFileStorageApiService, decorators: [{
277
+ type: Injectable
278
+ }] });
279
+
141
280
  class AXMOidcApplicationLoader {
142
281
  constructor(http) {
143
282
  this.http = http;
@@ -179,10 +318,10 @@ class AXMOidcApplicationLoader {
179
318
  // features: item.features || [],
180
319
  };
181
320
  }
182
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcApplicationLoader, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
183
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcApplicationLoader }); }
321
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMOidcApplicationLoader, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
322
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMOidcApplicationLoader }); }
184
323
  }
185
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcApplicationLoader, decorators: [{
324
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMOidcApplicationLoader, decorators: [{
186
325
  type: Injectable
187
326
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
188
327
 
@@ -222,10 +361,10 @@ class AXMConfigurationService {
222
361
  switchMap(() => of(this.applicationConfig)));
223
362
  }
224
363
  }
225
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMConfigurationService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
226
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMConfigurationService, providedIn: 'root' }); }
364
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMConfigurationService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
365
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMConfigurationService, providedIn: 'root' }); }
227
366
  }
228
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMConfigurationService, decorators: [{
367
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMConfigurationService, decorators: [{
229
368
  type: Injectable,
230
369
  args: [{
231
370
  providedIn: 'root',
@@ -252,22 +391,24 @@ class AXMOidcFeatureLoader {
252
391
  }
253
392
  }
254
393
 
255
- class AXMOidcStrategy {
394
+ //#endregion
395
+ class AXCAPIOidcStrategy extends AXPAuthStrategy {
256
396
  constructor() {
397
+ super(...arguments);
257
398
  this.aXMAuthConfigs = inject(AXM_AUTH_CONFIG_TOKEN);
258
399
  this.oauthService = inject(OAuthService);
259
400
  this.http = inject(HttpClient);
401
+ this.sessionService = inject(AXPSessionService);
402
+ this.router = inject(Router);
260
403
  }
261
404
  async configureOAuth() {
262
405
  if (this.openidConfigurationInfo)
263
406
  return;
264
- if (!this.authConfig) {
265
- if (!this.aXMAuthConfigs.authConfig) {
266
- throw new Error('authConfig is missing');
267
- }
268
- this.authConfig = this.aXMAuthConfigs.authConfig;
407
+ // Validation: اطمینان از وجود authConfig
408
+ if (!this.aXMAuthConfigs.authConfig) {
409
+ throw new Error('authConfig is missing. Please check your environment configuration.');
269
410
  }
270
- this.oauthService.configure(this.authConfig);
411
+ this.oauthService.configure(this.aXMAuthConfigs.authConfig);
271
412
  this.oauthService.setStorage(localStorage);
272
413
  this.openidConfigurationInfo = await this.oauthService.loadDiscoveryDocument();
273
414
  if (!this.openidConfigurationInfo) {
@@ -286,179 +427,290 @@ class AXMOidcStrategy {
286
427
  if (oidcJson) {
287
428
  const authData = JSON.parse(oidcJson);
288
429
  if (authData) {
289
- this.setServiceProps(authData);
430
+ this.sessionService.setSession(authData);
290
431
  if (authData.expiresIn && new Date(authData.expiresIn) < new Date()) {
291
432
  if (authData.expiresIn) {
292
- // this.refresh();
433
+ this.sessionService.refreshToken();
293
434
  }
294
435
  else {
295
- this.logout();
436
+ this.signout();
296
437
  }
297
438
  }
298
439
  }
299
440
  }
300
441
  }
301
442
  async signin(credentials) {
443
+ // If OIDC with username/password
444
+ if (credentials.strategy === 'oidc' && credentials.username && credentials.password) {
445
+ await this.handleOidcPasswordSignin(credentials);
446
+ await new Promise(() => { }); // Keeps the promise pending until another flow (e.g., OAuth callback) completes
447
+ }
448
+ throw new Error(`Authentication method or credentials not supported: ${credentials.strategy}`);
449
+ }
450
+ async handleOidcPasswordSignin(credentials) {
302
451
  await this.configureOAuth();
303
- try {
304
- const body = new HttpParams()
305
- .set('grant_type', 'password')
306
- .set('client_id', this.authConfig.clientId)
307
- .set('client_secret', this.authConfig.dummyClientSecret)
308
- .set('username', credentials.username)
309
- .set('password', credentials.password)
310
- .set('scope', this.authConfig.scope);
311
- const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
312
- const response = await firstValueFrom(this.http.post(this.openidConfigurationInfo.info.discoveryDocument.token_endpoint, body.toString(), { headers }));
313
- // const authData = new AuthenticationData(response);
314
- this.setServiceProps({
315
- accessToken: response.access_token,
316
- refreshToken: response.refresh_token,
317
- idToken: response.id_token,
318
- expiresIn: this.calculateExpireInDate(response.expires_in ?? 0),
319
- });
320
- return {
321
- succeed: true,
322
- data: {
323
- accessToken: response.access_token,
324
- expiresIn: this.calculateExpireInDate(response.expires_in ?? 0),
325
- idToken: response.id_token,
326
- refreshToken: response.refresh_token,
327
- user: {
328
- id: response.sub,
329
- title: response.fullname,
330
- name: response.sub,
331
- avatar: response.picture,
332
- },
333
- tenant: {
334
- id: response.tenantid,
335
- name: response.tenantname,
336
- title: response.tenanttitle,
337
- },
338
- application: {
339
- id: response.applicationid,
340
- name: response.applicationname,
341
- title: response.applicationtitle,
342
- },
343
- },
344
- };
452
+ // Validation: اطمینان از وجود baseUrl
453
+ if (!this.aXMAuthConfigs.baseUrl) {
454
+ throw new Error('baseUrl is missing. Please check your environment configuration.');
345
455
  }
346
- catch (error) {
347
- this.handleError(error);
456
+ // استفاده از baseUrl از configuration
457
+ const baseUrl = this.aXMAuthConfigs.baseUrl;
458
+ const loginRes = await fetch(baseUrl + '/auth/manual-login', {
459
+ method: 'POST',
460
+ headers: { 'Content-Type': 'application/json' },
461
+ body: JSON.stringify({ username: credentials.username, password: credentials.password }),
462
+ credentials: 'include',
463
+ });
464
+ if (!loginRes.ok) {
465
+ let errorText = 'Login failed';
466
+ try {
467
+ const errorJson = await loginRes.json();
468
+ if (errorJson && errorJson.error && errorJson.error.description) {
469
+ errorText = errorJson.error.description;
470
+ }
471
+ }
472
+ catch {
473
+ try {
474
+ const text = await loginRes.text();
475
+ if (text) {
476
+ errorText = text;
477
+ }
478
+ }
479
+ catch { }
480
+ }
481
+ throw new Error(errorText);
348
482
  }
483
+ // Check if response is JSON or text
484
+ const contentType = loginRes.headers.get('content-type');
485
+ let result;
486
+ if (contentType && contentType.includes('application/json')) {
487
+ result = await loginRes.json();
488
+ }
489
+ else {
490
+ // Handle text response (like "Login successful")
491
+ const responseText = await loginRes.text();
492
+ console.log('Server response:', responseText);
493
+ }
494
+ await this.updateToken({});
349
495
  }
350
- async signout() {
351
- //this.logout();
352
- }
353
- async refreshToken(context) {
496
+ async updateToken(params) {
354
497
  try {
355
- await this.configureOAuth();
356
- const refreshResult = await this.refresh(context.tenant?.id, context.application?.id);
357
- if (refreshResult) {
498
+ // Ensure OAuth is configured first
499
+ if (!this.openidConfigurationInfo) {
500
+ await this.configureOAuth();
501
+ }
502
+ // Validation: اطمینان از وجود authConfig
503
+ if (!this.aXMAuthConfigs.authConfig) {
504
+ throw new Error('authConfig is missing. Please check your environment configuration.');
505
+ }
506
+ // get Token Code
507
+ if (params['code']) {
508
+ // If params contains 'code', exchange it for tokens using the OpenIddict token endpoint
509
+ const code = params['code'];
510
+ const redirectUri = params['redirectUri'] || this.aXMAuthConfigs.authConfig.redirectUri;
511
+ const clientId = params['clientId'] || this.aXMAuthConfigs.authConfig.clientId;
512
+ const tokenEndpoint = params['tokenEndpoint'] ||
513
+ this.openidConfigurationInfo?.info?.discoveryDocument?.token_endpoint ||
514
+ `${this.aXMAuthConfigs?.authConfig?.issuer}/connect/token`;
515
+ // Get code_verifier from localStorage (PKCE)
516
+ const codeVerifier = localStorage.getItem('pkce_code_verifier');
517
+ localStorage.removeItem('pkce_code_verifier');
518
+ if (!codeVerifier) {
519
+ throw new Error('Code verifier not found. Please try signing in again.');
520
+ }
521
+ // Prepare body for token request
522
+ const body = new URLSearchParams({
523
+ grant_type: 'authorization_code',
524
+ client_id: clientId,
525
+ code_verifier: codeVerifier,
526
+ code: code,
527
+ redirect_uri: redirectUri,
528
+ });
529
+ // Call the token endpoint (OpenIddict)
530
+ const response = await fetch(tokenEndpoint, {
531
+ method: 'POST',
532
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
533
+ body: body.toString(),
534
+ });
535
+ if (!response.ok) {
536
+ throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);
537
+ }
538
+ const tokenData = await response.json();
539
+ if (!tokenData) {
540
+ throw new Error('Token data not found');
541
+ }
542
+ const payload = JwtUtil.parseJwt(tokenData.id_token);
543
+ if (!payload) {
544
+ throw new Error('Payload not found');
545
+ }
546
+ const user = {
547
+ id: payload['sub'] || payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'] || '',
548
+ title: payload['name'] || payload['email'] || '',
549
+ name: payload['name'] || payload['email'] || '',
550
+ avatar: payload['picture'] || '',
551
+ };
552
+ const tenant = payload['tenantid'] || payload['tenant']
553
+ ? {
554
+ id: payload['tenantid'] || payload['tenant'] || '',
555
+ name: payload['tenantname'] || '',
556
+ title: payload['tenanttitle'] || '',
557
+ }
558
+ : undefined;
559
+ const application = payload['applicationid'] || payload['application']
560
+ ? {
561
+ id: payload['applicationid'] || payload['application'] || '',
562
+ name: payload['applicationname'] || '',
563
+ title: payload['applicationtitle'] || '',
564
+ }
565
+ : undefined;
566
+ console.log('payload', payload);
358
567
  return {
359
568
  succeed: true,
360
569
  data: {
361
- accessToken: this.oauthService.getAccessToken(),
362
- refreshToken: this.oauthService.getRefreshToken(),
570
+ accessToken: tokenData.access_token,
571
+ refreshToken: tokenData.refresh_token,
572
+ idToken: tokenData.id_token,
573
+ expiresIn: TimeUtil.calculateExpireInDate(tokenData.expires_in || 0),
574
+ user,
575
+ tenant,
576
+ application,
363
577
  },
364
578
  };
365
579
  }
580
+ // get Authorizeation Code
366
581
  else {
367
- return { succeed: false };
582
+ // Validation: اطمینان از وجود authConfig
583
+ if (!this.aXMAuthConfigs.authConfig) {
584
+ throw new Error('authConfig is missing. Please check your environment configuration.');
585
+ }
586
+ // Extract parameters
587
+ // Support both direct id fields and nested tenant/application objects
588
+ const tenantId = params['tenantId'] ?? params['tenant']?.id ?? null;
589
+ const applicationId = params['applicationId'] ?? params['application']?.id ?? null;
590
+ const redirectUri = params['redirectUri'] || this.aXMAuthConfigs.authConfig.redirectUri;
591
+ const scope = params['scope'] || this.aXMAuthConfigs.authConfig.scope;
592
+ // Generate PKCE code verifier and challenge
593
+ const codeVerifier = PkceUtil.generateRandomString(128);
594
+ localStorage.setItem('pkce_code_verifier', codeVerifier);
595
+ const codeChallenge = await PkceUtil.generateCodeChallenge(codeVerifier);
596
+ // Build authorization URL
597
+ const authorizeEndpoint = this.openidConfigurationInfo.info.discoveryDocument.authorization_endpoint;
598
+ const clientId = this.aXMAuthConfigs.authConfig.clientId;
599
+ const responseType = 'code';
600
+ const state = Math.random().toString(36).substring(2);
601
+ const queryParams = [
602
+ `response_type=${encodeURIComponent(responseType)}`,
603
+ `client_id=${encodeURIComponent(clientId)}`,
604
+ `redirect_uri=${encodeURIComponent(redirectUri)}`,
605
+ `scope=${encodeURIComponent(scope)}`,
606
+ `state=${encodeURIComponent(state)}`,
607
+ tenantId ? `tenant_id=${encodeURIComponent(tenantId)}` : null,
608
+ applicationId ? `application_id=${encodeURIComponent(applicationId)}` : null,
609
+ `code_challenge=${encodeURIComponent(codeChallenge)}`,
610
+ `code_challenge_method=S256`,
611
+ ]
612
+ .filter(Boolean)
613
+ .join('&');
614
+ const authorizeUrl = `${authorizeEndpoint}?${queryParams}`;
615
+ window.location.href = authorizeUrl;
368
616
  }
369
617
  }
370
618
  catch (error) {
371
- console.error('Error refreshing token', error);
372
- return { succeed: false };
619
+ this.handleError(error);
373
620
  }
374
621
  }
375
- async refresh(tenantId, applicationId) {
376
- await this.configureOAuth();
377
- const authData = this.loadAuthData();
378
- if (!authData)
379
- return false;
380
- const refreshToken = this.oauthService.getRefreshToken();
381
- if (!refreshToken)
382
- return false;
383
- const body = new HttpParams()
384
- .set('grant_type', 'refresh_token')
385
- .set('client_id', this.authConfig.clientId)
386
- .set('client_secret', this.authConfig.dummyClientSecret)
387
- .set('refresh_token', refreshToken)
388
- .set('tenantId', tenantId ?? '')
389
- .set('applicationId', applicationId ?? '');
390
- const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
622
+ async signout() {
623
+ localStorage.removeItem('pkce_code_verifier');
624
+ localStorage.removeItem('oauth_provider');
625
+ console.log(this.openidConfigurationInfo?.info?.discoveryDocument);
626
+ const logoutUrl = `${this.aXMAuthConfigs?.authConfig?.issuer}/connect/logout`;
627
+ window.location.href = logoutUrl;
628
+ }
629
+ async refreshToken(context) {
391
630
  try {
631
+ await this.configureOAuth();
632
+ if (!this.aXMAuthConfigs.authConfig || !this.aXMAuthConfigs.authConfig.clientId) {
633
+ throw new Error('authConfig or clientId is missing');
634
+ }
635
+ const authData = this.loadAuthData();
636
+ if (!authData) {
637
+ return { succeed: false };
638
+ }
639
+ const refreshToken = authData.refreshToken;
640
+ if (!refreshToken) {
641
+ return { succeed: false };
642
+ }
643
+ const body = new HttpParams()
644
+ .set('grant_type', 'refresh_token')
645
+ .set('client_id', this.aXMAuthConfigs.authConfig.clientId)
646
+ .set('refresh_token', refreshToken);
647
+ const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
392
648
  const response = await firstValueFrom(this.http.post(this.openidConfigurationInfo.info.discoveryDocument.token_endpoint, body.toString(), { headers }));
393
- this.setServiceProps({
649
+ // Extract user, tenant, and application from id_token
650
+ const payload = JwtUtil.parseJwt(response.id_token);
651
+ const user = {
652
+ id: payload['sub'] || payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'] || '',
653
+ title: payload['name'] || payload['email'] || '',
654
+ name: payload['name'] || payload['email'] || '',
655
+ avatar: payload['picture'] || '',
656
+ };
657
+ const tenant = payload['tenantid'] || payload['tenant']
658
+ ? {
659
+ id: payload['tenantid'] || payload['tenant'] || '',
660
+ name: payload['tenantname'] || '',
661
+ title: payload['tenanttitle'] || '',
662
+ }
663
+ : undefined;
664
+ const application = payload['applicationid'] || payload['application']
665
+ ? {
666
+ id: payload['applicationid'] || payload['application'] || '',
667
+ name: payload['applicationname'] || '',
668
+ title: payload['applicationtitle'] || '',
669
+ }
670
+ : undefined;
671
+ const sessionData = {
394
672
  accessToken: response.access_token,
395
673
  refreshToken: response.refresh_token,
396
674
  idToken: response.id_token,
397
- expiresIn: this.calculateExpireInDate(response.expires_in ?? 0),
398
- });
399
- return true;
675
+ strategy: 'oidc',
676
+ expiresIn: TimeUtil.calculateExpireInDate(response.expires_in ?? 0),
677
+ user,
678
+ tenant,
679
+ application,
680
+ };
681
+ // this.setServiceProps(sessionData);
682
+ return {
683
+ succeed: true,
684
+ data: {
685
+ ...sessionData,
686
+ user: sessionData.user, // Ensure user is not undefined
687
+ },
688
+ };
400
689
  }
401
690
  catch (error) {
402
- console.error('Token refresh error', error);
403
- return false;
404
- }
405
- }
406
- expires_in_milisecound(expires_in_date) {
407
- const now = new Date();
408
- const expire = new Date(expires_in_date);
409
- return expire.getTime() - now.getTime();
410
- }
411
- setServiceProps(authData) {
412
- this.oauthService.getAccessToken = () => authData.accessToken;
413
- this.oauthService.getIdToken = () => authData.idToken ?? '';
414
- this.oauthService.getRefreshToken = () => authData.refreshToken;
415
- if (authData.expiresIn) {
416
- const refreshTime = this.expires_in_milisecound(authData.expiresIn);
417
- this.oauthService.getAccessTokenExpiration = () => refreshTime;
418
- // if (refreshTime < 0) {
419
- // this.refresh();
420
- // }else{
421
- // }
691
+ console.error('Error refreshing token', error);
692
+ return { succeed: false };
422
693
  }
423
694
  }
424
695
  loadAuthData() {
425
- const authDataJson = localStorage.getItem(AXPSessionService.SESSION_KEY);
426
- if (!authDataJson)
427
- return undefined;
428
- const authData = JSON.parse(authDataJson);
429
- // return authData ? new AuthenticationData(authData) : undefined;
430
- return authData;
696
+ const sessionData = this.sessionService.getSessionData();
697
+ return sessionData || undefined;
431
698
  }
432
699
  async loadUserInfo() {
433
700
  return this.oauthService.loadUserProfile();
434
701
  }
435
- calculateExpireInDate(expireInMilisecound) {
436
- return new Date(Date.now() + expireInMilisecound * 1000).toISOString();
437
- }
438
- logout() {
439
- this.oauthService.logOut({
440
- noRedirectToLogoutUrl: true,
441
- });
442
- }
443
702
  handleError(error) {
444
- if (error?.reason) {
445
- throw new Error(JSON.stringify(error.reason));
446
- }
447
- else if (error?.message) {
448
- throw new Error(error.message);
449
- }
450
- else {
451
- throw new Error('Network or server error occurred');
452
- }
703
+ console.error('Authentication error:', error);
704
+ throw error;
453
705
  }
454
706
  //#region getter
455
707
  get name() {
456
- return 'user-pass';
708
+ return 'oidc';
457
709
  }
458
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
459
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcStrategy }); }
710
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCAPIOidcStrategy, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
711
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCAPIOidcStrategy }); }
460
712
  }
461
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcStrategy, decorators: [{
713
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCAPIOidcStrategy, decorators: [{
462
714
  type: Injectable
463
715
  }] });
464
716
 
@@ -483,10 +735,10 @@ class AXMOidcPermissionLoader {
483
735
  const truePolicies = Object.keys(policies).filter((key) => policies[key] === true);
484
736
  return truePolicies;
485
737
  }
486
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcPermissionLoader, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
487
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcPermissionLoader }); }
738
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMOidcPermissionLoader, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
739
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMOidcPermissionLoader }); }
488
740
  }
489
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcPermissionLoader, decorators: [{
741
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMOidcPermissionLoader, decorators: [{
490
742
  type: Injectable
491
743
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
492
744
 
@@ -512,419 +764,29 @@ class AXMOidcTenantLoader {
512
764
  // Add other fields and defaults as needed, and handle the logo if applicable
513
765
  };
514
766
  }
515
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcTenantLoader, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
516
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcTenantLoader }); }
767
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMOidcTenantLoader, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
768
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMOidcTenantLoader }); }
517
769
  }
518
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXMOidcTenantLoader, decorators: [{
770
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXMOidcTenantLoader, decorators: [{
519
771
  type: Injectable
520
772
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
521
773
 
522
- class AXCFileStorageApiService extends AXPFileStorageService {
523
- constructor() {
524
- super(...arguments);
525
- this.http = inject(HttpClient);
526
- //#region ---- API Endpoints ----
527
- this.baseUrl = '/api/file-storage';
528
- //#endregion
529
- //#region ---- Fallback Data ----
530
- this.fallbackFileInfo = {
531
- fileId: 'fallback-file-id',
532
- refId: 'fallback-ref-id',
533
- refType: 'fallback-ref-type',
534
- category: 'fallback-category',
535
- size: 0,
536
- mimeType: 'application/octet-stream',
537
- uploadedAt: new Date(),
538
- isPublic: true,
539
- isPrimary: false,
540
- status: AXPFileStorageStatus.Temporary,
541
- name: 'fallback-file',
542
- binary: new File([''], 'fallback-file'),
543
- };
544
- }
545
- //#endregion
546
- async save(request) {
547
- try {
548
- const formData = new FormData();
549
- formData.append('file', request.file);
550
- formData.append('refId', request.refId);
551
- formData.append('refType', request.refType);
552
- formData.append('category', request.category);
553
- if (request.name) {
554
- formData.append('name', request.name);
555
- }
556
- if (request.path) {
557
- formData.append('path', request.path);
558
- }
559
- if (request.isPrimary !== undefined) {
560
- formData.append('isPrimary', request.isPrimary.toString());
561
- }
562
- if (request.status) {
563
- formData.append('status', request.status);
564
- }
565
- if (request.metadata) {
566
- formData.append('metadata', JSON.stringify(request.metadata));
567
- }
568
- return await firstValueFrom(this.http.post(`${this.baseUrl}/save`, formData).pipe(catchError(() => of(this.fallbackFileInfo))));
569
- }
570
- catch {
571
- return this.fallbackFileInfo;
572
- }
573
- }
574
- async update(request) {
575
- try {
576
- const updateData = {
577
- metadata: request.metadata,
578
- };
579
- if (request.path !== undefined) {
580
- updateData.path = request.path;
581
- }
582
- if (request.isPrimary !== undefined) {
583
- updateData.isPrimary = request.isPrimary;
584
- }
585
- return await firstValueFrom(this.http.put(`${this.baseUrl}/update/${request.fileId}`, updateData).pipe(catchError(() => of(this.fallbackFileInfo))));
586
- }
587
- catch {
588
- return this.fallbackFileInfo;
589
- }
590
- }
591
- async find(request) {
592
- try {
593
- let params = new HttpParams();
594
- if (request.refId) {
595
- params = params.set('refId', request.refId);
596
- }
597
- if (request.refType) {
598
- params = params.set('refType', request.refType);
599
- }
600
- if (request.category) {
601
- params = params.set('category', request.category);
602
- }
603
- if (request.mimeType) {
604
- params = params.set('mimeType', request.mimeType);
605
- }
606
- if (request.isPublic !== undefined) {
607
- params = params.set('isPublic', request.isPublic.toString());
608
- }
609
- if (request.isPrimary !== undefined) {
610
- params = params.set('isPrimary', request.isPrimary.toString());
611
- }
612
- if (request.uploadedAtRange) {
613
- params = params.set('uploadedAtFrom', request.uploadedAtRange.from.toISOString());
614
- params = params.set('uploadedAtTo', request.uploadedAtRange.to.toISOString());
615
- }
616
- return await firstValueFrom(this.http.get(`${this.baseUrl}/find`, { params }).pipe(catchError(() => of([]))));
617
- }
618
- catch {
619
- return [];
620
- }
621
- }
622
- async getInfo(fileId) {
623
- try {
624
- return await firstValueFrom(this.http.get(`${this.baseUrl}/info/${fileId}`).pipe(catchError(() => of(this.fallbackFileInfo))));
625
- }
626
- catch {
627
- return this.fallbackFileInfo;
628
- }
629
- }
630
- async remove(fileId) {
631
- try {
632
- await firstValueFrom(this.http.delete(`${this.baseUrl}/remove/${fileId}`).pipe(catchError(() => of(void 0))));
633
- }
634
- catch {
635
- // Silently fail in fallback mode
636
- }
637
- }
638
- async commit(fileId) {
639
- try {
640
- await firstValueFrom(this.http.post(`${this.baseUrl}/commit/${fileId}`, {}).pipe(catchError(() => of(void 0))));
641
- }
642
- catch {
643
- // Silently fail in fallback mode
644
- }
645
- }
646
- async markForDeletion(fileId) {
647
- try {
648
- await firstValueFrom(this.http.post(`${this.baseUrl}/mark-for-deletion/${fileId}`, {}).pipe(catchError(() => of(void 0))));
649
- }
650
- catch {
651
- // Silently fail in fallback mode
652
- }
653
- }
654
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXCFileStorageApiService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
655
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXCFileStorageApiService }); }
656
- }
657
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXCFileStorageApiService, decorators: [{
658
- type: Injectable
659
- }] });
660
-
661
- class AXCRegionalApiService extends AXPRegionalService {
662
- constructor() {
663
- super(...arguments);
664
- this.http = inject(HttpClient);
665
- this.languageService = inject(AXTranslationService);
666
- //#region ---- API Endpoints ----
667
- this.baseUrl = '/api/regional';
668
- //#endregion
669
- //#region ---- Fallback Data ----
670
- this.fallbackCountries = [
671
- {
672
- code: 'US',
673
- title: 'United States',
674
- native: 'United States',
675
- regional: 'en',
676
- timezone: 'America/New_York'
677
- },
678
- {
679
- code: 'CA',
680
- title: 'Canada',
681
- native: 'Canada',
682
- regional: 'en',
683
- timezone: 'America/Toronto'
684
- },
685
- {
686
- code: 'GB',
687
- title: 'United Kingdom',
688
- native: 'United Kingdom',
689
- regional: 'en',
690
- timezone: 'Europe/London'
691
- }
692
- ];
693
- this.fallbackProvinces = [
694
- {
695
- code: 'CA',
696
- title: 'California',
697
- native: 'California',
698
- timezone: 'America/Los_Angeles'
699
- },
700
- {
701
- code: 'NY',
702
- title: 'New York',
703
- native: 'New York',
704
- timezone: 'America/New_York'
705
- },
706
- {
707
- code: 'ON',
708
- title: 'Ontario',
709
- native: 'Ontario',
710
- timezone: 'America/Toronto'
711
- }
712
- ];
713
- this.fallbackCities = [
714
- {
715
- code: 'NYC',
716
- title: 'New York City',
717
- native: 'New York City',
718
- timezone: 'America/New_York'
719
- },
720
- {
721
- code: 'LA',
722
- title: 'Los Angeles',
723
- native: 'Los Angeles',
724
- timezone: 'America/Los_Angeles'
725
- },
726
- {
727
- code: 'TOR',
728
- title: 'Toronto',
729
- native: 'Toronto',
730
- timezone: 'America/Toronto'
731
- }
732
- ];
733
- this.fallbackCurrencies = [
734
- {
735
- code: 'USD',
736
- title: 'United States Dollar',
737
- symbol: '$',
738
- format: '${amount}'
739
- },
740
- {
741
- code: 'CAD',
742
- title: 'Canadian Dollar',
743
- symbol: 'CA$',
744
- format: 'CA${amount}'
745
- },
746
- {
747
- code: 'GBP',
748
- title: 'British Pound',
749
- symbol: '£',
750
- format: '£{amount}'
751
- }
752
- ];
753
- this.fallbackLocaleProfiles = [
754
- {
755
- ...AXUSLocaleProfile,
756
- code: 'en-US',
757
- title: 'English (United States)',
758
- nativeTitle: 'English (United States)',
759
- },
760
- {
761
- ...AXIRLocaleProfile,
762
- code: 'fa-IR',
763
- title: 'Persian (Iran)',
764
- nativeTitle: 'فارسی (ایران)',
765
- }
766
- ];
767
- this.fallbackLanguages = [
768
- {
769
- code: 'en',
770
- title: 'English'
771
- },
772
- {
773
- code: 'fa',
774
- title: 'Persian'
775
- },
776
- {
777
- code: 'es',
778
- title: 'Spanish'
779
- }
780
- ];
781
- this.fallbackTimeZones = [
782
- {
783
- code: 'America/New_York',
784
- title: 'Eastern Time (US & Canada)',
785
- offset: '-05:00',
786
- iana: 'America/New_York',
787
- abbr: 'EST'
788
- },
789
- {
790
- code: 'America/Los_Angeles',
791
- title: 'Pacific Time (US & Canada)',
792
- offset: '-08:00',
793
- iana: 'America/Los_Angeles',
794
- abbr: 'PST'
795
- },
796
- {
797
- code: 'Europe/London',
798
- title: 'Greenwich Mean Time',
799
- offset: '+00:00',
800
- iana: 'Europe/London',
801
- abbr: 'GMT'
802
- }
803
- ];
804
- }
805
- //#endregion
806
- async getCountries() {
807
- const lang = await firstValueFrom(this.languageService.langChanges$);
808
- try {
809
- const countries = await firstValueFrom(this.http.get(`${this.baseUrl}/countries`).pipe(catchError(() => of(this.fallbackCountries))));
810
- return countries.map((country) => {
811
- if (lang == country.regional) {
812
- return {
813
- ...country,
814
- title: country.native,
815
- };
816
- }
817
- else {
818
- return country;
819
- }
820
- });
821
- }
822
- catch {
823
- return this.fallbackCountries.map((country) => {
824
- if (lang == country.regional) {
825
- return {
826
- ...country,
827
- title: country.native,
828
- };
829
- }
830
- else {
831
- return country;
832
- }
833
- });
834
- }
835
- }
836
- async getProvinces(countryId) {
837
- let params = new HttpParams();
838
- if (countryId) {
839
- params = params.set('countryId', countryId);
840
- }
841
- try {
842
- return await firstValueFrom(this.http.get(`${this.baseUrl}/provinces`, { params }).pipe(catchError(() => of(this.fallbackProvinces))));
843
- }
844
- catch {
845
- return this.fallbackProvinces;
846
- }
847
- }
848
- async getCities(filter) {
849
- let params = new HttpParams();
850
- if (filter?.countryId) {
851
- params = params.set('countryId', filter.countryId);
852
- }
853
- if (filter?.provinceId) {
854
- params = params.set('provinceId', filter.provinceId);
855
- }
856
- try {
857
- return await firstValueFrom(this.http.get(`${this.baseUrl}/cities`, { params }).pipe(catchError(() => of(this.fallbackCities))));
858
- }
859
- catch {
860
- return this.fallbackCities;
861
- }
862
- }
863
- async getCurrencies() {
864
- try {
865
- return await firstValueFrom(this.http.get(`${this.baseUrl}/currencies`).pipe(catchError(() => of(this.fallbackCurrencies))));
866
- }
867
- catch {
868
- return this.fallbackCurrencies;
869
- }
870
- }
871
- async getLocaleProfiles() {
872
- try {
873
- return await firstValueFrom(this.http.get(`${this.baseUrl}/locale-profiles`).pipe(catchError(() => of(this.fallbackLocaleProfiles))));
874
- }
875
- catch {
876
- return this.fallbackLocaleProfiles;
877
- }
878
- }
879
- async getLanguages() {
880
- try {
881
- return await firstValueFrom(this.http.get(`${this.baseUrl}/languages`).pipe(catchError(() => of(this.fallbackLanguages))));
882
- }
883
- catch {
884
- return this.fallbackLanguages;
885
- }
886
- }
887
- async getAvailableLanguages() {
888
- try {
889
- return await firstValueFrom(this.http.get(`${this.baseUrl}/available-languages`).pipe(catchError(() => of(this.fallbackLanguages))));
890
- }
891
- catch {
892
- return this.fallbackLanguages;
893
- }
894
- }
895
- async getBrowserTimeZoneCode() {
896
- return Intl.DateTimeFormat().resolvedOptions().timeZone;
897
- }
898
- async getTimeZones() {
899
- try {
900
- return await firstValueFrom(this.http.get(`${this.baseUrl}/timezones`).pipe(catchError(() => of(this.fallbackTimeZones))));
901
- }
902
- catch {
903
- return this.fallbackTimeZones;
904
- }
905
- }
906
- }
907
-
908
774
  class AXCApiModule {
909
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXCApiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
910
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.3", ngImport: i0, type: AXCApiModule, imports: [i1$1.OAuthModule, i2.AXPAuthModule] }); }
911
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXCApiModule, providers: [
775
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCApiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
776
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.1.4", ngImport: i0, type: AXCApiModule, imports: [i1$1.OAuthModule, i2.AXPAuthModule, AXCUtilsModule] }); }
777
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCApiModule, providers: [
912
778
  {
913
779
  provide: AXPEntityStorageService,
914
780
  useClass: AXCApiEntityStorageService,
915
781
  },
916
- {
917
- provide: AXPRegionalService,
918
- useClass: AXCRegionalApiService,
919
- },
920
782
  {
921
783
  provide: AXPFileStorageService,
922
784
  useClass: AXCFileStorageApiService,
923
785
  },
924
- // {
925
- // provide: AXP_TENANT_LOADER,
926
- // useClass: AXMOidcTenantLoader,
927
- // },
786
+ {
787
+ provide: AXP_TENANT_LOADER,
788
+ useClass: AXMOidcTenantLoader,
789
+ },
928
790
  {
929
791
  provide: AXP_APPLICATION_LOADER,
930
792
  useClass: AXMOidcApplicationLoader,
@@ -946,35 +808,33 @@ class AXCApiModule {
946
808
  },
947
809
  ], imports: [OAuthModule.forRoot(),
948
810
  AXPAuthModule.forRoot({
949
- strategies: [],
950
- })] }); }
811
+ strategies: [AXCAPIOidcStrategy],
812
+ }),
813
+ AXCUtilsModule] }); }
951
814
  }
952
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXCApiModule, decorators: [{
815
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: AXCApiModule, decorators: [{
953
816
  type: NgModule,
954
817
  args: [{
955
818
  imports: [
956
819
  OAuthModule.forRoot(),
957
820
  AXPAuthModule.forRoot({
958
- strategies: [],
821
+ strategies: [AXCAPIOidcStrategy],
959
822
  }),
823
+ AXCUtilsModule,
960
824
  ],
961
825
  providers: [
962
826
  {
963
827
  provide: AXPEntityStorageService,
964
828
  useClass: AXCApiEntityStorageService,
965
829
  },
966
- {
967
- provide: AXPRegionalService,
968
- useClass: AXCRegionalApiService,
969
- },
970
830
  {
971
831
  provide: AXPFileStorageService,
972
832
  useClass: AXCFileStorageApiService,
973
833
  },
974
- // {
975
- // provide: AXP_TENANT_LOADER,
976
- // useClass: AXMOidcTenantLoader,
977
- // },
834
+ {
835
+ provide: AXP_TENANT_LOADER,
836
+ useClass: AXMOidcTenantLoader,
837
+ },
978
838
  {
979
839
  provide: AXP_APPLICATION_LOADER,
980
840
  useClass: AXMOidcApplicationLoader,
@@ -998,9 +858,280 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImpor
998
858
  }]
999
859
  }] });
1000
860
 
861
+ //#region ---- Class Definition ----
862
+ class APIGoogleStrategy extends AXPAuthStrategy {
863
+ constructor() {
864
+ super();
865
+ this.aXMAuthConfigs = inject(AXM_AUTH_CONFIG_TOKEN);
866
+ this.oauthService = inject(OAuthService);
867
+ this.http = inject(HttpClient);
868
+ this.sessionService = inject(AXPSessionService);
869
+ this.router = inject(Router);
870
+ this.externalAuthorizationService = inject(AXCExternalAuthorizationService);
871
+ this.tenantLoader = inject(AXP_TENANT_LOADER);
872
+ this.applicationLoader = inject(AXP_APPLICATION_LOADER);
873
+ }
874
+ get name() {
875
+ return 'google';
876
+ }
877
+ async configureOAuth() {
878
+ if (this.openidConfigurationInfo)
879
+ return;
880
+ if (!this.authConfig) {
881
+ if (!this.aXMAuthConfigs.authConfig) {
882
+ throw new Error('authConfig is missing');
883
+ }
884
+ this.authConfig = this.aXMAuthConfigs.authConfig;
885
+ }
886
+ this.oauthService.configure(this.authConfig);
887
+ this.oauthService.setStorage(localStorage);
888
+ this.openidConfigurationInfo = await this.oauthService.loadDiscoveryDocument();
889
+ if (!this.openidConfigurationInfo) {
890
+ throw new Error('openidConfigurationInfo is missing');
891
+ }
892
+ this.oauthService.events.subscribe(async (event) => {
893
+ // console.log('event', event);
894
+ // if (event.type === 'token_received') {
895
+ // console.log('Token has been refreshed');
896
+ // }
897
+ // if (event.type === 'token_expires') {
898
+ // console.log('Token is about to expire. Triggering silent refresh...');
899
+ // }
900
+ });
901
+ const oidcJson = localStorage.getItem(AXPSessionService.SESSION_KEY);
902
+ if (oidcJson) {
903
+ const authData = JSON.parse(oidcJson);
904
+ if (authData) {
905
+ this.sessionService.setSession(authData);
906
+ if (authData.expiresIn && new Date(authData.expiresIn) < new Date()) {
907
+ if (authData.expiresIn) {
908
+ this.sessionService.refreshToken();
909
+ }
910
+ else {
911
+ this.signout();
912
+ }
913
+ }
914
+ }
915
+ }
916
+ }
917
+ async signin(credentials) {
918
+ const providerName = credentials['strategy'];
919
+ await this.externalAuthorizationService.signin(providerName);
920
+ }
921
+ async signout() {
922
+ localStorage.removeItem('pkce_code_verifier');
923
+ localStorage.removeItem('oauth_provider');
924
+ console.log('User signed out');
925
+ }
926
+ async refreshToken(context) {
927
+ try {
928
+ await this.configureOAuth();
929
+ if (!this.authConfig || !this.authConfig.clientId) {
930
+ throw new Error('authConfig or clientId is missing');
931
+ }
932
+ const authData = this.loadAuthData();
933
+ if (!authData) {
934
+ return { succeed: false };
935
+ }
936
+ const refreshToken = authData.refreshToken;
937
+ if (!refreshToken) {
938
+ return { succeed: false };
939
+ }
940
+ const body = new URLSearchParams({
941
+ grant_type: 'refresh_token',
942
+ client_id: this.authConfig.clientId,
943
+ refresh_token: refreshToken,
944
+ });
945
+ const response = await fetch(this.openidConfigurationInfo.info.discoveryDocument.token_endpoint, {
946
+ method: 'POST',
947
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
948
+ body: body.toString(),
949
+ });
950
+ if (!response.ok) {
951
+ throw new Error(`Token refresh failed: ${response.status} ${response.statusText}`);
952
+ }
953
+ const tokenData = await response.json();
954
+ // Extract user information from the refreshed token
955
+ const payload = JwtUtil.parseJwt(tokenData.id_token);
956
+ const user = {
957
+ id: payload['sub'] || '',
958
+ title: payload['name'] || payload['email'] || '',
959
+ name: payload['name'] || payload['email'] || '',
960
+ avatar: payload['picture'] || '',
961
+ };
962
+ const tenant = payload['tenantid'] || payload['tenant']
963
+ ? {
964
+ id: payload['tenantid'] || payload['tenant'] || '',
965
+ name: payload['tenantname'] || '',
966
+ title: payload['tenanttitle'] || '',
967
+ }
968
+ : undefined;
969
+ const application = payload['applicationid'] || payload['application']
970
+ ? {
971
+ id: payload['applicationid'] || payload['application'] || '',
972
+ name: payload['applicationname'] || '',
973
+ title: payload['applicationtitle'] || '',
974
+ }
975
+ : undefined;
976
+ const sessionData = {
977
+ accessToken: tokenData.access_token,
978
+ refreshToken: tokenData.refresh_token,
979
+ idToken: tokenData.id_token,
980
+ strategy: 'google',
981
+ expiresIn: TimeUtil.calculateExpireInDate(tokenData.expires_in || 0),
982
+ user,
983
+ tenant,
984
+ application,
985
+ };
986
+ return {
987
+ succeed: true,
988
+ data: {
989
+ ...sessionData,
990
+ user: sessionData.user,
991
+ },
992
+ };
993
+ }
994
+ catch (error) {
995
+ console.error('Error refreshing token', error);
996
+ return { succeed: false };
997
+ }
998
+ }
999
+ async updateToken(params) {
1000
+ try {
1001
+ // Ensure OAuth is configured first
1002
+ if (!this.openidConfigurationInfo) {
1003
+ await this.configureOAuth();
1004
+ }
1005
+ // If params contains 'code', exchange it for tokens
1006
+ if (params['code']) {
1007
+ const code = params['code'];
1008
+ const redirectUri = params['redirectUri'] || this.authConfig.redirectUri;
1009
+ const clientId = params['clientId'] || this.authConfig.clientId;
1010
+ const tokenEndpoint = this.openidConfigurationInfo.info.discoveryDocument.token_endpoint;
1011
+ // Get code_verifier from localStorage (PKCE)
1012
+ const codeVerifier = localStorage.getItem('pkce_code_verifier');
1013
+ localStorage.removeItem('pkce_code_verifier');
1014
+ if (!codeVerifier) {
1015
+ throw new Error('Code verifier not found. Please try signing in again.');
1016
+ }
1017
+ // Prepare body for token request
1018
+ const body = new URLSearchParams({
1019
+ grant_type: 'authorization_code',
1020
+ client_id: clientId,
1021
+ code_verifier: codeVerifier,
1022
+ code: code,
1023
+ redirect_uri: redirectUri,
1024
+ });
1025
+ // Call the token endpoint
1026
+ const response = await fetch(tokenEndpoint, {
1027
+ method: 'POST',
1028
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1029
+ body: body.toString(),
1030
+ });
1031
+ if (!response.ok) {
1032
+ throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);
1033
+ }
1034
+ const tokenData = await response.json();
1035
+ if (!tokenData) {
1036
+ throw new Error('Token data not found');
1037
+ }
1038
+ // Parse the ID token to extract user information
1039
+ const payload = JwtUtil.parseJwt(tokenData.id_token);
1040
+ if (!payload) {
1041
+ throw new Error('Payload not found');
1042
+ }
1043
+ const user = {
1044
+ id: payload['sub'] || '',
1045
+ title: payload['name'] || payload['email'] || '',
1046
+ name: payload['name'] || payload['email'] || '',
1047
+ avatar: payload['picture'] || '',
1048
+ };
1049
+ const tenant = payload['tenantid'] || payload['tenant']
1050
+ ? {
1051
+ id: payload['tenantid'] || payload['tenant'] || '',
1052
+ name: payload['tenantname'] || '',
1053
+ title: payload['tenanttitle'] || '',
1054
+ }
1055
+ : undefined;
1056
+ const application = payload['applicationid'] || payload['application']
1057
+ ? {
1058
+ id: payload['applicationid'] || payload['application'] || '',
1059
+ name: payload['applicationname'] || '',
1060
+ title: payload['applicationtitle'] || '',
1061
+ }
1062
+ : undefined;
1063
+ return {
1064
+ succeed: true,
1065
+ data: {
1066
+ accessToken: tokenData.access_token,
1067
+ refreshToken: tokenData.refresh_token,
1068
+ idToken: tokenData.id_token,
1069
+ expiresIn: TimeUtil.calculateExpireInDate(tokenData.expires_in || 0),
1070
+ user,
1071
+ tenant,
1072
+ application,
1073
+ },
1074
+ };
1075
+ }
1076
+ // get Authorizeation Code
1077
+ else {
1078
+ // Extract parameters
1079
+ // Support both direct id fields and nested tenant/application objects
1080
+ const tenantId = params['tenantId'] ?? params['tenant']?.id ?? null;
1081
+ const applicationId = params['applicationId'] ?? params['application']?.id ?? null;
1082
+ const redirectUri = params['redirectUri'] || this.authConfig.redirectUri;
1083
+ const scope = params['scope'] || this.authConfig.scope;
1084
+ // Generate PKCE code verifier and challenge
1085
+ const codeVerifier = PkceUtil.generateRandomString(128);
1086
+ localStorage.setItem('pkce_code_verifier', codeVerifier);
1087
+ const codeChallenge = await PkceUtil.generateCodeChallenge(codeVerifier);
1088
+ // Build authorization URL
1089
+ const authorizeEndpoint = this.openidConfigurationInfo.info.discoveryDocument.authorization_endpoint;
1090
+ const clientId = this.authConfig.clientId;
1091
+ const responseType = 'code';
1092
+ const state = Math.random().toString(36).substring(2);
1093
+ const queryParams = [
1094
+ `response_type=${encodeURIComponent(responseType)}`,
1095
+ `client_id=${encodeURIComponent(clientId)}`,
1096
+ `redirect_uri=${encodeURIComponent(redirectUri)}`,
1097
+ `scope=${encodeURIComponent(scope)}`,
1098
+ `state=${encodeURIComponent(state)}`,
1099
+ tenantId ? `tenant_id=${encodeURIComponent(tenantId)}` : null,
1100
+ applicationId ? `application_id=${encodeURIComponent(applicationId)}` : null,
1101
+ `code_challenge=${encodeURIComponent(codeChallenge)}`,
1102
+ `code_challenge_method=S256`,
1103
+ ]
1104
+ .filter(Boolean)
1105
+ .join('&');
1106
+ const authorizeUrl = `${authorizeEndpoint}?${queryParams}`;
1107
+ window.location.href = authorizeUrl;
1108
+ await new Promise(() => { });
1109
+ return;
1110
+ }
1111
+ }
1112
+ catch (error) {
1113
+ console.error('Error in updateToken:', error);
1114
+ throw error;
1115
+ }
1116
+ }
1117
+ loadAuthData() {
1118
+ const sessionData = this.sessionService.getSessionData();
1119
+ return sessionData || undefined;
1120
+ }
1121
+ handleError(error) {
1122
+ console.error('Authentication error:', error);
1123
+ throw error;
1124
+ }
1125
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: APIGoogleStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1126
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: APIGoogleStrategy }); }
1127
+ }
1128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: APIGoogleStrategy, decorators: [{
1129
+ type: Injectable
1130
+ }], ctorParameters: () => [] });
1131
+
1001
1132
  /**
1002
1133
  * Generated bundle index. Do not edit.
1003
1134
  */
1004
1135
 
1005
- export { AXCApiEntityStorageService, AXCApiModule, AXMConfigurationService, AXMOidcApplicationLoader, AXMOidcFeatureLoader, AXMOidcPermissionLoader, AXMOidcStrategy, AXMOidcTenantLoader };
1136
+ export { APIGoogleStrategy, AXCAPIOidcStrategy, AXCApiEntityStorageService, AXCApiModule, AXMConfigurationService, AXMOidcApplicationLoader, AXMOidcFeatureLoader, AXMOidcPermissionLoader, AXMOidcTenantLoader };
1006
1137
  //# sourceMappingURL=acorex-connectivity-api.mjs.map