@anderson.tec12/utils
Version:
[](https://badge.fury.io/js/%40anderson.tec12%2Futils) [](https://opensource.org/licenses/MIT)
90 lines (76 loc) • 2.21 kB
text/typescript
class SecureStorage {
private secret: string;
private encoder = new TextEncoder();
private decoder = new TextDecoder();
constructor(secret: string) {
this.secret = secret;
}
private async getKey(): Promise<CryptoKey> {
const keyMaterial = await window.crypto.subtle.importKey(
'raw',
this.encoder.encode(this.secret),
'PBKDF2',
false,
['deriveKey']
);
return await window.crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: this.encoder.encode('saltaqui123'),
iterations: 100000,
hash: 'SHA-256',
},
keyMaterial,
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
}
async setItem(key: string, value: any): Promise<void> {
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const encoded = this.encoder.encode(JSON.stringify(value));
const cryptoKey = await this.getKey();
const encrypted = await window.crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: iv,
},
cryptoKey,
encoded
);
const data = {
iv: Array.from(iv),
value: Array.from(new Uint8Array(encrypted)),
};
localStorage.setItem(key, JSON.stringify(data));
}
async getItem<T>(key: string): Promise<T | null> {
const item = localStorage.getItem(key);
if (!item) return null;
const data = JSON.parse(item);
const iv = new Uint8Array(data.iv);
const encryptedData = new Uint8Array(data.value);
const cryptoKey = await this.getKey();
try {
const decrypted = await window.crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: iv,
},
cryptoKey,
encryptedData
);
return JSON.parse(this.decoder.decode(decrypted)) as T;
} catch (e) {
console.error('Erro ao descriptografar:', e);
return null;
}
}
removeItem(key: string): void {
localStorage.removeItem(key);
}
clear(): void {
localStorage.clear();
}
}
export const secureStorage = new SecureStorage('08dc3b0a3a70de0e0b82a6168814f697');