Commit 234c1d1fae6a7f2c78e456f992f91622ca599060
1 parent
3a132f3f
feat: the cache can be configured to be encrypted
Showing
18 changed files
with
225 additions
and
110 deletions
CHANGELOG.zh_CN.md
package.json
... | ... | @@ -37,16 +37,16 @@ |
37 | 37 | "vditor": "^3.6.3", |
38 | 38 | "vue": "^3.0.2", |
39 | 39 | "vue-i18n": "^9.0.0-beta.8", |
40 | - "vue-router": "^4.0.0-rc.3", | |
40 | + "vue-router": "^4.0.0-rc.5", | |
41 | 41 | "vuex": "^4.0.0-rc.1", |
42 | 42 | "vuex-module-decorators": "^1.0.1", |
43 | - "xlsx": "^0.16.8", | |
43 | + "xlsx": "^0.16.9", | |
44 | 44 | "zxcvbn": "^4.4.2" |
45 | 45 | }, |
46 | 46 | "devDependencies": { |
47 | 47 | "@commitlint/cli": "^11.0.0", |
48 | 48 | "@commitlint/config-conventional": "^11.0.0", |
49 | - "@iconify/json": "^1.1.261", | |
49 | + "@iconify/json": "^1.1.262", | |
50 | 50 | "@ls-lint/ls-lint": "^1.9.2", |
51 | 51 | "@purge-icons/generated": "^0.4.1", |
52 | 52 | "@types/echarts": "^4.9.1", |
... | ... | @@ -72,7 +72,7 @@ |
72 | 72 | "cross-env": "^7.0.2", |
73 | 73 | "dot-prop": "^6.0.1", |
74 | 74 | "dotenv": "^8.2.0", |
75 | - "eslint": "^7.13.0", | |
75 | + "eslint": "^7.14.0", | |
76 | 76 | "eslint-config-prettier": "^6.15.0", |
77 | 77 | "eslint-plugin-prettier": "^3.1.4", |
78 | 78 | "eslint-plugin-vue": "^7.1.0", | ... | ... |
src/components/Application/index.ts
1 | 1 | import AppLocalPicker from './src/AppLocalPicker.vue'; |
2 | +import AppFooterToolbar from './src/AppFooterToolbar.vue'; | |
3 | +import { withInstall } from '../util'; | |
2 | 4 | |
3 | -export { AppLocalPicker }; | |
5 | +export { AppLocalPicker, AppFooterToolbar }; | |
6 | + | |
7 | +export default withInstall(AppLocalPicker, AppFooterToolbar); | ... | ... |
src/components/Footer/src/index.vue renamed to src/components/Application/src/AppFooterToolbar.vue
... | ... | @@ -10,11 +10,14 @@ |
10 | 10 | </template> |
11 | 11 | <script lang="ts"> |
12 | 12 | import { defineComponent, computed, unref } from 'vue'; |
13 | + | |
13 | 14 | import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum'; |
15 | + | |
14 | 16 | import { appStore } from '/@/store/modules/app'; |
15 | 17 | import { menuStore } from '/@/store/modules/menu'; |
18 | + | |
16 | 19 | export default defineComponent({ |
17 | - name: 'AppFooter', | |
20 | + name: 'AppFooterToolbar', | |
18 | 21 | setup() { |
19 | 22 | const getMiniWidth = computed(() => { |
20 | 23 | const { | ... | ... |
src/components/Authority/index.ts
1 | -import type { App } from 'vue'; | |
2 | 1 | import Authority from './src/index.vue'; |
3 | 2 | |
4 | -export default (app: App): void => { | |
5 | - app.component(Authority.name, Authority); | |
6 | -}; | |
3 | +import { withInstall } from '../util'; | |
4 | + | |
5 | +export default withInstall(Authority); | |
7 | 6 | |
8 | 7 | export { Authority }; | ... | ... |
src/components/Footer/index.ts deleted
100644 → 0
1 | -export { default as AppFooter } from './src/index.vue'; |
src/components/registerGlobComp.ts
1 | 1 | import Icon from './Icon/index'; |
2 | 2 | import Button from './Button/index.vue'; |
3 | -import { AppFooter } from './Footer'; | |
4 | 3 | import { |
5 | 4 | // Need |
6 | 5 | Button as AntButton, |
... | ... | @@ -35,7 +34,7 @@ import { |
35 | 34 | } from 'ant-design-vue'; |
36 | 35 | import { getApp } from '/@/setup/App'; |
37 | 36 | |
38 | -const compList = [Icon, Button, AntButton.Group, AppFooter]; | |
37 | +const compList = [Icon, Button, AntButton.Group]; | |
39 | 38 | |
40 | 39 | // Fix hmr multiple registered components |
41 | 40 | let registered = false; | ... | ... |
src/components/util.ts
1 | 1 | import type { VNodeChild } from 'vue'; |
2 | +import type { App, Component } from 'vue'; | |
3 | + | |
4 | +export function withInstall(...components: Component[]) { | |
5 | + return (app: App) => { | |
6 | + components.forEach((comp) => { | |
7 | + comp.name && app.component(comp.name, comp); | |
8 | + }); | |
9 | + }; | |
10 | +} | |
2 | 11 | |
3 | 12 | export function convertToUnit( |
4 | 13 | str: string | number | null | undefined, | ... | ... |
src/settings/cipherSetting.ts renamed to src/settings/encryptionSetting.ts
1 | +import { isDevMode } from '/@/utils/env'; | |
2 | + | |
1 | 3 | // System default cache time, in seconds |
2 | 4 | export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7; |
3 | 5 | |
4 | -/** | |
5 | - * @description: | |
6 | - */ | |
7 | -export const storageCipher = { | |
6 | +// aes encryption key | |
7 | +export const cacheCipher = { | |
8 | 8 | key: '_12345678901234@', |
9 | 9 | iv: '@12345678901234_', |
10 | 10 | }; |
11 | + | |
12 | +// Whether the system cache is encrypted using aes | |
13 | +export const enableStorageEncryption = !isDevMode(); | ... | ... |
src/utils/cache/cookie.ts
0 → 100644
1 | +import { DEFAULT_CACHE_TIME } from '../../settings/encryptionSetting'; | |
2 | +import { getStorageShortName } from '/@/utils/helper/envHelper'; | |
3 | +import { cacheCipher } from '/@/settings/encryptionSetting'; | |
4 | +import Encryption from '/@/utils/encryption/aesEncryption'; | |
5 | + | |
6 | +export default class WebCookie { | |
7 | + private encryption: Encryption; | |
8 | + private hasEncrypt: boolean; | |
9 | + | |
10 | + constructor(hasEncrypt = true, key = cacheCipher.key, iv = cacheCipher.iv) { | |
11 | + const encryption = new Encryption({ key, iv }); | |
12 | + this.encryption = encryption; | |
13 | + this.hasEncrypt = hasEncrypt; | |
14 | + } | |
15 | + | |
16 | + private getKey(key: string) { | |
17 | + return `${getStorageShortName()}${key}`.toUpperCase(); | |
18 | + } | |
19 | + | |
20 | + /** | |
21 | + * Add cookie | |
22 | + * @param name cookie key | |
23 | + * @param value cookie value | |
24 | + * @param expire | |
25 | + * If the expiration time is not set, the default management browser will automatically delete | |
26 | + * e.g: | |
27 | + * cookieData.set('name','value',) | |
28 | + */ | |
29 | + setCookie(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) { | |
30 | + value = this.hasEncrypt ? this.encryption.encryptByAES(JSON.stringify(value)) : value; | |
31 | + document.cookie = this.getKey(key) + '=' + value + '; Max-Age=' + expire; | |
32 | + } | |
33 | + | |
34 | + /** | |
35 | + * Get the cook value according to the key | |
36 | + * @param key cookie key | |
37 | + */ | |
38 | + getCookie(key: string) { | |
39 | + const arr = document.cookie.split('; '); | |
40 | + for (let i = 0; i < arr.length; i++) { | |
41 | + const arr2 = arr[i].split('='); | |
42 | + if (arr2[0] === this.getKey(key)) { | |
43 | + let message: any = null; | |
44 | + const str = arr2[1]; | |
45 | + if (this.hasEncrypt && str) { | |
46 | + message = this.encryption.decryptByAES(str); | |
47 | + try { | |
48 | + return JSON.parse(message); | |
49 | + } catch (e) { | |
50 | + return str; | |
51 | + } | |
52 | + } | |
53 | + return str; | |
54 | + } | |
55 | + } | |
56 | + return ''; | |
57 | + } | |
58 | + | |
59 | + /** | |
60 | + * Delete cookie based on cookie key | |
61 | + * @param key cookie key | |
62 | + */ | |
63 | + removeCookie(key: string) { | |
64 | + this.setCookie(key, 1, -1); | |
65 | + } | |
66 | + | |
67 | + /** | |
68 | + * clear cookie | |
69 | + */ | |
70 | + clearCookie(): void { | |
71 | + const keys = document.cookie.match(/[^ =;]+(?==)/g); | |
72 | + if (keys) { | |
73 | + for (let i = keys.length; i--; ) { | |
74 | + document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString(); | |
75 | + } | |
76 | + } | |
77 | + } | |
78 | +} | ... | ... |
src/utils/storage/index.ts renamed to src/utils/cache/index.ts
1 | 1 | import { getStorageShortName } from '/@/utils/helper/envHelper'; |
2 | -import { createStorage as create } from './Storage'; | |
3 | - | |
4 | -// debug模式下不加密 | |
2 | +import { createStorage as create } from './storageCache'; | |
3 | +import { enableStorageEncryption } from '/@/settings/encryptionSetting'; | |
5 | 4 | |
6 | 5 | const createOptions = (storage = sessionStorage) => { |
7 | 6 | return { |
7 | + // No encryption in debug mode | |
8 | + hasEncrypt: enableStorageEncryption, | |
8 | 9 | storage, |
9 | 10 | prefixKey: getStorageShortName(), |
10 | 11 | }; |
11 | 12 | }; |
13 | + | |
12 | 14 | export const WebStorage = create(createOptions()); |
13 | 15 | |
14 | 16 | export const createStorage = (storage: Storage = sessionStorage) => { |
15 | 17 | return create(createOptions(storage))!; |
16 | 18 | }; |
19 | + | |
17 | 20 | export default WebStorage; | ... | ... |
src/utils/storage/Storage.ts renamed to src/utils/cache/storageCache.ts
1 | -import { DEFAULT_CACHE_TIME } from '/@/settings/cipherSetting'; | |
1 | +import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting'; | |
2 | +import { cacheCipher } from '/@/settings/encryptionSetting'; | |
3 | +import Encryption, { EncryptionParams } from '/@/utils/encryption/aesEncryption'; | |
2 | 4 | |
3 | -// import { EncryptionParams } from '/@/utils/cipher/aesEncryption'; | |
4 | -export interface CreateStorageParams { | |
5 | +export interface CreateStorageParams extends EncryptionParams { | |
5 | 6 | storage: Storage; |
7 | + | |
6 | 8 | hasEncrypt: boolean; |
7 | 9 | } |
8 | -export const createStorage = ({ prefixKey = '', storage = sessionStorage } = {}) => { | |
10 | +export const createStorage = ({ | |
11 | + prefixKey = '', | |
12 | + storage = sessionStorage, | |
13 | + key = cacheCipher.key, | |
14 | + iv = cacheCipher.iv, | |
15 | + hasEncrypt = true, | |
16 | +} = {}) => { | |
17 | + if (hasEncrypt && [key.length, iv.length].some((item) => item !== 16)) { | |
18 | + throw new Error('When hasEncrypt is true, the key or iv must be 16 bits!'); | |
19 | + } | |
20 | + | |
21 | + const encryption = new Encryption({ key, iv }); | |
22 | + | |
9 | 23 | /** |
10 | - *缓存类 | |
11 | - *构造参数可以传入 sessionStorage,localStorage, | |
24 | + *Cache class | |
25 | + *Construction parameters can be passed into sessionStorage, localStorage, | |
12 | 26 | * @class Cache |
13 | 27 | * @example |
14 | 28 | */ |
15 | 29 | const WebStorage = class WebStorage { |
16 | 30 | private storage: Storage; |
17 | 31 | private prefixKey?: string; |
18 | - | |
32 | + private encryption: Encryption; | |
33 | + private hasEncrypt: boolean; | |
19 | 34 | /** |
20 | 35 | * |
21 | 36 | * @param {*} storage |
... | ... | @@ -23,6 +38,8 @@ export const createStorage = ({ prefixKey = '', storage = sessionStorage } = {}) |
23 | 38 | constructor() { |
24 | 39 | this.storage = storage; |
25 | 40 | this.prefixKey = prefixKey; |
41 | + this.encryption = encryption; | |
42 | + this.hasEncrypt = hasEncrypt; | |
26 | 43 | } |
27 | 44 | |
28 | 45 | private getKey(key: string) { |
... | ... | @@ -31,10 +48,10 @@ export const createStorage = ({ prefixKey = '', storage = sessionStorage } = {}) |
31 | 48 | |
32 | 49 | /** |
33 | 50 | * |
34 | - * 设置缓存 | |
35 | - * @param {string} key 缓存键 | |
36 | - * @param {*} value 缓存值 | |
37 | - * @expire 过期时间 单位秒 | |
51 | + * Set cache | |
52 | + * @param {string} key | |
53 | + * @param {*} value | |
54 | + * @expire Expiration time in seconds | |
38 | 55 | * @memberof Cache |
39 | 56 | */ |
40 | 57 | set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) { |
... | ... | @@ -42,21 +59,23 @@ export const createStorage = ({ prefixKey = '', storage = sessionStorage } = {}) |
42 | 59 | value, |
43 | 60 | expire: expire !== null ? new Date().getTime() + expire * 1000 : null, |
44 | 61 | }); |
45 | - this.storage.setItem(this.getKey(key), stringData); | |
62 | + const stringifyValue = this.hasEncrypt | |
63 | + ? this.encryption.encryptByAES(stringData) | |
64 | + : stringData; | |
65 | + this.storage.setItem(this.getKey(key), stringifyValue); | |
46 | 66 | } |
47 | 67 | |
48 | 68 | /** |
49 | - * | |
50 | - *读取缓存 | |
51 | - * @param {string} key 缓存键 | |
52 | - * @returns 缓存值 | |
69 | + *Read cache | |
70 | + * @param {string} key | |
53 | 71 | * @memberof Cache |
54 | 72 | */ |
55 | 73 | get(key: string, def: any = null): any { |
56 | 74 | const item = this.storage.getItem(this.getKey(key)); |
57 | 75 | if (item) { |
58 | 76 | try { |
59 | - const data = JSON.parse(item); | |
77 | + const decItem = this.hasEncrypt ? this.encryption.decryptByAES(item) : item; | |
78 | + const data = JSON.parse(decItem); | |
60 | 79 | const { value, expire } = data; |
61 | 80 | if (expire === null || expire >= new Date().getTime()) { |
62 | 81 | return value; |
... | ... | @@ -70,9 +89,8 @@ export const createStorage = ({ prefixKey = '', storage = sessionStorage } = {}) |
70 | 89 | } |
71 | 90 | |
72 | 91 | /** |
73 | - * | |
74 | - *删除缓存 | |
75 | - * @param {string} key 缓存键 | |
92 | + * Delete cache based on key | |
93 | + * @param {string} key | |
76 | 94 | * @memberof Cache |
77 | 95 | */ |
78 | 96 | remove(key: string) { |
... | ... | @@ -80,59 +98,11 @@ export const createStorage = ({ prefixKey = '', storage = sessionStorage } = {}) |
80 | 98 | } |
81 | 99 | |
82 | 100 | /** |
83 | - * | |
84 | - *删除该实例所有缓存 | |
85 | - * @memberof Cache | |
101 | + * Delete all caches of this instance | |
86 | 102 | */ |
87 | 103 | clear(): void { |
88 | 104 | this.storage.clear(); |
89 | 105 | } |
90 | - | |
91 | - /** | |
92 | - * 添加cookie | |
93 | - * @param name cookie名字 | |
94 | - * @param value cookie内容 | |
95 | - * @param expire | |
96 | - * 如果过期时间未设置,默认管理浏览器自动删除 | |
97 | - * 例子: | |
98 | - * cookieData.set('name','value',) | |
99 | - */ | |
100 | - setCookie(name: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) { | |
101 | - document.cookie = this.getKey(name) + '=' + value + '; Max-Age=' + expire; | |
102 | - } | |
103 | - | |
104 | - /** | |
105 | - * 根据名字获取cooki值 | |
106 | - * @param name cookie名 | |
107 | - * @returns {*} cookie值 | |
108 | - */ | |
109 | - getCookie(name: string) { | |
110 | - const arr = document.cookie.split('; '); | |
111 | - for (let i = 0; i < arr.length; i++) { | |
112 | - const arr2 = arr[i].split('='); | |
113 | - if (arr2[0] === this.getKey(name)) { | |
114 | - return arr2[1]; | |
115 | - } | |
116 | - } | |
117 | - return ''; | |
118 | - } | |
119 | - | |
120 | - /** | |
121 | - * 根据cookie名字删除cookie | |
122 | - * @param name cookie名字 | |
123 | - */ | |
124 | - removeCookie(key: string) { | |
125 | - this.setCookie(key, 1, -1); | |
126 | - } | |
127 | - | |
128 | - clearCookie(): void { | |
129 | - const keys = document.cookie.match(/[^ =;]+(?==)/g); | |
130 | - if (keys) { | |
131 | - for (let i = keys.length; i--; ) { | |
132 | - document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString(); | |
133 | - } | |
134 | - } | |
135 | - } | |
136 | 106 | }; |
137 | 107 | return new WebStorage(); |
138 | 108 | }; | ... | ... |
src/utils/encryption/aesEncryption.ts
0 → 100644
1 | +import CryptoES from 'crypto-es'; | |
2 | +export interface EncryptionParams { | |
3 | + key: string; | |
4 | + iv: string; | |
5 | +} | |
6 | +export class Encryption { | |
7 | + private key; | |
8 | + | |
9 | + private iv; | |
10 | + | |
11 | + constructor(opt: EncryptionParams) { | |
12 | + const { key, iv } = opt; | |
13 | + this.key = CryptoES.enc.Utf8.parse(key); | |
14 | + this.iv = CryptoES.enc.Utf8.parse(iv); | |
15 | + } | |
16 | + | |
17 | + get getOpt(): CryptoES.lib.CipherCfg { | |
18 | + return { | |
19 | + mode: CryptoES.mode.CBC as any, | |
20 | + padding: CryptoES.pad.Pkcs7, | |
21 | + iv: this.iv, | |
22 | + }; | |
23 | + } | |
24 | + | |
25 | + encryptByAES(str: string) { | |
26 | + const encrypted = CryptoES.AES.encrypt(str, this.key, this.getOpt); | |
27 | + return encrypted.toString(); | |
28 | + } | |
29 | + | |
30 | + decryptByAES(str: string) { | |
31 | + const decrypted = CryptoES.AES.decrypt(str, this.key, this.getOpt); | |
32 | + return decrypted.toString(CryptoES.enc.Utf8); | |
33 | + } | |
34 | +} | |
35 | +export default Encryption; | ... | ... |
src/utils/file/base64.ts renamed to src/utils/file/base64Conver.ts
src/utils/file/download.ts
src/utils/helper/persistent.ts
src/views/demo/page/form/high/index.vue
... | ... | @@ -16,21 +16,23 @@ |
16 | 16 | </a-card> |
17 | 17 | </div> |
18 | 18 | |
19 | - <app-footer> | |
19 | + <AppFooterToolbar> | |
20 | 20 | <template #right> |
21 | 21 | <a-button type="primary" @click="submitAll">提交</a-button> |
22 | 22 | </template> |
23 | - </app-footer> | |
23 | + </AppFooterToolbar> | |
24 | 24 | </div> |
25 | 25 | </template> |
26 | 26 | <script lang="ts"> |
27 | 27 | import { BasicForm, useForm } from '/@/components/Form'; |
28 | 28 | import { defineComponent, ref } from 'vue'; |
29 | 29 | import PersonTable from './PersonTable.vue'; |
30 | + import { AppFooterToolbar } from '/@/components/Application'; | |
31 | + | |
30 | 32 | import { schemas, taskSchemas } from './data'; |
31 | 33 | |
32 | 34 | export default defineComponent({ |
33 | - components: { BasicForm, PersonTable }, | |
35 | + components: { BasicForm, PersonTable, AppFooterToolbar }, | |
34 | 36 | setup() { |
35 | 37 | const tableRef = ref<{ getDataSource: () => any } | null>(null); |
36 | 38 | ... | ... |
yarn.lock
... | ... | @@ -1050,10 +1050,10 @@ |
1050 | 1050 | resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.2.tgz#c4a95ddc06ca9b9496df03604e66fdefb39f4c4b" |
1051 | 1051 | integrity sha512-BybEHU5/I9EQ0CcwKAqmreZ2bMnAXrqLCTptAc6vPetHMbrXdZfejP5mt57e/8PNSt/qE7BHniU5PCYA+PGIHw== |
1052 | 1052 | |
1053 | -"@iconify/json@^1.1.261": | |
1054 | - version "1.1.261" | |
1055 | - resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.261.tgz#9a6986b6b36d77ca147c4be149db9a43280a8fb2" | |
1056 | - integrity sha512-lnRk1OBqNxZ593oZyOXEMp/O+cr+lF54xaW6+F3krWdWhzxQgi0W1ffzvdiLySdbTEorQ2NvVU4e0+Af27rXPA== | |
1053 | +"@iconify/json@^1.1.262": | |
1054 | + version "1.1.262" | |
1055 | + resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.262.tgz#a67067bad418d59c729ec514e3aa629d0ab3710b" | |
1056 | + integrity sha512-PfKUS/Ue9Rn2oO0ez/Yj4Cdodvv6vDHgPjIZNSElu2+149CYaPmWahHI87ZY+r8l3bijPIu6+blyAixdJtPPMg== | |
1057 | 1057 | |
1058 | 1058 | "@koa/cors@^3.1.0": |
1059 | 1059 | version "3.1.0" |
... | ... | @@ -3418,10 +3418,10 @@ eslint-visitor-keys@^2.0.0: |
3418 | 3418 | resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" |
3419 | 3419 | integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== |
3420 | 3420 | |
3421 | -eslint@^7.13.0: | |
3422 | - version "7.13.0" | |
3423 | - resolved "https://registry.npmjs.org/eslint/-/eslint-7.13.0.tgz#7f180126c0dcdef327bfb54b211d7802decc08da" | |
3424 | - integrity sha512-uCORMuOO8tUzJmsdRtrvcGq5qposf7Rw0LwkTJkoDbOycVQtQjmnhZSuLQnozLE4TmAzlMVV45eCHmQ1OpDKUQ== | |
3421 | +eslint@^7.14.0: | |
3422 | + version "7.14.0" | |
3423 | + resolved "https://registry.npmjs.org/eslint/-/eslint-7.14.0.tgz#2d2cac1d28174c510a97b377f122a5507958e344" | |
3424 | + integrity sha512-5YubdnPXrlrYAFCKybPuHIAH++PINe1pmKNc5wQRB9HSbqIK1ywAnntE3Wwua4giKu0bjligf1gLF6qxMGOYRA== | |
3425 | 3425 | dependencies: |
3426 | 3426 | "@babel/code-frame" "^7.0.0" |
3427 | 3427 | "@eslint/eslintrc" "^0.2.1" |
... | ... | @@ -3686,6 +3686,11 @@ fastq@^1.6.0: |
3686 | 3686 | dependencies: |
3687 | 3687 | reusify "^1.0.4" |
3688 | 3688 | |
3689 | +fflate@^0.3.8: | |
3690 | + version "0.3.10" | |
3691 | + resolved "https://registry.npmjs.org/fflate/-/fflate-0.3.10.tgz#0e581839a53203d2eeac7e61ce3652d855e24dcd" | |
3692 | + integrity sha512-s5j69APkUPPbzdI20Ix4pPtQP+1Qi58YcFRpE7aO/P1kEywUYjbl2RjZRVEMdnySO9pr4MB0BHPbxkiahrtD/Q== | |
3693 | + | |
3689 | 3694 | figures@^2.0.0: |
3690 | 3695 | version "2.0.0" |
3691 | 3696 | resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" |
... | ... | @@ -8196,10 +8201,10 @@ vue-i18n@^9.0.0-beta.8: |
8196 | 8201 | dependencies: |
8197 | 8202 | source-map "0.6.1" |
8198 | 8203 | |
8199 | -vue-router@^4.0.0-rc.3: | |
8200 | - version "4.0.0-rc.3" | |
8201 | - resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.0-rc.3.tgz#70d18e90030bc6a25e81a30401d673223998ec6b" | |
8202 | - integrity sha512-NnPqWIfanEhJC4wu8BEFBmnEDIrx9ST0/HtmBiE+oV2MQlhyRk1TmdttWwVqx6Sh7kONsrI10GQV9l3YEkcWXg== | |
8204 | +vue-router@^4.0.0-rc.5: | |
8205 | + version "4.0.0-rc.5" | |
8206 | + resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.0-rc.5.tgz#191d32e3d5276641ff21e881d34e33a71dc6e8f0" | |
8207 | + integrity sha512-Q8Tt6VGwGMN5qASeIdjSydU3uRADK9AUkqnbnzmTz+zZKS0W6GZOAuP235lf3y5/MqEFSKRJGaTWPEY0t+Rjmg== | |
8203 | 8208 | |
8204 | 8209 | vue-types@^3.0.0: |
8205 | 8210 | version "3.0.1" |
... | ... | @@ -8480,10 +8485,10 @@ ws@^7.3.1: |
8480 | 8485 | resolved "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz#a5dd76a24197940d4a8bb9e0e152bb4503764da7" |
8481 | 8486 | integrity sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ== |
8482 | 8487 | |
8483 | -xlsx@^0.16.8: | |
8484 | - version "0.16.8" | |
8485 | - resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.16.8.tgz#5546de9b0ba15169b36770d4e43b24790d3ff1b8" | |
8486 | - integrity sha512-qWub4YCn0xLEGHI7WWhk6IJ73MDu7sPSJQImxN6/LiI8wsHi0hUhICEDbyqBT+jgFgORZxrii0HvhNSwBNAPoQ== | |
8488 | +xlsx@^0.16.9: | |
8489 | + version "0.16.9" | |
8490 | + resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.16.9.tgz#dacd5bb46bda6dd3743940c9c3dc1e2171826256" | |
8491 | + integrity sha512-gxi1I3EasYvgCX1vN9pGyq920Ron4NO8PNfhuoA3Hpq6Y8f0ECXiy4OLrK4QZBnj1jx3QD+8Fq5YZ/3mPZ5iXw== | |
8487 | 8492 | dependencies: |
8488 | 8493 | adler-32 "~1.2.0" |
8489 | 8494 | cfb "^1.1.4" |
... | ... | @@ -8491,6 +8496,7 @@ xlsx@^0.16.8: |
8491 | 8496 | commander "~2.17.1" |
8492 | 8497 | crc-32 "~1.2.0" |
8493 | 8498 | exit-on-epipe "~1.0.1" |
8499 | + fflate "^0.3.8" | |
8494 | 8500 | ssf "~0.11.2" |
8495 | 8501 | wmf "~1.0.1" |
8496 | 8502 | word "~0.3.0" | ... | ... |