fix: 新增学习账号密码最少六字节 (#2)
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user