@arex95/vue-core 1.1.26 → 1.1.29

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,12 +1,12 @@
1
- import { AuthParams, AuthResponse } from "@/types";
1
+ import { AuthParams, AuthResponse, AuthTokenPaths } from "@/types";
2
2
  import { SessionPreference } from "@config/global/sessionConfig";
3
3
  /**
4
4
  * @typedef {object} AuthHook
5
5
  * @property {function(): Promise<number | null>} getTokenExpiry - Retrieves the expiration time of the current token in milliseconds.
6
6
  * @property {function(): Promise<void>} cleanCredentials - Clears authentication credentials from storage.
7
7
  * @property {(params?: AuthParams) => Promise<void>} logout - Logs out the user, clears credentials, and reloads the page.
8
- * @property {(params: AuthParams, persistence: SessionPreference) => Promise<AuthResponse>} login - Logs in the user and stores tokens.
9
- * @property {function(): Promise<AuthResponse>} refresh - Refreshes authentication tokens.
8
+ * @property {(params: AuthParams, persistence: SessionPreference, tokenPaths?: AuthTokenPaths) => Promise<AuthResponse>} login - Logs in the user and stores tokens.
9
+ * @property {(tokenPaths?: AuthTokenPaths) => Promise<AuthResponse>} refresh - Refreshes authentication tokens.
10
10
  * @property {function(): Promise<boolean>} verifyAuth - Verifies the validity and expiration of the current authentication token.
11
11
  * @property {(preference: SessionPreference) => void} setSessionPersistencePreference - Sets the user's preferred storage for authentication data.
12
12
  * @property {function(): SessionPreference} getSessionPersistencePreference - Retrieves the user's current preferred storage for authentication data.
@@ -19,6 +19,6 @@ import { SessionPreference } from "@config/global/sessionConfig";
19
19
  */
20
20
  export declare function useAuth(secretKey?: string): {
21
21
  logout: (params?: AuthParams) => Promise<void>;
22
- login: (params: AuthParams, persistence: SessionPreference) => Promise<AuthResponse>;
23
- refresh: () => Promise<AuthResponse>;
22
+ login: (params: AuthParams, persistence: SessionPreference, tokenPaths?: AuthTokenPaths) => Promise<AuthResponse>;
23
+ refresh: (tokenPaths?: AuthTokenPaths) => Promise<AuthResponse>;
24
24
  };
@@ -1,3 +1,4 @@
1
1
  export * from './tokensConfig';
2
2
  export * from './endpointsConfig';
3
3
  export * from './sessionConfig';
4
+ export * from './keyConfig';
@@ -0,0 +1,20 @@
1
+ import { AppKeyConfig } from "../../types/AppKeyConfig";
2
+ /**
3
+ * Sets the main application encryption key.
4
+ * This key is expected to be used for encryption purposes within the application.
5
+ *
6
+ * @param {AppKeyConfig} config - An object containing the application encryption key.
7
+ * @param {string} config.key - The new application encryption key.
8
+ *
9
+ * @returns {void} Does not return anything, but updates the application key.
10
+ * @throws {Error} If the provided key is null, undefined, or an empty string.
11
+ */
12
+ export declare function configAppKey(config: AppKeyConfig): void;
13
+ /**
14
+ * Retrieves the current application encryption key.
15
+ * Throws an error if the application key has not been configured.
16
+ *
17
+ * @returns {string} The configured application encryption key.
18
+ * @throws {Error} If the application encryption key has not been set.
19
+ */
20
+ export declare function getAppKey(): string;
@@ -8,6 +8,11 @@ interface SessionConfigObject {
8
8
  /** The storage preference: 'local' for localStorage, 'session' for sessionStorage. */
9
9
  persistencePreference?: SessionPreference;
10
10
  }
11
+ /**
12
+ * Loads the session configuration from storage (local or session).
13
+ * This should be called once when the application initializes.
14
+ */
15
+ export declare function loadSessionConfigFromStorage(): Promise<void>;
11
16
  /**
12
17
  * Configures the session identifier and/or the data persistence preference for the active browser session.
13
18
  * Once configured, the session ID cannot be modified. The persistence preference can be updated.
@@ -23,18 +23,4 @@ export declare function configTokenKeys(config: TokenKeyConfig): void;
23
23
  * @returns {TokensConfig} The configuration of the access and refresh token keys.
24
24
  */
25
25
  export declare function getTokenConfig(): TokensConfig;
26
- /**
27
- * Sets the secret key for use in authentication.
28
- *
29
- * @param {string} key - The new secret key.
30
- *
31
- * @returns {void} Does not return anything, but updates the secret key.
32
- */
33
- export declare function setSecretKey(key: string): void;
34
- /**
35
- * Retrieves the current secret key.
36
- *
37
- * @returns {string} The configured secret key.
38
- */
39
- export declare function getSecretKey(): string;
40
26
  export {};
package/dist/index.mjs CHANGED
@@ -538,7 +538,6 @@ function inferErrorType(error) {
538
538
  return 'error';
539
539
  }
540
540
 
541
- let secretKey = "12345678901234567890123456789012";
542
541
  let tokensConfig = Object.freeze({
543
542
  ACCESS_TOKEN: "access_token",
544
543
  REFRESH_TOKEN: "refresh_token",
@@ -567,24 +566,6 @@ function configTokenKeys(config) {
567
566
  function getTokenConfig() {
568
567
  return tokensConfig;
569
568
  }
570
- /**
571
- * Sets the secret key for use in authentication.
572
- *
573
- * @param {string} key - The new secret key.
574
- *
575
- * @returns {void} Does not return anything, but updates the secret key.
576
- */
577
- function setSecretKey(key) {
578
- secretKey = key;
579
- }
580
- /**
581
- * Retrieves the current secret key.
582
- *
583
- * @returns {string} The configured secret key.
584
- */
585
- function getSecretKey() {
586
- return secretKey;
587
- }
588
569
 
589
570
  let endpointsConfig = {
590
571
  LOGIN: "/login",
@@ -784,11 +765,219 @@ const createCustomAxiosInstance = (config) => {
784
765
  return new AxiosService(config.baseURL, config.headers).getAxiosInstance();
785
766
  };
786
767
 
768
+ /**
769
+ * Converts an ArrayBuffer or Uint8Array to a hexadecimal string.
770
+ * @param buffer The ArrayBuffer or Uint8Array to convert.
771
+ * @returns The hexadecimal string.
772
+ */
773
+ function ab2hex(buffer) {
774
+ return Array.from(new Uint8Array(buffer))
775
+ .map((byte) => byte.toString(16).padStart(2, "0"))
776
+ .join("");
777
+ }
778
+ /**
779
+ * Converts a hexadecimal string to a Uint8Array.
780
+ * @param hex The hexadecimal string to convert.
781
+ * @returns The Uint8Array.
782
+ * @throws {TypeError} If the input is not a string.
783
+ * @throws {Error} If the hexadecimal string format is invalid or has an odd length.
784
+ */
785
+ function hex2ab(hex) {
786
+ if (typeof hex !== "string") {
787
+ throw new TypeError("Input must be a string.");
788
+ }
789
+ if (hex.length === 0) {
790
+ return new Uint8Array();
791
+ }
792
+ if (!/^[0-9a-fA-F]*$/.test(hex) || hex.length % 2 !== 0) {
793
+ throw new Error("Invalid hexadecimal string format or odd length.");
794
+ }
795
+ const array = new Uint8Array(hex.length / 2);
796
+ for (let i = 0; i < hex.length; i += 2) {
797
+ array[i / 2] = parseInt(hex.substring(i, i + 2), 16);
798
+ }
799
+ return array;
800
+ }
801
+ /**
802
+ * Derives an encryption key from a secret key.
803
+ * @param secretKey The secret key in plain text.
804
+ * @returns A promise that resolves with the derived CryptoKey.
805
+ * @throws {Error} If the secretKey is null or empty.
806
+ */
807
+ async function importKey(secretKey) {
808
+ if (!secretKey) {
809
+ throw new Error("Secret key cannot be null or empty.");
810
+ }
811
+ const keyMaterial = new TextEncoder().encode(secretKey);
812
+ const digest = await crypto.subtle.digest("SHA-256", keyMaterial);
813
+ return crypto.subtle.importKey("raw", digest, { name: "AES-CBC", length: 256 }, false, ["encrypt", "decrypt"]);
814
+ }
815
+ /**
816
+ * Encrypts a value with the provided secret key.
817
+ * @param value The value to encrypt.
818
+ * @param secretKey The secret key for encryption.
819
+ * @returns A promise that resolves with the IV (hex) + ciphertext (hex) string.
820
+ * @throws {Error} If the secretKey is null or empty (via importKey).
821
+ */
822
+ async function encrypt(value, secretKey) {
823
+ const key = await importKey(secretKey);
824
+ const iv = crypto.getRandomValues(new Uint8Array(16));
825
+ const encodedValue = new TextEncoder().encode(value);
826
+ const ciphertext = await crypto.subtle.encrypt({ name: "AES-CBC", iv: iv }, key, encodedValue);
827
+ return ab2hex(iv) + ab2hex(new Uint8Array(ciphertext));
828
+ }
829
+ /**
830
+ * Decrypts an encrypted value.
831
+ * @param encryptedValue The encrypted string (IV_hex + ciphertext_hex).
832
+ * @param secretKey The secret key for decryption.
833
+ * @returns A promise that resolves with the decrypted value.
834
+ * @throws {Error} If encryptedValue is null or empty, too short,
835
+ * or if the IV/ciphertext have incorrect lengths after conversion.
836
+ * @throws {Error} If the secretKey is null or empty (via importKey).
837
+ * @throws {TypeError} If hex2ab receives an invalid input type.
838
+ */
839
+ async function decrypt(encryptedValue, secretKey) {
840
+ if (!encryptedValue) {
841
+ throw new Error("Encrypted value cannot be null or empty.");
842
+ }
843
+ // For AES-CBC, the IV is ALWAYS 16 bytes.
844
+ // 16 bytes * 2 hex characters/byte = 32 hex characters for the IV.
845
+ if (encryptedValue.length < 32) {
846
+ throw new Error("Encrypted value is too short. Expected at least 32 hexadecimal characters for the IV.");
847
+ }
848
+ const key = await importKey(secretKey);
849
+ const ivHex = encryptedValue.substring(0, 32);
850
+ const ciphertextHex = encryptedValue.substring(32);
851
+ const iv = hex2ab(ivHex);
852
+ const ciphertext = hex2ab(ciphertextHex);
853
+ if (iv.byteLength !== 16) {
854
+ throw new Error(`Converted IV has incorrect length: ${iv.byteLength} bytes. Expected 16 bytes.`);
855
+ }
856
+ if (ciphertext.byteLength === 0) {
857
+ throw new Error("Ciphertext is empty. No data to decrypt.");
858
+ }
859
+ const decryptedBuffer = await crypto.subtle.decrypt({ name: "AES-CBC", iv: iv }, key, ciphertext);
860
+ return new TextDecoder().decode(decryptedBuffer);
861
+ }
862
+
863
+ /**
864
+ * Encrypts and stores an item in local or session storage.
865
+ * Assumes the `window` environment is available.
866
+ * @param key The key under which to store the value.
867
+ * @param value The value to encrypt and store.
868
+ * @param secretKey The secret key for encryption.
869
+ * @param persistent If true, uses localStorage; otherwise, uses sessionStorage.
870
+ * @returns A promise that resolves when the item is stored. Throws an error if it fails.
871
+ */
872
+ async function storeEncryptedItem(key, value, secretKey, persistent) {
873
+ if (typeof window === "undefined") {
874
+ throw new Error("Cannot access storage: window is not defined.");
875
+ }
876
+ const storage = persistent ? window.localStorage : window.sessionStorage;
877
+ const encryptedValue = await encrypt(value, secretKey);
878
+ storage.setItem(key, encryptedValue);
879
+ }
880
+ /**
881
+ * Retrieves and decrypts a value from local or session storage.
882
+ * Assumes the `window` environment is available.
883
+ * @param key The key of the item to retrieve.
884
+ * @param secretKey The secret key for decryption.
885
+ * @param persistent If true, searches localStorage; otherwise, sessionStorage.
886
+ * @returns A promise that resolves with the decrypted value or null if not found or decryption fails.
887
+ */
888
+ async function getDecryptedItem(key, secretKey, persistent) {
889
+ if (typeof window === "undefined") {
890
+ return null;
891
+ }
892
+ const storage = persistent ? window.localStorage : window.sessionStorage;
893
+ const encryptedData = storage.getItem(key);
894
+ if (!encryptedData) {
895
+ return null;
896
+ }
897
+ try {
898
+ return await decrypt(encryptedData, secretKey);
899
+ }
900
+ catch (error) {
901
+ return null;
902
+ }
903
+ }
904
+
905
+ let appKey = null;
906
+ /**
907
+ * Sets the main application encryption key.
908
+ * This key is expected to be used for encryption purposes within the application.
909
+ *
910
+ * @param {AppKeyConfig} config - An object containing the application encryption key.
911
+ * @param {string} config.key - The new application encryption key.
912
+ *
913
+ * @returns {void} Does not return anything, but updates the application key.
914
+ * @throws {Error} If the provided key is null, undefined, or an empty string.
915
+ */
916
+ function configAppKey(config) {
917
+ if (!config || !config.appKey || config.appKey.trim() === "") {
918
+ throw new Error("The application encryption key cannot be null or empty.");
919
+ }
920
+ appKey = config.appKey;
921
+ }
922
+ /**
923
+ * Retrieves the current application encryption key.
924
+ * Throws an error if the application key has not been configured.
925
+ *
926
+ * @returns {string} The configured application encryption key.
927
+ * @throws {Error} If the application encryption key has not been set.
928
+ */
929
+ function getAppKey() {
930
+ if (appKey === null) {
931
+ throw new Error("The application encryption key has not been configured. Please call 'configAppKey()' before attempting to access it.");
932
+ }
933
+ return appKey;
934
+ }
935
+
787
936
  let sessionId = v4();
788
937
  let sessionConfig = Object.freeze({
789
938
  SESSION_ID: sessionId,
790
939
  });
791
940
  let persistencePreference = "session";
941
+ /**
942
+ * Loads the session configuration from storage (local or session).
943
+ * This should be called once when the application initializes.
944
+ */
945
+ async function loadSessionConfigFromStorage() {
946
+ const isPersistent = persistencePreference === "local";
947
+ const storedConfig = await getDecryptedItem("sessionConfig", getAppKey(), isPersistent);
948
+ if (storedConfig) {
949
+ try {
950
+ const parsedConfig = JSON.parse(storedConfig);
951
+ sessionConfig = Object.freeze({
952
+ ...sessionConfig,
953
+ ...parsedConfig,
954
+ });
955
+ if (parsedConfig.SESSION_ID) {
956
+ sessionId = parsedConfig.SESSION_ID;
957
+ }
958
+ }
959
+ catch (error) {
960
+ console.error("Error parsing stored session config:", error);
961
+ regenerateSessionId();
962
+ }
963
+ }
964
+ else {
965
+ regenerateSessionId();
966
+ }
967
+ await saveSessionConfigToStorage();
968
+ }
969
+ /**
970
+ * Saves the current session configuration to local or session storage.
971
+ */
972
+ async function saveSessionConfigToStorage() {
973
+ const isPersistent = persistencePreference === "local";
974
+ try {
975
+ await storeEncryptedItem("sessionConfig", JSON.stringify(sessionConfig), getAppKey(), isPersistent);
976
+ }
977
+ catch (error) {
978
+ console.error("Error saving session config to storage:", error);
979
+ }
980
+ }
792
981
  /**
793
982
  * Configures the session identifier and/or the data persistence preference for the active browser session.
794
983
  * Once configured, the session ID cannot be modified. The persistence preference can be updated.
@@ -798,15 +987,19 @@ let persistencePreference = "session";
798
987
  * @returns {void} Does not return anything, but freezes the session configuration (for ID) and updates preference.
799
988
  */
800
989
  function configSession(config) {
801
- if (config.sessionId) {
802
- sessionConfig = Object.freeze({
803
- ...sessionConfig,
990
+ let updatedConfig = { ...sessionConfig };
991
+ if (config.sessionId && sessionConfig.SESSION_ID === sessionId) {
992
+ updatedConfig = {
993
+ ...updatedConfig,
804
994
  SESSION_ID: config.sessionId,
805
- });
995
+ };
996
+ sessionId = config.sessionId;
806
997
  }
807
998
  if (config.persistencePreference) {
808
999
  persistencePreference = config.persistencePreference;
809
1000
  }
1001
+ sessionConfig = Object.freeze(updatedConfig);
1002
+ saveSessionConfigToStorage();
810
1003
  }
811
1004
  /**
812
1005
  * Retrieves the current session identifier configuration.
@@ -2504,143 +2697,6 @@ function isValidHexNumber(hex) {
2504
2697
  // console.log(isValidHexNumber('1A3F')); // true
2505
2698
  // console.log(isValidHexNumber('GHIJ')); // false
2506
2699
 
2507
- /**
2508
- * Converts an ArrayBuffer or Uint8Array to a hexadecimal string.
2509
- * @param buffer The ArrayBuffer or Uint8Array to convert.
2510
- * @returns The hexadecimal string.
2511
- */
2512
- function ab2hex(buffer) {
2513
- return Array.from(new Uint8Array(buffer))
2514
- .map((byte) => byte.toString(16).padStart(2, "0"))
2515
- .join("");
2516
- }
2517
- /**
2518
- * Converts a hexadecimal string to a Uint8Array.
2519
- * @param hex The hexadecimal string to convert.
2520
- * @returns The Uint8Array.
2521
- * @throws {TypeError} If the input is not a string.
2522
- * @throws {Error} If the hexadecimal string format is invalid or has an odd length.
2523
- */
2524
- function hex2ab(hex) {
2525
- if (typeof hex !== "string") {
2526
- throw new TypeError("Input must be a string.");
2527
- }
2528
- if (hex.length === 0) {
2529
- return new Uint8Array();
2530
- }
2531
- if (!/^[0-9a-fA-F]*$/.test(hex) || hex.length % 2 !== 0) {
2532
- throw new Error("Invalid hexadecimal string format or odd length.");
2533
- }
2534
- const array = new Uint8Array(hex.length / 2);
2535
- for (let i = 0; i < hex.length; i += 2) {
2536
- array[i / 2] = parseInt(hex.substring(i, i + 2), 16);
2537
- }
2538
- return array;
2539
- }
2540
- /**
2541
- * Derives an encryption key from a secret key.
2542
- * @param secretKey The secret key in plain text.
2543
- * @returns A promise that resolves with the derived CryptoKey.
2544
- * @throws {Error} If the secretKey is null or empty.
2545
- */
2546
- async function importKey(secretKey) {
2547
- if (!secretKey) {
2548
- throw new Error("Secret key cannot be null or empty.");
2549
- }
2550
- const keyMaterial = new TextEncoder().encode(secretKey);
2551
- const digest = await crypto.subtle.digest("SHA-256", keyMaterial);
2552
- return crypto.subtle.importKey("raw", digest, { name: "AES-CBC", length: 256 }, false, ["encrypt", "decrypt"]);
2553
- }
2554
- /**
2555
- * Encrypts a value with the provided secret key.
2556
- * @param value The value to encrypt.
2557
- * @param secretKey The secret key for encryption.
2558
- * @returns A promise that resolves with the IV (hex) + ciphertext (hex) string.
2559
- * @throws {Error} If the secretKey is null or empty (via importKey).
2560
- */
2561
- async function encrypt(value, secretKey) {
2562
- const key = await importKey(secretKey);
2563
- const iv = crypto.getRandomValues(new Uint8Array(16));
2564
- const encodedValue = new TextEncoder().encode(value);
2565
- const ciphertext = await crypto.subtle.encrypt({ name: "AES-CBC", iv: iv }, key, encodedValue);
2566
- return ab2hex(iv) + ab2hex(new Uint8Array(ciphertext));
2567
- }
2568
- /**
2569
- * Decrypts an encrypted value.
2570
- * @param encryptedValue The encrypted string (IV_hex + ciphertext_hex).
2571
- * @param secretKey The secret key for decryption.
2572
- * @returns A promise that resolves with the decrypted value.
2573
- * @throws {Error} If encryptedValue is null or empty, too short,
2574
- * or if the IV/ciphertext have incorrect lengths after conversion.
2575
- * @throws {Error} If the secretKey is null or empty (via importKey).
2576
- * @throws {TypeError} If hex2ab receives an invalid input type.
2577
- */
2578
- async function decrypt(encryptedValue, secretKey) {
2579
- if (!encryptedValue) {
2580
- throw new Error("Encrypted value cannot be null or empty.");
2581
- }
2582
- // For AES-CBC, the IV is ALWAYS 16 bytes.
2583
- // 16 bytes * 2 hex characters/byte = 32 hex characters for the IV.
2584
- if (encryptedValue.length < 32) {
2585
- throw new Error("Encrypted value is too short. Expected at least 32 hexadecimal characters for the IV.");
2586
- }
2587
- const key = await importKey(secretKey);
2588
- const ivHex = encryptedValue.substring(0, 32);
2589
- const ciphertextHex = encryptedValue.substring(32);
2590
- const iv = hex2ab(ivHex);
2591
- const ciphertext = hex2ab(ciphertextHex);
2592
- if (iv.byteLength !== 16) {
2593
- throw new Error(`Converted IV has incorrect length: ${iv.byteLength} bytes. Expected 16 bytes.`);
2594
- }
2595
- if (ciphertext.byteLength === 0) {
2596
- throw new Error("Ciphertext is empty. No data to decrypt.");
2597
- }
2598
- const decryptedBuffer = await crypto.subtle.decrypt({ name: "AES-CBC", iv: iv }, key, ciphertext);
2599
- return new TextDecoder().decode(decryptedBuffer);
2600
- }
2601
-
2602
- /**
2603
- * Encrypts and stores an item in local or session storage.
2604
- * Assumes the `window` environment is available.
2605
- * @param key The key under which to store the value.
2606
- * @param value The value to encrypt and store.
2607
- * @param secretKey The secret key for encryption.
2608
- * @param isRememberMe If true, uses localStorage; otherwise, uses sessionStorage.
2609
- * @returns A promise that resolves when the item is stored. Throws an error if it fails.
2610
- */
2611
- async function storeEncryptedItem(key, value, secretKey, isRememberMe) {
2612
- if (typeof window === "undefined") {
2613
- throw new Error("Cannot access storage: window is not defined.");
2614
- }
2615
- const storage = isRememberMe ? window.localStorage : window.sessionStorage;
2616
- const encryptedValue = await encrypt(value, secretKey);
2617
- storage.setItem(key, encryptedValue);
2618
- }
2619
- /**
2620
- * Retrieves and decrypts a value from local or session storage.
2621
- * Assumes the `window` environment is available.
2622
- * @param key The key of the item to retrieve.
2623
- * @param secretKey The secret key for decryption.
2624
- * @param isRememberMe If true, searches localStorage; otherwise, sessionStorage.
2625
- * @returns A promise that resolves with the decrypted value or null if not found or decryption fails.
2626
- */
2627
- async function getDecryptedItem(key, secretKey, isRememberMe) {
2628
- if (typeof window === "undefined") {
2629
- return null;
2630
- }
2631
- const storage = isRememberMe ? window.localStorage : window.sessionStorage;
2632
- const encryptedData = storage.getItem(key);
2633
- if (!encryptedData) {
2634
- return null;
2635
- }
2636
- try {
2637
- return await decrypt(encryptedData, secretKey);
2638
- }
2639
- catch (error) {
2640
- return null;
2641
- }
2642
- }
2643
-
2644
2700
  /**
2645
2701
  * Clears all stored authentication data (access and refresh tokens)
2646
2702
  * from either sessionStorage or localStorage based on the provided preference.
@@ -2715,9 +2771,10 @@ const storeAuthRefreshToken = async (token, secretKey, preference) => {
2715
2771
  * @throws {Error} "TOKEN_MISSING" if no token is found, "TOKEN_EXPIRED" if the token has expired,
2716
2772
  * "TOKEN_INVALID" if the token format is invalid.
2717
2773
  */
2718
- const verifyAuth = async (secretKey = getSecretKey(), preference = getSessionPersistencePreference()) => {
2774
+ const verifyAuth = async () => {
2775
+ const preference = getSessionPersistencePreference();
2719
2776
  try {
2720
- const token = await getAuthToken(secretKey, preference);
2777
+ const token = await getAuthToken(getAppKey(), preference);
2721
2778
  if (!token) {
2722
2779
  handleError("TOKEN_MISSING: No valid token found", false);
2723
2780
  await cleanCredentials(preference);
@@ -3305,8 +3362,8 @@ function useSorter(items, criteriaList, selectedCriteria) {
3305
3362
  * @property {function(): Promise<number | null>} getTokenExpiry - Retrieves the expiration time of the current token in milliseconds.
3306
3363
  * @property {function(): Promise<void>} cleanCredentials - Clears authentication credentials from storage.
3307
3364
  * @property {(params?: AuthParams) => Promise<void>} logout - Logs out the user, clears credentials, and reloads the page.
3308
- * @property {(params: AuthParams, persistence: SessionPreference) => Promise<AuthResponse>} login - Logs in the user and stores tokens.
3309
- * @property {function(): Promise<AuthResponse>} refresh - Refreshes authentication tokens.
3365
+ * @property {(params: AuthParams, persistence: SessionPreference, tokenPaths?: AuthTokenPaths) => Promise<AuthResponse>} login - Logs in the user and stores tokens.
3366
+ * @property {(tokenPaths?: AuthTokenPaths) => Promise<AuthResponse>} refresh - Refreshes authentication tokens.
3310
3367
  * @property {function(): Promise<boolean>} verifyAuth - Verifies the validity and expiration of the current authentication token.
3311
3368
  * @property {(preference: SessionPreference) => void} setSessionPersistencePreference - Sets the user's preferred storage for authentication data.
3312
3369
  * @property {function(): SessionPreference} getSessionPersistencePreference - Retrieves the user's current preferred storage for authentication data.
@@ -3317,7 +3374,7 @@ function useSorter(items, criteriaList, selectedCriteria) {
3317
3374
  * @param {string} secretKey - The secret key used for token encryption/decryption.
3318
3375
  * @returns {AuthHook} An object containing authentication functions.
3319
3376
  */
3320
- function useAuth(secretKey = getSecretKey()) {
3377
+ function useAuth(secretKey = getAppKey()) {
3321
3378
  const axiosInstance = getAxiosInstance();
3322
3379
  const endpoints = getEndpointsConfig();
3323
3380
  const currentPersistencePreference = getSessionPersistencePreference();
@@ -3347,26 +3404,33 @@ function useAuth(secretKey = getSecretKey()) {
3347
3404
  *
3348
3405
  * @param {AuthParams} params - The authentication parameters (e.g., username, password).
3349
3406
  * @param {SessionPreference} persistence - The storage preference: 'local' for localStorage, 'session' for sessionStorage.
3350
- * @returns {Promise<AuthResponse>} The authentication response containing tokens and user information.
3351
- * @throws {Error} If the login request fails.
3407
+ * @param {AuthTokenPaths} [tokenPaths] - Configuración opcional para las rutas (en notación de punto) donde se encuentran los tokens en la respuesta de la API.
3408
+ * @returns {Promise<AuthResponse>} La respuesta de autenticación que contiene los tokens e información del usuario.
3409
+ * @throws {Error} Si la solicitud de login falla, o si los tokens de acceso/refresco no se encuentran o no son válidos en la respuesta.
3352
3410
  */
3353
- const login = async (params, persistence) => {
3411
+ const login = async (params, persistence, tokenPaths) => {
3354
3412
  try {
3355
3413
  const { data } = await axiosInstance.post(endpoints.LOGIN, params);
3414
+ const accessTokenPath = tokenPaths?.accessTokenPath || "access_token";
3415
+ const refreshTokenPath = tokenPaths?.refreshTokenPath || "refresh_token";
3416
+ const accessTokenPathArray = accessTokenPath.split(".");
3417
+ const refreshTokenPathArray = refreshTokenPath.split(".");
3356
3418
  if (!data) {
3357
3419
  throw new Error("LOGIN_ERROR: No data received from login endpoint.");
3358
3420
  }
3359
- if (!data.access_token) {
3360
- throw new Error("LOGIN_ERROR: Access token not found in response.");
3421
+ const accessToken = safeGet(data, accessTokenPathArray);
3422
+ const refreshToken = safeGet(data, refreshTokenPathArray);
3423
+ if (!accessToken || typeof accessToken !== "string") {
3424
+ throw new Error(`LOGIN_ERROR: Access token not found or invalid at path '${accessTokenPath}' in response.`);
3361
3425
  }
3362
- if (!data.refresh_token) {
3363
- throw new Error("LOGIN_ERROR: Refresh token not found in response.");
3426
+ if (!refreshToken || typeof refreshToken !== "string") {
3427
+ throw new Error(`LOGIN_ERROR: Refresh token not found or invalid at path '${refreshTokenPath}' in response.`);
3364
3428
  }
3365
3429
  configSession({
3366
3430
  persistencePreference: persistence,
3367
3431
  });
3368
- await storeAuthToken(data.access_token, secretKey, persistence);
3369
- await storeAuthRefreshToken(data.refresh_token, secretKey, persistence);
3432
+ await storeAuthToken(accessToken, secretKey, persistence);
3433
+ await storeAuthRefreshToken(refreshToken, secretKey, persistence);
3370
3434
  return data;
3371
3435
  }
3372
3436
  catch (error) {
@@ -3376,20 +3440,40 @@ function useAuth(secretKey = getSecretKey()) {
3376
3440
  };
3377
3441
  /**
3378
3442
  * Refreshes the authentication tokens using the stored refresh token.
3443
+ * This function can also accept optional token paths if the refresh endpoint
3444
+ * returns tokens with a different structure than the default login.
3379
3445
  * If no refresh token is found, it throws an error and initiates a logout.
3380
3446
  *
3447
+ * @param {AuthTokenPaths} [tokenPaths] - Configuración opcional para las rutas (en notación de punto) de los tokens de acceso y refresco en la respuesta del endpoint de refresco.
3381
3448
  * @returns {Promise<AuthResponse>} The new authentication response with refreshed tokens.
3382
3449
  * @throws {Error} If the refresh token is missing or the refresh request fails.
3383
3450
  */
3384
- const refresh = async () => {
3451
+ const refresh = async (tokenPaths) => {
3385
3452
  try {
3386
- const refreshToken = await getAuthRefreshToken(secretKey, currentPersistencePreference);
3387
- if (!refreshToken) {
3388
- throw new Error("TOKEN_MISSING: No refresh token found");
3453
+ const refreshTokenFromStorage = await getAuthRefreshToken(secretKey, currentPersistencePreference);
3454
+ if (!refreshTokenFromStorage) {
3455
+ throw new Error("TOKEN_MISSING: No refresh token found in storage.");
3456
+ }
3457
+ const { data } = await axiosInstance.post(endpoints.REFRESH, { refresh_token: refreshTokenFromStorage });
3458
+ const accessTokenPath = tokenPaths?.accessTokenPath || "access_token";
3459
+ const refreshTokenPath = tokenPaths?.refreshTokenPath || "refresh_token";
3460
+ const accessTokenPathArray = accessTokenPath.split(".");
3461
+ const refreshTokenPathArray = refreshTokenPath.split(".");
3462
+ if (!data) {
3463
+ throw new Error("REFRESH_ERROR: No data received from refresh endpoint.");
3389
3464
  }
3390
- const { data } = await axiosInstance.post(endpoints.REFRESH, { refresh_token: refreshToken });
3391
- await storeAuthToken(data.access_token, secretKey, currentPersistencePreference);
3392
- await storeAuthRefreshToken(data.refresh_token, secretKey, currentPersistencePreference);
3465
+ const accessTokenAfterRefresh = safeGet(data, accessTokenPathArray);
3466
+ const refreshTokenAfterRefresh = safeGet(data, refreshTokenPathArray);
3467
+ if (!accessTokenAfterRefresh ||
3468
+ typeof accessTokenAfterRefresh !== "string") {
3469
+ throw new Error(`REFRESH_ERROR: Access token not found or invalid at path '${accessTokenPath}' in refresh response.`);
3470
+ }
3471
+ if (!refreshTokenAfterRefresh ||
3472
+ typeof refreshTokenAfterRefresh !== "string") {
3473
+ throw new Error(`REFRESH_ERROR: Refresh token not found or invalid at path '${refreshTokenPath}' in refresh response.`);
3474
+ }
3475
+ await storeAuthToken(accessTokenAfterRefresh, secretKey, currentPersistencePreference);
3476
+ await storeAuthRefreshToken(refreshTokenAfterRefresh, secretKey, currentPersistencePreference);
3393
3477
  return data;
3394
3478
  }
3395
3479
  catch (error) {
@@ -3401,7 +3485,7 @@ function useAuth(secretKey = getSecretKey()) {
3401
3485
  return {
3402
3486
  logout,
3403
3487
  login,
3404
- refresh
3488
+ refresh,
3405
3489
  };
3406
3490
  }
3407
3491
 
@@ -3422,10 +3506,8 @@ const ArexVueCore = {
3422
3506
  console.warn("ArexVueCore: No configuration options were provided. The library may not function correctly.");
3423
3507
  return;
3424
3508
  }
3425
- configEndpoints({
3426
- loginEndpoint: options.endpoints.login,
3427
- refreshEndpoint: options.endpoints.refresh,
3428
- logoutEndpoint: options.endpoints.logout
3509
+ configAppKey({
3510
+ appKey: options.appKey
3429
3511
  });
3430
3512
  configTokenKeys({
3431
3513
  accessTokenKey: options.tokenKeys.accessToken,
@@ -3434,7 +3516,12 @@ const ArexVueCore = {
3434
3516
  configAxios({
3435
3517
  baseURL: options.apiUrl,
3436
3518
  });
3519
+ configEndpoints({
3520
+ loginEndpoint: options.endpoints.login,
3521
+ refreshEndpoint: options.endpoints.refresh,
3522
+ logoutEndpoint: options.endpoints.logout,
3523
+ });
3437
3524
  },
3438
3525
  };
3439
3526
 
3440
- export { AppTypes, ArchiveTypes, ArexVueCore, AudioTypes, AxiosService, ContentTypeEnum, DocumentTypes, ERROR_MESSAGES, ERROR_STYLES, ErrorEnum, ErrorMessages, ErrorStyles, ExceptionEnum, FontTypes, ImageTypes, KeyCodeEnum, OtherTypes, RestStd, ScreenBreakpoint, ScreenSize, StorageKeyEnum, StorageTypeEnum, TextTypes, VideoTypes, ab2hex, addCustomKeyboardShortcut, addDays, addDoubleClickListener, addKeyListener, ageAtDate, axiosFetch, blobToFormData, bufferToBlob, calculateAge, cleanCredentials, clickOutside, compareObject, configAxios, configEndpoints, configSession, configTokenKeys, copyToClipboard, countWords, createCustomAxiosInstance, createFetch, createKeyMap, customShortcut, daysBetween, daysToNextBirthday, debounce, debounceAsync, debounceAsyncValidator, debounceAsyncWithImmediate, debounceLeading, debounceLeadingTrailing, debounceTrailing, decrypt, deepClone, deepEqual, deepMerge, detectKeyHold, disableCopy, disableF12Key, disableMouseButtons, disableRightClick, disableSpecificKeys, downloadBlob, enableMouseButtons, enableRightClick, enableSpecificKeys, encrypt, exportToCSV, exportToExcel, exportToJSON, exportToText, exportToXML, filterObjectByKeys, flattenObject, formDataToObject, formatDate, generateRandomString, getAuthRefreshToken, getAuthToken, getAxiosInstance, getDecryptedItem, getEndOfMonth, getEndpointsConfig, getObjectDifferences, getObjectKeys, getQueryParam, getSecretKey, getSessionConfig, getSessionId, getSessionPersistencePreference, getStartOfMonth, getTokenConfig, handleError, hasNestedProperties, hex2ab, importKey, isEmptyObject, isLeapYear, isStrongPassword, isValidAge, isValidCreditCard, isValidDate, isValidEmail, isValidExpiryDate, isValidHexColor, isValidHexColorAlpha, isValidHexNumber, isValidIP, isValidPhoneNumber, isValidSSN, isValidTime, isValidURL, isValidUsername, isValidZIP, lowerFirst, objectToFormData, objectToFormDataEnhanced, objectToQueryString, openWindow, parseDate, proxyToPlainObject, readFileAsDataURL, readFileAsText, regenerateSessionId, registerKeyboardShortcuts, removeAccent, removeClickOutside, removeCustomKeyboardShortcut, removeCustomShortcuts, removeDoubleClickListener, removeEmptyProperties, removeKeyListeners, replaceAll, reverseString, safeGet, screenMap, scrollToTop, setSecretKey, simulateKeyPress, stopDetectingKeyHold, storeAuthRefreshToken, storeAuthToken, storeEncryptedItem, stringToBlob, subtractDays, throttle, toCamelCase, toKebabCase, toggleTabNavigation, truncateString, unregisterKeyboardShortcuts, upperFirst, useAuth, useBreakpoint, useFilter, usePagination, useSorter, useVueQuery, validateAlphanumeric, validateLetters, validateNumbers, verifyAuth };
3527
+ export { AppTypes, ArchiveTypes, ArexVueCore, AudioTypes, AxiosService, ContentTypeEnum, DocumentTypes, ERROR_MESSAGES, ERROR_STYLES, ErrorEnum, ErrorMessages, ErrorStyles, ExceptionEnum, FontTypes, ImageTypes, KeyCodeEnum, OtherTypes, RestStd, ScreenBreakpoint, ScreenSize, StorageKeyEnum, StorageTypeEnum, TextTypes, VideoTypes, ab2hex, addCustomKeyboardShortcut, addDays, addDoubleClickListener, addKeyListener, ageAtDate, axiosFetch, blobToFormData, bufferToBlob, calculateAge, cleanCredentials, clickOutside, compareObject, configAppKey, configAxios, configEndpoints, configSession, configTokenKeys, copyToClipboard, countWords, createCustomAxiosInstance, createFetch, createKeyMap, customShortcut, daysBetween, daysToNextBirthday, debounce, debounceAsync, debounceAsyncValidator, debounceAsyncWithImmediate, debounceLeading, debounceLeadingTrailing, debounceTrailing, decrypt, deepClone, deepEqual, deepMerge, detectKeyHold, disableCopy, disableF12Key, disableMouseButtons, disableRightClick, disableSpecificKeys, downloadBlob, enableMouseButtons, enableRightClick, enableSpecificKeys, encrypt, exportToCSV, exportToExcel, exportToJSON, exportToText, exportToXML, filterObjectByKeys, flattenObject, formDataToObject, formatDate, generateRandomString, getAppKey, getAuthRefreshToken, getAuthToken, getAxiosInstance, getDecryptedItem, getEndOfMonth, getEndpointsConfig, getObjectDifferences, getObjectKeys, getQueryParam, getSessionConfig, getSessionId, getSessionPersistencePreference, getStartOfMonth, getTokenConfig, handleError, hasNestedProperties, hex2ab, importKey, isEmptyObject, isLeapYear, isStrongPassword, isValidAge, isValidCreditCard, isValidDate, isValidEmail, isValidExpiryDate, isValidHexColor, isValidHexColorAlpha, isValidHexNumber, isValidIP, isValidPhoneNumber, isValidSSN, isValidTime, isValidURL, isValidUsername, isValidZIP, loadSessionConfigFromStorage, lowerFirst, objectToFormData, objectToFormDataEnhanced, objectToQueryString, openWindow, parseDate, proxyToPlainObject, readFileAsDataURL, readFileAsText, regenerateSessionId, registerKeyboardShortcuts, removeAccent, removeClickOutside, removeCustomKeyboardShortcut, removeCustomShortcuts, removeDoubleClickListener, removeEmptyProperties, removeKeyListeners, replaceAll, reverseString, safeGet, screenMap, scrollToTop, simulateKeyPress, stopDetectingKeyHold, storeAuthRefreshToken, storeAuthToken, storeEncryptedItem, stringToBlob, subtractDays, throttle, toCamelCase, toKebabCase, toggleTabNavigation, truncateString, unregisterKeyboardShortcuts, upperFirst, useAuth, useBreakpoint, useFilter, usePagination, useSorter, useVueQuery, validateAlphanumeric, validateLetters, validateNumbers, verifyAuth };
@@ -0,0 +1,3 @@
1
+ export interface AppKeyConfig {
2
+ appKey: string;
3
+ }
@@ -1,26 +1,13 @@
1
1
  export interface ArexVueCoreOptions {
2
- /**
3
- * The authentication endpoints.
4
- */
2
+ appKey: string;
5
3
  endpoints: {
6
- /** The login endpoint. */
7
4
  login: string;
8
- /** The token refresh endpoint. */
9
5
  refresh: string;
10
- /** The logout endpoint. */
11
6
  logout: string;
12
7
  };
13
- /**
14
- * The key prefixes for storing tokens.
15
- */
16
8
  tokenKeys: {
17
- /** The access token key prefix. */
18
9
  accessToken: string;
19
- /** The refresh token key prefix. */
20
10
  refreshToken: string;
21
11
  };
22
- /**
23
- * The base URL for the API.
24
- */
25
12
  apiUrl: string;
26
13
  }
@@ -0,0 +1,16 @@
1
+ import { TokensConfig, EndpointsConfig } from "@/types";
2
+ export type AuthConfig = {
3
+ endpoints: EndpointsConfig;
4
+ storageKeys: TokensConfig;
5
+ };
6
+ export interface AuthParams {
7
+ username?: string;
8
+ password?: string;
9
+ }
10
+ export interface AuthTokenPaths {
11
+ accessTokenPath?: string;
12
+ refreshTokenPath?: string;
13
+ }
14
+ export interface AuthResponse {
15
+ [key: string]: any;
16
+ }
@@ -3,9 +3,8 @@ export * from './ExtendedQueryOptions';
3
3
  export * from './ErrorType';
4
4
  export * from './EndpointsConfig';
5
5
  export * from './TokenConfig';
6
- export * from './AuthConfig';
6
+ export * from './Auth';
7
7
  export * from './SessionConfig';
8
8
  export * from './DecodedJwtPayload';
9
- export * from './AuthResponse';
10
- export * from './AuthParams';
11
9
  export * from './ArexVueCoreOptions';
10
+ export * from './AppKeyConfig';
@@ -55,4 +55,4 @@ export declare const storeAuthRefreshToken: (token: string, secretKey: string, p
55
55
  * @throws {Error} "TOKEN_MISSING" if no token is found, "TOKEN_EXPIRED" if the token has expired,
56
56
  * "TOKEN_INVALID" if the token format is invalid.
57
57
  */
58
- export declare const verifyAuth: (secretKey?: string, preference?: SessionPreference) => Promise<boolean>;
58
+ export declare const verifyAuth: () => Promise<boolean>;
@@ -4,16 +4,16 @@
4
4
  * @param key The key under which to store the value.
5
5
  * @param value The value to encrypt and store.
6
6
  * @param secretKey The secret key for encryption.
7
- * @param isRememberMe If true, uses localStorage; otherwise, uses sessionStorage.
7
+ * @param persistent If true, uses localStorage; otherwise, uses sessionStorage.
8
8
  * @returns A promise that resolves when the item is stored. Throws an error if it fails.
9
9
  */
10
- export declare function storeEncryptedItem(key: string, value: string, secretKey: string, isRememberMe: boolean): Promise<void>;
10
+ export declare function storeEncryptedItem(key: string, value: string, secretKey: string, persistent: boolean): Promise<void>;
11
11
  /**
12
12
  * Retrieves and decrypts a value from local or session storage.
13
13
  * Assumes the `window` environment is available.
14
14
  * @param key The key of the item to retrieve.
15
15
  * @param secretKey The secret key for decryption.
16
- * @param isRememberMe If true, searches localStorage; otherwise, sessionStorage.
16
+ * @param persistent If true, searches localStorage; otherwise, sessionStorage.
17
17
  * @returns A promise that resolves with the decrypted value or null if not found or decryption fails.
18
18
  */
19
- export declare function getDecryptedItem(key: string, secretKey: string, isRememberMe: boolean): Promise<string | null>;
19
+ export declare function getDecryptedItem(key: string, secretKey: string, persistent: boolean): Promise<string | null>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arex95/vue-core",
3
- "version": "1.1.26",
3
+ "version": "1.1.29",
4
4
  "description": "Opinionated Vue Core",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",