95 lines
2.5 KiB
TypeScript
95 lines
2.5 KiB
TypeScript
import CryptoJS from 'crypto-js';
|
|
import { APP_CONFIG } from '@/config';
|
|
|
|
interface StorageEnvelope<T> {
|
|
value: T;
|
|
expiresAt: number;
|
|
}
|
|
|
|
const AES_KEY = CryptoJS.enc.Hex.parse(CryptoJS.SHA256(APP_CONFIG.STORAGE_ENCRYPTION_KEY).toString());
|
|
const AES_IV = CryptoJS.enc.Hex.parse(CryptoJS.MD5(APP_CONFIG.STORAGE_ENCRYPTION_KEY).toString());
|
|
|
|
const encrypt = (value: unknown) => {
|
|
const payload = CryptoJS.enc.Utf8.parse(JSON.stringify(value));
|
|
return CryptoJS.AES.encrypt(payload, AES_KEY, {
|
|
iv: AES_IV,
|
|
mode: CryptoJS.mode.CBC,
|
|
padding: CryptoJS.pad.Pkcs7
|
|
}).toString();
|
|
};
|
|
|
|
const decrypt = <T>(value: string): T | null => {
|
|
try {
|
|
const decrypted = CryptoJS.AES.decrypt(value, AES_KEY, {
|
|
iv: AES_IV,
|
|
mode: CryptoJS.mode.CBC,
|
|
padding: CryptoJS.pad.Pkcs7
|
|
}).toString(CryptoJS.enc.Utf8);
|
|
if (decrypted) {
|
|
return JSON.parse(decrypted) as T;
|
|
}
|
|
|
|
// Backward compatibility for old passphrase-based ciphertexts.
|
|
const legacy = CryptoJS.AES.decrypt(value, APP_CONFIG.STORAGE_ENCRYPTION_KEY).toString(CryptoJS.enc.Utf8);
|
|
return legacy ? JSON.parse(legacy) as T : null;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
export const encryptedStorage = {
|
|
set<T>(key: string, value: T, expiresInSeconds = 0) {
|
|
const envelope: StorageEnvelope<T> = {
|
|
value,
|
|
expiresAt: expiresInSeconds > 0 ? Date.now() + expiresInSeconds * 1000 : 0
|
|
};
|
|
uni.setStorageSync(key, encrypt(envelope));
|
|
},
|
|
|
|
get<T>(key: string): T | null {
|
|
const encryptedValue = uni.getStorageSync(key);
|
|
if (typeof encryptedValue !== 'string' || !encryptedValue) return null;
|
|
|
|
const envelope = decrypt<StorageEnvelope<T>>(encryptedValue);
|
|
if (!envelope || typeof envelope !== 'object' || !('value' in envelope)) {
|
|
uni.removeStorageSync(key);
|
|
return null;
|
|
}
|
|
|
|
if (envelope.expiresAt > 0 && envelope.expiresAt <= Date.now()) {
|
|
uni.removeStorageSync(key);
|
|
return null;
|
|
}
|
|
|
|
return envelope.value;
|
|
},
|
|
|
|
remove(key: string) {
|
|
uni.removeStorageSync(key);
|
|
}
|
|
};
|
|
|
|
let cachedTokenLogged = false;
|
|
|
|
export const authStorage = {
|
|
getToken() {
|
|
const token = encryptedStorage.get<string>(APP_CONFIG.STORAGE_TOKEN_KEY) || '';
|
|
if (token && !cachedTokenLogged) {
|
|
cachedTokenLogged = true;
|
|
console.log('[cashier] token:', token);
|
|
}
|
|
return token;
|
|
},
|
|
|
|
setToken(token: string, expiresInSeconds = 0) {
|
|
encryptedStorage.set(APP_CONFIG.STORAGE_TOKEN_KEY, token, expiresInSeconds);
|
|
cachedTokenLogged = true;
|
|
console.log('[cashier] token:', token);
|
|
},
|
|
|
|
clearToken() {
|
|
encryptedStorage.remove(APP_CONFIG.STORAGE_TOKEN_KEY);
|
|
cachedTokenLogged = false;
|
|
}
|
|
};
|