J. King
7 years ago
3 changed files with 150 additions and 1 deletions
@ -0,0 +1,128 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse\REST\TinyTinyRSS; |
|||
|
|||
use JKingWeb\Arsse\Arsse; |
|||
use JKingWeb\Arsse\User; |
|||
use JKingWeb\Arsse\Service; |
|||
use JKingWeb\Arsse\Misc\Context; |
|||
use JKingWeb\Arsse\AbstractException; |
|||
use JKingWeb\Arsse\Db\ExceptionInput; |
|||
use JKingWeb\Arsse\Feed\Exception as FeedException; |
|||
use JKingWeb\Arsse\REST\Response; |
|||
|
|||
class API extends \JKingWeb\Arsse\REST\AbstractHandler { |
|||
const LEVEL = 14; |
|||
const VERSION = "17.4"; |
|||
const OVVERIDE = [ |
|||
'auth' => ["login"], |
|||
]; |
|||
|
|||
public function __construct() { |
|||
} |
|||
|
|||
public function dispatch(\JKingWeb\Arsse\REST\Request $req): Response { |
|||
if ($req->method != "POST") { |
|||
// only POST requests are allowed |
|||
return new Response(405, "", "", ["Allow: POST"]); |
|||
} |
|||
if ($req->body) { |
|||
// only JSON entities are allowed |
|||
if (!preg_match("<^application/json\b|^$>", $req->type)) { |
|||
return new Response(415, "", "", ['Accept: application/json']); |
|||
} |
|||
$data = @json_decode($req->body, true); |
|||
if (json_last_error() != \JSON_ERROR_NONE || !is_array($data)) { |
|||
// non-JSON input indicates an error |
|||
return new Response(400); |
|||
} |
|||
// layer input over defaults |
|||
$data = array_merge([ |
|||
'seq' => 0, |
|||
'op' => "", |
|||
'sid' => null, |
|||
], $data); |
|||
try { |
|||
if (!in_array($data['op'], self::OVERRIDE['auth'])) { |
|||
// unless otherwise specified, a session identifier is required |
|||
$this->resumeSession($data['sid']); |
|||
} |
|||
$method = "op".ucfirst($data['op']); |
|||
if (!method_exists($this, $method)) { |
|||
// because method names are supposed to be case insensitive, we need to try a bit harder to match |
|||
$method = strtolower($method); |
|||
$map = get_class_methods($this); |
|||
$map = array_combine(array_map("strtolower", $map), $map); |
|||
if(!array_key_exists($method, $map)) { |
|||
// if the method really doesn't exist, throw an exception |
|||
throw new Exception("UNKNWON_METHOD", ['method' => $data['op']]); |
|||
} |
|||
// otherwise retrieve the correct camelCase and continue |
|||
$method = $map[$method]; |
|||
} |
|||
return new Response(200, [ |
|||
'seq' => $data['seq'], |
|||
'status' => 0, |
|||
'content' => $this->$method($data), |
|||
]); |
|||
} catch (Exception $e) { |
|||
return new Response(200, [ |
|||
'seq' => $data['seq'], |
|||
'status' => 1, |
|||
'content' => $e->getData(), |
|||
]); |
|||
} catch (AbstractException $e) { |
|||
return new Response(500); |
|||
} |
|||
} else { |
|||
// absence of a request body indicates an error |
|||
return new Response(400); |
|||
} |
|||
} |
|||
|
|||
protected function resumeSession($id): bool { |
|||
try { |
|||
// verify the supplied session is valid |
|||
$s = Arsse::$db->sessionResume((string) $id); |
|||
} catch (\JKingWeb\Arsse\User\ExceptionSession $e) { |
|||
// if not throw an exception |
|||
throw new Exception("NOT_LOGGED_IN"); |
|||
} |
|||
// resume the session (currently only the user name) |
|||
Arsse::$user->id = $s['user']; |
|||
return true; |
|||
} |
|||
|
|||
public function opGetApiLevel(array $data): aray { |
|||
return ['level' => self::LEVEL]; |
|||
} |
|||
|
|||
public function opGetVersion(array $data): array { |
|||
return [ |
|||
'version' => self::VERSION, |
|||
'arsse_version' => \JKingWeb\Arsse\VERSION, |
|||
]; |
|||
} |
|||
|
|||
public function opLogin(array $data): aray { |
|||
if (isset($data['user']) && isset($data['password']) && Arsse::$user->auth($data['user'], $data['password'])) { |
|||
$id = Arsse::$db->sessionCreate($data['user']); |
|||
return [ |
|||
'session_id' => $id, |
|||
'api_level' => self::LEVEL |
|||
]; |
|||
} else { |
|||
throw new Exception("LOGIN_ERROR"); |
|||
} |
|||
} |
|||
|
|||
public function opLogout(array $data): array { |
|||
Arsse::$db->sessionDestroy(Arsse::$user->id, $data['sid']); |
|||
return ['status' => "OK"]; |
|||
} |
|||
|
|||
public function opIsLoggedIn(array $data): array { |
|||
// session validity is already checked by the dispatcher, so we need only return true |
|||
return ['status' => true]; |
|||
} |
|||
} |
@ -0,0 +1,17 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse\REST\TinyTinyRSS; |
|||
|
|||
class Exception extends \Exception { |
|||
protected $data = []; |
|||
|
|||
public function __construct($msg = "UNSPECIFIED_ERROR", $data = [], $e = null) { |
|||
$this->data = $data; |
|||
parent::__construct($msg, 0, $e); |
|||
} |
|||
|
|||
public function getData(): array { |
|||
$err = ['error' => $this->getMesssage()]; |
|||
return array_merge($err, $this->data, $err); |
|||
} |
|||
} |
Loading…
Reference in new issue