Add support for tracking more SFTP specific events
This commit is contained in:
parent
2e01891074
commit
33ab762f5a
5 changed files with 38 additions and 11 deletions
|
@ -6,6 +6,7 @@ use Illuminate\Http\Request;
|
||||||
use Pterodactyl\Models\User;
|
use Pterodactyl\Models\User;
|
||||||
use Pterodactyl\Models\Server;
|
use Pterodactyl\Models\Server;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Pterodactyl\Facades\Activity;
|
||||||
use Pterodactyl\Models\Permission;
|
use Pterodactyl\Models\Permission;
|
||||||
use phpseclib3\Crypt\PublicKeyLoader;
|
use phpseclib3\Crypt\PublicKeyLoader;
|
||||||
use Pterodactyl\Http\Controllers\Controller;
|
use Pterodactyl\Http\Controllers\Controller;
|
||||||
|
@ -51,6 +52,8 @@ class SftpAuthenticationController extends Controller
|
||||||
|
|
||||||
if ($request->input('type') !== 'public_key') {
|
if ($request->input('type') !== 'public_key') {
|
||||||
if (!password_verify($request->input('password'), $user->password)) {
|
if (!password_verify($request->input('password'), $user->password)) {
|
||||||
|
Activity::event('auth:sftp.fail')->property('method', 'password')->subject($user)->log();
|
||||||
|
|
||||||
$this->reject($request);
|
$this->reject($request);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,13 +65,29 @@ class SftpAuthenticationController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$key || !$user->sshKeys()->where('fingerprint', $key->getFingerprint('sha256'))->exists()) {
|
if (!$key || !$user->sshKeys()->where('fingerprint', $key->getFingerprint('sha256'))->exists()) {
|
||||||
|
// We don't log here because of the way the SFTP system works. This endpoint
|
||||||
|
// will get hit for every key the user provides, which could be 4 or 5. That is
|
||||||
|
// a lot of unnecessary log noise.
|
||||||
|
//
|
||||||
|
// For now, we'll only log failures due to a bad password as those are not likely
|
||||||
|
// to occur more than once in a session for the user, and are more likely to be of
|
||||||
|
// value to the end user.
|
||||||
$this->reject($request, is_null($key));
|
$this->reject($request, is_null($key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->validateSftpAccess($user, $server);
|
$this->validateSftpAccess($user, $server);
|
||||||
|
|
||||||
|
Activity::event('auth:sftp.success')->actor($user)
|
||||||
|
->subject($user)
|
||||||
|
->property(array_filter([
|
||||||
|
'method' => isset($key) ? 'ssh_key' : 'password',
|
||||||
|
'fingerprint' => isset($key) ? 'SHA256:' . $key->getFingerprint('sha256') : null,
|
||||||
|
]))
|
||||||
|
->log();
|
||||||
|
|
||||||
return new JsonResponse([
|
return new JsonResponse([
|
||||||
|
'user' => $user->uuid,
|
||||||
'server' => $server->uuid,
|
'server' => $server->uuid,
|
||||||
'permissions' => $this->permissions->handle($server, $user),
|
'permissions' => $this->permissions->handle($server, $user),
|
||||||
]);
|
]);
|
||||||
|
@ -136,6 +155,8 @@ class SftpAuthenticationController extends Controller
|
||||||
$permissions = $this->permissions->handle($server, $user);
|
$permissions = $this->permissions->handle($server, $user);
|
||||||
|
|
||||||
if (!in_array(Permission::ACTION_FILE_SFTP, $permissions)) {
|
if (!in_array(Permission::ACTION_FILE_SFTP, $permissions)) {
|
||||||
|
Activity::event('server:sftp.denied')->actor($user)->subject($server)->log();
|
||||||
|
|
||||||
throw new HttpForbiddenException('You do not have permission to access SFTP for this server.');
|
throw new HttpForbiddenException('You do not have permission to access SFTP for this server.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ class ActivityLogTransformer extends BaseClientTransformer
|
||||||
$str = trans('activity.' . str_replace(':', '.', $model->event));
|
$str = trans('activity.' . str_replace(':', '.', $model->event));
|
||||||
preg_match_all('/:(?<key>[\w.-]+\w)(?:[^\w:]?|$)/', $str, $matches);
|
preg_match_all('/:(?<key>[\w.-]+\w)(?:[^\w:]?|$)/', $str, $matches);
|
||||||
|
|
||||||
$exclude = array_merge($matches['key'], ['ip', 'useragent']);
|
$exclude = array_merge($matches['key'], ['ip', 'useragent', 'using_sftp']);
|
||||||
foreach ($model->properties->keys() as $key) {
|
foreach ($model->properties->keys() as $key) {
|
||||||
if (!in_array($key, $exclude, true)) {
|
if (!in_array($key, $exclude, true)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -16,6 +16,10 @@ return [
|
||||||
'recovery-token' => 'Used two-factor recovery token',
|
'recovery-token' => 'Used two-factor recovery token',
|
||||||
'token' => 'Solved two-factor challenge',
|
'token' => 'Solved two-factor challenge',
|
||||||
'ip-blocked' => 'Blocked request from unlisted IP address for :identifier',
|
'ip-blocked' => 'Blocked request from unlisted IP address for :identifier',
|
||||||
|
'sftp' => [
|
||||||
|
'success' => 'Logged in using SFTP',
|
||||||
|
'fail' => 'Failed SFTP log in',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'user' => [
|
'user' => [
|
||||||
'account' => [
|
'account' => [
|
||||||
|
@ -96,6 +100,9 @@ return [
|
||||||
'update' => 'Updated the ":action" task for the :name schedule',
|
'update' => 'Updated the ":action" task for the :name schedule',
|
||||||
'delete' => 'Deleted a task for the :name schedule',
|
'delete' => 'Deleted a task for the :name schedule',
|
||||||
],
|
],
|
||||||
|
'sftp' => [
|
||||||
|
'denied' => 'Blocked SFTP access due to permissions',
|
||||||
|
],
|
||||||
'settings' => [
|
'settings' => [
|
||||||
'rename' => 'Renamed the server from :old to :new',
|
'rename' => 'Renamed the server from :old to :new',
|
||||||
],
|
],
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Translate from '@/components/elements/Translate';
|
||||||
import { format, formatDistanceToNowStrict } from 'date-fns';
|
import { format, formatDistanceToNowStrict } from 'date-fns';
|
||||||
import { ActivityLog } from '@definitions/user';
|
import { ActivityLog } from '@definitions/user';
|
||||||
import ActivityLogMetaButton from '@/components/elements/activity/ActivityLogMetaButton';
|
import ActivityLogMetaButton from '@/components/elements/activity/ActivityLogMetaButton';
|
||||||
import { TerminalIcon } from '@heroicons/react/solid';
|
import { FolderOpenIcon, TerminalIcon } from '@heroicons/react/solid';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import style from './style.module.css';
|
import style from './style.module.css';
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
|
@ -65,10 +65,13 @@ export default ({ activity, children }: Props) => {
|
||||||
</Link>
|
</Link>
|
||||||
<div className={classNames(style.icons, 'group-hover:text-gray-300')}>
|
<div className={classNames(style.icons, 'group-hover:text-gray-300')}>
|
||||||
{activity.isApi && (
|
{activity.isApi && (
|
||||||
<Tooltip placement={'top'} content={'Performed using API Key'}>
|
<Tooltip placement={'top'} content={'Using API Key'}>
|
||||||
<span>
|
|
||||||
<TerminalIcon />
|
<TerminalIcon />
|
||||||
</span>
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{activity.properties.using_sftp && (
|
||||||
|
<Tooltip placement={'top'} content={'Using SFTP'}>
|
||||||
|
<FolderOpenIcon />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
.icons {
|
.icons {
|
||||||
@apply flex space-x-1 mx-2 transition-colors duration-100 text-gray-400;
|
@apply flex space-x-1 mx-2 transition-colors duration-100 text-gray-400;
|
||||||
|
|
||||||
& > span {
|
|
||||||
@apply px-1 py-px cursor-pointer hover:text-gray-50;
|
|
||||||
}
|
|
||||||
|
|
||||||
& svg {
|
& svg {
|
||||||
@apply w-4 h-4;
|
@apply px-1 py-px cursor-pointer hover:text-gray-50 h-5 w-auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue