Skip to content

Commit d8be167

Browse files
PurpleIsEverythingDaneEveritt
authored andcommitted
Add support for allowing subusers to access SFTP. (pterodactyl#918)
1 parent f61a5fa commit d8be167

File tree

10 files changed

+64
-70
lines changed

10 files changed

+64
-70
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
.vscode/*
66
storage/framework/*
77
/.idea
8+
/nbproject
89

10+
package-lock.json
911
composer.lock
1012
node_modules
1113

app/Models/Permission.php

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,12 @@ class Permission extends Model implements CleansAttributes, ValidableContract
9090
'view-startup' => null,
9191
'edit-startup' => null,
9292
],
93-
'sftp' => [
94-
'view-sftp' => null,
95-
'view-sftp-password' => null,
96-
'reset-sftp' => 's:set-password',
93+
'database' => [
94+
'view-databases' => null,
95+
'reset-db-password' => null,
9796
],
9897
'file' => [
98+
'access-sftp' => null,
9999
'list-files' => 's:files:get',
100100
'edit-files' => 's:files:read',
101101
'save-files' => 's:files:post',
@@ -106,7 +106,7 @@ class Permission extends Model implements CleansAttributes, ValidableContract
106106
'create-files' => 's:files:create',
107107
'upload-files' => 's:files:upload',
108108
'delete-files' => 's:files:delete',
109-
'download-files' => null,
109+
'download-files' => 's:files:download',
110110
],
111111
'task' => [
112112
'list-schedules' => null,
@@ -117,10 +117,6 @@ class Permission extends Model implements CleansAttributes, ValidableContract
117117
'create-schedule' => null,
118118
'delete-schedule' => null,
119119
],
120-
'database' => [
121-
'view-databases' => null,
122-
'reset-db-password' => null,
123-
],
124120
];
125121

126122
/**

app/Services/Sftp/AuthenticateUsingPasswordService.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService;
77
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
88
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
9+
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
910
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
1011

1112
class AuthenticateUsingPasswordService
@@ -25,20 +26,28 @@ class AuthenticateUsingPasswordService
2526
*/
2627
private $userRepository;
2728

29+
/**
30+
* @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface
31+
*/
32+
private $subuserRepository;
33+
2834
/**
2935
* AuthenticateUsingPasswordService constructor.
3036
*
31-
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService $keyProviderService
32-
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
33-
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $userRepository
37+
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService $keyProviderService
38+
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
39+
* @param \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface $subuserRepository
40+
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $userRepository
3441
*/
3542
public function __construct(
3643
DaemonKeyProviderService $keyProviderService,
3744
ServerRepositoryInterface $repository,
45+
SubuserRepositoryInterface $subuserRepository,
3846
UserRepositoryInterface $userRepository
3947
) {
4048
$this->keyProviderService = $keyProviderService;
4149
$this->repository = $repository;
50+
$this->subuserRepository = $subuserRepository;
4251
$this->userRepository = $userRepository;
4352
}
4453

@@ -73,10 +82,19 @@ public function handle(string $username, string $password, int $node, string $se
7382
}
7483

7584
$server = $this->repository->setColumns(['id', 'node_id', 'owner_id', 'uuid', 'installed', 'suspended'])->getByUuid($server);
76-
if ($server->node_id !== $node || (! $user->root_admin && $server->owner_id !== $user->id)) {
85+
if ($server->node_id !== $node) {
7786
throw new RecordNotFoundException;
7887
}
7988

89+
if (! $user->root_admin && $server->owner_id !== $user->id) {
90+
$subuser = $this->subuserRepository->getWithPermissionsUsingUserAndServer($user->id, $server->id);
91+
$permissions = $subuser->getRelation('permissions')->pluck('permission')->toArray();
92+
93+
if (! in_array('access-sftp', $permissions)) {
94+
throw new RecordNotFoundException;
95+
}
96+
}
97+
8098
if ($server->installed !== 1 || $server->suspended) {
8199
throw new BadRequestHttpException;
82100
}

resources/lang/de/server.php

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@
103103
'subuser_header' => 'Subuser Verwaltung',
104104
'server_header' => 'Server Verwaltung',
105105
'task_header' => 'Schedule Verwaltung',
106-
'sftp_header' => 'SFTP Verwaltung',
107106
'database_header' => 'Database Verwaltung',
108107
'power_start' => [
109108
'title' => 'Start Server',
@@ -125,17 +124,21 @@
125124
'title' => 'Send Console Command',
126125
'description' => 'Der User darf die Konsole benutzen.',
127126
],
127+
'view_sftp' => [
128+
'title' => 'SFTP erlaubt',
129+
'description' => 'Ermöglicht dem Benutzer, eine Verbindung mit dem vom Daemon bereitgestellten SFTP-Server herzustellen.',
130+
],
128131
'list_files' => [
129132
'title' => 'List Files',
130133
'description' => 'Der User darf die Server-Dateien sehen.',
131134
],
132135
'edit_files' => [
133136
'title' => 'Edit Files',
134-
'description' => 'Der User darf die Server-Dateien sehen.',
137+
'description' => 'Der User darf die Server-Dateien sehen. SFTP ist von dieser Erlaubnis nicht betroffen.',
135138
],
136139
'save_files' => [
137140
'title' => 'Save Files',
138-
'description' => 'Der User darf die Server-Dateien bearbeiten.',
141+
'description' => 'Der User darf die Server-Dateien bearbeiten. SFTP ist von dieser Erlaubnis nicht betroffen.',
139142
],
140143
'move_files' => [
141144
'title' => 'Rename & Move Files',
@@ -233,18 +236,6 @@
233236
'title' => 'Delete Schedule',
234237
'description' => 'Der User darf geplante Aktionen für den Server löschen.',
235238
],
236-
'view_sftp' => [
237-
'title' => 'View SFTP Details',
238-
'description' => 'Der User darf die SFTP Informationen sehen (nicht das Passwort).',
239-
],
240-
'view_sftp_password' => [
241-
'title' => 'View SFTP Password',
242-
'description' => 'Der User darf dass SFTP Passwort sehen.',
243-
],
244-
'reset_sftp' => [
245-
'title' => 'Reset SFTP Password',
246-
'description' => 'Der User darf dass SFTP Passwort zurücksetzen.',
247-
],
248239
'view_databases' => [
249240
'title' => 'View Database Details',
250241
'description' => 'Der User darf die Datenbankinformationen sehen.',
@@ -298,7 +289,6 @@
298289
'sftp' => [
299290
'header' => 'SFTP Information',
300291
'header_sub' => 'Details für eine SFTP verbindung.',
301-
'change_pass' => 'Passwort ändern',
302292
'details' => 'SFTP Details',
303293
'conn_addr' => 'Adresse',
304294
'warning' => 'Bitte benutze SFTP und nicht FTP!.',

resources/lang/en/server.php

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@
107107
'subuser_header' => 'Subuser Management',
108108
'server_header' => 'Server Management',
109109
'task_header' => 'Schedule Management',
110-
'sftp_header' => 'SFTP Management',
111110
'database_header' => 'Database Management',
112111
'power_start' => [
113112
'title' => 'Start Server',
@@ -129,17 +128,21 @@
129128
'title' => 'Send Console Command',
130129
'description' => 'Allows sending a command from the console. If the user does not have stop or restart permissions they cannot send the application\'s stop command.',
131130
],
131+
'view_sftp' => [
132+
'title' => 'SFTP Allowed',
133+
'description' => 'Allows user to connect to the SFTP server provided by the daemon.',
134+
],
132135
'list_files' => [
133136
'title' => 'List Files',
134137
'description' => 'Allows user to list all files and folders on the server but not view file contents.',
135138
],
136139
'edit_files' => [
137140
'title' => 'Edit Files',
138-
'description' => 'Allows user to open a file for viewing only.',
141+
'description' => 'Allows user to open a file for viewing only. SFTP is not effected by this permission.',
139142
],
140143
'save_files' => [
141144
'title' => 'Save Files',
142-
'description' => 'Allows user to save modified file contents.',
145+
'description' => 'Allows user to save modified file contents. SFTP is not effected by this permission.',
143146
],
144147
'move_files' => [
145148
'title' => 'Rename & Move Files',
@@ -237,18 +240,6 @@
237240
'title' => 'Delete Schedule',
238241
'description' => 'Allows a user to delete a schedule from the server.',
239242
],
240-
'view_sftp' => [
241-
'title' => 'View SFTP Details',
242-
'description' => 'Allows user to view the server\'s SFTP information but not the password.',
243-
],
244-
'view_sftp_password' => [
245-
'title' => 'View SFTP Password',
246-
'description' => 'Allows user to view the SFTP password for the server.',
247-
],
248-
'reset_sftp' => [
249-
'title' => 'Reset SFTP Password',
250-
'description' => 'Allows user to change the SFTP password for the server.',
251-
],
252243
'view_databases' => [
253244
'title' => 'View Database Details',
254245
'description' => 'Allows user to view all databases associated with this server including the usernames and passwords for the databases.',
@@ -302,7 +293,6 @@
302293
'sftp' => [
303294
'header' => 'SFTP Configuration',
304295
'header_sub' => 'Account details for SFTP connections.',
305-
'change_pass' => 'Change SFTP Password',
306296
'details' => 'SFTP Details',
307297
'conn_addr' => 'Connection Address',
308298
'warning' => 'The SFTP password is your account password. Ensure that your client is set to use SFTP and not FTP or FTPS for connections, there is a difference between the protocols.',

resources/lang/es/server.php

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@
103103
'subuser_header' => 'Subuser De Gestión',
104104
'server_header' => 'Administración Del Servidor',
105105
'task_header' => 'La Programación De La Administración',
106-
'sftp_header' => 'SFTP Gestión',
107106
'database_header' => 'Administración De Base De Datos',
108107
'power_start' => [
109108
'title' => 'Inicio Del Servidor',
@@ -125,17 +124,21 @@
125124
'title' => 'Enviar Comandos De La Consola',
126125
'description' => 'Permite el envío de un comando desde la consola. Si el usuario no tiene permiso para detener o reiniciar, no puede enviar el comando de detención de la aplicación.',
127126
],
127+
'view_sftp' => [
128+
'title' => 'SFTP permitido',
129+
'description' => 'Permite al usuario conectarse al servidor SFTP proporcionado por el daemon.',
130+
],
128131
'list_files' => [
129132
'title' => 'Lista De Archivos',
130133
'description' => 'Permite al usuario a la lista de todos los archivos y carpetas en el servidor, pero no ver el contenido del archivo.',
131134
],
132135
'edit_files' => [
133136
'title' => 'Editar Archivos',
134-
'description' => 'Permite al usuario abrir un archivo solo para visualización.',
137+
'description' => 'Permite al usuario abrir un archivo solo para visualización. SFTP no se ve afectado por este permiso.',
135138
],
136139
'save_files' => [
137140
'title' => 'Guardar Archivos',
138-
'description' => 'Permite que el usuario guarde el archivo modificado contenido.',
141+
'description' => 'Permite que el usuario guarde el archivo modificado contenido. SFTP no se ve afectado por este permiso.',
139142
],
140143
'move_files' => [
141144
'title' => 'Renombrar Y Mover Archivos',
@@ -229,18 +232,6 @@
229232
'title' => 'Eliminar Horario',
230233
'description' => 'Permite a un usuario para eliminar un programa desde el servidor.',
231234
],
232-
'view_sftp' => [
233-
'title' => 'Ver SFTP Detalles',
234-
'description' => 'Permite al usuario ver la información SFTP del servidor pero no la contraseña.',
235-
],
236-
'view_sftp_password' => [
237-
'title' => 'Ver SFTP Contraseña',
238-
'description' => 'Permite al usuario ver el SFTP contraseña para el servidor.',
239-
],
240-
'reset_sftp' => [
241-
'title' => 'Restablecer Contraseña SFTP',
242-
'description' => 'Le permite al usuario cambiar el SFTP contraseña para el servidor.',
243-
],
244235
'view_databases' => [
245236
'title' => 'Ver Detalles De Base De Datos',
246237
'description' => 'Permite al usuario ver todas las bases de datos asociadas con este servidor, incluidos los nombres de usuario y contraseñas de las bases de datos de.',
@@ -294,7 +285,6 @@
294285
'sftp' => [
295286
'header' => 'SFTP Configuración',
296287
'header_sub' => 'Detalles de la cuenta para SFTP.',
297-
'change_pass' => 'Cambiar Contraseña SFTP',
298288
'details' => 'SFTP Detalles',
299289
'conn_addr' => 'Dirección De Conexión',
300290
'warning' => 'Asegúrese de que su cliente está configurado para utilizar SFTP y FTP no o FTPS para las conexiones, hay una diferencia entre los protocolos.',

resources/themes/pterodactyl/layouts/master.blade.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class="active"
166166
</a>
167167
</li>
168168
@endcan
169-
@if(Gate::allows('view-startup', $server) || Gate::allows('view-sftp', $server) || Gate::allows('view-allocation', $server))
169+
@if(Gate::allows('view-startup', $server) || Gate::allows('access-sftp', $server) || Gate::allows('view-allocation', $server))
170170
<li class="treeview
171171
@if(starts_with(Route::currentRouteName(), 'server.settings'))
172172
active
@@ -183,7 +183,7 @@ class="active"
183183
@can('view-allocation', $server)
184184
<li class="{{ Route::currentRouteName() !== 'server.settings.allocation' ?: 'active' }}"><a href="{{ route('server.settings.allocation', $server->uuidShort) }}"><i class="fa fa-angle-right"></i> @lang('navigation.server.port_allocations')</a></li>
185185
@endcan
186-
@can('view-sftp', $server)
186+
@can('access-sftp', $server)
187187
<li class="{{ Route::currentRouteName() !== 'server.settings.sftp' ?: 'active' }}"><a href="{{ route('server.settings.sftp', $server->uuidShort) }}"><i class="fa fa-angle-right"></i> @lang('navigation.server.sftp_settings')</a></li>
188188
@endcan
189189
@can('view-startup', $server)

tests/Unit/Services/Sftp/AuthenticateUsingPasswordServiceTest.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
1212
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
1313
use Pterodactyl\Services\Sftp\AuthenticateUsingPasswordService;
14+
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
1415

1516
class AuthenticateUsingPasswordServiceTest extends TestCase
1617
{
@@ -23,6 +24,11 @@ class AuthenticateUsingPasswordServiceTest extends TestCase
2324
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface|\Mockery\Mock
2425
*/
2526
private $repository;
27+
28+
/**
29+
* @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface|\Mockery\Mock
30+
*/
31+
private $subuserRepository;
2632

2733
/**
2834
* @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface|\Mockery\Mock
@@ -38,6 +44,7 @@ public function setUp()
3844

3945
$this->keyProviderService = m::mock(DaemonKeyProviderService::class);
4046
$this->repository = m::mock(ServerRepositoryInterface::class);
47+
$this->subuserRepository = m::mock(SubuserRepositoryInterface::class);
4148
$this->userRepository = m::mock(UserRepositoryInterface::class);
4249
}
4350

@@ -130,8 +137,8 @@ public function testExceptionIsThrownIfNoUserAccountIsFound()
130137
}
131138

132139
/**
133-
* Test that an exception is thrown if the user is not the owner of the server
134-
* and is not an administrator.
140+
* Test that an exception is thrown if the user is not the owner of the server,
141+
* is not a sub user and is not an administrator.
135142
*
136143
* @expectedException \Pterodactyl\Exceptions\Repository\RecordNotFoundException
137144
*/
@@ -146,6 +153,8 @@ public function testExceptionIsThrownIfUserDoesNotOwnServer()
146153
$this->repository->shouldReceive('setColumns')->with(['id', 'node_id', 'owner_id', 'uuid', 'installed', 'suspended'])->once()->andReturnSelf();
147154
$this->repository->shouldReceive('getByUuid')->with($server->uuidShort)->once()->andReturn($server);
148155

156+
$this->subuserRepository->shouldReceive('getWithPermissionsUsingUserAndServer')->with($user->id, $server->id)->once()->andThrow(new RecordNotFoundException);
157+
149158
$this->getService()->handle($user->username, 'password', 1, $server->uuidShort);
150159
}
151160

@@ -214,6 +223,6 @@ public function testNotInstalledServer()
214223
*/
215224
private function getService(): AuthenticateUsingPasswordService
216225
{
217-
return new AuthenticateUsingPasswordService($this->keyProviderService, $this->repository, $this->userRepository);
226+
return new AuthenticateUsingPasswordService($this->keyProviderService, $this->repository, $this->subuserRepository, $this->userRepository);
218227
}
219228
}

tests/Unit/Services/Subusers/PermissionCreationServiceTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,11 @@ public function setUp()
4242
*/
4343
public function testPermissionsAreAssignedCorrectly()
4444
{
45-
$permissions = ['reset-sftp', 'view-sftp'];
45+
$permissions = ['access-sftp'];
4646

4747
$this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf()
4848
->shouldReceive('insert')->with([
49-
['subuser_id' => 1, 'permission' => 'reset-sftp'],
50-
['subuser_id' => 1, 'permission' => 'view-sftp'],
49+
['subuser_id' => 1, 'permission' => 'access-sftp'],
5150
])->once()->andReturn(true);
5251

5352
$this->service->handle(1, $permissions);

tests/Unit/Services/Subusers/SubuserCreationServiceTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public function testAccountIsCreatedForNewUser()
121121
*/
122122
public function testExistingUserCanBeAddedAsASubuser()
123123
{
124-
$permissions = ['view-sftp', 'reset-sftp'];
124+
$permissions = ['access-sftp'];
125125
$server = factory(Server::class)->make();
126126
$user = factory(User::class)->make();
127127
$subuser = factory(Subuser::class)->make(['user_id' => $user->id, 'server_id' => $server->id]);

0 commit comments

Comments
 (0)