@snugdesk/core 0.2.12 → 0.2.13

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.
@@ -3198,6 +3198,195 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3198
3198
  }]
3199
3199
  }], ctorParameters: () => [{ type: AppSyncHelperService }] });
3200
3200
 
3201
+ var StorageType;
3202
+ (function (StorageType) {
3203
+ StorageType["SessionStorage"] = "sessionStorage";
3204
+ StorageType["LocalStorage"] = "localStorage";
3205
+ })(StorageType || (StorageType = {}));
3206
+ class EncryptedStorageService {
3207
+ authenticationService;
3208
+ DEFAULT_TTL_SECONDS = 60 * 60 * 12; // 12 hours
3209
+ constructor(authenticationService) {
3210
+ this.authenticationService = authenticationService;
3211
+ }
3212
+ buildKeys(baseKey) {
3213
+ const dataKey = this.scopedKey(baseKey);
3214
+ return {
3215
+ dataKey,
3216
+ cryptoKey: this.scopedKey(`${baseKey}_KEY`),
3217
+ cryptoKeyCreatedAt: this.scopedKey(`${baseKey}_KEY_CREATED_AT`),
3218
+ };
3219
+ }
3220
+ async getJsonByKey(storageType, baseKey, ttlSeconds) {
3221
+ return this.getJson(storageType, this.buildKeys(baseKey), ttlSeconds);
3222
+ }
3223
+ async setJsonByKey(storageType, baseKey, value, ttlSeconds) {
3224
+ await this.setJson(storageType, this.buildKeys(baseKey), value, ttlSeconds);
3225
+ }
3226
+ async updateJsonByKey(storageType, baseKey, value, ttlSeconds) {
3227
+ await this.updateJson(storageType, this.buildKeys(baseKey), ttlSeconds, () => value);
3228
+ }
3229
+ clearByKey(storageType, baseKey) {
3230
+ this.clear(storageType, this.buildKeys(baseKey));
3231
+ }
3232
+ async getJson(storageType, keys, ttlSeconds) {
3233
+ const storage = this.getStorage(storageType);
3234
+ if (!storage)
3235
+ return null;
3236
+ try {
3237
+ const encrypted = storage.getItem(keys.dataKey);
3238
+ if (!encrypted)
3239
+ return null;
3240
+ const decrypted = await this.decryptString(encrypted, keys, ttlSeconds, storage);
3241
+ if (!decrypted)
3242
+ return null;
3243
+ return JSON.parse(decrypted);
3244
+ }
3245
+ catch (err) {
3246
+ console.warn('Failed to read encrypted storage value:', err);
3247
+ return null;
3248
+ }
3249
+ }
3250
+ async setJson(storageType, keys, value, ttlSeconds) {
3251
+ const storage = this.getStorage(storageType);
3252
+ if (!storage)
3253
+ return;
3254
+ try {
3255
+ const payload = JSON.stringify(value);
3256
+ const encrypted = await this.encryptString(payload, keys, ttlSeconds, storage);
3257
+ if (!encrypted)
3258
+ return;
3259
+ storage.setItem(keys.dataKey, encrypted);
3260
+ }
3261
+ catch (err) {
3262
+ console.warn('Failed to persist encrypted storage value:', err);
3263
+ }
3264
+ }
3265
+ async updateJson(storageType, keys, ttlSeconds, updater) {
3266
+ const current = await this.getJson(storageType, keys, ttlSeconds);
3267
+ const next = await updater(current);
3268
+ if (!next)
3269
+ return;
3270
+ await this.setJson(storageType, keys, next, ttlSeconds);
3271
+ }
3272
+ clear(storageType, keys) {
3273
+ const storage = this.getStorage(storageType);
3274
+ if (!storage)
3275
+ return;
3276
+ try {
3277
+ storage.removeItem(keys.dataKey);
3278
+ }
3279
+ catch (err) {
3280
+ console.warn('Failed to clear encrypted storage value:', err);
3281
+ }
3282
+ }
3283
+ getStorage(storageType) {
3284
+ if (typeof window === 'undefined')
3285
+ return null;
3286
+ return storageType === StorageType.LocalStorage ? window.localStorage : window.sessionStorage;
3287
+ }
3288
+ scopedKey(baseKey) {
3289
+ const tenantId = this.authenticationService.getTenantId();
3290
+ return tenantId ? `${baseKey}:${tenantId}` : baseKey;
3291
+ }
3292
+ nowSeconds() {
3293
+ return Math.floor(Date.now() / 1000);
3294
+ }
3295
+ resolveTtlSeconds(ttlSeconds) {
3296
+ return typeof ttlSeconds === 'number' && ttlSeconds > 0 ? ttlSeconds : this.DEFAULT_TTL_SECONDS;
3297
+ }
3298
+ async getOrCreateCryptoKey(keys, ttlSeconds, storage) {
3299
+ if (!window?.crypto?.subtle)
3300
+ return null;
3301
+ try {
3302
+ const createdAtRaw = storage.getItem(keys.cryptoKeyCreatedAt);
3303
+ const keyRaw = storage.getItem(keys.cryptoKey);
3304
+ const now = this.nowSeconds();
3305
+ const ttl = this.resolveTtlSeconds(ttlSeconds);
3306
+ if (createdAtRaw && keyRaw) {
3307
+ const createdAt = Number(createdAtRaw);
3308
+ const isExpired = !Number.isFinite(createdAt) || now - createdAt > ttl;
3309
+ if (!isExpired) {
3310
+ const jwk = JSON.parse(keyRaw);
3311
+ return await crypto.subtle.importKey('jwk', jwk, { name: 'AES-GCM' }, true, ['encrypt', 'decrypt']);
3312
+ }
3313
+ }
3314
+ const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
3315
+ const jwk = await crypto.subtle.exportKey('jwk', key);
3316
+ storage.setItem(keys.cryptoKey, JSON.stringify(jwk));
3317
+ storage.setItem(keys.cryptoKeyCreatedAt, String(now));
3318
+ return key;
3319
+ }
3320
+ catch (err) {
3321
+ console.warn('Failed to create crypto key:', err);
3322
+ return null;
3323
+ }
3324
+ }
3325
+ async encryptString(plainText, keys, ttlSeconds, storage) {
3326
+ const key = await this.getOrCreateCryptoKey(keys, ttlSeconds, storage);
3327
+ if (!key)
3328
+ return null;
3329
+ try {
3330
+ const iv = crypto.getRandomValues(new Uint8Array(12));
3331
+ const encoded = new TextEncoder().encode(plainText);
3332
+ const cipherBuffer = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoded);
3333
+ const payload = {
3334
+ iv: this.bytesToBase64(iv),
3335
+ data: this.bytesToBase64(new Uint8Array(cipherBuffer)),
3336
+ };
3337
+ return JSON.stringify(payload);
3338
+ }
3339
+ catch (err) {
3340
+ console.warn('Failed to encrypt cache payload:', err);
3341
+ return null;
3342
+ }
3343
+ }
3344
+ async decryptString(cipherText, keys, ttlSeconds, storage) {
3345
+ const key = await this.getOrCreateCryptoKey(keys, ttlSeconds, storage);
3346
+ if (!key)
3347
+ return null;
3348
+ try {
3349
+ const payload = JSON.parse(cipherText);
3350
+ const iv = this.base64ToBytes(payload?.iv);
3351
+ const data = this.base64ToBytes(payload?.data);
3352
+ if (!iv?.length || !data?.length)
3353
+ return null;
3354
+ // Re-wrap into fresh Uint8Arrays backed by ArrayBuffer (not SharedArrayBuffer).
3355
+ const ivBytes = new Uint8Array(iv);
3356
+ const dataBytes = new Uint8Array(data);
3357
+ const plainBuffer = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: ivBytes }, key, dataBytes);
3358
+ return new TextDecoder().decode(plainBuffer);
3359
+ }
3360
+ catch (err) {
3361
+ console.warn('Failed to decrypt cache payload:', err);
3362
+ return null;
3363
+ }
3364
+ }
3365
+ bytesToBase64(bytes) {
3366
+ let binary = '';
3367
+ for (let i = 0; i < bytes.length; i += 1) {
3368
+ binary += String.fromCharCode(bytes[i]);
3369
+ }
3370
+ return btoa(binary);
3371
+ }
3372
+ base64ToBytes(base64) {
3373
+ const binary = atob(base64 || '');
3374
+ const bytes = new Uint8Array(binary.length);
3375
+ for (let i = 0; i < binary.length; i += 1) {
3376
+ bytes[i] = binary.charCodeAt(i);
3377
+ }
3378
+ return bytes;
3379
+ }
3380
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: EncryptedStorageService, deps: [{ token: SnugdeskAuthenticationService }], target: i0.ɵɵFactoryTarget.Injectable });
3381
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: EncryptedStorageService, providedIn: 'root' });
3382
+ }
3383
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: EncryptedStorageService, decorators: [{
3384
+ type: Injectable,
3385
+ args: [{
3386
+ providedIn: 'root',
3387
+ }]
3388
+ }], ctorParameters: () => [{ type: SnugdeskAuthenticationService }] });
3389
+
3201
3390
  class CleanDeep {
3202
3391
  static clean(obj) {
3203
3392
  Object.keys(obj).forEach((key) => {
@@ -3301,5 +3490,5 @@ class CustomValidators {
3301
3490
  * Generated bundle index. Do not edit.
3302
3491
  */
3303
3492
 
3304
- export { AMPLIFY_CONFIG, AppSyncHelperService, CleanDeep, CustomPipesModule, CustomValidators, DomainNamePipe, EntityConversationService, EntityService, ErrorComponent, FIELDS_ENTITY, FIELDS_ENTITY_CONVERSATION, FIELDS_ENTITY_CONVERSATION_EXPANDED, FIELDS_ENTITY_EXPANDED, FIELDS_ENTITY_MINIMAL, FIELDS_ENTITY_TYPE, FIELDS_INTERACTION, FIELDS_INTERACTION_ATTENDEE, FIELDS_INTERACTION_ATTENDEE_EXPANDED, FIELDS_INTERACTION_ENDPOINT, FIELDS_INTERACTION_EXPANDED, FIELDS_INTERACTION_HOST, FIELDS_INTERACTION_INVITEE, FIELDS_INTERACTION_MESSAGE, FIELDS_INTERACTION_MESSAGE_ATTACHMENT, FIELDS_INTERACTION_MESSAGE_EXPANDED, FIELDS_INTERACTION_WIDGET, FIELDS_INTERACTION_WIDGET_USER_SETTING, FIELDS_TEAM, FIELDS_TEAM_MEMBER, FIELDS_TENANT, FIELDS_TICKET, FIELDS_TICKET_PRIORITY, FIELDS_TICKET_STATUS, FIELDS_TICKET_TYPE, FIELDS_USER, FIELDS_USER_SESSION, FooterComponent, FormatEpochTimestampPipe, InteractionChannel, InteractionContext, InteractionDirection, InteractionEndpointService, InteractionProvider, InteractionRouteLogic, InteractionService, InteractionStatus, InteractionWidgetService, LoaderComponent, ModelAttributeTypes, ModelSortDirection, OpenSearchHelperService, S3HelperService, SafeHtmlPipe, SearchInnerFieldPipe, SearchPipe, SingularizePipe, SnugdeskAuthenticationService, SnugdeskCoreModule, SnugdeskIPRegistryService, TeamService, TenantSSOConfigurationProtocol, TenantService, TicketService, UserService, UserSessionService, UserStatus, UserType, provideAmplifyConfig };
3493
+ export { AMPLIFY_CONFIG, AppSyncHelperService, CleanDeep, CustomPipesModule, CustomValidators, DomainNamePipe, EncryptedStorageService, EntityConversationService, EntityService, ErrorComponent, FIELDS_ENTITY, FIELDS_ENTITY_CONVERSATION, FIELDS_ENTITY_CONVERSATION_EXPANDED, FIELDS_ENTITY_EXPANDED, FIELDS_ENTITY_MINIMAL, FIELDS_ENTITY_TYPE, FIELDS_INTERACTION, FIELDS_INTERACTION_ATTENDEE, FIELDS_INTERACTION_ATTENDEE_EXPANDED, FIELDS_INTERACTION_ENDPOINT, FIELDS_INTERACTION_EXPANDED, FIELDS_INTERACTION_HOST, FIELDS_INTERACTION_INVITEE, FIELDS_INTERACTION_MESSAGE, FIELDS_INTERACTION_MESSAGE_ATTACHMENT, FIELDS_INTERACTION_MESSAGE_EXPANDED, FIELDS_INTERACTION_WIDGET, FIELDS_INTERACTION_WIDGET_USER_SETTING, FIELDS_TEAM, FIELDS_TEAM_MEMBER, FIELDS_TENANT, FIELDS_TICKET, FIELDS_TICKET_PRIORITY, FIELDS_TICKET_STATUS, FIELDS_TICKET_TYPE, FIELDS_USER, FIELDS_USER_SESSION, FooterComponent, FormatEpochTimestampPipe, InteractionChannel, InteractionContext, InteractionDirection, InteractionEndpointService, InteractionProvider, InteractionRouteLogic, InteractionService, InteractionStatus, InteractionWidgetService, LoaderComponent, ModelAttributeTypes, ModelSortDirection, OpenSearchHelperService, S3HelperService, SafeHtmlPipe, SearchInnerFieldPipe, SearchPipe, SingularizePipe, SnugdeskAuthenticationService, SnugdeskCoreModule, SnugdeskIPRegistryService, StorageType, TeamService, TenantSSOConfigurationProtocol, TenantService, TicketService, UserService, UserSessionService, UserStatus, UserType, provideAmplifyConfig };
3305
3494
  //# sourceMappingURL=snugdesk-core.mjs.map