refactor: replace eval to validate valid function with ast parse

This commit is contained in:
Innei
2022-03-16 22:05:13 +08:00
parent 0791843882
commit b767d64288
4 changed files with 27 additions and 7 deletions

View File

@@ -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
View File

@@ -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

View File

@@ -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)
}
}
}

View File

@@ -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')
}