diff --git a/backend/.gitignore b/backend/.gitignore index 92c6761..f35e8ef 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -6,9 +6,8 @@ /storage/*.key /vendor /dist-frontend -.env -.env.backup -.env.production +.env* +!.env.example Homestead.json Homestead.yaml auth.json diff --git a/backend/app/Http/Controllers/AdminController.php b/backend/app/Http/Controllers/AdminController.php index 80e04eb..879201c 100644 --- a/backend/app/Http/Controllers/AdminController.php +++ b/backend/app/Http/Controllers/AdminController.php @@ -188,6 +188,13 @@ class AdminController extends Controller public function clearOptimization() { if(!request()->user()->hasPermission("admin-maintenance-update")) abort(401); + + //Check if .env file exists. If not, abort the operation + if(!file_exists(base_path('.env'))) { + return response()->json([ + 'message' => 'WARNING!! Environment file not found' + ], 400); + } Artisan::call('optimize:clear'); @@ -205,6 +212,66 @@ class AdminController extends Controller 'message' => 'Cache cleared successfully' ]); } + + public function encryptEnvironment(Request $request) { + if(!request()->user()->hasPermission("admin-maintenance-update")) abort(401); + $request->validate([ + 'key' => 'required|string|min:6' + ]); + + $key = "base64:".base64_encode(hash('sha256', $request->input('key'), true)); + + Artisan::call('env:encrypt', ['--force' => true, '--no-interaction' => true, '--key' => $key]); + //Check if "ERROR" is in the output + $output = Artisan::output(); + if(str_contains($output, 'ERROR')) { + return response()->json([ + 'message' => str_replace('ERROR ', '', $output) + ], 400); + } + + return response()->json([ + 'message' => 'Environment encrypted successfully' + ]); + } + + public function decryptEnvironment(Request $request) { + if(!request()->user()->hasPermission("admin-maintenance-update")) abort(401); + $request->validate([ + 'key' => 'required|string|min:6' + ]); + + $key = "base64:".base64_encode(hash('sha256', $request->input('key'), true)); + + Artisan::call('env:decrypt', ['--force' => true, '--no-interaction' => true, '--key' => $key]); + //Check if "ERROR" is in the output + $output = Artisan::output(); + if(str_contains($output, 'ERROR')) { + return response()->json([ + 'message' => str_replace('ERROR ', '', $output) + ], 400); + } + + //Delete .env.encrypted file if exists + if(file_exists(base_path('.env.encrypted'))) unlink(base_path('.env.encrypted')); + + return response()->json([ + 'message' => 'Environment decrypted successfully' + ]); + } + + public function deleteEnvironment() { + if(!request()->user()->hasPermission("admin-maintenance-update")) abort(401); + + if(!file_exists(base_path('bootstrap/cache/config.php'))) Artisan::call('config:cache'); + + //Delete .env file if exists + if(file_exists(base_path('.env'))) unlink(base_path('.env')); + + return response()->json([ + 'message' => 'Environment file deleted successfully' + ]); + } public function getTelegramBotDebugInfo() { if(!request()->user()->hasPermission("admin-maintenance-update")) abort(401); diff --git a/backend/routes/api.php b/backend/routes/api.php index bf1e9b3..102b5c4 100644 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -109,6 +109,10 @@ Route::middleware('auth:sanctum')->group( function () { Route::post('/admin/clearOptimization', [AdminController::class, 'clearOptimization']); Route::post('/admin/clearCache', [AdminController::class, 'clearCache']); + Route::post('/admin/envEncrypt', [AdminController::class, 'encryptEnvironment']); + Route::post('/admin/envDecrypt', [AdminController::class, 'decryptEnvironment']); + Route::post('/admin/envDelete', [AdminController::class, 'deleteEnvironment']); + Route::get('/admin/telegramBot/debug', [AdminController::class, 'getTelegramBotDebugInfo']); Route::post('/admin/telegramBot/setWebhook', [AdminController::class, 'setTelegramWebhook']); Route::post('/admin/telegramBot/unsetWebhook', [AdminController::class, 'unsetTelegramWebhook']); diff --git a/frontend/src/app/_components/modal-alert/modal-alert.component.ts b/frontend/src/app/_components/modal-alert/modal-alert.component.ts index 18b6b27..940e3bd 100644 --- a/frontend/src/app/_components/modal-alert/modal-alert.component.ts +++ b/frontend/src/app/_components/modal-alert/modal-alert.component.ts @@ -95,8 +95,8 @@ export class ModalAlertComponent implements OnInit, OnDestroy { this.translate.get([ 'alert.delete_confirm_title', 'alert.delete_confirm_text', - 'table.yes_remove', - 'table.cancel', + 'yes_remove', + 'cancel', 'alert.deleted_successfully', 'alert.delete_failed' ]).subscribe((res: any) => { @@ -108,8 +108,8 @@ export class ModalAlertComponent implements OnInit, OnDestroy { showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', - confirmButtonText: res['table.yes_remove'], - cancelButtonText: res['table.cancel'] + confirmButtonText: res['yes_remove'], + cancelButtonText: res['cancel'] }).then((result: any) => { if (result.isConfirmed) { this.api.patch(`alerts/${this.id}`, { diff --git a/frontend/src/app/_components/table/table.component.ts b/frontend/src/app/_components/table/table.component.ts index d9725b8..5231c35 100644 --- a/frontend/src/app/_components/table/table.component.ts +++ b/frontend/src/app/_components/table/table.component.ts @@ -242,7 +242,7 @@ export class TableComponent implements OnInit, OnDestroy { } deleteService(id: number) { - this.translate.get(['table.yes_remove', 'table.cancel', 'table.remove_service_confirm', 'table.remove_service_text']).subscribe((res: { [key: string]: string; }) => { + this.translate.get(['yes_remove', 'cancel', 'table.remove_service_confirm', 'table.remove_service_text']).subscribe((res: { [key: string]: string; }) => { Swal.fire({ title: res['table.remove_service_confirm'], text: res['table.remove_service_confirm_text'], @@ -250,8 +250,8 @@ export class TableComponent implements OnInit, OnDestroy { showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', - confirmButtonText: res['table.yes_remove'], - cancelButtonText: res['table.cancel'] + confirmButtonText: res['yes_remove'], + cancelButtonText: res['cancel'] }).then((result) => { if (result.isConfirmed) { this.api.delete(`services/${id}`).then((response) => { @@ -274,7 +274,7 @@ export class TableComponent implements OnInit, OnDestroy { } deleteTraining(id: number) { - this.translate.get(['table.yes_remove', 'table.cancel', 'table.remove_training_confirm', 'table.remove_training_text']).subscribe((res: { [key: string]: string; }) => { + this.translate.get(['yes_remove', 'cancel', 'table.remove_training_confirm', 'table.remove_training_text']).subscribe((res: { [key: string]: string; }) => { Swal.fire({ title: res['table.remove_training_confirm'], text: res['table.remove_training_confirm_text'], @@ -282,8 +282,8 @@ export class TableComponent implements OnInit, OnDestroy { showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', - confirmButtonText: res['table.yes_remove'], - cancelButtonText: res['table.cancel'] + confirmButtonText: res['yes_remove'], + cancelButtonText: res['cancel'] }).then((result) => { if (result.isConfirmed) { this.api.delete(`trainings/${id}`).then((response) => { diff --git a/frontend/src/app/_routes/admin/maintenance/admin-maintenance.component.html b/frontend/src/app/_routes/admin/maintenance/admin-maintenance.component.html index 25c8870..fcb997f 100644 --- a/frontend/src/app/_routes/admin/maintenance/admin-maintenance.component.html +++ b/frontend/src/app/_routes/admin/maintenance/admin-maintenance.component.html @@ -133,6 +133,13 @@ + +
{{ 'admin.env_operations'|translate|ftitlecase }}
+ + + +