oauth, first throw

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
pull/985/head
Maxence Lange 2020-08-28 01:35:57 -01:00
rodzic e986ca6a4f
commit 8965acea03
28 zmienionych plików z 2180 dodań i 311 usunięć

Wyświetl plik

@ -40,9 +40,9 @@ return [
['name' => 'Config#local', 'url' => '/local/', 'verb' => 'GET'],
['name' => 'Config#remote', 'url' => '/test/{account}/', 'verb' => 'GET'],
[
'name' => 'Navigation#timeline', 'url' => '/timeline/{path}', 'verb' => 'GET',
'name' => 'Navigation#timeline', 'url' => '/timeline/{path}', 'verb' => 'GET',
'requirements' => ['path' => '.+'],
'defaults' => ['path' => '']
'defaults' => ['path' => '']
],
['name' => 'Navigation#documentGet', 'url' => '/document/get', 'verb' => 'GET'],
['name' => 'Navigation#documentGetPublic', 'url' => '/document/public', 'verb' => 'GET'],
@ -62,21 +62,26 @@ return [
['name' => 'ActivityPub#displayPost', 'url' => '/@{username}/{token}', 'verb' => 'GET'],
// OStatus
['name' => 'OStatus#subscribe', 'url' => '/ostatus/follow/', 'verb' => 'GET'],
['name' => 'OStatus#followRemote', 'url' => '/api/v1/ostatus/followRemote/{local}', 'verb' => 'GET'],
['name' => 'OStatus#getLink', 'url' => '/api/v1/ostatus/link/{local}/{account}', 'verb' => 'GET'],
// OAuth
['name' => 'ActivityStream#apps', 'url' => '/api/v1/apps', 'verb' => 'POST'],
['name' => 'ActivityStream#authorize', 'url' => '/oauth/authorize', 'verb' => 'GET'],
['name' => 'ActivityStream#token', 'url' => '/oauth/token', 'verb' => 'POST'],
['name' => 'ActivityStream#appsCredentials', 'url' => '/api/v1/apps/verify_credentials', 'verb' => 'GET'],
['name' => 'ActivityStream#accountsCredentials', 'url' => '/api/v1/accounts/verify_credentials', 'verb' => 'GET'],
// New Local
['name' => 'ActivityStream#timelines', 'url' => '/api/v1/timelines/{timeline}/', 'verb' => 'GET'],
['name' => 'OAuth#apps', 'url' => '/api/v1/apps', 'verb' => 'POST'],
['name' => 'OAuth#authorize', 'url' => '/oauth/authorize', 'verb' => 'GET'],
['name' => 'OAuth#token', 'url' => '/oauth/token', 'verb' => 'POST'],
['name' => 'OAuth#appsCredentials', 'url' => '/api/v1/apps/verify_credentials', 'verb' => 'GET'],
[
'name' => 'OAuth#accountsCredentials', 'url' => '/api/v1/accounts/verify_credentials',
'verb' => 'GET'
],
// Api for 3rd party
['name' => 'Api#timelines', 'url' => '/api/v1/timelines/{timeline}/', 'verb' => 'GET'],
// Api for local front-end
// TODO: front-end should be using the new ApiController
['name' => 'Local#streamHome', 'url' => '/api/v1/stream/home', 'verb' => 'GET'],
['name' => 'Local#streamNotifications', 'url' => '/api/v1/stream/notifications', 'verb' => 'GET'],
['name' => 'Local#streamTimeline', 'url' => '/api/v1/stream/timeline', 'verb' => 'GET'],

Wyświetl plik

@ -34,7 +34,7 @@ use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse;
use daita\MySmallPhpTools\Traits\TAsync;
use daita\MySmallPhpTools\Traits\TStringTools;
use Exception;
use OC\AppFramework\Http;
use OCP\AppFramework\Http;
use OCA\Social\AppInfo\Application;
use OCA\Social\Exceptions\AccountDoesNotExistException;
use OCA\Social\Exceptions\ItemUnknownException;

Wyświetl plik

@ -0,0 +1,208 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Controller;
use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse;
use Exception;
use OCA\Social\AppInfo\Application;
use OCA\Social\Exceptions\AccountDoesNotExistException;
use OCA\Social\Exceptions\ClientAuthDoesNotExistException;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\ActivityPub\Stream;
use OCA\Social\Service\AccountService;
use OCA\Social\Service\CacheActorService;
use OCA\Social\Service\ClientService;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\FollowService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\StreamService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;
use OCP\IUserSession;
class ApiController extends Controller {
use TNCDataResponse;
/** @var IUserSession */
private $userSession;
/** @var ClientService */
private $clientService;
/** @var AccountService */
private $accountService;
/** @var CacheActorService */
private $cacheActorService;
/** @var FollowService */
private $followService;
/** @var StreamService */
private $streamService;
/** @var ConfigService */
private $configService;
/** @var MiscService */
private $miscService;
/** @var string */
private $bearer = '';
/** @var Person */
private $viewer;
/**
* ActivityStreamController constructor.
*
* @param IRequest $request
* @param IUserSession $userSession
* @param ClientService $clientService
* @param AccountService $accountService
* @param CacheActorService $cacheActorService
* @param FollowService $followService
* @param StreamService $streamService
* @param ConfigService $configService
* @param MiscService $miscService
*/
public function __construct(
IRequest $request, IUserSession $userSession, ClientService $clientService,
AccountService $accountService,
CacheActorService $cacheActorService, FollowService $followService, StreamService $streamService,
ConfigService $configService, MiscService $miscService
) {
parent::__construct(Application::APP_NAME, $request);
$this->userSession = $userSession;
$this->clientService = $clientService;
$this->accountService = $accountService;
$this->cacheActorService = $cacheActorService;
$this->followService = $followService;
$this->streamService = $streamService;
$this->configService = $configService;
$this->miscService = $miscService;
$authHeader = trim($this->request->getHeader('Authorization'));
list($authType, $authToken) = explode(' ', $authHeader);
if (strtolower($authType) === 'bearer') {
$this->bearer = $authToken;
}
}
/**
* @NoCSRFRequired
* @NoAdminRequired
* @PublicPage
*
* @param string $timeline
* @param int $limit
*
* @return DataResponse
*/
public function timelines(string $timeline, int $limit = 20): DataResponse {
try {
$this->initViewer(true);
$posts = $this->streamService->getStreamHome(0, $limit, Stream::FORMAT_LOCAL);
return new DataResponse($posts, Http::STATUS_OK);
} catch (Exception $e) {
return $this->fail($e);
}
}
/**
*
* @param bool $exception
*
* @return bool
* @throws AccountDoesNotExistException
*/
private function initViewer(bool $exception = false): bool {
$userId = $this->currentSession($exception);
try {
$this->viewer = $this->accountService->getActorFromUserId($userId);
$this->streamService->setViewer($this->viewer);
$this->followService->setViewer($this->viewer);
$this->cacheActorService->setViewer($this->viewer);
} catch (Exception $e) {
if ($exception) {
throw new AccountDoesNotExistException(
'unable to initViewer - ' . get_class($e) . ' - ' . $e->getMessage()
);
}
return false;
}
return true;
}
/**
* @param bool $exception
*
* @return string
* @throws AccountDoesNotExistException
*/
private function currentSession(bool $exception): string {
$user = $this->userSession->getUser();
if ($user !== null) {
return $user->getUID();
}
if ($this->bearer !== '') {
try {
$clientAuth = $this->clientService->getAuthFromToken($this->bearer);
return $clientAuth->getUserId();
} catch (ClientAuthDoesNotExistException $e) {
}
}
throw new AccountDoesNotExistException('userId not defined');
}
}

Wyświetl plik

@ -34,7 +34,7 @@ use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse;
use daita\MySmallPhpTools\Traits\TArrayTools;
use Exception;
use OC;
use OC\AppFramework\Http;
use OCP\AppFramework\Http;
use OC\User\NoUserException;
use OCA\Social\AppInfo\Application;
use OCA\Social\Exceptions\AccountAlreadyExistsException;

Wyświetl plik

@ -31,38 +31,41 @@ namespace OCA\Social\Controller;
use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse;
use Exception;
use OC\AppFramework\Http;
use OC\User\NoUserException;
use OCA\Social\AppInfo\Application;
use OCA\Social\Exceptions\AccountAlreadyExistsException;
use OCA\Social\Exceptions\AccountDoesNotExistException;
use OCA\Social\Exceptions\ActorDoesNotExistException;
use OCA\Social\Exceptions\ClientAppDoesNotExistException;
use OCA\Social\Exceptions\ClientAuthDoesNotExistException;
use OCA\Social\Exceptions\ClientException;
use OCA\Social\Exceptions\ItemAlreadyExistsException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Exceptions\UrlCloudException;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\ActivityPub\Stream;
use OCA\Social\Model\ActivityStream\ClientApp;
use OCA\Social\Model\Client\ClientApp;
use OCA\Social\Model\Client\ClientAuth;
use OCA\Social\Model\Client\ClientToken;
use OCA\Social\Service\AccountService;
use OCA\Social\Service\CacheActorService;
use OCA\Social\Service\ClientService;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\FollowService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\StreamService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;
use OCP\IUserSession;
class ActivityStreamController extends Controller {
class OAuthController extends Controller {
use TNCDataResponse;
/** @var IUserSession */
private $userSession;
/** @var AccountService */
private $accountService;
@ -72,12 +75,6 @@ class ActivityStreamController extends Controller {
/** @var ClientService */
private $clientService;
/** @var FollowService */
private $followService;
/** @var StreamService */
private $streamService;
/** @var ConfigService */
private $configService;
@ -85,46 +82,33 @@ class ActivityStreamController extends Controller {
private $miscService;
/** @var string */
private $bearer = '';
/** @var Person */
private $viewer;
/**
* ActivityStreamController constructor.
*
* @param IRequest $request
* @param IUserSession $userSession
* @param AccountService $accountService
* @param CacheActorService $cacheActorService
* @param ClientService $clientService
* @param FollowService $followService
* @param StreamService $streamService
* @param ConfigService $configService
* @param MiscService $miscService
*/
public function __construct(
IRequest $request, AccountService $accountService, CacheActorService $cacheActorService,
ClientService $clientService, FollowService $followService, StreamService $streamService,
ConfigService $configService,
IRequest $request, IUserSession $userSession, AccountService $accountService,
CacheActorService $cacheActorService, ClientService $clientService, ConfigService $configService,
MiscService $miscService
) {
parent::__construct(Application::APP_NAME, $request);
$this->userSession = $userSession;
$this->accountService = $accountService;
$this->cacheActorService = $cacheActorService;
$this->clientService = $clientService;
$this->followService = $followService;
$this->streamService = $streamService;
$this->configService = $configService;
$this->miscService = $miscService;
$authHeader = trim($this->request->getHeader('Authorization'));
list($authType, $authToken) = explode(' ', $authHeader);
if (strtolower($authType) === 'bearer') {
$this->bearer = $authToken;
}
$body = file_get_contents('php://input');
$this->miscService->log('[ClientService] input: ' . $body, 1);
}
@ -138,64 +122,88 @@ class ActivityStreamController extends Controller {
* @param string $client_name
*
* @return Response
* @throws ClientException
*/
public function apps(
string $website = '', string $redirect_uris = '', string $scopes = '', string $client_name = ''
string $client_name, string $redirect_uris, string $website = '', string $scopes = 'read'
): Response {
// TODO: manage array from request
if (!is_array($redirect_uris)) {
$redirect_uris = [$redirect_uris];
}
$clientApp = new ClientApp();
$clientApp->setWebsite($website);
$clientApp->setRedirectUri($redirect_uris);
$clientApp->setRedirectUris($redirect_uris);
$clientApp->setScopesFromString($scopes);
$clientApp->setName($client_name);
$this->clientService->createClient($clientApp);
$this->miscService->log('### ' . json_encode($clientApp));
return $this->directSuccess($clientApp);
return new DataResponse($clientApp, Http::STATUS_OK);
}
/**
* @NoCSRFRequired
* @NoAdminRequired
* @PublicPage
*
* @param string $client_id
* @param string $redirect_uri
* @param string $response_type
* @param string $scope
*
* @return DataResponse
* @throws SocialAppConfigException
* @throws AccountAlreadyExistsException
* @throws ActorDoesNotExistException
* @throws ClientAppDoesNotExistException
* @throws ClientException
* @throws ItemAlreadyExistsException
* @throws UrlCloudException
* @throws NoUserException
* @throws SocialAppConfigException
* @throws UrlCloudException
*/
public function authorize(): DataResponse {
$userId = 'cult';
public function authorize(
string $client_id, string $redirect_uri, string $response_type, string $scope = 'read'
): DataResponse {
$user = $this->userSession->getUser();
$account = $this->accountService->getActorFromUserId($user->getUID());
$account = $this->accountService->getActorFromUserId($userId);
$clientId = (string)$this->request->getParam('client_id', '');
$responseType = (string)$this->request->getParam('response_type', '');
$redirectUri = (string)$this->request->getParam('redirect_uri', '');
if ($responseType !== 'code') {
if ($response_type !== 'code') {
return new DataResponse(['error' => 'invalid_type'], Http::STATUS_BAD_REQUEST);
}
// $this->clientService->assignAccount($clientId, $account);
$code = 'test1234';
$clientApp = $this->clientService->getClientByClientId($client_id);
$this->clientService->confirmData(
$clientApp,
[
'scopes' => $scope,
]
);
if ($redirectUri !== '') {
header('Location: ' . $redirectUri . '?code=' . $code);
$clientAuth = new ClientAuth();
$clientAuth->setRedirectUri($redirect_uri);
$clientAuth->setScopes(explode(' ', $scope));
$clientAuth->setAccount($account->getPreferredUsername());
$clientAuth->setUserId($user->getUID());
$this->clientService->authClient($clientApp, $clientAuth);
$code = $clientAuth->getCode();
if ($redirect_uri !== 'urn:ietf:wg:oauth:2.0:oob') {
header('Location: ' . $redirect_uri . '?code=' . $code);
exit();
}
// return new DataResponse(
// [
// TODO : finalize result if no redirect_url
return new DataResponse(
[
// 'access_token' => '',
// "token_type" => "Bearer",
// "scope" => "read write follow push",
// "created_at" => 1573979017
// ], Http::STATUS_OK
// );
], Http::STATUS_OK
);
}
@ -205,21 +213,60 @@ class ActivityStreamController extends Controller {
* @NoAdminRequired
* @PublicPage
*
* @param string $client_id
* @param string $client_secret
* @param string $redirect_uri
* @param string $grant_type
* @param string $scope
* @param string $code
*
* @return DataResponse
* @throws ClientAppDoesNotExistException
* @throws ClientException
* @throws ClientAuthDoesNotExistException
*/
public function token() {
$body = file_get_contents('php://input');
$this->miscService->log('[<<] : ' . $body, 1);
////code=test1234&grant_type=authorization_code&
//client_secret=amJWTrlnZEhe44aXHsW2xlsTLD8g0DqabDDJ7jdp&
//redirect_uri=https%3A%2F%2Forg.mariotaku.twidere%2Fauth%2Fcallback%2Fmastodon&
//client_id=ihyiNapjftENlY2dZCbbfLHYoloB1HbpWQyLGtvr
public function token(
string $client_id, string $client_secret, string $redirect_uri, string $grant_type,
string $scope = 'read', string $code = ''
) {
$clientApp = $this->clientService->getClientByClientId($client_id);
$this->clientService->confirmData(
$clientApp,
[
'client_secret' => $client_secret,
'redirect_uri' => $redirect_uri,
'scopes' => $scope
]
);
$clientToken = new ClientToken();
$clientToken->setScopes(explode(' ', $scope));
if ($grant_type === 'authorization_code') {
if ($code === '') {
return new DataResponse(['error' => 'missing code'], Http::STATUS_BAD_REQUEST);
}
$clientAuth = $this->clientService->getAuthByCode($code);
$this->clientService->generateToken($clientApp, $clientAuth, $clientToken);
} else if ($grant_type === 'client_credentials') {
// TODO: manage client_credentials
} else {
return new DataResponse(['error' => 'invalid value for grant_type'], Http::STATUS_BAD_REQUEST);
}
if ($clientToken->getToken() === '') {
return new DataResponse(['error' => 'issue generating access_token'], Http::STATUS_BAD_REQUEST);
}
return new DataResponse(
[
"access_token" => "ZA-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL0",
"token_type" => "Bearer",
"scope" => "read write follow push",
"created_at" => time()
"access_token" => $clientToken->getToken(),
"token_type" => 'Bearer',
"scope" => $scope,
"created_at" => $clientToken->getCreation()
], 200
);
}
@ -286,63 +333,6 @@ class ActivityStreamController extends Controller {
}
/**
* @NoCSRFRequired
* @NoAdminRequired
* @PublicPage
*
* @param string $timeline
* @param int $limit
*
* @return DataResponse
*/
public function timelines(string $timeline, int $limit = 20): DataResponse {
try {
$this->initViewer(true);
$posts = $this->streamService->getStreamHome(0, $limit, Stream::FORMAT_LOCAL);
return new DataResponse($posts, 200);
} catch (Exception $e) {
return $this->fail($e);
}
}
/**
*
* @param bool $exception
*
* @return bool
* @throws AccountDoesNotExistException
*/
private function initViewer(bool $exception = false): bool {
if ($this->bearer === '') {
// if ($exception) {
// throw new AccountDoesNotExistException('userId not defined');
// }
//
// return false;
}
try {
$this->viewer = $this->cacheActorService->getFromLocalAccount('cult');
$this->streamService->setViewer($this->viewer);
$this->followService->setViewer($this->viewer);
$this->cacheActorService->setViewer($this->viewer);
} catch (Exception $e) {
if ($exception) {
throw new AccountDoesNotExistException(
'unable to initViewer - ' . get_class($e) . ' - ' . $e->getMessage()
);
}
return false;
}
return true;
}
}

Wyświetl plik

@ -35,12 +35,12 @@ use daita\MySmallPhpTools\Traits\TArrayTools;
use DateTime;
use Exception;
use OCA\Social\Exceptions\ClientAppDoesNotExistException;
use OCA\Social\Model\ActivityStream\ClientApp;
use OCA\Social\Model\Client\ClientApp;
use OCP\DB\QueryBuilder\IQueryBuilder;
/**
* Class ActionsRequest
* Class ClientAppRequest
*
* @package OCA\Social\Db
*/
@ -59,9 +59,10 @@ class ClientAppRequest extends ClientAppRequestBuilder {
$qb = $this->getClientAppInsertSql();
$qb->setValue('name', $qb->createNamedParameter($clientApp->getName()))
->setValue('website', $qb->createNamedParameter($clientApp->getWebsite()))
->setValue('redirect_uri', $qb->createNamedParameter($clientApp->getRedirectUri()))
->setValue('redirect_uris', $qb->createNamedParameter(json_encode($clientApp->getRedirectUris())))
->setValue('client_id', $qb->createNamedParameter($clientApp->getClientId()))
->setValue('client_secret', $qb->createNamedParameter($clientApp->getClientSecret()));
->setValue('client_secret', $qb->createNamedParameter($clientApp->getClientSecret()))
->setValue('scopes', $qb->createNamedParameter(json_encode($clientApp->getScopes())));
try {
$qb->setValue(
@ -100,7 +101,6 @@ class ClientAppRequest extends ClientAppRequestBuilder {
*/
public function getByClientId(string $clientId): ClientApp {
$qb = $this->getClientAppSelectSql();
$qb->limitToClientId($clientId);
return $this->getClientAppFromRequest($qb);

Wyświetl plik

@ -34,7 +34,7 @@ namespace OCA\Social\Db;
use daita\MySmallPhpTools\Exceptions\RowNotFoundException;
use daita\MySmallPhpTools\Traits\TArrayTools;
use OCA\Social\Exceptions\ClientAppDoesNotExistException;
use OCA\Social\Model\ActivityStream\ClientApp;
use OCA\Social\Model\Client\ClientApp;
/**
@ -55,7 +55,7 @@ class ClientAppRequestBuilder extends CoreRequestBuilder {
*/
protected function getClientAppInsertSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->insert(self::TABLE_CLIENT_APP);
$qb->insert(self::TABLE_CLIENT);
return $qb;
}
@ -68,7 +68,7 @@ class ClientAppRequestBuilder extends CoreRequestBuilder {
*/
protected function getClientAppUpdateSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->update(self::TABLE_CLIENT_APP);
$qb->update(self::TABLE_CLIENT);
return $qb;
}
@ -84,13 +84,13 @@ class ClientAppRequestBuilder extends CoreRequestBuilder {
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->select(
'ca.id', 'ca.name', 'ca.website', 'ca.redirect_uri', 'ca.client_id', 'ca.client_secret',
'ca.creation'
'cl.id', 'cl.name', 'cl.website', 'cl.redirect_uris', 'cl.client_id', 'cl.client_secret',
'cl.scopes', 'cl.creation'
)
->from(self::TABLE_CLIENT_APP, 'ca');
->from(self::TABLE_CLIENT, 'cl');
$this->defaultSelectAlias = 'ca';
$qb->setDefaultSelectAlias('ca');
$this->defaultSelectAlias = 'cl';
$qb->setDefaultSelectAlias('cl');
return $qb;
}
@ -103,7 +103,7 @@ class ClientAppRequestBuilder extends CoreRequestBuilder {
*/
protected function getClientAppDeleteSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->delete(self::TABLE_CLIENT_APP);
$qb->delete(self::TABLE_CLIENT);
return $qb;
}

Wyświetl plik

@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Db;
use daita\MySmallPhpTools\Traits\TArrayTools;
use DateTime;
use OCA\Social\Exceptions\ClientAuthDoesNotExistException;
use OCA\Social\Model\ActivityStream\ClientApp;
use OCA\Social\Model\Client\ClientAuth;
use OCP\DB\QueryBuilder\IQueryBuilder;
/**
* Class ClientAuthRequest
*
* @package OCA\Social\Db
*/
class ClientAuthRequest extends ClientAuthRequestBuilder {
use TArrayTools;
/**
* @param ClientAuth $clientAuth
*/
public function save(ClientAuth $clientAuth) {
$qb = $this->getClientAuthInsertSql();
$now = new DateTime('now');
$qb->setValue('client_id', $qb->createNamedParameter($clientAuth->getClientId()))
->setValue('account', $qb->createNamedParameter($clientAuth->getAccount()))
->setValue('code', $qb->createNamedParameter($clientAuth->getCode()))
->setValue('user_id', $qb->createNamedParameter($clientAuth->getUserId()))
->setValue('last_update', $qb->createNamedParameter($now, IQueryBuilder::PARAM_DATE))
->setValue('creation', $qb->createNamedParameter($now, IQueryBuilder::PARAM_DATE));
$qb->execute();
}
/**
* @param string $code
*
* @return ClientAuth
* @throws ClientAuthDoesNotExistException
*/
public function getByCode(string $code): ClientAuth {
$qb = $this->getClientAuthSelectSql();
$qb->limitToDBField('code', $code);
return $this->getClientAuthFromRequest($qb);
}
/**
* @param string $token
*
* @return ClientAuth
* @throws ClientAuthDoesNotExistException
*/
public function getByToken(string $token): ClientAuth {
$qb = $this->getClientAuthSelectSql();
$qb->leftJoinClientToken('clt');
$qb->limitToToken($token, 'clt');
return $this->getClientAuthFromRequest($qb);
}
}

Wyświetl plik

@ -0,0 +1,162 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Db;
use daita\MySmallPhpTools\Exceptions\RowNotFoundException;
use daita\MySmallPhpTools\Traits\TArrayTools;
use OCA\Social\Exceptions\ClientAuthDoesNotExistException;
use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Model\ActivityStream\ClientApp;
use OCA\Social\Model\Client\ClientAuth;
/**
* Class ClientAppRequestBuilder
*
* @package OCA\Social\Db
*/
class ClientAuthRequestBuilder extends CoreRequestBuilder {
use TArrayTools;
/**
* Base of the Sql Insert request
*
* @return SocialQueryBuilder
*/
protected function getClientAuthInsertSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->insert(self::TABLE_CLIENT_AUTH);
return $qb;
}
/**
* Base of the Sql Update request
*
* @return SocialQueryBuilder
*/
protected function getClientAuthUpdateSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->update(self::TABLE_CLIENT_AUTH);
return $qb;
}
/**
* Base of the Sql Select request for Shares
*
* @return SocialQueryBuilder
*/
protected function getClientAuthSelectSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->select('cla.id', 'cla.client_id', 'cla.account', 'cla.user_id', 'cla.code')
->from(self::TABLE_CLIENT_AUTH, 'cla');
$this->defaultSelectAlias = 'cla';
$qb->setDefaultSelectAlias('cla');
return $qb;
}
/**
* Base of the Sql Delete request
*
* @return SocialQueryBuilder
*/
protected function getClientAuthDeleteSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->delete(self::TABLE_CLIENT_AUTH);
return $qb;
}
/**
* @param SocialQueryBuilder $qb
*
* @return ClientAuth
* @throws ClientAuthDoesNotExistException
*/
public function getClientAuthFromRequest(SocialQueryBuilder $qb): ClientAuth {
/** @var ClientAuth $result */
try {
$result = $qb->getRow([$this, 'parseClientAuthSelectSql']);
} catch (RowNotFoundException $e) {
throw new ClientAuthDoesNotExistException($e->getMessage());
}
return $result;
}
/**
* @param SocialQueryBuilder $qb
*
* @return ClientAuth[]
*/
public function getClientAuthsFromRequest(SocialQueryBuilder $qb): array {
/** @var ClientAuth[] $result */
$result = $qb->getRows([$this, 'parseClientAuthSelectSql']);
return $result;
}
/**
* @param array $data
*
* @param SocialQueryBuilder $qb
*
* @return ClientAuth
*/
public function parseClientAuthSelectSql($data, SocialQueryBuilder $qb): ClientAuth {
$item = new ClientAuth();
$item->importFromDatabase($data);
try {
$item->setClientToken($qb->parseLeftJoinClientToken($data));
} catch (InvalidResourceException $e) {
}
return $item;
}
}

Wyświetl plik

@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Db;
use daita\MySmallPhpTools\Traits\TArrayTools;
use DateTime;
use OCA\Social\Exceptions\ClientTokenDoesNotExistException;
use OCA\Social\Model\Client\ClientToken;
use OCP\DB\QueryBuilder\IQueryBuilder;
/**
* Class ClientAuthRequest
*
* @package OCA\Social\Db
*/
class ClientTokenRequest extends ClientTokenRequestBuilder {
use TArrayTools;
/**
* @param ClientToken $clientToken
*/
public function save(ClientToken $clientToken) {
$now = new DateTime('now');
$clientToken->setCreation($now->getTimestamp());
$qb = $this->getClientTokenInsertSql();
$qb->setValue('id', $qb->createNamedParameter($clientToken->getId()))
->setValue('auth_id', $qb->createNamedParameter($clientToken->getAuthId()))
->setValue('token', $qb->createNamedParameter($clientToken->getToken()))
->setValue('last_update', $qb->createNamedParameter($now, IQueryBuilder::PARAM_DATE))
->setValue('creation', $qb->createNamedParameter($now, IQueryBuilder::PARAM_DATE));
$qb->execute();
}
/**
* @param string $code
*
* @return ClientToken
* @throws ClientTokenDoesNotExistException
*/
public function getByToken(string $code): ClientToken {
$qb = $this->getClientTokenSelectSql();
$qb->limitToDBField('token', $code);
return $this->getClientTokenFromRequest($qb);
}
}

Wyświetl plik

@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Db;
use daita\MySmallPhpTools\Exceptions\RowNotFoundException;
use daita\MySmallPhpTools\Traits\TArrayTools;
use OCA\Social\Exceptions\ClientTokenDoesNotExistException;
use OCA\Social\Model\ActivityStream\ClientApp;
use OCA\Social\Model\Client\ClientToken;
/**
* Class ClientAppRequestBuilder
*
* @package OCA\Social\Db
*/
class ClientTokenRequestBuilder extends CoreRequestBuilder {
use TArrayTools;
/**
* Base of the Sql Insert request
*
* @return SocialQueryBuilder
*/
protected function getClientTokenInsertSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->insert(self::TABLE_CLIENT_TOKEN);
return $qb;
}
/**
* Base of the Sql Update request
*
* @return SocialQueryBuilder
*/
protected function getClientTokenUpdateSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->update(self::TABLE_CLIENT_TOKEN);
return $qb;
}
/**
* Base of the Sql Select request for Shares
*
* @return SocialQueryBuilder
*/
protected function getClientTokenSelectSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->select('clt.id', 'clt.client_id', 'clt.client_auth_id', 'clt.token', 'clt.creation')
->from(self::TABLE_CLIENT_TOKEN, 'clt');
$this->defaultSelectAlias = 'clt';
$qb->setDefaultSelectAlias('clt');
return $qb;
}
/**
* Base of the Sql Delete request
*
* @return SocialQueryBuilder
*/
protected function getClientTokenDeleteSql(): SocialQueryBuilder {
$qb = $this->getQueryBuilder();
$qb->delete(self::TABLE_CLIENT_TOKEN);
return $qb;
}
/**
* @param SocialQueryBuilder $qb
*
* @return ClientToken
* @throws ClientTokenDoesNotExistException
*/
public function getClientTokenFromRequest(SocialQueryBuilder $qb): ClientToken {
/** @var ClientToken $result */
try {
$result = $qb->getRow([$this, 'parseClientTokenSelectSql']);
} catch (RowNotFoundException $e) {
throw new ClientTokenDoesNotExistException($e->getMessage());
}
return $result;
}
/**
* @param SocialQueryBuilder $qb
*
* @return ClientToken[]
*/
public function getClientTokensFromRequest(SocialQueryBuilder $qb): array {
/** @var ClientToken[] $result */
$result = $qb->getRows([$this, 'parseClientTokenSelectSql']);
return $result;
}
/**
* @param array $data
*
* @return ClientToken
*/
public function parseClientTokenSelectSql($data): ClientToken {
$item = new ClientToken();
$item->importFromDatabase($data);
return $item;
}
}

Wyświetl plik

@ -76,7 +76,9 @@ class CoreRequestBuilder {
const TABLE_CACHE_ACTORS = 'social_3_cache_actor';
const TABLE_CACHE_DOCUMENTS = 'social_3_cache_doc';
const TABLE_CLIENT_APP = 'social_3_client_app';
const TABLE_CLIENT = 'social_3_client';
const TABLE_CLIENT_AUTH = 'social_3_client_auth';
const TABLE_CLIENT_TOKEN = 'social_3_client_token';
/** @var array */
@ -93,7 +95,9 @@ class CoreRequestBuilder {
self::TABLE_STREAM_DEST,
self::TABLE_STREAM_TAGS,
self::TABLE_STREAM_ACTIONS,
self::TABLE_CLIENT_APP
self::TABLE_CLIENT,
self::TABLE_CLIENT_AUTH,
self::TABLE_CLIENT_TOKEN
];

Wyświetl plik

@ -32,8 +32,9 @@ namespace OCA\Social\Db;
use Doctrine\DBAL\Query\QueryBuilder;
use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Model\Client\ClientToken;
use OCP\DB\QueryBuilder\ICompositeExpression;
use OCP\DB\QueryBuilder\IQueryBuilder;
/**
@ -141,10 +142,9 @@ class SocialCrossQueryBuilder extends SocialCoreQueryBuilder {
/**
* @param IQueryBuilder $qb
* @param string $alias
*/
public function selectStreamActions(string $alias = 'sa') {
public function selectStreamActions(string $alias = 'sa'): void {
if ($this->getType() !== QueryBuilder::SELECT) {
return;
}
@ -161,7 +161,7 @@ class SocialCrossQueryBuilder extends SocialCoreQueryBuilder {
/**
* @param string $alias
*/
public function leftJoinStreamAction(string $alias = 'sa') {
public function leftJoinStreamAction(string $alias = 'sa'): void {
if ($this->getType() !== QueryBuilder::SELECT || !$this->hasViewer()) {
return;
}
@ -192,6 +192,56 @@ class SocialCrossQueryBuilder extends SocialCoreQueryBuilder {
}
/**
* @param string $alias
*/
public function leftJoinClientToken(string $alias = 'clt') {
if ($this->getType() !== QueryBuilder::SELECT) {
return;
}
$pf = $this->getDefaultSelectAlias();
$expr = $this->expr();
$this->selectAlias($alias . '.id', 'clienttoken_id')
->selectAlias($alias . '.auth_id', 'clienttoken_auth_id')
->selectAlias($alias . '.token', 'clienttoken_token')
->selectAlias($alias . '.scopes', 'clienttoken_scopes')
->selectAlias($alias . '.last_update', 'clienttoken_last_update')
->selectAlias($alias . '.creation', 'clienttoken_creation');
$on = $expr->andX();
$on->add($expr->eq($alias . '.auth_id', $pf . '.id'));
$this->leftJoin($this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_CLIENT_TOKEN, $alias, $on);
}
/**
* @param array $data
*
* @return ClientToken
* @throws InvalidResourceException
*/
public function parseLeftJoinClientToken(array $data): ClientToken {
$new = [];
foreach ($data as $k => $v) {
if (substr($k, 0, 12) === 'clienttoken_') {
$new[substr($k, 12)] = $v;
}
}
if (empty($new)) {
throw new InvalidResourceException();
}
$clientToken = new ClientToken();
$clientToken->importFromDatabase($new);
return $clientToken;
}
/**
* @param string $type
* @param string $field
@ -207,7 +257,6 @@ class SocialCrossQueryBuilder extends SocialCoreQueryBuilder {
/**
* @param string $type
* @param string $subType
* @param string $field
* @param string $aliasDest
* @param string $alias

Wyświetl plik

@ -139,11 +139,13 @@ class SocialLimitsQueryBuilder extends SocialCrossQueryBuilder {
* Limit the request to the token
*
* @param string $token
* @param string $alias
*/
public function limitToToken(string $token) {
$this->limitToDBField('token', $token);
public function limitToToken(string $token, string $alias = '') {
$this->limitToDBField('token', $token, true, $alias);
}
/**
* Limit the results to a given number
*

Wyświetl plik

@ -222,6 +222,7 @@ class StreamRequestBuilder extends CoreRequestBuilder {
try {
$actor = $this->parseCacheActorsLeftJoin($data);
$actor->setExportFormat($qb->getFormat());
$item->setCompleteDetails(true);
$item->setActor($actor);
} catch (InvalidResourceException $e) {

Wyświetl plik

@ -0,0 +1,39 @@
<?php
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Exceptions;
use Exception;
class ClientAuthDoesNotExistException extends Exception {
}

Wyświetl plik

@ -0,0 +1,39 @@
<?php
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Exceptions;
use Exception;
class ClientException extends Exception {
}

Wyświetl plik

@ -0,0 +1,39 @@
<?php
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Exceptions;
use Exception;
class ClientTokenDoesNotExistException extends Exception {
}

Wyświetl plik

@ -76,7 +76,9 @@ class Version0003Date20200611000001 extends SimpleMigrationStep {
$this->createActors($schema);
$this->createCacheActors($schema);
$this->createCacheDocuments($schema);
$this->createClientOauth($schema);
$this->createClient($schema);
$this->createClientAuth($schema);
$this->createClientToken($schema);
$this->createFollows($schema);
$this->createHashtags($schema);
$this->createRequestQueue($schema);
@ -907,12 +909,12 @@ class Version0003Date20200611000001 extends SimpleMigrationStep {
/**
* @param ISchemaWrapper $schema
*/
private function createClientOauth(ISchemaWrapper $schema) {
if ($schema->hasTable('social_3_client_app')) {
private function createClient(ISchemaWrapper $schema) {
if ($schema->hasTable('social_3_client')) {
return;
}
$table = $schema->createTable('social_3_client_app');
$table = $schema->createTable('social_3_client');
$table->addColumn(
'id', 'integer',
[
@ -939,10 +941,16 @@ class Version0003Date20200611000001 extends SimpleMigrationStep {
]
);
$table->addColumn(
'redirect_uri', 'string',
'scopes', 'string',
[
'notnull' => false,
'default' => '255'
]
);
$table->addColumn(
'redirect_uris', 'text',
[
'notnull' => false,
'length' => 255,
'default' => ''
]
);
@ -973,6 +981,138 @@ class Version0003Date20200611000001 extends SimpleMigrationStep {
}
/**
* @param ISchemaWrapper $schema
*/
private function createClientAuth(ISchemaWrapper $schema) {
if ($schema->hasTable('social_3_client_auth')) {
return;
}
$table = $schema->createTable('social_3_client_auth');
$table->addColumn(
'id', 'integer',
[
'autoincrement' => true,
'notnull' => true,
'length' => 7,
'unsigned' => true,
]
);
$table->addColumn(
'client_id', 'integer',
[
'notnull' => false,
'length' => 7,
'unsigned' => true
]
);
$table->addColumn(
'scopes', 'text',
[
'notnull' => false
]
);
$table->addColumn(
'account', 'string',
[
'notnull' => false,
'length' => 127,
'default' => ''
]
);
$table->addColumn(
'user_id', 'string',
[
'notnull' => false,
'length' => 127,
'default' => ''
]
);
$table->addColumn(
'code', 'string',
[
'notnull' => false,
'length' => 127,
'default' => ''
]
);
$table->addColumn(
'last_update', 'datetime',
[
'notnull' => false,
]
);
$table->addColumn(
'creation', 'datetime',
[
'notnull' => false,
]
);
$table->setPrimaryKey(['id']);
$table->addIndex(['client_id']);
}
/**
* @param ISchemaWrapper $schema
*/
private function createClientToken(ISchemaWrapper $schema) {
if ($schema->hasTable('social_3_client_token')) {
return;
}
$table = $schema->createTable('social_3_client_token');
$table->addColumn(
'id', 'integer',
[
'autoincrement' => true,
'notnull' => true,
'length' => 11,
'unsigned' => true
]
);
$table->addColumn(
'auth_id', 'integer',
[
'notnull' => false,
'length' => 7,
'unsigned' => true
]
);
$table->addColumn(
'token', 'string',
[
'notnull' => false,
'length' => 127,
'default' => ''
]
);
$table->addColumn(
'scopes', 'text',
[
'notnull' => false
]
);
$table->addColumn(
'last_update', 'datetime',
[
'notnull' => false,
]
);
$table->addColumn(
'creation', 'datetime',
[
'notnull' => false,
]
);
$table->setPrimaryKey(['id']);
$table->addIndex(['token', 'auth_id']);
}
/**
* @param ISchemaWrapper $schema
*/

Wyświetl plik

@ -73,7 +73,9 @@ class Version0003Date20200823023911 extends SimpleMigrationStep {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$this->createClientOauth($schema);
$this->createClient($schema);
$this->createClientAuth($schema);
$this->createClientToken($schema);
$this->addChunkToTable($schema, 'social_3_stream', '');
$this->addChunkToTable($schema, 'social_3_stream_act', '_act');
@ -86,12 +88,12 @@ class Version0003Date20200823023911 extends SimpleMigrationStep {
/**
* @param ISchemaWrapper $schema
*/
private function createClientOauth(ISchemaWrapper $schema) {
if ($schema->hasTable('social_3_client_app')) {
private function createClient(ISchemaWrapper $schema) {
if ($schema->hasTable('social_3_client')) {
return;
}
$table = $schema->createTable('social_3_client_app');
$table = $schema->createTable('social_3_client');
$table->addColumn(
'id', 'integer',
[
@ -118,10 +120,16 @@ class Version0003Date20200823023911 extends SimpleMigrationStep {
]
);
$table->addColumn(
'redirect_uri', 'string',
'scopes', 'string',
[
'notnull' => false,
'default' => '255'
]
);
$table->addColumn(
'redirect_uris', 'text',
[
'notnull' => false,
'length' => 255,
'default' => ''
]
);
@ -152,6 +160,138 @@ class Version0003Date20200823023911 extends SimpleMigrationStep {
}
/**
* @param ISchemaWrapper $schema
*/
private function createClientAuth(ISchemaWrapper $schema) {
if ($schema->hasTable('social_3_client_auth')) {
return;
}
$table = $schema->createTable('social_3_client_auth');
$table->addColumn(
'id', 'integer',
[
'autoincrement' => true,
'notnull' => true,
'length' => 7,
'unsigned' => true,
]
);
$table->addColumn(
'client_id', 'integer',
[
'notnull' => false,
'length' => 7,
'unsigned' => true
]
);
$table->addColumn(
'scopes', 'text',
[
'notnull' => false
]
);
$table->addColumn(
'account', 'string',
[
'notnull' => false,
'length' => 127,
'default' => ''
]
);
$table->addColumn(
'user_id', 'string',
[
'notnull' => false,
'length' => 127,
'default' => ''
]
);
$table->addColumn(
'code', 'string',
[
'notnull' => false,
'length' => 127,
'default' => ''
]
);
$table->addColumn(
'last_update', 'datetime',
[
'notnull' => false,
]
);
$table->addColumn(
'creation', 'datetime',
[
'notnull' => false,
]
);
$table->setPrimaryKey(['id']);
$table->addIndex(['client_id']);
}
/**
* @param ISchemaWrapper $schema
*/
private function createClientToken(ISchemaWrapper $schema) {
if ($schema->hasTable('social_3_client_token')) {
return;
}
$table = $schema->createTable('social_3_client_token');
$table->addColumn(
'id', 'integer',
[
'autoincrement' => true,
'notnull' => true,
'length' => 11,
'unsigned' => true
]
);
$table->addColumn(
'auth_id', 'integer',
[
'notnull' => false,
'length' => 7,
'unsigned' => true
]
);
$table->addColumn(
'token', 'string',
[
'notnull' => false,
'length' => 127,
'default' => ''
]
);
$table->addColumn(
'scopes', 'text',
[
'notnull' => false
]
);
$table->addColumn(
'last_update', 'datetime',
[
'notnull' => false,
]
);
$table->addColumn(
'creation', 'datetime',
[
'notnull' => false,
]
);
$table->setPrimaryKey(['id']);
$table->addIndex(['token', 'auth_id']);
}
/**
* @param ISchemaWrapper $schema
* @param string $tableName

Wyświetl plik

@ -757,96 +757,8 @@ class ACore extends Item implements JsonSerializable {
*/
public function exportAsLocal(): array {
return [
"id" => "104745311773345735",
"created_at" => "2020-08-24T16=>29=>13.000Z",
"in_reply_to_id" => null,
"in_reply_to_account_id" => null,
"sensitive" => false,
"spoiler_text" => "",
"visibility" => "unlisted",
"language" => "de",
// 'id' => $this->getId(),
// 'uri' => $this->getId(),
// 'url' => $this->getId(),
'replies_count' => 0,
'reblogs_count' => 0,
'favourites_count' => 0,
'favourited' => false,
'reblogged' => false,
'muted' => false,
'bookmarked' => false,
"content" => "\u003cp\u003e\"Mit den frisch freigegebenen Versionen 3.0 und 3.13 aktualisiert Nextcloud seine Desktop- und Android-Clients. Zentrale Neuerung ist die nun für den produktiven Einsatz einsatzbereite Ende-zu-Ende-Verschlüsselung.\" | iX Magazin @heiseonline \u003cbr\u003e\u003ca href=\"https://www.heise.de/news/Neue-Nextcloud-Clients-mit-Ende-zu-Ende-Verschluesselung-4873632.html\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://www.\u003c/span\u003e\u003cspan class=\"ellipsis\"\u003eheise.de/news/Neue-Nextcloud-C\u003c/span\u003e\u003cspan class=\"invisible\"\u003elients-mit-Ende-zu-Ende-Verschluesselung-4873632.html\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e",
"reblog" => null,
"account" => [
"id" => "126222",
"username" => "nextcloud",
"acct" => "nextcloud@mastodon.xyz",
"display_name" => "Nextcloud 📱☁️💻",
"locked" => false,
"bot" => false,
"discoverable" => false,
"group" => false,
"created_at" => "2017-05-02T09=>56=>41.951Z",
"note" => "\u003cp\u003eA safe home for all your data, community-driven \u0026amp; open source!\u003cbr\u003e\u003ca href=\"https=>//nextcloud.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps=>//\u003c/span\u003e\u003cspan class=\"\"\u003enextcloud.com\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e\u003cbr\u003eJoin us at \u003ca href=\"https=>//help.nextcloud.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps=>//\u003c/span\u003e\u003cspan class=\"\"\u003ehelp.nextcloud.com\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e and \u003ca href=\"https=>//github.com/nextcloud\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps=>//\u003c/span\u003e\u003cspan class=\"\"\u003egithub.com/nextcloud\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e 😊\u003c/p\u003e",
"url" => "https=>//mastodon.xyz/@nextcloud",
"avatar" => "https=>//files.mastodon.social/accounts/avatars/000/126/222/original/50785214e44d10cc.jpeg",
"avatar_static" => "https=>//files.mastodon.social/accounts/avatars/000/126/222/original/50785214e44d10cc.jpeg",
"header" => "https=>//files.mastodon.social/accounts/headers/000/126/222/original/6d7b41fdd92cfd6f.jpeg",
"header_static" => "https=>//files.mastodon.social/accounts/headers/000/126/222/original/6d7b41fdd92cfd6f.jpeg",
"followers_count" => 9451,
"following_count" => 132,
"statuses_count" => 3020,
"last_status_at" => "2020-08-24",
"emojis" => []
]
// "fields": [
// {
// "name": "💻 Website",
// "value": "\u003ca href=\"https://nextcloud.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003enextcloud.com\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e",
// "verified_at": null
// },
// {
// "name": "😍 Contribute",
// "value": "\u003ca href=\"https://nextcloud.com/contribute\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003enextcloud.com/contribute\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e",
// "verified_at": null
// },
// {
// "name": "🌈 Include initiative",
// "value": "\u003ca href=\"https://nextcloud.com/include\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003enextcloud.com/include\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e",
// "verified_at": null
// },
// {
// "name": "💬 Forum",
// "value": "\u003ca href=\"https://help.nextcloud.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003ehelp.nextcloud.com\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e",
// "verified_at": null
// }
// ]
// }
"id" => $this->getId(),
];
// "media_attachments": [],
// "mentions": [],
// "tags": [],
// "emojis": [],
// "card": {
// "url": "https://www.heise.de/news/Neue-Nextcloud-Clients-mit-Ende-zu-Ende-Verschluesselung-4873632.html",
// "title": "Neue Nextcloud-Clients mit Ende-zu-Ende-Verschlüsselung",
// "description": "Nextcloud aktualisiert seine Desktop- und Android-Clients. Zentrale Neuerung ist die Ende-zu-Ende-Verschlüsselung, die aber nicht für alle Dateien gedacht ist.",
// "type": "link",
// "author_name": "",
// "author_url": "",
// "provider_name": "",
// "provider_url": "",
// "html": "",
// "width": 400,
// "height": 225,
// "image": "https://files.mastodon.social/cache/preview_cards/images/023/249/328/original/3710f7a1b54f0319.png",
// "embed_url": "",
// "blurhash": "UbNwWf_3%L00Rkayt6ofRkIVjYxut7fkoej["
// },
// "poll": null
// },
}
}

Wyświetl plik

@ -73,6 +73,12 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
/** @var string */
private $preferredUsername = '';
/** @var string */
private $displayName = '';
/** @var string */
private $description = '';
/** @var string */
private $publicKey = '';
@ -103,13 +109,21 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
/** @var string */
private $featured = '';
/** @var bool */
private $locked = false;
/** @var bool */
private $bot = false;
/** @var bool */
private $discoverable = false;
/** @var int */
private $avatarVersion = -1;
/** @var string */
private $viewerLink = '';
/**
* Person constructor.
*
@ -134,7 +148,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setUserId(string $userId): Person {
public function setUserId(string $userId): self {
$this->userId = $userId;
return $this;
@ -153,13 +167,49 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setPreferredUsername(string $preferredUsername): Person {
public function setPreferredUsername(string $preferredUsername): self {
$this->preferredUsername = $preferredUsername;
return $this;
}
/**
* @return string
*/
public function getDisplayName(): string {
if ($this->displayName === '') {
return $this->getPreferredUsername();
}
return $this->displayName;
}
public function setDisplayName(string $displayName): string {
$this->displayName = $displayName;
}
/**
* @return string
*/
public function getDescription(): string {
return $this->description;
}
/**
* @param string $description
*
* @return Person
*/
public function setDescription(string $description): self {
$this->description = $description;
return $this;
}
/**
* @return string
*/
@ -172,7 +222,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setPublicKey(string $publicKey): Person {
public function setPublicKey(string $publicKey): self {
$this->publicKey = $publicKey;
return $this;
@ -191,7 +241,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setPrivateKey(string $privateKey): Person {
public function setPrivateKey(string $privateKey): self {
$this->privateKey = $privateKey;
return $this;
@ -210,7 +260,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setCreation(int $creation): Person {
public function setCreation(int $creation): self {
$this->creation = $creation;
return $this;
@ -229,7 +279,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setFollowing(string $following): Person {
public function setFollowing(string $following): self {
$this->following = $following;
return $this;
@ -247,7 +297,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setFollowers(string $followers): Person {
public function setFollowers(string $followers): self {
$this->followers = $followers;
return $this;
@ -265,7 +315,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setAccount(string $account): Person {
public function setAccount(string $account): self {
if ($account !== '' && substr($account, 0, 1) === '@') {
$account = substr($account, 1);
}
@ -288,7 +338,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setInbox(string $inbox): Person {
public function setInbox(string $inbox): self {
$this->inbox = $inbox;
return $this;
@ -306,7 +356,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setOutbox(string $outbox): Person {
public function setOutbox(string $outbox): self {
$this->outbox = $outbox;
return $this;
@ -324,7 +374,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setSharedInbox(string $sharedInbox): Person {
public function setSharedInbox(string $sharedInbox): self {
$this->sharedInbox = $sharedInbox;
return $this;
@ -342,7 +392,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setName(string $name): Person {
public function setName(string $name): self {
$this->name = $name;
return $this;
@ -361,13 +411,70 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setFeatured(string $featured): Person {
public function setFeatured(string $featured): self {
$this->featured = $featured;
return $this;
}
/**
* @return bool
*/
public function isLocked(): bool {
return $this->locked;
}
/**
* @param bool $locked
*
* @return Person
*/
public function setLocked(bool $locked): self {
$this->locked = $locked;
return $this;
}
/**
* @return bool
*/
public function isBot(): bool {
return $this->bot;
}
/**
* @param bool $bot
*
* @return Person
*/
public function setBot(bool $bot): self {
$this->bot = $bot;
return $this;
}
/**
* @return bool
*/
public function isDiscoverable(): bool {
return $this->discoverable;
}
/**
* @param bool $discoverable
*
* @return Person
*/
public function setDiscoverable(bool $discoverable): self {
$this->discoverable = $discoverable;
return $this;
}
/**
* @return int
*/
@ -380,7 +487,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setAvatarVersion(int $avatarVersion): Person {
public function setAvatarVersion(int $avatarVersion): self {
$this->avatarVersion = $avatarVersion;
return $this;
@ -399,7 +506,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
*
* @return Person
*/
public function setViewerLink(string $viewerLink): Person {
public function setViewerLink(string $viewerLink): self {
$this->viewerLink = $viewerLink;
return $this;
@ -468,9 +575,9 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
/**
* @return array
*/
public function jsonSerialize(): array {
public function exportAsActivityPub(): array {
$result = array_merge(
parent::jsonSerialize(),
parent::exportAsActivityPub(),
[
'aliases' => [
$this->getUrlSocial() . '@' . $this->getPreferredUsername(),
@ -483,8 +590,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
'account' => $this->getAccount(),
'following' => $this->getFollowing(),
'followers' => $this->getFollowers(),
'endpoints' =>
['sharedInbox' => $this->getSharedInbox()],
'endpoints' => ['sharedInbox' => $this->getSharedInbox()],
'publicKey' => [
'id' => $this->getId() . '#main-key',
'owner' => $this->getId(),
@ -501,4 +607,36 @@ class Person extends ACore implements IQueryRow, JsonSerializable {
return $result;
}
/**
* @return array
*/
public function exportAsLocal(): array {
$result =
[
"username" => $this->getPreferredUsername(),
"acct" => $this->getAccount(),
"display_name" => $this->getDisplayName(),
"locked" => $this->isLocked(),
"bot" => $this->isBot(),
"discoverable" => $this->isDiscoverable(),
"group" => false,
"created_at" => "2017-05-02T09=>56=>41.951Z",
"note" => $this->getDescription(),
"url" => $this->getId(),
"avatar" => "https://files.mastodon.social/accounts/avatars/000/126/222/original/50785214e44d10cc.jpeg",
"avatar_static" => "https://files.mastodon.social/accounts/avatars/000/126/222/original/50785214e44d10cc.jpeg",
"header" => "https://files.mastodon.social/accounts/headers/000/126/222/original/6d7b41fdd92cfd6f.jpeg",
"header_static" => "https://files.mastodon.social/accounts/headers/000/126/222/original/6d7b41fdd92cfd6f.jpeg",
"followers_count" => 9451,
"following_count" => 132,
"statuses_count" => 3020,
"last_status_at" => "2020-08-24",
"emojis" => ''
];
return array_merge(parent::exportAsLocal(), $result);
}
}

Wyświetl plik

@ -67,6 +67,12 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
/** @var string */
private $content = '';
/** @var string */
private $spoilerText = '';
/** @var string */
private $language = 'en';
/** @var string */
private $attributedTo = '';
@ -143,6 +149,44 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
}
/**
* @return string
*/
public function getSpoilerText(): string {
return $this->spoilerText;
}
/**
* @param string $text
*
* @return Stream
*/
public function setSpoilerText(string $text): self {
$this->spoilerText = $text;
return $this;
}
/**
* @return string
*/
public function getLanguage(): string {
return $this->language;
}
/**
* @param string $language
*
* @return $this
*/
public function setLanguage(string $language): self {
$this->language = $language;
return $this;
}
/**
* @return string
*/
@ -436,11 +480,32 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
* @return array
*/
public function exportAsLocal(): array {
$result = array_merge(
parent::exportAsLocal(),
[]);
$result = [
"content" => $this->getContent(),
"sensitive" => $this->isSensitive(),
"spoiler_text" => $this->getSpoilerText(),
"visibility" => 'unlisted',
"language" => $this->getLanguage(),
"in_reply_to_id" => null,
"in_reply_to_account_id" => null,
'replies_count' => 0,
'reblogs_count' => 0,
'favourites_count' => 0,
'favourited' => false,
'reblogged' => false,
'muted' => false,
'bookmarked' => false,
"reblog" => null,
"created_at" => date('Y-m-d\TH:i:s', $this->getPublishedTime()) . '.000Z'
];
return $result;
// TODO - store created_at full string with milliseconds ?
if ($this->hasActor()) {
$actor = $this->getActor();
$result['account'] = $actor;
}
return array_merge(parent::exportAsLocal(), $result);
}
}

Wyświetl plik

@ -28,7 +28,7 @@ declare(strict_types=1);
*/
namespace OCA\Social\Model\ActivityStream;
namespace OCA\Social\Model\Client;
use daita\MySmallPhpTools\IQueryRow;
@ -39,7 +39,7 @@ use JsonSerializable;
/**
* Class ClientApp
*
* @package OCA\Social\Model\ActivityStream
* @package OCA\Social\Model\Client
*/
class ClientApp implements IQueryRow, JsonSerializable {
@ -56,8 +56,8 @@ class ClientApp implements IQueryRow, JsonSerializable {
/** @var string */
private $website = '';
/** @var string */
private $redirectUri = '';
/** @var array */
private $redirectUris = [];
/** @var array */
private $scopes = [];
@ -134,19 +134,19 @@ class ClientApp implements IQueryRow, JsonSerializable {
/**
* @return string
* @return array
*/
public function getRedirectUri(): string {
return $this->redirectUri;
public function getRedirectUris(): array {
return $this->redirectUris;
}
/**
* @param string $redirectUri
* @param array $redirectUris
*
* @return ClientApp
*/
public function setRedirectUri(string $redirectUri): self {
$this->redirectUri = $redirectUri;
public function setRedirectUris(array $redirectUris): self {
$this->redirectUris = $redirectUris;
return $this;
}
@ -229,7 +229,8 @@ class ClientApp implements IQueryRow, JsonSerializable {
$this->setId($this->getInt('id', $data));
$this->setName($this->get('name', $data));
$this->setWebsite($this->get('website', $data));
$this->setRedirectUri($this->get('redirect_uri', $data));
$this->setRedirectUris($this->getArray('redirect_uris', $data));
$this->setScopes($this->getArray('scopes', $data));
$this->setClientId($this->get('client_id', $data));
$this->setClientSecret($this->get('client_secret', $data));
@ -245,7 +246,8 @@ class ClientApp implements IQueryRow, JsonSerializable {
'id' => $this->getId(),
'name' => $this->getName(),
'website' => $this->getWebsite(),
'redirect_uri' => $this->getRedirectUri(),
'redirect_uri' => $this->getRedirectUris(),
'scopes' => implode(' ', $this->getScopes()),
'client_id' => $this->getClientId(),
'client_secret' => $this->getClientSecret()
];

Wyświetl plik

@ -0,0 +1,280 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Model\Client;
use daita\MySmallPhpTools\IQueryRow;
use daita\MySmallPhpTools\Traits\TArrayTools;
use JsonSerializable;
/**
* Class ClientApp
*
* @package OCA\Social\Model\Client
*/
class ClientAuth implements IQueryRow, JsonSerializable {
use TArrayTools;
/** @var int */
private $id = 0;
/** @var int */
private $clientId = 0;
/** @var string */
private $redirectUri = '';
/** @var string */
private $code = '';
/** @var string */
private $userId = '';
/** @var string */
private $account = '';
/** @var array */
private $scopes = [];
/** @var ClientToken */
private $clientToken;
/**
* ClientApp constructor.
*/
public function __construct() {
}
/**
* @return int
*/
public function getId(): int {
return $this->id;
}
/**
* @param int $id
*
* @return ClientAuth
*/
public function setId(int $id): self {
$this->id = $id;
return $this;
}
/**
* @return string
*/
public function getRedirectUri(): string {
return $this->redirectUri;
}
/**
* @param string $redirectUri
*
* @return ClientAuth
*/
public function setRedirectUri(string $redirectUri): self {
$this->redirectUri = $redirectUri;
return $this;
}
/**
* @return string
*/
public function getCode(): string {
return $this->code;
}
/**
* @param string $code
*
* @return ClientAuth
*/
public function setCode(string $code): self {
$this->code = $code;
return $this;
}
/**
* @return string
*/
public function getAccount(): string {
return $this->account;
}
/**
* @param string $account
*
* @return ClientAuth
*/
public function setAccount(string $account): self {
$this->account = $account;
return $this;
}
/**
* @return string
*/
public function getUserId(): string {
return $this->userId;
}
/**
* @param string $userId
*
* @return ClientAuth
*/
public function setUserId(string $userId): self {
$this->userId = $userId;
return $this;
}
/**
* @return array
*/
public function getScopes(): array {
return $this->scopes;
}
/**
* @param array $scopes
*
* @return ClientAuth
*/
public function setScopes(array $scopes): self {
$this->scopes = $scopes;
return $this;
}
/**
* @return int
*/
public function getClientId(): int {
return $this->clientId;
}
/**
* @param int $clientId
*
* @return ClientAuth
*/
public function setClientId(int $clientId): self {
$this->clientId = $clientId;
return $this;
}
/**
* @return bool
*/
public function hasClientToken(): bool {
return ($this->clientToken !== null);
}
/**
* @param ClientToken $clientToken
*
* @return ClientAuth
*/
public function setClientToken(ClientToken $clientToken): self {
$this->clientToken = $clientToken;
return $this;
}
/**
* @return ClientToken
*/
public function getClientToken(): ClientToken {
return $this->clientToken;
}
/**
* @param array $data
*
* @return ClientAuth
*/
public function importFromDatabase(array $data): self {
$this->setId($this->getInt('id', $data));
$this->setClientId($this->getInt('client_id', $data));
$this->setScopes($this->getArray('scopes', $data));
$this->setAccount($this->get('account', $data));
$this->setUserId($this->get('user_id', $data));
$this->setCode($this->get('code', $data));
$this->setRedirectUri($this->get('redirect_uri', $data));
return $this;
}
/**
* @return array
*/
public function jsonSerialize(): array {
$arr = [
'id' => $this->getId(),
'client_id' => $this->getClientId(),
'scopes' => $this->getScopes(),
'account' => $this->getAccount(),
'user_id' => $this->getUserId(),
'code' => $this->getCode(),
'redirect_uri' => $this->getRedirectUri(),
];
if ($this->hasClientToken()) {
$arr['client_token'] = $this->getClientToken();
}
return array_filter($arr);
}
}

Wyświetl plik

@ -0,0 +1,215 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Model\Client;
use daita\MySmallPhpTools\IQueryRow;
use daita\MySmallPhpTools\Traits\TArrayTools;
use JsonSerializable;
/**
* Class ClientApp
*
* @package OCA\Social\Model\Client
*/
class ClientToken implements IQueryRow, JsonSerializable {
use TArrayTools;
/** @var int */
private $id = 0;
/** @var int */
private $authId = 0;
/** @var string */
private $token = '';
/** @var array */
private $scopes = [];
/** @var int */
private $lastUpdate = 0;
/** @var int */
private $creation = 0;
/**
* ClientApp constructor.
*/
public function __construct() {
}
/**
* @return int
*/
public function getId(): int {
return $this->id;
}
/**
* @param int $id
*
* @return ClientToken
*/
public function setId(int $id): self {
$this->id = $id;
return $this;
}
/**
* @return int
*/
public function getAuthId(): int {
return $this->authId;
}
/**
* @param int $authId
*
* @return ClientToken
*/
public function setAuthId(int $authId): self {
$this->authId = $authId;
return $this;
}
/**
* @return string
*/
public function getToken(): string {
return $this->token;
}
/**
* @param string $token
*
* @return ClientToken
*/
public function setToken(string $token): self {
$this->token = $token;
return $this;
}
/**
* @return array
*/
public function getScopes(): array {
return $this->scopes;
}
/**
* @param array $scopes
*
* @return ClientToken
*/
public function setScopes(array $scopes): self {
$this->scopes = $scopes;
return $this;
}
/**
* @return int
*/
public function getLastUpdate(): int {
return $this->lastUpdate;
}
/**
* @param int $lastUpdate
*/
public function setLastUpdate(int $lastUpdate): void {
$this->lastUpdate = $lastUpdate;
}
/**
* @return int
*/
public function getCreation(): int {
return $this->creation;
}
/**
* @param int $creation
*/
public function setCreation(int $creation): void {
$this->creation = $creation;
}
/**
* @param array $data
*
* @return ClientToken
*/
public function importFromDatabase(array $data): self {
$this->setId($this->getInt('id', $data));
$this->setAuthId($this->getInt('auth_id', $data));
$this->setToken($this->get('token', $data));
$this->setScopes($this->getArray('scopes', $data));
$this->setLastUpdate($this->getInt('last_update', $data));
$this->setCreation($this->getInt('creation', $data));
return $this;
}
/**
* @return array
*/
public function jsonSerialize(): array {
$arr = [
'id' => $this->getId(),
'auth_id' => $this->getAuthId(),
'token' => $this->getToken(),
'scopes' => $this->getScopes(),
'last_update' => $this->getLastUpdate(),
'creation' => $this->getCreation()
];
return array_filter($arr);
}
}

Wyświetl plik

@ -32,9 +32,14 @@ namespace OCA\Social\Service;
use daita\MySmallPhpTools\Traits\TStringTools;
use OCA\Social\Db\ClientAppRequest;
use OCA\Social\Db\ClientAuthRequest;
use OCA\Social\Db\ClientTokenRequest;
use OCA\Social\Exceptions\ClientAppDoesNotExistException;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\ActivityStream\ClientApp;
use OCA\Social\Exceptions\ClientAuthDoesNotExistException;
use OCA\Social\Exceptions\ClientException;
use OCA\Social\Model\Client\ClientApp;
use OCA\Social\Model\Client\ClientAuth;
use OCA\Social\Model\Client\ClientToken;
/**
@ -51,26 +56,49 @@ class ClientService {
/** @var ClientAppRequest */
private $clientAppRequest;
/** @var ClientAuthRequest */
private $clientAuthRequest;
/** @var ClientTokenRequest */
private $clientTokenRequest;
/** @var MiscService */
private $miscService;
/**
* BoostService constructor.
* ClientService constructor.
*
* @param ClientAppRequest $clientAppRequest
* @param ClientAuthRequest $clientAuthRequest
* @param ClientTokenRequest $clientTokenRequest
* @param MiscService $miscService
*/
public function __construct(ClientAppRequest $clientAppRequest, MiscService $miscService) {
public function __construct(
ClientAppRequest $clientAppRequest, ClientAuthRequest $clientAuthRequest,
ClientTokenRequest $clientTokenRequest, MiscService $miscService
) {
$this->clientAppRequest = $clientAppRequest;
$this->clientAuthRequest = $clientAuthRequest;
$this->clientTokenRequest = $clientTokenRequest;
$this->miscService = $miscService;
}
/**
* @param ClientApp $clientApp
*
* @throws ClientException
*/
public function createClient(ClientApp $clientApp): void {
if ($clientApp->getName() === '') {
throw new ClientException('missing client_name');
}
if (empty($clientApp->getRedirectUris())) {
throw new ClientException('missing redirect_uris');
}
$clientApp->setClientId($this->token(40));
$clientApp->setClientSecret($this->token(40));
@ -79,11 +107,32 @@ class ClientService {
/**
* @param string $clientId
* @param Person $account
* @param ClientAuth $clientAuth
* @param ClientApp $clientApp
*
* @throws ClientException
*/
public function assignAccount(string $clientId, Person $account) {
$this->clientAppRequest->assignAccount($clientId, $account->getPreferredUsername());
public function authClient(ClientApp $clientApp, ClientAuth $clientAuth) {
$this->confirmData($clientApp, ['redirect_uri' => $clientAuth->getRedirectUri()]);
$clientAuth->setCode($this->token(60));
$clientAuth->setClientId($clientApp->getId());
$this->clientAuthRequest->save($clientAuth);
}
/**
* @param ClientApp $clientApp
* @param ClientAuth $clientAuth
* @param ClientToken $clientToken
*/
public function generateToken(ClientApp $clientApp, ClientAuth $clientAuth, ClientToken $clientToken
): void {
$clientToken->setAuthId($clientAuth->getId());
$clientToken->setToken($this->token(80));
$this->clientTokenRequest->save($clientToken);
}
@ -93,9 +142,64 @@ class ClientService {
* @return ClientApp
* @throws ClientAppDoesNotExistException
*/
public function getByClientId(string $clientId): ClientApp {
public function getClientByClientId(string $clientId): ClientApp {
return $this->clientAppRequest->getByClientId($clientId);
}
/**
* @param string $code
*
* @return ClientAuth
* @throws ClientAuthDoesNotExistException
*/
public function getAuthByCode(string $code): ClientAuth {
return $this->clientAuthRequest->getByCode($code);
}
/**
* @param string $token
*
* @return ClientAuth
* @throws ClientAuthDoesNotExistException
*/
public function getAuthFromToken(string $token): ClientAuth {
return $this->clientAuthRequest->getByToken($token);
}
/**
* @param ClientApp $clientApp
* @param array $data
*
* @throws ClientException
*/
public function confirmData(ClientApp $clientApp, array $data) {
if (array_key_exists('redirect_uri', $data)
&& !in_array($data['redirect_uri'], $clientApp->getRedirectUris())) {
throw new ClientException('unknown redirect_uri');
}
if (array_key_exists('client_secret', $data)
&& $data['client_secret'] !== $clientApp->getClientSecret()) {
throw new ClientException('wrong client_secret');
}
if (array_key_exists('scopes', $data)) {
$scopes = $data['scopes'];
if (!is_array($scopes)) {
$scopes = explode(' ', $scopes);
}
foreach ($scopes as $scope) {
if (!in_array($scope, $clientApp->getScopes())) {
throw new ClientException('invalid scope');
}
}
}
}
}

Wyświetl plik

@ -285,10 +285,6 @@ class StreamService {
'name' => '#' . $hashtag
]
);
\OC::$server->getLogger()
->log(
3, '___' . $this->configService->getSocialUrl() . 'tag/' . strtolower($hashtag)
);
} catch (SocialAppConfigException $e) {
}
}
@ -414,7 +410,8 @@ class StreamService {
* @return Note[]
* @throws DateTimeException
*/
public function getStreamHome(int $since = 0, int $limit = 5, int $format = Stream::FORMAT_ACTIVITYPUB): array {
public function getStreamHome(int $since = 0, int $limit = 5, int $format = Stream::FORMAT_ACTIVITYPUB
): array {
return $this->streamRequest->getTimelineHome($since, $limit, $format);
}