feat: add auth gate and Chinese command parsing
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
export function isAuthorized(opts: {
|
||||||
|
allowAllUsers: boolean
|
||||||
|
allowedUserIds: number[]
|
||||||
|
userId?: number
|
||||||
|
}): boolean {
|
||||||
|
if (opts.allowAllUsers) return true
|
||||||
|
if (opts.userId === undefined) return false
|
||||||
|
return opts.allowedUserIds.includes(opts.userId)
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
export const MSG = {
|
||||||
|
DENIED: '无权限。',
|
||||||
|
WELCOME:
|
||||||
|
'你好,我是 DeepSeek Harness 渠道机器人。直接发消息开始对话,或发送 /help 查看命令。',
|
||||||
|
HELP: [
|
||||||
|
'/start — 开始 / 欢迎',
|
||||||
|
'/new 或 /clear — 新开会话',
|
||||||
|
'/help — 显示帮助',
|
||||||
|
'',
|
||||||
|
'仅白名单用户可对话;会话在内存中,重启 Harness 后需重新发消息建立。',
|
||||||
|
].join('\n'),
|
||||||
|
NEW_SESSION: '已开启新会话。',
|
||||||
|
unknown(command: string): string {
|
||||||
|
return `未知命令 ${command}。发送 /help 查看可用命令。`
|
||||||
|
},
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type ParsedCommand =
|
||||||
|
| { type: 'start'; text: string }
|
||||||
|
| { type: 'help'; text: string }
|
||||||
|
| { type: 'new'; text: string }
|
||||||
|
| { type: 'unknown'; command: string; text: string }
|
||||||
|
| { type: 'plain'; text: string }
|
||||||
|
|
||||||
|
export function parseCommand(text: string): ParsedCommand {
|
||||||
|
if (!text.startsWith('/')) return { type: 'plain', text }
|
||||||
|
const command = text.split(/\s+/)[0] ?? text
|
||||||
|
switch (command) {
|
||||||
|
case '/start':
|
||||||
|
return { type: 'start', text }
|
||||||
|
case '/help':
|
||||||
|
return { type: 'help', text }
|
||||||
|
case '/new':
|
||||||
|
case '/clear':
|
||||||
|
return { type: 'new', text }
|
||||||
|
default:
|
||||||
|
return { type: 'unknown', command, text }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import test from 'node:test'
|
||||||
|
import { isAuthorized } from '../src/auth.ts'
|
||||||
|
|
||||||
|
test('empty allowlist rejects even with userId', () => {
|
||||||
|
assert.equal(isAuthorized({ allowAllUsers: false, allowedUserIds: [], userId: 1 }), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('allowAllUsers accepts missing userId', () => {
|
||||||
|
assert.equal(isAuthorized({ allowAllUsers: true, allowedUserIds: [], userId: undefined }), true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('allowlist match', () => {
|
||||||
|
assert.equal(isAuthorized({ allowAllUsers: false, allowedUserIds: [42], userId: 42 }), true)
|
||||||
|
assert.equal(isAuthorized({ allowAllUsers: false, allowedUserIds: [42], userId: 7 }), false)
|
||||||
|
})
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import test from 'node:test'
|
||||||
|
import { MSG, parseCommand } from '../src/commands.ts'
|
||||||
|
|
||||||
|
test('parse slash commands', () => {
|
||||||
|
assert.equal(parseCommand('/start').type, 'start')
|
||||||
|
assert.equal(parseCommand('/help extra').type, 'help')
|
||||||
|
assert.equal(parseCommand('/new').type, 'new')
|
||||||
|
assert.equal(parseCommand('/clear').type, 'new')
|
||||||
|
assert.equal(parseCommand('/foo').type, 'unknown')
|
||||||
|
assert.equal(parseCommand('hello').type, 'plain')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Chinese copy is non-empty', () => {
|
||||||
|
assert.ok(MSG.DENIED.includes('权限') || MSG.DENIED.includes('授权'))
|
||||||
|
assert.ok(MSG.HELP.includes('/new'))
|
||||||
|
assert.ok(MSG.WELCOME.length > 0)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user