Update .gitignore, add environment variable operations

This commit is contained in:
Matteo Gheza 2024-01-17 17:48:20 +01:00
parent 9ae3dc846a
commit b04ab5aa20
9 changed files with 219 additions and 23 deletions

5
backend/.gitignore vendored
View File

@ -6,9 +6,8 @@
/storage/*.key
/vendor
/dist-frontend
.env
.env.backup
.env.production
.env*
!.env.example
Homestead.json
Homestead.yaml
auth.json

View File

@ -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);

View File

@ -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']);

View File

@ -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}`, {

View File

@ -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) => {

View File

@ -133,6 +133,13 @@
<button type="button" class="btn btn-lg btn-danger" (click)="clearOptimization()">{{ 'admin.clear_optimization'|translate|ftitlecase }}</button>
<button type="button" class="btn btn-lg btn-warning" (click)="clearCache()">{{ 'admin.clear_cache'|translate|ftitlecase }}</button>
</div>
<div class="btn-group-vertical mt-2 ps-5 pe-5">
<p class="btn-group-label">{{ 'admin.env_operations'|translate|ftitlecase }}</p>
<button type="button" class="btn btn-lg btn-primary" (click)="envEncrypt()">{{ 'admin.env_encrypt'|translate|ftitlecase }}</button>
<button type="button" class="btn btn-lg btn-warning" (click)="envDecrypt()">{{ 'admin.env_decrypt'|translate|ftitlecase }}</button>
<button type="button" class="btn btn-lg btn-danger" (click)="envDelete()">{{ 'admin.env_delete'|translate|ftitlecase }}</button>
</div>
</div>
<hr>
<div class="row">

View File

@ -202,7 +202,6 @@ export class AdminMaintenanceComponent implements OnInit {
title: this.translateService.instant('success_title'),
text: this.translateService.instant('admin.run_optimization_success')
});
this.getDB();
}).catch((err: any) => {
Swal.fire({
icon: 'error',
@ -219,7 +218,6 @@ export class AdminMaintenanceComponent implements OnInit {
title: this.translateService.instant('success_title'),
text: this.translateService.instant('admin.clear_optimization_success')
});
this.getDB();
}).catch((err: any) => {
Swal.fire({
icon: 'error',
@ -236,7 +234,6 @@ export class AdminMaintenanceComponent implements OnInit {
title: this.translateService.instant('success_title'),
text: this.translateService.instant('admin.clear_cache_success')
});
this.getDB();
}).catch((err: any) => {
Swal.fire({
icon: 'error',
@ -246,6 +243,100 @@ export class AdminMaintenanceComponent implements OnInit {
});
}
envEncrypt() {
Swal.fire({
title: this.translateService.instant('admin.env_encrypt_title'),
text: this.translateService.instant('admin.env_encrypt_text'),
input: 'password',
inputAttributes: {
autocapitalize: 'off'
},
showCancelButton: true,
confirmButtonText: this.translateService.instant('confirm'),
cancelButtonText: this.translateService.instant('cancel'),
showLoaderOnConfirm: true,
preConfirm: (key) => {
return this.api.post('admin/envEncrypt', { key }).then((res: any) => {
return res;
}).catch((err: any) => {
Swal.showValidationMessage(
err.error.message
);
});
},
allowOutsideClick: () => !Swal.isLoading()
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({
icon: 'success',
title: this.translateService.instant('success_title'),
text: this.translateService.instant('admin.env_encrypt_success')
});
}
});
}
envDecrypt() {
Swal.fire({
title: this.translateService.instant('admin.env_decrypt_title'),
text: this.translateService.instant('admin.env_decrypt_text'),
input: 'password',
inputAttributes: {
autocapitalize: 'off'
},
showCancelButton: true,
confirmButtonText: this.translateService.instant('confirm'),
cancelButtonText: this.translateService.instant('cancel'),
showLoaderOnConfirm: true,
preConfirm: (key) => {
return this.api.post('admin/envDecrypt', { key }).then((res: any) => {
return res;
}).catch((err: any) => {
Swal.showValidationMessage(
err.error.message
);
});
},
allowOutsideClick: () => !Swal.isLoading()
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({
icon: 'success',
title: this.translateService.instant('success_title'),
text: this.translateService.instant('admin.env_decrypt_success')
});
}
});
}
envDelete() {
//Require confirmation before proceeding
Swal.fire({
title: this.translateService.instant('admin.env_delete_title'),
text: this.translateService.instant('admin.env_delete_text'),
icon: 'warning',
showCancelButton: true,
confirmButtonText: this.translateService.instant('yes'),
cancelButtonText: this.translateService.instant('no')
}).then((result) => {
if (result.isConfirmed) {
this.api.post('admin/envDelete').then((res: any) => {
Swal.fire({
icon: 'success',
title: this.translateService.instant('success_title'),
text: this.translateService.instant('admin.env_delete_success')
});
}).catch((err: any) => {
Swal.fire({
icon: 'error',
title: this.translateService.instant('error_title'),
text: err.message
});
});
}
});
}
setTelegramBotWebhook() {
this.api.post('admin/telegramBot/setWebhook').then((res: any) => {
Swal.fire({

View File

@ -52,11 +52,22 @@
"run": "run",
"run_confirm_title": "Are you sure you want to run this command?",
"run_confirm_text": "This action cannot be undone.",
"run_success": "Command executed successfully"
"run_success": "Command executed successfully",
"env_operations": "environment variables operations",
"env_encrypt": "encrypt .env",
"env_encrypt_title": "Encrypt .env file",
"env_encrypt_confirm": "Insert the password to encrypt the .env file",
"env_encrypt_success": ".env encrypted successfully",
"env_decrypt": "decrypt .env",
"env_decrypt_title": "Decrypt .env file",
"env_decrypt_confirm": "Insert the password to decrypt the .env file",
"env_decrypt_success": ".env decrypted successfully",
"env_delete": "delete .env",
"env_delete_title": "Delete .env file",
"env_delete_confirm": "Are you sure you want to delete the .env file?",
"env_delete_success": ".env deleted successfully"
},
"table": {
"yes_remove": "Yes, remove",
"cancel": "Cancel",
"table": {
"remove_service_confirm": "Are you sure you want to remove this service?",
"remove_service_confirm_text": "This action cannot be undone.",
"service_deleted_successfully": "Service deleted successfully",
@ -174,6 +185,9 @@
"file_too_big": "File too big",
"password_min_length": "Password must be at least 6 characters long"
},
"yes_remove": "Yes, remove",
"confirm": "Confirm",
"cancel": "Cancel",
"enable": "enable",
"disable": "disable",
"maintenance_mode": "maintenance mode",

View File

@ -52,11 +52,22 @@
"run": "esegui",
"run_confirm_title": "Sei sicuro di voler eseguire questo comando?",
"run_confirm_text": "Questa operazione non potrà essere annullata.",
"run_success": "Comando eseguito con successo"
"run_success": "Comando eseguito con successo",
"env_operations": "operazioni alle variabili d'ambiente",
"env_encrypt": "cripta .env",
"env_encrypt_title": "Cripta il file .env",
"env_encrypt_text": "Inserisci la password per criptare il file .env",
"env_encrypt_success": ".env criptato con successo",
"env_decrypt": "decripta .env",
"env_decrypt_title": "Decripta il file .env",
"env_decrypt_text": "Inserisci la password per decriptare il file .env",
"env_decrypt_success": ".env decriptato con successo",
"env_delete": "rimuovi .env",
"env_delete_title": "Rimuovi il file .env",
"env_delete_text": "Sei sicuro di voler rimuovere il file .env?",
"env_delete_success": ".env rimosso con successo"
},
"table": {
"yes_remove": "Si, rimuovi",
"cancel": "Annulla",
"remove_service_confirm": "Sei sicuro di voler rimuovere questo intervento?",
"remove_service_confirm_text": "Questa operazione non può essere annullata.",
"service_deleted_successfully": "Intervento rimosso con successo",
@ -174,6 +185,9 @@
"file_too_big": "File troppo grande",
"password_min_length": "La password deve essere di almeno 6 caratteri"
},
"yes_remove": "Si, rimuovi",
"confirm": "Conferma",
"cancel": "Annulla",
"enable": "attiva",
"disable": "disattiva",
"maintenance_mode": "modalità manutenzione",