diff --git a/.githooks/pre-commit b/.githooks/pre-commit
new file mode 100755
index 00000000..1dfeb762
--- /dev/null
+++ b/.githooks/pre-commit
@@ -0,0 +1,119 @@
+#!/bin/bash
+
+set -o pipefail
+
+GIT_ROOT=$(git rev-parse --show-toplevel) # ".../lti-1-3-php-library"
+
+# So we avoid the "Not a git repository" error when performing git commands in a subdir
+unset GIT_DIR
+
+# Get changed files to be committed, excluding deleted files (since we can't grep them)
+CHANGED_FILES=$(git diff --cached --name-only --diff-filter=d)
+
+NO_FORMAT="\e[0m"
+F_BOLD="\e[1m"
+C_RED="\e[31m"
+C_YELLOW="\e[93m"
+C_CYAN="\e[36m"
+C_LIME="\e[92m"
+
+# Rather than doing `return 1`, we fail fast.
+function fail {
+ echo -e "${C_RED}${F_BOLD}Pre-commit hook failed! Fix the above errors before committing.${NO_FORMAT}"
+ exit 1
+}
+
+function file_ends_with_newline {
+ file_path=$1
+
+ # NOTE: Empty files technically end with a newline.
+ [[ $(wc -l < "$file_path") -eq 0 ]] || [[ $(tail -c1 "$file_path" | wc -l) -gt 0 ]]
+}
+
+function is_executable_installed {
+ executable_name=$1
+
+ which "$executable_name" >/dev/null
+}
+
+# Returns a 0 status code if the given feature is enabled, 1 otherwise.
+# Feature names are arbitrarily defined in the optional file `.skipped-checks`
+# in order to give more control to developers to-as what gets executed.
+function feature_is_enabled {
+ feature_name=$1
+
+ # We redirect output so that it doesn't emit warnings if the file doesn't exist.
+ ! grep "$feature_name" "$GIT_ROOT/.githooks/.skipped-checks" &> /dev/null
+}
+
+function feature_is_disabled {
+ feature_name=$1
+
+ ! feature_is_enabled "$feature_name"
+}
+
+function skip_if_no_changes {
+ if [[ -z "$CHANGED_FILES" ]]; then
+ echo "No changes were detected while running the pre-commit hook." && exit 0
+ fi
+}
+
+function skip_if_merge_in_progress {
+ if [ -f ".git/MERGE_HEAD" ]; then
+ echo "Detected merge in progress, skipping pre-commit hook." && exit 0
+ fi
+}
+
+function fail_if_unresolved_merge_conflict {
+ # Check the files to prevent merge markers from being committed.
+ if echo "$CHANGED_FILES" | xargs --no-run-if-empty egrep '[><]{7}' -H -I --line-number; then
+ echo -e "${C_RED}You have merge markers (conflicts) in the above files, lines. Fix them before committing.${NO_FORMAT}" && fail
+ fi
+}
+
+function lint_eof_newlines {
+ if feature_is_disabled "pre-commit-auto-newlines"; then
+ return 0
+ fi
+
+ text_files=$(echo "$CHANGED_FILES" | grep -E '\.(css|docker|Dockerfile|dockerignore|ejs|env|example|gitignore|html|js|json|php|py|rb|scss|sh|svg|toml|trivyignore|ts|txt|yaml|yml)$')
+ for f in $text_files; do
+ # Add a linebreak to the file if it doesn't have one
+ if ! file_ends_with_newline "$f"; then
+ echo >>"$f"
+ git add "$f"
+ fi
+ done
+}
+
+function lint_php {
+ php_files=$(echo "$CHANGED_FILES" | grep '\.php')
+ if [[ -z "$php_files" ]]; then
+ return 0 # There's nothing to lint.
+ fi
+
+ phpcsfixer="vendor/bin/php-cs-fixer"
+
+ if ! [ -x "$phpcsfixer" ]; then
+ echo -e "${C_RED}PHP-CS-Fixer is not installed. Install it with \`composer install\`.${NO_FORMAT}" && return 1
+ fi
+
+ php_files_arg=$(echo "$php_files" | tr '\n' ' ')
+
+ echo -e "${C_CYAN}Linting PHP-CS-Fixer...${NO_FORMAT}"
+ $phpcsfixer fix -q || return 1
+
+ git add $php_files_arg
+}
+
+echo -e "${NO_FORMAT}${F_BOLD}Running pre-commit hook...${NO_FORMAT}"
+
+skip_if_merge_in_progress
+skip_if_no_changes
+
+fail_if_unresolved_merge_conflict
+
+lint_eof_newlines || fail
+lint_php || fail
+
+echo -e "${C_LIME}${F_BOLD}Pre-commit hook passed!${NO_FORMAT}"
diff --git a/README.md b/README.md
index f95f6bbd..aa71587d 100644
--- a/README.md
+++ b/README.md
@@ -44,11 +44,11 @@ A JWKS (JSON Web Key Set) endpoint can be generated for either an individual reg
use Packback\Lti1p3\JwksEndpoint;
// From issuer
-JwksEndpoint::fromIssuer($database, 'http://example.com')->outputJwks();
+JwksEndpoint::fromIssuer($database, 'http://example.com')->getPublicJwks();
// From registration
-JwksEndpoint::fromRegistration($registration)->outputJwks();
+JwksEndpoint::fromRegistration($registration)->getPublicJwks();
// From array
-JwksEndpoint::new(['a_unique_KID' => file_get_contents('/path/to/private/key.pem')])->outputJwks();
+JwksEndpoint::new(['a_unique_KID' => file_get_contents('/path/to/private/key.pem')])->getPublicJwks();
```
## Documentation
diff --git a/src/ImsStorage/ImsCache.php b/src/ImsStorage/ImsCache.php
index 41f7bc48..a0be843c 100644
--- a/src/ImsStorage/ImsCache.php
+++ b/src/ImsStorage/ImsCache.php
@@ -5,7 +5,7 @@
use Packback\Lti1p3\Interfaces\ICache;
/**
- * @todo Deprecate this in the next major version
+ * @deprecated
*/
class ImsCache implements ICache
{
diff --git a/src/ImsStorage/ImsCookie.php b/src/ImsStorage/ImsCookie.php
index dab75f2e..3e3b552c 100644
--- a/src/ImsStorage/ImsCookie.php
+++ b/src/ImsStorage/ImsCookie.php
@@ -5,7 +5,7 @@
use Packback\Lti1p3\Interfaces\ICookie;
/**
- * @todo Deprecate this in the next major version
+ * @deprecated
*/
class ImsCookie implements ICookie
{
diff --git a/src/JwksEndpoint.php b/src/JwksEndpoint.php
index 4aa8a423..92197f17 100644
--- a/src/JwksEndpoint.php
+++ b/src/JwksEndpoint.php
@@ -6,6 +6,9 @@
use Packback\Lti1p3\Interfaces\ILtiRegistration;
use phpseclib3\Crypt\RSA;
+/**
+ * @todo Pin versions to v6.6 and php 8
+ */
class JwksEndpoint
{
private $keys;
@@ -49,10 +52,12 @@ public function getPublicJwks()
}
/**
- * @todo: Deprecate this in the next major version
+ * @deprecated
*/
public function outputJwks()
{
+ trigger_error('Method '.__METHOD__.' is deprecated', E_USER_DEPRECATED);
+
echo json_encode($this->getPublicJwks());
}
}
diff --git a/src/LtiDeepLink.php b/src/LtiDeepLink.php
index ba6764c9..e1ce2d8e 100644
--- a/src/LtiDeepLink.php
+++ b/src/LtiDeepLink.php
@@ -44,18 +44,12 @@ public function getResponseJwt($resources)
}
/**
- * This method builds an auto-submitting HTML form to post the deep linking response message
- * back to platform, as per LTI-DL 2.0 specification. The resulting HTML is then written to standard output,
- * so calling this method will automatically send an HTTP response to conclude the content selection flow.
- *
- * @param LtiDeepLinkResource[] $resources The list of selected resources to be sent to the platform
- *
- * @todo Consider wrapping the content inside a well-formed HTML document,
- * and returning it instead of directly writing to standard output
- * @todo Deprecate this in the next major version
+ * @deprecated
*/
public function outputResponseForm($resources)
{
+ trigger_error('Method '.__METHOD__.' is deprecated', E_USER_DEPRECATED);
+
$jwt = $this->getResponseJwt($resources);
$formActionUrl = $this->deep_link_settings['deep_link_return_url'];
diff --git a/src/LtiDeepLinkResource.php b/src/LtiDeepLinkResource.php
index 093f979c..5f4ba7a8 100644
--- a/src/LtiDeepLinkResource.php
+++ b/src/LtiDeepLinkResource.php
@@ -125,6 +125,8 @@ public function setCustomParams(array $value): LtiDeepLinkResource
*/
public function getTarget(): string
{
+ trigger_error('Method '.__METHOD__.' is deprecated', E_USER_DEPRECATED);
+
return $this->target;
}
@@ -134,6 +136,8 @@ public function getTarget(): string
*/
public function setTarget(string $value): LtiDeepLinkResource
{
+ trigger_error('Method '.__METHOD__.' is deprecated', E_USER_DEPRECATED);
+
$this->target = $value;
return $this;
diff --git a/src/LtiMessageLaunch.php b/src/LtiMessageLaunch.php
index b3ad2825..2f15c69e 100644
--- a/src/LtiMessageLaunch.php
+++ b/src/LtiMessageLaunch.php
@@ -121,7 +121,7 @@ public static function fromCache(
ICache $cache = null,
ILtiServiceConnector $serviceConnector = null
) {
- // @TODO: Fix the null here on the next major version
+ // @todo: Fix the null here on the next major version
$new = new LtiMessageLaunch($database, $cache, null, $serviceConnector);
$new->launch_id = $launch_id;
$new->jwt = ['body' => $new->cache->getLaunchData($launch_id)];
@@ -171,7 +171,7 @@ public function validate(array $request = null)
->validateJwtSignature()
->validateDeployment()
->validateMessage()
- // @TODO: Remove this in v6.0
+ // @todo remove this in v6.0
->cacheLaunchData();
}
diff --git a/src/LtiOidcLogin.php b/src/LtiOidcLogin.php
index c77f1d0b..f6582107 100644
--- a/src/LtiOidcLogin.php
+++ b/src/LtiOidcLogin.php
@@ -48,6 +48,7 @@ public static function new(IDatabase $database, ICache $cache = null, ICookie $c
*/
public function doOidcLoginRedirect($launchUrl, array $request = null)
{
+ // @todo remove this in v6.0
if ($request === null) {
$request = $_REQUEST;
}
diff --git a/src/Redirect.php b/src/Redirect.php
index a87ed5f1..f90f6961 100644
--- a/src/Redirect.php
+++ b/src/Redirect.php
@@ -22,8 +22,12 @@ public function doRedirect()
exit;
}
+ /**
+ * @deprecated
+ */
public function doHybridRedirect(ICookie $cookie)
{
+ trigger_error('Method '.__METHOD__.' is deprecated', E_USER_DEPRECATED);
if (!empty($cookie->getCookie(self::$CAN_302_COOKIE))) {
return $this->doRedirect();
}
@@ -36,8 +40,13 @@ public function getRedirectUrl()
return $this->location;
}
+ /**
+ * @deprecated
+ */
public function doJsRedirect()
{
+ trigger_error('Method '.__METHOD__.' is deprecated', E_USER_DEPRECATED);
+
?>
If you are not automatically redirected, click here to continue