123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- <?php declare(strict_types=1);
- const SUBPATH_REGEX = '^[a-z0-9-]{4,63}$';
- const ED25519_PUBKEY_REGEX = '^[a-zA-Z0-9/+]{68}$';
- function htSetupUserFs(string $id): void {
- // Setup SFTP directory
- if (mkdir(CONF['ht']['ht_path'] . '/fs/' . $id, 0000) !== true)
- output(500, 'Can\'t create user directory.');
- 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);
- if ($code !== 0)
- output(500, 'Can\'t change user directory group.');
- // Setup Tor config directory
- if (mkdir(CONF['ht']['tor_config_path'] . '/' . $id, 0000) !== true)
- output(500, 'Can\'t create Tor config directory.');
- if (chmod(CONF['ht']['tor_config_path'] . '/' . $id, 0775) !== true)
- output(500, 'Can\'t chmod Tor config directory.');
- // 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);
- if ($code !== 0)
- output(500, 'Can\'t create Tor keys directory.');
- }
- function checkDomainFormat(string $domain): void {
- // If the domain must end without a dot
- 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.'));
- }
- function formatDomain(string $domain): string {
- $domain = rtrim(strtolower($domain), '.');
- checkDomainFormat($domain);
- return $domain;
- }
- function listFsDirs(string $username): array {
- if ($username === '')
- return [];
- $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)))
- array_push($dirs, basename($absoluteDir));
- return $dirs;
- }
- 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'),
- ]);
- }
- function dirsStatuses(string $type): array {
- if (isset($_SESSION['id']) !== true)
- return [];
- $dbDirs = query('select', 'sites', [
- 'username' => $_SESSION['id'],
- 'type' => $type,
- ], ['site_dir']);
- $dirs = [];
- foreach (listFsDirs($_SESSION['id']) as $fsDir)
- $dirs[$fsDir] = in_array($fsDir, $dbDirs);
- return $dirs;
- }
- 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.');
- }
- function reloadTor() { // Using Tor control protocol <https://spec.torproject.org/control-spec/>
- $sock = stream_socket_client('unix://' . CONF['ht']['tor_control_socket']);
- if ($sock === false)
- output(500, 'Failed to connect to Tor control socket.', [$out]);
- fwrite($sock, 'AUTHENTICATE' . CRLF);
- if (($out = fgets($sock)) !== '250 OK' . CRLF)
- output(500, 'Failed to authenticate to Tor control socket.', [$out]);
- fwrite($sock, 'SIGNAL RELOAD' . CRLF);
- if (($out = fgets($sock)) !== '250 OK' . CRLF)
- output(500, 'Failed to reload Tor.', [$out]);
- fwrite($sock, 'QUIT' . CRLF);
- if (($out = fgets($sock)) !== '250 closing connection' . CRLF)
- output(500, 'Failed to close connection to Tor control socket.', [$out]);
- fclose($sock);
- }
- 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
- reloadTor();
- // 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'],
- '--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,
- ]);
- }
|