Use Apache
- Allows customization through .htaccess - No need to configure or reload a server when adding a site - Content negotiation
This commit is contained in:
parent
2d6f2745a6
commit
bd06fc7fbf
50 changed files with 138 additions and 551 deletions
|
@ -101,7 +101,15 @@ Administrator email address published in every SOA record. Ends with a `.`, `@`
|
|||
|
||||
### `ht_path`
|
||||
|
||||
Filesystem path to the users files base directory. Files of a user are located inside `ht_path/<their-internal-user-id>/`
|
||||
Apache can be [chroot](https://httpd.apache.org/docs/current/mod/mod_unixd.html#chrootdir)ed to this directory.
|
||||
|
||||
`<ht_path>/fs/<internal-user-id>/` is the users files base directory.
|
||||
|
||||
`<ht_path>/uri/<address>/` is automatically reachable by Apache (using [mod_vhost_alias](https://httpd.apache.org/docs/current/mod/mod_vhost_alias.html)) and contains relative symlinks to users managed directories.
|
||||
|
||||
### `user_quota_testing`, `user_quota_approved`
|
||||
|
||||
Maximum bytes a user can use on its SFTP space, depending on its account type.
|
||||
|
||||
### `subpath_domain` and `subpath_path`
|
||||
|
||||
|
@ -125,16 +133,6 @@ For the feature of sites in subdomains of a root domain:
|
|||
|
||||
`https://example.<subdomain_domain>/` maps to `<subdomain_path>/example/`
|
||||
|
||||
### `nginx_config_path`
|
||||
|
||||
Filesystem path to the directory that contains configuration files for dedicated sites.
|
||||
|
||||
The `http` block of nginx must contain something like `include <nginx_config_path>/*.conf;`
|
||||
|
||||
### `nginx_reload_cmd`
|
||||
|
||||
Command to execute through sudo to reload the nginx daemon.
|
||||
|
||||
### `tor_config_path`
|
||||
|
||||
Filesystem path to the directory containing Tor configuration for onion accesses. The full Tor configuration file path is `tor_config_path/<internal-user-id>/<site-dir-name>`
|
||||
|
@ -151,6 +149,10 @@ Linux user as who runs the Tor daemon. Some commands are executed as this user t
|
|||
|
||||
Command to execute through sudo to reload the Tor daemon.
|
||||
|
||||
### `onion_internal_host`
|
||||
|
||||
HTTP Onion services listen on port 80 and forward requests to this host.
|
||||
|
||||
### `sudo_path`
|
||||
|
||||
Filesystem path to the sudo binary.
|
||||
|
@ -198,19 +200,3 @@ Domain name that users need to direct their SFTP clients to. May be the same key
|
|||
### `public_sftp_port`
|
||||
|
||||
Network port that users need to direct their SFTP clients to. The common default port is `22`.
|
||||
|
||||
### `https_port`
|
||||
|
||||
Network port where nginx listens. The common default port is `443`.
|
||||
|
||||
### `ipv6_listen_address`, `ipv4_listen_address`
|
||||
|
||||
IP address where nginx listens. May be the same as `ipv6_address` and `ipv4_address`, or `[::]` and `0.0.0.0` to listen on every address available.
|
||||
|
||||
### `http_onion_socket`
|
||||
|
||||
Filesystem path to the unix socket created by nginx and listening for incoming Onion services connections. (Used in Tor and nginx configuration files when creating an Onion service.)
|
||||
|
||||
### `user_quota_testing`, `user_quota_approved`
|
||||
|
||||
Maximum bytes a user can use on its SFTP space, depending on its account type.
|
||||
|
|
|
@ -54,8 +54,11 @@ Upload site's files to the server using SFTP. The way the site is accessed can t
|
|||
[SFTPGo](https://github.com/drakkan/sftpgo)
|
||||
: upload sites files using SFTP
|
||||
|
||||
[Apache HTTP Server](https://httpd.apache.org/)
|
||||
: static HTTP server, with content negotiation and `.htaccess` dynamic configuration
|
||||
|
||||
[nginx](https://nginx.org/)
|
||||
: static HTTP server
|
||||
: HTTP reverse proxy for Apache; terminates TLS and enforces security header
|
||||
|
||||
Tor
|
||||
: [Onion services](https://community.torproject.org/onion-services/)
|
||||
|
|
17
config.ini
17
config.ini
|
@ -30,20 +30,18 @@ public_soa_email = "hostmaster.invalid."
|
|||
|
||||
[ht]
|
||||
ht_path = "/srv/servnest/ht"
|
||||
user_quota_testing = 20971520
|
||||
user_quota_approved = 209715200
|
||||
|
||||
subpath_domain = "ht.servnest.test"
|
||||
subpath_path = "/srv/servnest/subpath"
|
||||
|
||||
subdomain_domain = "ht.servnest.test"
|
||||
subdomain_path = "/srv/servnest/subdomain"
|
||||
|
||||
nginx_config_path = "/srv/servnest/nginx"
|
||||
nginx_reload_cmd = "/usr/bin/systemctl reload nginx"
|
||||
|
||||
tor_config_path = "/srv/servnest/tor-config"
|
||||
tor_keys_path = "/srv/servnest/tor-keys"
|
||||
tor_user = "tor"
|
||||
tor_reload_cmd = "/usr/bin/systemctl reload tor"
|
||||
onion_internal_host = "[::1]:9080"
|
||||
|
||||
sudo_path = "/usr/bin/sudo"
|
||||
certbot_path = "/usr/bin/certbot"
|
||||
|
@ -65,12 +63,3 @@ sftp_fp = "/etc/sftpgo/ed25519.fp"
|
|||
sftp_asciiart = "/etc/sftpgo/ed25519.asciiart"
|
||||
sftp_domain = "sftp.servnest.test"
|
||||
public_sftp_port = 2022
|
||||
|
||||
; Will be used in configuration files
|
||||
https_port = 42443
|
||||
ipv6_listen_address = "::1"
|
||||
ipv4_listen_address = "127.0.0.1"
|
||||
http_onion_socket = "/run/servnest/nginx.sock"
|
||||
|
||||
user_quota_testing = 20971520
|
||||
user_quota_approved = 209715200
|
||||
|
|
|
@ -89,12 +89,12 @@ a:active {
|
|||
text-decoration-thickness: 0.35em;
|
||||
}
|
||||
|
||||
a[rel=help]:before {
|
||||
a[rel~=help]:before {
|
||||
content: 'ℹ️\202F';
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
a[rel=external]:after {
|
||||
a[rel~=external]:after {
|
||||
content: '\202F↗';
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
|
63
fn/ht.php
63
fn/ht.php
|
@ -3,9 +3,9 @@
|
|||
function htSetupUserFs($id) {
|
||||
// Setup SFTP directory
|
||||
umask(0002);
|
||||
if (mkdir(CONF['ht']['ht_path'] . '/' . $id, 0775) !== true)
|
||||
if (mkdir(CONF['ht']['ht_path'] . '/fs/' . $id, 0775) !== true)
|
||||
output(500, 'Can\'t create user directory.');
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['chgrp_path'] . ' ' . CONF['ht']['sftpgo_group'] . ' ' . CONF['ht']['ht_path'] . '/' . $id . ' --no-dereference', result_code: $code);
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['chgrp_path'] . ' ' . CONF['ht']['sftpgo_group'] . ' ' . CONF['ht']['ht_path'] . '/fs/' . $id . ' --no-dereference', result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t change user directory group.');
|
||||
|
||||
|
@ -32,7 +32,7 @@ function formatDomain($domain) {
|
|||
}
|
||||
|
||||
function listFsDirs($username) {
|
||||
$absoluteDirs = glob(CONF['ht']['ht_path'] . '/' . $username . '/*/', GLOB_ONLYDIR);
|
||||
$absoluteDirs = glob(CONF['ht']['ht_path'] . '/fs/' . $username . '/*/', GLOB_ONLYDIR);
|
||||
$dirs = [];
|
||||
foreach ($absoluteDirs as $absoluteDir)
|
||||
if (preg_match('/^[a-zA-Z0-9_-]{1,64}$/D', basename($absoluteDir)))
|
||||
|
@ -63,31 +63,23 @@ function dirsStatuses($type) {
|
|||
return $dirs;
|
||||
}
|
||||
|
||||
function htRelativeSymlink($target, $name) {
|
||||
chdir(pathinfo($name)['dirname']);
|
||||
$symlink = symlink($target, pathinfo($name)['basename']);
|
||||
chdir(ROOT_PATH);
|
||||
if ($symlink !== true)
|
||||
output(500, 'Unable to create symlink.');
|
||||
}
|
||||
|
||||
function htDeleteSite($address, $type) {
|
||||
match ($type) {
|
||||
'onion', 'dns' => htDeleteDedicatedSite($address, $type),
|
||||
'subpath', 'subdomain' => htDeleteSubSite($address, $type)
|
||||
};
|
||||
}
|
||||
|
||||
function htDeleteSubSite($address, $type) {
|
||||
if (unlink(CONF['ht'][$type . '_path'] . '/' . $address) !== true)
|
||||
output(500, 'Unable to delete symlink.');
|
||||
|
||||
query('delete', 'sites', [
|
||||
'username' => $_SESSION['id'],
|
||||
'type' => $type,
|
||||
'address' => $address,
|
||||
]);
|
||||
}
|
||||
|
||||
function htDeleteDedicatedSite($address, $type) {
|
||||
$dir = query('select', 'sites', [
|
||||
'address' => $address,
|
||||
'type' => $type,
|
||||
], 'site_dir')[0];
|
||||
|
||||
if ($type === 'onion') {
|
||||
$dir = query('select', 'sites', [
|
||||
'username' => $_SESSION['id'],
|
||||
'address' => $address,
|
||||
'type' => $type,
|
||||
], 'site_dir')[0];
|
||||
|
||||
// Delete Tor config
|
||||
if (unlink(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id'] . '/' . $dir) !== true)
|
||||
output(500, 'Failed to delete Tor configuration.');
|
||||
|
@ -103,15 +95,6 @@ function htDeleteDedicatedSite($address, $type) {
|
|||
output(500, 'Failed to delete Tor keys.');
|
||||
}
|
||||
|
||||
// Delete Nginx config
|
||||
if (unlink(CONF['ht']['nginx_config_path'] . '/' . $address . '.conf') !== true)
|
||||
output(500, 'Failed to delete Nginx configuration.');
|
||||
|
||||
// Reload Nginx
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['nginx_reload_cmd'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Failed to reload Nginx.');
|
||||
|
||||
if ($type === 'dns') {
|
||||
// Delete Let's Encrypt certificate
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['certbot_path'] . ' delete --quiet --cert-name ' . $address, $output, $code);
|
||||
|
@ -119,10 +102,18 @@ function htDeleteDedicatedSite($address, $type) {
|
|||
output(500, 'Certbot failed to delete the Let\'s Encrypt certificate.');
|
||||
}
|
||||
|
||||
// Delete from database
|
||||
$link = CONF['ht']['ht_path'] . '/uri/' . match ($type) {
|
||||
'onion', 'dns' => $address,
|
||||
'subdomain' => $address . '.' . CONF['ht']['subdomain_domain'],
|
||||
'subpath' => CONF['ht']['subpath_domain'] . '/' . $address,
|
||||
};
|
||||
|
||||
if (unlink($link) !== true)
|
||||
output(500, 'Unable to delete symlink.');
|
||||
|
||||
query('delete', 'sites', [
|
||||
'username' => $_SESSION['id'],
|
||||
'type' => $type,
|
||||
'site_dir' => $dir,
|
||||
'address' => $address,
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Bad request · HTTP 400</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Bad request</h1>
|
||||
<p>
|
||||
The request is malformed.
|
||||
</p>
|
||||
<small>HTTP <code>400</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Access forbidden · HTTP 403</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Access forbidden</h1>
|
||||
<p>
|
||||
The server refused to process the request for security reasons.
|
||||
</p>
|
||||
<small>HTTP <code>403</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>File not found · HTTP 404</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>File not found</h1>
|
||||
<p>
|
||||
The server did not find anything at the requested address.
|
||||
</p>
|
||||
<ul>
|
||||
<li>The file may have been moved or deleted.</li>
|
||||
<li>Perhaps the address was mistyped.</li>
|
||||
</ul>
|
||||
<small>HTTP <code>404</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Fichier introuvable · HTTP 404</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Fichier introuvable</h1>
|
||||
<p>
|
||||
Le serveur n'a rien trouvé à l'adresse demandée.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Le fichier a pu être déplacé ou supprimé.</li>
|
||||
<li>L'adresse a peut-être été mal saisie.</li>
|
||||
</ul>
|
||||
<small>HTTP <code>404</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +0,0 @@
|
|||
<?php
|
||||
|
||||
require 'lib.php';
|
||||
|
||||
echo file_get_contents('404.' . $locale . '.html');
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Method Not Allowed · HTTP 405</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Method Not Allowed</h1>
|
||||
<p>
|
||||
The request method is not supported for this resource.
|
||||
</p>
|
||||
<small>HTTP <code>405</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Gone · HTTP 410</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Gone</h1>
|
||||
<p>
|
||||
The requested resource is not available anymore.
|
||||
</p>
|
||||
<small>HTTP <code>410</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>I'm a teapot · HTTP 418</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>I'm a teapot</h1>
|
||||
<p>
|
||||
Your coffee cannot be brewed because this server is a teapot.
|
||||
</p>
|
||||
<small>HTTP <code>418</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Server error · HTTP 500</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Server error</h1>
|
||||
<p>
|
||||
The server encountered an error and is unable to satisfy your request.
|
||||
</p>
|
||||
<ul>
|
||||
<li>This error is probably temporary.</li>
|
||||
<li>If it isn't, you can try to contact an administrator.</li>
|
||||
</ul>
|
||||
<small>HTTP <code>500</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Erreur du serveur · HTTP 500</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Erreur du serveur</h1>
|
||||
<p>
|
||||
Le serveur a rencontré une erreur et ne peut pas répondre à cette requête.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Cette erreur est probablement temporaire.</li>
|
||||
<li>Si ce n'est pas le cas, vous pouvez contacter ane administrataire.</li>
|
||||
</ul>
|
||||
<small>HTTP <code>500</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +0,0 @@
|
|||
<?php
|
||||
|
||||
require 'lib.php';
|
||||
|
||||
echo file_get_contents('500.' . $locale . '.html');
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Bad gateway · HTTP 502</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Bad gateway</h1>
|
||||
<p>
|
||||
The backend server encountered an error and is unable to satisfy your request.
|
||||
</p>
|
||||
<ul>
|
||||
<li>This error is probably temporary.</li>
|
||||
<li>If it isn't, you can try to contact an administrator.</li>
|
||||
</ul>
|
||||
<small>HTTP <code>502</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Service unavailable · HTTP 503</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Service unavailable</h1>
|
||||
<p>
|
||||
The server cannot handle the request, because it is overloaded or down for maintenance.
|
||||
</p>
|
||||
<ul>
|
||||
<li>This error is probably temporary.</li>
|
||||
<li>If it isn't, you can try to contact an administrator.</li>
|
||||
</ul>
|
||||
<small>HTTP <code>503</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Service indisponible · HTTP 503</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Service indisponible</h1>
|
||||
<p>
|
||||
Le serveur ne peut pas répondre à cette requête, car il est surchargé ou en cours de maintenance.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Cette erreur est probablement temporaire.</li>
|
||||
<li>Si ce n'est pas le cas, vous pouvez contacter ane administrataire.</li>
|
||||
</ul>
|
||||
<small>HTTP <code>503</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +0,0 @@
|
|||
<?php
|
||||
|
||||
require 'lib.php';
|
||||
|
||||
echo file_get_contents('503.' . $locale . '.html');
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Gateway timeout · HTTP 504</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Gateway timeout</h1>
|
||||
<p>
|
||||
The backend server did not send a timely response.
|
||||
</p>
|
||||
<ul>
|
||||
<li>This error is probably temporary.</li>
|
||||
<li>If it isn't, you can try to contact an administrator.</li>
|
||||
</ul>
|
||||
<small>HTTP <code>504</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Broken site</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Broken site</h1>
|
||||
<p>
|
||||
The site you're trying to reach is misconfigured. This domain seems to be pointing to this server, but this server is not aware of a site using this domain.
|
||||
</p>
|
||||
<small>HTTP <code>404</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,15 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Nothing here</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Nothing here</h1>
|
||||
<p>
|
||||
You reached the default site of this server directly using its IP address. There's nothing for you here.
|
||||
</p>
|
||||
<small>HTTP <code>404</code></small>
|
||||
</body>
|
||||
</html>
|
|
@ -1,8 +0,0 @@
|
|||
<?php
|
||||
|
||||
http_response_code(404);
|
||||
|
||||
if (filter_var(str_replace(['[', ']'], '', $_SERVER['HTTP_HOST']), FILTER_VALIDATE_IP))
|
||||
echo file_get_contents('default-ip.html');
|
||||
else
|
||||
echo file_get_contents('default-domain.html');
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
$locale = 'en';
|
||||
foreach (explode(',', preg_replace('/[A-Z0-9]|q=|;|-|\./', '', $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '')) as $client_locale) {
|
||||
if (in_array($client_locale, ['en', 'fr'], true)) {
|
||||
$locale = $client_locale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
header('Content-Language: ' . $locale);
|
|
@ -1,23 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>TLS required</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TLS required</h1>
|
||||
<p>
|
||||
This site does not accept HTTP requests without TLS.
|
||||
</p>
|
||||
<h2>What happened?</h2>
|
||||
<p>
|
||||
You made a request using HTTP without TLS to the server, which refused this for privacy and security reasons, as unsecure HTTP connections can be watched and modified by any device on the way.
|
||||
</p>
|
||||
<h2>How to solve this?</h2>
|
||||
<p>
|
||||
You can replace the URI scheme <code>http</code> by <code>https</code> to tell your client to make the request using TLS.
|
||||
</p>
|
||||
<code>HTTP 403</code>
|
||||
</body>
|
||||
</html>
|
|
@ -1,23 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Nécessite TLS</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Nécessite TLS</h1>
|
||||
<p>
|
||||
Ce site n'accepte pas les connexions HTTP sans TLS.
|
||||
</p>
|
||||
<h2>Que s'est-il passé ?</h2>
|
||||
<p>
|
||||
Vous avez envoyé une requête HTTP sans TLS au serveur, qui l'a refusée pour des raisons de sécurité et de confidentialité.
|
||||
</p>
|
||||
<h2>Comment régler ce problème ?</h2>
|
||||
<p>
|
||||
Vous pouvez remplacer le schéma d'URI <code>http</code> par <code>https</code> pour indiquer à votre client de faire la requête avec TLS.
|
||||
</p>
|
||||
<code>HTTP 403</code>
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
http_response_code(403);
|
||||
|
||||
require 'lib.php';
|
||||
|
||||
require 'unsecure.' . $locale . '.html';
|
|
@ -1,7 +1,5 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-25 16:16+0100\n"
|
||||
"Language: fr\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
|
@ -410,13 +408,13 @@ msgstr "Ce domaine doit avoir %2$s pour unique enregistrement %1$s."
|
|||
msgid "No TXT record with the expected format has been found."
|
||||
msgstr "Aucun enregistrement TXT avec le format attendu n'a été trouvé."
|
||||
|
||||
#: pg-act/ht/add-dns.php:59 pg-act/ht/add-onion.php:47
|
||||
#: pg-act/ht/add-dns.php:41 pg-act/ht/add-onion.php:31
|
||||
#: pg-act/ht/add-subdomain.php:19 pg-act/ht/add-subpath.php:19
|
||||
#, php-format
|
||||
msgid "%s added on this directory."
|
||||
msgstr "%s ajouté sur ce dossier."
|
||||
|
||||
#: pg-act/ht/add-onion.php:47
|
||||
#: pg-act/ht/add-onion.php:31
|
||||
#, php-format
|
||||
msgid "Its address is: %s"
|
||||
msgstr "Son adresse est : %s"
|
||||
|
@ -771,28 +769,12 @@ msgid "A content security policy (CSP) forbids Web browsers from loading JavaScr
|
|||
msgstr "Une politique de sécurité du contenu (CSP) interdit l'intégration de ressources tierces ou de JavaScript."
|
||||
|
||||
#: pg-view/ht/index.php:114
|
||||
msgid "gzip compression"
|
||||
msgstr "Compression gzip"
|
||||
msgid "<code>.htaccess</code> configuration"
|
||||
msgstr "Configuration par <code>.htaccess</code>"
|
||||
|
||||
#: pg-view/ht/index.php:116
|
||||
msgid "Static <em>gzip</em> compression is supported: if the client supports it and the file is available, <code>path.gz</code> is served instead of <code>path</code>."
|
||||
msgstr "La compression <em>gzip</em> statique est supportée : si le client le supporte et que le fichier est disponible, <code>chemin.gz</code> est servi au lieu de <code>chemin</code>."
|
||||
|
||||
#: pg-view/ht/index.php:119
|
||||
msgid "Index page"
|
||||
msgstr "Page d'index"
|
||||
|
||||
#: pg-view/ht/index.php:121
|
||||
msgid "When a request hits a directory, the first of the following files that exists <em>inside this directory</em> is served:"
|
||||
msgstr "Lors d'une requête sur un dossier, le premier des fichiers suivants qui existe <em>dans ce dossier</em> est répondu :"
|
||||
|
||||
#: pg-view/ht/index.php:129
|
||||
msgid "404 error page"
|
||||
msgstr "Page d'erreur 404"
|
||||
|
||||
#: pg-view/ht/index.php:131
|
||||
msgid "When a request ends in a <code>404</code> error, the first of the following files that exists <em>at the root of the site</em> is served:"
|
||||
msgstr "Lors d'une requête aboutissant à une erreur <code>404</code>, le premier des fichiers suivants qui existe <em>à la racine du site</em> est répondu :"
|
||||
msgid "You can change the way the HTTP server answers to requests in a directory by setting some directives in a file named <code>.htaccess</code> at the root of this directory. Only the following directives are allowed:"
|
||||
msgstr "Vous pouvez modifier la façon dont le serveur HTTP répond aux requêtes dans un dossier en indiquant des directives dans un fichier nommé <code>.htaccess</code> à la racine de ce dossier. Seules les directives suivantes sont autorisées :"
|
||||
|
||||
#: pg-view/ns/caa.php:3
|
||||
msgid "Flag"
|
||||
|
|
|
@ -407,13 +407,13 @@ msgstr ""
|
|||
msgid "No TXT record with the expected format has been found."
|
||||
msgstr ""
|
||||
|
||||
#: pg-act/ht/add-dns.php:59 pg-act/ht/add-onion.php:47
|
||||
#: pg-act/ht/add-dns.php:41 pg-act/ht/add-onion.php:31
|
||||
#: pg-act/ht/add-subdomain.php:19 pg-act/ht/add-subpath.php:19
|
||||
#, php-format
|
||||
msgid "%s added on this directory."
|
||||
msgstr ""
|
||||
|
||||
#: pg-act/ht/add-onion.php:47
|
||||
#: pg-act/ht/add-onion.php:31
|
||||
#, php-format
|
||||
msgid "Its address is: %s"
|
||||
msgstr ""
|
||||
|
@ -768,27 +768,11 @@ msgid "A content security policy (CSP) forbids Web browsers from loading JavaScr
|
|||
msgstr ""
|
||||
|
||||
#: pg-view/ht/index.php:114
|
||||
msgid "gzip compression"
|
||||
msgid "<code>.htaccess</code> configuration"
|
||||
msgstr ""
|
||||
|
||||
#: pg-view/ht/index.php:116
|
||||
msgid "Static <em>gzip</em> compression is supported: if the client supports it and the file is available, <code>path.gz</code> is served instead of <code>path</code>."
|
||||
msgstr ""
|
||||
|
||||
#: pg-view/ht/index.php:119
|
||||
msgid "Index page"
|
||||
msgstr ""
|
||||
|
||||
#: pg-view/ht/index.php:121
|
||||
msgid "When a request hits a directory, the first of the following files that exists <em>inside this directory</em> is served:"
|
||||
msgstr ""
|
||||
|
||||
#: pg-view/ht/index.php:129
|
||||
msgid "404 error page"
|
||||
msgstr ""
|
||||
|
||||
#: pg-view/ht/index.php:131
|
||||
msgid "When a request ends in a <code>404</code> error, the first of the following files that exists <em>at the root of the site</em> is served:"
|
||||
msgid "You can change the way the HTTP server answers to requests in a directory by setting some directives in a file named <code>.htaccess</code> at the root of this directory. Only the following directives are allowed:"
|
||||
msgstr ""
|
||||
|
||||
#: pg-view/ns/caa.php:3
|
||||
|
|
|
@ -30,7 +30,7 @@ if (in_array('ht', $user_services, true)) {
|
|||
|
||||
removeDirectory(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id']);
|
||||
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['sftpgo_user'] . ' ' . CONF['ht']['rm_path'] . ' --recursive ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'], result_code: $code);
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['sftpgo_user'] . ' ' . CONF['ht']['rm_path'] . ' --recursive ' . CONF['ht']['ht_path'] . '/fs/' . $_SESSION['id'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t remove user\'s directory.');
|
||||
}
|
||||
|
|
|
@ -6,23 +6,23 @@ if (dirsStatuses('dns')[$_POST['dir']] !== false)
|
|||
output(403, 'Wrong value for <code>dir</code>.');
|
||||
|
||||
if (query('select', 'sites', ['domain' => $_POST['domain']], 'domain') !== [])
|
||||
output(403, _('This domain already exists on this service. Use another one.');
|
||||
output(403, _('This domain already exists on this service. Use another one.'));
|
||||
|
||||
$remoteAaaaRecords = dns_get_record($_POST['domain'], DNS_AAAA);
|
||||
if (is_array($remoteAaaaRecords) !== true)
|
||||
output(500, sprintf(_('Can\'t retrieve the %s record.'), 'AAAA');
|
||||
output(500, sprintf(_('Can\'t retrieve the %s record.'), 'AAAA'));
|
||||
if (equalArrays([CONF['ht']['ipv6_address']], array_column($remoteAaaaRecords, 'ipv6')) !== true)
|
||||
output(403, sprintf(_('This domain must have %2$s as its only %1$s record.'), 'AAAA', '<code>' . CONF['ht']['ipv6_address'] . '</code>'));
|
||||
|
||||
$remoteARecords = dns_get_record($_POST['domain'], DNS_A);
|
||||
if (is_array($remoteARecords) !== true)
|
||||
output(500, sprintf(_('Can\'t retrieve the %s record.'), 'A');
|
||||
output(500, sprintf(_('Can\'t retrieve the %s record.'), 'A'));
|
||||
if (equalArrays([CONF['ht']['ipv4_address']], array_column($remoteARecords, 'ip')) !== true)
|
||||
output(403, sprintf(_('This domain must have %2$s as its only %1$s record.'), 'A', '<code>' . CONF['ht']['ipv4_address'] . '</code>'));
|
||||
|
||||
$remoteTXTRecords = dns_get_record($_POST['domain'], DNS_TXT);
|
||||
if (is_array($remoteTXTRecords) !== true)
|
||||
output(500, sprintf(_('Can\'t retrieve the %s record.'), 'TXT');
|
||||
output(500, sprintf(_('Can\'t retrieve the %s record.'), 'TXT'));
|
||||
if (preg_match('/^' . preg_quote(SERVER_NAME, '/') . '_domain-verification=([0-9a-f]{8})-([0-9a-f]{32})$/Dm', implode(LF, array_column($remoteTXTRecords, 'txt')), $matches) !== 1)
|
||||
output(403, _('No TXT record with the expected format has been found.'));
|
||||
|
||||
|
@ -36,24 +36,6 @@ exec('2>&1 ' . CONF['ht']['sudo_path'] . ' ' . CONF['ht']['certbot_path'] . ' ce
|
|||
if ($returnCode !== 0)
|
||||
output(500, 'Certbot failed to get a Let\'s Encrypt certificate.', $output);
|
||||
|
||||
$nginxConf = 'server {
|
||||
listen [' . CONF['ht']['ipv6_listen_address'] . ']:' . CONF['ht']['https_port'] . ' ssl http2;
|
||||
listen ' . CONF['ht']['ipv4_listen_address'] . ':' . CONF['ht']['https_port'] . ' ssl http2;
|
||||
server_name ' . $_POST['domain'] . ';
|
||||
root ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . ';
|
||||
htRelativeSymlink('../fs/' . $_SESSION['id'] . '/' . $_POST['dir'], CONF['ht']['ht_path'] . '/uri/' . $_POST['domain']);
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/' . $_POST['domain'] . '/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/' . $_POST['domain'] . '/privkey.pem;
|
||||
|
||||
include inc/ht-tls.conf;
|
||||
}
|
||||
';
|
||||
if (file_put_contents(CONF['ht']['nginx_config_path'] . '/' . $_POST['domain'] . '.conf', $nginxConf) === false)
|
||||
output(500, 'Failed to write Nginx configuration.');
|
||||
|
||||
// Reload Nginx
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['nginx_reload_cmd'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Failed to reload Nginx.');
|
||||
|
||||
output(200, sprintf(_('%s added on this directory.'), PAGE_METADATA['title']);
|
||||
output(200, sprintf(_('%s added on this directory.'), PAGE_METADATA['title']));
|
||||
|
|
|
@ -7,8 +7,7 @@ rateLimit();
|
|||
|
||||
// Add Tor config
|
||||
$torConf = 'HiddenServiceDir ' . CONF['ht']['tor_keys_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . '/
|
||||
HiddenServicePort 80 unix:' . CONF['ht']['http_onion_socket'] . '
|
||||
';
|
||||
HiddenServicePort 80 ' . CONF['ht']['onion_internal_host'] . LF;
|
||||
if (file_put_contents(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'], $torConf) === false)
|
||||
output(500, 'Failed to write new Tor configuration.');
|
||||
|
||||
|
@ -26,22 +25,7 @@ if (preg_match('/^[0-9a-z]{56}\.onion$/D', $onion) !== 1)
|
|||
// Store it in the database
|
||||
addSite($_SESSION['id'], $_POST['dir'], $onion, 'onion');
|
||||
|
||||
// Add Nginx config
|
||||
$nginxConf = 'server {
|
||||
listen unix:' . CONF['ht']['http_onion_socket'] . ';
|
||||
server_name ' . $onion . ';
|
||||
root ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . ';
|
||||
|
||||
include inc/ht-onion.conf;
|
||||
}
|
||||
';
|
||||
if (file_put_contents(CONF['ht']['nginx_config_path'] . '/' . $onion . '.conf', $nginxConf) === false)
|
||||
output(500, 'Failed to write Nginx configuration.');
|
||||
|
||||
// Reload Nginx
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['nginx_reload_cmd'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Failed to reload Nginx.');
|
||||
htRelativeSymlink('../fs/' . $_SESSION['id'] . '/' . $_POST['dir'], CONF['ht']['ht_path'] . '/uri/' . $onion);
|
||||
|
||||
// Tell the user their site address
|
||||
output(200, sprintf(_('%s added on this directory.'), PAGE_METADATA['title']) . ' ' . sprintf(_('Its address is: %s'), '<a href="http://' . $onion . '/"><code>http://' . $onion . '/</code></a>'));
|
||||
|
|
|
@ -13,7 +13,7 @@ rateLimit();
|
|||
|
||||
addSite($_SESSION['id'], $_POST['dir'], $_POST['subdomain'], 'subdomain');
|
||||
|
||||
if (symlink(CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'], CONF['ht']['subdomain_path'] . '/' . $_POST['subdomain']) !== true)
|
||||
if (symlink('../../fs/' . $_SESSION['id'] . '/' . $_POST['dir'], CONF['ht']['ht_path'] . '/uri/' . $_POST['subdomain'] . '.' . CONF['ht']['subdomain_domain']) !== true)
|
||||
output(500, 'Unable to create symlink.');
|
||||
|
||||
output(200, sprintf(_('%s added on this directory.'), PAGE_METADATA['title']));
|
||||
|
|
|
@ -13,7 +13,7 @@ rateLimit();
|
|||
|
||||
addSite($_SESSION['id'], $_POST['dir'], $_POST['path'], 'subpath');
|
||||
|
||||
if (symlink(CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'], CONF['ht']['subpath_path'] . '/' . $_POST['path']) !== true)
|
||||
if (symlink('../../fs/' . $_SESSION['id'] . '/' . $_POST['dir'], CONF['ht']['ht_path'] . '/uri/' . CONF['ht']['subpath_domain'] . '/' . $_POST['path']) !== true)
|
||||
output(500, 'Unable to create symlink.');
|
||||
|
||||
output(200, sprintf(_('%s added on this directory.'), PAGE_METADATA['title']));
|
||||
|
|
|
@ -111,28 +111,57 @@ $quota = ($_SESSION['type'] ?? '' === 'approved') ? CONF['ht']['user_quota_appro
|
|||
<?= _('A content security policy (CSP) forbids Web browsers from loading JavaScript or third-party resources.') ?>
|
||||
</p>
|
||||
|
||||
<h3><?= _('gzip compression') ?></h3>
|
||||
<h3><?= _('<code>.htaccess</code> configuration') ?></h3>
|
||||
<p>
|
||||
<?= _('Static <em>gzip</em> compression is supported: if the client supports it and the file is available, <code>path.gz</code> is served instead of <code>path</code>.') ?>
|
||||
<?= _('You can change the way the HTTP server answers to requests in a directory by setting some directives in a file named <code>.htaccess</code> at the root of this directory. Only the following directives are allowed:') ?>
|
||||
</p>
|
||||
<ul>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/core.html#files"><code><Files></code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/core.html#filesmatch"><code><FilesMatch></code></a></li>
|
||||
|
||||
<h3><?= _('Index page') ?></h3>
|
||||
<p>
|
||||
<?= _('When a request hits a directory, the first of the following files that exists <em>inside this directory</em> is served:') ?>
|
||||
</p>
|
||||
<ol>
|
||||
<li><code>index.html</code></li>
|
||||
<li><code>index.md</code></li>
|
||||
<li><code>index.gmi</code></li>
|
||||
</ol>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_alias.html#redirect"><code>Redirect</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_alias.html#redirectmatch"><code>RedirectMatch</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_alias.html#redirectpermanent"><code>RedirectPermanent</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_alias.html#redirecttemp"><code>RedirectTemp</code></a></li>
|
||||
|
||||
<h3><?= _('404 error page') ?></h3>
|
||||
<p>
|
||||
<?= _('When a request ends in a <code>404</code> error, the first of the following files that exists <em>at the root of the site</em> is served:') ?>
|
||||
</p>
|
||||
<ol>
|
||||
<li><code>404.html</code></li>
|
||||
<li><code>404.md</code></li>
|
||||
<li><code>404.gmi</code></li>
|
||||
</ol>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/core.html#errordocument"><code>ErrorDocument</code></a></li>
|
||||
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_mime.html#addtype"><code>AddType</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/core.html#forcetype"><code>ForceType</code></a></li>
|
||||
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_mime.html#defaultlanguage"><code>DefaultLanguage</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_mime.html#addanguage"><code>AddLanguage</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_negotiation.html#languagepriority"><code>LanguagePriority</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_negotiation.html#forcelanguagepriority"><code>ForceLanguagePriority</code></a></li>
|
||||
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_dir.html#directoryindex"><code>DirectoryIndex</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_dir.html#directoryslash"><code>DirectorySlash</code></a></li>
|
||||
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_mime.html#removetype"><code>RemoveType</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_mime.html#removeoutputfilter"><code>RemoveOutputFilter</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_mime.html#removelanguage"><code>RemoveLanguage</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_mime.html#removeencoding"><code>RemoveEncoding</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_mime.html#removecharset"><code>RemoveCharset</code></a></li>
|
||||
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_expires.html#expiresactive"><code>ExpiresActive</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_expires.html#expiresdefault"><code>ExpiresDefault</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_expires.html#expiresbytype"><code>ExpiresByType</code></a></li>
|
||||
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#defaulticon"><code>DefaultIcon</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#adddescription"><code>AddDescription</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#addalt"><code>AddAlt</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#addaltbyencoding"><code>AddAltByEncoding</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#addaltbytype"><code>AddAltByType</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#addicon"><code>AddIcon</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#addiconbyencoding"><code>AddIconByEncoding</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#addiconbytype"><code>AddIconByType</code></a></li>
|
||||
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexignore"><code>IndexIgnore</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexignorereset"><code>IndexIgnoreReset</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexoptions"><code>IndexOptions</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexorderdefault"><code>IndexOrderDefault</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#headername"><code>HeaderName</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#readmename"><code>ReadmeName</code></a></li>
|
||||
<li><a rel="external help" href="https://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexstylesheet"><code>IndexStyleSheet</code></a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
<label for="flag"><?= _('Flag') ?></label>
|
||||
<br>
|
||||
<input id="flag" min="0" max="127" placeholder="0" name="flag" type="number">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
<label for="cname"><?= _('Canonical name') ?></label>
|
||||
<br>
|
||||
<input id="cname" placeholder="main.<?= PLACEHOLDER_DOMAIN ?>" name="cname" type="text">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
<label for="dname"><?= _('Delegation name') ?></label>
|
||||
<br>
|
||||
<input id="dname" placeholder="main.<?= PLACEHOLDER_DOMAIN ?>" name="dname" type="text">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
<label for="ip"><?= _('IP address') ?></label><br>
|
||||
<input required="" pattern="^[a-f0-9:.]+$" id="ip" name="ip" minlength="2" maxlength="39" size="40" type="text" placeholder="<?= PLACEHOLDER_IPV6 ?> ou <?= PLACEHOLDER_IPV4 ?>"><br>
|
||||
<input type="submit" value="<?= _('Apply') ?>">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
<fieldset>
|
||||
<legend><?= _('Latitude') ?></legend>
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
<label for="priority"><?= _('Priority') ?></label>
|
||||
<br>
|
||||
<input id="priority" min="0" max="65535" value="0" placeholder="0" name="priority" type="number">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
<label for="ns"><?= _('Name server') ?></label>
|
||||
<br>
|
||||
<input id="ns" placeholder="ns1.<?= PLACEHOLDER_DOMAIN ?>" name="ns" type="text">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
|
||||
<label for="priority"><?= _('Priority') ?></label>
|
||||
<br>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
|
||||
<label for="algo"><?= _('Algorithm') ?></label>
|
||||
<br>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
|
||||
<label for="use"><?= _('Use') ?></label>
|
||||
<br>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form method="post">
|
||||
<?php require 'form.ns.php'; ?>
|
||||
<?php require ROOT_PATH . '/pg-view/ns/form.ns.php'; ?>
|
||||
<label for="txt"><?= _('Text') ?></label>
|
||||
<br>
|
||||
<input id="txt" minlenght="5" maxlength="8192" pattern="^[a-zA-Z0-9 .@=:!%$+/\()[\]_-]{5,8192}$" placeholder="<?= _('Some text…') ?>" name="txt" type="text">
|
||||
|
|
10
router.php
10
router.php
|
@ -10,7 +10,7 @@ date_default_timezone_set('UTC');
|
|||
|
||||
$locale = 'en';
|
||||
foreach (explode(',', preg_replace('/[A-Z0-9]|q=|;|-|\./', '', $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '')) as $client_locale) {
|
||||
if (in_array($client_locale, array_diff(scandir('locales'), ['..', '.']), true)) {
|
||||
if (in_array($client_locale, array_diff(scandir(ROOT_PATH . '/locales'), ['..', '.']), true)) {
|
||||
$locale = $client_locale;
|
||||
break;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ const PLACEHOLDER_IPV4 = '203.0.113.42'; // From RFC5737: IPv4 Address Blocks Re
|
|||
foreach (array_diff(scandir(ROOT_PATH . '/fn'), ['..', '.']) as $file)
|
||||
require ROOT_PATH . '/fn/' . $file;
|
||||
|
||||
require 'pages.php';
|
||||
require ROOT_PATH . '/pages.php';
|
||||
|
||||
if ($_SERVER['REQUEST_URI'] === '/sftpgo-auth.php')
|
||||
return;
|
||||
|
@ -150,12 +150,12 @@ if ($_POST !== []) {
|
|||
output(403, _('This account doesn\'t exist anymore. Log out to end this ghost session.'));
|
||||
}
|
||||
|
||||
if (file_exists('pg-act/' . PAGE_ADDRESS . '.php'))
|
||||
require 'pg-act/' . PAGE_ADDRESS . '.php';
|
||||
if (file_exists(ROOT_PATH . '/pg-act/' . PAGE_ADDRESS . '.php'))
|
||||
require ROOT_PATH . '/pg-act/' . PAGE_ADDRESS . '.php';
|
||||
}
|
||||
|
||||
function displayPage($data) {
|
||||
require 'view.php';
|
||||
require ROOT_PATH . '/view.php';
|
||||
exit();
|
||||
}
|
||||
displayPage($data ??= NULL);
|
||||
|
|
|
@ -10,7 +10,7 @@ function deny() {
|
|||
if (CONF['common']['services']['ht'] !== 'enabled')
|
||||
deny();
|
||||
|
||||
$auth_data = json_decode(file_get_contents('php://input'), true);
|
||||
$auth_data = json_decode(file_get_contents('php://input'), true, flags: JSON_THROW_ON_ERROR);
|
||||
|
||||
$username = hashUsername($auth_data['username']);
|
||||
|
||||
|
@ -29,7 +29,7 @@ echo '
|
|||
{
|
||||
"status": 1,
|
||||
"username": ' . json_encode($auth_data['username']) . ',
|
||||
"home_dir": "' . CONF['ht']['ht_path'] . '/' . $id . '",
|
||||
"home_dir": "' . CONF['ht']['ht_path'] . '/fs/' . $id . '",
|
||||
"quota_size": ' . ((query('select', 'users', ['id' => $id], 'type')[0] === 'approved') ? CONF['ht']['user_quota_approved'] : CONF['ht']['user_quota_testing']) . ',
|
||||
"permissions": {
|
||||
"/": [
|
||||
|
|
2
view.php
2
view.php
|
@ -38,7 +38,7 @@
|
|||
if (in_array(SERVICE, SERVICES_USER, true) AND CONF['common']['services'][SERVICE] === 'error')
|
||||
echo '<p><strong>' . _('This service is currently under maintenance. No action can be taken on it until an administrator finishes repairing it.') . '</strong></p>';
|
||||
|
||||
require 'pg-view/' . PAGE_ADDRESS . '.php';
|
||||
require ROOT_PATH . '/pg-view/' . PAGE_ADDRESS . '.php';
|
||||
|
||||
if ($_POST === [] AND PAGE_METADATA['require-login'] ?? true !== false AND !isset($_SESSION['id']) AND PAGE_TERMINAL)
|
||||
echo '<p>' . sprintf(_('This form won\'t be accepted because you need to %slog in%s first.'), '<a class="auth" href="' . redirUrl('auth/login') . '">', '</a>') . '</p>';
|
||||
|
|
Loading…
Reference in a new issue