Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
23e7fe8
Add first draft for token generation / auth checks
Sabr1n4W Nov 29, 2025
094651a
Remove access code room auth tokens when access code is changed
Sabr1n4W Nov 30, 2025
ad40140
Improve frontend draft
Sabr1n4W Nov 30, 2025
aa9a89c
Improve frontend draft (Add room auth token to requests)
Sabr1n4W Nov 30, 2025
e96b04a
Add first draft for file access refactoring
Sabr1n4W Dec 2, 2025
b961e7e
Use deprecated route for roomFileService url generation
Sabr1n4W Dec 3, 2025
238d103
Fix start and join
Sabr1n4W Dec 3, 2025
eee0738
Add error handling draft
Sabr1n4W Dec 7, 2025
d9d5238
Merge branch 'develop' of github.com:THM-Health/PILOS into 1409-refac…
Sabr1n4W Dec 7, 2025
d8802ce
Rename routes
Sabr1n4W Dec 10, 2025
3db8673
Merge branch 'develop' of github.com:THM-Health/PILOS into 1409-refac…
Sabr1n4W Dec 10, 2025
33a21fa
Improve error handling
Sabr1n4W Dec 10, 2025
abe81f0
Remove unnecessary ToDos
Sabr1n4W Dec 10, 2025
7cdde74
Improve error handling
Sabr1n4W Dec 11, 2025
411bac1
Remove unnecessary ToDos, improve error handling
Sabr1n4W Dec 11, 2025
0008a1e
Improve error handling
Sabr1n4W Dec 15, 2025
38904f6
Improve error handling
Sabr1n4W Dec 16, 2025
5f1d6ac
Improve error handling
Sabr1n4W Dec 17, 2025
d14e41c
Start adjusting backend tests
Sabr1n4W Dec 17, 2025
4f5d43b
Fix download route
Sabr1n4W Dec 18, 2025
6d9bf35
Add room auth token type to requests
Sabr1n4W Dec 21, 2025
e07938f
Continue adjusting backend tests (RoomTest)
Sabr1n4W Dec 27, 2025
0e2c303
Continue adjusting backend tests
Sabr1n4W Dec 28, 2025
7341357
Start adjusting frontend tests
Sabr1n4W Jan 3, 2026
ba68ed7
Continue adjusting frontend tests
Sabr1n4W Jan 5, 2026
cce2eb3
Improve error handling and tests
Sabr1n4W Jan 8, 2026
8014611
Improve error handling and tests
Sabr1n4W Jan 9, 2026
0b7cf64
Improve error handling and tests
Sabr1n4W Jan 13, 2026
6aa9031
Improve tests
Sabr1n4W Jan 14, 2026
a73b9a2
Merge branch 'develop' of github.com:THM-Health/PILOS into 1409-refac…
Sabr1n4W Jan 14, 2026
abcc125
Temp fix for uuid error
Sabr1n4W Jan 15, 2026
5641cd1
Improve error handling and tests
Sabr1n4W Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions app/Enums/RoomAuthTokenType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace App\Enums;

/**
* Type of the room auth token enum
*/
enum RoomAuthTokenType: int
{
case CODE = 0;

case TOKEN = 1;
}
26 changes: 0 additions & 26 deletions app/Http/Controllers/FileController.php

This file was deleted.

54 changes: 54 additions & 0 deletions app/Http/Controllers/RoomFileController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace App\Http\Controllers;

use App\Models\Room;
use App\Models\RoomFile;
use App\Services\RoomFileService;
use Illuminate\Auth\Access\AuthorizationException;
use Symfony\Component\HttpFoundation\StreamedResponse;

/**
* Class RoomFileController
* Handle file management for rooms
*/
class RoomFileController extends Controller
{
/**
* Display/Download a file
*
* @return StreamedResponse
*/
public function show(Room $room, RoomFile $file)
{
// Check authorization
try {
$this->authorize('downloadFile', [$room, $file]);
} catch (AuthorizationException $e) {
// User is not authorized to download the file
return response(view('new-tab-error', [
'type' => 'forbidden',
'code' => 403,
'title' => 'Forbidden',
'message' => __('rooms.flash.file_forbidden'),
]))->setStatusCode(403);
}

$roomFileService = new RoomFileService($file);

return $roomFileService->download();
}

/**
* Display/Download a file without authorization check
* (Needed to allow bbb server to access the presentation files)
*
* @return StreamedResponse
*/
public function showPresentation(Room $room, RoomFile $roomFile)
{
$roomFileService = new RoomFileService($roomFile);

return $roomFileService->download();
}
}
102 changes: 102 additions & 0 deletions app/Http/Controllers/api/v1/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@
namespace App\Http\Controllers\api\v1;

use App\Enums\CustomStatusCodes;
use App\Enums\RoomAuthTokenType;
use App\Enums\RoomSortingType;
use App\Enums\RoomUserRole;
use App\Enums\RoomVisibility;
use App\Http\Controllers\Controller;
use App\Http\Requests\CreateRoom;
use App\Http\Requests\JoinMeeting;
use App\Http\Requests\RoomAuthRequest;
use App\Http\Requests\ShowRoomsRequest;
use App\Http\Requests\StartMeeting;
use App\Http\Requests\TransferOwnershipRequest;
use App\Http\Requests\UpdateRoomDescription;
use App\Http\Requests\UpdateRoomSettings;
use App\Http\Resources\RoomAuthTokenResource;
use App\Http\Resources\RoomSettings;
use App\Models\Room;
use App\Models\RoomAuthToken;
use App\Models\RoomToken;
use App\Models\RoomType;
use App\Models\User;
use App\Prometheus\Counter;
use App\Services\RoomAuthService;
use App\Services\RoomService;
use App\Settings\GeneralSettings;
Expand All @@ -27,6 +33,7 @@
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Log;

class RoomController extends Controller
Expand Down Expand Up @@ -423,4 +430,99 @@ public function transferOwnership(Room $room, TransferOwnershipRequest $request)
return abort(500);
}
}

/**
* Authenticate a user based on a provided access code or
* room token and return a room auth token for further requests
*/
public function authenticate(Room $room, RoomAuthRequest $request)
{
// Check if user tries to authenticate even though it is not necessary
if (\Illuminate\Support\Facades\Auth::user() && ($room->owner->is(Auth::user()) || $room->members->contains(Auth::user()) || Auth::user()->can('viewAll', Room::class))) {
return response()->noContent();
}

if ($request->type === RoomAuthTokenType::CODE->value) {
if (! $room->getRoomSetting('allow_guests') && ! Auth::user()) {
// user is not authenticated and room is not allowed for guests
Counter::get('room_authentication_errors_total')->inc('guest_access');

Log::notice('Room guest access failed for room {room}', ['room' => $room->getLogLabel()]);

abort(403, 'guests_not_allowed');
}

if ($room->access_code == null) {
// room has no access code set therefore authentication by access code is not required
return response()->noContent();
}

// Key used to rate limit access code attempts
$rateLimitKey = 'room_auth:'.($request->user()?->id ?: $request->ip());

// Check if rate limit has been reached
if (RateLimiter::tooManyAttempts($rateLimitKey, 6)) {
return response()->json(['limit' => 'room_auth', 'retry_after' => RateLimiter::availableIn($rateLimitKey)], 429);
}

$accessCode = $request->access_code;

if (is_numeric($accessCode) && $room->access_code == $accessCode) {
// Generate new room auth token or retrieve existing one
$roomAuthToken = RoomAuthToken::firstOrCreate([
'room_id' => $room->id,
'session_id' => session()->getId(),
'type' => RoomAuthTokenType::CODE,
]);

return new RoomAuthTokenResource($roomAuthToken);
} else {
// Access code is incorrect

// Metrics and logging
Counter::get('room_authentication_errors_total')->inc('access_code_invalid');
Log::notice('Room access code authentication failed for room {room}', ['room' => $room->getLogLabel()]);

// Increment rate limit counter for failed access code attempts
RateLimiter::increment($rateLimitKey);

abort(401, 'invalid_code');
}
} elseif ($request->type === RoomAuthTokenType::TOKEN->value) {
if (! Auth::guest()) {
// current user is authenticated
abort(420, 'guests only');
}

$accessToken = RoomToken::where('token', $request->access_token)
->where('room_id', $room->id)
->first();

if ($accessToken == null) {
// Access token is invalid

// Metrics and logging
Counter::get('room_authentication_errors_total')->inc('token');

Log::notice('Room token authentication failed for room {room}', ['room' => $room->getLogLabel()]);
abort(401, 'invalid_token');
}

$accessToken->last_usage = now();
$accessToken->save();

// Generate new room auth token
$roomAuthToken = RoomAuthToken::firstOrCreate([
'room_id' => $room->id,
'room_token_id' => $accessToken->token,
'session_id' => session()->getId(),
'type' => RoomAuthTokenType::TOKEN,
]);

return new RoomAuthTokenResource($roomAuthToken);
} else {
// Unknown authentication type
abort(500);
}
}
}
15 changes: 0 additions & 15 deletions app/Http/Controllers/api/v1/RoomFileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use App\Http\Resources\PrivateRoomFile;
use App\Models\Room;
use App\Models\RoomFile;
use App\Services\RoomFileService;
use App\Settings\GeneralSettings;
use Illuminate\Http\Request;
use Log;
Expand Down Expand Up @@ -95,20 +94,6 @@ public function store(Room $room, StoreRoomFile $request)
return response()->noContent();
}

/**
* Get url to download the specified file
*
* @param UpdateRoomFile $request
* @return \Illuminate\Http\JsonResponse
*/
public function show(Room $room, RoomFile $file)
{
$roomFileService = new RoomFileService($file);
$url = $roomFileService->setTimeLimit(1)->url();

return response()->json(['url' => $url]);
}

/**
* Update the specified file attributes
*
Expand Down
Loading
Loading