servnest/fn/ht.php

167 lines
4.5 KiB
PHP
Raw Permalink Normal View History

2023-07-17 21:15:18 +02:00
<?php declare(strict_types=1);
2021-02-16 19:20:19 +01:00
const SUBPATH_REGEX = '^[a-z0-9-]{4,63}$';
const ED25519_PUBKEY_REGEX = '^[a-zA-Z0-9/+]{68}$';
2023-06-20 00:36:58 +02:00
function htSetupUserFs(string $id): void {
2023-03-09 01:35:30 +01:00
// Setup SFTP directory
2023-04-19 14:59:07 +02:00
if (mkdir(CONF['ht']['ht_path'] . '/fs/' . $id, 0000) !== true)
2023-03-09 01:35:30 +01:00
output(500, 'Can\'t create user directory.');
2023-04-19 14:59:07 +02:00
if (chmod(CONF['ht']['ht_path'] . '/fs/' . $id, 0775) !== true)
output(500, 'Can\'t chmod user directory.');
exescape([
CONF['ht']['sudo_path'],
'--',
CONF['ht']['chgrp_path'],
'--no-dereference',
'--',
CONF['ht']['sftpgo_group'],
CONF['ht']['ht_path'] . '/fs/' . $id,
], result_code: $code);
2023-03-09 01:35:30 +01:00
if ($code !== 0)
output(500, 'Can\'t change user directory group.');
// Setup Tor config directory
2023-04-19 14:59:07 +02:00
if (mkdir(CONF['ht']['tor_config_path'] . '/' . $id, 0000) !== true)
2023-03-09 01:35:30 +01:00
output(500, 'Can\'t create Tor config directory.');
2023-04-19 14:59:07 +02:00
if (chmod(CONF['ht']['tor_config_path'] . '/' . $id, 0775) !== true)
output(500, 'Can\'t chmod Tor config directory.');
2023-03-09 01:35:30 +01:00
// Setup Tor keys directory
exescape([
CONF['ht']['sudo_path'],
'-u',
CONF['ht']['tor_user'],
'--',
CONF['ht']['mkdir_path'],
'--mode=0700',
'--',
CONF['ht']['tor_keys_path'] . '/' . $id,
], result_code: $code);
2023-03-09 01:35:30 +01:00
if ($code !== 0)
output(500, 'Can\'t create Tor keys directory.');
}
2023-06-20 00:36:58 +02:00
function checkDomainFormat(string $domain): void {
2022-04-23 01:57:43 +02:00
// If the domain must end without a dot
2023-04-21 19:01:46 +02:00
if (!filter_var($domain, FILTER_VALIDATE_DOMAIN) OR !preg_match('/^(?=^.{1,254}$)([a-z0-9_-]{1,63}\.){1,126}[a-z0-9]{1,63}$/D', $domain))
output(403, _('Domain malformed.'));
2022-09-14 13:49:15 +02:00
}
2023-06-20 00:36:58 +02:00
function formatDomain(string $domain): string {
2022-09-14 13:49:15 +02:00
$domain = rtrim(strtolower($domain), '.');
checkDomainFormat($domain);
return $domain;
2022-04-23 01:57:43 +02:00
}
2023-06-20 00:36:58 +02:00
function listFsDirs(string $username): array {
if ($username === '')
return [];
$absoluteDirs = glob(CONF['ht']['ht_path'] . '/fs/' . $username . '/*/', GLOB_ONLYDIR);
2022-06-11 23:42:48 +02:00
$dirs = [];
2022-06-10 16:42:55 +02:00
foreach ($absoluteDirs as $absoluteDir)
2022-11-28 17:16:30 +01:00
if (preg_match('/^[a-zA-Z0-9_-]{1,64}$/D', basename($absoluteDir)))
2022-06-10 16:42:55 +02:00
array_push($dirs, basename($absoluteDir));
return $dirs;
2021-02-16 19:20:19 +01:00
}
2023-06-20 00:36:58 +02:00
function addSite(string $username, string $siteDir, string $address, string $type): void {
insert('sites', [
'username' => $username,
'site_dir' => $siteDir,
'address' => $address,
'type' => $type,
'creation_date' => date('Y-m-d H:i:s'),
]);
2021-02-16 19:20:19 +01:00
}
2023-06-20 00:36:58 +02:00
function dirsStatuses(string $type): array {
if (isset($_SESSION['id']) !== true)
2022-11-28 17:16:30 +01:00
return [];
2022-06-11 23:42:48 +02:00
$dbDirs = query('select', 'sites', [
'username' => $_SESSION['id'],
'type' => $type,
], ['site_dir']);
2022-06-11 23:42:48 +02:00
$dirs = [];
foreach (listFsDirs($_SESSION['id']) as $fsDir)
2022-06-11 23:42:48 +02:00
$dirs[$fsDir] = in_array($fsDir, $dbDirs);
2022-05-21 02:15:36 +02:00
return $dirs;
}
2023-06-20 00:36:58 +02:00
function htRelativeSymlink(string $target, string $name): void {
chdir(pathinfo($name)['dirname']);
$symlink = symlink($target, pathinfo($name)['basename']);
chdir(ROOT_PATH);
if ($symlink !== true)
output(500, 'Unable to create symlink.');
}
2023-06-20 00:36:58 +02:00
function htDeleteSite(string $address, string $type, string $user_id): void {
if ($type === 'onion') {
$dir = query('select', 'sites', [
'username' => $user_id,
'address' => $address,
'type' => $type,
], ['site_dir'])[0];
// Delete Tor config
if (unlink(CONF['ht']['tor_config_path'] . '/' . $user_id . '/' . $dir) !== true)
output(500, 'Failed to delete Tor configuration.');
// Reload Tor
exescape([
CONF['ht']['sudo_path'],
'--',
...explode(' ', CONF['ht']['tor_reload_cmd']),
], result_code: $code);
if ($code !== 0)
output(500, 'Failed to reload Tor.');
// Delete Tor keys
exescape([
CONF['ht']['sudo_path'],
'-u',
CONF['ht']['tor_user'],
'--',
CONF['ht']['rm_path'],
'-r',
'--',
CONF['ht']['tor_keys_path'] . '/' . $user_id . '/' . $dir,
], result_code: $code);
if ($code !== 0)
output(500, 'Failed to delete Tor keys.');
}
if ($type === 'dns') {
// Delete Let's Encrypt certificate
exescape([
CONF['ht']['sudo_path'],
CONF['ht']['certbot_path'],
2024-01-28 19:21:01 +01:00
'--config',
CONF['ht']['certbot_config_path'],
'delete',
'--quiet',
'--cert-name',
$address,
], result_code: $code);
if ($code !== 0)
output(500, 'Certbot failed to delete the Let\'s Encrypt certificate.');
}
$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' => $user_id,
'type' => $type,
'address' => $address,
]);
}