补齐控制器测试中的会话与安全版本上下文,更新Telegram用户配置协议及前端回归断言。
This commit is contained in:
parent
11000e8953
commit
314a2d53d2
@ -54,15 +54,21 @@ func TestEditUserPasswordResetRoleMatrix(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
superContext := &appcontext.Context{UserID: superAdmin.ID, UserAccount: superAdmin.Account, Role: access.RoleSuperAdmin, RecentAuth: true, RecoveryCodeConfigured: true, Lang: "zhCn"}
|
||||
adminContext := &appcontext.Context{UserID: admin.ID, UserAccount: admin.Account, Role: access.RoleAdmin, RecentAuth: true, RecoveryCodeConfigured: true, Lang: "zhCn"}
|
||||
userContext := &appcontext.Context{UserID: user.ID, UserAccount: user.Account, Role: access.RoleUser, RecentAuth: true, RecoveryCodeConfigured: true, Lang: "zhCn"}
|
||||
superContext := &appcontext.Context{UserID: superAdmin.ID, SessionVersion: superAdmin.SessionVersion, SecurityVersion: superAdmin.SecurityVersion, UserAccount: superAdmin.Account, Role: access.RoleSuperAdmin, RecentAuth: true, RecoveryCodeConfigured: true, Lang: "zhCn"}
|
||||
adminContext := &appcontext.Context{UserID: admin.ID, SessionVersion: admin.SessionVersion, SecurityVersion: admin.SecurityVersion, UserAccount: admin.Account, Role: access.RoleAdmin, RecentAuth: true, RecoveryCodeConfigured: true, Lang: "zhCn"}
|
||||
userContext := &appcontext.Context{UserID: user.ID, SessionVersion: user.SessionVersion, SecurityVersion: user.SecurityVersion, UserAccount: user.Account, Role: access.RoleUser, RecentAuth: true, RecoveryCodeConfigured: true, Lang: "zhCn"}
|
||||
|
||||
if result := editUserRequest(t, superContext, `{"id":`+itoa(admin.ID)+`,"password":"ResetAdm12","disabled":0}`); result != 0 {
|
||||
t.Fatalf("super administrator could not reset administrator: %d", result)
|
||||
}
|
||||
assertUserPassword(t, admin.ID, "ResetAdm12")
|
||||
|
||||
if _, err := db.Instance.ID(admin.ID).Get(&admin); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
adminContext.SessionVersion = admin.SessionVersion
|
||||
adminContext.SecurityVersion = admin.SecurityVersion
|
||||
|
||||
if result := editUserRequest(t, adminContext, `{"id":`+itoa(user.ID)+`,"password":"ResetUser123","disabled":0}`); result != 0 {
|
||||
t.Fatalf("administrator could not reset regular user: %d", result)
|
||||
}
|
||||
@ -159,7 +165,7 @@ func TestPasswordChangeRevokesOfflineCredentialsAtomically(t *testing.T) {
|
||||
|
||||
func newControllerTestUser(t *testing.T, account, name string, role access.Role, plainPassword string) models.User {
|
||||
t.Helper()
|
||||
user := models.User{Account: account, Name: name, Role: string(role), SessionVersion: 1}
|
||||
user := models.User{Account: account, Name: name, Role: string(role), SessionVersion: 1, SecurityVersion: 1}
|
||||
user.ApplyRole(role)
|
||||
if err := auth.SetPassword(&user, plainPassword); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@ -37,7 +37,7 @@ func TestEditUserProtectsAdministrativeCredentialsAndRevokesUserSessions(t *test
|
||||
if err := db.Init(""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
admin := models.User{Account: "admin-user", Name: "Admin", IsAdmin: 1, SessionVersion: 1}
|
||||
admin := models.User{Account: "admin-user", Name: "Admin", IsAdmin: 1, SessionVersion: 1, SecurityVersion: 1}
|
||||
if err := auth.SetPassword(&admin, "AdminPass123"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -49,7 +49,8 @@ func TestEditUserProtectsAdministrativeCredentialsAndRevokesUserSessions(t *test
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx := &appcontext.Context{
|
||||
UserID: admin.ID, UserAccount: admin.Account, IsAdmin: true, Lang: "zhCn",
|
||||
UserID: admin.ID, SessionVersion: admin.SessionVersion, SecurityVersion: admin.SecurityVersion,
|
||||
UserAccount: admin.Account, IsAdmin: true, Lang: "zhCn",
|
||||
RecentAuth: true, RecoveryCodeConfigured: true,
|
||||
}
|
||||
|
||||
@ -268,7 +269,8 @@ func TestManagedRecoveryCodesAreScopedAndShownOnce(t *testing.T) {
|
||||
}
|
||||
ConfigureSecurityRuntime(nil, nil, nil, credentialService)
|
||||
ctx := &appcontext.Context{
|
||||
UserID: actor.ID, UserAccount: actor.Account, Role: access.RoleSuperAdmin, RecentAuth: true,
|
||||
UserID: actor.ID, SessionVersion: actor.SessionVersion, SecurityVersion: actor.SecurityVersion,
|
||||
UserAccount: actor.Account, Role: access.RoleSuperAdmin, RecentAuth: true,
|
||||
}
|
||||
|
||||
generateRecorder := httptest.NewRecorder()
|
||||
@ -405,10 +407,12 @@ func TestManagedExternalEmailChangeInvalidatesPreviousChallenge(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := &appcontext.Context{
|
||||
UserID: actor.ID,
|
||||
UserAccount: actor.Account,
|
||||
Role: access.RoleSuperAdmin,
|
||||
RecentAuth: true,
|
||||
UserID: actor.ID,
|
||||
SessionVersion: actor.SessionVersion,
|
||||
SecurityVersion: actor.SecurityVersion,
|
||||
UserAccount: actor.Account,
|
||||
Role: access.RoleSuperAdmin,
|
||||
RecentAuth: true,
|
||||
}
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(
|
||||
|
||||
@ -275,7 +275,7 @@ export function useTelegramSettings() {
|
||||
})
|
||||
return {
|
||||
settings, status, binding, ready, working, errorMessage, bindingError,
|
||||
dialogVisible, polling, hasChanges, bindingLabel, refresh, submit,
|
||||
dialogVisible, polling, hasChanges, bindingLabel, load, refresh, submit,
|
||||
beginBinding, confirmBinding, closeBinding, poll, beforeLeave
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,48 +8,76 @@ import { computed, reactive, ref } from './vue.mjs'
|
||||
const root = new URL('../../frontend/src/views/components/PluginSettings/', import.meta.url)
|
||||
const source = readFileSync(new URL('TelegramSettings/TelegramSettings.js', root), 'utf8')
|
||||
const create = compileFunction(source.replace(/^import .*$/gm, '').replace('export function ', 'function ') + '\nreturn useTelegramSettings()',
|
||||
['computed', 'onMounted', 'onBeforeUnmount', 'reactive', 'ref', 'ElMessage', 'http', 'ElMessageBox'])
|
||||
['computed', 'onMounted', 'onBeforeUnmount', 'reactive', 'ref', 'ElMessage', 'ElMessageBox', 'QRCode', 'http', 'isRecentAuthenticationCancelled', 'requestWithRecentAuthentication'])
|
||||
const createPage = (http, confirm = async () => {}) => create(
|
||||
computed,
|
||||
() => {},
|
||||
() => {},
|
||||
reactive,
|
||||
ref,
|
||||
{ success() {} },
|
||||
{ confirm },
|
||||
{ toDataURL: async () => '' },
|
||||
http,
|
||||
() => false,
|
||||
request => request()
|
||||
)
|
||||
const userSettings = (overrides = {}) => ({
|
||||
version: 7,
|
||||
bound: true,
|
||||
displayName: 'smail_test_user',
|
||||
needsRebind: false,
|
||||
available: true,
|
||||
message: '',
|
||||
enabled: false,
|
||||
showContent: false,
|
||||
spoilerContent: false,
|
||||
sendAttachments: false,
|
||||
disableLinkPreview: true,
|
||||
...overrides
|
||||
})
|
||||
|
||||
test('Telegram 原生设置保留版本、限制用户字段,不依赖插件 iframe', async () => {
|
||||
const requests = []
|
||||
let conflict = false
|
||||
const page = create(computed, () => {}, () => {}, reactive, ref, { success() {} }, {
|
||||
get: async url => ({ errorNo: 0, data: url.endsWith('/bot') ? { username: 'smail_test_bot', botLink: 'javascript:alert(1)' }
|
||||
: { version: 7, settings: { chatId: '123', sendAttachments: false, secret: '不得传回' } } }),
|
||||
const page = createPage({
|
||||
get: async () => ({ errorNo: 0, data: userSettings() }),
|
||||
put: async (url, body) => {
|
||||
requests.push({ url, body })
|
||||
return conflict ? { errorNo: 400, errorMsg: '配置已被其他操作更新,请刷新后重试' }
|
||||
: { errorNo: 0, data: { version: 8, settings: body.settings } }
|
||||
return conflict
|
||||
? { errorNo: 400, errorMsg: '配置已被其他操作更新,请刷新后重试' }
|
||||
: { errorNo: 0, data: userSettings({ ...body, version: 8, synced: true, secret: '不应返回' }) }
|
||||
},
|
||||
post: async (url, body) => { requests.push({ url, body }); return { errorNo: 0 } }
|
||||
post: async (url, body) => {
|
||||
requests.push({ url, body })
|
||||
return { errorNo: 0, data: {} }
|
||||
}
|
||||
})
|
||||
await page.load()
|
||||
assert.equal(page.ready.value, true)
|
||||
assert.equal(page.botLink.value, 'https://t.me/smail_test_bot')
|
||||
assert.equal(page.status.bound, true)
|
||||
assert.equal(page.status.displayName, 'smail_test_user')
|
||||
page.settings.sendAttachments = true
|
||||
await page.submit('save')
|
||||
assert.equal(requests[0].body.version, 7)
|
||||
assert.deepEqual(Object.keys(requests[0].body.settings).sort(), ['chatId', 'disableLinkPreview', 'sendAttachments', 'showContent', 'spoilerContent'])
|
||||
assert.equal(page.version.value, 8)
|
||||
assert.deepEqual(Object.keys(requests[0].body).sort(), [
|
||||
'disableLinkPreview', 'enabled', 'sendAttachments', 'showContent', 'spoilerContent', 'version'
|
||||
])
|
||||
assert.equal(page.settings.secret, undefined)
|
||||
await page.submit('test')
|
||||
assert.equal(requests[1].url, '/api/v1/plugin/settings/telegram_push/test')
|
||||
assert.equal(page.version.value, 8)
|
||||
assert.equal(requests[1].body, undefined)
|
||||
conflict = true
|
||||
await page.submit('save')
|
||||
assert.match(page.errorMessage.value, /刷新/)
|
||||
assert.equal(page.version.value, 8)
|
||||
const count = requests.length
|
||||
page.settings.chatId = 'invalid'
|
||||
await page.submit('test')
|
||||
assert.equal(requests.length, count)
|
||||
assert.notEqual(page.errorMessage.value, '')
|
||||
})
|
||||
|
||||
test('Telegram 首次读取失败禁止覆盖存量设置,机器人故障不影响停用', async () => {
|
||||
let fail = true
|
||||
const page = create(computed, () => {}, () => {}, reactive, ref, { success() {} }, {
|
||||
get: async url => {
|
||||
if (fail || url.endsWith('/bot')) throw new Error('模拟离线')
|
||||
return { errorNo: 0, data: { version: 0, settings: {} } }
|
||||
const page = createPage({
|
||||
get: async () => {
|
||||
if (fail) throw new Error('模拟离线')
|
||||
return { errorNo: 0, data: userSettings({ version: 0, bound: false, available: false, displayName: '' }) }
|
||||
},
|
||||
put: async () => assert.fail('读取失败后不能保存')
|
||||
})
|
||||
@ -59,14 +87,14 @@ test('Telegram 首次读取失败禁止覆盖存量设置,机器人故障不
|
||||
fail = false
|
||||
await page.load()
|
||||
assert.equal(page.ready.value, true)
|
||||
assert.equal(page.botLink.value, '')
|
||||
assert.equal(page.status.bound, false)
|
||||
})
|
||||
|
||||
test('Telegram 模板独立编译,其他插件继续保持 sandbox 隔离', () => {
|
||||
const require = createRequire(new URL('../../frontend/package.json', import.meta.url))
|
||||
const { parse, compileScript, compileStyle } = require('@vue/compiler-sfc')
|
||||
const parent = readFileSync(new URL('PluginSettings.vue', root), 'utf8')
|
||||
assert.match(parent, /TelegramSettings v-else-if="activePage\?\.kind === 'account'"/)
|
||||
assert.match(parent, /TelegramSettings\s+v-else-if="activePage\?\.value === 'telegram-user'"/)
|
||||
assert.match(parent, /sandbox="allow-scripts"/)
|
||||
assert.doesNotMatch(parent, /allow-same-origin/)
|
||||
const { descriptor, errors } = parse(readFileSync(new URL('TelegramSettings/TelegramSettings.vue', root), 'utf8'))
|
||||
@ -80,22 +108,24 @@ test('Telegram 通知编辑在切页和重新加载前确认,取消保留输
|
||||
let cancel = true
|
||||
let reads = 0
|
||||
let prompts = 0
|
||||
const page = create(computed, () => {}, () => {}, reactive, ref, { success() {} }, {
|
||||
get: async url => {
|
||||
const page = createPage({
|
||||
get: async () => {
|
||||
reads++
|
||||
return { errorNo: 0, data: url.endsWith('/bot') ? {} : { version: 1, settings: { chatId: '123' } } }
|
||||
return { errorNo: 0, data: userSettings({ version: 1, showContent: false }) }
|
||||
},
|
||||
put: async (url, body) => ({ errorNo: 0, data: { version: 2, settings: body.settings } })
|
||||
put: async (url, body) => ({ errorNo: 0, data: userSettings({ ...body, version: 2, synced: true }) })
|
||||
}, { confirm: async () => { prompts++; if (cancel) throw new Error('取消') } })
|
||||
await page.load()
|
||||
assert.equal(await page.beforeLeave(), true)
|
||||
page.settings.chatId = '456'
|
||||
page.settings.showContent = true
|
||||
assert.equal(await page.beforeLeave(), false)
|
||||
await page.refresh()
|
||||
assert.equal(reads, 2)
|
||||
assert.equal(page.settings.chatId, '456')
|
||||
assert.equal(reads, 1)
|
||||
assert.equal(page.settings.showContent, true)
|
||||
cancel = false
|
||||
assert.equal(await page.beforeLeave(), true)
|
||||
await page.refresh()
|
||||
assert.equal(reads, 2)
|
||||
assert.equal(page.settings.showContent, false)
|
||||
await page.submit('save')
|
||||
assert.equal(page.hasChanges.value, false)
|
||||
const count = prompts
|
||||
@ -103,4 +133,4 @@ test('Telegram 通知编辑在切页和重新加载前确认,取消保留输
|
||||
assert.equal(prompts, count)
|
||||
page.working.value = 'save'
|
||||
assert.equal(await page.beforeLeave(), false)
|
||||
})
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user