Add network protection and administrator account support
This commit is contained in:
@@ -148,10 +148,10 @@ try {
|
||||
await admin.getByRole('menuitem', { name: '관리자', exact: true }).click();
|
||||
await admin.locator('.admin-stats').waitFor();
|
||||
await admin.locator('.admin-file').filter({ hasText: 'sample.mp4' }).waitFor();
|
||||
assert.match(await admin.locator('.admin-file').innerText(), /중국 · Beijing/);
|
||||
assert.match(await admin.locator('.admin-file').innerText(), /중국\(CN\) · Beijing/);
|
||||
assert.match(await admin.locator('.admin-file').innerText(), /1\.1\.1\.1/);
|
||||
assert.match(await admin.locator('.admin-file-info').first().innerText(), /^\[.+\]\s+guest-/);
|
||||
assert.match(await admin.locator('.admin-file').innerText(), /접속 지역 · 중국 · Beijing/);
|
||||
assert.match(await admin.locator('.admin-file').innerText(), /접속 지역 · 중국\(CN\) · Beijing/);
|
||||
assert.doesNotMatch(await admin.locator('.admin-file').innerText(), /최근 접속/);
|
||||
assert.match(
|
||||
await admin.locator('.admin-file footer small').innerText(),
|
||||
@@ -162,7 +162,7 @@ try {
|
||||
assert.equal(runtime.service.admin.state.uploadsPaused, true);
|
||||
await admin.getByRole('button', { name: '업로드 재개', exact: true }).click();
|
||||
await admin.getByText('신규 업로드 허용 중', { exact: true }).waitFor();
|
||||
await admin.getByRole('button', { name: '접속 · 용량 설정', exact: true }).click();
|
||||
await admin.getByRole('button', { name: '용량 설정', exact: true }).click();
|
||||
assert.match(
|
||||
await admin.locator('.admin-limit-details').innerText(),
|
||||
/로그인 보관함[\s\S]*계정당 2\.1GB/,
|
||||
@@ -180,12 +180,55 @@ try {
|
||||
);
|
||||
await admin.getByLabel('동시에 처리할 업로드 수').fill('3');
|
||||
await admin.getByLabel('전체 파일 저장 한도 (GB)').fill('16');
|
||||
await admin.getByLabel('차단할 국가 코드').fill('CN');
|
||||
await admin.getByLabel('차단할 IP 또는 IP 대역').fill('9.9.9.0/24');
|
||||
await admin.getByRole('button', { name: '설정 저장', exact: true }).click();
|
||||
await admin.getByText('관리 설정을 저장했어요.', { exact: true }).waitFor();
|
||||
assert.equal(runtime.service.admin.state.maxConcurrentUploads, 3);
|
||||
assert.equal(runtime.service.admin.state.totalStorageLimitMb, Math.round(16e9 / 1048576));
|
||||
await admin.getByRole('button', { name: '네트워크', exact: true }).click();
|
||||
async function addRule(page, list, kind, value) {
|
||||
await page.getByRole('button', { name: list + ' 추가', exact: true }).click();
|
||||
const modal = page.getByRole('dialog', { name: list + ' 추가', exact: true });
|
||||
await modal.getByLabel('등록 대상').selectOption(kind);
|
||||
await modal
|
||||
.getByLabel(kind === 'country' ? '국가 코드' : 'IP 주소 또는 CIDR', { exact: true })
|
||||
.fill(value);
|
||||
await modal.getByRole('button', { name: '추가', exact: true }).click();
|
||||
await modal.waitFor({ state: 'hidden' });
|
||||
}
|
||||
await addRule(admin, '블랙리스트', 'country', 'cn');
|
||||
await addRule(admin, '블랙리스트', 'ip', '9.9.9.0/24');
|
||||
await addRule(admin, '화이트리스트', 'country', 'KR');
|
||||
await addRule(admin, '화이트리스트', 'ip', '8.8.8.0/24');
|
||||
await addRule(admin, '화이트리스트', 'ip', '4.4.4.4');
|
||||
await admin.getByRole('checkbox', { name: '4.4.4.4 허용 규칙 선택', exact: true }).check();
|
||||
await admin
|
||||
.locator('section[aria-labelledby="whitelist-title"]')
|
||||
.getByRole('button', { name: '선택 항목 제거', exact: true })
|
||||
.click();
|
||||
await admin.getByRole('switch', { name: '자동 블랙리스트 사용', exact: true }).click();
|
||||
await admin.getByLabel('로그인 실패 (회)', { exact: true }).fill('3');
|
||||
await admin.getByRole('button', { name: '네트워크 설정 저장', exact: true }).click();
|
||||
await admin.getByText('네트워크 설정을 저장했어요.', { exact: true }).waitFor();
|
||||
assert.deepEqual(runtime.service.admin.state.allowedCountries, ['KR']);
|
||||
assert.deepEqual(runtime.service.admin.state.allowedIps, ['8.8.8.0/24']);
|
||||
assert.equal(runtime.service.admin.state.autoBlockEnabled, true);
|
||||
const attacker = await page(390, '8.8.8.9', 'KR'),
|
||||
attackSession = await session(attacker);
|
||||
await attacker.evaluate(async (csrf) => {
|
||||
for (let i = 0; i < 3; i++)
|
||||
await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrf },
|
||||
body: JSON.stringify({ email: 'missing@hop.test', password: 'incorrect' }),
|
||||
});
|
||||
}, attackSession.csrfToken);
|
||||
await admin.getByRole('button', { name: '자동 차단 목록 새로고침', exact: true }).click();
|
||||
await admin.getByRole('checkbox', { name: '8.8.8.9 자동 차단 선택', exact: true }).waitFor();
|
||||
await admin.screenshot({ path: 'tests/e2e/network-desktop.png', fullPage: true });
|
||||
await admin.getByRole('checkbox', { name: '8.8.8.9 자동 차단 선택', exact: true }).check();
|
||||
await admin.getByRole('button', { name: '선택 차단 해제', exact: true }).click();
|
||||
await admin.getByText('선택한 IP의 자동 차단을 해제했어요.', { exact: true }).waitFor();
|
||||
assert.equal(await attacker.evaluate(async () => (await fetch('/api/device/me')).status), 200);
|
||||
assert.deepEqual(runtime.service.admin.state.blockedCountries, ['CN']);
|
||||
assert.equal(await sender.evaluate(async () => (await fetch('/api/device/me')).status), 403);
|
||||
await admin.getByRole('button', { name: '저장 파일', exact: true }).click();
|
||||
@@ -200,22 +243,75 @@ try {
|
||||
assert.equal(runtime.service.admin.summary().storedBytes, 0);
|
||||
await admin.getByRole('button', { name: '관리 기록', exact: true }).click();
|
||||
await admin.getByText('원본 파일 삭제', { exact: true }).waitFor();
|
||||
const changedRow = admin
|
||||
.locator('.admin-audit article')
|
||||
.filter({ hasText: '동시에 처리할 업로드 수 4 > 3' });
|
||||
await changedRow.waitFor();
|
||||
await changedRow.getByRole('checkbox').check();
|
||||
await admin.getByRole('button', { name: '선택 기록 삭제', exact: true }).click();
|
||||
await admin.getByText('선택한 관리 기록을 삭제했어요.', { exact: true }).waitFor();
|
||||
assert.equal(await changedRow.count(), 0);
|
||||
await admin.getByRole('button', { name: '사용자', exact: true }).click();
|
||||
await admin.getByRole('button', { name: 'other@hop.test 더보기', exact: true }).waitFor();
|
||||
assert.equal(await admin.getByRole('menuitem', { name: '계정 삭제', exact: true }).count(), 0);
|
||||
await admin.screenshot({ path: 'tests/e2e/admin-users.png', fullPage: true });
|
||||
await admin.getByRole('button', { name: 'other@hop.test 더보기', exact: true }).click();
|
||||
await admin.getByRole('menuitem', { name: '비밀번호 재설정 메일 보내기', exact: true }).click();
|
||||
await admin
|
||||
.getByRole('alertdialog')
|
||||
.getByRole('button', { name: '메일 보내기', exact: true })
|
||||
.click();
|
||||
await admin.getByText('비밀번호 재설정 메일을 보냈어요.', { exact: true }).waitFor();
|
||||
await admin.getByRole('button', { name: 'other@hop.test 더보기', exact: true }).click();
|
||||
await admin.getByRole('menuitem', { name: '계정 삭제', exact: true }).click();
|
||||
const deletion = admin.getByRole('alertdialog', { name: '계정을 삭제할까요?', exact: true });
|
||||
assert.equal(
|
||||
await deletion.getByRole('button', { name: '계정 삭제 확인', exact: true }).isDisabled(),
|
||||
true,
|
||||
);
|
||||
await deletion.getByLabel('확인을 위해 대상 이메일 입력', { exact: true }).fill('other@hop.test');
|
||||
await deletion.getByRole('button', { name: '계정 삭제 확인', exact: true }).click();
|
||||
await admin.getByText('계정을 삭제했어요.', { exact: true }).waitFor();
|
||||
assert.equal(
|
||||
await admin.getByRole('button', { name: 'other@hop.test 더보기', exact: true }).count(),
|
||||
0,
|
||||
);
|
||||
await admin.getByRole('button', { name: '관리 기록', exact: true }).click();
|
||||
await admin.getByText('사용자 계정 삭제', { exact: true }).waitFor();
|
||||
await admin.getByText('비밀번호 재설정 메일 발송', { exact: true }).waitFor();
|
||||
await admin.getByRole('button', { name: '전체 기록 삭제', exact: true }).click();
|
||||
await admin
|
||||
.getByRole('alertdialog')
|
||||
.getByRole('button', { name: '전체 삭제 확인', exact: true })
|
||||
.click();
|
||||
await admin.getByText('관리 기록이 없습니다.', { exact: true }).waitFor();
|
||||
|
||||
const mobile = await page(390);
|
||||
await login(mobile, 'hello@noname.company');
|
||||
await mobile.getByRole('button', { name: '더보기', exact: true }).click();
|
||||
await mobile.getByRole('menuitem', { name: '관리자', exact: true }).click();
|
||||
await mobile.locator('.admin-stats').waitFor();
|
||||
await mobile.getByRole('button', { name: '접속 · 용량 설정', exact: true }).click();
|
||||
await mobile.getByRole('button', { name: '용량 설정', exact: true }).click();
|
||||
assert.equal(
|
||||
await mobile.evaluate(() => document.documentElement.scrollWidth <= innerWidth),
|
||||
true,
|
||||
);
|
||||
await mobile.getByRole('button', { name: '네트워크', exact: true }).click();
|
||||
assert.equal(
|
||||
await mobile
|
||||
.getByLabel('차단할 국가 코드')
|
||||
await mobile.evaluate(() => document.documentElement.scrollWidth <= innerWidth),
|
||||
true,
|
||||
);
|
||||
await mobile.getByRole('button', { name: '블랙리스트 추가', exact: true }).click();
|
||||
const ruleModal = mobile.getByRole('dialog', { name: '블랙리스트 추가', exact: true });
|
||||
assert.equal(
|
||||
await ruleModal
|
||||
.getByLabel('국가 코드', { exact: true })
|
||||
.evaluate((element) => parseFloat(getComputedStyle(element).fontSize) >= 16),
|
||||
true,
|
||||
);
|
||||
await ruleModal.getByLabel('국가 코드', { exact: true }).fill('JP');
|
||||
await mobile.screenshot({ path: 'tests/e2e/network-rule-mobile.png', fullPage: true });
|
||||
await ruleModal.getByRole('button', { name: '규칙 추가 닫기' }).click();
|
||||
await mobile.screenshot({ path: 'tests/e2e/admin-mobile.png', fullPage: true });
|
||||
await mobile.getByRole('button', { name: '메인으로', exact: true }).click();
|
||||
await mobile.locator('.nearby-section').waitFor();
|
||||
|
||||
Reference in New Issue
Block a user