Compare commits
No commits in common. "0dd2c64c3873ee57fa26d5726e3296b7311cce7c" and "af626f5d3a14a365e97dc6437025a0b1da6b42bc" have entirely different histories.
0dd2c64c38
...
af626f5d3a
|
@ -72,8 +72,7 @@ class Api
|
||||||
{
|
{
|
||||||
$this->assertLoggedIn();
|
$this->assertLoggedIn();
|
||||||
|
|
||||||
return app(Paginator::class)->startResult(
|
return app(Paginator::class)->startResult(100,
|
||||||
100,
|
|
||||||
fn ($page, $start) => $this->http()->get($this->url.'/ica/rest/nami/search-multi/result-list?searchedValues='.rawurlencode(json_encode((object) $payload) ?: '{}').'&page='.$page.'&start='.$start.'&limit=100'),
|
fn ($page, $start) => $this->http()->get($this->url.'/ica/rest/nami/search-multi/result-list?searchedValues='.rawurlencode(json_encode((object) $payload) ?: '{}').'&page='.$page.'&start='.$start.'&limit=100'),
|
||||||
function ($response) {
|
function ($response) {
|
||||||
if (true !== $response->json()['success']) {
|
if (true !== $response->json()['success']) {
|
||||||
|
|
|
@ -6,8 +6,6 @@ use Illuminate\Http\Client\PendingRequest;
|
||||||
|
|
||||||
abstract class Authenticator
|
abstract class Authenticator
|
||||||
{
|
{
|
||||||
protected static string $path = __DIR__ . '/../../.cookies';
|
|
||||||
|
|
||||||
abstract public function login(int $mglnr, string $password): self;
|
abstract public function login(int $mglnr, string $password): self;
|
||||||
|
|
||||||
abstract public function purge(): void;
|
abstract public function purge(): void;
|
||||||
|
@ -18,6 +16,8 @@ abstract class Authenticator
|
||||||
|
|
||||||
abstract public function refresh(): void;
|
abstract public function refresh(): void;
|
||||||
|
|
||||||
|
protected static string $path = __DIR__.'/../../.cookies';
|
||||||
|
|
||||||
public static function setPath(string $path): void
|
public static function setPath(string $path): void
|
||||||
{
|
{
|
||||||
static::$path = $path;
|
static::$path = $path;
|
||||||
|
|
|
@ -12,8 +12,8 @@ class MainCookie extends Authenticator
|
||||||
{
|
{
|
||||||
private CookieJar $cookie;
|
private CookieJar $cookie;
|
||||||
private string $url = 'https://nami.dpsg.de';
|
private string $url = 'https://nami.dpsg.de';
|
||||||
private int $mglnr;
|
private ?int $mglnr = null;
|
||||||
private string $password;
|
private ?string $password = null;
|
||||||
|
|
||||||
public function login(int $mglnr, string $password): self
|
public function login(int $mglnr, string $password): self
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,7 @@ class MainCookie extends Authenticator
|
||||||
unlink($file);
|
unlink($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->http()->get($this->url.'/ica/pages/login.jsp');
|
||||||
$response = $this->http()->asForm()->post($this->url.'/ica/rest/nami/auth/manual/sessionStartup', [
|
$response = $this->http()->asForm()->post($this->url.'/ica/rest/nami/auth/manual/sessionStartup', [
|
||||||
'Login' => 'API',
|
'Login' => 'API',
|
||||||
'redirectTo' => './app.jsp',
|
'redirectTo' => './app.jsp',
|
||||||
|
@ -64,8 +65,10 @@ class MainCookie extends Authenticator
|
||||||
|
|
||||||
public function refresh(): void
|
public function refresh(): void
|
||||||
{
|
{
|
||||||
|
if ($this->mglnr && $this->password) {
|
||||||
$this->login($this->mglnr, $this->password);
|
$this->login($this->mglnr, $this->password);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function http(): PendingRequest
|
public function http(): PendingRequest
|
||||||
{
|
{
|
||||||
|
@ -74,12 +77,12 @@ class MainCookie extends Authenticator
|
||||||
|
|
||||||
private function newFileName(): string
|
private function newFileName(): string
|
||||||
{
|
{
|
||||||
return parent::$path . '/' . $this->mglnr . '_' . now()->timestamp . '.txt';
|
return parent::$path.'/'.time().'.txt';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function isExpired(): bool
|
private function isExpired(): bool
|
||||||
{
|
{
|
||||||
$lastLoginTime = Carbon::createFromTimestamp(str(pathinfo($this->file(), PATHINFO_FILENAME))->replace($this->mglnr . '_', '')->toString());
|
$lastLoginTime = Carbon::createFromTimestamp(pathinfo($this->file(), PATHINFO_FILENAME));
|
||||||
|
|
||||||
return $lastLoginTime->addMinutes(50)->isPast();
|
return $lastLoginTime->addMinutes(50)->isPast();
|
||||||
}
|
}
|
||||||
|
@ -91,7 +94,7 @@ class MainCookie extends Authenticator
|
||||||
*/
|
*/
|
||||||
private function file(): ?string
|
private function file(): ?string
|
||||||
{
|
{
|
||||||
$files = glob(parent::$path . '/' . $this->mglnr . '_*');
|
$files = glob(parent::$path.'/*');
|
||||||
|
|
||||||
if (!count($files)) {
|
if (!count($files)) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Zoomyboy\LaravelNami\Fakes;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Http;
|
|
||||||
|
|
||||||
class LoginFake extends Fake
|
|
||||||
{
|
|
||||||
public function succeeds(string $token): void
|
|
||||||
{
|
|
||||||
$this->fakeLogin($token, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fails(string $token): void
|
|
||||||
{
|
|
||||||
$this->fakeLogin($token, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function fakeLogin(string $token, int $statusCode): void
|
|
||||||
{
|
|
||||||
Http::fake(function ($request) use ($token, $statusCode) {
|
|
||||||
if ($request->url() !== 'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Http::response(json_encode([
|
|
||||||
"servicePrefix" => null,
|
|
||||||
"methodCall" => null,
|
|
||||||
"response" => null,
|
|
||||||
"statusCode" => $statusCode,
|
|
||||||
"statusMessage" => "",
|
|
||||||
"apiSessionName" => "JSESSIONID",
|
|
||||||
"apiSessionToken" => $token,
|
|
||||||
"minorNumber" => 2,
|
|
||||||
"majorNumber" => 1,
|
|
||||||
]), 200, [
|
|
||||||
'Set-Cookie' => 'JSESSIONID=' . $token . '.srv-nami06; path=/ica; secure; HttpOnly; Max-Age=9000; Expires=Sat, 24-Feb-2024 01:18:00 GMT'
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function assertSent(int $mglnr, string $password): void
|
|
||||||
{
|
|
||||||
Http::assertSent(function ($request) use ($mglnr, $password) {
|
|
||||||
return $request->url() === 'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup'
|
|
||||||
&& $request->header('Content-Type')[0] === 'application/x-www-form-urlencoded'
|
|
||||||
&& $request['Login'] === 'API'
|
|
||||||
&& $request['redirectTo'] === './app.jsp'
|
|
||||||
&& $request['username'] === $mglnr
|
|
||||||
&& $request['password'] === $password;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -69,6 +69,13 @@ class CourseTest extends TestCase
|
||||||
$this->login()->coursesOf(11111);
|
$this->login()->coursesOf(11111);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItNeedsLoginToGetCourses(): void
|
||||||
|
{
|
||||||
|
$this->expectException(NotAuthenticatedException::class);
|
||||||
|
|
||||||
|
Nami::coursesOf(11111);
|
||||||
|
}
|
||||||
|
|
||||||
public function testStoreACourse(): void
|
public function testStoreACourse(): void
|
||||||
{
|
{
|
||||||
app(CourseFake::class)->createsSuccessfully(123, 999);
|
app(CourseFake::class)->createsSuccessfully(123, 999);
|
||||||
|
@ -87,6 +94,17 @@ class CourseTest extends TestCase
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNeedsLoginToStoreACourse(): void
|
||||||
|
{
|
||||||
|
$this->expectException(NotAuthenticatedException::class);
|
||||||
|
Nami::createCourse(123, [
|
||||||
|
'event_name' => '::event::',
|
||||||
|
'completed_at' => '2021-01-02 00:00:00',
|
||||||
|
'organizer' => '::org::',
|
||||||
|
'course_id' => 456,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function testUpdateACourse(): void
|
public function testUpdateACourse(): void
|
||||||
{
|
{
|
||||||
app(CourseFake::class)->updatesSuccessfully(123, 999);
|
app(CourseFake::class)->updatesSuccessfully(123, 999);
|
||||||
|
@ -122,6 +140,17 @@ class CourseTest extends TestCase
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItNeedsValidCredentialsToStoreACourse(): void
|
||||||
|
{
|
||||||
|
$this->expectException(NotAuthenticatedException::class);
|
||||||
|
Nami::createCourse(123, [
|
||||||
|
'event_name' => '::event::',
|
||||||
|
'completed_at' => '2021-01-02 00:00:00',
|
||||||
|
'organizer' => '::org::',
|
||||||
|
'course_id' => 456,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function testItThrowsLoginExceptionWhenFetchingWithWrongCredentials(): void
|
public function testItThrowsLoginExceptionWhenFetchingWithWrongCredentials(): void
|
||||||
{
|
{
|
||||||
$this->expectException(LoginException::class);
|
$this->expectException(LoginException::class);
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Zoomyboy\LaravelNami\Tests\Unit;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Support\Facades\Http;
|
|
||||||
use Zoomyboy\LaravelNami\Authentication\Authenticator;
|
|
||||||
use Zoomyboy\LaravelNami\Authentication\MainCookie;
|
|
||||||
use Zoomyboy\LaravelNami\Fakes\CourseFake;
|
|
||||||
use Zoomyboy\LaravelNami\Fakes\LoginFake;
|
|
||||||
use Zoomyboy\LaravelNami\LoginException;
|
|
||||||
use Zoomyboy\LaravelNami\Nami;
|
|
||||||
use Zoomyboy\LaravelNami\Tests\TestCase;
|
|
||||||
|
|
||||||
class LoginTest extends TestCase
|
|
||||||
{
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
Carbon::setTestNow(Carbon::parse('2024-02-23 23:48:00'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testItLoggsInAndSavesCookie(): void
|
|
||||||
{
|
|
||||||
app(LoginFake::class)->succeeds('lala-testsession');
|
|
||||||
|
|
||||||
app(MainCookie::class)->login(12345, 'secret');
|
|
||||||
|
|
||||||
Http::assertSentCount(1);
|
|
||||||
$cookie = file_get_contents(__DIR__ . '/../../.cookies_test/12345_' . now()->timestamp . '.txt');
|
|
||||||
$this->assertEquals('lala-testsession.srv-nami06', $cookie);
|
|
||||||
app(LoginFake::class)->assertSent(12345, 'secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testItThrowsExceptionWhenLoginFails(): void
|
|
||||||
{
|
|
||||||
app(LoginFake::class)->fails('::token::');
|
|
||||||
$this->expectException(LoginException::class);
|
|
||||||
app(MainCookie::class)->login(12345, 'secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testItDoesntSaveCookieWhenLoginFails(): void
|
|
||||||
{
|
|
||||||
app(LoginFake::class)->fails('::token::');
|
|
||||||
|
|
||||||
try {
|
|
||||||
app(MainCookie::class)->login(12345, 'secret');
|
|
||||||
} catch (LoginException $e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Http::assertSentCount(1);
|
|
||||||
$this->assertEmpty(glob(__DIR__ . '/../../.cookies_test/*'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testItDoesntResetCookieWhenAlreadyLoggedIn(): void
|
|
||||||
{
|
|
||||||
app(CourseFake::class)->fetches(103, []);
|
|
||||||
file_put_contents(__DIR__ . '/../../.cookies_test/90100_' . now()->subMinutes(5)->timestamp . '.txt', 'cook-testsession.srv-nami06');
|
|
||||||
|
|
||||||
Nami::login(90100, 'secret');
|
|
||||||
|
|
||||||
Http::assertSentCount(0);
|
|
||||||
$this->assertFileExists(__DIR__ . '/../../.cookies_test/90100_' . now()->subMinutes(5)->timestamp . '.txt');
|
|
||||||
$this->assertCount(1, glob(__DIR__ . '/../../.cookies_test/*'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testItIgnoresExpiredCookie(): void
|
|
||||||
{
|
|
||||||
app(CourseFake::class)->fetches(103, []);
|
|
||||||
app(LoginFake::class)->succeeds('newlogin');
|
|
||||||
file_put_contents(__DIR__ . '/../../.cookies_test/90100_' . now()->subHour()->timestamp . '.txt', 'oldlogin-testsession.srv-nami06');
|
|
||||||
|
|
||||||
Nami::login(90100, 'secret');
|
|
||||||
|
|
||||||
Http::assertSentCount(1);
|
|
||||||
$cookie = file_get_contents(__DIR__ . '/../../.cookies_test/90100_' . now()->timestamp . '.txt');
|
|
||||||
$this->assertEquals('newlogin.srv-nami06', $cookie);
|
|
||||||
$this->assertFileExists(__DIR__ . '/../../.cookies_test/90100_' . now()->timestamp . '.txt');
|
|
||||||
$this->assertCount(1, glob(__DIR__ . '/../../.cookies_test/*'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testItDoesntUseOtherCookieForLogin(): void
|
|
||||||
{
|
|
||||||
app(CourseFake::class)->fetches(103, []);
|
|
||||||
app(LoginFake::class)->succeeds('newlogin');
|
|
||||||
file_put_contents(__DIR__ . '/../../.cookies_test/11111_' . now()->timestamp . '.txt', 'oldlogin-testsession.srv-nami06');
|
|
||||||
app(Authenticator::class)->login(12345, 'secret');
|
|
||||||
|
|
||||||
app(LoginFake::class)->assertSent(12345, 'secret');
|
|
||||||
$this->assertFileExists(__DIR__ . '/../../.cookies_test/11111_' . now()->timestamp . '.txt');
|
|
||||||
$this->assertFileExists(__DIR__ . '/../../.cookies_test/12345_' . now()->timestamp . '.txt');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testItRefreshesLogin(): void
|
|
||||||
{
|
|
||||||
app(LoginFake::class)->succeeds('newlogin');
|
|
||||||
$auth = app(Authenticator::class)->login(12345, 'secret');
|
|
||||||
rename(
|
|
||||||
__DIR__ . '/../../.cookies_test/12345_' . now()->timestamp . '.txt',
|
|
||||||
__DIR__ . '/../../.cookies_test/12345_' . now()->subMinutes(51)->timestamp . '.txt'
|
|
||||||
);
|
|
||||||
$auth->refresh();
|
|
||||||
Http::assertSentCount(2);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue