Ensure correct permissions on user creation or file manager interaction - changed to an action as its used multiple places

This commit is contained in:
Alex Crivion
2025-02-23 17:03:52 +00:00
parent 35d39a9113
commit 0e22b669c9
9 changed files with 109 additions and 70 deletions

View File

@@ -33,16 +33,7 @@ class CreateFileAction
}
// ensure file/directory permissions
$p = Process::run([
'sudo',
config('laranode.laranode_bin_path') . '/laranode-file-permissions.sh',
$r->path . '/' . $r->fileName,
auth()->user()->systemUsername,
]);
dump('sudo ' . config('laranode.laranode_bin_path') . '/laranode-file-permissions.sh', $r->path . '/' . $r->fileName);
dump($p->output(), $p->errorOutput());
(new EnsurePermissionsAction)->execute($r->path . '/' . $r->fileName, auth()->user()->systemUsername);
return response()->json([
'message' => $r->fileType . ' ' . $r->path . '/' . $r->fileName . ' created successfully!',

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Actions\Filemanager;
use Illuminate\Support\Facades\Process;
class EnsurePermissionsAction
{
public function execute(string $path, string $systemUser): void
{
Process::run([
'sudo',
config('laranode.laranode_bin_path') . '/laranode-file-permissions.sh',
$path,
$systemUser,
]);
}
}

View File

@@ -22,32 +22,7 @@ class GetFileContentsAction
$filesystem = $this->filesystem;
$editableMimeTypes = [
'text/plain', // .txt, .log, .ini, .env, .conf, .md, .sh, .bash, .zsh
'text/html', // .html, .htm
'text/css', // .css
'text/x-php', // .php
'application/x-empty', // for example empty php files
'text/javascript', // .js
'application/javascript', // .js
'application/json', // .json
'application/xml', // .xml
'application/x-yaml', // .yaml, .yml
'application/x-httpd-php', // .php
'text/x-python', // .py
'text/x-c', // .c
'text/x-c++', // .cpp, .cc, .h
'text/x-java-source', // .java
'text/x-shellscript', // .sh, .bash, .zsh
'text/x-sql', // .sql
'text/markdown', // .md
'text/x-typescript', // .ts, .tsx
'text/x-jsx', // .jsx, .tsx
'text/rtf',
'application/x-sh', // .sh
'application/x-sql', // .sql
];
$editableMimeTypes = config('laranode.editable_mime_types');
try {

View File

@@ -20,10 +20,14 @@ class UploadFileAction
]);
$file = $r->file('file');
$path = Config::get('laranode.user_base_path') . '/' . $r->path;
$path = '/home/' . $r->user()->systemUsername . '/' . $r->path;
File::append($path . '/' . $r->originalName, $file->get());
// ensure file permissions
(new EnsurePermissionsAction)->execute($r->path . '/' . $r->originalName, $r->user()->systemUsername);
return response()->json([
'message' => 'Chunk uploaded',
'chunkIndex' => $r->chunkIndex,

View File

@@ -61,5 +61,10 @@ class AppServiceProvider extends ServiceProvider
{
Vite::prefetch(concurrency: 3);
URL::forceScheme('https');
if (Auth::check()) {
$user = Auth::user();
Config::set('laranode.user_base_path', $user->homedir);
}
}
}

View File

@@ -34,4 +34,44 @@ return [
*/
'apache_vhost_template' => base_path('laranode-scripts/templates/apache-vhost.template'),
/*
|--------------------------------------------------------------------------
| Laranode File Manager - Editable Mime Types
|--------------------------------------------------------------------------
|
| This option allows you to specify the mime types that can be edited
| in the file manager.
*/
'editable_mime_types' =>
[
'text/plain', // .txt, .log, .ini, .env, .conf, .md, .sh, .bash, .zsh
'text/html', // .html, .htm
'text/css', // .css
'text/x-php', // .php
'text/csv', // .csv
'application/x-empty', // for example empty php files
'text/javascript', // .js
'application/javascript', // .js
'application/x-javascript', // .js
'application/java', // .java, .js (sometimes)
'application/json', // .json
'application/xml', // .xml
'application/x-yaml', // .yaml, .yml
'application/x-httpd-php', // .php
'text/php', // .php
'text/x-python', // .py
'text/x-c', // .c
'text/x-c++', // .cpp, .cc, .h
'text/x-java-source', // .java
'text/x-shellscript', // .sh, .bash, .zsh
'text/x-sql', // .sql
'text/markdown', // .md
'text/x-typescript', // .ts, .tsx
'text/x-jsx', // .jsx, .tsx
'text/rtf',
'application/x-sh', // .sh
'application/x-sql', // .sql
]
];

View File

@@ -52,6 +52,8 @@ create_user() {
echo "User $USERNAME created successfully with no SSH login."
fi
chmod 770 "/home/$USERNAME"
# add this user group to www-data group too
usermod -aG "$USERNAME" www-data

View File

@@ -38,7 +38,7 @@ const EditFile = ({ editFile, setEditFile }) => {
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
const decoder = new TextDecoder("utf-8");
// let buffer = '';
while (true) {

View File

@@ -249,7 +249,7 @@ const Filemanager = () => {
{copyFiles && (
<button onClick={() => pasteFiles('paste')} className="flex items-center hover:text-indigo-600 disabled:opacity-25">
<BiPaste className="mr-1" />
Paste
Paste -tbd
</button>
)}
@@ -287,42 +287,45 @@ const Filemanager = () => {
)}
{files.sort((a, b) => {
if (a.type === 'dir' && b.type !== 'dir') return -1;
if (a.type !== 'dir' && b.type === 'dir') return 1;
return 0;
}).map((file, index) => (
<div
key={`file-${index}`}
className={`flex items-center font-bold text-gray-900 dark:text-gray-300 py-3 px-6 border-b dark:border-b-gray-800 space-x-2 ${selectedPaths.includes(file.path)
? 'bg-gray-200 text-sky-700 hover:text-sky-700 hover:bg-gray-100 dark:hover:bg-gray-700 dark:hover:text-sky-600 dark:bg-gray-800 dark:text-sky-600'
: 'bg-white hover:bg-gray-200 dark:bg-gray-850 dark:hover:bg-gray-800'
}`}
onDoubleClick={() => handleDoubleClick(file)}
>
<div>
<Checkbox checked={selectedPaths.includes(file.path)} onChange={(e) => handleFileClick(file)} className="-mt-1 mr-1" />
</div>
{file.type === "dir" ? (
{files
.filter(file => !file.path.includes('laranode-scripts'))
.filter(file => ![".bash_logout", ".bashrc", ".profile"].includes(file.path))
.sort((a, b) => {
if (a.type === 'dir' && b.type !== 'dir') return -1;
if (a.type !== 'dir' && b.type === 'dir') return 1;
return 0;
}).map((file, index) => (
<div
key={`file-${index}`}
className={`flex items-center font-bold text-gray-900 dark:text-gray-300 py-3 px-6 border-b dark:border-b-gray-800 space-x-2 ${selectedPaths.includes(file.path)
? 'bg-gray-200 text-sky-700 hover:text-sky-700 hover:bg-gray-100 dark:hover:bg-gray-700 dark:hover:text-sky-600 dark:bg-gray-800 dark:text-sky-600'
: 'bg-white hover:bg-gray-200 dark:bg-gray-850 dark:hover:bg-gray-800'
}`}
onDoubleClick={() => handleDoubleClick(file)}
>
<div>
<FaFolderClosed className={`text-gray-500 ${selectedPaths.includes(file.path) ? 'text-sky-600' : ''} cursor-pointer`} />
<Checkbox checked={selectedPaths.includes(file.path)} onChange={(e) => handleFileClick(file)} className="-mt-1 mr-1" />
</div>
) : (
<div className="w-4 h-4">
<FileIcon extension={file.path.split('.').pop()} {...defaultStyles[file.path.split('.').pop()]} className="cursor-pointer" />
{file.type === "dir" ? (
<div>
<FaFolderClosed className={`text-gray-500 ${selectedPaths.includes(file.path) ? 'text-sky-600' : ''} cursor-pointer`} />
</div>
) : (
<div className="w-4 h-4">
<FileIcon extension={file.path.split('.').pop()} {...defaultStyles[file.path.split('.').pop()]} className="cursor-pointer" />
</div>
)}
<div className={`text-sm cursor-pointer flex-grow flex items-center ${selectedPaths.includes(file.path) && cutFiles && 'text-gray-400'}`}>
{file.path.split('/').pop()}
{selectedPaths.includes(file.path) && cutFiles && <IoMdCut className="ml-1" />}
</div>
)}
<div className={`text-sm cursor-pointer flex-grow flex items-center ${selectedPaths.includes(file.path) && cutFiles && 'text-gray-400'}`}>
{file.path.split('/').pop()}
{selectedPaths.includes(file.path) && cutFiles && <IoMdCut className="ml-1" />}
<div className="text-xs text-gray-400 dark:text-gray-600">
{typeof file.file_size == "undefined" ? "--" : formatBytes(file.file_size)}
</div>
</div>
<div className="text-xs text-gray-400 dark:text-gray-600">
{typeof file.file_size == "undefined" ? "--" : formatBytes(file.file_size)}
</div>
</div>
))}
))}
</div>
</div>