@ollaid/native-sso 2.7.2 → 2.7.4

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.
package/dist/index.d.ts CHANGED
@@ -40,8 +40,9 @@ export { mobilePasswordService } from './services/mobilePassword';
40
40
  export { profileChangeService } from './services/profileChange';
41
41
  export { profileMediaService } from './services/profileMedia';
42
42
  export { iamAccountService } from './services/iamAccount';
43
- export { setNativeAuthConfig, getNativeAuthConfig, setNativeStorage, getNativeStorage, ApiError, getAuthToken, getAuthUser, getAccountType, clearAuthToken, logout, getSsoSessionSnapshot, hasSsoSession, getDeviceId, getSessionUuid, STORAGE_KEYS, PROFILE_PROMPT_KEYS, getProfilePromptState, setProfilePromptState, markProfilePromptComplete, snoozeProfilePrompt, } from './services/api';
43
+ export { setNativeAuthConfig, getNativeAuthConfig, setNativeStorage, getNativeStorage, ApiError, getAuthToken, getAuthUser, getAccountType, clearAuthToken, clearNativeSsoStorage, repairNativeSsoStorage, logout, getSsoSessionSnapshot, hasSsoSession, getDeviceId, getSessionUuid, STORAGE_KEYS, PROFILE_PROMPT_KEYS, getProfilePromptState, setProfilePromptState, markProfilePromptComplete, snoozeProfilePrompt, } from './services/api';
44
44
  export type { NativeAuthConfig, NativeStorageAdapter, ApiErrorType, ProfilePromptState } from './services/api';
45
+ export type { NativeSsoStorageRepairResult } from './services/api';
45
46
  export type { SsoSessionSnapshot } from './services/api';
46
47
  export type { NativeAuthType, NativeAuthStatus, AccountType, RegistrationType, NativeCredentials, NativeEncryptRequest, NativeEncryptResponse, NativeConfigResponse, NativeInitResponse, NativeValidateResponse, NativeGrantAccessResponse, NativeResendOtpResponse, NativeExchangeResponse, NativeRefreshResponse, NativeUser, NativeAuthState, UserInfos, LinkPhoneRequest, LinkPhoneResponse, LinkEmailRequest, LinkEmailResponse, RefreshUserInfoSingleRequest, RefreshUserInfoSingleResponse, RefreshUserInfoBulkRequest, RefreshUserInfoBulkResponse, UpdateAvatarRequest, UpdateAvatarResponse, ResetAvatarRequest, ResetAvatarResponse, CheckTokenResponse, } from './types/native';
47
48
  export type { MobilePasswordState, MobilePasswordStatus, } from './types/mobile';
package/dist/index.js CHANGED
@@ -7106,6 +7106,27 @@ function isRawStorageKey(key) {
7106
7106
  function getLegacyStorageKey(key) {
7107
7107
  return LEGACY_STORAGE_KEYS[key] || null;
7108
7108
  }
7109
+ function normalizeStorageValue(value) {
7110
+ if (typeof value === "string") return value;
7111
+ if (value === null || value === void 0) return "";
7112
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
7113
+ return String(value);
7114
+ }
7115
+ try {
7116
+ const serialized = JSON.stringify(value);
7117
+ return serialized ?? "";
7118
+ } catch {
7119
+ return String(value);
7120
+ }
7121
+ }
7122
+ function safeJSONStringify(value) {
7123
+ try {
7124
+ const serialized = JSON.stringify(value);
7125
+ return serialized ?? "null";
7126
+ } catch {
7127
+ return "null";
7128
+ }
7129
+ }
7109
7130
  function migrateLegacyValue(base, key, legacyKey, rawValue) {
7110
7131
  base.setItem(key, encryptStorageValue(rawValue));
7111
7132
  base.removeItem(legacyKey);
@@ -7114,31 +7135,44 @@ function migrateLegacyValue(base, key, legacyKey, rawValue) {
7114
7135
  function getStorageEncryptionSecret() {
7115
7136
  var _a;
7116
7137
  const storage = rawStorageAdapter;
7117
- let seed = storage.getItem("native_sso_storage_seed");
7138
+ let seed = storage.getItem(STORAGE_SEED_KEY);
7118
7139
  if (!seed) {
7119
7140
  seed = `seed_${Date.now()}_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
7120
- storage.setItem("native_sso_storage_seed", seed);
7141
+ storage.setItem(STORAGE_SEED_KEY, seed);
7121
7142
  }
7122
7143
  const origin = typeof window !== "undefined" && ((_a = window.location) == null ? void 0 : _a.origin) ? window.location.origin : "unknown-origin";
7123
7144
  const prefix = config.configPrefix || "iam";
7124
7145
  return `${STORAGE_ENCRYPTION_SECRET_PREFIX}::${origin}::${prefix}::${seed}`;
7125
7146
  }
7126
7147
  function encryptStorageValue(value) {
7127
- const secret = getStorageEncryptionSecret();
7128
- const ciphertext = cryptoJsExports.AES.encrypt(value, secret).toString();
7129
- return `${STORAGE_ENCRYPTION_PREFIX}${ciphertext}`;
7148
+ const normalizedValue = normalizeStorageValue(value);
7149
+ try {
7150
+ const secret = getStorageEncryptionSecret();
7151
+ const ciphertext = cryptoJsExports.AES.encrypt(normalizedValue, secret).toString();
7152
+ return `${STORAGE_ENCRYPTION_PREFIX}${ciphertext}`;
7153
+ } catch (error) {
7154
+ if (isDebugMode()) {
7155
+ console.warn("⚠️ [native-sso] Encryption storage fallback to plain value", error);
7156
+ }
7157
+ return normalizedValue;
7158
+ }
7130
7159
  }
7131
7160
  function decryptStorageValue(value) {
7132
- if (!value.startsWith(STORAGE_ENCRYPTION_PREFIX)) {
7133
- return value;
7161
+ const normalizedValue = normalizeStorageValue(value);
7162
+ if (!normalizedValue.startsWith(STORAGE_ENCRYPTION_PREFIX)) {
7163
+ return normalizedValue;
7134
7164
  }
7135
- const secret = getStorageEncryptionSecret();
7136
- const ciphertext = value.slice(STORAGE_ENCRYPTION_PREFIX.length);
7165
+ const ciphertext = normalizedValue.slice(STORAGE_ENCRYPTION_PREFIX.length);
7166
+ if (!ciphertext) return null;
7137
7167
  try {
7168
+ const secret = getStorageEncryptionSecret();
7138
7169
  const bytes = cryptoJsExports.AES.decrypt(ciphertext, secret);
7139
7170
  const plaintext = bytes.toString(cryptoJsExports.enc.Utf8);
7140
7171
  return plaintext || null;
7141
- } catch {
7172
+ } catch (error) {
7173
+ if (isDebugMode()) {
7174
+ console.warn("⚠️ [native-sso] Failed to decrypt storage value, clearing corrupted entry", error);
7175
+ }
7142
7176
  return null;
7143
7177
  }
7144
7178
  }
@@ -7154,8 +7188,9 @@ function createEncryptedStorageAdapter(base) {
7154
7188
  if (decrypted !== null) {
7155
7189
  return decrypted;
7156
7190
  }
7157
- if (rawValue.length > 0) {
7158
- base.setItem(key, encryptStorageValue(rawValue));
7191
+ if (normalizeStorageValue(rawValue).startsWith(STORAGE_ENCRYPTION_PREFIX)) {
7192
+ base.removeItem(key);
7193
+ return null;
7159
7194
  }
7160
7195
  return rawValue;
7161
7196
  }
@@ -7176,7 +7211,7 @@ function createEncryptedStorageAdapter(base) {
7176
7211
  },
7177
7212
  setItem: (key, value) => {
7178
7213
  if (isRawStorageKey(key)) {
7179
- base.setItem(key, value);
7214
+ base.setItem(key, normalizeStorageValue(value));
7180
7215
  return;
7181
7216
  }
7182
7217
  base.setItem(key, encryptStorageValue(value));
@@ -7228,6 +7263,7 @@ const getIamApiBaseUrl = () => {
7228
7263
  };
7229
7264
  const DEVICE_ID_KEY = "sso_device_id";
7230
7265
  const SESSION_UUID_KEY = "sso_session_uuid";
7266
+ const STORAGE_SEED_KEY = "native_sso_storage_seed";
7231
7267
  function generateUuid() {
7232
7268
  const globalCrypto = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
7233
7269
  if (globalCrypto && typeof globalCrypto.randomUUID === "function") {
@@ -7335,8 +7371,26 @@ const PROFILE_STORAGE = {
7335
7371
  IMAGE_LAST_CHECK: "sso_image_last_check",
7336
7372
  IMAGE_RECHECK_AT: "sso_image_recheck_at"
7337
7373
  };
7374
+ const ALL_SESSION_STORAGE_KEYS = [
7375
+ STORAGE.AUTH_TOKEN,
7376
+ STORAGE.TOKEN,
7377
+ STORAGE.USER,
7378
+ STORAGE.ACCOUNT_TYPE,
7379
+ STORAGE.ALIAS_REFERENCE,
7380
+ STORAGE.APP_ACCESS_TOKEN_REF,
7381
+ STORAGE.REFRESH_TOKEN,
7382
+ STORAGE.TOKEN_EXPIRES_AT,
7383
+ STORAGE.REFRESH_EXPIRES_AT,
7384
+ PROFILE_STORAGE.IMAGE_LAST_STATUS,
7385
+ PROFILE_STORAGE.IMAGE_LAST_CHECK,
7386
+ PROFILE_STORAGE.IMAGE_RECHECK_AT,
7387
+ DEVICE_ID_KEY,
7388
+ SESSION_UUID_KEY,
7389
+ STORAGE_SEED_KEY
7390
+ ];
7338
7391
  const setAuthToken = (token) => {
7339
7392
  const storage = getNativeStorage();
7393
+ if (typeof token !== "string" || token.length === 0) return;
7340
7394
  storage.setItem(STORAGE.AUTH_TOKEN, token);
7341
7395
  };
7342
7396
  const getAuthToken = () => {
@@ -7345,15 +7399,68 @@ const getAuthToken = () => {
7345
7399
  };
7346
7400
  const clearAuthToken = () => {
7347
7401
  const storage = getNativeStorage();
7348
- storage.removeItem(STORAGE.AUTH_TOKEN);
7349
- storage.removeItem(STORAGE.TOKEN);
7350
- storage.removeItem(STORAGE.USER);
7351
- storage.removeItem(STORAGE.ACCOUNT_TYPE);
7352
- storage.removeItem(STORAGE.ALIAS_REFERENCE);
7353
- storage.removeItem(STORAGE.APP_ACCESS_TOKEN_REF);
7354
- storage.removeItem(STORAGE.REFRESH_TOKEN);
7355
- storage.removeItem(STORAGE.TOKEN_EXPIRES_AT);
7356
- storage.removeItem(STORAGE.REFRESH_EXPIRES_AT);
7402
+ [
7403
+ STORAGE.AUTH_TOKEN,
7404
+ STORAGE.TOKEN,
7405
+ STORAGE.USER,
7406
+ STORAGE.ACCOUNT_TYPE,
7407
+ STORAGE.ALIAS_REFERENCE,
7408
+ STORAGE.APP_ACCESS_TOKEN_REF,
7409
+ STORAGE.REFRESH_TOKEN,
7410
+ STORAGE.TOKEN_EXPIRES_AT,
7411
+ STORAGE.REFRESH_EXPIRES_AT
7412
+ ].forEach((key) => {
7413
+ try {
7414
+ storage.removeItem(key);
7415
+ } catch {
7416
+ }
7417
+ });
7418
+ };
7419
+ const clearNativeSsoStorage = (options) => {
7420
+ const storage = getNativeStorage();
7421
+ const preserveDeviceIdentity = (options == null ? void 0 : options.preserveDeviceIdentity) === true;
7422
+ ALL_SESSION_STORAGE_KEYS.forEach((key) => {
7423
+ if (preserveDeviceIdentity && (key === DEVICE_ID_KEY || key === SESSION_UUID_KEY || key === STORAGE_SEED_KEY)) {
7424
+ return;
7425
+ }
7426
+ try {
7427
+ storage.removeItem(key);
7428
+ } catch {
7429
+ }
7430
+ });
7431
+ };
7432
+ const repairNativeSsoStorage = () => {
7433
+ try {
7434
+ const storage = getNativeStorage();
7435
+ const authToken = getAuthToken();
7436
+ const userRaw = storage.getItem(STORAGE.USER);
7437
+ if (userRaw && !authToken) {
7438
+ clearNativeSsoStorage();
7439
+ return { cleaned: true, reason: "incomplete_session" };
7440
+ }
7441
+ if (authToken && !userRaw) {
7442
+ clearNativeSsoStorage();
7443
+ return { cleaned: true, reason: "incomplete_session" };
7444
+ }
7445
+ if (userRaw) {
7446
+ try {
7447
+ JSON.parse(userRaw);
7448
+ } catch {
7449
+ clearNativeSsoStorage();
7450
+ return { cleaned: true, reason: "invalid_user_json" };
7451
+ }
7452
+ }
7453
+ return { cleaned: false, reason: null };
7454
+ } catch (error) {
7455
+ if (isDebugMode()) {
7456
+ console.warn("⚠️ [native-sso] Storage repair failed, forcing cleanup", error);
7457
+ }
7458
+ try {
7459
+ clearNativeSsoStorage();
7460
+ } catch {
7461
+ }
7462
+ return { cleaned: true, reason: "incomplete_session" };
7463
+ }
7357
7464
  };
7358
7465
  const logout = async () => {
7359
7466
  const { nativeAuthService: nativeAuthService2 } = await Promise.resolve().then(() => nativeAuth);
@@ -7361,7 +7468,7 @@ const logout = async () => {
7361
7468
  return nativeAuthService2.logout(token || void 0);
7362
7469
  };
7363
7470
  const setAuthUser = (user) => {
7364
- getNativeStorage().setItem(STORAGE.USER, JSON.stringify(user));
7471
+ getNativeStorage().setItem(STORAGE.USER, safeJSONStringify(user));
7365
7472
  };
7366
7473
  const getAuthUser = () => {
7367
7474
  const user = getNativeStorage().getItem(STORAGE.USER);
@@ -8187,6 +8294,12 @@ function getErrorMessage$2(err, context) {
8187
8294
  function useMobilePassword(options) {
8188
8295
  const { saasApiUrl, iamApiUrl, autoLoadCredentials = true } = options;
8189
8296
  const configuredRef = useRef(false);
8297
+ useEffect(() => {
8298
+ const repairResult = repairNativeSsoStorage();
8299
+ if (repairResult.cleaned && isDebugMode()) {
8300
+ console.warn("🔧 [useMobilePassword] Storage SSO réparé", repairResult.reason);
8301
+ }
8302
+ }, []);
8190
8303
  useEffect(() => {
8191
8304
  if (!configuredRef.current) {
8192
8305
  setNativeAuthConfig({ saasApiUrl, iamApiUrl });
@@ -8832,6 +8945,12 @@ function useNativeAuth(options) {
8832
8945
  setNativeStorage(storage);
8833
8946
  }
8834
8947
  const configuredRef = useRef(false);
8948
+ useEffect(() => {
8949
+ const repairResult = repairNativeSsoStorage();
8950
+ if (repairResult.cleaned && isDebugMode()) {
8951
+ console.warn("🔧 [useNativeAuth] Storage SSO réparé", repairResult.reason);
8952
+ }
8953
+ }, []);
8835
8954
  const [isDebug, setIsDebug] = useState(isDebugMode());
8836
8955
  useEffect(() => {
8837
8956
  if (!configuredRef.current) {
@@ -13286,6 +13405,16 @@ function NativeSSOPage({
13286
13405
  useEffect(() => {
13287
13406
  sessionRef.current = session;
13288
13407
  }, [session]);
13408
+ useEffect(() => {
13409
+ const repairResult = repairNativeSsoStorage();
13410
+ if (repairResult.cleaned) {
13411
+ setSession(null);
13412
+ const isDev = Boolean(false);
13413
+ if (isDev) {
13414
+ console.warn("🔧 [NativeSSOPage] Storage SSO réparé", repairResult.reason);
13415
+ }
13416
+ }
13417
+ }, []);
13289
13418
  useEffect(() => {
13290
13419
  if (!redirectingTarget) return;
13291
13420
  const timer = window.setTimeout(() => {
@@ -14034,6 +14163,7 @@ export {
14034
14163
  STORAGE as STORAGE_KEYS,
14035
14164
  SignupModal,
14036
14165
  clearAuthToken,
14166
+ clearNativeSsoStorage,
14037
14167
  getAccountType,
14038
14168
  getAuthToken,
14039
14169
  getAuthUser,
@@ -14054,6 +14184,7 @@ export {
14054
14184
  nativeAuthService,
14055
14185
  profileChangeService,
14056
14186
  profileMediaService,
14187
+ repairNativeSsoStorage,
14057
14188
  searchCountries,
14058
14189
  setNativeAuthConfig,
14059
14190
  setNativeStorage,