Skip to content

Commit 6fee98a

Browse files
committed
2 parents f92d1b5 + 13ed08d commit 6fee98a

4 files changed

Lines changed: 330 additions & 3 deletions

File tree

modules/aggiornamenti/actions.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Modules\Aggiornamenti\Controlli\ColonneDuplicateViste;
2626
use Modules\Aggiornamenti\Controlli\Controllo;
2727
use Modules\Aggiornamenti\Controlli\DatiFattureElettroniche;
28+
use Modules\Aggiornamenti\Controlli\FileHtaccess;
2829
use Modules\Aggiornamenti\Controlli\IntegritaFile;
2930
use Modules\Aggiornamenti\Controlli\PianoConti;
3031
use Modules\Aggiornamenti\Controlli\PianoContiRagioneSociale;
@@ -174,6 +175,7 @@
174175
PluginDuplicati::class,
175176
TabelleLanguage::class,
176177
IntegritaFile::class,
178+
FileHtaccess::class,
177179
];
178180

179181
$results = [];
@@ -264,6 +266,7 @@
264266
PluginDuplicati::class,
265267
TabelleLanguage::class,
266268
IntegritaFile::class,
269+
FileHtaccess::class,
267270
];
268271

269272
$results = [];

modules/aggiornamenti/controlli.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,8 @@ function hasGlobalActions(controllo) {
11161116
"Modules\\\\Aggiornamenti\\\\Controlli\\\\ColonneDuplicateViste",
11171117
"Modules\\\\Aggiornamenti\\\\Controlli\\\\PluginDuplicati",
11181118
"Modules\\\\Aggiornamenti\\\\Controlli\\\\TabelleLanguage",
1119-
"Modules\\\\Aggiornamenti\\\\Controlli\\\\IntegritaFile"
1119+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\IntegritaFile",
1120+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\FileHtaccess"
11201121
];
11211122
11221123
return controlliConAzioniGlobali.includes(controllo["class"]);
@@ -1202,6 +1203,16 @@ function getMessaggioConferma(controlloClass) {
12021203
"'.tr('Libererà spazio su disco e pulirà il database da riferimenti non validi').'",
12031204
"'.tr('Non può essere annullata').'"
12041205
]
1206+
},
1207+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\FileHtaccess": {
1208+
titolo: "'.tr('Conferma rigenerazione file .htaccess').'",
1209+
descrizione: "'.tr('Sei sicuro di voler rigenerare tutti i file .htaccess mancanti?').'",
1210+
operazioni: [
1211+
"'.tr('Creerà i file .htaccess mancanti nelle cartelle di sistema').'",
1212+
"'.tr('I file .htaccess proteggono le cartelle sensibili da accessi non autorizzati').'",
1213+
"'.tr('Verranno utilizzati i contenuti standard per ciascuna cartella').'",
1214+
"'.tr('I file esistenti non verranno sovrascritti').'"
1215+
]
12051216
}
12061217
};
12071218
@@ -1225,7 +1236,8 @@ function eseguiAzioneGlobale(buttonElement) {
12251236
"Modules\\\\Aggiornamenti\\\\Controlli\\\\PianoConti",
12261237
"Modules\\\\Aggiornamenti\\\\Controlli\\\\PianoContiRagioneSociale",
12271238
"Modules\\\\Aggiornamenti\\\\Controlli\\\\ReaValidi",
1228-
"Modules\\\\Aggiornamenti\\\\Controlli\\\\TabelleLanguage"
1239+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\TabelleLanguage",
1240+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\FileHtaccess"
12291241
];
12301242
12311243
let isInfo = controlliInfo.includes(controlloClass);
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
<?php
2+
3+
/*
4+
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
5+
* Copyright (C) DevCode s.r.l.
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
namespace Modules\Aggiornamenti\Controlli;
22+
23+
/**
24+
* Controllo per verificare la presenza dei file .htaccess critici nelle cartelle di sistema.
25+
*/
26+
class FileHtaccess extends Controllo
27+
{
28+
/**
29+
* Definizione delle cartelle che richiedono un file .htaccess e il relativo contenuto.
30+
*/
31+
protected static $htaccess_config = [
32+
'' => [
33+
'description' => 'File di configurazione principale Apache per la sicurezza del gestionale',
34+
'content' => null, // Contenuto generato dinamicamente
35+
],
36+
'files' => [
37+
'description' => 'Cartella per i file allegati degli utenti',
38+
'content' => "# Disable directory listing\nOptions -Indexes\n\n# Disable PHP rendering\n<IfModule mod_php5.c>\n php_flag engine off\n</IfModule>\n<IfModule mod_php7.c>\n php_flag engine off\n</IfModule>\n",
39+
],
40+
'logs' => [
41+
'description' => 'Cartella per i file di log',
42+
'content' => "Deny from all\n",
43+
],
44+
'backup' => [
45+
'description' => 'Cartella per i backup',
46+
'content' => "Deny from all\n",
47+
],
48+
'update' => [
49+
'description' => 'Cartella per gli aggiornamenti',
50+
'content' => "Deny from all\n",
51+
],
52+
'locale' => [
53+
'description' => 'Cartella per le traduzioni',
54+
'content' => "Deny from all\n",
55+
],
56+
];
57+
58+
/**
59+
* Contenuto del file .htaccess principale (root).
60+
*/
61+
protected static function getRootHtaccessContent()
62+
{
63+
return <<<'HTACCESS'
64+
# Remove autoindex
65+
<IfModule mod_autoindex.c>
66+
IndexIgnore */*
67+
</IfModule>
68+
69+
# Deny access to files starting with a dot (e.g. .htaccess, .git)
70+
<FilesMatch "^\.">
71+
Require all denied
72+
</FilesMatch>
73+
74+
# Deny access to certain file types like log, sql, htaccess, etc.
75+
<FilesMatch "\.(ini|psd|log|sh|sql|md|lock|phar)$">
76+
Require all denied
77+
</FilesMatch>
78+
79+
# Deny access to VERSION, REVISION, LICENSE, and config files
80+
<Files ~ "(VERSION$|REVISION$|LICENSE|(config.inc|config.example).php|(composer|package).json|gulpfile.js)">
81+
Require all denied
82+
</Files>
83+
84+
# Disable indexing of php, html, htm, pdf files
85+
ServerSignature Off
86+
<IfModule mod_headers.c>
87+
Header set X-Robots-Tag: "noindex,nofollow"
88+
Header set X-Content-Type-Options nosniff
89+
</IfModule>
90+
91+
<IfModule mod_rewrite.c>
92+
RewriteEngine On
93+
94+
# Tell PHP that the mod_rewrite module is ENABLED.
95+
<IfModule mod_env.c>
96+
SetEnv HTTP_MOD_REWRITE On
97+
</IfModule>
98+
99+
# Deny access to protected folders
100+
RewriteRule ^backup/ - [F,L]
101+
RewriteRule ^docs/ - [F,L]
102+
RewriteRule ^include/ - [F,L]
103+
RewriteRule ^locale/ - [F,L]
104+
RewriteRule ^logs/ - [F,L]
105+
RewriteRule ^update/ - [F,L]
106+
107+
# Deny access to svn, git, node_modules and vendor folders
108+
RewriteRule ^.git/ - [F,L]
109+
RewriteRule ^.svn/ - [F,L]
110+
RewriteRule ^node_modules/ - [F,L]
111+
RewriteRule ^vendor/ - [F,L]
112+
113+
# Disable HTTP TRACE
114+
RewriteCond %{REQUEST_METHOD} ^TRACE
115+
RewriteRule .* - [F]
116+
117+
# Prevent hacks
118+
# proc/self/environ? no way!
119+
RewriteCond %{QUERY_STRING} proc/self/environ [OR]
120+
121+
# Block out any script trying to set a mosConfig value through the URL
122+
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
123+
124+
# Block out any script trying to base64_encode crap to send via URL
125+
RewriteCond %{QUERY_STRING} base64_encode.*(.*) [OR]
126+
127+
# Block out any script that includes a <script> tag in URL
128+
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
129+
130+
# Block out any script trying to set a PHP GLOBALS variable via URL
131+
RewriteCond %{QUERY_STRING} GLOBALS(=|[|\%[0-9A-Z]{0,2}) [OR]
132+
133+
# Block out any script trying to modify a _REQUEST variable via URL
134+
RewriteCond %{QUERY_STRING} _REQUEST(=|[|\%[0-9A-Z]{0,2})
135+
136+
# Set an environment variable for bad bots using user-agent patterns
137+
SetEnvIfNoCase User-Agent ".*(craftbot|download|extract|stripper|sucker|ninja|clshttp|webspider|leacher|collector|grabber|webpictures).*" HTTP_SAFE_BADBOT
138+
SetEnvIfNoCase User-Agent ".*(libwww-perl|aesop_com_spiderman).*" HTTP_SAFE_BADBOT
139+
140+
# Deny access to requests from this environment variable
141+
<RequireAll>
142+
Require all granted
143+
Require not env HTTP_SAFE_BADBOT
144+
</RequireAll>
145+
</ifModule>
146+
147+
# Compress text, html, javascript, css, ecc...
148+
<IfModule mod_gzip.c>
149+
mod_gzip_on Yes
150+
mod_gzip_dechunk Yes
151+
mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
152+
mod_gzip_item_include handler ^cgi-script$
153+
mod_gzip_item_include mime ^text/.*
154+
mod_gzip_item_include mime ^application/x-javascript.*
155+
mod_gzip_item_exclude mime ^image/.*
156+
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
157+
</IfModule>
158+
159+
<IfModule mod_mime.c>
160+
AddType text/javascript mjs
161+
</IfModule>
162+
HTACCESS;
163+
}
164+
165+
public function getName()
166+
{
167+
return tr('File .htaccess di sistema');
168+
}
169+
170+
public function getType($record)
171+
{
172+
return 'warning';
173+
}
174+
175+
public function getOptions($record)
176+
{
177+
return [
178+
[
179+
'name' => tr('Rigenera file'),
180+
'icon' => 'fa fa-refresh',
181+
'color' => 'success',
182+
'params' => ['action' => 'regenerate'],
183+
],
184+
];
185+
}
186+
187+
public function hasGlobalActions()
188+
{
189+
return true;
190+
}
191+
192+
public function getGlobalActions()
193+
{
194+
$missing_count = count($this->results);
195+
if ($missing_count === 0) {
196+
return [];
197+
}
198+
199+
return [
200+
[
201+
'name' => tr('Rigenera tutti i file mancanti'),
202+
'icon' => 'fa fa-refresh',
203+
'color' => 'success',
204+
'params' => ['action' => 'regenerate_all'],
205+
'badge' => $missing_count.' '.tr('file'),
206+
],
207+
];
208+
}
209+
210+
public function check()
211+
{
212+
foreach (self::$htaccess_config as $folder => $config) {
213+
// Gestione speciale per la directory root
214+
if ($folder === '') {
215+
$folder_path = base_dir();
216+
$htaccess_path = $folder_path.'/.htaccess';
217+
$display_path = '.htaccess';
218+
$display_folder = tr('directory principale');
219+
} else {
220+
$folder_path = base_dir().'/'.$folder;
221+
$htaccess_path = $folder_path.'/.htaccess';
222+
$display_path = $folder.'/.htaccess';
223+
$display_folder = '<code>'.$folder.'</code>';
224+
225+
// Verifica se la cartella esiste (solo per sottocartelle)
226+
if (!is_dir($folder_path)) {
227+
continue;
228+
}
229+
}
230+
231+
// Verifica se il file .htaccess esiste
232+
if (!file_exists($htaccess_path)) {
233+
$this->addResult([
234+
'id' => 'htaccess_'.($folder === '' ? 'root' : $folder),
235+
'folder' => $folder,
236+
'nome' => '<strong>.htaccess</strong><br><small class="text-muted">'.$display_path.'</small>',
237+
'descrizione' => tr('File .htaccess mancante nella _FOLDER_', ['_FOLDER_' => $display_folder]).'<br><small class="text-muted">'.$config['description'].'</small>',
238+
]);
239+
}
240+
}
241+
}
242+
243+
public function execute($record, $params = [])
244+
{
245+
$action = $params['action'] ?? '';
246+
247+
if ($action === 'regenerate') {
248+
return $this->regenerateHtaccess($record['folder']);
249+
}
250+
251+
return tr('Azione non supportata');
252+
}
253+
254+
/**
255+
* Rigenera tutti i file .htaccess mancanti.
256+
*/
257+
public function solveGlobal($params = [])
258+
{
259+
$action = $params['action'] ?? '';
260+
$results = [];
261+
262+
if ($action === 'regenerate_all') {
263+
foreach ($this->results as $record) {
264+
$results[$record['id']] = $this->regenerateHtaccess($record['folder']);
265+
}
266+
}
267+
268+
return $results;
269+
}
270+
271+
/**
272+
* Rigenera il file .htaccess per una cartella specifica.
273+
*/
274+
protected function regenerateHtaccess($folder)
275+
{
276+
if (!isset(self::$htaccess_config[$folder])) {
277+
return tr('Configurazione non trovata per la cartella _FOLDER_', ['_FOLDER_' => $folder]);
278+
}
279+
280+
// Gestione speciale per la directory root
281+
if ($folder === '') {
282+
$folder_path = base_dir();
283+
$display_folder = tr('directory principale');
284+
} else {
285+
$folder_path = base_dir().'/'.$folder;
286+
$display_folder = $folder;
287+
288+
// Crea la cartella se non esiste (solo per sottocartelle)
289+
if (!is_dir($folder_path)) {
290+
if (!mkdir($folder_path, 0755, true)) {
291+
return tr('Impossibile creare la cartella _FOLDER_', ['_FOLDER_' => $folder]);
292+
}
293+
}
294+
}
295+
296+
$htaccess_path = $folder_path.'/.htaccess';
297+
298+
// Ottieni il contenuto appropriato
299+
$content = self::$htaccess_config[$folder]['content'];
300+
if ($content === null && $folder === '') {
301+
$content = self::getRootHtaccessContent();
302+
}
303+
304+
// Scrivi il contenuto del file .htaccess
305+
if (file_put_contents($htaccess_path, $content) === false) {
306+
return tr('Impossibile creare il file .htaccess nella _FOLDER_', ['_FOLDER_' => $display_folder]);
307+
}
308+
309+
return tr('File .htaccess rigenerato con successo nella _FOLDER_', ['_FOLDER_' => $display_folder]);
310+
}
311+
}
312+

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,5 @@
104104
"fix-openapi-js": "node -e \"require('fs').writeFileSync('assets/api/src/main.js', \\\"import * as API from './index';global.window.API = API;\\\");\"",
105105
"update-openapi-client": "npm run-script export-openapi && npx @openapitools/openapi-generator-cli generate -i openapi.json -g javascript -o assets/api --skip-validate-spec && npm run-script fix-openapi-js && npm install --no-save ./assets/api && cd ./assets/api && npx babel src -d dist && cd ../.. && npx browserify ./assets/api/dist/main.js -o ./assets/dist/js/api.js"
106106
},
107-
"packageManager": "yarn@4.6.0"
107+
"packageManager": "yarn@4.12.0"
108108
}

0 commit comments

Comments
 (0)