renusify 3.1.0 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/directive/animate/index.js +1 -1
- package/index.d.ts +73 -0
- package/package.json +38 -30
- package/plugins/auto-loader.mjs +314 -0
- package/plugins/storage/index.js +151 -22
- package/scripts/generate-types.mjs +83 -0
- package/plugins/crypt/crypt.js +0 -281
- package/plugins/crypt/random.js +0 -52
package/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Auto-generated Vue component type declarations
|
|
2
|
+
// Do not edit manually - run `npm run build` to update
|
|
3
|
+
declare module 'vue' {
|
|
4
|
+
export interface GlobalComponents {
|
|
5
|
+
rApp: typeof import('./components/app/index.js')['rApp']
|
|
6
|
+
rAvatar: typeof import('./components/avatar/index.js')['rAvatar']
|
|
7
|
+
rBtn: typeof import('./components/button/index.js')['rBtn']
|
|
8
|
+
rBtnConfirm: typeof import('./components/button/buttonConfirm.js')['rBtnConfirm']
|
|
9
|
+
rBtnGroup: typeof import('./components/button/buttonGroup.js')['rBtnGroup']
|
|
10
|
+
rCalendar: typeof import('./components/calendar/index.js')['rCalendar']
|
|
11
|
+
rCard: typeof import('./components/card/index.js')['rCard']
|
|
12
|
+
rCodeEditor: typeof import('./components/codeEditor/index.js')['rCodeEditor']
|
|
13
|
+
rConfirm: typeof import('./components/confirm/index.js')['rConfirm']
|
|
14
|
+
rContainer: typeof import('./components/container/index.js')['rContainer']
|
|
15
|
+
rRow: typeof import('./components/container/row.js')['rRow']
|
|
16
|
+
rCol: typeof import('./components/container/col.js')['rCol']
|
|
17
|
+
rSpacer: typeof import('./components/container/spacer.js')['rSpacer']
|
|
18
|
+
rDivider: typeof import('./components/container/divider.js')['rDivider']
|
|
19
|
+
rContent: typeof import('./components/content/index.js')['rContent']
|
|
20
|
+
rCropper: typeof import('./components/cropper/index.js')['rCropper']
|
|
21
|
+
rFloat: typeof import('./components/float/index.js')['rFloat']
|
|
22
|
+
rForm: typeof import('./components/form/index.js')['rForm']
|
|
23
|
+
rInput: typeof import('./components/form/input/index.js')['rInput']
|
|
24
|
+
rColorInput: typeof import('./components/form/colorInput/index.js')['rColorInput']
|
|
25
|
+
rDateInput: typeof import('./components/form/dateInput/index.js')['rDateInput']
|
|
26
|
+
rFileInput: typeof import('./components/form/fileInput/index.js')['rFileInput']
|
|
27
|
+
rTelInput: typeof import('./components/form/telInput/index.js')['rTelInput']
|
|
28
|
+
rJsonInput: typeof import('./components/form/jsonInput/index.js')['rJsonInput']
|
|
29
|
+
rTextEditor: typeof import('./components/form/textEditor/index.js')['rTextEditor']
|
|
30
|
+
rTextEditorPreview: typeof import('./components/form/textEditor/preview.js')['rTextEditorPreview']
|
|
31
|
+
rTimeInput: typeof import('./components/form/timeInput/index.js')['rTimeInput']
|
|
32
|
+
rTimeRangeInput: typeof import('./components/form/timeInput/range.js')['rTimeRangeInput']
|
|
33
|
+
rUniqueInput: typeof import('./components/form/uniqueInput/index.js')['rUniqueInput']
|
|
34
|
+
rAddressInput: typeof import('./components/form/addressInput/index.js')['rAddressInput']
|
|
35
|
+
rCamInput: typeof import('./components/form/camInput/index.js')['rCamInput']
|
|
36
|
+
rCheckInput: typeof import('./components/form/checkInput/index.js')['rCheckInput']
|
|
37
|
+
rCheckboxInput: typeof import('./components/form/checkboxInput/index.js')['rCheckboxInput']
|
|
38
|
+
rGroupInput: typeof import('./components/form/groupInput/index.js')['rGroupInput']
|
|
39
|
+
rMaskInput: typeof import('./components/form/maskInput/index.js')['rMaskInput']
|
|
40
|
+
rNumberInput: typeof import('./components/form/numberInput/index.js')['rNumberInput']
|
|
41
|
+
rPasswordInput: typeof import('./components/form/passwordInput/index.js')['rPasswordInput']
|
|
42
|
+
rRadioInput: typeof import('./components/form/radioInput/index.js')['rRadioInput']
|
|
43
|
+
rRangeInput: typeof import('./components/form/rangeInput/index.js')['rRangeInput']
|
|
44
|
+
rRatingInput: typeof import('./components/form/ratingInput/index.js')['rRatingInput']
|
|
45
|
+
rSelectInput: typeof import('./components/form/selectInput/index.js')['rSelectInput']
|
|
46
|
+
rSwitchInput: typeof import('./components/form/switchInput/index.js')['rSwitchInput']
|
|
47
|
+
rTextArea: typeof import('./components/form/textArea/index.js')['rTextArea']
|
|
48
|
+
rTextInput: typeof import('./components/form/textInput/index.js')['rTextInput']
|
|
49
|
+
rUnitInput: typeof import('./components/form/unitInput/index.js')['rUnitInput']
|
|
50
|
+
rFormCreator: typeof import('./components/formCreator/index.js')['rFormCreator']
|
|
51
|
+
rIcon: typeof import('./components/icon/index.js')['rIcon']
|
|
52
|
+
rImg: typeof import('./components/img/index.js')['rImg']
|
|
53
|
+
rInfinite: typeof import('./components/infinite/index.js')['rInfinite']
|
|
54
|
+
rMap: typeof import('./components/map/index.js')['rMap']
|
|
55
|
+
rMapSelect: typeof import('./components/map/select.js')['rMapSelect']
|
|
56
|
+
rMapRoute: typeof import('./components/map/route.js')['rMapRoute']
|
|
57
|
+
rMenu: typeof import('./components/menu/index.js')['rMenu']
|
|
58
|
+
rMeta: typeof import('./components/meta/index.js')['rMeta']
|
|
59
|
+
rModal: typeof import('./components/modal/index.js')['rModal']
|
|
60
|
+
rNotify: typeof import('./components/notify/index.js')['rNotify']
|
|
61
|
+
rProgressCircle: typeof import('./components/progress/circle.js')['rProgressCircle']
|
|
62
|
+
rProgressLine: typeof import('./components/progress/line.js')['rProgressLine']
|
|
63
|
+
rSearchBox: typeof import('./components/searchBox/index.js')['rSearchBox']
|
|
64
|
+
rSlider: typeof import('./components/slider/index.js')['rSlider']
|
|
65
|
+
rSwiper: typeof import('./components/swiper/index.js')['rSwiper']
|
|
66
|
+
rTable: typeof import('./components/table/index.js')['rTable']
|
|
67
|
+
rTableCrud: typeof import('./components/table/crud/index.js')['rTableCrud']
|
|
68
|
+
rTimeAgo: typeof import('./components/timeAgo/index.js')['rTimeAgo']
|
|
69
|
+
rTour: typeof import('./components/tour/index.js')['rTour']
|
|
70
|
+
rTree: typeof import('./components/tree/index.js')['rTree']
|
|
71
|
+
rHighlight: typeof import('./components/highlight/index.js')['rHighlight']
|
|
72
|
+
}
|
|
73
|
+
}
|
package/package.json
CHANGED
|
@@ -1,30 +1,38 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "renusify",
|
|
3
|
-
"version": "3.1.
|
|
4
|
-
"description": "Vue3 Framework",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"vuejs",
|
|
7
|
-
"vue framework",
|
|
8
|
-
"ui framework",
|
|
9
|
-
"component framework",
|
|
10
|
-
"ui library",
|
|
11
|
-
"component library",
|
|
12
|
-
"material components",
|
|
13
|
-
"renusify"
|
|
14
|
-
],
|
|
15
|
-
"homepage": "https://github.com/smkoBa/renusify",
|
|
16
|
-
"main": "index.js",
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "renusify",
|
|
3
|
+
"version": "3.1.3",
|
|
4
|
+
"description": "Vue3 Framework",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vuejs",
|
|
7
|
+
"vue framework",
|
|
8
|
+
"ui framework",
|
|
9
|
+
"component framework",
|
|
10
|
+
"ui library",
|
|
11
|
+
"component library",
|
|
12
|
+
"material components",
|
|
13
|
+
"renusify"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/smkoBa/renusify",
|
|
16
|
+
"main": "index.js",
|
|
17
|
+
"types": "index.d.ts",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/smkoBa/renusify.git"
|
|
21
|
+
},
|
|
22
|
+
"author": {
|
|
23
|
+
"name": "Smko Bayazidi",
|
|
24
|
+
"email": "ba.smko@gmail.com"
|
|
25
|
+
},
|
|
26
|
+
"license": "BSD",
|
|
27
|
+
"private": false,
|
|
28
|
+
"scripts": {
|
|
29
|
+
"docs:generate": "node scripts/generate-docs.mjs",
|
|
30
|
+
"build:types": "node scripts/generate-types.mjs",
|
|
31
|
+
"build": "npm run docs:generate && npm run build:types"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"sass": "^1.69.0",
|
|
35
|
+
"vue": "^3.3.0",
|
|
36
|
+
"vue-router": "^4.5.0"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
|
|
4
|
+
export default function renusifyAutoPlugin(options = {}) {
|
|
5
|
+
const { prefix = 'r', debug = false } = options
|
|
6
|
+
|
|
7
|
+
const state = {
|
|
8
|
+
usedComponents: new Set(),
|
|
9
|
+
usedDirectives: new Set(),
|
|
10
|
+
componentsMap: new Map(),
|
|
11
|
+
directivesMap: new Map(),
|
|
12
|
+
rootDir: '',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
function parseExports(filePath, exclude = []) {
|
|
17
|
+
try {
|
|
18
|
+
const content = fs.readFileSync(filePath, 'utf-8')
|
|
19
|
+
const clean = content
|
|
20
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
21
|
+
.replace(/\/\/.*$/gm, '')
|
|
22
|
+
|
|
23
|
+
const regex = /export\s+\*\s+as\s+([a-zA-Z_]\w*)\s+from\s+['"]([^'"]+)['"]/g
|
|
24
|
+
const map = new Map()
|
|
25
|
+
let m
|
|
26
|
+
while ((m = regex.exec(clean)) !== null) {
|
|
27
|
+
const [, name, relPath] = m
|
|
28
|
+
if (exclude.includes(name)) continue
|
|
29
|
+
let p = relPath.replace(/^\.\//, '')
|
|
30
|
+
if (!p.match(/\.(js|vue|ts|mjs)$/)) p = `${p}/index.js`
|
|
31
|
+
map.set(name, p)
|
|
32
|
+
}
|
|
33
|
+
return map
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.warn(`[renusify-auto] Could not parse ${filePath}:`, err.message)
|
|
36
|
+
return new Map()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
function kebab2camel(s) {
|
|
42
|
+
return s.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase())
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
function scanFile(filePath) {
|
|
47
|
+
try {
|
|
48
|
+
const content = fs.readFileSync(filePath, 'utf-8')
|
|
49
|
+
const tmplMatch = content.match(/<template(?:\s[^>]*)?>([\s\S]*?)<\/template>/)
|
|
50
|
+
if (!tmplMatch) return
|
|
51
|
+
|
|
52
|
+
const tmpl = tmplMatch[1]
|
|
53
|
+
|
|
54
|
+
const tagRe = /<\s*\/?([a-zA-Z][a-zA-Z0-9-]*)/g
|
|
55
|
+
let m
|
|
56
|
+
while ((m = tagRe.exec(tmpl)) !== null) {
|
|
57
|
+
const tag = m[1]
|
|
58
|
+
if (!tag.startsWith(prefix)) continue
|
|
59
|
+
const camel = kebab2camel(tag)
|
|
60
|
+
if (state.componentsMap.has(camel)) state.usedComponents.add(camel)
|
|
61
|
+
else if (state.componentsMap.has(tag)) state.usedComponents.add(tag)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const dirRe = /\bv-([a-zA-Z][a-zA-Z0-9-]*)/g
|
|
65
|
+
const builtins = new Set([
|
|
66
|
+
'model', 'if', 'else', 'else-if', 'for', 'show', 'bind', 'on',
|
|
67
|
+
'slot', 'text', 'html', 'cloak', 'once', 'memo', 'pre'
|
|
68
|
+
])
|
|
69
|
+
|
|
70
|
+
while ((m = dirRe.exec(tmpl)) !== null) {
|
|
71
|
+
const d = m[1]
|
|
72
|
+
if (builtins.has(d)) continue
|
|
73
|
+
const camel = kebab2camel(d)
|
|
74
|
+
const candidates = [d, camel, `v${camel.charAt(0).toUpperCase()}${camel.slice(1)}`]
|
|
75
|
+
for (const c of candidates) {
|
|
76
|
+
if (state.directivesMap.has(c)) {
|
|
77
|
+
state.usedDirectives.add(c)
|
|
78
|
+
break
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
// ignore
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
function scanDirSync(dir) {
|
|
89
|
+
let entries
|
|
90
|
+
try {
|
|
91
|
+
entries = fs.readdirSync(dir, { withFileTypes: true })
|
|
92
|
+
} catch {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
const full = path.join(dir, entry.name)
|
|
97
|
+
if (entry.isDirectory()) {
|
|
98
|
+
if (['node_modules', 'dist', '.git', '.nuxt', '.output'].includes(entry.name)) continue
|
|
99
|
+
scanDirSync(full)
|
|
100
|
+
} else if (entry.name.endsWith('.vue')) {
|
|
101
|
+
scanFile(full)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
function generateImportStatements() {
|
|
108
|
+
const comps = [...state.usedComponents].sort()
|
|
109
|
+
const dirs = [...state.usedDirectives].sort()
|
|
110
|
+
|
|
111
|
+
if (comps.length === 0 && dirs.length === 0) return ''
|
|
112
|
+
|
|
113
|
+
let code = '\n'
|
|
114
|
+
if (comps.length > 0) {
|
|
115
|
+
code += `import {\n ${comps.join(',\n ')}\n} from 'renusify/components/index.js'\n`
|
|
116
|
+
}
|
|
117
|
+
if (dirs.length > 0) {
|
|
118
|
+
const dirNames = dirs.map(name => {
|
|
119
|
+
if (name.startsWith('v') || name.startsWith('V')) {
|
|
120
|
+
return name.charAt(1).toLowerCase() + name.slice(2)
|
|
121
|
+
}
|
|
122
|
+
return name
|
|
123
|
+
})
|
|
124
|
+
code += `import { ${dirNames.join(', ')} } from 'renusify/directive/index.js'\n`
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return code
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
function generateComponentsObject() {
|
|
132
|
+
const comps = [...state.usedComponents].sort()
|
|
133
|
+
if (comps.length === 0) return null
|
|
134
|
+
return `components: {\n ${comps.join(',\n ')}\n }`
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
function generateDirectivesObject() {
|
|
139
|
+
const dirs = [...state.usedDirectives].sort()
|
|
140
|
+
if (dirs.length === 0) return null
|
|
141
|
+
const dirNames = dirs.map(name => {
|
|
142
|
+
if (name.startsWith('v') || name.startsWith('V')) {
|
|
143
|
+
return name.charAt(1).toLowerCase() + name.slice(2)
|
|
144
|
+
}
|
|
145
|
+
return name
|
|
146
|
+
})
|
|
147
|
+
return `directives: { ${dirNames.join(', ')} }`
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
name: 'vite-plugin-renusify-auto',
|
|
152
|
+
enforce: 'pre',
|
|
153
|
+
|
|
154
|
+
configResolved(config) {
|
|
155
|
+
state.rootDir = config.root
|
|
156
|
+
const renusifyPath = path.join(config.root, 'node_modules/renusify')
|
|
157
|
+
|
|
158
|
+
state.componentsMap = parseExports(
|
|
159
|
+
path.join(renusifyPath, 'components/index.js'),
|
|
160
|
+
['_register']
|
|
161
|
+
)
|
|
162
|
+
state.directivesMap = parseExports(
|
|
163
|
+
path.join(renusifyPath, 'directive/index.js'),
|
|
164
|
+
['_registers']
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if (config.command === 'serve') {
|
|
168
|
+
state.usedComponents = new Set(state.componentsMap.keys())
|
|
169
|
+
state.usedDirectives = new Set(state.directivesMap.keys())
|
|
170
|
+
if (debug) {
|
|
171
|
+
console.log(`[renusify-auto] Dev mode: ALL ${state.componentsMap.size} components, ${state.directivesMap.size} directives`)
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
scanDirSync(path.join(config.root, 'src'))
|
|
175
|
+
if (debug) {
|
|
176
|
+
console.log(`[renusify-auto] Build mode: ${state.usedComponents.size} components, ${state.usedDirectives.size} directives`)
|
|
177
|
+
console.log(' Components:', [...state.usedComponents].join(', '))
|
|
178
|
+
console.log(' Directives:', [...state.usedDirectives].join(', '))
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
transform(code, id) {
|
|
184
|
+
if (!/main\.(js|ts)$/.test(id)) return null
|
|
185
|
+
if (id.includes('node_modules')) return null
|
|
186
|
+
|
|
187
|
+
let newCode = code
|
|
188
|
+
let modified = false
|
|
189
|
+
|
|
190
|
+
const importStmts = generateImportStatements()
|
|
191
|
+
if (importStmts) {
|
|
192
|
+
const importRegex = /^import\s+[^;]+;?\s*$/gm
|
|
193
|
+
const allImports = code.match(importRegex)
|
|
194
|
+
|
|
195
|
+
if (allImports && allImports.length > 0) {
|
|
196
|
+
const lastImport = allImports[allImports.length - 1]
|
|
197
|
+
const lastImportIndex = code.lastIndexOf(lastImport)
|
|
198
|
+
const insertPos = lastImportIndex + lastImport.length
|
|
199
|
+
newCode = newCode.slice(0, insertPos) + importStmts + newCode.slice(insertPos)
|
|
200
|
+
} else {
|
|
201
|
+
newCode = importStmts + '\n' + newCode
|
|
202
|
+
}
|
|
203
|
+
modified = true
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const renusifyRegex = /\.use\s*\(\s*renusify\s*,\s*\{/
|
|
207
|
+
const useMatch = newCode.match(renusifyRegex)
|
|
208
|
+
|
|
209
|
+
if (useMatch) {
|
|
210
|
+
const matchIndex = useMatch.index
|
|
211
|
+
const startOfOptions = matchIndex + useMatch[0].length
|
|
212
|
+
|
|
213
|
+
let braceCount = 1
|
|
214
|
+
let i = startOfOptions
|
|
215
|
+
while (i < newCode.length && braceCount > 0) {
|
|
216
|
+
if (newCode[i] === '{') braceCount++
|
|
217
|
+
else if (newCode[i] === '}') braceCount--
|
|
218
|
+
if (braceCount > 0) i++
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (braceCount === 0) {
|
|
222
|
+
const endOfOptions = i
|
|
223
|
+
const optionsContent = newCode.slice(startOfOptions, endOfOptions)
|
|
224
|
+
let cleanedOptions = optionsContent
|
|
225
|
+
|
|
226
|
+
cleanedOptions = removeProperty(cleanedOptions, 'components')
|
|
227
|
+
cleanedOptions = removeProperty(cleanedOptions, 'directives')
|
|
228
|
+
|
|
229
|
+
cleanedOptions = cleanedOptions.replace(/,(\s*)}/g, '$1}')
|
|
230
|
+
cleanedOptions = cleanedOptions.trim()
|
|
231
|
+
|
|
232
|
+
const componentsObj = generateComponentsObject()
|
|
233
|
+
const directivesObj = generateDirectivesObject()
|
|
234
|
+
|
|
235
|
+
let newOptionsContent = cleanedOptions
|
|
236
|
+
|
|
237
|
+
if (componentsObj || directivesObj) {
|
|
238
|
+
const needsComma = newOptionsContent.trim().length > 0 && !newOptionsContent.trim().endsWith(',')
|
|
239
|
+
const comma = needsComma ? ',' : ''
|
|
240
|
+
|
|
241
|
+
let additions = ''
|
|
242
|
+
if (componentsObj) additions += '\n ' + componentsObj
|
|
243
|
+
if (directivesObj) additions += (additions ? ',' : '') + '\n ' + directivesObj
|
|
244
|
+
|
|
245
|
+
if (newOptionsContent.trim().length === 0) {
|
|
246
|
+
newOptionsContent = additions + '\n '
|
|
247
|
+
} else {
|
|
248
|
+
newOptionsContent = newOptionsContent + comma + additions + '\n '
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
newCode = newCode.slice(0, startOfOptions) + newOptionsContent + newCode.slice(endOfOptions)
|
|
253
|
+
modified = true
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (modified) {
|
|
258
|
+
if (debug) {
|
|
259
|
+
console.log(`[renusify-auto] Transformed ${path.basename(id)}`)
|
|
260
|
+
}
|
|
261
|
+
return { code: newCode, map: null }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return null
|
|
265
|
+
},
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function removeProperty(optionsStr, propName) {
|
|
270
|
+
const propRegex = new RegExp(`,?\\s*${propName}\\s*:\\s*`)
|
|
271
|
+
const match = propRegex.exec(optionsStr)
|
|
272
|
+
|
|
273
|
+
if (!match) return optionsStr
|
|
274
|
+
|
|
275
|
+
const startIndex = match.index
|
|
276
|
+
const valueStart = startIndex + match[0].length
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
let endIndex = valueStart
|
|
280
|
+
const firstChar = optionsStr[valueStart]
|
|
281
|
+
|
|
282
|
+
if (firstChar === '{') {
|
|
283
|
+
|
|
284
|
+
let braceCount = 1
|
|
285
|
+
let i = valueStart + 1
|
|
286
|
+
while (i < optionsStr.length && braceCount > 0) {
|
|
287
|
+
if (optionsStr[i] === '{') braceCount++
|
|
288
|
+
else if (optionsStr[i] === '}') braceCount--
|
|
289
|
+
i++
|
|
290
|
+
}
|
|
291
|
+
endIndex = i
|
|
292
|
+
} else if (firstChar === '[') {
|
|
293
|
+
let bracketCount = 1
|
|
294
|
+
let i = valueStart + 1
|
|
295
|
+
while (i < optionsStr.length && bracketCount > 0) {
|
|
296
|
+
if (optionsStr[i] === '[') bracketCount++
|
|
297
|
+
else if (optionsStr[i] === ']') bracketCount--
|
|
298
|
+
i++
|
|
299
|
+
}
|
|
300
|
+
endIndex = i
|
|
301
|
+
} else {
|
|
302
|
+
let i = valueStart
|
|
303
|
+
while (i < optionsStr.length && optionsStr[i] !== ',' && optionsStr[i] !== '}') {
|
|
304
|
+
i++
|
|
305
|
+
}
|
|
306
|
+
endIndex = i
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (endIndex < optionsStr.length && optionsStr[endIndex] === ',') {
|
|
310
|
+
endIndex++
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return optionsStr.slice(0, startIndex) + optionsStr.slice(endIndex)
|
|
314
|
+
}
|
package/plugins/storage/index.js
CHANGED
|
@@ -1,35 +1,164 @@
|
|
|
1
1
|
class Storage {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
constructor(encryptionKey) {
|
|
3
|
+
this._key = encryptionKey || this._loadKeyFromEnv();
|
|
4
|
+
this._available = this._checkAvailability();
|
|
5
|
+
if (!this._key) {
|
|
6
|
+
console.warn('[Storage] ⚠️ No encryption key provided. Safe methods will throw.');
|
|
4
7
|
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
_loadKeyFromEnv() {
|
|
11
|
+
if (typeof import.meta !== 'undefined' && import.meta.env?.VITE_STORAGE_KEY)
|
|
12
|
+
return import.meta.env.VITE_STORAGE_KEY;
|
|
13
|
+
if (typeof process !== 'undefined' && process.env?.STORAGE_KEY)
|
|
14
|
+
return process.env.STORAGE_KEY;
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_checkAvailability() {
|
|
19
|
+
try {
|
|
20
|
+
const test = '__storage_test__';
|
|
21
|
+
localStorage.setItem(test, '1');
|
|
22
|
+
localStorage.removeItem(test);
|
|
23
|
+
return true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
10
26
|
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_arrayBufferToBase64(buffer) {
|
|
30
|
+
const bytes = new Uint8Array(buffer);
|
|
31
|
+
let binary = '';
|
|
32
|
+
for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
|
|
33
|
+
return btoa(binary);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_base64ToArrayBuffer(base64) {
|
|
37
|
+
const binary = atob(base64);
|
|
38
|
+
const bytes = new Uint8Array(binary.length);
|
|
39
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
40
|
+
return bytes.buffer;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async _deriveKey(password, salt) {
|
|
44
|
+
const enc = new TextEncoder();
|
|
45
|
+
const keyMaterial = await crypto.subtle.importKey(
|
|
46
|
+
'raw', enc.encode(password), 'PBKDF2', false, ['deriveKey']
|
|
47
|
+
);
|
|
48
|
+
return crypto.subtle.deriveKey(
|
|
49
|
+
{name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256'},
|
|
50
|
+
keyMaterial,
|
|
51
|
+
{name: 'AES-GCM', length: 256},
|
|
52
|
+
false,
|
|
53
|
+
['encrypt', 'decrypt']
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async _encrypt(plaintext) {
|
|
58
|
+
const salt = crypto.getRandomValues(new Uint8Array(16));
|
|
59
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
60
|
+
const key = await this._deriveKey(this._key, salt);
|
|
61
|
+
const cipher = await crypto.subtle.encrypt(
|
|
62
|
+
{name: 'AES-GCM', iv}, key, new TextEncoder().encode(plaintext)
|
|
63
|
+
);
|
|
64
|
+
return JSON.stringify({
|
|
65
|
+
salt: this._arrayBufferToBase64(salt),
|
|
66
|
+
iv: this._arrayBufferToBase64(iv),
|
|
67
|
+
data: this._arrayBufferToBase64(cipher)
|
|
68
|
+
});
|
|
69
|
+
}
|
|
11
70
|
|
|
12
|
-
|
|
13
|
-
|
|
71
|
+
async _decrypt(payloadString) {
|
|
72
|
+
const {salt, iv, data} = JSON.parse(payloadString);
|
|
73
|
+
const key = await this._deriveKey(this._key, this._base64ToArrayBuffer(salt));
|
|
74
|
+
const decrypted = await crypto.subtle.decrypt(
|
|
75
|
+
{name: 'AES-GCM', iv: this._base64ToArrayBuffer(iv)},
|
|
76
|
+
key,
|
|
77
|
+
this._base64ToArrayBuffer(data)
|
|
78
|
+
);
|
|
79
|
+
return new TextDecoder().decode(decrypted);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
stringify(value) {
|
|
83
|
+
return JSON.stringify(value);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
parse(value) {
|
|
87
|
+
return JSON.parse(value);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
set(key, value) {
|
|
91
|
+
if (!this._available) return false;
|
|
92
|
+
try {
|
|
93
|
+
localStorage.setItem(String(key), this.stringify(value));
|
|
94
|
+
return true;
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.error(`[Storage] set failed:`, err);
|
|
97
|
+
return false;
|
|
14
98
|
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
has(key) {
|
|
102
|
+
if (!this._available) return false;
|
|
103
|
+
return localStorage.getItem(String(key)) !== null;
|
|
104
|
+
}
|
|
15
105
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
106
|
+
get(key, def = null) {
|
|
107
|
+
if (!this._available) return def;
|
|
108
|
+
const raw = localStorage.getItem(String(key));
|
|
109
|
+
if (raw === null) return def;
|
|
110
|
+
try {
|
|
111
|
+
return this.parse(raw);
|
|
112
|
+
} catch {
|
|
113
|
+
return def;
|
|
22
114
|
}
|
|
115
|
+
}
|
|
23
116
|
|
|
24
|
-
|
|
25
|
-
|
|
117
|
+
remove(key) {
|
|
118
|
+
if (!this._available) return false;
|
|
119
|
+
localStorage.removeItem(String(key));
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
pull(key, def = null) {
|
|
124
|
+
const data = this.get(key, def);
|
|
125
|
+
this.remove(key);
|
|
126
|
+
return data;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async setSafe(key, value) {
|
|
130
|
+
if (!this._key) throw new Error('[Storage] Encryption key not configured.');
|
|
131
|
+
if (!this._available) return false;
|
|
132
|
+
try {
|
|
133
|
+
const plaintext = this.stringify(value);
|
|
134
|
+
const encrypted = await this._encrypt(plaintext);
|
|
135
|
+
localStorage.setItem(String(key), encrypted);
|
|
136
|
+
return true;
|
|
137
|
+
} catch (err) {
|
|
138
|
+
console.error(`[Storage] setSafe failed:`, err);
|
|
139
|
+
return false;
|
|
26
140
|
}
|
|
141
|
+
}
|
|
27
142
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
143
|
+
async getSafe(key, def = null) {
|
|
144
|
+
if (!this._key) throw new Error('[Storage] Encryption key not configured.');
|
|
145
|
+
if (!this._available) return def;
|
|
146
|
+
const raw = localStorage.getItem(String(key));
|
|
147
|
+
if (raw === null) return def;
|
|
148
|
+
try {
|
|
149
|
+
const decrypted = await this._decrypt(raw);
|
|
150
|
+
return this.parse(decrypted);
|
|
151
|
+
} catch (err) {
|
|
152
|
+
console.warn(`[Storage] getSafe failed (tampered/invalid):`, err);
|
|
153
|
+
return def;
|
|
32
154
|
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async pullSafe(key, def = null) {
|
|
158
|
+
const data = await this.getSafe(key, def);
|
|
159
|
+
this.remove(key);
|
|
160
|
+
return data;
|
|
161
|
+
}
|
|
33
162
|
}
|
|
34
163
|
|
|
35
|
-
export default new Storage();
|
|
164
|
+
export default new Storage();
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
const CONFIG = {
|
|
9
|
+
inputFile: path.resolve(__dirname, '../components/index.js'),
|
|
10
|
+
outputFile: path.resolve(__dirname, '../index.d.ts'),
|
|
11
|
+
importPathPrefix: './components',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
function parseExports(content) {
|
|
16
|
+
return content
|
|
17
|
+
.split('\n')
|
|
18
|
+
.map(line => line.trim())
|
|
19
|
+
.filter(line => line && !line.startsWith('//'))
|
|
20
|
+
.map(line => {
|
|
21
|
+
const match = line.match(/^export\s+\*\s+as\s+(\w+)\s+from\s+['"](.+)['"]\s*;?$/);
|
|
22
|
+
return match ? { componentName: match[1], relativePath: match[2] } : null;
|
|
23
|
+
})
|
|
24
|
+
.filter(item => item !== null);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
function transformImportPath(relativePath, prefix) {
|
|
29
|
+
if (relativePath.startsWith('./')) {
|
|
30
|
+
return `${prefix}${relativePath.slice(1)}`;
|
|
31
|
+
}
|
|
32
|
+
return relativePath;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
function generateDeclaration(components, prefix) {
|
|
37
|
+
const lines = [
|
|
38
|
+
'// Auto-generated Vue component type declarations',
|
|
39
|
+
'// Do not edit manually - run `npm run build` to update',
|
|
40
|
+
`declare module 'vue' {`,
|
|
41
|
+
` export interface GlobalComponents {`,
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
for (const { componentName, relativePath } of components) {
|
|
45
|
+
const importPath = transformImportPath(relativePath, prefix);
|
|
46
|
+
lines.push(` ${componentName}: typeof import('${importPath}')['${componentName}']`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
lines.push(` }`, `}`, '');
|
|
50
|
+
return lines.join('\n');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
function main() {
|
|
55
|
+
try {
|
|
56
|
+
console.log(`Reading exports from: ${CONFIG.inputFile}`);
|
|
57
|
+
|
|
58
|
+
if (!fs.existsSync(CONFIG.inputFile)) {
|
|
59
|
+
throw new Error(`Input file not found: ${CONFIG.inputFile}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const content = fs.readFileSync(CONFIG.inputFile, 'utf-8');
|
|
63
|
+
const components = parseExports(content);
|
|
64
|
+
|
|
65
|
+
if (components.length === 0) {
|
|
66
|
+
console.warn('No component exports found. Check your input file format.');
|
|
67
|
+
} else {
|
|
68
|
+
console.log(`Found ${components.length} component exports`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const declaration = generateDeclaration(components, CONFIG.importPathPrefix);
|
|
72
|
+
|
|
73
|
+
fs.writeFileSync(CONFIG.outputFile, declaration, 'utf-8');
|
|
74
|
+
console.log(`Generated: ${CONFIG.outputFile}`);
|
|
75
|
+
console.log(`Total components: ${components.length}`);
|
|
76
|
+
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('Error:', error.message);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
main();
|
package/plugins/crypt/crypt.js
DELETED
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
import SimpleRng from "./random";
|
|
2
|
-
|
|
3
|
-
export default class Cryptor {
|
|
4
|
-
constructor() {
|
|
5
|
-
this.matrix = 32;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
packUint32BE(value) {
|
|
9
|
-
const bytes = new Uint8Array(4);
|
|
10
|
-
bytes[0] = (value >> 24) & 0xFF;
|
|
11
|
-
bytes[1] = (value >> 16) & 0xFF;
|
|
12
|
-
bytes[2] = (value >> 8) & 0xFF;
|
|
13
|
-
bytes[3] = value & 0xFF;
|
|
14
|
-
return bytes;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
unpackUint32BE(bytes, offset = 0) {
|
|
18
|
-
return ((bytes[offset] << 24) |
|
|
19
|
-
(bytes[offset + 1] << 16) |
|
|
20
|
-
(bytes[offset + 2] << 8) |
|
|
21
|
-
bytes[offset + 3]) >>> 0;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
encrypt(data, key) {
|
|
25
|
-
const matrixSize = this.matrix;
|
|
26
|
-
const pad = (matrixSize - ((10 + data.length) % matrixSize)) % matrixSize;
|
|
27
|
-
const keyBytes = this.generatePassword(matrixSize, this.stringToBytes(key));
|
|
28
|
-
|
|
29
|
-
const dataSize = this.packUint32BE(data.length);
|
|
30
|
-
|
|
31
|
-
const randomPrefix = this.getRandomBytes(6);
|
|
32
|
-
const seedRandom = randomPrefix.reduce((sum, b) => sum + b, 0);
|
|
33
|
-
|
|
34
|
-
const paddedText = new Uint8Array(10 + data.length + pad);
|
|
35
|
-
paddedText.set(dataSize, 0);
|
|
36
|
-
paddedText.set(randomPrefix, 4);
|
|
37
|
-
paddedText.set(data, 10);
|
|
38
|
-
|
|
39
|
-
if (pad > 0) {
|
|
40
|
-
paddedText.fill(1, 10 + data.length, 10 + data.length + pad);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const seedSum = keyBytes.reduce((sum, b) => sum + b, 0);
|
|
44
|
-
this.shuffle(paddedText, seedSum + seedRandom, 5);
|
|
45
|
-
|
|
46
|
-
for (let i = 0; i < paddedText.length; i += matrixSize) {
|
|
47
|
-
const end = Math.min(i + matrixSize, paddedText.length);
|
|
48
|
-
const seed = (i + matrixSize < paddedText.length) ? paddedText[i + matrixSize] : keyBytes[0];
|
|
49
|
-
const chunkCopy = new Uint8Array(paddedText.slice(i, end));
|
|
50
|
-
this.shuffle(chunkCopy, seed + seedRandom, 2);
|
|
51
|
-
paddedText.set(chunkCopy, i);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
this.mix(matrixSize, paddedText, keyBytes);
|
|
55
|
-
|
|
56
|
-
const result = new Uint8Array(paddedText.length + 2);
|
|
57
|
-
result.set(paddedText, 0);
|
|
58
|
-
result[paddedText.length] = (seedRandom >> 8) & 0xFF;
|
|
59
|
-
result[paddedText.length + 1] = seedRandom & 0xFF;
|
|
60
|
-
|
|
61
|
-
return result;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
encryptText(text, key) {
|
|
65
|
-
const data = this.stringToBytes(text);
|
|
66
|
-
const encrypted = this.encrypt(data, key);
|
|
67
|
-
return this.base64UrlEncode(encrypted);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
decrypt(encoded, key) {
|
|
71
|
-
if (encoded.length < 8) {
|
|
72
|
-
throw new Error('Invalid Token Matrix Length.');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const seedRandom = (encoded[encoded.length - 2] << 8) | encoded[encoded.length - 1];
|
|
76
|
-
const decoded = new Uint8Array(encoded.slice(0, -2));
|
|
77
|
-
const matrixSize = this.matrix;
|
|
78
|
-
|
|
79
|
-
const keyBytes = this.generatePassword(matrixSize, this.stringToBytes(key));
|
|
80
|
-
this.unmix(matrixSize, decoded, keyBytes);
|
|
81
|
-
|
|
82
|
-
for (let i = Math.floor(decoded.length / matrixSize) * matrixSize; i >= 0; i -= matrixSize) {
|
|
83
|
-
const end = Math.min(i + matrixSize, decoded.length);
|
|
84
|
-
const seed = (i + matrixSize < decoded.length) ? decoded[i + matrixSize] : keyBytes[0];
|
|
85
|
-
const chunkCopy = new Uint8Array(decoded.slice(i, end));
|
|
86
|
-
this.unshuffle(chunkCopy, seed + seedRandom, 2);
|
|
87
|
-
decoded.set(chunkCopy, i);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const seedSum = keyBytes.reduce((sum, b) => sum + b, 0);
|
|
91
|
-
this.unshuffle(decoded, seedSum + seedRandom, 5);
|
|
92
|
-
|
|
93
|
-
const dataSize = this.unpackUint32BE(decoded, 0);
|
|
94
|
-
|
|
95
|
-
if (decoded.length < dataSize + 10) {
|
|
96
|
-
throw new Error('Invalid Token Matrix Length');
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return decoded.slice(10, 10 + dataSize);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
decryptText(encoded, key) {
|
|
103
|
-
const padding = encoded.length % 4;
|
|
104
|
-
const paddedInput = padding === 0 ? encoded : encoded + '='.repeat(4 - padding);
|
|
105
|
-
|
|
106
|
-
const data = this.base64UrlDecode(paddedInput);
|
|
107
|
-
const decrypted = this.decrypt(data, key);
|
|
108
|
-
return this.bytesToString(decrypted);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
setMatrix(size) {
|
|
112
|
-
if (size > 0) {
|
|
113
|
-
this.matrix = size;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
generatePassword(matrix, password) {
|
|
118
|
-
const result = new Uint8Array(matrix);
|
|
119
|
-
const passwordLen = password.length;
|
|
120
|
-
|
|
121
|
-
if (passwordLen === 0) {
|
|
122
|
-
return result;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const repeats = Math.floor(matrix / passwordLen);
|
|
126
|
-
const remainder = matrix % passwordLen;
|
|
127
|
-
|
|
128
|
-
for (let i = 0; i < repeats; i++) {
|
|
129
|
-
const start = i * passwordLen;
|
|
130
|
-
result.set(password, start);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (remainder > 0) {
|
|
134
|
-
const start = repeats * passwordLen;
|
|
135
|
-
result.set(password.slice(0, remainder), start);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return result;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
shuffle(data, seed, step) {
|
|
142
|
-
const rng = new SimpleRng(seed);
|
|
143
|
-
const length = data.length;
|
|
144
|
-
|
|
145
|
-
for (let i = length - 1; i > 0; i -= step) {
|
|
146
|
-
const j = Math.floor(rng.genRange(0, i));
|
|
147
|
-
[data[i], data[j]] = [data[j], data[i]];
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
unshuffle(data, seed, step) {
|
|
152
|
-
const rng = new SimpleRng(seed);
|
|
153
|
-
const length = data.length;
|
|
154
|
-
const swaps = [];
|
|
155
|
-
|
|
156
|
-
for (let i = length - 1; i > 0; i -= step) {
|
|
157
|
-
const j = Math.floor(rng.genRange(0, i));
|
|
158
|
-
swaps.push([i, j]);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
for (let k = swaps.length - 1; k >= 0; k--) {
|
|
162
|
-
const [i, j] = swaps[k];
|
|
163
|
-
[data[i], data[j]] = [data[j], data[i]];
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
mix(blockSize, buf, key) {
|
|
168
|
-
let prevBlock = new Uint8Array(key);
|
|
169
|
-
|
|
170
|
-
for (let i = 0; i < buf.length; i += blockSize) {
|
|
171
|
-
const blockEnd = Math.min(i + blockSize, buf.length);
|
|
172
|
-
for (let j = 0; j < blockEnd - i && j < prevBlock.length; j++) {
|
|
173
|
-
buf[i + j] ^= prevBlock[j];
|
|
174
|
-
}
|
|
175
|
-
prevBlock = new Uint8Array(buf.slice(i, blockEnd));
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
unmix(blockSize, buf, key) {
|
|
180
|
-
const blocks = [];
|
|
181
|
-
for (let i = 0; i < buf.length; i += blockSize) {
|
|
182
|
-
const end = Math.min(i + blockSize, buf.length);
|
|
183
|
-
blocks.push(new Uint8Array(buf.slice(i, end)));
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
for (let i = blocks.length - 1; i >= 0; i--) {
|
|
187
|
-
if (i === 0) {
|
|
188
|
-
for (let j = 0; j < blocks[i].length && j < key.length; j++) {
|
|
189
|
-
blocks[i][j] ^= key[j];
|
|
190
|
-
}
|
|
191
|
-
} else {
|
|
192
|
-
for (let j = 0; j < blocks[i].length && j < blocks[i - 1].length; j++) {
|
|
193
|
-
blocks[i][j] ^= blocks[i - 1][j];
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
let offset = 0;
|
|
199
|
-
for (const block of blocks) {
|
|
200
|
-
buf.set(block, offset);
|
|
201
|
-
offset += block.length;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
getRandomBytes(length) {
|
|
206
|
-
const rng = new SimpleRng(Date.now());
|
|
207
|
-
return rng.getRandomBytes(length);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
base64UrlEncode(data) {
|
|
211
|
-
if (typeof Buffer !== 'undefined') {
|
|
212
|
-
// Node.js
|
|
213
|
-
return Buffer.from(data)
|
|
214
|
-
.toString('base64')
|
|
215
|
-
.replace(/\+/g, '-')
|
|
216
|
-
.replace(/\//g, '_')
|
|
217
|
-
.replace(/=+$/, '');
|
|
218
|
-
} else {
|
|
219
|
-
// Browser
|
|
220
|
-
let binary = '';
|
|
221
|
-
for (let i = 0; i < data.length; i++) {
|
|
222
|
-
binary += String.fromCharCode(data[i]);
|
|
223
|
-
}
|
|
224
|
-
return btoa(binary)
|
|
225
|
-
.replace(/\+/g, '-')
|
|
226
|
-
.replace(/\//g, '_')
|
|
227
|
-
.replace(/=+$/, '');
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
base64UrlDecode(encoded) {
|
|
232
|
-
let padded = encoded;
|
|
233
|
-
const padding = encoded.length % 4;
|
|
234
|
-
if (padding !== 0) {
|
|
235
|
-
padded += '='.repeat(4 - padding);
|
|
236
|
-
}
|
|
237
|
-
const base64 = padded.replace(/-/g, '+').replace(/_/g, '/');
|
|
238
|
-
|
|
239
|
-
if (typeof Buffer !== 'undefined') {
|
|
240
|
-
// Node.js
|
|
241
|
-
return new Uint8Array(Buffer.from(base64, 'base64'));
|
|
242
|
-
} else {
|
|
243
|
-
// Browser
|
|
244
|
-
const binary = atob(base64);
|
|
245
|
-
const bytes = new Uint8Array(binary.length);
|
|
246
|
-
for (let i = 0; i < binary.length; i++) {
|
|
247
|
-
bytes[i] = binary.charCodeAt(i);
|
|
248
|
-
}
|
|
249
|
-
return bytes;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
stringToBytes(str) {
|
|
254
|
-
if (typeof TextEncoder !== 'undefined') {
|
|
255
|
-
return new TextEncoder().encode(str);
|
|
256
|
-
}
|
|
257
|
-
if (typeof Buffer !== 'undefined') {
|
|
258
|
-
return new Uint8Array(Buffer.from(str, 'utf-8'));
|
|
259
|
-
}
|
|
260
|
-
const bytes = new Uint8Array(str.length);
|
|
261
|
-
for (let i = 0; i < str.length; i++) {
|
|
262
|
-
bytes[i] = str.charCodeAt(i) & 0xFF;
|
|
263
|
-
}
|
|
264
|
-
return bytes;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
bytesToString(bytes) {
|
|
268
|
-
if (typeof TextDecoder !== 'undefined') {
|
|
269
|
-
return new TextDecoder('utf-8').decode(bytes);
|
|
270
|
-
}
|
|
271
|
-
if (typeof Buffer !== 'undefined') {
|
|
272
|
-
return Buffer.from(bytes).toString('utf-8');
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
let str = '';
|
|
276
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
277
|
-
str += String.fromCharCode(bytes[i]);
|
|
278
|
-
}
|
|
279
|
-
return str;
|
|
280
|
-
}
|
|
281
|
-
}
|
package/plugins/crypt/random.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export default class SimpleRng {
|
|
2
|
-
constructor(seed) {
|
|
3
|
-
this.state = BigInt(seed) & 0xFFFFFFFFFFFFFFFFn;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
static newWithTimeSeed() {
|
|
7
|
-
return new SimpleRng(Date.now());
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
nextU32() {
|
|
11
|
-
this.state = (this.state * 6364136223846793005n + 1442695040888963407n) & 0xFFFFFFFFFFFFFFFFn;
|
|
12
|
-
return Number((this.state >> 32n) & 0xFFFFFFFFn);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
nextU64() {
|
|
16
|
-
const high = this.nextU32();
|
|
17
|
-
const low = this.nextU32();
|
|
18
|
-
return (high << 32) | low;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
nextF64() {
|
|
22
|
-
const val = this.nextU32();
|
|
23
|
-
return val / 4294967295.0;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
genRange(low, high) {
|
|
27
|
-
return low + (high - low) * this.nextF64();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
getRandomBytes(length) {
|
|
31
|
-
const byteArray = new Uint8Array(length);
|
|
32
|
-
const chunks = Math.floor(length / 4);
|
|
33
|
-
const remainder = length % 4;
|
|
34
|
-
|
|
35
|
-
for (let i = 0; i < chunks; i++) {
|
|
36
|
-
const random = this.nextU32();
|
|
37
|
-
byteArray[i * 4] = random & 0xFF;
|
|
38
|
-
byteArray[i * 4 + 1] = (random >> 8) & 0xFF;
|
|
39
|
-
byteArray[i * 4 + 2] = (random >> 16) & 0xFF;
|
|
40
|
-
byteArray[i * 4 + 3] = (random >> 24) & 0xFF;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (remainder > 0) {
|
|
44
|
-
const random = this.nextU32();
|
|
45
|
-
for (let i = 0; i < remainder; i++) {
|
|
46
|
-
byteArray[chunks * 4 + i] = (random >> (i * 8)) & 0xFF;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return byteArray;
|
|
51
|
-
}
|
|
52
|
-
}
|