refactor: replace eval to validate valid function with ast parse
This commit is contained in:
@@ -66,6 +66,7 @@
|
||||
"@algolia/client-search": "*",
|
||||
"@babel/core": "7.17.7",
|
||||
"@babel/plugin-transform-typescript": "7.16.8",
|
||||
"@babel/types": "*",
|
||||
"@innei/class-validator-jsonschema": "3.1.1",
|
||||
"@nestjs/common": "8.4.1",
|
||||
"@nestjs/core": "8.4.1",
|
||||
@@ -131,6 +132,7 @@
|
||||
"zx": "4.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel__types@*": "link:@types/@babel__types@*",
|
||||
"@innei-util/eslint-config-ts": "0.5.0",
|
||||
"@innei-util/prettier": "0.4.1",
|
||||
"@nestjs/cli": "8.2.3",
|
||||
|
||||
4
pnpm-lock.yaml
generated
4
pnpm-lock.yaml
generated
@@ -9,6 +9,8 @@ specifiers:
|
||||
'@algolia/client-search': '*'
|
||||
'@babel/core': 7.17.7
|
||||
'@babel/plugin-transform-typescript': 7.16.8
|
||||
'@babel/types': '*'
|
||||
'@babel__types@*': link:@types/@babel__types@*
|
||||
'@innei-util/eslint-config-ts': 0.5.0
|
||||
'@innei-util/prettier': 0.4.1
|
||||
'@innei/class-validator-jsonschema': 3.1.1
|
||||
@@ -123,6 +125,7 @@ dependencies:
|
||||
'@algolia/client-search': 4.12.1
|
||||
'@babel/core': 7.17.7
|
||||
'@babel/plugin-transform-typescript': 7.16.8_@babel+core@7.17.7
|
||||
'@babel/types': 7.17.0
|
||||
'@innei/class-validator-jsonschema': 3.1.1_279461c9b8c03a205cdbc4878bc60cf8
|
||||
'@nestjs/common': 8.4.1_add13df2cdecb4b62cd3f7664ea82e18
|
||||
'@nestjs/core': 8.4.1_b4e0a43386936f36c413921c49aca7e6
|
||||
@@ -192,6 +195,7 @@ optionalDependencies:
|
||||
redis-memory-server: 0.5.0
|
||||
|
||||
devDependencies:
|
||||
'@babel__types@*': link:@types/@babel__types@*
|
||||
'@innei-util/eslint-config-ts': 0.5.0_typescript@4.6.2
|
||||
'@innei-util/prettier': 0.4.1
|
||||
'@nestjs/cli': 8.2.3
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import fs, { mkdir, stat } from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { nextTick } from 'process'
|
||||
import { transformAsync } from '@babel/core'
|
||||
import * as t from '@babel/types'
|
||||
import { parseAsync, transformAsync } from '@babel/core'
|
||||
import {
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
@@ -293,6 +294,7 @@ export class ServerlessService {
|
||||
const trustPackagePrefixes = ['@innei/', '@mx-space/', 'mx-function-']
|
||||
|
||||
if (
|
||||
isDev ||
|
||||
allowedThirdPartLibs.includes(id as any) ||
|
||||
trustPackagePrefixes.some((prefix) => id.startsWith(prefix))
|
||||
) {
|
||||
@@ -337,13 +339,21 @@ export class ServerlessService {
|
||||
async isValidServerlessFunction(raw: string) {
|
||||
try {
|
||||
// 验证 handler 是否存在并且是函数
|
||||
return safeEval(`
|
||||
${await this.convertTypescriptCode(raw)}
|
||||
return typeof handler === 'function'
|
||||
`)
|
||||
const ast = (await parseAsync(raw, {
|
||||
plugins: [require('@babel/plugin-transform-typescript')],
|
||||
})) as t.File
|
||||
|
||||
const { body } = ast.program as t.Program
|
||||
|
||||
const hasEntryFunction = body.some(
|
||||
(node) => t.isFunction(node) && node.id && node.id.name === 'handler',
|
||||
)
|
||||
return hasEntryFunction
|
||||
} catch (e) {
|
||||
console.error(e.message)
|
||||
return false
|
||||
if (isDev) {
|
||||
console.error(e.message)
|
||||
}
|
||||
return e.message?.split('\n').at(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,10 @@ export class SnippetService {
|
||||
const isValid = await this.serverlessService.isValidServerlessFunction(
|
||||
model.raw,
|
||||
)
|
||||
// if isValid is string, eq error message
|
||||
if (typeof isValid === 'string') {
|
||||
throw new BadRequestException(isValid)
|
||||
}
|
||||
if (!isValid) {
|
||||
throw new BadRequestException('serverless function is not valid')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user