Add cookie class

This commit is contained in:
philipp lang 2021-06-21 22:37:23 +02:00
parent 4aae6f6af2
commit 009a9b1678
13 changed files with 206 additions and 30 deletions

View File

@ -11,25 +11,21 @@ use Illuminate\Support\Collection;
use Zoomyboy\LaravelNami\Backend\Backend; use Zoomyboy\LaravelNami\Backend\Backend;
use Zoomyboy\LaravelNami\Concerns\IsNamiMember; use Zoomyboy\LaravelNami\Concerns\IsNamiMember;
use Zoomyboy\LaravelNami\NamiException; use Zoomyboy\LaravelNami\NamiException;
use Illuminate\Support\Facades\Cache;
use Zoomyboy\LaravelNami\Cookies\Cookie;
class Api { class Api {
public $cookie; private $cookie;
public $loggedIn = null; public $loggedIn = null;
public static $url = 'https://nami.dpsg.de'; public static $url = 'https://nami.dpsg.de';
public function __construct() { public function __construct($cookieStore) {
$this->cookie = new \GuzzleHttp\Cookie\CookieJar(); $this->cookie = $cookieStore;
} }
public function http() { public function http() {
return Backend::cookie($this->cookie); return Backend::init($this->cookie);
}
public function setUser(NamiUser $user) {
$this->user = $user;
return $this;
} }
public function findNr($nr) { public function findNr($nr) {
@ -51,6 +47,8 @@ class Api {
return Member::fromNami($data); return Member::fromNami($data);
} }
$this->exception('Search failed', ['url' => $url], $response->json());
} }
protected function loggedInAlready(): bool { protected function loggedInAlready(): bool {
@ -58,7 +56,9 @@ class Api {
} }
public function login($mglnr = null, $password = null, $groupid = null): self { public function login($mglnr = null, $password = null, $groupid = null): self {
if ($this->loggedIn) { return $this; } if ($this->cookie->resolve($mglnr)) {
return $this;
}
$mglnr = $mglnr ?: config('nami.auth.mglnr'); $mglnr = $mglnr ?: config('nami.auth.mglnr');
$password = $password ?: config('nami.auth.password'); $password = $password ?: config('nami.auth.password');
@ -78,6 +78,7 @@ class Api {
throw $e; throw $e;
} }
$this->cookie->store($mglnr);
$this->loggedIn = $mglnr; $this->loggedIn = $mglnr;
return $this; return $this;
@ -92,7 +93,7 @@ class Api {
$response = $this->http()->put(self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$member->group_id.'/'.$member->id, $member->toNami()); $response = $this->http()->put(self::$url.'/ica/rest/nami/mitglied/filtered-for-navigation/gruppierung/gruppierung/'.$member->group_id.'/'.$member->id, $member->toNami());
if (!data_get($response->json(), 'id')) { if (!data_get($response->json(), 'id')) {
throw new NamiException('update failed'); $this->exception('Update failed', $response->json(), $member->toNami());
} }
} }
@ -246,5 +247,9 @@ class Api {
return $member->toArray(); return $member->toArray();
} }
private function exception($message, $request, $response) {
throw (new NamiException($message))->response($response)->request($request);
}
} }

View File

@ -47,7 +47,7 @@ class NamiGuard {
return; return;
} }
return new NamiUser($cache); return NamiUser::fromPayload($cache);
} }
public function attempt(array $credentials = [], $remember = false) { public function attempt(array $credentials = [], $remember = false) {
@ -57,7 +57,7 @@ class NamiGuard {
'credentials' => $credentials 'credentials' => $credentials
]; ];
$this->setUser(new NamiUser($payload)); $this->setUser(NamiUser::fromPayload($payload));
$key = $this->newCacheKey(); $key = $this->newCacheKey();
Cache::forever("namiauth-{$key}", $payload); Cache::forever("namiauth-{$key}", $payload);
$this->updateSession($key); $this->updateSession($key);

View File

@ -5,7 +5,8 @@ namespace Zoomyboy\LaravelNami\Backend;
use Illuminate\Http\Client\Response; use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use GuzzleHttp\Psr7\Response as GuzzleResponse; use GuzzleHttp\Psr7\Response as GuzzleResponse;
use GuzzleHttp\Cookie\SetCookie; use Illuminate\Support\Str;
use Illuminate\Support\Facades\Cache;
class FakeBackend { class FakeBackend {
@ -19,10 +20,11 @@ class FakeBackend {
} }
public function addMember(array $member) { public function addMember(array $member) {
$member['mitgliedsNummer'] = $member['id'];
$this->members->push($member); $this->members->push($member);
} }
public function cookie($cookie) { public function init($cookie) {
$this->cookie = $cookie; $this->cookie = $cookie;
return $this; return $this;
} }
@ -104,9 +106,35 @@ class FakeBackend {
]); ]);
} }
if (Str::contains($url, 'search-multi/result-list')) {
$query = parse_url($url)['query'];
parse_str($query, $q);
$params = json_decode($q['searchedValues'], true);
if (array_keys($params) === ['mitgliedsNummber']) {
return $this->findNr($params['mitgliedsNummber']);
}
}
$this->urlNotFoundException($url); $this->urlNotFoundException($url);
} }
public function findNr($nr) {
$found = $this->members->first(fn($m) => $m['id'] === $nr);
$found = [
'entries_mitgliedsNummer' => $found['mitgliedsNummer'],
'entries_vorname' => $found['vorname'],
'entries_nachname' => $found['nachname'],
];
return $this->response([
"success" => true,
"data" => [$found],
"responseType" => "OK",
"totalEntries" => 1
]);
}
public function post($url, $data) { public function post($url, $data) {
if ($url === 'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup') { if ($url === 'https://nami.dpsg.de/ica/rest/nami/auth/manual/sessionStartup') {
if (!data_get($data, 'username') || !data_get($data, 'password')) { if (!data_get($data, 'username') || !data_get($data, 'password')) {
@ -115,9 +143,7 @@ class FakeBackend {
if ($this->passwords[data_get($data, 'username')] === data_get($data, 'password')) { if ($this->passwords[data_get($data, 'username')] === data_get($data, 'password')) {
$this->loggedInAs = data_get($data, 'username'); $this->loggedInAs = data_get($data, 'username');
$this->cookie->setCookie(tap(SetCookie::fromString('JSESSIONID=rZMBv1McDAJ-KukQ6BboJBTq.srv-nami06; path=/ica'), function($cookie) { $this->cookie->set($data['username'], 'rZMBv1McDAJ-KukQ6BboJBTq.srv-nami06');
$cookie->setDomain('nami.dpsg.de');
}));
return $this->response([ return $this->response([
"statusCode" => 0, "statusCode" => 0,
]); ]);

View File

@ -3,11 +3,12 @@
namespace Zoomyboy\LaravelNami\Backend; namespace Zoomyboy\LaravelNami\Backend;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Zoomyboy\LaravelNami\Cookies\Cookie;
class LiveBackend { class LiveBackend {
public static function cookie($cookie) { public static function init($cookie) {
return Http::withOptions(['cookies' => $cookie]); return Http::withOptions(['cookies' => $cookie->forBackend()]);
} }
} }

View File

@ -0,0 +1,50 @@
<?php
namespace Zoomyboy\LaravelNami\Cookies;
use Illuminate\Support\Facades\Cache;
use GuzzleHttp\Cookie\SetCookie;
class CacheCookie {
private $store;
public function __construct() {
$this->store = new \GuzzleHttp\Cookie\CookieJar();
}
public function forBackend() {
return $this->store;
return \GuzzleHttp\Cookie\CookieJar::fromArray(['JSESSIONID' => Cache::get("namicookie-{$mglnr}")], 'nami.dpsg.de');
}
/**
* Store the current cookie in the cache
*/
public function store($mglnr) {
Cache::forever("namicookie-{$mglnr}", $this->store->getCookieByName('JSESSIONID')->getValue());
}
/**
* Set a cookie by string
*/
public function set($mglnr, $cookie) {
$this->store->setCookie(tap(SetCookie::fromString('JSESSIONID='.$cookie.'; path=/ica'), function($cookie) {
$cookie->setDomain('nami.dpsg.de');
}));
}
/**
* Get the stored cookie from the cache
*/
public function resolve($mglnr) {
$cookie = Cache::get("namicookie-{$mglnr}");
if ($cookie === null) {
return false;
}
$this->set($mglnr, $cookie);
return true;
}
}

13
src/Cookies/Cookie.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace Zoomyboy\LaravelNami\Cookies;
use Illuminate\Support\Facades\Facade;
class Cookie extends Facade {
public static function getFacadeAccessor() {
return 'nami.cookie';
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Zoomyboy\LaravelNami\Cookies;
class FakeCookie {
private $loggedIn = false;
public function forBackend() {
return \GuzzleHttp\Cookie\CookieJar::fromArray([], 'nami.dpsg.de');
}
public function store($cookie) {
$this->loggedIn = true;
}
public function resolve($mglnr) {
return $this->loggedIn;
}
}

View File

@ -46,6 +46,7 @@ class Member extends Model {
'regionId' => 'region_id', 'regionId' => 'region_id',
'landId' => 'country_id', 'landId' => 'country_id',
'beitragsartId' => 'fee_id', 'beitragsartId' => 'fee_id',
'version' => 'version',
]; ];
protected $casts = []; protected $casts = [];
@ -73,6 +74,16 @@ class Member extends Model {
'vorname' => $this->firstname, 'vorname' => $this->firstname,
'nachname' => $this->lastname, 'nachname' => $this->lastname,
'spitzname' => $this->nickname ?: '', 'spitzname' => $this->nickname ?: '',
'strasse' => $this->address,
'plz' => $this->zip,
'ort' => $this->location,
'eintrittsdatum' => $this->joined_at.'T00:00:00',
'version' => $this->version,
'beitragsartId' => $this->fee_id,
'regionId' => $this->region_id,
'landId' => $this->country_id,
'staatsangehoerigkeitId' => $this->nationality_id,
'geburtsDatum' => $this->birthday,
'geschlechtId' => $this->gender_id ?: Gender::getNullValue(), 'geschlechtId' => $this->gender_id ?: Gender::getNullValue(),
'gruppierungId' => $this->group_id, 'gruppierungId' => $this->group_id,
'id' => $this->id, 'id' => $this->id,

View File

@ -7,6 +7,8 @@ use Illuminate\Support\Str;
class NamiException extends \Exception { class NamiException extends \Exception {
private $data; private $data;
public $response;
public $request;
public function setData($data) { public function setData($data) {
$this->data = $data; $this->data = $data;
@ -15,4 +17,16 @@ class NamiException extends \Exception {
public function getData() { public function getData() {
return $this->data; return $this->data;
} }
public function request($request) {
$this->request = $request;
return $this;
}
public function response($response) {
$this->response = $response;
return $this;
}
} }

View File

@ -4,15 +4,25 @@ namespace Zoomyboy\LaravelNami;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Cache;
class NamiUser extends Model implements Authenticatable { class NamiUser implements Authenticatable {
public $mglnr; public $mglnr;
public $password; public $password;
public function __construct($payload) { public function __construct($attributes) {
$this->mglnr = data_get($payload, 'credentials.mglnr'); $this->mglnr = $attributes['mglnr'];
$this->password = data_get($payload, 'credentials.password'); $this->password = $attributes['password'];
}
public static function fromPayload($payload) {
$user = new static([
'mglnr' => data_get($payload, 'credentials.mglnr'),
'password' => data_get($payload, 'credentials.password'),
]);
return $user;
} }
public function api() { public function api() {
@ -27,12 +37,20 @@ class NamiUser extends Model implements Authenticatable {
return 'mglnr'; return 'mglnr';
} }
public function getFirstnameAttribute() { public function getMglnr() {
return $this->api()->findNr($this->mglnr)->vorname; return $this->mglnr;
} }
public function getLastnameAttribute() { public function getFirstname() {
return $this->api()->findNr($this->mglnr)->nachname; return Cache::remember('member-'.$this->mglnr.'-firstname', 3600, function() {
return $this->api()->findNr($this->mglnr)->firstname;
});
}
public function getLastname() {
return Cache::remember('member-'.$this->mglnr.'-lastname', 3600, function() {
return $this->api()->findNr($this->mglnr)->lastname;
});
} }
public function getAuthIdentifier() { public function getAuthIdentifier() {
@ -52,4 +70,5 @@ class NamiUser extends Model implements Authenticatable {
public function getRememberTokenName() { public function getRememberTokenName() {
return null; return null;
} }
} }

View File

@ -7,6 +7,7 @@ use GuzzleHttp\Client as GuzzleClient;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Zoomyboy\LaravelNami\Backend\LiveBackend; use Zoomyboy\LaravelNami\Backend\LiveBackend;
use Zoomyboy\LaravelNami\Api; use Zoomyboy\LaravelNami\Api;
use Zoomyboy\LaravelNami\Cookies\CacheCookie;
use Zoomyboy\LaravelNami\Authentication\NamiGuard; use Zoomyboy\LaravelNami\Authentication\NamiGuard;
class NamiServiceProvider extends ServiceProvider class NamiServiceProvider extends ServiceProvider
@ -20,10 +21,13 @@ class NamiServiceProvider extends ServiceProvider
public function register() { public function register() {
$this->app->singleton('nami.api', function() { $this->app->singleton('nami.api', function() {
return new Api(); return new Api($this->app['nami.cookie']);
}); });
$this->app->bind('nami.backend', function() { $this->app->bind('nami.backend', function() {
return new LiveBackend(); return new LiveBackend();
}); });
$this->app->singleton('nami.cookie', function() {
return new CacheCookie();
});
} }
} }

View File

@ -6,6 +6,8 @@ use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Zoomyboy\LaravelNami\Tests\Stub\Member; use Zoomyboy\LaravelNami\Tests\Stub\Member;
use Zoomyboy\LaravelNami\Providers\NamiServiceProvider; use Zoomyboy\LaravelNami\Providers\NamiServiceProvider;
use Zoomyboy\LaravelNami\Cookies\Cookie;
use Zoomyboy\LaravelNami\Cookies\FakeCookie;
class TestCase extends \Orchestra\Testbench\TestCase class TestCase extends \Orchestra\Testbench\TestCase
{ {
@ -13,6 +15,12 @@ class TestCase extends \Orchestra\Testbench\TestCase
public $bruteJson = '{"servicePrefix":null,"methodCall":null,"response":null,"statusCode":3000,"statusMessage":"Die höchste Anzahl von Login-Versuchen wurde erreicht. Ihr Konto ist für 15 Minuten gesperrt worden. Nach Ablauf dieser Zeitspanne wird ihr Zugang wieder freigegeben.","apiSessionName":"JSESSIONID","apiSessionToken":"tGlSpMMij9ruHfeiUYjO7SD2","minorNumber":0,"majorNumber":0}'; public $bruteJson = '{"servicePrefix":null,"methodCall":null,"response":null,"statusCode":3000,"statusMessage":"Die höchste Anzahl von Login-Versuchen wurde erreicht. Ihr Konto ist für 15 Minuten gesperrt worden. Nach Ablauf dieser Zeitspanne wird ihr Zugang wieder freigegeben.","apiSessionName":"JSESSIONID","apiSessionToken":"tGlSpMMij9ruHfeiUYjO7SD2","minorNumber":0,"majorNumber":0}';
public $wrongCredentialsJson = '{"servicePrefix":null,"methodCall":null,"response":null,"statusCode":3000,"statusMessage":"Benutzer nicht gefunden oder Passwort falsch.","apiSessionName":"JSESSIONID","apiSessionToken":"v7lrjgPBbXInJR57qJzVIJ05","minorNumber":0,"majorNumber":0}'; public $wrongCredentialsJson = '{"servicePrefix":null,"methodCall":null,"response":null,"statusCode":3000,"statusMessage":"Benutzer nicht gefunden oder Passwort falsch.","apiSessionName":"JSESSIONID","apiSessionToken":"v7lrjgPBbXInJR57qJzVIJ05","minorNumber":0,"majorNumber":0}';
public function setUp(): void {
parent::setUp();
Cookie::swap(new FakeCookie());
}
protected function getPackageProviders($app) protected function getPackageProviders($app)
{ {
return [ NamiServiceProvider::class ]; return [ NamiServiceProvider::class ];

View File

@ -24,6 +24,8 @@ class PushMemberTest extends TestCase
'group_id' => 103, 'group_id' => 103,
'nickname' => 'spitz1', 'nickname' => 'spitz1',
'gender_id' => 17, 'gender_id' => 17,
'joined_at' => '2021-02-02T00:00:00',
'birthday' => '2021-02-02',
'id' => 16, 'id' => 16,
], [ ], [
'firstname' => 'Jane', 'firstname' => 'Jane',
@ -31,6 +33,8 @@ class PushMemberTest extends TestCase
'nickname' => null, 'nickname' => null,
'group_id' => 103, 'group_id' => 103,
'gender_id' => null, 'gender_id' => null,
'joined_at' => '2021-02-02T00:00:00',
'birthday' => '2021-02-02',
'id' => 17, 'id' => 17,
] ]
]; ];