Skip to content

Commit ed3f110

Browse files
committed
Fix config file missing test cases
1 parent ec36ee2 commit ed3f110

9 files changed

Lines changed: 758 additions & 6 deletions

File tree

package-lock.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"crypto-random-string": "^5.0.0",
2929
"date-fns": "^2.30.0",
3030
"extract-zip": "^2.0.1",
31+
"ini": "^5.0.0",
3132
"inquirer": "^9.2.10",
3233
"ms": "^2.1.3",
3334
"mysql2": "^3.12.0",
@@ -41,6 +42,7 @@
4142
"devDependencies": {
4243
"@trivago/prettier-plugin-sort-imports": "^5.2.1",
4344
"@types/archiver": "^5.3.2",
45+
"@types/ini": "^4.1.1",
4446
"@types/inquirer": "^9.0.3",
4547
"@types/node": "^20.5.1",
4648
"@types/psl": "^1.1.0",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default class PHPIdentifyMalformatError extends Error {}

src/service/installation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export default class InstallationService {
8080
createPHPErrorLogFile(phpVer, identity);
8181

8282
// setup nginx
83-
const virtualHostConfig = getNginxVirtualHostConfig(domain, identity);
83+
const virtualHostConfig = getNginxVirtualHostConfig(phpVer, domain, identity);
8484
fs.writeFileSync(unixpath.nginx.host, virtualHostConfig);
8585

8686
// finish directory with permission

src/template/nginx-virtual-host.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,6 @@ server {
201201

202202
location ~ \.php$ {
203203
include snippets/fastcgi-php.conf;
204-
fastcgi_pass unix:/var/run/php/php8.1-fpm-{{alt_host}}.sock;
204+
fastcgi_pass unix:/var/run/php/php{{phpVer}}-fpm-{{alt_host}}.sock;
205205
}
206206
}

src/util/config.spec.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
import { path as appRootPath } from 'app-root-path';
22
import fs from 'fs';
3+
import { parse } from 'ini';
34
import path from 'path';
45
import { describe, expect, test } from 'vitest';
56

6-
import { getWpConfig, getWpConfigByPath, setupInitialWpConfig } from './config';
7+
import {
8+
getNginxVirtualHostConfig,
9+
getWpConfig,
10+
getWpConfigByPath,
11+
setupInitialPHPConfig,
12+
setupInitialWpConfig,
13+
} from './config';
14+
15+
import PHPIdentifyMalformatError from '@/error/PHPIdentifyMalformatError';
716

817
describe('getWpConfigByPath()', () => {
918
test('should call getWpConfig()', () => {
@@ -62,3 +71,46 @@ describe('setupInitialWpConfig()', () => {
6271
expect(newWpConfig).equal(wpConfig);
6372
});
6473
});
74+
75+
describe('setupInitialPHPConfig()', () => {
76+
test('should throw malformat error', () => {
77+
const phpWWWConfigSample = fs.readFileSync(
78+
path.join(appRootPath, 'test/php/8.1/fpm/pool.d/www.conf'),
79+
'utf8'
80+
);
81+
const siteIdentify = 'my.site';
82+
const phpVer = '8.1';
83+
expect(() => setupInitialPHPConfig(phpWWWConfigSample, phpVer, siteIdentify)).toThrowError(
84+
PHPIdentifyMalformatError
85+
);
86+
});
87+
test('should inject correct parameters', () => {
88+
const phpWWWConfigSample = fs.readFileSync(
89+
path.join(appRootPath, 'test/php/8.1/fpm/pool.d/www.conf'),
90+
'utf8'
91+
);
92+
const siteIdentify = 'my_site';
93+
const phpVer = '8.1';
94+
const newConfig = setupInitialPHPConfig(phpWWWConfigSample, phpVer, siteIdentify);
95+
const ini = parse(newConfig);
96+
expect(ini.www).not.toBeDefined();
97+
expect(ini.my_site).toBeDefined();
98+
expect(ini.my_site.user).toBe(siteIdentify);
99+
expect(ini.my_site.group).toBe(siteIdentify);
100+
expect(ini.my_site.listen).toBe(`/run/php/php${phpVer}-fpm-$pool.sock`);
101+
expect(ini.my_site.slowlog).toBe(`/var/log/php${phpVer}-fpm-$pool.log.slow`);
102+
expect(ini.my_site['php_admin_value[error_log]']).toBe(
103+
`/var/log/php${phpVer}-fpm-$pool.log.error`
104+
);
105+
expect(ini.my_site['php_admin_flag[log_errors]']).toBe('on');
106+
});
107+
});
108+
109+
describe('getNginxVirtualHostConfig()', () => {
110+
test('should inject correct parameters', () => {
111+
const phpVer = '8.1';
112+
const nginxConfig = fs.readFileSync(path.join(appRootPath, 'test/nginx/my.site.conf'), 'utf8');
113+
const newConfig = getNginxVirtualHostConfig(phpVer, 'my.site', 'my_site');
114+
expect(newConfig).equal(nginxConfig);
115+
});
116+
});

src/util/config.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import { path as appRootPath } from 'app-root-path';
12
import fs from 'fs';
3+
import path from 'path';
24
import { Engine } from 'php-parser';
35

46
import { getWpConfigPath } from './path';
57

8+
import PHPIdentifyMalformatError from '@/error/PHPIdentifyMalformatError';
9+
610
export function getWpConfigByPath(wpInstalledPath: string, options?: any) {
711
const fileContent = fs.readFileSync(getWpConfigPath(wpInstalledPath), 'utf8');
812
return getWpConfig(fileContent, options);
@@ -56,6 +60,9 @@ export function setupInitialWpConfig(
5660
}
5761

5862
export function setupInitialPHPConfig(fileContent: string, phpVer: string, siteIdentify: string) {
63+
if (!/^[a-z0-9_]+$/i.test(siteIdentify)) {
64+
throw new PHPIdentifyMalformatError('site identify only allow a-z, A-Z, 0-9 and underscore.');
65+
}
5966
return fileContent
6067
.replace('[www]', `[${siteIdentify}]`)
6168
.replace('user = www-data', `user = ${siteIdentify}`)
@@ -72,7 +79,12 @@ export function setupInitialPHPConfig(fileContent: string, phpVer: string, siteI
7279
.replace(';php_admin_flag[log_errors] = on', 'php_admin_flag[log_errors] = on');
7380
}
7481

75-
export function getNginxVirtualHostConfig(host: string, altHost: string) {
76-
const config = fs.readFileSync('../template/nginx-virtual-host.conf', { encoding: 'utf8' });
77-
return config.replace(/{{host}}/g, host).replace(/{{alt_host}}/g, altHost);
82+
export function getNginxVirtualHostConfig(phpVer: string, host: string, altHost: string) {
83+
const config = fs.readFileSync(path.join(appRootPath, 'src/template/nginx-virtual-host.conf'), {
84+
encoding: 'utf8',
85+
});
86+
return config
87+
.replace(/{{phpVer}}/g, phpVer)
88+
.replace(/{{host}}/g, host)
89+
.replace(/{{alt_host}}/g, altHost);
7890
}

test/nginx/my.site.conf

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
2+
server {
3+
listen 80;
4+
listen [::]:80;
5+
6+
server_name my.site www.my.site;
7+
8+
return 301 https://$host$request_uri;
9+
}
10+
11+
server {
12+
listen 443 http2 ssl;
13+
listen [::]:443 http2 ssl;
14+
15+
root /var/www/my.site;
16+
17+
index index.html index.htm index.php;
18+
19+
server_name my.site www.my.site;
20+
21+
client_max_body_size 500M;
22+
23+
ssl_certificate /etc/nginx/ssl/my.site.pem;
24+
ssl_certificate_key /etc/nginx/ssl/my.site.key;
25+
26+
error_log /var/log/nginx/my.site_error.log;
27+
access_log /var/log/nginx/my.site_access.log;
28+
29+
#Deny access to wp-content folders for suspicious files
30+
location ~* ^/(wp-content)/(.*?)\.(zip|gz|tar|bzip2|7z)$ {
31+
deny all;
32+
}
33+
34+
location ~ ^/wp-content/uploads/sucuri {
35+
deny all;
36+
}
37+
38+
location ~ ^/wp-content/updraft {
39+
deny all;
40+
}
41+
42+
#Disable execution of scripts other than PHP from your document root
43+
location ~* .(pl|cgi|py|sh|lua|asp)$ {
44+
return 404;
45+
}
46+
47+
#Disable access to your configuration files and other files that you don’t want to users are able to see
48+
location ~* /(wp-config.php|readme.html|license.txt|nginx.conf) {
49+
deny all;
50+
}
51+
52+
# Disable wp-config.txt
53+
location = /wp-config.txt {
54+
deny all;
55+
access_log off;
56+
log_not_found off;
57+
}
58+
59+
# nginx block xmlrpc.php requests
60+
location = /xmlrpc.php {
61+
deny all;
62+
access_log off;
63+
log_not_found off;
64+
return 404;
65+
}
66+
67+
# nginx block wpscann on plugins folder
68+
location ~* ^/wp-content/(?:plugins|themes)/.+\.(txt|log|md)$ {
69+
deny all;
70+
error_page 403 =404 / ;
71+
}
72+
73+
# block access to install.php and upgrade.php
74+
location ^~ /wp-admin/(install.php|upgrade.php) {
75+
deny all;
76+
error_page 403 =404 / ;
77+
}
78+
79+
#This module will allow us to pattern match certain key files and inject random text in the files that
80+
# is non-destructive / non-invasive and will most importantly alter the md5sum calculated on such files. All transparent to WPScan.
81+
location ~* ^/(license.txt|wp-includes/(.*)/.+\.(js|css)|wp-admin/(.*)/.+\.(js|css))$ {
82+
sub_filter_types text/css text/javascript text/plain;
83+
sub_filter_once on;
84+
sub_filter ';' '; /* $msec */ ';
85+
}
86+
87+
#Direct PHP File Access
88+
#If somehow, a hacker successfully sneaks in a PHP file onto your site,
89+
#they’ll be able to run this file by loading file which effectively becomes a backdoor to infiltrate your site.
90+
#We should disable direct access to any PHP files by adding the following rules:
91+
location ~* /(?:uploads|files|wp-content|wp-includes|akismet)/.*.php$ {
92+
deny all;
93+
access_log off;
94+
log_not_found off;
95+
}
96+
97+
#Dotfiles
98+
#Similar to PHP file, a dotfile like .htaccess, .user.ini, and .git may contain sensitive information.
99+
#To be on the safer side, it’s better to disable direct access to these files.
100+
location ~ /\.(svn|git)/* {
101+
deny all;
102+
access_log off;
103+
log_not_found off;
104+
}
105+
106+
location ~ /\.ht {
107+
deny all;
108+
access_log off;
109+
log_not_found off;
110+
}
111+
112+
location ~ /\.user.ini {
113+
deny all;
114+
access_log off;
115+
log_not_found off;
116+
}
117+
118+
# Deny backup extensions & log files
119+
location ~* ^.+\.(bak|log|old|orig|original|php#|php~|php_bak|save|swo|swp|sql)$ {
120+
deny all;
121+
access_log off;
122+
log_not_found off;
123+
}
124+
125+
# common nginx configuration to block sql injection and other attacks
126+
location ~* "(eval\()" {
127+
deny all;
128+
}
129+
130+
location ~* "(127\.0\.0\.1)" {
131+
deny all;
132+
}
133+
134+
location ~* "([a-z0-9]{2000})" {
135+
deny all;
136+
}
137+
138+
location ~* "(javascript\:)(.*)(\;)" {
139+
deny all;
140+
}
141+
142+
location ~* "(base64_encode)(.*)(\()" {
143+
deny all;
144+
}
145+
146+
location ~* "(GLOBALS|REQUEST)(=|\[|%)" {
147+
deny all;
148+
}
149+
150+
location ~* "(<|%3C).*script.*(>|%3)" {
151+
deny all;
152+
}
153+
154+
location ~ "(\|\.\.\.|\.\./|~|\`|<|>|\|)" {
155+
deny all;
156+
}
157+
158+
location ~* "(boot\.ini|etc/passwd|self/environ)" {
159+
deny all;
160+
}
161+
162+
location ~* "(thumbs?(_editor|open)?|tim(thumb)?)\.php" {
163+
deny all;
164+
}
165+
166+
location ~* "(\'|\")(.*)(drop|insert|md5|select|union)" {
167+
deny all;
168+
}
169+
170+
location ~* "(https?|ftp|php):/" {
171+
deny all;
172+
}
173+
174+
location ~* "(=\\'|=\%27|/\\'/?)\." {
175+
deny all;
176+
}
177+
178+
location ~ "(\{0\}|\(/\(|\.\.\.|\+\+\+|\"\")" {
179+
deny all;
180+
}
181+
182+
location ~ "(~|\`|<|>|:|;|%|\|\s|\{|\}|\[|\]|\|)" {
183+
deny all;
184+
}
185+
186+
location ~* "/(=|$&|_mm|(wp-)?config\.|cgi-|etc/passwd|muieblack)" {
187+
deny all;
188+
}
189+
190+
location ~* "(&pws=0|_vti_|\(null\)|\{$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)" {
191+
deny all;
192+
}
193+
194+
location ~* "/(^$|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell|config|settings|configuration)\.php" {
195+
deny all;
196+
}
197+
198+
location / {
199+
try_files $uri $uri/ /index.php?$args;
200+
}
201+
202+
location ~ \.php$ {
203+
include snippets/fastcgi-php.conf;
204+
fastcgi_pass unix:/var/run/php/php8.1-fpm-my_site.sock;
205+
}
206+
}

0 commit comments

Comments
 (0)