setTables(array('editors' => array(array('username' => 'ed', 'password' => 'x', 'email' => '')))); $this->token = $this->loginAs(); } private function add(array $fields = array()): array { return $this->post('/publish/addeditor', $fields + array('adduser' => '1', 'username' => 'newbie', 'password' => 'a long pass phrase', 'email' => 'new@example.org', 'csrf_token' => $this->token)); } public function testVisitorsAreSentToTheLogin(): void { $this->cookies = array(); $this->assertRedirect('/publish/login', $this->get('/publish/addeditor')); $this->assertRedirect('/publish/login', $this->add(array('csrf_token' => ''))); $this->assertCount(1, $this->tables()['editors']); } public function testPlainHttpIsSentToHttps(): void { $this->assertRedirect('https://site.test/publish/addeditor', $this->get('/publish/addeditor', array('X-Test-Plain' => '1'))); } public function testTheFormHasTheToken(): void { $this->assertSame($this->token, $this->csrfToken($this->get('/publish/addeditor')['body'])); } public function testAnEditorIsAddedWithAPasswordHash(): void { $answer = $this->add(); $this->assertStringContainsString('
Added editor newbie
', $answer['body']); $row = $this->tables()['editors'][1]; $this->assertSame(array('newbie', 'new@example.org'), array($row['username'], $row['email'])); $this->assertTrue(password_verify('a long pass phrase', $row['password'])); } public function testTheTokenIsChecked(): void { $answer = $this->add(array('csrf_token' => 'wrong')); $this->assertStringContainsString('Your session has expired. Please try again.', $answer['body']); $this->assertCount(1, $this->tables()['editors']); } public function testAnExistingUsernameIsRefused(): void { $answer = $this->add(array('username' => 'ed')); $this->assertStringContainsString('An editor with that username already exists.', $answer['body']); $this->assertSame('x', $this->tables()['editors'][0]['password']); } public function testAHashThatDoesNotFitIsNotKept(): void { $this->setTables(array('editors' => array(array('username' => 'ed', 'password' => 'x', 'email' => ''))), 40); $answer = $this->add(); $this->assertStringContainsString('the editors.password column is too short', $answer['body']); $this->assertSame(array('ed'), array_column($this->tables()['editors'], 'username')); $this->assertCount(1, $this->queries('/^DELETE FROM persistent_sessions WHERE username = \?$/')); } public static function badAccounts(): array { return array( 'no username' => array(array('username' => ''), 'Please enter a username.'), 'a blank username' => array(array('username' => ' '), 'Please enter a username.'), 'an array username' => array(array('username' => array('x')), 'Please enter a username.'), 'spaces at the ends' => array(array('username' => ' newbie'), 'no spaces at the ends'), 'a bar' => array(array('username' => 'new|bie'), 'no spaces at the ends'), 'a long username' => array(array('username' => str_repeat('n', 65)), 'at most 64 characters'), 'no password' => array(array('password' => ''), 'A password needs at least 12 characters.'), 'a short password' => array(array('password' => 'eleven char'), 'A password needs at least 12 characters.'), 'an array password' => array(array('password' => array('a long pass phrase')), 'A password needs at least 12 characters.'), 'a huge password' => array(array('password' => str_repeat('p', 1025)), 'A password has at most 1024 characters.'), 'the username' => array(array('username' => 'newbie-editor', 'password' => 'NEWBIE-EDITOR'), 'The password cannot be the username.'), ); } #[DataProvider('badAccounts')] public function testABadAccountIsRefused(array $fields, string $message): void { $answer = $this->add($fields); $this->assertSame(200, $answer['status']); $this->assertStringContainsString(htmlspecialchars($message, ENT_QUOTES), $answer['body']); $this->assertStringNotContainsString('Added editor', $answer['body']); $this->assertCount(1, $this->tables()['editors']); $this->assertCount(0, $this->queries('/^INSERT INTO editors/')); } public function testTwelveCharactersAreEnough(): void { $this->assertStringContainsString('Added editor newbie', $this->add(array('password' => 'twelve chars'))['body']); } public function testTheUsernameIsEscaped(): void { $body = $this->add(array('username' => 'x'))['body']; $this->assertStringContainsString('Added editor <b>x</b>', $body); } }