Compare commits

..

17 Commits

Author SHA1 Message Date
c362aa1283 Remove superfluous checks for empty realnames 2022-03-31 14:38:02 +02:00
65aaea4097 Check links for using an accepted scheme during validation (http, https,
ftp)
2022-03-30 13:03:04 +02:00
7c02bbb8ad Fix function comment for setting content-security-policies 2022-03-29 17:51:21 +02:00
6a7b8bd8fd Disable setting language cookie for curl or clients without user agents 2022-03-26 16:49:10 +01:00
8d7b270f6f Allow setting worker-src in MD_STD_SEC 2022-03-24 23:25:05 +01:00
9507387c8a Fix bug in validating ISBN 13s 2022-03-11 23:31:41 +01:00
589161219f Require numbers OR special chars for passwords, not AND 2022-03-09 00:16:55 +01:00
e18b649250 Return array of error messages on password validate 2022-03-08 21:23:45 +01:00
5bb863ffc9 Add function validate_password 2022-03-08 20:12:54 +01:00
1b63951b44 Enable TCP Fast-Open for outgoing curl requests 2022-02-12 23:06:53 +01:00
93991225fe Use curl_setopt_array and enable http2 for speeding up CURL requests 2022-02-12 22:51:42 +01:00
321609306d Use strip tags in sanitize_text over deprecated FILTER_SANITIZE_STRING 2022-02-02 02:18:33 +01:00
2a333c1de6 Simplify MD_STD::startsWithAny 2022-01-16 15:19:40 +01:00
c689f7568f Allow empty input haystacks in MD_STD::stri_contains() 2022-01-09 22:20:05 +01:00
dc86540da2 Explicitly expect positive ints for depths in MD_STD::json_encode 2022-01-08 01:09:57 +01:00
e50f1f0526 Remove superfluous parentheses 2021-12-24 02:01:53 +01:00
e2ada291f7 Fix bug in splitting int arrays, add function for splitting string
arrays
2021-12-14 03:16:11 +01:00
4 changed files with 95 additions and 32 deletions

View File

@ -44,7 +44,7 @@ final class MD_STD {
public static function realpath(string $path):string {
$output = \realpath($path);
if (!\is_string($output) || empty($output)) {
if (!\is_string($output)) {
throw new MDFileDoesNotExist("The file {$path} does not exist or is not readable.");
}
return $output;
@ -163,21 +163,19 @@ final class MD_STD {
*/
public static function startsWithAny(string $haystack, array $needles):bool {
$output = false;
foreach ($needles as $needle) {
$output = \str_starts_with($haystack, $needle);
if ($output == true) {
return $output;
if (\str_starts_with($haystack, $needle) === true) {
return true;
}
}
return $output;
return false;
}
/**
* Function checking if a string contains another in a case-insensitive way.
*
* @param non-empty-string $haystack String to check.
* @param string $haystack String to check.
* @param non-empty-string $needle Potential start of $haystack.
*
* @return boolean
@ -234,7 +232,7 @@ final class MD_STD {
*
* @param array<mixed> $value The value being encoded. Can be any type except a resource.
* @param integer $options Bitmask consisting of JSON_FORCE_OBJECT, JSON_HEX_QUOT ...
* @param integer $depth Depth of coding.
* @param positive-int $depth Depth of coding.
*
* @return string
*/
@ -253,9 +251,9 @@ final class MD_STD {
*
* @see https://www.php.net/manual/en/function.json-encode.php
*
* @param object $value The value being encoded. Can be any type except a resource.
* @param integer $options Bitmask consisting of JSON_FORCE_OBJECT, JSON_HEX_QUOT ...
* @param integer $depth Depth of coding.
* @param object $value The value being encoded. Can be any type except a resource.
* @param integer $options Bitmask consisting of JSON_FORCE_OBJECT, JSON_HEX_QUOT ...
* @param positive-int $depth Depth of coding.
*
* @return string
*/
@ -298,14 +296,18 @@ final class MD_STD {
$curl = \curl_init();
\curl_setopt($curl, CURLOPT_URL, $url);
\curl_setopt($curl, CURLOPT_HEADER, false);
\curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, $timeout); //timeout in seconds
\curl_setopt($curl, CURLOPT_TIMEOUT_MS, $timeout); //timeout in seconds
\curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
// \curl_setopt($curl, CURLOPT_COOKIESESSION, true);
\curl_setopt($curl, CURLOPT_AUTOREFERER, true);
\curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2');
\curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_HEADER => false,
CURLOPT_CONNECTTIMEOUT_MS => $timeout, //timeout in seconds
CURLOPT_TIMEOUT_MS => $timeout, //timeout in seconds
CURLOPT_FOLLOWLOCATION => true,
// CURLOPT_COOKIESESSION => true,
CURLOPT_AUTOREFERER => true,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2',
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
CURLOPT_TCP_FASTOPEN => true,
]);
/*
if (!file_exists(__DIR__ . '/../../curled.txt')) {
@ -426,6 +428,12 @@ final class MD_STD {
}
else {
$lang = self::lang_getfrombrowser($allowed_langs, $default_lang, "", false);
// If the user is a bot or has no user agent at all or one of curl's,
// setting a cookie usually makes little sense.
// On the other hand, setting the cookie prevents effective caching.
if (empty($_SERVER['HTTP_USER_AGENT']) || substr($_SERVER['HTTP_USER_AGENT'], 0, 5) === 'curl/') return $lang;
if (!setcookie('__Host-lang', $lang, $cookie_options)) {
throw new Exception("Failed to set language");
}
@ -773,7 +781,7 @@ final class MD_STD {
* @param array<int, int> $input Input array.
* @param positive-int $size Size of each part of the return set.
*
* @return array<non-empty-array<integer>>
* @return array<non-empty-array<int, integer>>
*/
public static function split_int_array_into_sized_parts(array $input, int $size):array {
@ -788,7 +796,36 @@ final class MD_STD {
while ($offset < $max) {
$cur = array_slice($input, $offset, $size - 1);
if (!empty($cur)) $output[] = $cur;
$offset += $size;
$offset += $size - 1;
}
return $output;
}
/**
* Splits an lists of strings into parts of a predefined size and returns those
* as sub-lists of a superordinate list.
*
* @param array<int, string> $input Input array.
* @param positive-int $size Size of each part of the return set.
*
* @return array<non-empty-array<int, string>>
*/
public static function split_string_array_into_sized_parts(array $input, int $size):array {
/*
if ($size < 1) throw new Exception("Size of the target array must be a positive integer");
*/
$output = [];
$max = count($input);
$offset = 0;
while ($offset < $max) {
$cur = array_slice($input, $offset, $size - 1);
if (!empty($cur)) $output[] = $cur;
$offset += $size - 1;
}
return $output;

View File

@ -72,7 +72,7 @@ final class MD_STD_CACHE {
ob_start();
if (($redisResult = $redis->get($redisKey))) {
if ($redisResult = $redis->get($redisKey)) {
if (strlen($redisResult) > 3 and strpos($redisResult, ' id="errorPage"') === false) {
$redis->close();

View File

@ -73,13 +73,12 @@ final class MD_STD_IN {
*/
public static function sanitize_text(mixed $input):string {
$output = \filter_var($input,
FILTER_SANITIZE_STRING,
FILTER_FLAG_NO_ENCODE_QUOTES);
$output = \filter_var($input, FILTER_UNSAFE_RAW);
if ($output === false) {
return "";
}
$output = strip_tags($output);
while (strpos($output, " ") !== false) {
$output = str_replace(" ", " ", $output);
}
@ -97,9 +96,7 @@ final class MD_STD_IN {
*/
public static function sanitize_rgb_color(mixed $input):string {
$output = \filter_var($input,
FILTER_SANITIZE_STRING,
FILTER_FLAG_NO_ENCODE_QUOTES);
$output = \filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
if ($output === false
|| (preg_match('/^[a-zA-Z0-9]{3}$/', $output) === false && preg_match('/^[a-zA-Z0-9]{6}$/', $output) === false)
@ -205,6 +202,11 @@ final class MD_STD_IN {
throw new MDInvalidUrl("Invalid input URL");
}
// Check for valid schemes
if (MD_STD::startsWithAny($input, ['https://', 'http://', 'ftp://']) === false) {
throw new MDInvalidUrl("Invalid input URL");
}
return $output;
}
@ -231,6 +233,30 @@ final class MD_STD_IN {
}
/**
* Validates a password (minimum requirements: 8 characters, including
* one number and one special char) and returns a list of errors,
* if there are any.
*
* @param string $input Input string.
*
* @return array<string>
*/
public static function validate_password(string $input):array {
$errors = [];
if (mb_strlen($input) < 8) {
$errors[] = 'password_too_short';
}
if (!(\preg_match('@[0-9]@', $input)) && !(\preg_match('@[^\w]@', $input))) {
$errors[] = 'password_has_no_number_no_special_char';
}
return $errors;
}
/**
* Sanitizes and validates a phone number. An empty string passes.
*
@ -295,7 +321,7 @@ final class MD_STD_IN {
}
// ISBN 13
if (\mb_strlen($input) === 10) {
if (\mb_strlen($input) === 13) {
if (\preg_match('/\d{13}/i', $input)) {
return $input;

View File

@ -134,14 +134,14 @@ final class MD_STD_SEC {
/**
* Send CSP headers.
*
* @param array{default-src: string, connect-src: string, script-src: string, img-src: string, media-src: string, style-src: string, frame-src: string, object-src: string, base-uri: string, form-action: string, frame-ancestors?: string} $directives Directives to send. Font source is always set to 'self', and hence excluded.
* @param string $frame_ancestors Frame ancestors directive. Default is to not set it.
* @param array{default-src: string, connect-src: string, script-src: string, img-src: string, media-src: string, style-src: string, frame-src: string, object-src: string, base-uri: string, form-action: string, worker-src?: string, frame-ancestors?: string} $directives Directives to send. Font source is always set to 'self', and hence excluded.
* @param string $frame_ancestors Frame ancestors directive. Default is to not set it.
*
* @return void
*/
public static function sendContentSecurityPolicy(array $directives, string $frame_ancestors = ""):void {
$policy = 'Content-Security-Policy: default-src ' . $directives['default-src'] . '; connect-src ' . $directives['connect-src'] . '; script-src ' . $directives['script-src'] . '; img-src ' . $directives['img-src'] . '; media-src ' . $directives['media-src'] . '; style-src ' . $directives['style-src'] . '; font-src \'self\'; frame-src ' . $directives['frame-src'] . '; object-src ' . $directives['object-src'] . '; base-uri ' . $directives['base-uri'] . '; form-action ' . $directives['form-action'] . '; manifest-src \'self\'; worker-src \'self\';';
$policy = 'Content-Security-Policy: default-src ' . $directives['default-src'] . '; connect-src ' . $directives['connect-src'] . '; script-src ' . $directives['script-src'] . '; img-src ' . $directives['img-src'] . '; media-src ' . $directives['media-src'] . '; style-src ' . $directives['style-src'] . '; font-src \'self\'; frame-src ' . $directives['frame-src'] . '; object-src ' . $directives['object-src'] . '; base-uri ' . $directives['base-uri'] . '; form-action ' . $directives['form-action'] . '; manifest-src \'self\'; worker-src ' . ($directives['worker-src'] ?? '\'self\'') . ';';
if (!empty($frame_ancestors)) {
$policy .= ' frame-ancestors ' . $frame_ancestors . ';';