feat: terminal password support

This commit is contained in:
Innei
2022-02-10 21:44:57 +08:00
parent 64ba19851d
commit f20945c27e
6 changed files with 51 additions and 12 deletions

View File

@@ -8,12 +8,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter'
import { DocumentType, ReturnModelType } from '@typegoose/typegoose'
import { BeAnObject } from '@typegoose/typegoose/lib/types'
import camelcaseKeys from 'camelcase-keys'
import {
ClassConstructor,
instanceToPlain,
plainToClass,
plainToInstance,
} from 'class-transformer'
import { ClassConstructor, plainToInstance } from 'class-transformer'
import { validateSync, ValidatorOptions } from 'class-validator'
import cluster from 'cluster'
import { cloneDeep, mergeWith } from 'lodash'
@@ -145,7 +140,7 @@ export class ConfigsService {
return new Promise((resolve, reject) => {
this.waitForConfigReady()
.then((config) => {
resolve(instanceToPlain(config[key]) as any)
resolve(config[key])
})
.catch(reject)
})
@@ -250,7 +245,7 @@ export class ConfigsService {
}
private validWithDto<T extends object>(dto: ClassConstructor<T>, value: any) {
const validModel = plainToClass(dto, value)
const validModel = plainToInstance(dto, value)
const errors = validateSync(validModel, this.validOptions)
if (errors.length > 0) {
const error = this.validate.createExceptionFactory()(errors as any[])

View File

@@ -49,7 +49,7 @@ export class OptionController {
if (!value) {
throw new BadRequestException('key is not exists.')
}
return { data: value }
return { data: instanceToPlain(value) }
}
@Patch('/:key')

View File

@@ -9,11 +9,13 @@ import {
WebSocketServer,
} from '@nestjs/websockets'
import { Emitter } from '@socket.io/redis-emitter'
import { isNil } from 'lodash'
import { IPty, spawn } from 'node-pty'
import { resolve } from 'path'
import SocketIO, { Socket } from 'socket.io'
import { EventBusEvents } from '~/constants/event.constant'
import { LOG_DIR } from '~/constants/path.constant'
import { ConfigsService } from '~/modules/configs/configs.service'
import { CacheService } from '~/processors/cache/cache.service'
import { getTodayLogFilePath } from '~/utils/consola.util'
import { AuthService } from '../../../modules/auth/auth.service'
@@ -29,6 +31,7 @@ export class AdminEventsGateway
private readonly jwtService: JwtService,
private readonly authService: AuthService,
private readonly cacheService: CacheService,
private readonly configService: ConfigsService,
) {
super()
}
@@ -118,7 +121,45 @@ export class AdminEventsGateway
socket2ptyMap = new WeakMap<Socket, IPty>()
@SubscribeMessage('pty')
async pty(client: Socket, data?: { cols: number; rows: number }) {
async pty(
client: Socket,
data?: { password?: string; cols: number; rows: number },
) {
const password = data?.password
const terminalOptions = await this.configService.get('terminalOptions')
if (!terminalOptions.enable) {
client.send(
this.gatewayMessageFormat(EventTypes.PTY_MESSAGE, 'PTY 已禁用'),
)
return
}
const isValidPassword = isNil(terminalOptions.password)
? true
: password === terminalOptions.password
if (!isValidPassword) {
if (typeof password === 'undefined' || password === '') {
client.send(
this.gatewayMessageFormat(
EventTypes.PTY_MESSAGE,
'PTY 验证未通过:需要密码验证',
10000,
),
)
} else {
client.send(
this.gatewayMessageFormat(
EventTypes.PTY_MESSAGE,
'PTY 验证未通过:密码错误',
10001,
),
)
}
return
}
const zsh = await nothrow($`zsh --version`)
const pty = spawn(

View File

@@ -2,10 +2,11 @@ import { Socket } from 'socket.io'
import { EventTypes } from './events.types'
export abstract class BaseGateway {
public gatewayMessageFormat(type: EventTypes, message: any) {
public gatewayMessageFormat(type: EventTypes, message: any, code?: number) {
return {
type,
data: message,
code,
}
}

View File

@@ -42,6 +42,7 @@ export enum EventTypes {
STDOUT = 'STDOUT',
PTY = 'pty',
PTY_MESSAGE = 'pty_message',
}
export type NotificationTypes = 'error' | 'warn' | 'success' | 'info'

View File

@@ -53,7 +53,8 @@ describe('Test ConfigsService', () => {
const config = await service.getConfig()
expect(config).toBeDefined()
expect(config).toStrictEqual(service.defaultConfig)
// use `toEqual` instead of `toStrictEqual` baseuse config is InstanceType of IConfig
expect(config).toEqual(service.defaultConfig)
})
describe('patch config should apply change between db and redis', () => {