feat: pageproxy debug mode
This commit is contained in:
@@ -73,6 +73,7 @@
|
||||
"dotenv": "*",
|
||||
"ejs": "3.1.6",
|
||||
"fastify-multipart": "5.0.0",
|
||||
"fastify-secure-session": "^2.3.1",
|
||||
"fastify-swagger": "4.12.0",
|
||||
"graphql": "15.5.3",
|
||||
"html-minifier": "4.0.0",
|
||||
|
||||
41
pnpm-lock.yaml
generated
41
pnpm-lock.yaml
generated
@@ -58,6 +58,7 @@ specifiers:
|
||||
eslint: '*'
|
||||
fastify: '*'
|
||||
fastify-multipart: 5.0.0
|
||||
fastify-secure-session: ^2.3.1
|
||||
fastify-swagger: 4.12.0
|
||||
graphql: 15.5.3
|
||||
html-minifier: 4.0.0
|
||||
@@ -137,6 +138,7 @@ dependencies:
|
||||
dotenv: 10.0.0
|
||||
ejs: 3.1.6
|
||||
fastify-multipart: 5.0.0
|
||||
fastify-secure-session: 2.3.1
|
||||
fastify-swagger: 4.12.0
|
||||
graphql: 15.5.3
|
||||
html-minifier: 4.0.0
|
||||
@@ -3390,6 +3392,11 @@ packages:
|
||||
safe-buffer: 5.1.2
|
||||
dev: true
|
||||
|
||||
/cookie-signature/1.1.0:
|
||||
resolution: {integrity: sha512-Alvs19Vgq07eunykd3Xy2jF0/qSNv2u7KDbAek9H5liV1UMijbqFs5cycZvv5dVsvseT/U4H8/7/w8Koh35C4A==}
|
||||
engines: {node: '>=6.6.0'}
|
||||
dev: false
|
||||
|
||||
/cookie/0.4.1:
|
||||
resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@@ -4169,6 +4176,14 @@ packages:
|
||||
fastify-plugin: 2.3.4
|
||||
dev: false
|
||||
|
||||
/fastify-cookie/5.3.1:
|
||||
resolution: {integrity: sha512-ubiC5ydvgqaXOydeg3G+SFEiTJtsyNPde6ForXi+UG66aDbsHlWNLJTQZg4BopXv+MJ0SzlShGVCWv26mgAwpw==}
|
||||
dependencies:
|
||||
cookie: 0.4.1
|
||||
cookie-signature: 1.1.0
|
||||
fastify-plugin: 3.0.0
|
||||
dev: false
|
||||
|
||||
/fastify-cors/6.0.2:
|
||||
resolution: {integrity: sha512-sE0AOyzmj5hLLRRVgenjA6G2iOGX35/1S3QGYB9rr9TXelMZB3lFrXy4CzwYVOMiujJeMiLgO4J7eRm8sQSv8Q==}
|
||||
dependencies:
|
||||
@@ -4207,6 +4222,15 @@ packages:
|
||||
resolution: {integrity: sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w==}
|
||||
dev: false
|
||||
|
||||
/fastify-secure-session/2.3.1:
|
||||
resolution: {integrity: sha512-6XsatyRSiX0UQB0MOPlU/PC9yn3seImefS1yv8C0bAyjAJ876839eHKPrclwNKBVX+9SUX+LdJGJTBi8DSU63g==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
fastify-cookie: 5.3.1
|
||||
fastify-plugin: 3.0.0
|
||||
sodium-native: 3.2.1
|
||||
dev: false
|
||||
|
||||
/fastify-static/4.2.3:
|
||||
resolution: {integrity: sha512-uFRgwYXZwLKyaMrByf10efO+HTjAPqyQOlUthoGljQKGCfbwUeTeE7EHadsDWeN7NMeqBE617RamVh9uqatuUw==}
|
||||
dependencies:
|
||||
@@ -4836,6 +4860,10 @@ packages:
|
||||
/inherits/2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
||||
/ini/1.3.8:
|
||||
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
|
||||
dev: false
|
||||
|
||||
/inquirer/7.3.3:
|
||||
resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
@@ -6447,6 +6475,11 @@ packages:
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
dev: false
|
||||
|
||||
/node-gyp-build/4.3.0:
|
||||
resolution: {integrity: sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/node-int64/0.4.0:
|
||||
resolution: {integrity: sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=}
|
||||
dev: true
|
||||
@@ -7581,6 +7614,14 @@ packages:
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
/sodium-native/3.2.1:
|
||||
resolution: {integrity: sha512-EgDZ/Z7PxL2kCasKk7wnRkV8W9kvwuIlHuHXAxkQm3FF0MgVsjyLBXGjSRGhjE6u7rhSpk3KaMfFM23bfMysIQ==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
ini: 1.3.8
|
||||
node-gyp-build: 4.3.0
|
||||
dev: false
|
||||
|
||||
/sonic-boom/1.4.1:
|
||||
resolution: {integrity: sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==}
|
||||
dependencies:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
import { argv } from 'yargs'
|
||||
|
||||
import yargs from 'yargs'
|
||||
const argv = yargs.argv as any
|
||||
console.log(argv)
|
||||
|
||||
export const API_VERSION = 2
|
||||
@@ -47,4 +47,9 @@ export const SECURITY = {
|
||||
jwtExpire: '7d',
|
||||
// 跳过登陆鉴权
|
||||
skipAuth: argv.skipAuth ?? false,
|
||||
get secret() {
|
||||
return this.jwtSecret
|
||||
},
|
||||
// 必须 16 位
|
||||
salt: argv.salt || 'axczswrasxzfqxsa',
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { FastifyAdapter } from '@nestjs/platform-fastify'
|
||||
import FastifyMultipart from 'fastify-multipart'
|
||||
export const fastifyApp: FastifyAdapter = new FastifyAdapter({
|
||||
import secureSession from 'fastify-secure-session'
|
||||
import { SECURITY } from '~/app.config'
|
||||
|
||||
const app: FastifyAdapter = new FastifyAdapter({
|
||||
trustProxy: true,
|
||||
})
|
||||
export { app as fastifyApp }
|
||||
|
||||
fastifyApp.register(FastifyMultipart, {
|
||||
app.register(FastifyMultipart, {
|
||||
limits: {
|
||||
fields: 10, // Max number of non-file fields
|
||||
fileSize: 1024 * 1024 * 6, // limit size 6M
|
||||
@@ -12,7 +16,7 @@ fastifyApp.register(FastifyMultipart, {
|
||||
},
|
||||
})
|
||||
|
||||
fastifyApp.getInstance().addHook('onRequest', (request, reply, done) => {
|
||||
app.getInstance().addHook('onRequest', (request, reply, done) => {
|
||||
const origin = request.headers.origin
|
||||
if (!origin) {
|
||||
request.headers.origin = request.headers.host
|
||||
@@ -20,3 +24,12 @@ fastifyApp.getInstance().addHook('onRequest', (request, reply, done) => {
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
app.register(secureSession, {
|
||||
secret: SECURITY.secret.slice(10).repeat(4),
|
||||
salt: SECURITY.salt,
|
||||
cookie: {
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Controller, Get, Header } from '@nestjs/common'
|
||||
import { Controller, Get, Header, Query, Session } from '@nestjs/common'
|
||||
import * as secureSession from 'fastify-secure-session'
|
||||
import { API_VERSION } from '~/app.config'
|
||||
import { HTTPDecorators } from '~/common/decorator/http.decorator'
|
||||
import { ApiName } from '~/common/decorator/openapi.decorator'
|
||||
@@ -7,6 +8,7 @@ import { CacheService } from '~/processors/cache/cache.service'
|
||||
import { getRedisKey } from '~/utils/redis.util'
|
||||
import { ConfigsService } from '../configs/configs.service'
|
||||
import { InitService } from '../init/init.service'
|
||||
import { PageProxyDebugDto } from './pageproxy.dto'
|
||||
|
||||
interface IInjectableData {
|
||||
BASE_API: null | string
|
||||
@@ -30,7 +32,10 @@ export class PageProxyController {
|
||||
@Get('/qaqdmin')
|
||||
@Header('Content-Type', 'text/html')
|
||||
@HTTPDecorators.Bypass
|
||||
async proxyAdmin() {
|
||||
async proxyAdmin(
|
||||
@Session() session: secureSession.Session,
|
||||
@Query() query: PageProxyDebugDto,
|
||||
) {
|
||||
const {
|
||||
adminExtra,
|
||||
url: { webUrl },
|
||||
@@ -38,24 +43,57 @@ export class PageProxyController {
|
||||
if (!adminExtra.enableAdminProxy && !isDev) {
|
||||
return '<h1>Admin Proxy is disabled</h1>'
|
||||
}
|
||||
const {
|
||||
__apiUrl: apiUrl,
|
||||
__gatewayUrl: gatewayUrl,
|
||||
__onlyGithub: onlyGithub,
|
||||
__debug: debug,
|
||||
} = query
|
||||
session.options({ maxAge: 1000 * 60 * 10 })
|
||||
if (apiUrl) {
|
||||
session.set('__apiUrl', apiUrl)
|
||||
}
|
||||
|
||||
if (gatewayUrl) {
|
||||
session.set('__gatewayUrl', gatewayUrl)
|
||||
}
|
||||
|
||||
if (debug === false) {
|
||||
session.delete()
|
||||
}
|
||||
|
||||
let entry =
|
||||
(await this.cacheService.get<string>(getRedisKey(RedisKeys.AdminPage))) ||
|
||||
(!onlyGithub &&
|
||||
(await this.cacheService.get<string>(
|
||||
getRedisKey(RedisKeys.AdminPage),
|
||||
))) ||
|
||||
(await (async () => {
|
||||
const indexEntryUrl = `https://raw.githubusercontent.com/mx-space/admin-next/gh-pages/index.html`
|
||||
const indexEntryCdnUrl = `https://cdn.jsdelivr.net/gh/mx-space/admin-next@gh-pages/index.html?t=${+new Date()}`
|
||||
return await Promise.any([
|
||||
const tasks = [
|
||||
// 龟兔赛跑, 乌龟先跑
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
fetch(indexEntryUrl).then((res) => res.text()),
|
||||
sleep(1000).then(async () => (await fetch(indexEntryCdnUrl)).text()),
|
||||
])
|
||||
]
|
||||
if (!onlyGithub) {
|
||||
tasks.push(
|
||||
sleep(1000).then(async () =>
|
||||
(await fetch(indexEntryCdnUrl)).text(),
|
||||
),
|
||||
)
|
||||
}
|
||||
return await Promise.any(tasks)
|
||||
})())
|
||||
|
||||
await this.cacheService.set(getRedisKey(RedisKeys.AdminPage), entry, {
|
||||
ttl: 10 * 60,
|
||||
})
|
||||
|
||||
const sessionInjectableData = {
|
||||
BASE_API: session.get('__apiUrl'),
|
||||
GATEWAY: session.get('__gatewayUrl'),
|
||||
}
|
||||
|
||||
entry = entry.replace(
|
||||
`<!-- injectable script -->`,
|
||||
`<script>${`window.injectData = ${JSON.stringify({
|
||||
@@ -64,10 +102,18 @@ export class PageProxyController {
|
||||
WEB_URL: webUrl,
|
||||
INIT: await this.initService.isInit(),
|
||||
} as IInjectableData)}`}
|
||||
window.injectData.BASE_API = location.origin + '${
|
||||
!isDev ? '/api/v' + API_VERSION : ''
|
||||
}';
|
||||
window.injectData.GATEWAY = location.origin;
|
||||
${
|
||||
sessionInjectableData.BASE_API
|
||||
? `window.injectData.BASE_API = '${sessionInjectableData.BASE_API}'`
|
||||
: `window.injectData.BASE_API = location.origin + '${
|
||||
!isDev ? '/api/v' + API_VERSION : ''
|
||||
}';`
|
||||
}
|
||||
${
|
||||
sessionInjectableData.GATEWAY
|
||||
? `window.injectData.GATEWAY = '${sessionInjectableData.GATEWAY}';`
|
||||
: `window.injectData.GATEWAY = location.origin;`
|
||||
}
|
||||
</script>`,
|
||||
)
|
||||
return entry
|
||||
|
||||
24
src/modules/pageproxy/pageproxy.dto.ts
Normal file
24
src/modules/pageproxy/pageproxy.dto.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Transform } from 'class-transformer'
|
||||
import { IsBoolean, IsIn, IsOptional, IsUrl } from 'class-validator'
|
||||
|
||||
export class PageProxyDebugDto {
|
||||
@IsIn([false])
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => (value === 'false' ? false : true))
|
||||
__debug: boolean
|
||||
@IsUrl({ require_protocol: true })
|
||||
@IsOptional()
|
||||
__apiUrl?: string
|
||||
|
||||
@IsUrl({ require_protocol: true })
|
||||
@IsOptional()
|
||||
__gatewayUrl?: string
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => (value === 'true' ? true : false))
|
||||
/**
|
||||
* If true, always use index.html pull from github.
|
||||
*/
|
||||
__onlyGithub = false
|
||||
}
|
||||
Reference in New Issue
Block a user