update footer
This commit is contained in:
@@ -7,3 +7,4 @@ npm-debug.log*
|
|||||||
vite-dev*.log
|
vite-dev*.log
|
||||||
server-local*.log
|
server-local*.log
|
||||||
.local-storage/
|
.local-storage/
|
||||||
|
.claude/
|
||||||
Generated
+1215
-1
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -27,6 +27,7 @@
|
|||||||
"eslint": "^9.27.0",
|
"eslint": "^9.27.0",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
"globals": "^16.1.0"
|
"globals": "^16.1.0",
|
||||||
|
"rollup-plugin-obfuscator": "^1.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+76
-1
@@ -1,9 +1,84 @@
|
|||||||
|
import crypto from 'node:crypto'
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
import tailwindcss from '@tailwindcss/vite'
|
import tailwindcss from '@tailwindcss/vite'
|
||||||
|
import obfuscatorPlugin from 'rollup-plugin-obfuscator'
|
||||||
|
|
||||||
|
const OBFUSCATOR_OPTIONS = {
|
||||||
|
compact: true,
|
||||||
|
controlFlowFlattening: true,
|
||||||
|
controlFlowFlatteningThreshold: 0.75,
|
||||||
|
deadCodeInjection: true,
|
||||||
|
deadCodeInjectionThreshold: 0.4,
|
||||||
|
debugProtection: false,
|
||||||
|
disableConsoleOutput: false,
|
||||||
|
identifierNamesGenerator: 'hexadecimal',
|
||||||
|
log: false,
|
||||||
|
numbersToExpressions: true,
|
||||||
|
renameGlobals: false,
|
||||||
|
selfDefending: true,
|
||||||
|
simplify: true,
|
||||||
|
splitStrings: true,
|
||||||
|
splitStringsChunkLength: 10,
|
||||||
|
stringArray: true,
|
||||||
|
stringArrayCallsTransform: true,
|
||||||
|
stringArrayEncoding: ['base64'],
|
||||||
|
stringArrayIndexShift: true,
|
||||||
|
stringArrayRotate: true,
|
||||||
|
stringArrayShuffle: true,
|
||||||
|
stringArrayWrappersCount: 2,
|
||||||
|
stringArrayWrappersChainedCalls: true,
|
||||||
|
stringArrayWrappersParametersMaxCount: 4,
|
||||||
|
stringArrayWrappersType: 'function',
|
||||||
|
stringArrayThreshold: 0.75,
|
||||||
|
transformObjectKeys: true,
|
||||||
|
unicodeEscapeSequence: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
function obfuscate() {
|
||||||
|
const factory = obfuscatorPlugin.default || obfuscatorPlugin
|
||||||
|
const inner = factory({ global: true, options: OBFUSCATOR_OPTIONS })
|
||||||
|
return { ...inner, apply: 'build', enforce: 'post' }
|
||||||
|
}
|
||||||
|
|
||||||
const MAX_TEAM_NAME_LENGTH = 80
|
const MAX_TEAM_NAME_LENGTH = 80
|
||||||
|
|
||||||
|
function sri() {
|
||||||
|
return {
|
||||||
|
name: 'sri',
|
||||||
|
apply: 'build',
|
||||||
|
enforce: 'post',
|
||||||
|
transformIndexHtml: {
|
||||||
|
order: 'post',
|
||||||
|
handler(html, ctx) {
|
||||||
|
const bundle = ctx?.bundle
|
||||||
|
if (!bundle) return html
|
||||||
|
|
||||||
|
const hashFor = (fileName) => {
|
||||||
|
const asset = bundle[fileName]
|
||||||
|
if (!asset) return null
|
||||||
|
const source = asset.type === 'asset' ? asset.source : asset.code
|
||||||
|
const buf = Buffer.isBuffer(source) ? source : Buffer.from(source, 'utf8')
|
||||||
|
return `sha384-${crypto.createHash('sha384').update(buf).digest('base64')}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const tagPattern = /<(?:script|link)\b[^>]*\b(?:src|href)=["'](\/[^"']+)["'][^>]*>/g
|
||||||
|
return html.replace(tagPattern, (tag, url) => {
|
||||||
|
if (/\bintegrity=/.test(tag)) return tag
|
||||||
|
const fileName = url.replace(/^\//, '').split('?')[0].split('#')[0]
|
||||||
|
const integrity = hashFor(fileName)
|
||||||
|
if (!integrity) return tag
|
||||||
|
const closing = tag.endsWith('/>') ? ' />' : '>'
|
||||||
|
const body = tag.slice(0, -closing.length)
|
||||||
|
let out = `${body} integrity="${integrity}"`
|
||||||
|
if (!/\bcrossorigin\b/.test(tag)) out += ' crossorigin="anonymous"'
|
||||||
|
return `${out}${closing}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function isAllowedApiUrl(req) {
|
function isAllowedApiUrl(req) {
|
||||||
const url = new URL(req.url, 'http://localhost')
|
const url = new URL(req.url, 'http://localhost')
|
||||||
const params = url.searchParams
|
const params = url.searchParams
|
||||||
@@ -62,7 +137,7 @@ function apiGuard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [apiGuard(), react(), tailwindcss()],
|
plugins: [apiGuard(), react(), tailwindcss(), obfuscate(), sri()],
|
||||||
server: {
|
server: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
port: 3001,
|
port: 3001,
|
||||||
|
|||||||
Reference in New Issue
Block a user