Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,24 @@ repos:
resources/lib/UnityHTTPD\.php$|
workers/.*|
)$
- id: assert-no-assert
name: Assert no assert()
entry: ./test/assert-no-assert.bash
language: system
files: \.php$
exclude: |
(?x)^(
resources/lib/utils\.php$|
workers/.*|
test/.*|
)$
- id: assert-no-json_encode
name: Assert no json_encode()
entry: ./test/assert-no-json_encode.bash
language: system
files: \.php$
exclude: |
(?x)^(
resources/lib/utils\.php$|
workers/.*|
)$
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
* Comments should be used sparingly.
* Empty lines should be used sparingly.
* No code should call `die()` or `exit()`, instead `UnityHTTPD::die()`. This will avoid the premature death of our automated testing processes.
* Instead of `assert`, use `\ensure`. This will enforce conditions even in production.
* No code should call `assert()`, instead `\ensure()`. This will enforce conditions even in production.
* No code should call `json_encode()`, instead `\jsonEncode()`. This will throw errors and escape slashes by default.

This repository will automatically check PRs for linting compliance.

Expand Down
30 changes: 23 additions & 7 deletions resources/lib/UnityHTTPD.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,14 @@ public static function errorLog(
$output["trace"] = explode("\n", (new \Exception())->getTraceAsString());
}
if (!is_null($data)) {
$output["data"] = $data;
try {
\jsonEncode($data);
$output["data"] = $data;
} catch (\JsonException $e) {
$output["data"] = "data could not be JSON encoded: " . $e->getMessage();
}
}
error_log("$title: " . json_encode($output, JSON_UNESCAPED_SLASHES));
error_log("$title: " . \jsonEncode($output));
}

// recursive on $t->getPrevious()
Expand Down Expand Up @@ -147,8 +152,11 @@ public static function getPostData(...$keys)
}
}

public static function getUploadedFileContents($filename, $do_delete_tmpfile_after_read = true)
{
public static function getUploadedFileContents(
$filename,
$do_delete_tmpfile_after_read = true,
$encoding = "UTF-8",
) {
try {
$tmpfile_path = \arrayGet($_FILES, $filename, "tmp_name");
} catch (ArrayKeyException $e) {
Expand All @@ -161,14 +169,22 @@ public static function getUploadedFileContents($filename, $do_delete_tmpfile_aft
if ($do_delete_tmpfile_after_read) {
unlink($tmpfile_path);
}
return $contents;
$old_encoding = mb_detect_encoding($contents);
if ($old_encoding === $encoding) {
return $contents;
}
$converted = mb_convert_encoding($contents, $encoding, $old_encoding);
if ($converted !== false) {
return $converted;
}
self::badRequest("failed to convert file '$filename' from '$old_encoding' to '$encoding'");
}

// in firefox, the user can disable alert/confirm/prompt after the 2nd or 3rd popup
// after I disable alerts, if I quit and reopen my browser, the alerts come back
public static function alert(string $message)
{
// json_encode escapes quotes
echo "<script type='text/javascript'>alert(" . json_encode($message) . ");</script>";
// jsonEncode escapes quotes
echo "<script type='text/javascript'>alert(" . \jsonEncode($message) . ");</script>";
}
}
2 changes: 1 addition & 1 deletion resources/lib/UnityLDAP.php
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ public function getAllPIGroupOwnerAttributes($attributes)
if (count($owners_not_found) > 0) {
UnityHTTPD::errorLog(
"warning",
"PI group owners not found: " . json_encode($owners_not_found) . "\n"
"PI group owners not found: " . \jsonEncode($owners_not_found) . "\n"
);
}
return $owner_attributes;
Expand Down
2 changes: 1 addition & 1 deletion resources/lib/UnityWebhook.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function sendWebhook($template = null, $data = null)
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(array('text' => $message)));
curl_setopt($ch, CURLOPT_POSTFIELDS, \jsonEncode(array('text' => $message)));
$result = curl_exec($ch);
curl_close($ch);
return $result;
Expand Down
2 changes: 1 addition & 1 deletion resources/lib/phpopenldaper
8 changes: 7 additions & 1 deletion resources/lib/utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function arrayGet($array, ...$keys)
throw new ArrayKeyException(
"key not found: \$array" .
// [1, 2, "foo"] => [1][2]["foo"]
implode("", array_map(fn($x) => json_encode([$x]), $keysTraversed))
implode("", array_map(fn($x) => jsonEncode([$x]), $keysTraversed))
);
}
$cursor = $cursor[$key];
Expand Down Expand Up @@ -53,3 +53,9 @@ function testValidSSHKey($key_str)
return false;
}
}

function jsonEncode($value, $flags = 0, $depth = 512)
{
$flags |= JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES;
return json_encode($value, $flags, $depth);
}
12 changes: 12 additions & 0 deletions test/assert-no-assert.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
set -euo pipefail
if [[ $# -lt 1 ]]; then
echo "at least one argument required"
exit 1
fi

# --color=never because magit git output log doesn't support it
if grep -H --color=never --line-number -P '\bassert\s*[\(;]' "$@"; then
echo "assert() is not allowed! use \ensure() instead."
exit 1
fi
12 changes: 12 additions & 0 deletions test/assert-no-json_encode.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
set -euo pipefail
if [[ $# -lt 1 ]]; then
echo "at least one argument required"
exit 1
fi

# --color=never because magit git output log doesn't support it
if grep -H --color=never --line-number -P '\bjson_encode\b' "$@"; then
echo "json_encode() is not allowed! use \jsonEncode() instead."
exit 1
fi
2 changes: 1 addition & 1 deletion webroot/api/notices/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
$jsonArray[] = $formattedNotice;
}

$jsonOutput = json_encode($jsonArray, JSON_PRETTY_PRINT);
$jsonOutput = jsonEncode($jsonArray, JSON_PRETTY_PRINT);
echo $jsonOutput;