Skip to content

Commit cb64a33

Browse files
committed
Implement CloudFederationProvider
Signed-off-by: Gary Kim <gary@garykim.dev>
1 parent 8f3e737 commit cb64a33

7 files changed

Lines changed: 369 additions & 18 deletions

File tree

appinfo/routes.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,27 @@
505505
],
506506
],
507507

508+
/**
509+
* Remote
510+
*/
511+
512+
[
513+
'name' => 'Remote#acceptShare',
514+
'url' => 'api/{apiVersion}/remote/pending/{id}',
515+
'verb' => 'POST',
516+
'requirements' => [
517+
'apiVersion' => 'v1',
518+
],
519+
],
520+
[
521+
'name' => 'Remote#rejectShare',
522+
'url' => 'api/{apiVersion}/remote/pending/{id}',
523+
'verb' => 'DELETE',
524+
'requirements' => [
525+
'apiVersion' => 'v1',
526+
],
527+
],
528+
508529
/**
509530
* PublicShareAuth
510531
*/
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2021, Gary Kim <gary@garykim.dev>
6+
*
7+
* @author Gary Kim <gary@garykim.dev>
8+
*
9+
* @license GNU AGPL version 3 or any later version
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Affero General Public License as
13+
* published by the Free Software Foundation, either version 3 of the
14+
* License, or (at your option) any later version.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU Affero General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU Affero General Public License
22+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
*
24+
*/
25+
26+
namespace OCA\Talk\Controller;
27+
28+
use OCP\AppFramework\Http\DataResponse;
29+
use OCP\AppFramework\OCSController;
30+
use OCP\IRequest;
31+
32+
class FederationController extends OCSController {
33+
public function __construct(string $appName, IRequest $request) {
34+
parent::__construct($appName, $request);
35+
}
36+
37+
/**
38+
* @param string $id
39+
* @return DataResponse
40+
*/
41+
public function acceptShare(string $id): DataResponse {
42+
43+
}
44+
45+
/**
46+
* @param string $id
47+
* @return DataResponse
48+
*/
49+
public function rejectShare(string $id): DataResponse {
50+
51+
}
52+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2021, Gary Kim <gary@garykim.dev>
6+
*
7+
* @author Gary Kim <gary@garykim.dev>
8+
*
9+
* @license GNU AGPL version 3 or any later version
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Affero General Public License as
13+
* published by the Free Software Foundation, either version 3 of the
14+
* License, or (at your option) any later version.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU Affero General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU Affero General Public License
22+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
*
24+
*/
25+
26+
namespace OCA\Talk\Federation;
27+
28+
use OC\AppFramework\Http;
29+
use OC\HintException;
30+
use OCA\FederatedFileSharing\AddressHandler;
31+
use OCA\Talk\AppInfo\Application;
32+
use OCA\Talk\Federation\FederationManager;
33+
use OCP\DB\Exception as DBException;
34+
use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
35+
use OCP\Federation\ICloudFederationProvider;
36+
use OCP\Federation\ICloudFederationShare;
37+
use OCP\IURLGenerator;
38+
use OCP\IUserManager;
39+
use OCP\Notification\IManager as INotificationManager;
40+
use OCP\Share\IShare;
41+
42+
class CloudFederationProviderTalk implements ICloudFederationProvider {
43+
44+
/** @var IUserManager */
45+
private IUserManager $userManager;
46+
47+
/** @var AddressHandler */
48+
private AddressHandler $addressHandler;
49+
50+
/** @var FederationManager */
51+
private FederationManager $federationManager;
52+
53+
/** @var INotificationManager */
54+
private INotificationManager $notificationManager;
55+
56+
/** @var IURLGenerator */
57+
private IURLGenerator $urlGenerator;
58+
59+
public function __construct(
60+
IUserManager $userManager,
61+
AddressHandler $addressHandler,
62+
FederationManager $federationManager,
63+
INotificationManager $notificationManager,
64+
IURLGenerator $urlGenerator
65+
) {
66+
$this->userManager = $userManager;
67+
$this->addressHandler = $addressHandler;
68+
$this->federationManager = $federationManager;
69+
$this->notificationManager = $notificationManager;
70+
$this->urlGenerator = $urlGenerator;
71+
}
72+
73+
/**
74+
* @inheritDoc
75+
*/
76+
public function getShareType(): string {
77+
return 'talk-room';
78+
}
79+
80+
/**
81+
* @inheritDoc
82+
* @throws HintException
83+
* @throws DBException
84+
*/
85+
public function shareReceived(ICloudFederationShare $share): string {
86+
if (!$this->federationManager->isEnabled()) {
87+
throw new ProviderCouldNotAddShareException('Server does not support talk federation', '', Http::STATUS_SERVICE_UNAVAILABLE);
88+
}
89+
if ($share->getShareType() !== 'user') {
90+
throw new ProviderCouldNotAddShareException('support for sharing with non-groups not implemented yet', '', Http::STATUS_NOT_IMPLEMENTED);
91+
}
92+
93+
$shareSecret = $share->getShareSecret();
94+
$shareWith = $share->getShareWith();
95+
$roomToken = $share->getProviderId();
96+
[, $remote] = $this->addressHandler->splitUserRemote($share->getOwner());
97+
98+
if ($remote && $shareSecret && $shareWith) {
99+
$shareWith = $this->userManager->get($shareWith);
100+
if ($shareWith === null) {
101+
throw new ProviderCouldNotAddShareException('User does not exist', '',Http::STATUS_BAD_REQUEST);
102+
}
103+
104+
$shareId = $this->federationManager->addRemoteRoom($shareWith, $roomToken, $remote, $shareSecret);
105+
return (string) $shareId;
106+
}
107+
throw new ProviderCouldNotAddShareException('required request data not found', '', Http::STATUS_BAD_REQUEST);
108+
// TODO: Finish implementing shareReceived() method.
109+
}
110+
111+
/**
112+
* @inheritDoc
113+
*/
114+
public function notificationReceived($notificationType, $providerId, array $notification) {
115+
116+
// TODO: Implement notificationReceived() method.
117+
}
118+
119+
private function notifyAboutNewShare(string $shareWith, string $shareId, string $ownerFederatedId, string $sharedByFederatedId, string $name) {
120+
$notification = $this->notificationManager->createNotification();
121+
$notification->setApp(Application::APP_ID)
122+
->setUser($shareWith)
123+
->setDateTime(new \DateTime());
124+
125+
$declineAction = $notification->createAction();
126+
$declineAction->setLabel('decline')
127+
->setLink($this->urlGenerator->linkToOCSRouteAbsolute('spreed.Remote.rejectShare', ['id' => $shareId]), 'DELETE');
128+
$notification->addAction($declineAction);
129+
130+
$acceptAction = $notification->createAction();
131+
$acceptAction->setLabel('accept')
132+
->setLink($this->urlGenerator->linkToOCSRouteAbsolute('spreed.Remote.acceptShare', ['id' => $shareId]), 'POST');
133+
$notification->addAction($acceptAction);
134+
135+
$this->notificationManager->notify($notification);
136+
}
137+
138+
/**
139+
* @inheritDoc
140+
*/
141+
public function getSupportedShareTypes() {
142+
return ['user'];
143+
}
144+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2021, Gary Kim <gary@garykim.dev>
6+
*
7+
* @author Gary Kim <gary@garykim.dev>
8+
*
9+
* @license GNU AGPL version 3 or any later version
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Affero General Public License as
13+
* published by the Free Software Foundation, either version 3 of the
14+
* License, or (at your option) any later version.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU Affero General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU Affero General Public License
22+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
*
24+
*/
25+
26+
namespace OCA\Talk\Federation;
27+
28+
use OCA\Talk\Exceptions\UnauthorizedException;
29+
use OCA\Talk\Room;
30+
use OCP\DB\Exception as DBException;
31+
use OCP\DB\QueryBuilder\IQueryBuilder;
32+
use OCP\IConfig;
33+
use OCP\IDBConnection;
34+
use OCP\IUser;
35+
36+
class FederationManager {
37+
/** @var IDBConnection */
38+
private $db;
39+
/** @var IConfig */
40+
private $config;
41+
42+
public function __construct (
43+
IDBConnection $db,
44+
IConfig $config
45+
) {
46+
$this->db = $db;
47+
$this->config = $config;
48+
}
49+
50+
/**
51+
* Determine if Talk federation is enabled on this instance
52+
* @return bool
53+
*/
54+
public function isEnabled(): bool {
55+
// TODO: Set to true once implementation is complete
56+
return $this->config->getSystemValueBool('talk_federation_enabled', false);
57+
}
58+
59+
/**
60+
* @param IUser $user
61+
* @param string $roomToken
62+
* @param string $remoteUrl
63+
* @param string $sharedSecret
64+
* @return int share id for this specific remote room share
65+
* @throws DBException
66+
*/
67+
public function addRemoteRoom(IUser $user, string $roomToken, string $remoteUrl, string $sharedSecret): int {
68+
$qb = $this->db->getQueryBuilder();
69+
70+
$query = $qb->insert('talk_rooms_external')
71+
->values([
72+
'user_id' => $qb->createNamedParameter($user->getUID(), IQueryBuilder::PARAM_STR),
73+
'room_id' => $qb->createNamedParameter($roomToken, IQueryBuilder::PARAM_STR),
74+
'remote_url' => $qb->createNamedParameter($remoteUrl, IQueryBuilder::PARAM_STR),
75+
'shareToken' => $qb->createNamedParameter($sharedSecret, IQueryBuilder::PARAM_STR),
76+
])
77+
->executeQuery();
78+
79+
$row = $query->fetch();
80+
return (int)($row['id']);
81+
}
82+
83+
/**
84+
* @throws DBException
85+
* @throws UnauthorizedException
86+
*/
87+
public function acceptRemoteRoomShare(IUser $user, int $shareId) {
88+
$share = this->$this->getShare($shareId);
89+
if ($share['user_id'] !== $user->getUID()) {
90+
throw new UnauthorizedException();
91+
}
92+
93+
$qb = $this->db->getQueryBuilder();
94+
95+
$qb->update('talk_rooms_external')
96+
->set('accepted', true)
97+
->where(
98+
$qb->expr()->eq('id', $qb->createNamedParameter($shareId, IQueryBuilder::PARAM_INT))
99+
)
100+
->executeQuery();
101+
}
102+
103+
/**
104+
* @throws DBException
105+
* @throws UnauthorizedException
106+
*/
107+
public function rejectRemoteRoomShare(IUser $user, int $shareId) {
108+
$share = this->$this->getShare($shareId);
109+
if ($share['user_id'] !== $user->getUID()) {
110+
throw new UnauthorizedException();
111+
}
112+
113+
$qb = $this->db->getQueryBuilder();
114+
115+
$qb->delete('talk_rooms_external')
116+
->where(
117+
$qb->expr()->eq('id', $qb->createNamedParameter($shareId, IQueryBuilder::PARAM_INT))
118+
)
119+
->executeQuery();
120+
}
121+
122+
/**
123+
* @throws DBException
124+
*/
125+
public function getShare(int $shareId): array {
126+
$qb = $this->db->getQueryBuilder();
127+
128+
$query = $qb->select('*')
129+
->from('talk_rooms_external')
130+
->where(
131+
$qb->expr()->eq('id', $qb->createNamedParameter($shareId, IQueryBuilder::PARAM_INT))
132+
)
133+
->executeQuery();
134+
135+
return $query->fetch();
136+
}
137+
}

0 commit comments

Comments
 (0)