fix: 新增学习账号密码最少六字节 (#2)

This commit is contained in:
ila
2026-09-10 20:10:14 +08:00
parent 722ae152ca
commit b7768c10de
7 changed files with 50 additions and 12 deletions
+3 -3
View File
@@ -1,7 +1,7 @@
export function normalizeUsername(value) { return value.trim().toLowerCase() }
export function validPassword(value) {
export function validPassword(value, minimum = 10) {
const bytes = new TextEncoder().encode(value).length
return bytes >= 10 && bytes <= 72
return bytes >= minimum && bytes <= 72
}
export function validUsername(value) { return /^[a-z][a-z0-9_.-]{2,31}$/.test(normalizeUsername(value)) }
export function createSession({ fetch, storage, changed = () => {} }) {
@@ -94,7 +94,7 @@ export function createSession({ fetch, storage, changed = () => {} }) {
async createAccount(username, password) {
authorized()
if (!validUsername(username)) throw new Error('账号须为 3–32 位,以字母开头,仅含字母、数字、点、下划线或短横线')
if (!validPassword(password)) throw new Error('密码须为 10–72 字节')
if (!validPassword(password, 6)) throw new Error('密码须为 6–72 字节')
return request('/accounts', 'POST', { username: normalizeUsername(username), password })
},
async updateAccount(id, patch) {
+1 -1
View File
@@ -17,7 +17,7 @@
<el-alert v-if="formError" :title="formError" type="error" :closable="false" />
<el-form :model="form" label-position="top" @submit.prevent="save">
<el-form-item v-if="!target" label="账号"><el-input v-model="form.username" autocomplete="off" maxlength="32" /><div class="hint">3–32 位,以字母开头;可含数字、点、下划线、短横线</div></el-form-item>
<el-form-item label="新密码"><el-input v-model="form.password" type="password" show-password autocomplete="new-password" /><div class="hint">10–72 字节;中文等字符会占多个字节</div></el-form-item>
<el-form-item label="新密码"><el-input v-model="form.password" type="password" show-password autocomplete="new-password" /><div class="hint">{{ target ? 10 : 6 }}–72 字节;中文等字符会占多个字节</div></el-form-item>
<div class="dialog-footer"><el-button :disabled="busy" @click="open = false">取消</el-button><el-button type="primary" native-type="submit" :loading="busy">保存</el-button></div>
</el-form>
</el-dialog>
+17
View File
@@ -15,6 +15,23 @@ test('normalizes account names and enforces UTF-8 password byte limits', () => {
assert.equal(validPassword('短'), false)
assert.equal(validPassword('虚'.repeat(25)), false)
})
test('creation accepts six bytes but rejects five and over 72; reset retains its minimum', async () => {
const writes = []
const { session } = setup(async (url, options) => {
if (url.endsWith('/login')) return response({ token: 'fictional-admin-token', user: admin })
writes.push(JSON.parse(options.body))
return response(learner)
})
await session.login(admin.username, 'fictional-password')
await assert.rejects(session.createAccount('fixture.new', 'z'.repeat(5)))
await assert.rejects(session.createAccount('fixture.new', 'z'.repeat(73)))
await session.createAccount('fixture.new', 'z'.repeat(6))
await session.createAccount('fixture.unicode', '虚构')
await session.createAccount('fixture.maximum', 'z'.repeat(72))
assert.equal(writes.length, 3)
await assert.rejects(session.updateAccount(learner.id, { password: 'z'.repeat(6) }))
})
test('learner login is rejected, revoked, and never stored in admin session', async () => {
const requests = []
const { session, data } = setup(async (url, options) => {