UNPKG

@secure-storage/common

Version:

NPM package for storing and managing data across window local-storage and session-storage securely

1 lines 15.2 kB
{"version":3,"sources":["../src/index.ts","../src/utils/env.ts","../src/utils/crypt.ts","../src/utils/config.ts","../src/utils/store.ts"],"sourcesContent":["import { ENV } from \"./utils/env\";\nENV;\n\nimport { Store, changeWindow } from \"./utils/store\";\nimport { configure } from \"./utils/config\";\n\nchangeWindow(window);\n\nconst localStorage = new Store(\"local\");\nconst sessionStorage = new Store(\"session\");\n\nexport { localStorage, sessionStorage, configure };\n","export const ENV = process.env;\n","import CryptoJS from \"crypto-js\";\nimport { mainConfig } from \"./config\";\n\nconst secret = mainConfig.secret;\n\nexport const encrypt = (value: string) => {\n try {\n if (typeof value !== \"string\") {\n throw new Error(\"Value must be string\");\n }\n const str = CryptoJS.AES.encrypt(value, secret).toString();\n return str;\n } catch (err) {\n console.error(\"Error secure storage => encrypt :\", err);\n return null;\n }\n};\n\nexport const decrypt = (value: string) => {\n try {\n if (typeof value !== \"string\") {\n throw new Error(\"Value must be string\");\n }\n const str = CryptoJS.AES.decrypt(value, secret).toString(CryptoJS.enc.Utf8);\n return str;\n } catch (err) {\n console.error(\"Error secure storage => decrypt :\", err);\n return null;\n }\n};\n","export type Config = {\n /** @description The secret hash will be used for AES encryption */\n secret: string;\n /**\n * @description The prefix which will prepend on every key in the storage as `{prefix}.{key}`\n */\n prefix: string;\n};\n\nconst ENV =\n (typeof process === \"object\" &&\n process?.env &&\n typeof process.env === \"object\" &&\n process.env) ||\n null;\n\nexport const mainConfig: Config = {\n secret: ENV?.SECURE_STORAGE_SECRET || \"x1bQYQA4vSEcR6RQ05XtJg\",\n prefix: ENV?.SECURE_STORAGE_PREFIX || \"@secst\",\n};\n\nconst optionValidation = (\n value?: string,\n options?: Partial<{\n appendChecker: (value: string) => boolean;\n message: string;\n }>\n) => {\n if (typeof value === \"undefined\") {\n return;\n }\n if (\n typeof value !== \"string\" ||\n !value.trim() ||\n (typeof options?.appendChecker === \"function\" &&\n !options.appendChecker(value))\n ) {\n throw new Error(options?.message || \"Value must be a valid string\");\n }\n};\n\nexport const configure = (config?: Partial<Config>) => {\n try {\n if (config && typeof config === \"object\") {\n optionValidation(config.prefix, {\n message: \"Prefix must be a valid string\",\n });\n optionValidation(config.secret, {\n message: \"Secret must be a valid string\",\n });\n\n for (const key in config) {\n if (typeof config[key as keyof Config] !== \"undefined\") {\n mainConfig[key as keyof Config] = config[\n key as keyof Config\n ] as string;\n }\n }\n }\n } catch (err) {\n console.error(\"Error secure storage => update-configuration :\", err);\n }\n};\n","import { decrypt, encrypt } from \"./crypt\";\nimport { mainConfig } from \"./config\";\n\nvar window: Window & typeof globalThis;\n/**\n * @description ⚠️`Experimental`⚠️\n * @description Use this to change the global `window` object\n */\nexport const changeWindow = (newWindow: any) => {\n window = newWindow;\n};\n\nexport type SupportedTypes =\n | boolean\n | object\n | null\n | undefined\n | string\n | number\n | bigint;\nexport type SupportedTypesString =\n | \"boolean\"\n | \"number\"\n | \"bigint\"\n | \"string\"\n | \"object\"\n | \"undefined\";\n\nconst getPrefix = () => {\n try {\n const prefix = mainConfig.prefix;\n if (typeof prefix !== \"string\") {\n throw new Error(\"Invalid prefix, not a string\");\n }\n const str = `${prefix}`;\n return str;\n } catch (err) {\n console.error(\"Error secure storage => prefix :\", err);\n return null;\n }\n};\nconst prefix = getPrefix();\n\nexport const getModKey = (key: string) => {\n if (typeof prefix !== \"string\") {\n throw new Error(\"Prefix is invalid\");\n }\n if (typeof key !== \"string\") {\n throw new Error(\"Key must be string\");\n }\n const str = `${prefix}.${key}`;\n return str;\n};\n\ntype TemplateData = {\n data: SupportedTypes;\n type: SupportedTypesString;\n};\n\n/**\n * @description Returns string format of data passed or `null`\n * @description Modifies in the format of `{data, type}`\n */\nexport const modifyDataToString = (data: any) => {\n try {\n if (typeof data === \"function\" || typeof data === \"symbol\") {\n throw new Error(\"Data must not be a function or symbol\");\n }\n const template: TemplateData = {\n data: data,\n // @ts-ignore\n type: typeof data,\n };\n const str = JSON.stringify(template);\n return str;\n } catch (err) {\n console.error(\"Error secure storage => modify data :\", err);\n return null;\n }\n};\n\n/**\n * @description Returns data from of formatted string passed or `null`\n * @description Accepts data string in the format of `{data, type}`\n */\nexport const getDataFromModifiedString = (str: string) => {\n try {\n if (typeof str !== \"string\") {\n throw new Error(\"Value must be string\");\n }\n const template: TemplateData = JSON.parse(str);\n if (\n typeof template !== \"object\" ||\n !Object.getOwnPropertyNames(template).includes(\"data\") ||\n !Object.getOwnPropertyNames(template).includes(\"type\")\n ) {\n throw new Error(\"Invalid data scheme\");\n }\n const dataType = typeof template.data;\n template.type = dataType as SupportedTypesString;\n if (dataType === \"symbol\" || dataType === \"function\") {\n throw new Error(\n \"Invalid data type, does not supports function or symbol\"\n );\n }\n return template;\n } catch (err) {\n console.error(\"Error secure storage => get data :\", err);\n return null;\n }\n};\n\nconst storeTypes = [\"local\", \"session\"] as const;\nexport type StoreType = (typeof storeTypes)[number];\n\n/**\n * @description Validates store by checking any of `local` or `session`\n */\nconst validateStore = (store: StoreType) => {\n if (typeof store !== \"string\" || !storeTypes.includes(store)) {\n throw new Error(\"Store type must be one of [local, session]\");\n }\n if (\n typeof window !== \"object\" ||\n typeof window.localStorage !== \"object\" ||\n typeof window.sessionStorage !== \"object\"\n ) {\n throw new Error(\"Invalid window, please use only in browser\");\n }\n};\n\n/**\n * @description Validates store by checking any of `local` or `session`\n * @description Validates prefix as `string`\n * @description Validates key as `string`\n */\nconst preValidations = (prefix: string, key: string, store: StoreType) => {\n if (typeof prefix !== \"string\") {\n throw new Error(\"Prefix is invalid\");\n }\n if (typeof key !== \"string\") {\n throw new Error(\"Key must be string\");\n }\n validateStore(store);\n};\n\n/**\n * @description Syncronously removes matched values with matching `prefix`\n */\nconst matchedClear = (storage: Storage) => {\n try {\n const len = storage.length;\n for (let i = 0; i < len; i++) {\n const key = storage.key(i);\n if (key?.startsWith(`${prefix}.`)) {\n storage.removeItem(key);\n }\n }\n } catch (err) {\n console.error(\"Error secure storage => matched-clear :\", err);\n }\n};\n\nexport class Store<S extends StoreType> {\n private store: StoreType = \"local\" as S;\n private storage: Storage = window.localStorage;\n\n constructor(store?: S) {\n try {\n validateStore(store as StoreType);\n this.store = store as StoreType;\n if (store === \"local\") {\n this.storage = window.localStorage;\n }\n if (store === \"session\") {\n this.storage = window.sessionStorage;\n }\n } catch (err) {}\n }\n\n /**\n * @description Stores data to store matching `key`\n */\n setItem = (key: string, data: SupportedTypes) => {\n try {\n preValidations(prefix as string, key, this.store);\n\n const str = modifyDataToString(data);\n if (typeof str !== \"string\") {\n return;\n }\n const encrypted = encrypt(str);\n if (typeof encrypted !== \"string\") {\n return;\n }\n\n const modKey = `${prefix}.${key}`;\n this.storage.setItem(modKey, encrypted);\n } catch (err) {\n console.error(\"Error secure storage => setItem :\", err);\n }\n };\n\n /**\n * @description Gets data from store matching `key`\n */\n getItem = <T extends any = SupportedTypes>(key: string) => {\n try {\n preValidations(prefix as string, key, this.store);\n\n const modKey = `${prefix}.${key}`;\n let str: string | null = null;\n str = this.storage.getItem(modKey);\n\n const decrypted = decrypt(str as string);\n if (typeof decrypted !== \"string\") {\n return null;\n }\n\n const template = getDataFromModifiedString(decrypted);\n if (!template) {\n return null;\n }\n\n const data = template.data as T;\n return data;\n } catch (err) {\n console.error(\"Error secure storage => setItem :\", err);\n return null;\n }\n };\n\n /**\n * @description Removes single item from store matching `key`\n */\n removeItem = (key: string) => {\n try {\n preValidations(prefix as string, key, this.store);\n\n const modKey = `${prefix}.${key}`;\n this.storage.removeItem(modKey);\n } catch (err) {\n console.error(\"Error secure storage => removeItem :\", err);\n }\n };\n\n /**\n * @description Syncronously removes matched values with matching `prefix`\n */\n clear = () => {\n try {\n preValidations(prefix as string, \"\", this.store);\n matchedClear(this.storage);\n } catch (err) {\n console.error(\"Error secure storage => clear :\", err);\n }\n };\n\n /**\n * @description Executes `storage.clear()` to clear complete store\n */\n forceClear = () => {\n try {\n preValidations(prefix as string, \"\", this.store);\n this.storage.clear();\n } catch (err) {\n console.error(\"Error secure storage => force-clear :\", err);\n }\n };\n}\n"],"mappings":"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","names":["index_exports","__export","configure","localStorage","sessionStorage","__toCommonJS","ENV","import_crypto_js","ENV","mainConfig","optionValidation","value","options","configure","config","key","err","secret","mainConfig","encrypt","value","CryptoJS","err","decrypt","window","changeWindow","newWindow","getPrefix","prefix","mainConfig","err","modifyDataToString","data","err","getDataFromModifiedString","str","template","dataType","storeTypes","validateStore","store","window","preValidations","prefix","key","matchedClear","storage","len","i","Store","encrypted","encrypt","modKey","decrypted","decrypt","changeWindow","localStorage","Store","sessionStorage"]}