mikrosafe
Version:
Encrypt and decrypt your LocalStorage data, simply and securely.
164 lines (162 loc) • 4.55 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/MikroSafe.ts
var MikroSafe_exports = {};
__export(MikroSafe_exports, {
MikroSafe: () => MikroSafe
});
module.exports = __toCommonJS(MikroSafe_exports);
var MikroSafe = class {
cryptoKey;
salt;
/**
* @description Creates a new MikroSafe instance with the provided password.
*/
constructor(password, options = {}) {
if (options.salt) {
if (typeof options.salt === "string") {
const encoder = new TextEncoder();
this.salt = encoder.encode(options.salt);
} else this.salt = options.salt;
} else {
this.salt = new Uint8Array([
21,
35,
190,
124,
99,
84,
23,
67,
128,
56,
33,
71,
190,
222,
37,
85
]);
}
this.cryptoKey = this.generateKey(password);
}
/**
* @description Store an encrypted value in localStorage.
*/
async setItem(key, value) {
try {
const valueString = JSON.stringify(value);
const encryptedData = await this.encrypt(valueString);
localStorage.setItem(key, encryptedData);
} catch (error) {
console.error("Failed to encrypt and store data:", error);
throw new Error("Encryption failed");
}
}
/**
* @description Retrieve and decrypt a value from localStorage.
*/
async getItem(key) {
const encryptedData = localStorage.getItem(key);
if (!encryptedData) return null;
try {
const decryptedString = await this.decrypt(encryptedData);
return JSON.parse(decryptedString);
} catch (error) {
console.error("Failed to decrypt data:", error);
return null;
}
}
/**
* @description Remove an item from localStorage.
*/
removeItem(key) {
localStorage.removeItem(key);
}
/**
* @description Clear all items from localStorage.
*/
clear() {
localStorage.clear();
}
/**
* @description Generate a cryptographic key from the password.
*/
async generateKey(password) {
const passwordBuffer = new TextEncoder().encode(password);
const keyMaterial = await window.crypto.subtle.importKey(
"raw",
passwordBuffer,
{ name: "PBKDF2" },
false,
["deriveBits", "deriveKey"]
);
return window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: this.salt,
iterations: 1e5,
hash: "SHA-256"
},
keyMaterial,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
}
/**
* @description Encrypt a string using AES-GCM.
*/
async encrypt(plaintext) {
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const key = await this.cryptoKey;
const dataBuffer = new TextEncoder().encode(plaintext);
const encryptedBuffer = await window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
key,
dataBuffer
);
const result = new Uint8Array(iv.length + encryptedBuffer.byteLength);
result.set(iv, 0);
result.set(new Uint8Array(encryptedBuffer), iv.length);
return btoa(String.fromCharCode(...result));
}
/**
* @description Decrypt a string using AES-GCM.
*/
async decrypt(encryptedData) {
const dataBuffer = Uint8Array.from(
atob(encryptedData),
(c) => c.charCodeAt(0)
);
const iv = dataBuffer.slice(0, 12);
const encryptedBuffer = dataBuffer.slice(12);
const key = await this.cryptoKey;
const decryptedBuffer = await window.crypto.subtle.decrypt(
{ name: "AES-GCM", iv },
key,
encryptedBuffer
);
return new TextDecoder().decode(decryptedBuffer);
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
MikroSafe
});
;