summaryrefslogtreecommitdiffstats
path: root/modules-available/webinterface/inc/webinterface.inc.php
blob: 276110ebc961706593602081f8b2625623b3634f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<?php

class WebInterface
{
	public const PROP_TYPE = 'webinterface.https-type';
	public const PROP_HSTS = 'webinterface.https-hsts';
	public const PROP_REDIRECT = 'webinterface.https-redirect';
	public const PROP_CURRENT_CERT_DOMAINS = 'webinterface.https-domains';

	public const PROP_REDIRECT_DOMAIN = 'webinterface.redirect-domain';

	public const PROP_API_KEY = 'webinterface.api-key';

	/**
	 * Read data all handled domains from current certificate.
	 * SAN takes precedence, if empty, we fall back to CN.
	 * @param string[] $certDomains
	 * @return bool success reading?
	 */
	public static function extractCurrentCertData(array &$certDomains, int &$expireTimestamp, string &$issuer): bool
	{
		if (!is_readable('/etc/lighttpd/pub-cert.pem'))
		return false;
		$cert = openssl_x509_parse(file_get_contents('/etc/lighttpd/pub-cert.pem'));
		if ($cert === false)
			return false;
		// Domains
		$certDomains = [];
		if (isset($cert['extensions']['subjectAltName'])) {
			$doms = preg_split('/[,\s]+/', $cert['extensions']['subjectAltName'], -1, PREG_SPLIT_NO_EMPTY);
			foreach ($doms as $d) {
				if (substr_compare($d, 'DNS:', 0, 4, true) !== 0)
					continue;
				$d = substr($d, 4);
				if (preg_match('/^([a-z0-9_-]|\*\.)[a-z0-9_.-]+$/', $d) && !in_array($d, $certDomains)) {
					$certDomains[] = $d;
				}
			}
		}
		if (empty($certDomains) && isset($cert['subject']['CN'])
				&& preg_match('/^([a-z0-9_-]|\*\.)[a-z0-9_.-]+$/', $cert['subject']['CN'])) {
			$certDomains[] = $cert['subject']['CN'];
		}
		foreach ($certDomains as &$d) {
			if ($d[-1] === '.') {
				$d = substr($d, 0, -1);
			}
		}
		Property::set(self::PROP_CURRENT_CERT_DOMAINS, implode(' ', $certDomains));
		// Expire time
		$expireTimestamp = $cert['validTo_time_t'] ?? 0;
		// Issuer
		$issuer = $cert['issuer']['CN'] ?? 'Unknown';
		return true;
	}

	public static function setDomainRedirect(bool $enable): void
	{
		Property::set(self::PROP_REDIRECT_DOMAIN, $enable ? '1' : false);
	}

	public static function getDomainRedirect(): bool
	{
		return !empty(Property::get(self::PROP_REDIRECT_DOMAIN, false));
	}

	public static function isHttpsRedirectEnabled(): bool
	{
		return Property::get(self::PROP_REDIRECT) === 'True';
	}

	public static function tmDisableHttps(): ?string
	{
		Property::set(WebInterface::PROP_TYPE, 'off');
		Property::set(WebInterface::PROP_HSTS, 'off');
		$task = Taskmanager::submit('LighttpdHttps', []);
		return $task['id'] ?? null;
	}

	public static function tmGenerateRandomCert(): ?string
	{
		Property::set(WebInterface::PROP_TYPE, 'generated');
		$task = Taskmanager::submit('LighttpdHttps', [
			'proxyip' => Property::getServerIp(),
			'redirect' => self::isHttpsRedirectEnabled(),
		]);
		return $task['id'] ?? null;
	}

	public static function tmImportCustomCert(string $key, string $cert, ?string $chain = null): ?string
	{
		Property::set(WebInterface::PROP_TYPE, 'supplied');
		$task = Taskmanager::submit('LighttpdHttps', [
			'importcert' => $cert,
			'importkey' => $key,
			'importchain' => $chain,
			'redirect' => self::isHttpsRedirectEnabled(),
		]);
		return $task['id'] ?? null;
	}

	public static function tmSetHttpRedirectMode(): ?string
	{
		if (Property::get(WebInterface::PROP_TYPE) === 'off')
			return null;
		$task = Taskmanager::submit('LighttpdHttps', array(
			'redirectOnly' => true,
			'redirect' => self::isHttpsRedirectEnabled(),
		));
		return $task['id'] ?? null;
	}

}