index.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import globalConfig from '@/config';
  2. import {
  3. stringMd5,
  4. aesCbcEncryptString,
  5. aesCbcDecryptString,
  6. rabbitEncryptString,
  7. rabbitDecryptString,
  8. } from '@/utils/crypto';
  9. const storageKeyIV = stringMd5(`${globalConfig.app.title}_${globalConfig.app.version}`).slice(0, 8);
  10. export function encryptKey(key: string) {
  11. return rabbitEncryptString(key, globalConfig.security.storageEncryptionKey, storageKeyIV);
  12. }
  13. export function decryptKey(key: string) {
  14. return rabbitDecryptString(key, globalConfig.security.storageEncryptionKey, storageKeyIV);
  15. }
  16. export function encryptData(data: string) {
  17. return aesCbcEncryptString(data, globalConfig.security.storageEncryptionKey);
  18. }
  19. export function decryptData(data: string) {
  20. return aesCbcDecryptString(data, globalConfig.security.storageEncryptionKey);
  21. }
  22. export interface StorageOptions {
  23. /**
  24. * 过期时间(秒), 0 为永远不过期
  25. * @default 0
  26. */
  27. expire?: number;
  28. /**
  29. * 是否加密key
  30. * @default false
  31. */
  32. encryptKey?: boolean;
  33. /**
  34. * 是否加密数据
  35. * @default false
  36. */
  37. encryptData?: boolean;
  38. }
  39. interface StorageData<T = any> {
  40. data: T;
  41. expire: number;
  42. }
  43. function shouldEncryptKey(functionOptions?: StorageOptions, instanceOptions?: StorageOptions) {
  44. if (globalConfig.security.enableStorageEncryption) {
  45. return functionOptions?.encryptKey ?? instanceOptions?.encryptKey ?? false;
  46. }
  47. return false;
  48. }
  49. function shouldEncryptData(funcOpts?: StorageOptions, instanceOpts?: StorageOptions) {
  50. if (globalConfig.security.enableStorageEncryption) {
  51. return funcOpts?.encryptData ?? instanceOpts?.encryptData ?? false;
  52. }
  53. return false;
  54. }
  55. /**
  56. * 创建 localStorage 工具实例
  57. * @param opts {StorageOptions} 本实例使用的全局配置
  58. * @returns
  59. */
  60. export function createLocalStorage({
  61. expire: confExpire = 0,
  62. encryptKey: confEncryptKey = false,
  63. encryptData: confEncryptData = false,
  64. }: StorageOptions = {}) {
  65. /**
  66. * 保存数据
  67. * @param key
  68. * @param data
  69. * @param opts 当传递了 opts 时,opts 中存在的配置项会覆盖当前实例的全局配置中的配置项。
  70. */
  71. function set<T = any>(key: string, data: T, opts?: StorageOptions) {
  72. const expire = opts?.expire ?? confExpire;
  73. const isEncryptKey = shouldEncryptKey(opts, { encryptKey: confEncryptKey });
  74. const isEncryptData = shouldEncryptData(opts, { encryptData: confEncryptData });
  75. const storageData: StorageData<T> = {
  76. data,
  77. expire: expire !== 0 ? new Date().getTime() + expire * 1000 : 0,
  78. };
  79. const json = JSON.stringify(storageData);
  80. const finalKey = isEncryptKey ? encryptKey(key) : key;
  81. const finalData = isEncryptData ? encryptData(json) : json;
  82. window.localStorage.setItem(finalKey, finalData);
  83. }
  84. /**
  85. * 读取数据
  86. * @param key
  87. * @param opts 当传递了 opts 时,opts 中存在的配置项会覆盖当前实例的全局配置中的配置项。
  88. * @returns
  89. */
  90. function get<T = any>(key: string, opts?: StorageOptions) {
  91. const isEncryptKey = shouldEncryptKey(opts, { encryptKey: confEncryptKey });
  92. const isEncryptData = shouldEncryptData(opts, { encryptData: confEncryptData });
  93. const finalKey = isEncryptKey ? encryptKey(key) : key;
  94. let data = window.localStorage.getItem(finalKey);
  95. if (!data) return null;
  96. if (isEncryptData) {
  97. data = decryptData(data);
  98. }
  99. if (!data) return null;
  100. let storageData: StorageData | null = null;
  101. try {
  102. storageData = JSON.parse(data);
  103. } catch {
  104. // Prevent failure
  105. }
  106. if (storageData) {
  107. const { data, expire = 0 } = storageData;
  108. if (expire === 0 || expire >= Date.now()) return data as T;
  109. }
  110. return null;
  111. }
  112. /**
  113. * 删除数据
  114. * @param key
  115. * @param opts 当传递了 opts 时,opts 中存在的配置项会覆盖当前实例的全局配置中的配置项。
  116. */
  117. function remove(key: string, opts?: StorageOptions) {
  118. const isEncryptKey = shouldEncryptKey(opts, { encryptKey: confEncryptKey });
  119. const finalKey = isEncryptKey ? encryptKey(key) : key;
  120. window.localStorage.removeItem(finalKey);
  121. }
  122. /**
  123. * 清除 localStorage 中的所有数据。**慎用**
  124. */
  125. function clear() {
  126. window.localStorage.clear();
  127. }
  128. return { set, get, remove, clear };
  129. }
  130. /**
  131. * 创建 sessionStorage 工具实例
  132. * @param opts {StorageOptions} 本实例使用的全局配置
  133. * @returns
  134. */
  135. export function createSessionStorage({
  136. expire: confExpire = 0,
  137. encryptKey: confEncryptKey = false,
  138. encryptData: confEncryptData = false,
  139. }: StorageOptions = {}) {
  140. /**
  141. * 保存数据
  142. * @param key
  143. * @param data
  144. * @param opts 当传递了 opts 时,opts 中存在的配置项会覆盖当前实例的全局配置中的配置项。
  145. */
  146. function set<T = any>(key: string, data: T, opts?: StorageOptions) {
  147. const expire = opts?.expire ?? confExpire;
  148. const isEncryptKey = shouldEncryptKey(opts, { encryptKey: confEncryptKey });
  149. const isEncryptData = shouldEncryptData(opts, { encryptData: confEncryptData });
  150. const storageData: StorageData<T> = {
  151. data,
  152. expire: expire !== 0 ? new Date().getTime() + expire * 1000 : 0,
  153. };
  154. const json = JSON.stringify(storageData);
  155. const finalKey = isEncryptKey ? encryptKey(key) : key;
  156. const finalData = isEncryptData ? encryptData(json) : json;
  157. window.sessionStorage.setItem(finalKey, finalData);
  158. }
  159. /**
  160. * 读取数据
  161. * @param key
  162. * @param opts 当传递了 opts 时,opts 中存在的配置项会覆盖当前实例的全局配置中的配置项。
  163. * @returns
  164. */
  165. function get<T = any>(key: string, opts?: StorageOptions) {
  166. const isEncryptKey = shouldEncryptKey(opts, { encryptKey: confEncryptKey });
  167. const isEncryptData = shouldEncryptData(opts, { encryptData: confEncryptData });
  168. const finalKey = isEncryptKey ? encryptKey(key) : key;
  169. let data = window.sessionStorage.getItem(finalKey);
  170. if (!data) return null;
  171. if (isEncryptData) {
  172. data = decryptData(data);
  173. }
  174. if (!data) return null;
  175. let storageData: StorageData | null = null;
  176. try {
  177. storageData = JSON.parse(data);
  178. } catch {
  179. // Prevent failure
  180. }
  181. if (storageData) {
  182. const { data, expire = 0 } = storageData;
  183. if (expire === 0 || expire >= Date.now()) return data as T;
  184. }
  185. return null;
  186. }
  187. /**
  188. * 删除数据
  189. * @param key
  190. * @param opts 当传递了 opts 时,opts 中存在的配置项会覆盖当前实例的全局配置中的配置项。
  191. */
  192. function remove(key: string, opts?: StorageOptions) {
  193. const isEncryptKey = shouldEncryptKey(opts, { encryptKey: confEncryptKey });
  194. const finalKey = isEncryptKey ? encryptKey(key) : key;
  195. window.sessionStorage.removeItem(finalKey);
  196. }
  197. /**
  198. * 清除 sessionStorage 中的所有数据。**慎用**
  199. */
  200. function clear() {
  201. window.sessionStorage.clear();
  202. }
  203. return { set, get, remove, clear };
  204. }
  205. export const ls = createLocalStorage({
  206. expire: 60 * 60 * 24 * 7,
  207. encryptKey: true,
  208. encryptData: true,
  209. });
  210. export const ss = createSessionStorage({
  211. expire: 60 * 60 * 24 * 7,
  212. encryptKey: true,
  213. encryptData: true,
  214. });