Skip to content

Commit

Permalink
feat: add access policy
Browse files Browse the repository at this point in the history
public, require password for guests, moderator approval
for guests, only Nextcloud users

fix #10
fix #24
  • Loading branch information
sualko committed Jun 4, 2020
1 parent 07f679a commit 70b06aa
Show file tree
Hide file tree
Showing 16 changed files with 253 additions and 45 deletions.
14 changes: 13 additions & 1 deletion appinfo/app.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
<?php

OCP\Util::addScript ( 'bbb', 'filelist');
OCP\Util::addScript ( 'bbb', 'filelist');

$apiUrl = \OC::$server->getConfig()->getAppValue('bbb', 'api.url');
$parsedApiUrl = @parse_url($apiUrl);

if ($parsedApiUrl !== false) {
$manager = \OC::$server->getContentSecurityPolicyManager();
$policy = new \OCP\AppFramework\Http\EmptyContentSecurityPolicy();

$policy->addAllowedFormActionDomain(($parsedApiUrl['scheme'] ?: 'https') . '://' . $parsedApiUrl['host']);

$manager->addDefaultPolicy($policy);
}
5 changes: 5 additions & 0 deletions lib/BigBlueButton/API.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public function createJoinUrl(Room $room, int $creationTime, string $displayname
$joinMeetingParams->setCreationTime($creationTime);
$joinMeetingParams->setJoinViaHtml5(true);
$joinMeetingParams->setRedirect(true);
$joinMeetingParams->setGuest($uid === null);

if ($uid) {
$joinMeetingParams->setUserId($uid);
Expand Down Expand Up @@ -114,6 +115,10 @@ private function buildMeetingParams(Room $room, Presentation $presentation = nul
$createMeetingParams->addPresentation($presentation->getUrl(), null, $presentation->getFilename());
}

if ($room->access === Room::ACCESS_WAITING_ROOM) {
$createMeetingParams->setGuestPolicyAskModerator();
}

return $createMeetingParams;
}

Expand Down
27 changes: 22 additions & 5 deletions lib/Controller/JoinController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use OCP\AppFramework\Http\RedirectResponse;
use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
use OCP\IUserSession;
use OCP\IConfig;
use OCA\BigBlueButton\Service\RoomService;
Expand All @@ -25,6 +26,9 @@ class JoinController extends Controller
/** @var RoomService */
private $service;

/** @var IURLGenerator */
private $urlGenerator;

/** @var IUserSession */
private $userSession;

Expand All @@ -39,13 +43,15 @@ public function __construct(
IRequest $request,
ISession $session,
RoomService $service,
IURLGenerator $urlGenerator,
IUserSession $userSession,
IConfig $config,
API $api
) {
parent::__construct($appName, $request, $session);

$this->service = $service;
$this->urlGenerator = $urlGenerator;
$this->userSession = $userSession;
$this->config = $config;
$this->api = $api;
Expand All @@ -68,7 +74,7 @@ public function isValidToken(): bool
* @PublicPage
* @NoCSRFRequired
*/
public function index($displayname, $u = '', $filename = '')
public function index($displayname, $u = '', $filename = '', $password = '')
{
$room = $this->getRoom();

Expand All @@ -87,10 +93,21 @@ public function index($displayname, $u = '', $filename = '')
if ($userId === $room->userId) {
$presentation = new Presentation($u, $filename);
}
} elseif (empty($displayname) || strlen($displayname) < 3) {
$response = new TemplateResponse($this->appName, 'publicdisplayname', [
} elseif ($room->access === Room::ACCESS_INTERNAL) {
return new RedirectResponse(
$this->urlGenerator->linkToRoute('core.login.showLoginForm', [
'redirect_url' => $this->urlGenerator->linkToRoute(
'bbb.join.index',
['token' => $this->token]
),
])
);
} elseif (empty($displayname) || strlen($displayname) < 3 || ($room->access === Room::ACCESS_PASSWORD && $password !== $room->password)) {
$response = new TemplateResponse($this->appName, 'join', [
'room' => $room->name,
'wrongdisplayname' => !empty($displayname) && strlen($displayname) < 3
'wrongdisplayname' => !empty($displayname) && strlen($displayname) < 3,
'passwordRequired' => $room->access === Room::ACCESS_PASSWORD,
'wrongPassword' => $password !== $room->password && $password !== '',
], 'guest');

$this->addFormActionDomain($response);
Expand All @@ -116,7 +133,7 @@ private function addFormActionDomain($response)
$response->getContentSecurityPolicy()->addAllowedFormActionDomain(($parsedApiUrl['scheme'] ?: 'https') . '://' . $parsedApiUrl['host']);
}

private function getRoom(): Room
private function getRoom(): ?Room
{
if ($this->room === null) {
$this->room = $this->service->findByUid($this->token);
Expand Down
7 changes: 4 additions & 3 deletions lib/Controller/RoomApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@ public function update(
string $name,
string $welcome,
int $maxParticipants,
bool $record
bool $record,
string $access
): DataResponse {
return $this->handleNotFound(function () use ($id, $name, $welcome, $maxParticipants, $record) {
return $this->service->update($id, $name, $welcome, $maxParticipants, $record, $this->userId);
return $this->handleNotFound(function () use ($id, $name, $welcome, $maxParticipants, $record, $access) {
return $this->service->update($id, $name, $welcome, $maxParticipants, $record, $access, $this->userId);
});
}

Expand Down
7 changes: 4 additions & 3 deletions lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ public function update(
string $name,
string $welcome,
int $maxParticipants,
bool $record
bool $record,
string $access
): DataResponse {
return $this->handleNotFound(function () use ($id, $name, $welcome, $maxParticipants, $record) {
return $this->service->update($id, $name, $welcome, $maxParticipants, $record, $this->userId);
return $this->handleNotFound(function () use ($id, $name, $welcome, $maxParticipants, $record, $access) {
return $this->service->update($id, $name, $welcome, $maxParticipants, $record, $access, $this->userId);
});
}

Expand Down
10 changes: 10 additions & 0 deletions lib/Db/Room.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@

class Room extends Entity implements JsonSerializable
{
const ACCESS_PUBLIC = 'public';
const ACCESS_PASSWORD = 'password';
const ACCESS_WAITING_ROOM = 'waiting_room';
const ACCESS_INTERNAL = 'internal';
const ACCESS_INTERNAL_RESTRICTED = 'internal_restricted';

public $uid;
public $name;
public $attendeePassword;
Expand All @@ -15,6 +21,8 @@ class Room extends Entity implements JsonSerializable
public $maxParticipants;
public $record;
public $userId;
public $access;
public $password;

public function __construct()
{
Expand All @@ -31,6 +39,8 @@ public function jsonSerialize(): array
'welcome' => $this->welcome,
'maxParticipants' => (int) $this->maxParticipants,
'record' => boolval($this->record),
'access' => $this->access,
'password' => $this->password,
];
}
}
51 changes: 51 additions & 0 deletions lib/Migration/Version000000Date20200604130935.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace OCA\BigBlueButton\Migration;

use Closure;
use OCA\BigBlueButton\Db\Room;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

/**
* Auto-generated migration step: Please modify to your needs!
*/
class Version000000Date20200604130935 extends SimpleMigrationStep
{
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options)
{
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

if ($schema->hasTable('bbb_rooms')) {
$table = $schema->getTable('bbb_rooms');

if (!$table->hasColumn('access')) {
$table->addColumn('access', 'string', [
'notnull' => true,
'default' => Room::ACCESS_PUBLIC,
]);
}

if (!$table->hasColumn('password')) {
$table->addColumn('password', 'string', [
'length' => 64,
'notnull' => false,
]);
}

return $schema;
}

return null;
}
}
12 changes: 11 additions & 1 deletion lib/Service/RoomService.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,20 @@ public function create($name, $welcome, $maxParticipants, $record, $userId)
return $this->mapper->insert($room);
}

public function update($id, $name, $welcome, $maxParticipants, $record, $userId)
public function update($id, $name, $welcome, $maxParticipants, $record, $access, $userId)
{
try {
$room = $this->mapper->find($id, $userId);

if ($room->access !== $access) {
$room->setPassword($access === Room::ACCESS_PASSWORD ? $this->humanReadableRandom(8) : null);
}

$room->setName($name);
$room->setWelcome($welcome);
$room->setMaxParticipants($maxParticipants);
$room->setRecord($record);
$room->setAccess($access);
$room->setUserId($userId);

return $this->mapper->update($room);
Expand All @@ -102,4 +107,9 @@ public function delete($id, $userId)
$this->handleException($e);
}
}

private function humanReadableRandom($length)
{
return \OC::$server->getSecureRandom()->generate($length, \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE);
}
}
38 changes: 38 additions & 0 deletions templates/join.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
/** @var $_ array */
/** @var $l \OCP\IL10N */
style('core', 'guest');
script('bbb', 'join');
?>
<form method="get" action="?">
<fieldset class="warning bbb">
<h2><?php p($_['room']) ?></h2>
<?php if (!isset($_['wrongdisplayname']) || !$_['wrongdisplayname']): ?>
<p><?php p($l->t('Please enter your name!')); ?></p>
<?php endif; ?>
<?php if (isset($_['wrongdisplayname']) && $_['wrongdisplayname']): ?>
<div class="warning"><?php p($l->t('The name must be at least 3 characters long.')); ?></div>
<?php endif; ?>
<?php if (isset($_['wrongPassword']) && $_['wrongPassword']): ?>
<div class="warning"><?php p($l->t('You have to provide the correct password to join the meeting.')); ?></div>
<?php endif; ?>
<div class="bbb-container">
<label for="displayname" class="infield"><?php p($l->t('Display name')); ?></label>
<input type="text" name="displayname" id="displayname" class="bbb-input"
placeholder="<?php p($l->t('Display name')); ?>" value=""
required minlength="3" autofocus />
<?php if (isset($_['passwordRequired']) && $_['passwordRequired']): ?>
<label for="password" class="infield"><?php p($l->t('Password')); ?></label>
<input type="text" name="password" id="password" class="bbb-input"
placeholder="<?php p($l->t('Password')); ?>" value=""
required minlength="8" />
<button class="primary"><?php p($l->t('Join')); ?>
<div class="submit-icon icon-confirm-white"></div></button>
<?php else: ?>
<input type="submit" id="displayname-submit"
class="svg icon-confirm input-button-inline" value="" />
<?php endif; ?>

</div>
</fieldset>
</form>
25 changes: 0 additions & 25 deletions templates/publicdisplayname.php

This file was deleted.

10 changes: 10 additions & 0 deletions ts/Manager/Api.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import axios from '@nextcloud/axios';

export enum Access {
Public = 'public',
Password = 'password',
WaitingRoom = 'waiting_room',
Internal = 'internal',
InternalRestricted = 'internal_restricted',
}

export interface Room {
id: number;
uid: string;
name: string;
welcome: string;
maxParticipants: number;
record: boolean;
access: Access;
password?: string;
}

export type Recording = {
Expand Down
8 changes: 7 additions & 1 deletion ts/Manager/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,14 @@
min-width: 300px;
margin: 2em 0;

input:not([type="checkbox"]) {
input:not([type="checkbox"]),
select {
width: 100%;
display: block;
}

[readonly] {
background-color: #f1f1f1;
}

em {
Expand Down
Loading

3 comments on commit 70b06aa

@joergmschulz
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while config is possible, save of the config is not possible. NC 18.0.5, build of the app from current master

@sualko
Copy link
Member Author

@sualko sualko commented on 70b06aa Jun 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you execute the migration? Because without version bump they are not executed automatically.

@joergmschulz
Copy link
Collaborator

@joergmschulz joergmschulz commented on 70b06aa Jun 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2nd edit
ok, removed the migration status from the nc database and reinstalled the app; now passwords are working perfectly. The welcome message is displayed perfectly.
Good Stuff! Thanks a ton!

Please sign in to comment.