@nlabs/arkhamjs-storage-browser
Version:
Browser storage for ArkhamJS with enhanced performance and modern ESNext features
311 lines (310 loc) • 30.4 kB
JavaScript
/**
* Copyright (c) 2018-Present, Nitrogen Labs, Inc.
* Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
*/ function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
const DEFAULT_PREFIX = 'arkhamjs_';
const DEFAULT_MAX_SIZE = 5 * 1024 * 1024; // 5MB
const DEFAULT_TTL = 24 * 60 * 60 * 1000; // 24 hours
const isExpired = (data)=>{
if (!data.ttl) {
return false;
}
return Date.now() - data.timestamp > data.ttl;
};
const getStorageSize = (data)=>new Blob([
data
]).size;
const compressData = (data)=>{
const jsonString = JSON.stringify(data);
if (jsonString.length > 1000) {
return jsonString;
}
return jsonString;
};
const decompressData = (data)=>{
try {
return JSON.parse(data);
} catch {
return null;
}
};
export class BrowserStorage {
static delLocalData(key) {
try {
const storage = BrowserStorage.window.localStorage;
if (storage) {
storage.removeItem(key);
return true;
}
} catch {
// Storage not available
}
return false;
}
static delSessionData(key) {
try {
const storage = BrowserStorage.window.sessionStorage;
if (storage) {
storage.removeItem(key);
return true;
}
} catch {
// Storage not available
}
return false;
}
static getLocalData(key) {
try {
const storage = BrowserStorage.window.localStorage;
if (storage) {
const item = storage.getItem(key);
return item ? JSON.parse(item) : null;
}
} catch {
// Storage not available or invalid JSON
}
return null;
}
static getSessionData(key) {
try {
const storage = BrowserStorage.window.sessionStorage;
if (storage) {
const item = storage.getItem(key);
return item ? JSON.parse(item) : null;
}
} catch {
// Storage not available or invalid JSON
}
return null;
}
static setLocalData(key, value) {
try {
const storage = BrowserStorage.window.localStorage;
if (storage) {
storage.setItem(key, JSON.stringify(value));
return true;
}
} catch {
// Storage not available or quota exceeded
}
return false;
}
static setSessionData(key, value) {
try {
const storage = BrowserStorage.window.sessionStorage;
if (storage) {
storage.setItem(key, JSON.stringify(value));
return true;
}
} catch {
// Storage not available or quota exceeded
}
return false;
}
static getLocalStorage() {
try {
return BrowserStorage.window.localStorage || null;
} catch {
return null;
}
}
static getSessionStorage() {
try {
return BrowserStorage.window.sessionStorage || null;
} catch {
return null;
}
}
async getStorageData(key) {
if (!this.isStorageAvailable()) {
return null;
}
const prefixedKey = this.getPrefixedKey(key);
if (this.storageCache.has(prefixedKey)) {
return this.storageCache.get(prefixedKey);
}
try {
const item = this.storage.getItem(prefixedKey);
if (!item) {
return null;
}
const data = decompressData(item);
if (!data) {
return null;
}
if (isExpired(data)) {
this.storage.removeItem(prefixedKey);
this.storageCache.delete(prefixedKey);
return null;
}
this.storageCache.set(prefixedKey, data.value);
return data.value;
} catch {
return null;
}
}
async setStorageData(key, value) {
if (!this.isStorageAvailable()) {
return false;
}
const prefixedKey = this.getPrefixedKey(key);
try {
// Clean expired data periodically
if (Math.random() < 0.1) {
this.cleanExpiredData();
}
const storageData = {
timestamp: Date.now(),
ttl: this.options.ttl,
value
};
const jsonString = this.options.compression ? compressData(storageData) : JSON.stringify(storageData);
if (!this.validateSize(jsonString)) {
// eslint-disable-next-line no-console
console.warn(`Storage data exceeds maximum size for key: ${key}`);
return false;
}
this.storage.setItem(prefixedKey, jsonString);
this.storageCache.set(prefixedKey, value);
return true;
} catch (error) {
// eslint-disable-next-line no-console
console.error('Failed to set storage data:', error);
return false;
}
}
async removeStorageData(key) {
if (!this.isStorageAvailable()) {
return false;
}
const prefixedKey = this.getPrefixedKey(key);
try {
this.storage.removeItem(prefixedKey);
this.storageCache.delete(prefixedKey);
return true;
} catch {
return false;
}
}
async clearStorageData() {
if (!this.isStorageAvailable()) {
return false;
}
try {
const keys = [];
for(let i = 0; i < this.storage.length; i++){
const key = this.storage.key(i);
if (key?.startsWith(this.options.prefix)) {
keys.push(key);
}
}
keys.forEach((key)=>{
this.storage.removeItem(key);
this.storageCache.delete(key);
});
return true;
} catch {
return false;
}
}
getStorageStats() {
if (!this.isStorageAvailable()) {
return {
available: 0,
total: 0,
used: 0
};
}
let used = 0;
const keys = [];
for(let i = 0; i < this.storage.length; i++){
const key = this.storage.key(i);
if (key?.startsWith(this.options.prefix)) {
keys.push(key);
const item = this.storage.getItem(key);
if (item) {
used += getStorageSize(item);
}
}
}
return {
available: this.options.maxSize - used,
total: this.options.maxSize,
used
};
}
getStorage() {
try {
const { type } = this.options;
const storage = type === 'local' ? BrowserStorage.window.localStorage : BrowserStorage.window.sessionStorage;
return storage || null;
} catch {
return null;
}
}
getPrefixedKey(key) {
return `${this.options.prefix}${key}`;
}
isStorageAvailable() {
return this.storage !== null;
}
validateSize(data) {
const size = getStorageSize(data);
return size <= this.options.maxSize;
}
cleanExpiredData() {
if (!this.isStorageAvailable()) {
return;
}
const keys = [];
for(let i = 0; i < this.storage.length; i++){
const key = this.storage.key(i);
if (key?.startsWith(this.options.prefix)) {
keys.push(key);
}
}
keys.forEach((key)=>{
try {
const item = this.storage.getItem(key);
if (item) {
const data = decompressData(item);
if (data && isExpired(data)) {
this.storage.removeItem(key);
this.storageCache.delete(key);
}
}
} catch {
this.storage.removeItem(key);
this.storageCache.delete(key);
}
});
}
constructor(options = {}){
_define_property(this, "options", void 0);
_define_property(this, "storageCache", new Map());
_define_property(this, "storage", void 0);
this.options = {
compression: false,
maxSize: DEFAULT_MAX_SIZE,
prefix: DEFAULT_PREFIX,
ttl: DEFAULT_TTL,
type: 'session',
...options
};
this.storage = this.getStorage();
}
}
_define_property(BrowserStorage, "window", typeof window !== 'undefined' ? window : {});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L2Fya2hhbWpzL3BhY2thZ2VzL2Fya2hhbWpzLXN0b3JhZ2UtYnJvd3Nlci9zcmMvQnJvd3NlclN0b3JhZ2UvQnJvd3NlclN0b3JhZ2UudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTgtUHJlc2VudCwgTml0cm9nZW4gTGFicywgSW5jLlxuICogQ29weXJpZ2h0cyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSB0aGUgYWNjb21wYW55aW5nIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMuXG4gKi9cbmltcG9ydCB0eXBlIHtcbiAgQnJvd3NlclN0b3JhZ2VPcHRpb25zLFxuICBTdG9yYWdlRGF0YSxcbiAgU3RvcmFnZUludGVyZmFjZVxufSBmcm9tICcuLi90eXBlcy9tYWluLmpzJztcblxuY29uc3QgREVGQVVMVF9QUkVGSVggPSAnYXJraGFtanNfJztcbmNvbnN0IERFRkFVTFRfTUFYX1NJWkUgPSA1ICogMTAyNCAqIDEwMjQ7IC8vIDVNQlxuY29uc3QgREVGQVVMVF9UVEwgPSAyNCAqIDYwICogNjAgKiAxMDAwOyAvLyAyNCBob3Vyc1xuXG5jb25zdCBpc0V4cGlyZWQgPSAoZGF0YTogU3RvcmFnZURhdGEpOiBib29sZWFuID0+IHtcbiAgaWYoIWRhdGEudHRsKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiBEYXRlLm5vdygpIC0gZGF0YS50aW1lc3RhbXAgPiBkYXRhLnR0bDtcbn07XG5cbmNvbnN0IGdldFN0b3JhZ2VTaXplID0gKGRhdGE6IHN0cmluZyk6IG51bWJlciA9PiBuZXcgQmxvYihbZGF0YV0pLnNpemU7XG5cbmNvbnN0IGNvbXByZXNzRGF0YSA9IChkYXRhOiBhbnkpOiBzdHJpbmcgPT4ge1xuICBjb25zdCBqc29uU3RyaW5nID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gIGlmKGpzb25TdHJpbmcubGVuZ3RoID4gMTAwMCkge1xuICAgIHJldHVybiBqc29uU3RyaW5nO1xuICB9XG4gIHJldHVybiBqc29uU3RyaW5nO1xufTtcblxuY29uc3QgZGVjb21wcmVzc0RhdGEgPSAoZGF0YTogc3RyaW5nKTogYW55ID0+IHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShkYXRhKTtcbiAgfSBjYXRjaHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufTtcblxuZXhwb3J0IGNsYXNzIEJyb3dzZXJTdG9yYWdlIHtcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgd2luZG93OiBXaW5kb3cgJiB0eXBlb2YgZ2xvYmFsVGhpcyA9XG4gICAgdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiB7fSBhcyBhbnk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiBSZXF1aXJlZDxCcm93c2VyU3RvcmFnZU9wdGlvbnM+O1xuICBwcml2YXRlIHJlYWRvbmx5IHN0b3JhZ2VDYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBhbnk+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgc3RvcmFnZTogU3RvcmFnZUludGVyZmFjZSB8IG51bGw7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogQnJvd3NlclN0b3JhZ2VPcHRpb25zID0ge30pIHtcbiAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICBjb21wcmVzc2lvbjogZmFsc2UsXG4gICAgICBtYXhTaXplOiBERUZBVUxUX01BWF9TSVpFLFxuICAgICAgcHJlZml4OiBERUZBVUxUX1BSRUZJWCxcbiAgICAgIHR0bDogREVGQVVMVF9UVEwsXG4gICAgICB0eXBlOiAnc2Vzc2lvbicsXG4gICAgICAuLi5vcHRpb25zXG4gICAgfTtcblxuICAgIHRoaXMuc3RvcmFnZSA9IHRoaXMuZ2V0U3RvcmFnZSgpO1xuICB9XG5cbiAgc3RhdGljIGRlbExvY2FsRGF0YShrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzdG9yYWdlID0gQnJvd3NlclN0b3JhZ2Uud2luZG93LmxvY2FsU3RvcmFnZTtcbiAgICAgIGlmKHN0b3JhZ2UpIHtcbiAgICAgICAgc3RvcmFnZS5yZW1vdmVJdGVtKGtleSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH0gY2F0Y2h7XG4gICAgICAvLyBTdG9yYWdlIG5vdCBhdmFpbGFibGVcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgc3RhdGljIGRlbFNlc3Npb25EYXRhKGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN0b3JhZ2UgPSBCcm93c2VyU3RvcmFnZS53aW5kb3cuc2Vzc2lvblN0b3JhZ2U7XG4gICAgICBpZihzdG9yYWdlKSB7XG4gICAgICAgIHN0b3JhZ2UucmVtb3ZlSXRlbShrZXkpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9IGNhdGNoe1xuICAgICAgLy8gU3RvcmFnZSBub3QgYXZhaWxhYmxlXG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHN0YXRpYyBnZXRMb2NhbERhdGEoa2V5OiBzdHJpbmcpOiBhbnkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzdG9yYWdlID0gQnJvd3NlclN0b3JhZ2Uud2luZG93LmxvY2FsU3RvcmFnZTtcbiAgICAgIGlmKHN0b3JhZ2UpIHtcbiAgICAgICAgY29uc3QgaXRlbSA9IHN0b3JhZ2UuZ2V0SXRlbShrZXkpO1xuICAgICAgICByZXR1cm4gaXRlbSA/IEpTT04ucGFyc2UoaXRlbSkgOiBudWxsO1xuICAgICAgfVxuICAgIH0gY2F0Y2h7XG4gICAgICAvLyBTdG9yYWdlIG5vdCBhdmFpbGFibGUgb3IgaW52YWxpZCBKU09OXG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgc3RhdGljIGdldFNlc3Npb25EYXRhKGtleTogc3RyaW5nKTogYW55IHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc3RvcmFnZSA9IEJyb3dzZXJTdG9yYWdlLndpbmRvdy5zZXNzaW9uU3RvcmFnZTtcbiAgICAgIGlmKHN0b3JhZ2UpIHtcbiAgICAgICAgY29uc3QgaXRlbSA9IHN0b3JhZ2UuZ2V0SXRlbShrZXkpO1xuICAgICAgICByZXR1cm4gaXRlbSA/IEpTT04ucGFyc2UoaXRlbSkgOiBudWxsO1xuICAgICAgfVxuICAgIH0gY2F0Y2h7XG4gICAgICAvLyBTdG9yYWdlIG5vdCBhdmFpbGFibGUgb3IgaW52YWxpZCBKU09OXG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgc3RhdGljIHNldExvY2FsRGF0YShrZXk6IHN0cmluZywgdmFsdWU6IGFueSk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzdG9yYWdlID0gQnJvd3NlclN0b3JhZ2Uud2luZG93LmxvY2FsU3RvcmFnZTtcbiAgICAgIGlmKHN0b3JhZ2UpIHtcbiAgICAgICAgc3RvcmFnZS5zZXRJdGVtKGtleSwgSlNPTi5zdHJpbmdpZnkodmFsdWUpKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfSBjYXRjaHtcbiAgICAgIC8vIFN0b3JhZ2Ugbm90IGF2YWlsYWJsZSBvciBxdW90YSBleGNlZWRlZFxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBzdGF0aWMgc2V0U2Vzc2lvbkRhdGEoa2V5OiBzdHJpbmcsIHZhbHVlOiBhbnkpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc3RvcmFnZSA9IEJyb3dzZXJTdG9yYWdlLndpbmRvdy5zZXNzaW9uU3RvcmFnZTtcbiAgICAgIGlmKHN0b3JhZ2UpIHtcbiAgICAgICAgc3RvcmFnZS5zZXRJdGVtKGtleSwgSlNPTi5zdHJpbmdpZnkodmFsdWUpKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfSBjYXRjaHtcbiAgICAgIC8vIFN0b3JhZ2Ugbm90IGF2YWlsYWJsZSBvciBxdW90YSBleGNlZWRlZFxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBzdGF0aWMgZ2V0TG9jYWxTdG9yYWdlKCk6IFN0b3JhZ2UgfCBudWxsIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEJyb3dzZXJTdG9yYWdlLndpbmRvdy5sb2NhbFN0b3JhZ2UgfHwgbnVsbDtcbiAgICB9IGNhdGNoe1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIGdldFNlc3Npb25TdG9yYWdlKCk6IFN0b3JhZ2UgfCBudWxsIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEJyb3dzZXJTdG9yYWdlLndpbmRvdy5zZXNzaW9uU3RvcmFnZSB8fCBudWxsO1xuICAgIH0gY2F0Y2h7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICBhc3luYyBnZXRTdG9yYWdlRGF0YShrZXk6IHN0cmluZyk6IFByb21pc2U8YW55PiB7XG4gICAgaWYoIXRoaXMuaXNTdG9yYWdlQXZhaWxhYmxlKCkpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IHByZWZpeGVkS2V5ID0gdGhpcy5nZXRQcmVmaXhlZEtleShrZXkpO1xuXG4gICAgaWYodGhpcy5zdG9yYWdlQ2FjaGUuaGFzKHByZWZpeGVkS2V5KSkge1xuICAgICAgcmV0dXJuIHRoaXMuc3RvcmFnZUNhY2hlLmdldChwcmVmaXhlZEtleSk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGl0ZW0gPSB0aGlzLnN0b3JhZ2UhLmdldEl0ZW0ocHJlZml4ZWRLZXkpO1xuICAgICAgaWYoIWl0ZW0pIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRhdGEgPSBkZWNvbXByZXNzRGF0YShpdGVtKTtcbiAgICAgIGlmKCFkYXRhKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBpZihpc0V4cGlyZWQoZGF0YSkpIHtcbiAgICAgICAgdGhpcy5zdG9yYWdlIS5yZW1vdmVJdGVtKHByZWZpeGVkS2V5KTtcbiAgICAgICAgdGhpcy5zdG9yYWdlQ2FjaGUuZGVsZXRlKHByZWZpeGVkS2V5KTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc3RvcmFnZUNhY2hlLnNldChwcmVmaXhlZEtleSwgZGF0YS52YWx1ZSk7XG4gICAgICByZXR1cm4gZGF0YS52YWx1ZTtcbiAgICB9IGNhdGNoe1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgc2V0U3RvcmFnZURhdGEoa2V5OiBzdHJpbmcsIHZhbHVlOiBhbnkpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZighdGhpcy5pc1N0b3JhZ2VBdmFpbGFibGUoKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IHByZWZpeGVkS2V5ID0gdGhpcy5nZXRQcmVmaXhlZEtleShrZXkpO1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIENsZWFuIGV4cGlyZWQgZGF0YSBwZXJpb2RpY2FsbHlcbiAgICAgIGlmKE1hdGgucmFuZG9tKCkgPCAwLjEpIHsgLy8gMTAlIGNoYW5jZSB0byBjbGVhblxuICAgICAgICB0aGlzLmNsZWFuRXhwaXJlZERhdGEoKTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3RvcmFnZURhdGE6IFN0b3JhZ2VEYXRhID0ge1xuICAgICAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXG4gICAgICAgIHR0bDogdGhpcy5vcHRpb25zLnR0bCxcbiAgICAgICAgdmFsdWVcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGpzb25TdHJpbmcgPSB0aGlzLm9wdGlvbnMuY29tcHJlc3Npb25cbiAgICAgICAgPyBjb21wcmVzc0RhdGEoc3RvcmFnZURhdGEpXG4gICAgICAgIDogSlNPTi5zdHJpbmdpZnkoc3RvcmFnZURhdGEpO1xuXG4gICAgICBpZighdGhpcy52YWxpZGF0ZVNpemUoanNvblN0cmluZykpIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICAgICAgY29uc29sZS53YXJuKGBTdG9yYWdlIGRhdGEgZXhjZWVkcyBtYXhpbXVtIHNpemUgZm9yIGtleTogJHtrZXl9YCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5zdG9yYWdlIS5zZXRJdGVtKHByZWZpeGVkS2V5LCBqc29uU3RyaW5nKTtcblxuICAgICAgdGhpcy5zdG9yYWdlQ2FjaGUuc2V0KHByZWZpeGVkS2V5LCB2YWx1ZSk7XG5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gICAgICBjb25zb2xlLmVycm9yKCdGYWlsZWQgdG8gc2V0IHN0b3JhZ2UgZGF0YTonLCBlcnJvcik7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcmVtb3ZlU3RvcmFnZURhdGEoa2V5OiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZighdGhpcy5pc1N0b3JhZ2VBdmFpbGFibGUoKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGNvbnN0IHByZWZpeGVkS2V5ID0gdGhpcy5nZXRQcmVmaXhlZEtleShrZXkpO1xuXG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuc3RvcmFnZSEucmVtb3ZlSXRlbShwcmVmaXhlZEtleSk7XG4gICAgICB0aGlzLnN0b3JhZ2VDYWNoZS5kZWxldGUocHJlZml4ZWRLZXkpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBjbGVhclN0b3JhZ2VEYXRhKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmKCF0aGlzLmlzU3RvcmFnZUF2YWlsYWJsZSgpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGtleXM6IHN0cmluZ1tdID0gW107XG4gICAgICBmb3IobGV0IGkgPSAwOyBpIDwgdGhpcy5zdG9yYWdlIS5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCBrZXkgPSB0aGlzLnN0b3JhZ2UhLmtleShpKTtcbiAgICAgICAgaWYoa2V5Py5zdGFydHNXaXRoKHRoaXMub3B0aW9ucy5wcmVmaXgpKSB7XG4gICAgICAgICAga2V5cy5wdXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAga2V5cy5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAgICAgdGhpcy5zdG9yYWdlIS5yZW1vdmVJdGVtKGtleSk7XG4gICAgICAgIHRoaXMuc3RvcmFnZUNhY2hlLmRlbGV0ZShrZXkpO1xuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2h7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgZ2V0U3RvcmFnZVN0YXRzKCk6IHsgYXZhaWxhYmxlOiBudW1iZXI7IHRvdGFsOiBudW1iZXI7IHVzZWQ6IG51bWJlciB9IHtcbiAgICBpZighdGhpcy5pc1N0b3JhZ2VBdmFpbGFibGUoKSkge1xuICAgICAgcmV0dXJuIHthdmFpbGFibGU6IDAsIHRvdGFsOiAwLCB1c2VkOiAwfTtcbiAgICB9XG5cbiAgICBsZXQgdXNlZCA9IDA7XG4gICAgY29uc3Qga2V5czogc3RyaW5nW10gPSBbXTtcblxuICAgIGZvcihsZXQgaSA9IDA7IGkgPCB0aGlzLnN0b3JhZ2UhLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBrZXkgPSB0aGlzLnN0b3JhZ2UhLmtleShpKTtcbiAgICAgIGlmKGtleT8uc3RhcnRzV2l0aCh0aGlzLm9wdGlvbnMucHJlZml4KSkge1xuICAgICAgICBrZXlzLnB1c2goa2V5KTtcbiAgICAgICAgY29uc3QgaXRlbSA9IHRoaXMuc3RvcmFnZSEuZ2V0SXRlbShrZXkpO1xuICAgICAgICBpZihpdGVtKSB7XG4gICAgICAgICAgdXNlZCArPSBnZXRTdG9yYWdlU2l6ZShpdGVtKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBhdmFpbGFibGU6IHRoaXMub3B0aW9ucy5tYXhTaXplIC0gdXNlZCxcbiAgICAgIHRvdGFsOiB0aGlzLm9wdGlvbnMubWF4U2l6ZSxcbiAgICAgIHVzZWRcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRTdG9yYWdlKCk6IFN0b3JhZ2VJbnRlcmZhY2UgfCBudWxsIHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qge3R5cGV9ID0gdGhpcy5vcHRpb25zO1xuICAgICAgY29uc3Qgc3RvcmFnZSA9IHR5cGUgPT09ICdsb2NhbCdcbiAgICAgICAgPyBCcm93c2VyU3RvcmFnZS53aW5kb3cubG9jYWxTdG9yYWdlXG4gICAgICAgIDogQnJvd3NlclN0b3JhZ2Uud2luZG93LnNlc3Npb25TdG9yYWdlO1xuXG4gICAgICByZXR1cm4gc3RvcmFnZSB8fCBudWxsO1xuICAgIH0gY2F0Y2h7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGdldFByZWZpeGVkS2V5KGtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYCR7dGhpcy5vcHRpb25zLnByZWZpeH0ke2tleX1gO1xuICB9XG5cbiAgcHJpdmF0ZSBpc1N0b3JhZ2VBdmFpbGFibGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmFnZSAhPT0gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVTaXplKGRhdGE6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHNpemUgPSBnZXRTdG9yYWdlU2l6ZShkYXRhKTtcbiAgICByZXR1cm4gc2l6ZSA8PSB0aGlzLm9wdGlvbnMubWF4U2l6ZTtcbiAgfVxuXG4gIHByaXZhdGUgY2xlYW5FeHBpcmVkRGF0YSgpOiB2b2lkIHtcbiAgICBpZighdGhpcy5pc1N0b3JhZ2VBdmFpbGFibGUoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGtleXM6IHN0cmluZ1tdID0gW107XG4gICAgZm9yKGxldCBpID0gMDsgaSA8IHRoaXMuc3RvcmFnZSEubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGtleSA9IHRoaXMuc3RvcmFnZSEua2V5KGkpO1xuICAgICAgaWYoa2V5Py5zdGFydHNXaXRoKHRoaXMub3B0aW9ucy5wcmVmaXgpKSB7XG4gICAgICAgIGtleXMucHVzaChrZXkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGtleXMuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBpdGVtID0gdGhpcy5zdG9yYWdlIS5nZXRJdGVtKGtleSk7XG4gICAgICAgIGlmKGl0ZW0pIHtcbiAgICAgICAgICBjb25zdCBkYXRhID0gZGVjb21wcmVzc0RhdGEoaXRlbSk7XG4gICAgICAgICAgaWYoZGF0YSAmJiBpc0V4cGlyZWQoZGF0YSkpIHtcbiAgICAgICAgICAgIHRoaXMuc3RvcmFnZSEucmVtb3ZlSXRlbShrZXkpO1xuICAgICAgICAgICAgdGhpcy5zdG9yYWdlQ2FjaGUuZGVsZXRlKGtleSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGNhdGNoe1xuICAgICAgICB0aGlzLnN0b3JhZ2UhLnJlbW92ZUl0ZW0oa2V5KTtcbiAgICAgICAgdGhpcy5zdG9yYWdlQ2FjaGUuZGVsZXRlKGtleSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJERUZBVUxUX1BSRUZJWCIsIkRFRkFVTFRfTUFYX1NJWkUiLCJERUZBVUxUX1RUTCIsImlzRXhwaXJlZCIsImRhdGEiLCJ0dGwiLCJEYXRlIiwibm93IiwidGltZXN0YW1wIiwiZ2V0U3RvcmFnZVNpemUiLCJCbG9iIiwic2l6ZSIsImNvbXByZXNzRGF0YSIsImpzb25TdHJpbmciLCJKU09OIiwic3RyaW5naWZ5IiwibGVuZ3RoIiwiZGVjb21wcmVzc0RhdGEiLCJwYXJzZSIsIkJyb3dzZXJTdG9yYWdlIiwiZGVsTG9jYWxEYXRhIiwia2V5Iiwic3RvcmFnZSIsIndpbmRvdyIsImxvY2FsU3RvcmFnZSIsInJlbW92ZUl0ZW0iLCJkZWxTZXNzaW9uRGF0YSIsInNlc3Npb25TdG9yYWdlIiwiZ2V0TG9jYWxEYXRhIiwiaXRlbSIsImdldEl0ZW0iLCJnZXRTZXNzaW9uRGF0YSIsInNldExvY2FsRGF0YSIsInZhbHVlIiwic2V0SXRlbSIsInNldFNlc3Npb25EYXRhIiwiZ2V0TG9jYWxTdG9yYWdlIiwiZ2V0U2Vzc2lvblN0b3JhZ2UiLCJnZXRTdG9yYWdlRGF0YSIsImlzU3RvcmFnZUF2YWlsYWJsZSIsInByZWZpeGVkS2V5IiwiZ2V0UHJlZml4ZWRLZXkiLCJzdG9yYWdlQ2FjaGUiLCJoYXMiLCJnZXQiLCJkZWxldGUiLCJzZXQiLCJzZXRTdG9yYWdlRGF0YSIsIk1hdGgiLCJyYW5kb20iLCJjbGVhbkV4cGlyZWREYXRhIiwic3RvcmFnZURhdGEiLCJvcHRpb25zIiwiY29tcHJlc3Npb24iLCJ2YWxpZGF0ZVNpemUiLCJjb25zb2xlIiwid2FybiIsImVycm9yIiwicmVtb3ZlU3RvcmFnZURhdGEiLCJjbGVhclN0b3JhZ2VEYXRhIiwia2V5cyIsImkiLCJzdGFydHNXaXRoIiwicHJlZml4IiwicHVzaCIsImZvckVhY2giLCJnZXRTdG9yYWdlU3RhdHMiLCJhdmFpbGFibGUiLCJ0b3RhbCIsInVzZWQiLCJtYXhTaXplIiwiZ2V0U3RvcmFnZSIsInR5cGUiLCJNYXAiXSwibWFwcGluZ3MiOiJBQUFBOzs7Q0FHQzs7Ozs7Ozs7Ozs7OztBQU9ELE1BQU1BLGlCQUFpQjtBQUN2QixNQUFNQyxtQkFBbUIsSUFBSSxPQUFPLE1BQU0sTUFBTTtBQUNoRCxNQUFNQyxjQUFjLEtBQUssS0FBSyxLQUFLLE1BQU0sV0FBVztBQUVwRCxNQUFNQyxZQUFZLENBQUNDO0lBQ2pCLElBQUcsQ0FBQ0EsS0FBS0MsR0FBRyxFQUFFO1FBQ1osT0FBTztJQUNUO0lBQ0EsT0FBT0MsS0FBS0MsR0FBRyxLQUFL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