diff --git a/classes/Conf/class.xoctConfFormGUI.php b/classes/Conf/class.xoctConfFormGUI.php index a4a95e1fa..cd4bcbf95 100644 --- a/classes/Conf/class.xoctConfFormGUI.php +++ b/classes/Conf/class.xoctConfFormGUI.php @@ -557,6 +557,15 @@ protected function initGroupsRolesSection(): void protected function initSecuritySection(): void { + $strings = (object) [ + 'show' => $this->getLocaleString(PluginConfig::F_JWT_SECURITY_PK . '_show_icon'), + 'hide' => $this->getLocaleString(PluginConfig::F_JWT_SECURITY_PK . '_hide_icon'), + 'hidden_element_title' => $this->getLocaleString(PluginConfig::F_JWT_SECURITY_PK . '_hidden_element_title') + ]; + $strings = json_encode($strings); + $code = "il.Opencast.Form.passwordToggle.initTextarea('" . PluginConfig::F_JWT_SECURITY_PK . "', '" . $strings . "');"; + $this->main_tpl->addOnLoadCode($code); + $this->main_tpl->setOnScreenMessage('info', $this->getLocaleString('security_info'), true); $h = new ilFormSectionHeaderGUI(); $h->setTitle($this->getLocaleString('security')); @@ -658,6 +667,53 @@ protected function initSecuritySection(): void ); $cb->setInfo($this->getLocaleString(PluginConfig::F_PRESIGN_LINKS . '_info')); $this->addItem($cb); + + // JWT enabled. + $cb = new ilCheckboxInputGUI( + $this->getLocaleString(PluginConfig::F_JWT_SECURITY_ENABLED), + PluginConfig::F_JWT_SECURITY_ENABLED + ); + $cb->setInfo($this->getLocaleString(PluginConfig::F_JWT_SECURITY_ENABLED . '_info')); + $this->addItem($cb); + + // JWT Private Key. + $te_cb_sub = new ilTextAreaInputGUI($this->getLocaleString(PluginConfig::F_JWT_SECURITY_PK), PluginConfig::F_JWT_SECURITY_PK); + $te_cb_sub->setInfo($this->getLocaleString(PluginConfig::F_JWT_SECURITY_PK . '_info')); + $te_cb_sub->setRequired(true); + $cb->addSubItem($te_cb_sub); + + //JWT Expiration. + $nu_cb_sub = new ilNumberInputGUI($this->getLocaleString(PluginConfig::F_JWT_SECURITY_EXP), PluginConfig::F_JWT_SECURITY_EXP); + $nu_cb_sub->setMinValue(1, true); + $nu_cb_sub->setValue((string) PluginConfig::getConfig(PluginConfig::F_JWT_SECURITY_EXP) ?? "15"); + $nu_cb_sub->setInfo($this->getLocaleString(PluginConfig::F_JWT_SECURITY_EXP . '_info')); + $cb->addSubItem($nu_cb_sub); + + // JWT Algorithm. + $se_cb_sub = new ilSelectInputGUI($this->getLocaleString(PluginConfig::F_JWT_SECURITY_ALG), PluginConfig::F_JWT_SECURITY_ALG); + $se_cb_sub->setInfo($this->getLocaleString(PluginConfig::F_JWT_SECURITY_ALG . '_info')); + $algorithms = []; + foreach (array_keys(\OpencastApi\Auth\JWT\OcJwtHandler::SUPPORTED_ALGORITHMS) as $alg) { + $algorithms[$alg] = $alg; + } + $default = \OpencastApi\Auth\JWT\OcJwtHandler::DEFAULT_ALGORITHM; + $se_cb_sub->setOptions($algorithms); + $se_cb_sub->setValue(PluginConfig::getConfig(PluginConfig::F_JWT_SECURITY_EXP) ?? $default); + $cb->addSubItem($se_cb_sub); + + // JWT Studio Roles. + $te_studio_cb_sub = new ilTextInputGUI($this->getLocaleString('jwt_security_studio_roles'), PluginConfig::F_JWT_SECURITY_STUDIO_ROLES); + $te_studio_cb_sub->setInfo($this->getLocaleString('jwt_security_studio_roles_info')); + $te_studio_cb_sub->setMulti(true); + $te_studio_cb_sub->setInlineStyle('min-width:250px'); + $cb->addSubItem($te_studio_cb_sub); + + // JWT Editor Roles. + $te_editor_cb_sub = new ilTextInputGUI($this->getLocaleString('jwt_security_editor_roles'), PluginConfig::F_JWT_SECURITY_EDITOR_ROLES); + $te_editor_cb_sub->setInfo($this->getLocaleString('jwt_security_editor_roles_info')); + $te_editor_cb_sub->setMulti(true); + $te_editor_cb_sub->setInlineStyle('min-width:250px'); + $cb->addSubItem($te_editor_cb_sub); } protected function initAdvancedSection(): void diff --git a/classes/Event/class.xoctEventGUI.php b/classes/Event/class.xoctEventGUI.php index 8d56dcaf3..7b8cf369b 100755 --- a/classes/Event/class.xoctEventGUI.php +++ b/classes/Event/class.xoctEventGUI.php @@ -7,6 +7,7 @@ use ILIAS\DI\Container; use ILIAS\UI\Component\Input\Field\UploadHandler; use ILIAS\UI\Renderer; +use srag\Plugins\Opencast\API\OpencastAPI; use srag\Plugins\Opencast\Model\ACL\ACLUtils; use srag\Plugins\Opencast\Model\Config\PluginConfig; use srag\Plugins\Opencast\Model\Event\Event; @@ -893,7 +894,20 @@ public function opencaststudio(): void // Append the query string to the studio link. $studio_link .= '?' . $combined_query_string; - $this->ctrl->redirectToURL($studio_link); + if (empty(PluginConfig::getConfig(PluginConfig::F_JWT_SECURITY_ENABLED))) { + $this->ctrl->redirectToURL($studio_link); + return; + } + + $encoded_studio_link = $base . '/studio?' . http_build_query($query_params); + + $redirect_url = $base . '/redirect/get'; + $jwt = $this->api->issueExternalServicesJwtFor(OpencastAPI::JWT_SERVICE_STUDIO); + $temp = $this->plugin->getTemplate('default/tpl.jwt_redirect.html', false, false); + $temp->setVariable('ACTION', $redirect_url); + $temp->setVariable('JWT', $jwt); + $temp->setVariable('TARGET_URL', $encoded_studio_link); + $this->main_tpl->setContent($temp->get()); } @@ -912,7 +926,20 @@ public function cut(): void // redirect $cutting_link = $event->publications()->getCuttingLink(); - $this->ctrl->redirectToURL($cutting_link); + + if (empty(PluginConfig::getConfig(PluginConfig::F_JWT_SECURITY_ENABLED))) { + $this->ctrl->redirectToURL($cutting_link); + return; + } + + $base = rtrim((string) PluginConfig::getConfig(PluginConfig::F_API_BASE), "/"); + $redirect_url = str_replace('/api', '/redirect/get', $base); + $jwt = $this->api->issueExternalServicesJwtFor(OpencastAPI::JWT_SERVICE_EDITOR); + $temp = $this->plugin->getTemplate('default/tpl.jwt_redirect.html', false, false); + $temp->setVariable('ACTION', $redirect_url); + $temp->setVariable('JWT', $jwt); + $temp->setVariable('TARGET_URL', $cutting_link); + $this->main_tpl->setContent($temp->get()); } private function retrieveQuery(string $q): ?string diff --git a/classes/class.xoctException.php b/classes/class.xoctException.php index 18a9427a7..42e6801cf 100644 --- a/classes/class.xoctException.php +++ b/classes/class.xoctException.php @@ -16,6 +16,7 @@ class xoctException extends Exception public const NO_USER_MAPPING = 40; public const INTERNAL_ERROR = 50; public const NO_STREAMING_DATA = 60; + public const JWT_TOKEN_ISSUE_FAILED = 70; public const API_CALL_STATUS_500 = 500; public const API_CALL_STATUS_403 = 403; public const API_CALL_STATUS_404 = 404; @@ -38,6 +39,7 @@ class xoctException extends Exception self::API_CALL_BAD_CREDENTIALS => 'The OpenCast-Server cannot be accessed at the moment.', self::INTERNAL_ERROR => 'A plugin-internal error occured.', self::NO_STREAMING_DATA => 'No streaming data found.', + self::JWT_TOKEN_ISSUE_FAILED => 'Opencast JWT: An error occurred while generating token', ]; /** diff --git a/classes/class.xoctSecureLink.php b/classes/class.xoctSecureLink.php index 50f70a3ae..d8dc78761 100644 --- a/classes/class.xoctSecureLink.php +++ b/classes/class.xoctSecureLink.php @@ -24,6 +24,10 @@ class xoctSecureLink */ protected static function sign(string $url, ?string $valid_until = null, ?bool $restict_ip = false) { + // JWT takes precedence. + if (!empty(PluginConfig::getConfig(PluginConfig::F_JWT_SECURITY_ENABLED))) { + return $url; + } $opencastContainer = Init::init(); if (str_contains((string) $url, 'policy=') && str_contains((string) $url, 'signature=')) { // already signed, e.g. when presigning is active diff --git a/composer.json b/composer.json index 606fe4de8..cfeff8e79 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "require": { "php": ">=8.1 <8.3", "ext-dom": "*", - "elan-ev/opencast-api": "1.9.0" + "elan-ev/opencast-api": "2.0.0" }, "autoload": { "exclude-from-classmap": ["vendor/guzzlehttp/", "vendor/ralouphie/", "vendor/psr/http-message", "vendor/psr/http-factory", "vendor/psr/http-client"], diff --git a/composer.lock b/composer.lock index 01acbef60..c92665a69 100644 --- a/composer.lock +++ b/composer.lock @@ -4,25 +4,26 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f7c63dfe3c40f83852eef7b05d15a416", + "content-hash": "972393e3ffbc56dbfe623b7f3a979306", "packages": [ { "name": "elan-ev/opencast-api", - "version": "1.9.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/elan-ev/opencast-php-library.git", - "reference": "041f29d10f9572b038e8665f6cc2f9c86d488da8" + "reference": "56a32f5498006d1da343ac195ea509a1af3e9a82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/elan-ev/opencast-php-library/zipball/041f29d10f9572b038e8665f6cc2f9c86d488da8", - "reference": "041f29d10f9572b038e8665f6cc2f9c86d488da8", + "url": "https://api.github.com/repos/elan-ev/opencast-php-library/zipball/56a32f5498006d1da343ac195ea509a1af3e9a82", + "reference": "56a32f5498006d1da343ac195ea509a1af3e9a82", "shasum": "" }, "require": { - "guzzlehttp/guzzle": ">=7.5.1", - "php": ">=7.2.5" + "guzzlehttp/guzzle": "^7.5", + "lcobucci/jwt": "^5.3", + "php": "^8.1" }, "require-dev": { "phpcompatibility/php-compatibility": "^9.3", @@ -62,9 +63,9 @@ ], "support": { "issues": "https://github.com/elan-ev/opencast-php-library/issues", - "source": "https://github.com/elan-ev/opencast-php-library/tree/1.9.0" + "source": "https://github.com/elan-ev/opencast-php-library/tree/2.0.0" }, - "time": "2025-03-10T07:54:08+00:00" + "time": "2025-10-28T07:14:10+00:00" }, { "name": "guzzlehttp/guzzle", @@ -391,6 +392,127 @@ ], "time": "2024-07-18T11:15:46+00:00" }, + { + "name": "lcobucci/jwt", + "version": "5.5.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "a835af59b030d3f2967725697cf88300f579088e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/a835af59b030d3f2967725697cf88300f579088e", + "reference": "a835af59b030d3f2967725697cf88300f579088e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-sodium": "*", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/clock": "^1.0" + }, + "require-dev": { + "infection/infection": "^0.29", + "lcobucci/clock": "^3.2", + "lcobucci/coding-standard": "^11.0", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", + "phpstan/phpstan-strict-rules": "^1.5.0", + "phpunit/phpunit": "^11.1" + }, + "suggest": { + "lcobucci/clock": ">= 3.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/5.5.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2025-01-26T21:29:45+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, { "name": "psr/http-client", "version": "1.0.3", diff --git a/js/opencast/dist/index.js b/js/opencast/dist/index.js index e5e72e60e..dff55cd35 100644 --- a/js/opencast/dist/index.js +++ b/js/opencast/dist/index.js @@ -1 +1 @@ -!function(t,e){"use strict";function r(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=r(t),o=r(e);"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self&&self;function i(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var a=i(function(t,e,r){return t(r={path:e,exports:{},require:function(t,e){return function(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==e&&r.path)}},r.exports),r.exports}((function(t,e){var r;r=()=>(()=>{var t={28:(t,e,r)=>{r.r(e),r.d(e,{default:()=>d});var n=r(46),o=r(911),i=r.n(o);function a(t){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function s(){s=function(){return e};var t,e={},r=Object.prototype,n=r.hasOwnProperty,o=Object.defineProperty||function(t,e,r){t[e]=r.value},i="function"==typeof Symbol?Symbol:{},c=i.iterator||"@@iterator",u=i.asyncIterator||"@@asyncIterator",l=i.toStringTag||"@@toStringTag";function f(t,e,r){return Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{f({},"")}catch(t){f=function(t,e,r){return t[e]=r}}function h(t,e,r,n){var i=e&&e.prototype instanceof m?e:m,a=Object.create(i.prototype),s=new P(n||[]);return o(a,"_invoke",{value:C(t,r,s)}),a}function p(t,e,r){try{return{type:"normal",arg:t.call(e,r)}}catch(t){return{type:"throw",arg:t}}}e.wrap=h;var d="suspendedStart",y="executing",v="completed",g={};function m(){}function b(){}function w(){}var x={};f(x,c,(function(){return this}));var A=Object.getPrototypeOf,E=A&&A(A(j([])));E&&E!==r&&n.call(E,c)&&(x=E);var L=w.prototype=m.prototype=Object.create(x);function _(t){["next","throw","return"].forEach((function(e){f(t,e,(function(t){return this._invoke(e,t)}))}))}function k(t,e){function r(o,i,s,c){var u=p(t[o],t,i);if("throw"!==u.type){var l=u.arg,f=l.value;return f&&"object"==a(f)&&n.call(f,"__await")?e.resolve(f.__await).then((function(t){r("next",t,s,c)}),(function(t){r("throw",t,s,c)})):e.resolve(f).then((function(t){l.value=t,s(l)}),(function(t){return r("throw",t,s,c)}))}c(u.arg)}var i;o(this,"_invoke",{value:function(t,n){function o(){return new e((function(e,o){r(t,n,e,o)}))}return i=i?i.then(o,o):o()}})}function C(e,r,n){var o=d;return function(i,a){if(o===y)throw Error("Generator is already running");if(o===v){if("throw"===i)throw a;return{value:t,done:!0}}for(n.method=i,n.arg=a;;){var s=n.delegate;if(s){var c=S(s,n);if(c){if(c===g)continue;return c}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(o===d)throw o=v,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o=y;var u=p(e,r,n);if("normal"===u.type){if(o=n.done?v:"suspendedYield",u.arg===g)continue;return{value:u.arg,done:n.done}}"throw"===u.type&&(o=v,n.method="throw",n.arg=u.arg)}}}function S(e,r){var n=r.method,o=e.iterator[n];if(o===t)return r.delegate=null,"throw"===n&&e.iterator.return&&(r.method="return",r.arg=t,S(e,r),"throw"===r.method)||"return"!==n&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+n+"' method")),g;var i=p(o,e.iterator,r.arg);if("throw"===i.type)return r.method="throw",r.arg=i.arg,r.delegate=null,g;var a=i.arg;return a?a.done?(r[e.resultName]=a.value,r.next=e.nextLoc,"return"!==r.method&&(r.method="next",r.arg=t),r.delegate=null,g):a:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,g)}function O(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function T(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function P(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(O,this),this.reset(!0)}function j(e){if(e||""===e){var r=e[c];if(r)return r.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var o=-1,i=function r(){for(;++o=0;--i){var a=this.tryEntries[i],s=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var c=n.call(a,"catchLoc"),u=n.call(a,"finallyLoc");if(c&&u){if(this.prev=0;--r){var o=this.tryEntries[r];if(o.tryLoc<=this.prev&&n.call(o,"finallyLoc")&&this.prev=0;--e){var r=this.tryEntries[e];if(r.finallyLoc===t)return this.complete(r.completion,r.afterLoc),T(r),g}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var r=this.tryEntries[e];if(r.tryLoc===t){var n=r.completion;if("throw"===n.type){var o=n.arg;T(r)}return o}}throw Error("illegal catch attempt")},delegateYield:function(e,r,n){return this.delegate={iterator:j(e),resultName:r,nextLoc:n},"next"===this.method&&(this.arg=t),g}},e}function c(t,e,r,n,o,i,a){try{var s=t[i](a),c=s.value}catch(t){return void r(t)}s.done?e(c):Promise.resolve(c).then(n,o)}function u(t){return function(){var e=this,r=arguments;return new Promise((function(n,o){var i=t.apply(e,r);function a(t){c(i,n,o,a,s,"next",t)}function s(t){c(i,n,o,a,s,"throw",t)}a(void 0)}))}}function l(t){var e=function(t){if("object"!=a(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var r=e.call(t,"string");if("object"!=a(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==a(e)?e:e+""}function f(){try{var t=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(t){}return(f=function(){return!!t})()}function h(t){return(h=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function p(t,e){return(p=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t})(t,e)}var d=function(t){function e(){return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),function(t,e,r){return e=h(e),function(t,e){if(e&&("object"==a(e)||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t)}(t,f()?Reflect.construct(e,r||[],h(t).constructor):e.apply(t,r))}(this,e,arguments)}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&p(t,e)}(e,t),r=e,(n=[{key:"name",get:function(){return"org.ilias.paella.liveStreamingButtonIndicator"}},{key:"isEnabled",value:(c=u(s().mark((function t(){var e;return s().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.abrupt("return",null===(e=this.config)||void 0===e?void 0:e.enabled);case 1:case"end":return t.stop()}}),t,this)}))),function(){return c.apply(this,arguments)})},{key:"getAriaLabel",value:function(){return"Livestream"}},{key:"getDescription",value:function(){return this.getAriaLabel()}},{key:"className",get:function(){return"ilias-livestream-button"}},{key:"titleSize",get:function(){return"large"}},{key:"load",value:(o=u(s().mark((function t(){return s().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:this.title="Livestream",this.icon=i();case 2:case"end":return t.stop()}}),t,this)}))),function(){return o.apply(this,arguments)})},{key:"interactive",get:function(){return!1}},{key:"dynamicWidth",get:function(){return!0}}])&&function(t,e){for(var r=0;r{r.r(e),r.d(e,{default:()=>T});var n=r(46),o=r(527),i=r.n(o),a=r(72),s=r.n(a),c=r(825),u=r.n(c),l=r(659),f=r.n(l),h=r(56),p=r.n(h),d=r(540),y=r.n(d),v=r(113),g=r.n(v),m=r(362),b={};function w(t){return(w="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function x(){x=function(){return e};var t,e={},r=Object.prototype,n=r.hasOwnProperty,o=Object.defineProperty||function(t,e,r){t[e]=r.value},i="function"==typeof Symbol?Symbol:{},a=i.iterator||"@@iterator",s=i.asyncIterator||"@@asyncIterator",c=i.toStringTag||"@@toStringTag";function u(t,e,r){return Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{u({},"")}catch(t){u=function(t,e,r){return t[e]=r}}function l(t,e,r,n){var i=e&&e.prototype instanceof v?e:v,a=Object.create(i.prototype),s=new P(n||[]);return o(a,"_invoke",{value:C(t,r,s)}),a}function f(t,e,r){try{return{type:"normal",arg:t.call(e,r)}}catch(t){return{type:"throw",arg:t}}}e.wrap=l;var h="suspendedStart",p="executing",d="completed",y={};function v(){}function g(){}function m(){}var b={};u(b,a,(function(){return this}));var A=Object.getPrototypeOf,E=A&&A(A(j([])));E&&E!==r&&n.call(E,a)&&(b=E);var L=m.prototype=v.prototype=Object.create(b);function _(t){["next","throw","return"].forEach((function(e){u(t,e,(function(t){return this._invoke(e,t)}))}))}function k(t,e){function r(o,i,a,s){var c=f(t[o],t,i);if("throw"!==c.type){var u=c.arg,l=u.value;return l&&"object"==w(l)&&n.call(l,"__await")?e.resolve(l.__await).then((function(t){r("next",t,a,s)}),(function(t){r("throw",t,a,s)})):e.resolve(l).then((function(t){u.value=t,a(u)}),(function(t){return r("throw",t,a,s)}))}s(c.arg)}var i;o(this,"_invoke",{value:function(t,n){function o(){return new e((function(e,o){r(t,n,e,o)}))}return i=i?i.then(o,o):o()}})}function C(e,r,n){var o=h;return function(i,a){if(o===p)throw Error("Generator is already running");if(o===d){if("throw"===i)throw a;return{value:t,done:!0}}for(n.method=i,n.arg=a;;){var s=n.delegate;if(s){var c=S(s,n);if(c){if(c===y)continue;return c}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(o===h)throw o=d,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o=p;var u=f(e,r,n);if("normal"===u.type){if(o=n.done?d:"suspendedYield",u.arg===y)continue;return{value:u.arg,done:n.done}}"throw"===u.type&&(o=d,n.method="throw",n.arg=u.arg)}}}function S(e,r){var n=r.method,o=e.iterator[n];if(o===t)return r.delegate=null,"throw"===n&&e.iterator.return&&(r.method="return",r.arg=t,S(e,r),"throw"===r.method)||"return"!==n&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+n+"' method")),y;var i=f(o,e.iterator,r.arg);if("throw"===i.type)return r.method="throw",r.arg=i.arg,r.delegate=null,y;var a=i.arg;return a?a.done?(r[e.resultName]=a.value,r.next=e.nextLoc,"return"!==r.method&&(r.method="next",r.arg=t),r.delegate=null,y):a:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,y)}function O(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function T(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function P(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(O,this),this.reset(!0)}function j(e){if(e||""===e){var r=e[a];if(r)return r.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var o=-1,i=function r(){for(;++o=0;--i){var a=this.tryEntries[i],s=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var c=n.call(a,"catchLoc"),u=n.call(a,"finallyLoc");if(c&&u){if(this.prev=0;--r){var o=this.tryEntries[r];if(o.tryLoc<=this.prev&&n.call(o,"finallyLoc")&&this.prev=0;--e){var r=this.tryEntries[e];if(r.finallyLoc===t)return this.complete(r.completion,r.afterLoc),T(r),y}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var r=this.tryEntries[e];if(r.tryLoc===t){var n=r.completion;if("throw"===n.type){var o=n.arg;T(r)}return o}}throw Error("illegal catch attempt")},delegateYield:function(e,r,n){return this.delegate={iterator:j(e),resultName:r,nextLoc:n},"next"===this.method&&(this.arg=t),y}},e}function A(t,e,r,n,o,i,a){try{var s=t[i](a),c=s.value}catch(t){return void r(t)}s.done?e(c):Promise.resolve(c).then(n,o)}function E(t){return function(){var e=this,r=arguments;return new Promise((function(n,o){var i=t.apply(e,r);function a(t){A(i,n,o,a,s,"next",t)}function s(t){A(i,n,o,a,s,"throw",t)}a(void 0)}))}}function L(t){var e=function(t){if("object"!=w(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var r=e.call(t,"string");if("object"!=w(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==w(e)?e:e+""}function _(){try{var t=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(t){}return(_=function(){return!!t})()}function k(t,e,r,n){var o=C(S(1&n?t.prototype:t),e,r);return 2&n&&"function"==typeof o?function(t){return o.apply(r,t)}:o}function C(){return(C="undefined"!=typeof Reflect&&Reflect.get?Reflect.get.bind():function(t,e,r){var n=function(t,e){for(;!{}.hasOwnProperty.call(t,e)&&null!==(t=S(t)););return t}(t,e);if(n){var o=Object.getOwnPropertyDescriptor(n,e);return o.get?o.get.call(arguments.length<3?t:r):o.value}}).apply(null,arguments)}function S(t){return(S=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function O(t,e){return(O=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t})(t,e)}b.styleTagTransform=g(),b.setAttributes=p(),b.insert=f().bind(null,"head"),b.domAPI=u(),b.insertStyleElement=y(),s()(m.A,b),m.A&&m.A.locals&&m.A.locals;var T=function(t){function e(){return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),function(t,e,r){return e=S(e),function(t,e){if(e&&("object"==w(e)||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t)}(t,_()?Reflect.construct(e,r||[],S(t).constructor):e.apply(t,r))}(this,e,arguments)}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&O(t,e)}(e,t),r=e,(o=[{key:"moveable",get:function(){return!0}},{key:"resizeable",get:function(){return!0}},{key:"popUpType",get:function(){return"no-modal"}},{key:"closeActions",get:function(){return{clickOutside:!1,closeButton:!0}}},{key:"customPopUpClass",get:function(){return"transcription-plugin-popup"}},{key:"menuTitle",get:function(){return"Transcriptions"}},{key:"isEnabled",value:(c=E(x().mark((function t(){var r,n;return x().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,k(e,"isEnabled",this,3)([]);case 2:return n=t.sent,this.transcriptions=(null==this||null===(r=this.player)||void 0===r||null===(r=r.videoManifest)||void 0===r||null===(r=r.transcriptions)||void 0===r?void 0:r.filter((function(t){return""!=(null==t?void 0:t.text)})))||[],t.abrupt("return",n&&this.transcriptions.length>0);case 5:case"end":return t.stop()}}),t,this)}))),function(){return c.apply(this,arguments)})},{key:"load",value:(s=E(x().mark((function t(){return x().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:this.icon=this.player.getCustomPluginIcon(this.name,"buttonIcon")||i();case 1:case"end":return t.stop()}}),t,this)}))),function(){return s.apply(this,arguments)})},{key:"rebuildList",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",r=this.player.videoContainer;this._transcriptionsContainer.innerHTML="",this.transcriptions.filter((function(t){return!r.isTrimEnabled||t.time>r.trimStart&&t.time\n ').concat(e.text,'\n
\n ').concat(n.utils.secondsToTime(a),"\n ").concat(e.text,"\n
\n "),t._transcriptionsContainer).addEventListener("click",function(){var n=E(x().mark((function n(o){var i;return x().wrap((function(n){for(;;)switch(n.prev=n.next){case 0:i=r.isTrimEnabled?r.trimStart:0,t.player.videoContainer.setCurrentTime(e.time-i),o.stopPropagation();case 3:case"end":return n.stop()}}),n)})));return function(t){return n.apply(this,arguments)}}())}))}},{key:"getContent",value:(a=E(x().mark((function t(){var e,r,o,i=this;return x().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return e=(0,n.createElementWithHtmlText)('
'),(r=(0,n.createElementWithHtmlText)(''),e)).addEventListener("click",(function(t){return t.stopPropagation()})),r.addEventListener("keyup",(function(t){t.stopPropagation(),i.rebuildList(t.target.value)})),o=(0,n.createElementWithHtmlText)('
    ',e),this._transcriptionsContainer=o,this.rebuildList(),t.abrupt("return",e);case 8:case"end":return t.stop()}}),t,this)}))),function(){return a.apply(this,arguments)})}])&&function(t,e){for(var r=0;r{r.r(e),r.d(e,{default:()=>d});var n=r(46),o=r(883),i=r.n(o);function a(t){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function s(){s=function(){return e};var t,e={},r=Object.prototype,n=r.hasOwnProperty,o=Object.defineProperty||function(t,e,r){t[e]=r.value},i="function"==typeof Symbol?Symbol:{},c=i.iterator||"@@iterator",u=i.asyncIterator||"@@asyncIterator",l=i.toStringTag||"@@toStringTag";function f(t,e,r){return Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{f({},"")}catch(t){f=function(t,e,r){return t[e]=r}}function h(t,e,r,n){var i=e&&e.prototype instanceof m?e:m,a=Object.create(i.prototype),s=new P(n||[]);return o(a,"_invoke",{value:C(t,r,s)}),a}function p(t,e,r){try{return{type:"normal",arg:t.call(e,r)}}catch(t){return{type:"throw",arg:t}}}e.wrap=h;var d="suspendedStart",y="executing",v="completed",g={};function m(){}function b(){}function w(){}var x={};f(x,c,(function(){return this}));var A=Object.getPrototypeOf,E=A&&A(A(j([])));E&&E!==r&&n.call(E,c)&&(x=E);var L=w.prototype=m.prototype=Object.create(x);function _(t){["next","throw","return"].forEach((function(e){f(t,e,(function(t){return this._invoke(e,t)}))}))}function k(t,e){function r(o,i,s,c){var u=p(t[o],t,i);if("throw"!==u.type){var l=u.arg,f=l.value;return f&&"object"==a(f)&&n.call(f,"__await")?e.resolve(f.__await).then((function(t){r("next",t,s,c)}),(function(t){r("throw",t,s,c)})):e.resolve(f).then((function(t){l.value=t,s(l)}),(function(t){return r("throw",t,s,c)}))}c(u.arg)}var i;o(this,"_invoke",{value:function(t,n){function o(){return new e((function(e,o){r(t,n,e,o)}))}return i=i?i.then(o,o):o()}})}function C(e,r,n){var o=d;return function(i,a){if(o===y)throw Error("Generator is already running");if(o===v){if("throw"===i)throw a;return{value:t,done:!0}}for(n.method=i,n.arg=a;;){var s=n.delegate;if(s){var c=S(s,n);if(c){if(c===g)continue;return c}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(o===d)throw o=v,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o=y;var u=p(e,r,n);if("normal"===u.type){if(o=n.done?v:"suspendedYield",u.arg===g)continue;return{value:u.arg,done:n.done}}"throw"===u.type&&(o=v,n.method="throw",n.arg=u.arg)}}}function S(e,r){var n=r.method,o=e.iterator[n];if(o===t)return r.delegate=null,"throw"===n&&e.iterator.return&&(r.method="return",r.arg=t,S(e,r),"throw"===r.method)||"return"!==n&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+n+"' method")),g;var i=p(o,e.iterator,r.arg);if("throw"===i.type)return r.method="throw",r.arg=i.arg,r.delegate=null,g;var a=i.arg;return a?a.done?(r[e.resultName]=a.value,r.next=e.nextLoc,"return"!==r.method&&(r.method="next",r.arg=t),r.delegate=null,g):a:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,g)}function O(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function T(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function P(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(O,this),this.reset(!0)}function j(e){if(e||""===e){var r=e[c];if(r)return r.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var o=-1,i=function r(){for(;++o=0;--i){var a=this.tryEntries[i],s=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var c=n.call(a,"catchLoc"),u=n.call(a,"finallyLoc");if(c&&u){if(this.prev=0;--r){var o=this.tryEntries[r];if(o.tryLoc<=this.prev&&n.call(o,"finallyLoc")&&this.prev=0;--e){var r=this.tryEntries[e];if(r.finallyLoc===t)return this.complete(r.completion,r.afterLoc),T(r),g}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var r=this.tryEntries[e];if(r.tryLoc===t){var n=r.completion;if("throw"===n.type){var o=n.arg;T(r)}return o}}throw Error("illegal catch attempt")},delegateYield:function(e,r,n){return this.delegate={iterator:j(e),resultName:r,nextLoc:n},"next"===this.method&&(this.arg=t),g}},e}function c(t,e,r,n,o,i,a){try{var s=t[i](a),c=s.value}catch(t){return void r(t)}s.done?e(c):Promise.resolve(c).then(n,o)}function u(t,e){for(var r=0;r{r.d(e,{A:()=>s});var n=r(601),o=r.n(n),i=r(314),a=r.n(i)()(o());a.push([t.id,"/* Transcriptions Plugin ILIAS */\n.popup-container.transcription-plugin-popup .popup-content.static-position {\n opacity: 0.6;\n}\n\n.popup-container.transcription-plugin-popup .popup-content {\n opacity: 1;\n}\n\n.popup-container.transcription-plugin-popup:hover .popup-content {\n opacity: 1;\n}\n\n.transcriptions-container {\n min-width: 300px;\n}\n\n.transcriptions-container input {\n width: 100%;\n}\n.popup-container.transcription-plugin-popup .popup-content {\n width: 50vw;\n}\n\n.popup-container.transcription-plugin-popup .popup-content .transcriptions-container {\n max-height: 80vh;\n display: flex;\n flex-direction: column;\n /* opacity: 1; */\n color: #ffffff;\n font-size: 14px;\n height: 100%\n}\n\n.popup-container.transcription-plugin-popup .popup-content.static-position .transcriptions-container {\n max-height: unset;\n}\n\n.transcriptions-list {\n overflow-y: auto;\n}\n\n.transcriptions-container ul {\n margin-block-start: 5px;\n margin-block-end: 5px;\n margin-inline-start: 3px;\n padding-inline-start: 0px;\n}\n\n.transcriptions-container ul li {\n display: flex;\n gap: 10px;\n margin-top: 3px;\n margin-right: 3px;\n padding-left: 5px;\n padding-right: 5px;\n border: 1px rgba(0,0,0,0) solid;\n}\n\n.transcriptions-container ul li:hover {\n border: 1px lightsalmon dashed;\n cursor: pointer;\n}\n\n.transcriptions-container ul li img {\n max-width: 160px;\n max-height: 90px;\n}\n.transcriptions-container ul li .details {\n font-weight: normal;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.transcriptions-container ul li .details .timepoint {\n font-size: 13px;\n font-weight: bold;\n}\n",""]);const s=a},314:t=>{t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var r="",n=void 0!==e[5];return e[4]&&(r+="@supports (".concat(e[4],") {")),e[2]&&(r+="@media ".concat(e[2]," {")),n&&(r+="@layer".concat(e[5].length>0?" ".concat(e[5]):""," {")),r+=t(e),n&&(r+="}"),e[2]&&(r+="}"),e[4]&&(r+="}"),r})).join("")},e.i=function(t,r,n,o,i){"string"==typeof t&&(t=[[null,t,void 0]]);var a={};if(n)for(var s=0;s0?" ".concat(l[5]):""," {").concat(l[1],"}")),l[5]=i),r&&(l[2]?(l[1]="@media ".concat(l[2]," {").concat(l[1],"}"),l[2]=r):l[2]=r),o&&(l[4]?(l[1]="@supports (".concat(l[4],") {").concat(l[1],"}"),l[4]=o):l[4]="".concat(o)),e.push(l))}},e}},601:t=>{t.exports=function(t){return t[1]}},692:function(t,e){var r;!function(e,r){"object"==typeof t.exports?t.exports=e.document?r(e,!0):function(t){if(!t.document)throw new Error("jQuery requires a window with a document");return r(t)}:r(e)}("undefined"!=typeof window?window:this,(function(n,o){var i=[],a=Object.getPrototypeOf,s=i.slice,c=i.flat?function(t){return i.flat.call(t)}:function(t){return i.concat.apply([],t)},u=i.push,l=i.indexOf,f={},h=f.toString,p=f.hasOwnProperty,d=p.toString,y=d.call(Object),v={},g=function(t){return"function"==typeof t&&"number"!=typeof t.nodeType&&"function"!=typeof t.item},m=function(t){return null!=t&&t===t.window},b=n.document,w={type:!0,src:!0,nonce:!0,noModule:!0};function x(t,e,r){var n,o,i=(r=r||b).createElement("script");if(i.text=t,e)for(n in w)(o=e[n]||e.getAttribute&&e.getAttribute(n))&&i.setAttribute(n,o);r.head.appendChild(i).parentNode.removeChild(i)}function A(t){return null==t?t+"":"object"==typeof t||"function"==typeof t?f[h.call(t)]||"object":typeof t}var E="3.7.1",L=/HTML$/i,_=function(t,e){return new _.fn.init(t,e)};function k(t){var e=!!t&&"length"in t&&t.length,r=A(t);return!g(t)&&!m(t)&&("array"===r||0===e||"number"==typeof e&&e>0&&e-1 in t)}function C(t,e){return t.nodeName&&t.nodeName.toLowerCase()===e.toLowerCase()}_.fn=_.prototype={jquery:E,constructor:_,length:0,toArray:function(){return s.call(this)},get:function(t){return null==t?s.call(this):t<0?this[t+this.length]:this[t]},pushStack:function(t){var e=_.merge(this.constructor(),t);return e.prevObject=this,e},each:function(t){return _.each(this,t)},map:function(t){return this.pushStack(_.map(this,(function(e,r){return t.call(e,r,e)})))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(_.grep(this,(function(t,e){return(e+1)%2})))},odd:function(){return this.pushStack(_.grep(this,(function(t,e){return e%2})))},eq:function(t){var e=this.length,r=+t+(t<0?e:0);return this.pushStack(r>=0&&r+~]|"+P+")"+P+"*"),U=new RegExp(P+"|>"),$=new RegExp(N),H=new RegExp("^"+I+"$"),V={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+R),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:new RegExp("^(?:"+k+")$","i"),needsContext:new RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,W=/[+~]/,q=new RegExp("\\\\[\\da-fA-F]{1,6}"+P+"?|\\\\([^\\r\\n\\f])","g"),Z=function(t,e){var r="0x"+t.slice(1)-65536;return e||(r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320))},X=function(){ct()},Q=ht((function(t){return!0===t.disabled&&C(t,"fieldset")}),{dir:"parentNode",next:"legend"});try{y.apply(i=s.call(D.childNodes),D.childNodes),i[D.childNodes.length].nodeType}catch(t){y={apply:function(t,e){B.apply(t,s.call(e))},call:function(t){B.apply(t,s.call(arguments,1))}}}function J(t,e,r,n){var o,i,a,s,u,l,p,d=e&&e.ownerDocument,m=e?e.nodeType:9;if(r=r||[],"string"!=typeof t||!t||1!==m&&9!==m&&11!==m)return r;if(!n&&(ct(e),e=e||c,f)){if(11!==m&&(u=z.exec(t)))if(o=u[1]){if(9===m){if(!(a=e.getElementById(o)))return r;if(a.id===o)return y.call(r,a),r}else if(d&&(a=d.getElementById(o))&&J.contains(e,a)&&a.id===o)return y.call(r,a),r}else{if(u[2])return y.apply(r,e.getElementsByTagName(t)),r;if((o=u[3])&&e.getElementsByClassName)return y.apply(r,e.getElementsByClassName(o)),r}if(!(E[t+" "]||h&&h.test(t))){if(p=t,d=e,1===m&&(U.test(t)||G.test(t))){for((d=W.test(t)&&st(e.parentNode)||e)==e&&v.scope||((s=e.getAttribute("id"))?s=_.escapeSelector(s):e.setAttribute("id",s=g)),i=(l=lt(t)).length;i--;)l[i]=(s?"#"+s:":scope")+" "+ft(l[i]);p=l.join(",")}try{return y.apply(r,d.querySelectorAll(p)),r}catch(e){E(t,!0)}finally{s===g&&e.removeAttribute("id")}}}return mt(t.replace(j,"$1"),e,r,n)}function tt(){var t=[];return function r(n,o){return t.push(n+" ")>e.cacheLength&&delete r[t.shift()],r[n+" "]=o}}function et(t){return t[g]=!0,t}function rt(t){var e=c.createElement("fieldset");try{return!!t(e)}catch(t){return!1}finally{e.parentNode&&e.parentNode.removeChild(e),e=null}}function nt(t){return function(e){return C(e,"input")&&e.type===t}}function ot(t){return function(e){return(C(e,"input")||C(e,"button"))&&e.type===t}}function it(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&Q(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function at(t){return et((function(e){return e=+e,et((function(r,n){for(var o,i=t([],r.length,e),a=i.length;a--;)r[o=i[a]]&&(r[o]=!(n[o]=r[o]))}))}))}function st(t){return t&&void 0!==t.getElementsByTagName&&t}function ct(t){var r,n=t?t.ownerDocument||t:D;return n!=c&&9===n.nodeType&&n.documentElement?(u=(c=n).documentElement,f=!_.isXMLDoc(c),d=u.matches||u.webkitMatchesSelector||u.msMatchesSelector,u.msMatchesSelector&&D!=c&&(r=c.defaultView)&&r.top!==r&&r.addEventListener("unload",X),v.getById=rt((function(t){return u.appendChild(t).id=_.expando,!c.getElementsByName||!c.getElementsByName(_.expando).length})),v.disconnectedMatch=rt((function(t){return d.call(t,"*")})),v.scope=rt((function(){return c.querySelectorAll(":scope")})),v.cssHas=rt((function(){try{return c.querySelector(":has(*,:jqfake)"),!1}catch(t){return!0}})),v.getById?(e.filter.ID=function(t){var e=t.replace(q,Z);return function(t){return t.getAttribute("id")===e}},e.find.ID=function(t,e){if(void 0!==e.getElementById&&f){var r=e.getElementById(t);return r?[r]:[]}}):(e.filter.ID=function(t){var e=t.replace(q,Z);return function(t){var r=void 0!==t.getAttributeNode&&t.getAttributeNode("id");return r&&r.value===e}},e.find.ID=function(t,e){if(void 0!==e.getElementById&&f){var r,n,o,i=e.getElementById(t);if(i){if((r=i.getAttributeNode("id"))&&r.value===t)return[i];for(o=e.getElementsByName(t),n=0;i=o[n++];)if((r=i.getAttributeNode("id"))&&r.value===t)return[i]}return[]}}),e.find.TAG=function(t,e){return void 0!==e.getElementsByTagName?e.getElementsByTagName(t):e.querySelectorAll(t)},e.find.CLASS=function(t,e){if(void 0!==e.getElementsByClassName&&f)return e.getElementsByClassName(t)},h=[],rt((function(t){var e;u.appendChild(t).innerHTML="",t.querySelectorAll("[selected]").length||h.push("\\["+P+"*(?:value|"+k+")"),t.querySelectorAll("[id~="+g+"-]").length||h.push("~="),t.querySelectorAll("a#"+g+"+*").length||h.push(".#.+[+~]"),t.querySelectorAll(":checked").length||h.push(":checked"),(e=c.createElement("input")).setAttribute("type","hidden"),t.appendChild(e).setAttribute("name","D"),u.appendChild(t).disabled=!0,2!==t.querySelectorAll(":disabled").length&&h.push(":enabled",":disabled"),(e=c.createElement("input")).setAttribute("name",""),t.appendChild(e),t.querySelectorAll("[name='']").length||h.push("\\["+P+"*name"+P+"*="+P+"*(?:''|\"\")")})),v.cssHas||h.push(":has"),h=h.length&&new RegExp(h.join("|")),L=function(t,e){if(t===e)return a=!0,0;var r=!t.compareDocumentPosition-!e.compareDocumentPosition;return r||(1&(r=(t.ownerDocument||t)==(e.ownerDocument||e)?t.compareDocumentPosition(e):1)||!v.sortDetached&&e.compareDocumentPosition(t)===r?t===c||t.ownerDocument==D&&J.contains(D,t)?-1:e===c||e.ownerDocument==D&&J.contains(D,e)?1:o?l.call(o,t)-l.call(o,e):0:4&r?-1:1)},c):c}for(t in J.matches=function(t,e){return J(t,null,null,e)},J.matchesSelector=function(t,e){if(ct(t),f&&!E[e+" "]&&(!h||!h.test(e)))try{var r=d.call(t,e);if(r||v.disconnectedMatch||t.document&&11!==t.document.nodeType)return r}catch(t){E(e,!0)}return J(e,c,null,[t]).length>0},J.contains=function(t,e){return(t.ownerDocument||t)!=c&&ct(t),_.contains(t,e)},J.attr=function(t,r){(t.ownerDocument||t)!=c&&ct(t);var n=e.attrHandle[r.toLowerCase()],o=n&&p.call(e.attrHandle,r.toLowerCase())?n(t,r,!f):void 0;return void 0!==o?o:t.getAttribute(r)},J.error=function(t){throw new Error("Syntax error, unrecognized expression: "+t)},_.uniqueSort=function(t){var e,r=[],n=0,i=0;if(a=!v.sortStable,o=!v.sortStable&&s.call(t,0),O.call(t,L),a){for(;e=t[i++];)e===t[i]&&(n=r.push(i));for(;n--;)T.call(t,r[n],1)}return o=null,t},_.fn.uniqueSort=function(){return this.pushStack(_.uniqueSort(s.apply(this)))},(e=_.expr={cacheLength:50,createPseudo:et,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(t){return t[1]=t[1].replace(q,Z),t[3]=(t[3]||t[4]||t[5]||"").replace(q,Z),"~="===t[2]&&(t[3]=" "+t[3]+" "),t.slice(0,4)},CHILD:function(t){return t[1]=t[1].toLowerCase(),"nth"===t[1].slice(0,3)?(t[3]||J.error(t[0]),t[4]=+(t[4]?t[5]+(t[6]||1):2*("even"===t[3]||"odd"===t[3])),t[5]=+(t[7]+t[8]||"odd"===t[3])):t[3]&&J.error(t[0]),t},PSEUDO:function(t){var e,r=!t[6]&&t[2];return V.CHILD.test(t[0])?null:(t[3]?t[2]=t[4]||t[5]||"":r&&$.test(r)&&(e=lt(r,!0))&&(e=r.indexOf(")",r.length-e)-r.length)&&(t[0]=t[0].slice(0,e),t[2]=r.slice(0,e)),t.slice(0,3))}},filter:{TAG:function(t){var e=t.replace(q,Z).toLowerCase();return"*"===t?function(){return!0}:function(t){return C(t,e)}},CLASS:function(t){var e=w[t+" "];return e||(e=new RegExp("(^|"+P+")"+t+"("+P+"|$)"))&&w(t,(function(t){return e.test("string"==typeof t.className&&t.className||void 0!==t.getAttribute&&t.getAttribute("class")||"")}))},ATTR:function(t,e,r){return function(n){var o=J.attr(n,t);return null==o?"!="===e:!e||(o+="","="===e?o===r:"!="===e?o!==r:"^="===e?r&&0===o.indexOf(r):"*="===e?r&&o.indexOf(r)>-1:"$="===e?r&&o.slice(-r.length)===r:"~="===e?(" "+o.replace(F," ")+" ").indexOf(r)>-1:"|="===e&&(o===r||o.slice(0,r.length+1)===r+"-"))}},CHILD:function(t,e,r,n,o){var i="nth"!==t.slice(0,3),a="last"!==t.slice(-4),s="of-type"===e;return 1===n&&0===o?function(t){return!!t.parentNode}:function(e,r,c){var u,l,f,h,p,d=i!==a?"nextSibling":"previousSibling",y=e.parentNode,v=s&&e.nodeName.toLowerCase(),b=!c&&!s,w=!1;if(y){if(i){for(;d;){for(f=e;f=f[d];)if(s?C(f,v):1===f.nodeType)return!1;p=d="only"===t&&!p&&"nextSibling"}return!0}if(p=[a?y.firstChild:y.lastChild],a&&b){for(w=(h=(u=(l=y[g]||(y[g]={}))[t]||[])[0]===m&&u[1])&&u[2],f=h&&y.childNodes[h];f=++h&&f&&f[d]||(w=h=0)||p.pop();)if(1===f.nodeType&&++w&&f===e){l[t]=[m,h,w];break}}else if(b&&(w=h=(u=(l=e[g]||(e[g]={}))[t]||[])[0]===m&&u[1]),!1===w)for(;(f=++h&&f&&f[d]||(w=h=0)||p.pop())&&(!(s?C(f,v):1===f.nodeType)||!++w||(b&&((l=f[g]||(f[g]={}))[t]=[m,w]),f!==e)););return(w-=o)===n||w%n==0&&w/n>=0}}},PSEUDO:function(t,r){var n,o=e.pseudos[t]||e.setFilters[t.toLowerCase()]||J.error("unsupported pseudo: "+t);return o[g]?o(r):o.length>1?(n=[t,t,"",r],e.setFilters.hasOwnProperty(t.toLowerCase())?et((function(t,e){for(var n,i=o(t,r),a=i.length;a--;)t[n=l.call(t,i[a])]=!(e[n]=i[a])})):function(t){return o(t,0,n)}):o}},pseudos:{not:et((function(t){var e=[],r=[],n=gt(t.replace(j,"$1"));return n[g]?et((function(t,e,r,o){for(var i,a=n(t,null,o,[]),s=t.length;s--;)(i=a[s])&&(t[s]=!(e[s]=i))})):function(t,o,i){return e[0]=t,n(e,null,i,r),e[0]=null,!r.pop()}})),has:et((function(t){return function(e){return J(t,e).length>0}})),contains:et((function(t){return t=t.replace(q,Z),function(e){return(e.textContent||_.text(e)).indexOf(t)>-1}})),lang:et((function(t){return H.test(t||"")||J.error("unsupported lang: "+t),t=t.replace(q,Z).toLowerCase(),function(e){var r;do{if(r=f?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(r=r.toLowerCase())===t||0===r.indexOf(t+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}})),target:function(t){var e=n.location&&n.location.hash;return e&&e.slice(1)===t.id},root:function(t){return t===u},focus:function(t){return t===function(){try{return c.activeElement}catch(t){}}()&&c.hasFocus()&&!!(t.type||t.href||~t.tabIndex)},enabled:it(!1),disabled:it(!0),checked:function(t){return C(t,"input")&&!!t.checked||C(t,"option")&&!!t.selected},selected:function(t){return t.parentNode&&t.parentNode.selectedIndex,!0===t.selected},empty:function(t){for(t=t.firstChild;t;t=t.nextSibling)if(t.nodeType<6)return!1;return!0},parent:function(t){return!e.pseudos.empty(t)},header:function(t){return K.test(t.nodeName)},input:function(t){return Y.test(t.nodeName)},button:function(t){return C(t,"input")&&"button"===t.type||C(t,"button")},text:function(t){var e;return C(t,"input")&&"text"===t.type&&(null==(e=t.getAttribute("type"))||"text"===e.toLowerCase())},first:at((function(){return[0]})),last:at((function(t,e){return[e-1]})),eq:at((function(t,e,r){return[r<0?r+e:r]})),even:at((function(t,e){for(var r=0;re?e:r;--n>=0;)t.push(n);return t})),gt:at((function(t,e,r){for(var n=r<0?r+e:r;++n1?function(e,r,n){for(var o=t.length;o--;)if(!t[o](e,r,n))return!1;return!0}:t[0]}function dt(t,e,r,n,o){for(var i,a=[],s=0,c=t.length,u=null!=e;s-1&&(i[u]=!(a[u]=h))}}else p=dt(p===a?p.splice(g,p.length):p),o?o(null,a,p,c):y.apply(a,p)}))}function vt(t){for(var n,o,i,a=t.length,s=e.relative[t[0].type],c=s||e.relative[" "],u=s?1:0,f=ht((function(t){return t===n}),c,!0),h=ht((function(t){return l.call(n,t)>-1}),c,!0),p=[function(t,e,o){var i=!s&&(o||e!=r)||((n=e).nodeType?f(t,e,o):h(t,e,o));return n=null,i}];u1&&pt(p),u>1&&ft(t.slice(0,u-1).concat({value:" "===t[u-2].type?"*":""})).replace(j,"$1"),o,u0,i=t.length>0,a=function(a,s,u,l,h){var p,d,v,g=0,b="0",w=a&&[],x=[],A=r,E=a||i&&e.find.TAG("*",h),L=m+=null==A?1:Math.random()||.1,k=E.length;for(h&&(r=s==c||s||h);b!==k&&null!=(p=E[b]);b++){if(i&&p){for(d=0,s||p.ownerDocument==c||(ct(p),u=!f);v=t[d++];)if(v(p,s||c,u)){y.call(l,p);break}h&&(m=L)}o&&((p=!v&&p)&&g--,a&&w.push(p))}if(g+=b,o&&b!==g){for(d=0;v=n[d++];)v(w,x,s,u);if(a){if(g>0)for(;b--;)w[b]||x[b]||(x[b]=S.call(l));x=dt(x)}y.apply(l,x),h&&!a&&x.length>0&&g+n.length>1&&_.uniqueSort(l)}return h&&(m=L,r=A),w};return o?et(a):a}(a,i))).selector=t}return s}function mt(t,r,n,o){var i,a,s,c,u,l="function"==typeof t&&t,h=!o&<(t=l.selector||t);if(n=n||[],1===h.length){if((a=h[0]=h[0].slice(0)).length>2&&"ID"===(s=a[0]).type&&9===r.nodeType&&f&&e.relative[a[1].type]){if(!(r=(e.find.ID(s.matches[0].replace(q,Z),r)||[])[0]))return n;l&&(r=r.parentNode),t=t.slice(a.shift().value.length)}for(i=V.needsContext.test(t)?0:a.length;i--&&(s=a[i],!e.relative[c=s.type]);)if((u=e.find[c])&&(o=u(s.matches[0].replace(q,Z),W.test(a[0].type)&&st(r.parentNode)||r))){if(a.splice(i,1),!(t=o.length&&ft(a)))return y.apply(n,o),n;break}}return(l||gt(t,h))(o,r,!f,n,!r||W.test(t)&&st(r.parentNode)||r),n}ut.prototype=e.filters=e.pseudos,e.setFilters=new ut,v.sortStable=g.split("").sort(L).join("")===g,ct(),v.sortDetached=rt((function(t){return 1&t.compareDocumentPosition(c.createElement("fieldset"))})),_.find=J,_.expr[":"]=_.expr.pseudos,_.unique=_.uniqueSort,J.compile=gt,J.select=mt,J.setDocument=ct,J.tokenize=lt,J.escape=_.escapeSelector,J.getText=_.text,J.isXML=_.isXMLDoc,J.selectors=_.expr,J.support=_.support,J.uniqueSort=_.uniqueSort}();var N=function(t,e,r){for(var n=[],o=void 0!==r;(t=t[e])&&9!==t.nodeType;)if(1===t.nodeType){if(o&&_(t).is(r))break;n.push(t)}return n},F=function(t,e){for(var r=[];t;t=t.nextSibling)1===t.nodeType&&t!==e&&r.push(t);return r},M=_.expr.match.needsContext,G=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function U(t,e,r){return g(e)?_.grep(t,(function(t,n){return!!e.call(t,n,t)!==r})):e.nodeType?_.grep(t,(function(t){return t===e!==r})):"string"!=typeof e?_.grep(t,(function(t){return l.call(e,t)>-1!==r})):_.filter(e,t,r)}_.filter=function(t,e,r){var n=e[0];return r&&(t=":not("+t+")"),1===e.length&&1===n.nodeType?_.find.matchesSelector(n,t)?[n]:[]:_.find.matches(t,_.grep(e,(function(t){return 1===t.nodeType})))},_.fn.extend({find:function(t){var e,r,n=this.length,o=this;if("string"!=typeof t)return this.pushStack(_(t).filter((function(){for(e=0;e1?_.uniqueSort(r):r},filter:function(t){return this.pushStack(U(this,t||[],!1))},not:function(t){return this.pushStack(U(this,t||[],!0))},is:function(t){return!!U(this,"string"==typeof t&&M.test(t)?_(t):t||[],!1).length}});var $,H=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(_.fn.init=function(t,e,r){var n,o;if(!t)return this;if(r=r||$,"string"==typeof t){if(!(n="<"===t[0]&&">"===t[t.length-1]&&t.length>=3?[null,t,null]:H.exec(t))||!n[1]&&e)return!e||e.jquery?(e||r).find(t):this.constructor(e).find(t);if(n[1]){if(e=e instanceof _?e[0]:e,_.merge(this,_.parseHTML(n[1],e&&e.nodeType?e.ownerDocument||e:b,!0)),G.test(n[1])&&_.isPlainObject(e))for(n in e)g(this[n])?this[n](e[n]):this.attr(n,e[n]);return this}return(o=b.getElementById(n[2]))&&(this[0]=o,this.length=1),this}return t.nodeType?(this[0]=t,this.length=1,this):g(t)?void 0!==r.ready?r.ready(t):t(_):_.makeArray(t,this)}).prototype=_.fn,$=_(b);var V=/^(?:parents|prev(?:Until|All))/,Y={children:!0,contents:!0,next:!0,prev:!0};function K(t,e){for(;(t=t[e])&&1!==t.nodeType;);return t}_.fn.extend({has:function(t){var e=_(t,this),r=e.length;return this.filter((function(){for(var t=0;t-1:1===r.nodeType&&_.find.matchesSelector(r,t))){i.push(r);break}return this.pushStack(i.length>1?_.uniqueSort(i):i)},index:function(t){return t?"string"==typeof t?l.call(_(t),this[0]):l.call(this,t.jquery?t[0]:t):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(t,e){return this.pushStack(_.uniqueSort(_.merge(this.get(),_(t,e))))},addBack:function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}}),_.each({parent:function(t){var e=t.parentNode;return e&&11!==e.nodeType?e:null},parents:function(t){return N(t,"parentNode")},parentsUntil:function(t,e,r){return N(t,"parentNode",r)},next:function(t){return K(t,"nextSibling")},prev:function(t){return K(t,"previousSibling")},nextAll:function(t){return N(t,"nextSibling")},prevAll:function(t){return N(t,"previousSibling")},nextUntil:function(t,e,r){return N(t,"nextSibling",r)},prevUntil:function(t,e,r){return N(t,"previousSibling",r)},siblings:function(t){return F((t.parentNode||{}).firstChild,t)},children:function(t){return F(t.firstChild)},contents:function(t){return null!=t.contentDocument&&a(t.contentDocument)?t.contentDocument:(C(t,"template")&&(t=t.content||t),_.merge([],t.childNodes))}},(function(t,e){_.fn[t]=function(r,n){var o=_.map(this,e,r);return"Until"!==t.slice(-5)&&(n=r),n&&"string"==typeof n&&(o=_.filter(n,o)),this.length>1&&(Y[t]||_.uniqueSort(o),V.test(t)&&o.reverse()),this.pushStack(o)}}));var z=/[^\x20\t\r\n\f]+/g;function W(t){return t}function q(t){throw t}function Z(t,e,r,n){var o;try{t&&g(o=t.promise)?o.call(t).done(e).fail(r):t&&g(o=t.then)?o.call(t,e,r):e.apply(void 0,[t].slice(n))}catch(t){r.apply(void 0,[t])}}_.Callbacks=function(t){t="string"==typeof t?function(t){var e={};return _.each(t.match(z)||[],(function(t,r){e[r]=!0})),e}(t):_.extend({},t);var e,r,n,o,i=[],a=[],s=-1,c=function(){for(o=o||t.once,n=e=!0;a.length;s=-1)for(r=a.shift();++s-1;)i.splice(r,1),r<=s&&s--})),this},has:function(t){return t?_.inArray(t,i)>-1:i.length>0},empty:function(){return i&&(i=[]),this},disable:function(){return o=a=[],i=r="",this},disabled:function(){return!i},lock:function(){return o=a=[],r||e||(i=r=""),this},locked:function(){return!!o},fireWith:function(t,r){return o||(r=[t,(r=r||[]).slice?r.slice():r],a.push(r),e||c()),this},fire:function(){return u.fireWith(this,arguments),this},fired:function(){return!!n}};return u},_.extend({Deferred:function(t){var e=[["notify","progress",_.Callbacks("memory"),_.Callbacks("memory"),2],["resolve","done",_.Callbacks("once memory"),_.Callbacks("once memory"),0,"resolved"],["reject","fail",_.Callbacks("once memory"),_.Callbacks("once memory"),1,"rejected"]],r="pending",o={state:function(){return r},always:function(){return i.done(arguments).fail(arguments),this},catch:function(t){return o.then(null,t)},pipe:function(){var t=arguments;return _.Deferred((function(r){_.each(e,(function(e,n){var o=g(t[n[4]])&&t[n[4]];i[n[1]]((function(){var t=o&&o.apply(this,arguments);t&&g(t.promise)?t.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[n[0]+"With"](this,o?[t]:arguments)}))})),t=null})).promise()},then:function(t,r,o){var i=0;function a(t,e,r,o){return function(){var s=this,c=arguments,u=function(){var n,u;if(!(t=i&&(r!==q&&(s=void 0,c=[n]),e.rejectWith(s,c))}};t?l():(_.Deferred.getErrorHook?l.error=_.Deferred.getErrorHook():_.Deferred.getStackHook&&(l.error=_.Deferred.getStackHook()),n.setTimeout(l))}}return _.Deferred((function(n){e[0][3].add(a(0,n,g(o)?o:W,n.notifyWith)),e[1][3].add(a(0,n,g(t)?t:W)),e[2][3].add(a(0,n,g(r)?r:q))})).promise()},promise:function(t){return null!=t?_.extend(t,o):o}},i={};return _.each(e,(function(t,n){var a=n[2],s=n[5];o[n[1]]=a.add,s&&a.add((function(){r=s}),e[3-t][2].disable,e[3-t][3].disable,e[0][2].lock,e[0][3].lock),a.add(n[3].fire),i[n[0]]=function(){return i[n[0]+"With"](this===i?void 0:this,arguments),this},i[n[0]+"With"]=a.fireWith})),o.promise(i),t&&t.call(i,i),i},when:function(t){var e=arguments.length,r=e,n=Array(r),o=s.call(arguments),i=_.Deferred(),a=function(t){return function(r){n[t]=this,o[t]=arguments.length>1?s.call(arguments):r,--e||i.resolveWith(n,o)}};if(e<=1&&(Z(t,i.done(a(r)).resolve,i.reject,!e),"pending"===i.state()||g(o[r]&&o[r].then)))return i.then();for(;r--;)Z(o[r],a(r),i.reject);return i.promise()}});var X=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;_.Deferred.exceptionHook=function(t,e){n.console&&n.console.warn&&t&&X.test(t.name)&&n.console.warn("jQuery.Deferred exception: "+t.message,t.stack,e)},_.readyException=function(t){n.setTimeout((function(){throw t}))};var Q=_.Deferred();function J(){b.removeEventListener("DOMContentLoaded",J),n.removeEventListener("load",J),_.ready()}_.fn.ready=function(t){return Q.then(t).catch((function(t){_.readyException(t)})),this},_.extend({isReady:!1,readyWait:1,ready:function(t){(!0===t?--_.readyWait:_.isReady)||(_.isReady=!0,!0!==t&&--_.readyWait>0||Q.resolveWith(b,[_]))}}),_.ready.then=Q.then,"complete"===b.readyState||"loading"!==b.readyState&&!b.documentElement.doScroll?n.setTimeout(_.ready):(b.addEventListener("DOMContentLoaded",J),n.addEventListener("load",J));var tt=function(t,e,r,n,o,i,a){var s=0,c=t.length,u=null==r;if("object"===A(r))for(s in o=!0,r)tt(t,e,s,r[s],!0,i,a);else if(void 0!==n&&(o=!0,g(n)||(a=!0),u&&(a?(e.call(t,n),e=null):(u=e,e=function(t,e,r){return u.call(_(t),r)})),e))for(;s1,null,!0)},removeData:function(t){return this.each((function(){ct.remove(this,t)}))}}),_.extend({queue:function(t,e,r){var n;if(t)return e=(e||"fx")+"queue",n=st.get(t,e),r&&(!n||Array.isArray(r)?n=st.access(t,e,_.makeArray(r)):n.push(r)),n||[]},dequeue:function(t,e){e=e||"fx";var r=_.queue(t,e),n=r.length,o=r.shift(),i=_._queueHooks(t,e);"inprogress"===o&&(o=r.shift(),n--),o&&("fx"===e&&r.unshift("inprogress"),delete i.stop,o.call(t,(function(){_.dequeue(t,e)}),i)),!n&&i&&i.empty.fire()},_queueHooks:function(t,e){var r=e+"queueHooks";return st.get(t,r)||st.access(t,r,{empty:_.Callbacks("once memory").add((function(){st.remove(t,[e+"queue",r])}))})}}),_.fn.extend({queue:function(t,e){var r=2;return"string"!=typeof t&&(e=t,t="fx",r--),arguments.length\x20\t\r\n\f]*)/i,Ct=/^$|^module$|\/(?:java|ecma)script/i;Et=b.createDocumentFragment().appendChild(b.createElement("div")),(Lt=b.createElement("input")).setAttribute("type","radio"),Lt.setAttribute("checked","checked"),Lt.setAttribute("name","t"),Et.appendChild(Lt),v.checkClone=Et.cloneNode(!0).cloneNode(!0).lastChild.checked,Et.innerHTML="",v.noCloneChecked=!!Et.cloneNode(!0).lastChild.defaultValue,Et.innerHTML="",v.option=!!Et.lastChild;var St={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function Ot(t,e){var r;return r=void 0!==t.getElementsByTagName?t.getElementsByTagName(e||"*"):void 0!==t.querySelectorAll?t.querySelectorAll(e||"*"):[],void 0===e||e&&C(t,e)?_.merge([t],r):r}function Tt(t,e){for(var r=0,n=t.length;r",""]);var Pt=/<|&#?\w+;/;function jt(t,e,r,n,o){for(var i,a,s,c,u,l,f=e.createDocumentFragment(),h=[],p=0,d=t.length;p-1)o&&o.push(i);else if(u=vt(i),a=Ot(f.appendChild(i),"script"),u&&Tt(a),r)for(l=0;i=a[l++];)Ct.test(i.type||"")&&r.push(i);return f}var It=/^([^.]*)(?:\.(.+)|)/;function Rt(){return!0}function Dt(){return!1}function Bt(t,e,r,n,o,i){var a,s;if("object"==typeof e){for(s in"string"!=typeof r&&(n=n||r,r=void 0),e)Bt(t,s,r,n,e[s],i);return t}if(null==n&&null==o?(o=r,n=r=void 0):null==o&&("string"==typeof r?(o=n,n=void 0):(o=n,n=r,r=void 0)),!1===o)o=Dt;else if(!o)return t;return 1===i&&(a=o,(o=function(t){return _().off(t),a.apply(this,arguments)}).guid=a.guid||(a.guid=_.guid++)),t.each((function(){_.event.add(this,e,o,n,r)}))}function Nt(t,e,r){r?(st.set(t,e,!1),_.event.add(t,e,{namespace:!1,handler:function(t){var r,n=st.get(this,e);if(1&t.isTrigger&&this[e]){if(n)(_.event.special[e]||{}).delegateType&&t.stopPropagation();else if(n=s.call(arguments),st.set(this,e,n),this[e](),r=st.get(this,e),st.set(this,e,!1),n!==r)return t.stopImmediatePropagation(),t.preventDefault(),r}else n&&(st.set(this,e,_.event.trigger(n[0],n.slice(1),this)),t.stopPropagation(),t.isImmediatePropagationStopped=Rt)}})):void 0===st.get(t,e)&&_.event.add(t,e,Rt)}_.event={global:{},add:function(t,e,r,n,o){var i,a,s,c,u,l,f,h,p,d,y,v=st.get(t);if(it(t))for(r.handler&&(r=(i=r).handler,o=i.selector),o&&_.find.matchesSelector(yt,o),r.guid||(r.guid=_.guid++),(c=v.events)||(c=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return void 0!==_&&_.event.triggered!==e.type?_.event.dispatch.apply(t,arguments):void 0}),u=(e=(e||"").match(z)||[""]).length;u--;)p=y=(s=It.exec(e[u])||[])[1],d=(s[2]||"").split(".").sort(),p&&(f=_.event.special[p]||{},p=(o?f.delegateType:f.bindType)||p,f=_.event.special[p]||{},l=_.extend({type:p,origType:y,data:n,handler:r,guid:r.guid,selector:o,needsContext:o&&_.expr.match.needsContext.test(o),namespace:d.join(".")},i),(h=c[p])||((h=c[p]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,n,d,a)||t.addEventListener&&t.addEventListener(p,a)),f.add&&(f.add.call(t,l),l.handler.guid||(l.handler.guid=r.guid)),o?h.splice(h.delegateCount++,0,l):h.push(l),_.event.global[p]=!0)},remove:function(t,e,r,n,o){var i,a,s,c,u,l,f,h,p,d,y,v=st.hasData(t)&&st.get(t);if(v&&(c=v.events)){for(u=(e=(e||"").match(z)||[""]).length;u--;)if(p=y=(s=It.exec(e[u])||[])[1],d=(s[2]||"").split(".").sort(),p){for(f=_.event.special[p]||{},h=c[p=(n?f.delegateType:f.bindType)||p]||[],s=s[2]&&new RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=i=h.length;i--;)l=h[i],!o&&y!==l.origType||r&&r.guid!==l.guid||s&&!s.test(l.namespace)||n&&n!==l.selector&&("**"!==n||!l.selector)||(h.splice(i,1),l.selector&&h.delegateCount--,f.remove&&f.remove.call(t,l));a&&!h.length&&(f.teardown&&!1!==f.teardown.call(t,d,v.handle)||_.removeEvent(t,p,v.handle),delete c[p])}else for(p in c)_.event.remove(t,p+e[u],r,n,!0);_.isEmptyObject(c)&&st.remove(t,"handle events")}},dispatch:function(t){var e,r,n,o,i,a,s=new Array(arguments.length),c=_.event.fix(t),u=(st.get(this,"events")||Object.create(null))[c.type]||[],l=_.event.special[c.type]||{};for(s[0]=c,e=1;e=1))for(;u!==this;u=u.parentNode||this)if(1===u.nodeType&&("click"!==t.type||!0!==u.disabled)){for(i=[],a={},r=0;r-1:_.find(o,this,null,[u]).length),a[o]&&i.push(n);i.length&&s.push({elem:u,handlers:i})}return u=this,c\s*$/g;function Ut(t,e){return C(t,"table")&&C(11!==e.nodeType?e:e.firstChild,"tr")&&_(t).children("tbody")[0]||t}function $t(t){return t.type=(null!==t.getAttribute("type"))+"/"+t.type,t}function Ht(t){return"true/"===(t.type||"").slice(0,5)?t.type=t.type.slice(5):t.removeAttribute("type"),t}function Vt(t,e){var r,n,o,i,a,s;if(1===e.nodeType){if(st.hasData(t)&&(s=st.get(t).events))for(o in st.remove(e,"handle events"),s)for(r=0,n=s[o].length;r1&&"string"==typeof d&&!v.checkClone&&Mt.test(d))return t.each((function(o){var i=t.eq(o);y&&(e[0]=d.call(this,o,i.html())),Kt(i,e,r,n)}));if(h&&(i=(o=jt(e,t[0].ownerDocument,!1,t,n)).firstChild,1===o.childNodes.length&&(o=i),i||n)){for(s=(a=_.map(Ot(o,"script"),$t)).length;f0&&Tt(a,!c&&Ot(t,"script")),s},cleanData:function(t){for(var e,r,n,o=_.event.special,i=0;void 0!==(r=t[i]);i++)if(it(r)){if(e=r[st.expando]){if(e.events)for(n in e.events)o[n]?_.event.remove(r,n):_.removeEvent(r,n,e.handle);r[st.expando]=void 0}r[ct.expando]&&(r[ct.expando]=void 0)}}}),_.fn.extend({detach:function(t){return zt(this,t,!0)},remove:function(t){return zt(this,t)},text:function(t){return tt(this,(function(t){return void 0===t?_.text(this):this.empty().each((function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=t)}))}),null,t,arguments.length)},append:function(){return Kt(this,arguments,(function(t){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Ut(this,t).appendChild(t)}))},prepend:function(){return Kt(this,arguments,(function(t){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var e=Ut(this,t);e.insertBefore(t,e.firstChild)}}))},before:function(){return Kt(this,arguments,(function(t){this.parentNode&&this.parentNode.insertBefore(t,this)}))},after:function(){return Kt(this,arguments,(function(t){this.parentNode&&this.parentNode.insertBefore(t,this.nextSibling)}))},empty:function(){for(var t,e=0;null!=(t=this[e]);e++)1===t.nodeType&&(_.cleanData(Ot(t,!1)),t.textContent="");return this},clone:function(t,e){return t=null!=t&&t,e=null==e?t:e,this.map((function(){return _.clone(this,t,e)}))},html:function(t){return tt(this,(function(t){var e=this[0]||{},r=0,n=this.length;if(void 0===t&&1===e.nodeType)return e.innerHTML;if("string"==typeof t&&!Ft.test(t)&&!St[(kt.exec(t)||["",""])[1].toLowerCase()]){t=_.htmlPrefilter(t);try{for(;r=0&&(c+=Math.max(0,Math.ceil(t["offset"+e[0].toUpperCase()+e.slice(1)]-i-c-s-.5))||0),c+u}function le(t,e,r){var n=Zt(t),o=(!v.boxSizingReliable()||r)&&"border-box"===_.css(t,"boxSizing",!1,n),i=o,a=Jt(t,e,n),s="offset"+e[0].toUpperCase()+e.slice(1);if(Wt.test(a)){if(!r)return a;a="auto"}return(!v.boxSizingReliable()&&o||!v.reliableTrDimensions()&&C(t,"tr")||"auto"===a||!parseFloat(a)&&"inline"===_.css(t,"display",!1,n))&&t.getClientRects().length&&(o="border-box"===_.css(t,"boxSizing",!1,n),(i=s in t)&&(a=t[s])),(a=parseFloat(a)||0)+ue(t,e,r||(o?"border":"content"),i,n,a)+"px"}function fe(t,e,r,n,o){return new fe.prototype.init(t,e,r,n,o)}_.extend({cssHooks:{opacity:{get:function(t,e){if(e){var r=Jt(t,"opacity");return""===r?"1":r}}}},cssNumber:{animationIterationCount:!0,aspectRatio:!0,borderImageSlice:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,scale:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeMiterlimit:!0,strokeOpacity:!0},cssProps:{},style:function(t,e,r,n){if(t&&3!==t.nodeType&&8!==t.nodeType&&t.style){var o,i,a,s=ot(e),c=qt.test(e),u=t.style;if(c||(e=oe(s)),a=_.cssHooks[e]||_.cssHooks[s],void 0===r)return a&&"get"in a&&void 0!==(o=a.get(t,!1,n))?o:u[e];"string"==(i=typeof r)&&(o=pt.exec(r))&&o[1]&&(r=bt(t,e,o),i="number"),null!=r&&r==r&&("number"!==i||c||(r+=o&&o[3]||(_.cssNumber[s]?"":"px")),v.clearCloneStyle||""!==r||0!==e.indexOf("background")||(u[e]="inherit"),a&&"set"in a&&void 0===(r=a.set(t,r,n))||(c?u.setProperty(e,r):u[e]=r))}},css:function(t,e,r,n){var o,i,a,s=ot(e);return qt.test(e)||(e=oe(s)),(a=_.cssHooks[e]||_.cssHooks[s])&&"get"in a&&(o=a.get(t,!0,r)),void 0===o&&(o=Jt(t,e,n)),"normal"===o&&e in se&&(o=se[e]),""===r||r?(i=parseFloat(o),!0===r||isFinite(i)?i||0:o):o}}),_.each(["height","width"],(function(t,e){_.cssHooks[e]={get:function(t,r,n){if(r)return!ie.test(_.css(t,"display"))||t.getClientRects().length&&t.getBoundingClientRect().width?le(t,e,n):Xt(t,ae,(function(){return le(t,e,n)}))},set:function(t,r,n){var o,i=Zt(t),a=!v.scrollboxSize()&&"absolute"===i.position,s=(a||n)&&"border-box"===_.css(t,"boxSizing",!1,i),c=n?ue(t,e,n,s,i):0;return s&&a&&(c-=Math.ceil(t["offset"+e[0].toUpperCase()+e.slice(1)]-parseFloat(i[e])-ue(t,e,"border",!1,i)-.5)),c&&(o=pt.exec(r))&&"px"!==(o[3]||"px")&&(t.style[e]=r,r=_.css(t,e)),ce(0,r,c)}}})),_.cssHooks.marginLeft=te(v.reliableMarginLeft,(function(t,e){if(e)return(parseFloat(Jt(t,"marginLeft"))||t.getBoundingClientRect().left-Xt(t,{marginLeft:0},(function(){return t.getBoundingClientRect().left})))+"px"})),_.each({margin:"",padding:"",border:"Width"},(function(t,e){_.cssHooks[t+e]={expand:function(r){for(var n=0,o={},i="string"==typeof r?r.split(" "):[r];n<4;n++)o[t+dt[n]+e]=i[n]||i[n-2]||i[0];return o}},"margin"!==t&&(_.cssHooks[t+e].set=ce)})),_.fn.extend({css:function(t,e){return tt(this,(function(t,e,r){var n,o,i={},a=0;if(Array.isArray(e)){for(n=Zt(t),o=e.length;a1)}}),_.Tween=fe,fe.prototype={constructor:fe,init:function(t,e,r,n,o,i){this.elem=t,this.prop=r,this.easing=o||_.easing._default,this.options=e,this.start=this.now=this.cur(),this.end=n,this.unit=i||(_.cssNumber[r]?"":"px")},cur:function(){var t=fe.propHooks[this.prop];return t&&t.get?t.get(this):fe.propHooks._default.get(this)},run:function(t){var e,r=fe.propHooks[this.prop];return this.options.duration?this.pos=e=_.easing[this.easing](t,this.options.duration*t,0,1,this.options.duration):this.pos=e=t,this.now=(this.end-this.start)*e+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),r&&r.set?r.set(this):fe.propHooks._default.set(this),this}},fe.prototype.init.prototype=fe.prototype,fe.propHooks={_default:{get:function(t){var e;return 1!==t.elem.nodeType||null!=t.elem[t.prop]&&null==t.elem.style[t.prop]?t.elem[t.prop]:(e=_.css(t.elem,t.prop,""))&&"auto"!==e?e:0},set:function(t){_.fx.step[t.prop]?_.fx.step[t.prop](t):1!==t.elem.nodeType||!_.cssHooks[t.prop]&&null==t.elem.style[oe(t.prop)]?t.elem[t.prop]=t.now:_.style(t.elem,t.prop,t.now+t.unit)}}},fe.propHooks.scrollTop=fe.propHooks.scrollLeft={set:function(t){t.elem.nodeType&&t.elem.parentNode&&(t.elem[t.prop]=t.now)}},_.easing={linear:function(t){return t},swing:function(t){return.5-Math.cos(t*Math.PI)/2},_default:"swing"},_.fx=fe.prototype.init,_.fx.step={};var he,pe,de=/^(?:toggle|show|hide)$/,ye=/queueHooks$/;function ve(){pe&&(!1===b.hidden&&n.requestAnimationFrame?n.requestAnimationFrame(ve):n.setTimeout(ve,_.fx.interval),_.fx.tick())}function ge(){return n.setTimeout((function(){he=void 0})),he=Date.now()}function me(t,e){var r,n=0,o={height:t};for(e=e?1:0;n<4;n+=2-e)o["margin"+(r=dt[n])]=o["padding"+r]=t;return e&&(o.opacity=o.width=t),o}function be(t,e,r){for(var n,o=(we.tweeners[e]||[]).concat(we.tweeners["*"]),i=0,a=o.length;i1)},removeAttr:function(t){return this.each((function(){_.removeAttr(this,t)}))}}),_.extend({attr:function(t,e,r){var n,o,i=t.nodeType;if(3!==i&&8!==i&&2!==i)return void 0===t.getAttribute?_.prop(t,e,r):(1===i&&_.isXMLDoc(t)||(o=_.attrHooks[e.toLowerCase()]||(_.expr.match.bool.test(e)?xe:void 0)),void 0!==r?null===r?void _.removeAttr(t,e):o&&"set"in o&&void 0!==(n=o.set(t,r,e))?n:(t.setAttribute(e,r+""),r):o&&"get"in o&&null!==(n=o.get(t,e))?n:null==(n=_.find.attr(t,e))?void 0:n)},attrHooks:{type:{set:function(t,e){if(!v.radioValue&&"radio"===e&&C(t,"input")){var r=t.value;return t.setAttribute("type",e),r&&(t.value=r),e}}}},removeAttr:function(t,e){var r,n=0,o=e&&e.match(z);if(o&&1===t.nodeType)for(;r=o[n++];)t.removeAttribute(r)}}),xe={set:function(t,e,r){return!1===e?_.removeAttr(t,r):t.setAttribute(r,r),r}},_.each(_.expr.match.bool.source.match(/\w+/g),(function(t,e){var r=Ae[e]||_.find.attr;Ae[e]=function(t,e,n){var o,i,a=e.toLowerCase();return n||(i=Ae[a],Ae[a]=o,o=null!=r(t,e,n)?a:null,Ae[a]=i),o}}));var Ee=/^(?:input|select|textarea|button)$/i,Le=/^(?:a|area)$/i;function _e(t){return(t.match(z)||[]).join(" ")}function ke(t){return t.getAttribute&&t.getAttribute("class")||""}function Ce(t){return Array.isArray(t)?t:"string"==typeof t&&t.match(z)||[]}_.fn.extend({prop:function(t,e){return tt(this,_.prop,t,e,arguments.length>1)},removeProp:function(t){return this.each((function(){delete this[_.propFix[t]||t]}))}}),_.extend({prop:function(t,e,r){var n,o,i=t.nodeType;if(3!==i&&8!==i&&2!==i)return 1===i&&_.isXMLDoc(t)||(e=_.propFix[e]||e,o=_.propHooks[e]),void 0!==r?o&&"set"in o&&void 0!==(n=o.set(t,r,e))?n:t[e]=r:o&&"get"in o&&null!==(n=o.get(t,e))?n:t[e]},propHooks:{tabIndex:{get:function(t){var e=_.find.attr(t,"tabindex");return e?parseInt(e,10):Ee.test(t.nodeName)||Le.test(t.nodeName)&&t.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),v.optSelected||(_.propHooks.selected={get:function(t){var e=t.parentNode;return e&&e.parentNode&&e.parentNode.selectedIndex,null},set:function(t){var e=t.parentNode;e&&(e.selectedIndex,e.parentNode&&e.parentNode.selectedIndex)}}),_.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],(function(){_.propFix[this.toLowerCase()]=this})),_.fn.extend({addClass:function(t){var e,r,n,o,i,a;return g(t)?this.each((function(e){_(this).addClass(t.call(this,e,ke(this)))})):(e=Ce(t)).length?this.each((function(){if(n=ke(this),r=1===this.nodeType&&" "+_e(n)+" "){for(i=0;i-1;)r=r.replace(" "+o+" "," ");a=_e(r),n!==a&&this.setAttribute("class",a)}})):this:this.attr("class","")},toggleClass:function(t,e){var r,n,o,i,a=typeof t,s="string"===a||Array.isArray(t);return g(t)?this.each((function(r){_(this).toggleClass(t.call(this,r,ke(this),e),e)})):"boolean"==typeof e&&s?e?this.addClass(t):this.removeClass(t):(r=Ce(t),this.each((function(){if(s)for(i=_(this),o=0;o-1)return!0;return!1}});var Se=/\r/g;_.fn.extend({val:function(t){var e,r,n,o=this[0];return arguments.length?(n=g(t),this.each((function(r){var o;1===this.nodeType&&(null==(o=n?t.call(this,r,_(this).val()):t)?o="":"number"==typeof o?o+="":Array.isArray(o)&&(o=_.map(o,(function(t){return null==t?"":t+""}))),(e=_.valHooks[this.type]||_.valHooks[this.nodeName.toLowerCase()])&&"set"in e&&void 0!==e.set(this,o,"value")||(this.value=o))}))):o?(e=_.valHooks[o.type]||_.valHooks[o.nodeName.toLowerCase()])&&"get"in e&&void 0!==(r=e.get(o,"value"))?r:"string"==typeof(r=o.value)?r.replace(Se,""):null==r?"":r:void 0}}),_.extend({valHooks:{option:{get:function(t){var e=_.find.attr(t,"value");return null!=e?e:_e(_.text(t))}},select:{get:function(t){var e,r,n,o=t.options,i=t.selectedIndex,a="select-one"===t.type,s=a?null:[],c=a?i+1:o.length;for(n=i<0?c:a?i:0;n-1)&&(r=!0);return r||(t.selectedIndex=-1),i}}}}),_.each(["radio","checkbox"],(function(){_.valHooks[this]={set:function(t,e){if(Array.isArray(e))return t.checked=_.inArray(_(t).val(),e)>-1}},v.checkOn||(_.valHooks[this].get=function(t){return null===t.getAttribute("value")?"on":t.value})}));var Oe=n.location,Te={guid:Date.now()},Pe=/\?/;_.parseXML=function(t){var e,r;if(!t||"string"!=typeof t)return null;try{e=(new n.DOMParser).parseFromString(t,"text/xml")}catch(t){}return r=e&&e.getElementsByTagName("parsererror")[0],e&&!r||_.error("Invalid XML: "+(r?_.map(r.childNodes,(function(t){return t.textContent})).join("\n"):t)),e};var je=/^(?:focusinfocus|focusoutblur)$/,Ie=function(t){t.stopPropagation()};_.extend(_.event,{trigger:function(t,e,r,o){var i,a,s,c,u,l,f,h,d=[r||b],y=p.call(t,"type")?t.type:t,v=p.call(t,"namespace")?t.namespace.split("."):[];if(a=h=s=r=r||b,3!==r.nodeType&&8!==r.nodeType&&!je.test(y+_.event.triggered)&&(y.indexOf(".")>-1&&(v=y.split("."),y=v.shift(),v.sort()),u=y.indexOf(":")<0&&"on"+y,(t=t[_.expando]?t:new _.Event(y,"object"==typeof t&&t)).isTrigger=o?2:3,t.namespace=v.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+v.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=r),e=null==e?[t]:_.makeArray(e,[t]),f=_.event.special[y]||{},o||!f.trigger||!1!==f.trigger.apply(r,e))){if(!o&&!f.noBubble&&!m(r)){for(c=f.delegateType||y,je.test(c+y)||(a=a.parentNode);a;a=a.parentNode)d.push(a),s=a;s===(r.ownerDocument||b)&&d.push(s.defaultView||s.parentWindow||n)}for(i=0;(a=d[i++])&&!t.isPropagationStopped();)h=a,t.type=i>1?c:f.bindType||y,(l=(st.get(a,"events")||Object.create(null))[t.type]&&st.get(a,"handle"))&&l.apply(a,e),(l=u&&a[u])&&l.apply&&it(a)&&(t.result=l.apply(a,e),!1===t.result&&t.preventDefault());return t.type=y,o||t.isDefaultPrevented()||f._default&&!1!==f._default.apply(d.pop(),e)||!it(r)||u&&g(r[y])&&!m(r)&&((s=r[u])&&(r[u]=null),_.event.triggered=y,t.isPropagationStopped()&&h.addEventListener(y,Ie),r[y](),t.isPropagationStopped()&&h.removeEventListener(y,Ie),_.event.triggered=void 0,s&&(r[u]=s)),t.result}},simulate:function(t,e,r){var n=_.extend(new _.Event,r,{type:t,isSimulated:!0});_.event.trigger(n,null,e)}}),_.fn.extend({trigger:function(t,e){return this.each((function(){_.event.trigger(t,e,this)}))},triggerHandler:function(t,e){var r=this[0];if(r)return _.event.trigger(t,e,r,!0)}});var Re=/\[\]$/,De=/\r?\n/g,Be=/^(?:submit|button|image|reset|file)$/i,Ne=/^(?:input|select|textarea|keygen)/i;function Fe(t,e,r,n){var o;if(Array.isArray(e))_.each(e,(function(e,o){r||Re.test(t)?n(t,o):Fe(t+"["+("object"==typeof o&&null!=o?e:"")+"]",o,r,n)}));else if(r||"object"!==A(e))n(t,e);else for(o in e)Fe(t+"["+o+"]",e[o],r,n)}_.param=function(t,e){var r,n=[],o=function(t,e){var r=g(e)?e():e;n[n.length]=encodeURIComponent(t)+"="+encodeURIComponent(null==r?"":r)};if(null==t)return"";if(Array.isArray(t)||t.jquery&&!_.isPlainObject(t))_.each(t,(function(){o(this.name,this.value)}));else for(r in t)Fe(r,t[r],e,o);return n.join("&")},_.fn.extend({serialize:function(){return _.param(this.serializeArray())},serializeArray:function(){return this.map((function(){var t=_.prop(this,"elements");return t?_.makeArray(t):this})).filter((function(){var t=this.type;return this.name&&!_(this).is(":disabled")&&Ne.test(this.nodeName)&&!Be.test(t)&&(this.checked||!_t.test(t))})).map((function(t,e){var r=_(this).val();return null==r?null:Array.isArray(r)?_.map(r,(function(t){return{name:e.name,value:t.replace(De,"\r\n")}})):{name:e.name,value:r.replace(De,"\r\n")}})).get()}});var Me=/%20/g,Ge=/#.*$/,Ue=/([?&])_=[^&]*/,$e=/^(.*?):[ \t]*([^\r\n]*)$/gm,He=/^(?:GET|HEAD)$/,Ve=/^\/\//,Ye={},Ke={},ze="*/".concat("*"),We=b.createElement("a");function qe(t){return function(e,r){"string"!=typeof e&&(r=e,e="*");var n,o=0,i=e.toLowerCase().match(z)||[];if(g(r))for(;n=i[o++];)"+"===n[0]?(n=n.slice(1)||"*",(t[n]=t[n]||[]).unshift(r)):(t[n]=t[n]||[]).push(r)}}function Ze(t,e,r,n){var o={},i=t===Ke;function a(s){var c;return o[s]=!0,_.each(t[s]||[],(function(t,s){var u=s(e,r,n);return"string"!=typeof u||i||o[u]?i?!(c=u):void 0:(e.dataTypes.unshift(u),a(u),!1)})),c}return a(e.dataTypes[0])||!o["*"]&&a("*")}function Xe(t,e){var r,n,o=_.ajaxSettings.flatOptions||{};for(r in e)void 0!==e[r]&&((o[r]?t:n||(n={}))[r]=e[r]);return n&&_.extend(!0,t,n),t}We.href=Oe.href,_.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Oe.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Oe.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":ze,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":_.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(t,e){return e?Xe(Xe(t,_.ajaxSettings),e):Xe(_.ajaxSettings,t)},ajaxPrefilter:qe(Ye),ajaxTransport:qe(Ke),ajax:function(t,e){"object"==typeof t&&(e=t,t=void 0),e=e||{};var r,o,i,a,s,c,u,l,f,h,p=_.ajaxSetup({},e),d=p.context||p,y=p.context&&(d.nodeType||d.jquery)?_(d):_.event,v=_.Deferred(),g=_.Callbacks("once memory"),m=p.statusCode||{},w={},x={},A="canceled",E={readyState:0,getResponseHeader:function(t){var e;if(u){if(!a)for(a={};e=$e.exec(i);)a[e[1].toLowerCase()+" "]=(a[e[1].toLowerCase()+" "]||[]).concat(e[2]);e=a[t.toLowerCase()+" "]}return null==e?null:e.join(", ")},getAllResponseHeaders:function(){return u?i:null},setRequestHeader:function(t,e){return null==u&&(t=x[t.toLowerCase()]=x[t.toLowerCase()]||t,w[t]=e),this},overrideMimeType:function(t){return null==u&&(p.mimeType=t),this},statusCode:function(t){var e;if(t)if(u)E.always(t[E.status]);else for(e in t)m[e]=[m[e],t[e]];return this},abort:function(t){var e=t||A;return r&&r.abort(e),L(0,e),this}};if(v.promise(E),p.url=((t||p.url||Oe.href)+"").replace(Ve,Oe.protocol+"//"),p.type=e.method||e.type||p.method||p.type,p.dataTypes=(p.dataType||"*").toLowerCase().match(z)||[""],null==p.crossDomain){c=b.createElement("a");try{c.href=p.url,c.href=c.href,p.crossDomain=We.protocol+"//"+We.host!=c.protocol+"//"+c.host}catch(t){p.crossDomain=!0}}if(p.data&&p.processData&&"string"!=typeof p.data&&(p.data=_.param(p.data,p.traditional)),Ze(Ye,p,e,E),u)return E;for(f in(l=_.event&&p.global)&&0==_.active++&&_.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!He.test(p.type),o=p.url.replace(Ge,""),p.hasContent?p.data&&p.processData&&0===(p.contentType||"").indexOf("application/x-www-form-urlencoded")&&(p.data=p.data.replace(Me,"+")):(h=p.url.slice(o.length),p.data&&(p.processData||"string"==typeof p.data)&&(o+=(Pe.test(o)?"&":"?")+p.data,delete p.data),!1===p.cache&&(o=o.replace(Ue,"$1"),h=(Pe.test(o)?"&":"?")+"_="+Te.guid+++h),p.url=o+h),p.ifModified&&(_.lastModified[o]&&E.setRequestHeader("If-Modified-Since",_.lastModified[o]),_.etag[o]&&E.setRequestHeader("If-None-Match",_.etag[o])),(p.data&&p.hasContent&&!1!==p.contentType||e.contentType)&&E.setRequestHeader("Content-Type",p.contentType),E.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+ze+"; q=0.01":""):p.accepts["*"]),p.headers)E.setRequestHeader(f,p.headers[f]);if(p.beforeSend&&(!1===p.beforeSend.call(d,E,p)||u))return E.abort();if(A="abort",g.add(p.complete),E.done(p.success),E.fail(p.error),r=Ze(Ke,p,e,E)){if(E.readyState=1,l&&y.trigger("ajaxSend",[E,p]),u)return E;p.async&&p.timeout>0&&(s=n.setTimeout((function(){E.abort("timeout")}),p.timeout));try{u=!1,r.send(w,L)}catch(t){if(u)throw t;L(-1,t)}}else L(-1,"No Transport");function L(t,e,a,c){var f,h,b,w,x,A=e;u||(u=!0,s&&n.clearTimeout(s),r=void 0,i=c||"",E.readyState=t>0?4:0,f=t>=200&&t<300||304===t,a&&(w=function(t,e,r){for(var n,o,i,a,s=t.contents,c=t.dataTypes;"*"===c[0];)c.shift(),void 0===n&&(n=t.mimeType||e.getResponseHeader("Content-Type"));if(n)for(o in s)if(s[o]&&s[o].test(n)){c.unshift(o);break}if(c[0]in r)i=c[0];else{for(o in r){if(!c[0]||t.converters[o+" "+c[0]]){i=o;break}a||(a=o)}i=i||a}if(i)return i!==c[0]&&c.unshift(i),r[i]}(p,E,a)),!f&&_.inArray("script",p.dataTypes)>-1&&_.inArray("json",p.dataTypes)<0&&(p.converters["text script"]=function(){}),w=function(t,e,r,n){var o,i,a,s,c,u={},l=t.dataTypes.slice();if(l[1])for(a in t.converters)u[a.toLowerCase()]=t.converters[a];for(i=l.shift();i;)if(t.responseFields[i]&&(r[t.responseFields[i]]=e),!c&&n&&t.dataFilter&&(e=t.dataFilter(e,t.dataType)),c=i,i=l.shift())if("*"===i)i=c;else if("*"!==c&&c!==i){if(!(a=u[c+" "+i]||u["* "+i]))for(o in u)if((s=o.split(" "))[1]===i&&(a=u[c+" "+s[0]]||u["* "+s[0]])){!0===a?a=u[o]:!0!==u[o]&&(i=s[0],l.unshift(s[1]));break}if(!0!==a)if(a&&t.throws)e=a(e);else try{e=a(e)}catch(t){return{state:"parsererror",error:a?t:"No conversion from "+c+" to "+i}}}return{state:"success",data:e}}(p,w,E,f),f?(p.ifModified&&((x=E.getResponseHeader("Last-Modified"))&&(_.lastModified[o]=x),(x=E.getResponseHeader("etag"))&&(_.etag[o]=x)),204===t||"HEAD"===p.type?A="nocontent":304===t?A="notmodified":(A=w.state,h=w.data,f=!(b=w.error))):(b=A,!t&&A||(A="error",t<0&&(t=0))),E.status=t,E.statusText=(e||A)+"",f?v.resolveWith(d,[h,A,E]):v.rejectWith(d,[E,A,b]),E.statusCode(m),m=void 0,l&&y.trigger(f?"ajaxSuccess":"ajaxError",[E,p,f?h:b]),g.fireWith(d,[E,A]),l&&(y.trigger("ajaxComplete",[E,p]),--_.active||_.event.trigger("ajaxStop")))}return E},getJSON:function(t,e,r){return _.get(t,e,r,"json")},getScript:function(t,e){return _.get(t,void 0,e,"script")}}),_.each(["get","post"],(function(t,e){_[e]=function(t,r,n,o){return g(r)&&(o=o||n,n=r,r=void 0),_.ajax(_.extend({url:t,type:e,dataType:o,data:r,success:n},_.isPlainObject(t)&&t))}})),_.ajaxPrefilter((function(t){var e;for(e in t.headers)"content-type"===e.toLowerCase()&&(t.contentType=t.headers[e]||"")})),_._evalUrl=function(t,e,r){return _.ajax({url:t,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(t){_.globalEval(t,e,r)}})},_.fn.extend({wrapAll:function(t){var e;return this[0]&&(g(t)&&(t=t.call(this[0])),e=_(t,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&e.insertBefore(this[0]),e.map((function(){for(var t=this;t.firstElementChild;)t=t.firstElementChild;return t})).append(this)),this},wrapInner:function(t){return g(t)?this.each((function(e){_(this).wrapInner(t.call(this,e))})):this.each((function(){var e=_(this),r=e.contents();r.length?r.wrapAll(t):e.append(t)}))},wrap:function(t){var e=g(t);return this.each((function(r){_(this).wrapAll(e?t.call(this,r):t)}))},unwrap:function(t){return this.parent(t).not("body").each((function(){_(this).replaceWith(this.childNodes)})),this}}),_.expr.pseudos.hidden=function(t){return!_.expr.pseudos.visible(t)},_.expr.pseudos.visible=function(t){return!!(t.offsetWidth||t.offsetHeight||t.getClientRects().length)},_.ajaxSettings.xhr=function(){try{return new n.XMLHttpRequest}catch(t){}};var Qe={0:200,1223:204},Je=_.ajaxSettings.xhr();v.cors=!!Je&&"withCredentials"in Je,v.ajax=Je=!!Je,_.ajaxTransport((function(t){var e,r;if(v.cors||Je&&!t.crossDomain)return{send:function(o,i){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];for(a in t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||o["X-Requested-With"]||(o["X-Requested-With"]="XMLHttpRequest"),o)s.setRequestHeader(a,o[a]);e=function(t){return function(){e&&(e=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===t?s.abort():"error"===t?"number"!=typeof s.status?i(0,"error"):i(s.status,s.statusText):i(Qe[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=e(),r=s.onerror=s.ontimeout=e("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&n.setTimeout((function(){e&&r()}))},e=e("abort");try{s.send(t.hasContent&&t.data||null)}catch(t){if(e)throw t}},abort:function(){e&&e()}}})),_.ajaxPrefilter((function(t){t.crossDomain&&(t.contents.script=!1)})),_.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(t){return _.globalEval(t),t}}}),_.ajaxPrefilter("script",(function(t){void 0===t.cache&&(t.cache=!1),t.crossDomain&&(t.type="GET")})),_.ajaxTransport("script",(function(t){var e,r;if(t.crossDomain||t.scriptAttrs)return{send:function(n,o){e=_(" diff --git a/vendor/autoload.php b/vendor/autoload.php index f753ba7d8..c0b3cdf86 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -14,10 +14,7 @@ echo $err; } } - trigger_error( - $err, - E_USER_ERROR - ); + throw new RuntimeException($err); } require_once __DIR__ . '/composer/autoload_real.php'; diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php index 6d29bff66..2052022fd 100644 --- a/vendor/composer/InstalledVersions.php +++ b/vendor/composer/InstalledVersions.php @@ -26,6 +26,12 @@ */ class InstalledVersions { + /** + * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to + * @internal + */ + private static $selfDir = null; + /** * @var mixed[]|null * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null @@ -322,6 +328,18 @@ public static function reload($data) self::$installedIsLocalDir = false; } + /** + * @return string + */ + private static function getSelfDir() + { + if (self::$selfDir === null) { + self::$selfDir = strtr(__DIR__, '\\', '/'); + } + + return self::$selfDir; + } + /** * @return array[] * @psalm-return list}> @@ -336,7 +354,7 @@ private static function getInstalled() $copiedLocalDir = false; if (self::$canGetVendors) { - $selfDir = strtr(__DIR__, '\\', '/'); + $selfDir = self::getSelfDir(); foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { $vendorDir = strtr($vendorDir, '\\', '/'); if (isset(self::$installedByVendor[$vendorDir])) { diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 21188d6f1..0e06eba0c 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -9,6 +9,82 @@ 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'ILIAS\\UI\\Implementation\\Component\\Input\\Field\\ChunkedFile' => $baseDir . '/src/UI/Form/ChunkedFile.php', 'ILIAS\\UI\\Implementation\\Component\\Input\\Field\\ChunkedFileRenderer' => $baseDir . '/src/UI/Form/ChunkedFileRenderer.php', + 'Lcobucci\\JWT\\Builder' => $vendorDir . '/lcobucci/jwt/src/Builder.php', + 'Lcobucci\\JWT\\ClaimsFormatter' => $vendorDir . '/lcobucci/jwt/src/ClaimsFormatter.php', + 'Lcobucci\\JWT\\Configuration' => $vendorDir . '/lcobucci/jwt/src/Configuration.php', + 'Lcobucci\\JWT\\Decoder' => $vendorDir . '/lcobucci/jwt/src/Decoder.php', + 'Lcobucci\\JWT\\Encoder' => $vendorDir . '/lcobucci/jwt/src/Encoder.php', + 'Lcobucci\\JWT\\Encoding\\CannotDecodeContent' => $vendorDir . '/lcobucci/jwt/src/Encoding/CannotDecodeContent.php', + 'Lcobucci\\JWT\\Encoding\\CannotEncodeContent' => $vendorDir . '/lcobucci/jwt/src/Encoding/CannotEncodeContent.php', + 'Lcobucci\\JWT\\Encoding\\ChainedFormatter' => $vendorDir . '/lcobucci/jwt/src/Encoding/ChainedFormatter.php', + 'Lcobucci\\JWT\\Encoding\\JoseEncoder' => $vendorDir . '/lcobucci/jwt/src/Encoding/JoseEncoder.php', + 'Lcobucci\\JWT\\Encoding\\MicrosecondBasedDateConversion' => $vendorDir . '/lcobucci/jwt/src/Encoding/MicrosecondBasedDateConversion.php', + 'Lcobucci\\JWT\\Encoding\\UnifyAudience' => $vendorDir . '/lcobucci/jwt/src/Encoding/UnifyAudience.php', + 'Lcobucci\\JWT\\Encoding\\UnixTimestampDates' => $vendorDir . '/lcobucci/jwt/src/Encoding/UnixTimestampDates.php', + 'Lcobucci\\JWT\\Exception' => $vendorDir . '/lcobucci/jwt/src/Exception.php', + 'Lcobucci\\JWT\\JwtFacade' => $vendorDir . '/lcobucci/jwt/src/JwtFacade.php', + 'Lcobucci\\JWT\\Parser' => $vendorDir . '/lcobucci/jwt/src/Parser.php', + 'Lcobucci\\JWT\\Signer' => $vendorDir . '/lcobucci/jwt/src/Signer.php', + 'Lcobucci\\JWT\\Signer\\Blake2b' => $vendorDir . '/lcobucci/jwt/src/Signer/Blake2b.php', + 'Lcobucci\\JWT\\Signer\\CannotSignPayload' => $vendorDir . '/lcobucci/jwt/src/Signer/CannotSignPayload.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa' => $vendorDir . '/lcobucci/jwt/src/Signer/Ecdsa.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\ConversionFailed' => $vendorDir . '/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\MultibyteStringConverter' => $vendorDir . '/lcobucci/jwt/src/Signer/Ecdsa/MultibyteStringConverter.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\Sha256' => $vendorDir . '/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\Sha384' => $vendorDir . '/lcobucci/jwt/src/Signer/Ecdsa/Sha384.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\Sha512' => $vendorDir . '/lcobucci/jwt/src/Signer/Ecdsa/Sha512.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\SignatureConverter' => $vendorDir . '/lcobucci/jwt/src/Signer/Ecdsa/SignatureConverter.php', + 'Lcobucci\\JWT\\Signer\\Eddsa' => $vendorDir . '/lcobucci/jwt/src/Signer/Eddsa.php', + 'Lcobucci\\JWT\\Signer\\Hmac' => $vendorDir . '/lcobucci/jwt/src/Signer/Hmac.php', + 'Lcobucci\\JWT\\Signer\\Hmac\\Sha256' => $vendorDir . '/lcobucci/jwt/src/Signer/Hmac/Sha256.php', + 'Lcobucci\\JWT\\Signer\\Hmac\\Sha384' => $vendorDir . '/lcobucci/jwt/src/Signer/Hmac/Sha384.php', + 'Lcobucci\\JWT\\Signer\\Hmac\\Sha512' => $vendorDir . '/lcobucci/jwt/src/Signer/Hmac/Sha512.php', + 'Lcobucci\\JWT\\Signer\\InvalidKeyProvided' => $vendorDir . '/lcobucci/jwt/src/Signer/InvalidKeyProvided.php', + 'Lcobucci\\JWT\\Signer\\Key' => $vendorDir . '/lcobucci/jwt/src/Signer/Key.php', + 'Lcobucci\\JWT\\Signer\\Key\\FileCouldNotBeRead' => $vendorDir . '/lcobucci/jwt/src/Signer/Key/FileCouldNotBeRead.php', + 'Lcobucci\\JWT\\Signer\\Key\\InMemory' => $vendorDir . '/lcobucci/jwt/src/Signer/Key/InMemory.php', + 'Lcobucci\\JWT\\Signer\\OpenSSL' => $vendorDir . '/lcobucci/jwt/src/Signer/OpenSSL.php', + 'Lcobucci\\JWT\\Signer\\Rsa' => $vendorDir . '/lcobucci/jwt/src/Signer/Rsa.php', + 'Lcobucci\\JWT\\Signer\\Rsa\\Sha256' => $vendorDir . '/lcobucci/jwt/src/Signer/Rsa/Sha256.php', + 'Lcobucci\\JWT\\Signer\\Rsa\\Sha384' => $vendorDir . '/lcobucci/jwt/src/Signer/Rsa/Sha384.php', + 'Lcobucci\\JWT\\Signer\\Rsa\\Sha512' => $vendorDir . '/lcobucci/jwt/src/Signer/Rsa/Sha512.php', + 'Lcobucci\\JWT\\SodiumBase64Polyfill' => $vendorDir . '/lcobucci/jwt/src/SodiumBase64Polyfill.php', + 'Lcobucci\\JWT\\Token' => $vendorDir . '/lcobucci/jwt/src/Token.php', + 'Lcobucci\\JWT\\Token\\Builder' => $vendorDir . '/lcobucci/jwt/src/Token/Builder.php', + 'Lcobucci\\JWT\\Token\\DataSet' => $vendorDir . '/lcobucci/jwt/src/Token/DataSet.php', + 'Lcobucci\\JWT\\Token\\InvalidTokenStructure' => $vendorDir . '/lcobucci/jwt/src/Token/InvalidTokenStructure.php', + 'Lcobucci\\JWT\\Token\\Parser' => $vendorDir . '/lcobucci/jwt/src/Token/Parser.php', + 'Lcobucci\\JWT\\Token\\Plain' => $vendorDir . '/lcobucci/jwt/src/Token/Plain.php', + 'Lcobucci\\JWT\\Token\\RegisteredClaimGiven' => $vendorDir . '/lcobucci/jwt/src/Token/RegisteredClaimGiven.php', + 'Lcobucci\\JWT\\Token\\RegisteredClaims' => $vendorDir . '/lcobucci/jwt/src/Token/RegisteredClaims.php', + 'Lcobucci\\JWT\\Token\\Signature' => $vendorDir . '/lcobucci/jwt/src/Token/Signature.php', + 'Lcobucci\\JWT\\Token\\UnsupportedHeaderFound' => $vendorDir . '/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php', + 'Lcobucci\\JWT\\UnencryptedToken' => $vendorDir . '/lcobucci/jwt/src/UnencryptedToken.php', + 'Lcobucci\\JWT\\Validation\\Constraint' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint.php', + 'Lcobucci\\JWT\\Validation\\ConstraintViolation' => $vendorDir . '/lcobucci/jwt/src/Validation/ConstraintViolation.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\CannotValidateARegisteredClaim' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/CannotValidateARegisteredClaim.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\HasClaim' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/HasClaim.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\HasClaimWithValue' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/HasClaimWithValue.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\IdentifiedBy' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/IdentifiedBy.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\IssuedBy' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\LeewayCannotBeNegative' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\LooseValidAt' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/LooseValidAt.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\PermittedFor' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/PermittedFor.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\RelatedTo' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\SignedWith' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/SignedWith.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\SignedWithOneInSet' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/SignedWithOneInSet.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\SignedWithUntilDate' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/SignedWithUntilDate.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\StrictValidAt' => $vendorDir . '/lcobucci/jwt/src/Validation/Constraint/StrictValidAt.php', + 'Lcobucci\\JWT\\Validation\\NoConstraintsGiven' => $vendorDir . '/lcobucci/jwt/src/Validation/NoConstraintsGiven.php', + 'Lcobucci\\JWT\\Validation\\RequiredConstraintsViolated' => $vendorDir . '/lcobucci/jwt/src/Validation/RequiredConstraintsViolated.php', + 'Lcobucci\\JWT\\Validation\\SignedWith' => $vendorDir . '/lcobucci/jwt/src/Validation/SignedWith.php', + 'Lcobucci\\JWT\\Validation\\ValidAt' => $vendorDir . '/lcobucci/jwt/src/Validation/ValidAt.php', + 'Lcobucci\\JWT\\Validation\\Validator' => $vendorDir . '/lcobucci/jwt/src/Validation/Validator.php', + 'Lcobucci\\JWT\\Validator' => $vendorDir . '/lcobucci/jwt/src/Validator.php', + 'OpencastApi\\Auth\\JWT\\OcJwtBuilder' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtBuilder.php', + 'OpencastApi\\Auth\\JWT\\OcJwtClaim' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtClaim.php', + 'OpencastApi\\Auth\\JWT\\OcJwtHandler' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtHandler.php', + 'OpencastApi\\Auth\\JWT\\OcJwtValidationConstraint' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtValidationConstraint.php', 'OpencastApi\\Mock\\OcMockHanlder' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Mock/OcMockHanlder.php', 'OpencastApi\\Opencast' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Opencast.php', 'OpencastApi\\Rest\\OcAgentsApi' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcAgentsApi.php', @@ -17,6 +93,7 @@ 'OpencastApi\\Rest\\OcEventAdminNg' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcEventAdminNg.php', 'OpencastApi\\Rest\\OcEventsApi' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcEventsApi.php', 'OpencastApi\\Rest\\OcGroupsApi' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcGroupsApi.php', + 'OpencastApi\\Rest\\OcInfo' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcInfo.php', 'OpencastApi\\Rest\\OcIngest' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcIngest.php', 'OpencastApi\\Rest\\OcListProvidersApi' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcListProvidersApi.php', 'OpencastApi\\Rest\\OcPlaylistsApi' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcPlaylistsApi.php', @@ -33,6 +110,7 @@ 'OpencastApi\\Rest\\OcWorkflow' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcWorkflow.php', 'OpencastApi\\Rest\\OcWorkflowsApi' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcWorkflowsApi.php', 'OpencastApi\\Util\\OcUtils' => $vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Util/OcUtils.php', + 'Psr\\Clock\\ClockInterface' => $vendorDir . '/psr/clock/src/ClockInterface.php', 'WaitOverlay' => $baseDir . '/src/UI/WaitOverlay.php', 'ilObjOpenCast' => $baseDir . '/classes/class.ilObjOpenCast.php', 'ilObjOpenCastAccess' => $baseDir . '/classes/class.ilObjOpenCastAccess.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index a157a4d79..96bee638f 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -8,10 +8,12 @@ return array( 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), + 'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'), 'OpencastApi\\Util\\' => array($vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Util'), 'OpencastApi\\Rest\\' => array($vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Rest'), 'OpencastApi\\Mock\\' => array($vendorDir . '/elan-ev/opencast-api/src/OpencastApi/Mock'), 'OpencastApi\\' => array($vendorDir . '/elan-ev/opencast-api/src/OpencastApi'), + 'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'), 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 63d86d5fb..e701078be 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -22,6 +22,8 @@ public static function getLoader() return self::$loader; } + require __DIR__ . '/platform_check.php'; + spl_autoload_register(array('ComposerAutoloaderInit20975cba620fc47d8c392214bb856b0a', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); spl_autoload_unregister(array('ComposerAutoloaderInit20975cba620fc47d8c392214bb856b0a', 'loadClassLoader')); diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 0f876cf6a..3992299be 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -17,6 +17,7 @@ class ComposerStaticInit20975cba620fc47d8c392214bb856b0a array ( 'Psr\\Http\\Message\\' => 17, 'Psr\\Http\\Client\\' => 16, + 'Psr\\Clock\\' => 10, ), 'O' => array ( @@ -25,6 +26,10 @@ class ComposerStaticInit20975cba620fc47d8c392214bb856b0a 'OpencastApi\\Mock\\' => 17, 'OpencastApi\\' => 12, ), + 'L' => + array ( + 'Lcobucci\\JWT\\' => 13, + ), 'G' => array ( 'GuzzleHttp\\Psr7\\' => 16, @@ -43,6 +48,10 @@ class ComposerStaticInit20975cba620fc47d8c392214bb856b0a array ( 0 => __DIR__ . '/..' . '/psr/http-client/src', ), + 'Psr\\Clock\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/clock/src', + ), 'OpencastApi\\Util\\' => array ( 0 => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Util', @@ -59,6 +68,10 @@ class ComposerStaticInit20975cba620fc47d8c392214bb856b0a array ( 0 => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi', ), + 'Lcobucci\\JWT\\' => + array ( + 0 => __DIR__ . '/..' . '/lcobucci/jwt/src', + ), 'GuzzleHttp\\Psr7\\' => array ( 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', @@ -77,6 +90,82 @@ class ComposerStaticInit20975cba620fc47d8c392214bb856b0a 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'ILIAS\\UI\\Implementation\\Component\\Input\\Field\\ChunkedFile' => __DIR__ . '/../..' . '/src/UI/Form/ChunkedFile.php', 'ILIAS\\UI\\Implementation\\Component\\Input\\Field\\ChunkedFileRenderer' => __DIR__ . '/../..' . '/src/UI/Form/ChunkedFileRenderer.php', + 'Lcobucci\\JWT\\Builder' => __DIR__ . '/..' . '/lcobucci/jwt/src/Builder.php', + 'Lcobucci\\JWT\\ClaimsFormatter' => __DIR__ . '/..' . '/lcobucci/jwt/src/ClaimsFormatter.php', + 'Lcobucci\\JWT\\Configuration' => __DIR__ . '/..' . '/lcobucci/jwt/src/Configuration.php', + 'Lcobucci\\JWT\\Decoder' => __DIR__ . '/..' . '/lcobucci/jwt/src/Decoder.php', + 'Lcobucci\\JWT\\Encoder' => __DIR__ . '/..' . '/lcobucci/jwt/src/Encoder.php', + 'Lcobucci\\JWT\\Encoding\\CannotDecodeContent' => __DIR__ . '/..' . '/lcobucci/jwt/src/Encoding/CannotDecodeContent.php', + 'Lcobucci\\JWT\\Encoding\\CannotEncodeContent' => __DIR__ . '/..' . '/lcobucci/jwt/src/Encoding/CannotEncodeContent.php', + 'Lcobucci\\JWT\\Encoding\\ChainedFormatter' => __DIR__ . '/..' . '/lcobucci/jwt/src/Encoding/ChainedFormatter.php', + 'Lcobucci\\JWT\\Encoding\\JoseEncoder' => __DIR__ . '/..' . '/lcobucci/jwt/src/Encoding/JoseEncoder.php', + 'Lcobucci\\JWT\\Encoding\\MicrosecondBasedDateConversion' => __DIR__ . '/..' . '/lcobucci/jwt/src/Encoding/MicrosecondBasedDateConversion.php', + 'Lcobucci\\JWT\\Encoding\\UnifyAudience' => __DIR__ . '/..' . '/lcobucci/jwt/src/Encoding/UnifyAudience.php', + 'Lcobucci\\JWT\\Encoding\\UnixTimestampDates' => __DIR__ . '/..' . '/lcobucci/jwt/src/Encoding/UnixTimestampDates.php', + 'Lcobucci\\JWT\\Exception' => __DIR__ . '/..' . '/lcobucci/jwt/src/Exception.php', + 'Lcobucci\\JWT\\JwtFacade' => __DIR__ . '/..' . '/lcobucci/jwt/src/JwtFacade.php', + 'Lcobucci\\JWT\\Parser' => __DIR__ . '/..' . '/lcobucci/jwt/src/Parser.php', + 'Lcobucci\\JWT\\Signer' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer.php', + 'Lcobucci\\JWT\\Signer\\Blake2b' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Blake2b.php', + 'Lcobucci\\JWT\\Signer\\CannotSignPayload' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/CannotSignPayload.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Ecdsa.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\ConversionFailed' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\MultibyteStringConverter' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Ecdsa/MultibyteStringConverter.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\Sha256' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\Sha384' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Ecdsa/Sha384.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\Sha512' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Ecdsa/Sha512.php', + 'Lcobucci\\JWT\\Signer\\Ecdsa\\SignatureConverter' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Ecdsa/SignatureConverter.php', + 'Lcobucci\\JWT\\Signer\\Eddsa' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Eddsa.php', + 'Lcobucci\\JWT\\Signer\\Hmac' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Hmac.php', + 'Lcobucci\\JWT\\Signer\\Hmac\\Sha256' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Hmac/Sha256.php', + 'Lcobucci\\JWT\\Signer\\Hmac\\Sha384' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Hmac/Sha384.php', + 'Lcobucci\\JWT\\Signer\\Hmac\\Sha512' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Hmac/Sha512.php', + 'Lcobucci\\JWT\\Signer\\InvalidKeyProvided' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/InvalidKeyProvided.php', + 'Lcobucci\\JWT\\Signer\\Key' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Key.php', + 'Lcobucci\\JWT\\Signer\\Key\\FileCouldNotBeRead' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Key/FileCouldNotBeRead.php', + 'Lcobucci\\JWT\\Signer\\Key\\InMemory' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Key/InMemory.php', + 'Lcobucci\\JWT\\Signer\\OpenSSL' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/OpenSSL.php', + 'Lcobucci\\JWT\\Signer\\Rsa' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Rsa.php', + 'Lcobucci\\JWT\\Signer\\Rsa\\Sha256' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Rsa/Sha256.php', + 'Lcobucci\\JWT\\Signer\\Rsa\\Sha384' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Rsa/Sha384.php', + 'Lcobucci\\JWT\\Signer\\Rsa\\Sha512' => __DIR__ . '/..' . '/lcobucci/jwt/src/Signer/Rsa/Sha512.php', + 'Lcobucci\\JWT\\SodiumBase64Polyfill' => __DIR__ . '/..' . '/lcobucci/jwt/src/SodiumBase64Polyfill.php', + 'Lcobucci\\JWT\\Token' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token.php', + 'Lcobucci\\JWT\\Token\\Builder' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token/Builder.php', + 'Lcobucci\\JWT\\Token\\DataSet' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token/DataSet.php', + 'Lcobucci\\JWT\\Token\\InvalidTokenStructure' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token/InvalidTokenStructure.php', + 'Lcobucci\\JWT\\Token\\Parser' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token/Parser.php', + 'Lcobucci\\JWT\\Token\\Plain' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token/Plain.php', + 'Lcobucci\\JWT\\Token\\RegisteredClaimGiven' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token/RegisteredClaimGiven.php', + 'Lcobucci\\JWT\\Token\\RegisteredClaims' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token/RegisteredClaims.php', + 'Lcobucci\\JWT\\Token\\Signature' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token/Signature.php', + 'Lcobucci\\JWT\\Token\\UnsupportedHeaderFound' => __DIR__ . '/..' . '/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php', + 'Lcobucci\\JWT\\UnencryptedToken' => __DIR__ . '/..' . '/lcobucci/jwt/src/UnencryptedToken.php', + 'Lcobucci\\JWT\\Validation\\Constraint' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint.php', + 'Lcobucci\\JWT\\Validation\\ConstraintViolation' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/ConstraintViolation.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\CannotValidateARegisteredClaim' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/CannotValidateARegisteredClaim.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\HasClaim' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/HasClaim.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\HasClaimWithValue' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/HasClaimWithValue.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\IdentifiedBy' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/IdentifiedBy.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\IssuedBy' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\LeewayCannotBeNegative' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\LooseValidAt' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/LooseValidAt.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\PermittedFor' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/PermittedFor.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\RelatedTo' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\SignedWith' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/SignedWith.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\SignedWithOneInSet' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/SignedWithOneInSet.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\SignedWithUntilDate' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/SignedWithUntilDate.php', + 'Lcobucci\\JWT\\Validation\\Constraint\\StrictValidAt' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Constraint/StrictValidAt.php', + 'Lcobucci\\JWT\\Validation\\NoConstraintsGiven' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/NoConstraintsGiven.php', + 'Lcobucci\\JWT\\Validation\\RequiredConstraintsViolated' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/RequiredConstraintsViolated.php', + 'Lcobucci\\JWT\\Validation\\SignedWith' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/SignedWith.php', + 'Lcobucci\\JWT\\Validation\\ValidAt' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/ValidAt.php', + 'Lcobucci\\JWT\\Validation\\Validator' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validation/Validator.php', + 'Lcobucci\\JWT\\Validator' => __DIR__ . '/..' . '/lcobucci/jwt/src/Validator.php', + 'OpencastApi\\Auth\\JWT\\OcJwtBuilder' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtBuilder.php', + 'OpencastApi\\Auth\\JWT\\OcJwtClaim' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtClaim.php', + 'OpencastApi\\Auth\\JWT\\OcJwtHandler' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtHandler.php', + 'OpencastApi\\Auth\\JWT\\OcJwtValidationConstraint' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtValidationConstraint.php', 'OpencastApi\\Mock\\OcMockHanlder' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Mock/OcMockHanlder.php', 'OpencastApi\\Opencast' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Opencast.php', 'OpencastApi\\Rest\\OcAgentsApi' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcAgentsApi.php', @@ -85,6 +174,7 @@ class ComposerStaticInit20975cba620fc47d8c392214bb856b0a 'OpencastApi\\Rest\\OcEventAdminNg' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcEventAdminNg.php', 'OpencastApi\\Rest\\OcEventsApi' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcEventsApi.php', 'OpencastApi\\Rest\\OcGroupsApi' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcGroupsApi.php', + 'OpencastApi\\Rest\\OcInfo' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcInfo.php', 'OpencastApi\\Rest\\OcIngest' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcIngest.php', 'OpencastApi\\Rest\\OcListProvidersApi' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcListProvidersApi.php', 'OpencastApi\\Rest\\OcPlaylistsApi' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcPlaylistsApi.php', @@ -101,6 +191,7 @@ class ComposerStaticInit20975cba620fc47d8c392214bb856b0a 'OpencastApi\\Rest\\OcWorkflow' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcWorkflow.php', 'OpencastApi\\Rest\\OcWorkflowsApi' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Rest/OcWorkflowsApi.php', 'OpencastApi\\Util\\OcUtils' => __DIR__ . '/..' . '/elan-ev/opencast-api/src/OpencastApi/Util/OcUtils.php', + 'Psr\\Clock\\ClockInterface' => __DIR__ . '/..' . '/psr/clock/src/ClockInterface.php', 'WaitOverlay' => __DIR__ . '/../..' . '/src/UI/WaitOverlay.php', 'ilObjOpenCast' => __DIR__ . '/../..' . '/classes/class.ilObjOpenCast.php', 'ilObjOpenCastAccess' => __DIR__ . '/../..' . '/classes/class.ilObjOpenCastAccess.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 76cde1b9c..45012b124 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -2,29 +2,30 @@ "packages": [ { "name": "elan-ev/opencast-api", - "version": "1.9.0", - "version_normalized": "1.9.0.0", + "version": "2.0.0", + "version_normalized": "2.0.0.0", "source": { "type": "git", "url": "https://github.com/elan-ev/opencast-php-library.git", - "reference": "041f29d10f9572b038e8665f6cc2f9c86d488da8" + "reference": "56a32f5498006d1da343ac195ea509a1af3e9a82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/elan-ev/opencast-php-library/zipball/041f29d10f9572b038e8665f6cc2f9c86d488da8", - "reference": "041f29d10f9572b038e8665f6cc2f9c86d488da8", + "url": "https://api.github.com/repos/elan-ev/opencast-php-library/zipball/56a32f5498006d1da343ac195ea509a1af3e9a82", + "reference": "56a32f5498006d1da343ac195ea509a1af3e9a82", "shasum": "" }, "require": { - "guzzlehttp/guzzle": ">=7.5.1", - "php": ">=7.2.5" + "guzzlehttp/guzzle": "^7.5", + "lcobucci/jwt": "^5.3", + "php": "^8.1" }, "require-dev": { "phpcompatibility/php-compatibility": "^9.3", "phpunit/phpunit": "^10.5", "squizlabs/php_codesniffer": "^3.7" }, - "time": "2025-03-10T07:54:08+00:00", + "time": "2025-10-28T07:14:10+00:00", "type": "library", "extra": { "branch-alias": { @@ -59,7 +60,7 @@ ], "support": { "issues": "https://github.com/elan-ev/opencast-php-library/issues", - "source": "https://github.com/elan-ev/opencast-php-library/tree/1.9.0" + "source": "https://github.com/elan-ev/opencast-php-library/tree/2.0.0" }, "install-path": "../elan-ev/opencast-api" }, @@ -397,6 +398,133 @@ ], "install-path": "../guzzlehttp/psr7" }, + { + "name": "lcobucci/jwt", + "version": "5.5.0", + "version_normalized": "5.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "a835af59b030d3f2967725697cf88300f579088e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/a835af59b030d3f2967725697cf88300f579088e", + "reference": "a835af59b030d3f2967725697cf88300f579088e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-sodium": "*", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/clock": "^1.0" + }, + "require-dev": { + "infection/infection": "^0.29", + "lcobucci/clock": "^3.2", + "lcobucci/coding-standard": "^11.0", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", + "phpstan/phpstan-strict-rules": "^1.5.0", + "phpunit/phpunit": "^11.1" + }, + "suggest": { + "lcobucci/clock": ">= 3.2" + }, + "time": "2025-01-26T21:29:45+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/5.5.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "install-path": "../lcobucci/jwt" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "time": "2022-11-25T14:36:26+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "install-path": "../psr/clock" + }, { "name": "psr/http-client", "version": "1.0.3", diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 06570dcdb..c872900a8 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'opencast-ilias/opencast', 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => 'df85d6e145a525c8c47887ed1af3cdb33819bbb0', + 'reference' => '5214079cd7b8a8c009e5d10f3ce0dc85314c4194', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -11,9 +11,9 @@ ), 'versions' => array( 'elan-ev/opencast-api' => array( - 'pretty_version' => '1.9.0', - 'version' => '1.9.0.0', - 'reference' => '041f29d10f9572b038e8665f6cc2f9c86d488da8', + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'reference' => '56a32f5498006d1da343ac195ea509a1af3e9a82', 'type' => 'library', 'install_path' => __DIR__ . '/../elan-ev/opencast-api', 'aliases' => array(), @@ -46,15 +46,33 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'lcobucci/jwt' => array( + 'pretty_version' => '5.5.0', + 'version' => '5.5.0.0', + 'reference' => 'a835af59b030d3f2967725697cf88300f579088e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../lcobucci/jwt', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'opencast-ilias/opencast' => array( 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => 'df85d6e145a525c8c47887ed1af3cdb33819bbb0', + 'reference' => '5214079cd7b8a8c009e5d10f3ce0dc85314c4194', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false, ), + 'psr/clock' => array( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'reference' => 'e41a24703d4560fd0acb709162f73b8adfc3aa0d', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/clock', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'psr/http-client' => array( 'pretty_version' => '1.0.3', 'version' => '1.0.3.0', diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 000000000..14bf88da3 --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,25 @@ += 80200)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 8.2.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + throw new \RuntimeException( + 'Composer detected issues in your platform: ' . implode(' ', $issues) + ); +} diff --git a/vendor/elan-ev/opencast-api/.github/workflows/opencast-php-lib-ci.yml b/vendor/elan-ev/opencast-api/.github/workflows/opencast-php-lib-ci.yml index 3be31cca2..f462ecabd 100644 --- a/vendor/elan-ev/opencast-api/.github/workflows/opencast-php-lib-ci.yml +++ b/vendor/elan-ev/opencast-api/.github/workflows/opencast-php-lib-ci.yml @@ -14,6 +14,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" dependency-versions: - "lowest" - "highest" @@ -40,6 +41,16 @@ jobs: needs: compatibility name: PHPUnit Test runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + php-version: + - "8.1" + - "8.2" + - "8.3" + - "8.4" + steps: - name: Repo checkout uses: actions/checkout@v4 @@ -47,13 +58,11 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: ${{ matrix.php-version }} coverage: none - name: Install composer dependencies uses: ramsey/composer-install@v3 - with: - dependency-versions: 8.1 - name: Run PHPUnit run: vendor/bin/phpunit --display-incomplete --display-phpunit-deprecations --display-deprecations --display-errors --display-warnings --display-skipped --display-notices diff --git a/vendor/elan-ev/opencast-api/CHANGELOG.md b/vendor/elan-ev/opencast-api/CHANGELOG.md index dfa0bf0a4..1e5270832 100644 --- a/vendor/elan-ev/opencast-api/CHANGELOG.md +++ b/vendor/elan-ev/opencast-api/CHANGELOG.md @@ -52,18 +52,27 @@ - Fix for unauthorized access when extracting the Opencast API Version. # 1.9.0 -- Allow passing additional options to Guzzle [#30] +- Allow passing additional options to Guzzle [#30](https://github.com/elan-ev/opencast-php-library/issues/30) - Added `OcUtils` class, a utility class providing additional functionality to simplify the integration and consumption of this library. - - Initially includes the `findValueByKey` function, which is meant to retrieve a specific value from the response body. [#33] + - Initially includes the `findValueByKey` function, which is meant to retrieve a specific value from the response body. [#33](https://github.com/elan-ev/opencast-php-library/issues/33) - WorkflowApi endpoint methods got updated - - `withconfigurationpaneljson` parameter has been added to `/api/workflow-definitions` endpoints. [#34] + - `withconfigurationpaneljson` parameter has been added to `/api/workflow-definitions` endpoints. [#34](https://github.com/elan-ev/opencast-php-library/issues/34) - `@deprecated` removal of OcWorkflowsApi::geAll() method! -- Repair and enhance Event API `addTrack`under `/api/events/{eventId}/track` [#36] +- Repair and enhance Event API `addTrack`under `/api/events/{eventId}/track` [#36](https://github.com/elan-ev/opencast-php-library/issues/36) - Tags are now added, therefore it can be replaced by ingest method. - overwriteExisting flag has been fixed and works as expected now! -- Introduce `includeInternalPublication` in Events API `getAll`, `get` and `getPublications` methods [#37] -- Deprecated methods cleanup! [#39] +- Introduce `includeInternalPublication` in Events API `getAll`, `get` and `getPublications` methods [#37](https://github.com/elan-ev/opencast-php-library/issues/37) +- Deprecated methods cleanup! [#39](https://github.com/elan-ev/opencast-php-library/issues/39) - `OcWorkflow->getStatistics()` - `OcWorkflow->getInstances()` - `OcSeries->getTitles()` - `OcSeries->getAll()` + +# 1.9.1 +- Make sure ingest service is selected only when it is online and active [#47](https://github.com/elan-ev/opencast-php-library/issues/47) + +# 2.0.0 +* Introduced **JWT Authentication Mechanism** [#50](https://github.com/elan-ev/opencast-php-library/issues/50) +* Updated PHPUnit tests and configurations +* Extended GitHub CI supported PHP versions to **8.1 – 8.4** +* Return response body on HTTP errors (e.g. 409 Conflict) [#52](https://github.com/elan-ev/opencast-php-library/issues/52) diff --git a/vendor/elan-ev/opencast-api/README.md b/vendor/elan-ev/opencast-api/README.md index 6f3675702..3f82f20a8 100644 --- a/vendor/elan-ev/opencast-api/README.md +++ b/vendor/elan-ev/opencast-api/README.md @@ -3,11 +3,13 @@ This PHP composer package is meant to provide a unified easy-to-use Opencast RES Please refer to the [Change Log](https://github.com/elan-ev/opencast-php-library/blob/master/CHANGELOG.md) for more info. ## Note -As of version 1.2.0 the main class name has been changed from `OpenCast` to `OpenCast`. Please refer to [Upgrade Log](https://github.com/elan-ev/opencast-php-library/blob/master/UPGRADING.md) for more info. +As of version 1.2.0 the main class name has been changed from `OpenCast` to `Opencast`. Please refer to [Upgrade Log](https://github.com/elan-ev/opencast-php-library/blob/master/UPGRADING.md) for more info. # Requisitions PHP Version 7.2.5 or above as well as cURL are required. Additionaly, the [requirements](https://docs.guzzlephp.org/en/stable/overview.html#requirements) of [guzzlehttp/guzzle](https://packagist.org/packages/guzzlehttp/guzzle#7.0.0) must be fullfiled. +Note: Starting from version 2.x, the minimum required PHP version is 8.1. + # Installation `composer require elan-ev/opencast-api` @@ -28,6 +30,11 @@ $config = [ 'handler' => null, // The callable Handler or HandlerStack. (Default null). (optional) 'features' => null, // A set of additional features [e.g. lucene search]. (Default null). (optional) 'guzzle' => null, // Additional Guzzle Request Options. These options can overwrite some default options (Default null). (optional) + 'jwt' => [ // JWT Configuration. When exists, the JWT auth is activated. + 'private_key' => '...', // Private Key in full text. + 'algorithm' => 'ES256', // Algorithm with which the public/private key has been created + 'expiration' => 3600, // The expiration duration of the token + ], ]; $engageConfig = [ @@ -40,6 +47,11 @@ $engageConfig = [ 'handler' => null, // The callable Handler or HandlerStack. (Default null). (optional) 'features' => null, // A set of additional features [e.g. lucene search]. (Default null). (optional) 'guzzle' => null, // Additional Guzzle Request Options. These options can overwrite some default options (Default null). (optional) + 'jwt' => [ // JWT Configuration. When exists, the JWT auth is activated. + 'private_key' => '...', // Private Key in full text. + 'algorithm' => 'ES256', // Algorithm with which the public/private key has been created + 'expiration' => 3600, // The expiration duration of the token + ], ]; use OpencastApi\Opencast; @@ -79,6 +91,11 @@ $config = [ 'handler' => null, // The callable Handler or HandlerStack. (Default null). (optional) 'features' => null, // A set of additional features [e.g. lucene search]. (Default null). (optional) 'guzzle' => null, // Additional Guzzle Request Options. These options can overwrite some default options (Default null). (optional) + 'jwt' => [ // JWT Configuration. When exists, the JWT auth is activated. + 'private_key' => '...', // Private Key in full text. + 'algorithm' => 'ES256', // Algorithm with which the public/private key has been created + 'expiration' => 3600, // The expiration duration of the token + ], ]; @@ -120,12 +137,20 @@ $config = [ 'handler' => null, // The callable Handler or HandlerStack. (Default null). (optional) 'features' => null, // A set of additional features [e.g. lucene search]. (Default null). (optional) 'guzzle' => null, // Additional Guzzle Request Options. These options can overwrite some default options (Default null). (optional) + 'jwt' => [ // JWT Configuration. When exists, the JWT auth is activated. + 'private_key' => '...', // Private Key in full text. + 'algorithm' => 'ES256', // Algorithm with which the public/private key has been created + 'expiration' => 3600, // The expiration duration of the token + ], ]; ``` -**UPDATE (v1.9.0):** a new config parameter called "guzzle" is introduced, which is intended to pass additional guzzle request options to the call. These options will take precedence over the default configs like uri, auth and timeouts, but some other options like query, fome_params and json will be overwritten by the function if present. -**UPDATE (v1.7.0):** the new items called `features` is added to the configuration array. As of now, it is meant to hanlde the toggle behavior to enable/disable Lucene search endpoint simply by adding `'features' => ['lucene' => true]`. Just keep in mind that this endpoint id off by default and won't work in Opencast 16 onwards. Therefore, developer must be very careful to use this feature and to toggle it! +> **Update (v2.0.0):** A new configuration parameter has been introduced to enable **JWT authentication**, allowing the JWT component to issue and validate tokens. For more details, see the [JWT Authentication Mechanism](#jwt-authentication-mechanism). -NOTE: the configuration for presentation (`engage` node) responsible for search has to follow the same definition as normal config. But in case any parameter is missing, the value will be taken from the main config param. +> **UPDATE (v1.9.0):** a new config parameter called "guzzle" is introduced, which is intended to pass additional guzzle request options to the call. These options will take precedence over the default configs like uri, auth and timeouts, but some other options like query, fome_params and json will be overwritten by the function if present. + +> **UPDATE (v1.7.0):** the new items called `features` is added to the configuration array. As of now, it is meant to hanlde the toggle behavior to enable/disable Lucene search endpoint simply by adding `'features' => ['lucene' => true]`. Just keep in mind that this endpoint id off by default and won't work in Opencast 16 onwards. Therefore, developer must be very careful to use this feature and to toggle it! + +> NOTE: the configuration for presentation (`engage` node) responsible for search has to follow the same definition as normal config. But in case any parameter is missing, the value will be taken from the main config param. #### Extra: Dynamically loading the ingest endpoint class into Opencast instance. As of v1.3 it is possible to enable (Default) or disable the ingest endpoint to be loaded into `OpencastApi\Opencast` by passing a boolean value as the last argument of the class as follows: @@ -136,6 +161,172 @@ $opencastApiWithIngest = new Opencast($config, $engageConfig); $opencastApiWithoutIngest = new Opencast($config, $engageConfig, false); // ... ``` +# JWT Authentication Mechanism + +Starting from **version 2.0.0**, the Opencast PHP library introduces a **JWT-based authentication mechanism**. +This feature handles issuing and verifying access tokens, creating Opencast-specific claims, and validating these claims. + +For details about Opencast's JWT configuration and claim standards, see the official documentation: +👉 [Opencast Configuration for JWT-based Authentication and Authorization](https://docs.opencast.org/r/18.x/admin/#configuration/security.jwt/#configuration-for-jwt-based-authentication-and-authorization) + +--- + +### Requirements + +To support this feature, some version requirements apply: + +* **PHP:** 8.1 or higher +* **Opencast:** 18.0 or higher (JWT and ACL support required) + +--- + +### Configuration + +To enable JWT authentication in this library, add the `jwt` configuration array to your existing setup: + +```php +$config = [ + ..., + 'jwt' => [ // JWT configuration. When present, JWT auth is enabled. + 'private_key' => '...', // Private key in full text. + 'algorithm' => 'ES256', // Algorithm used for key generation. + 'expiration' => 3600, // Token expiration time in seconds. + ], +]; +``` + +--- + +### How to Use + +Before performing authenticated requests, you need to create an Opencast-specific claim using `OcJwtClaim`. + +```php +use OpencastApi\Auth\JWT\OcJwtClaim; +... + +// Example: Claim with event ACLs +$ocClaim = new OcJwtClaim(); +$eventAcl = [ + "{event id}" => ['read'], +]; +$ocClaim->setEventAcls($eventAcl); +// Also for series. +$seriesAcl = [ + "{series id}" => ['read', 'write'], +]; +$ocClaim->setSeriesAcls($seriesAcl); +// Also for playlists. +$playlistAcl = [ + "{playlist id}" => ['read', 'write'], +]; +$ocClaim->setPlaylistAcls($playlistAcl); + +// Example: Claim with user info and roles +$ocClaim = new OcJwtClaim(); +$name = 'JWT TEST USER 1'; +$username = 'jwt_test_user_1'; +$email = 'jwt_test_user_1@test.test'; + +// User Info. +$ocClaim->setUserInfoClaims($username, $name, $email); +// Roles. +$ocClaim->setRoles(['ROLE_USER_1', 'ROLE_JWT_USER_1']); + + +// Creating from array is also there: +$userInfoArray = [ + 'sub' => 'jwt_test_user_2', + 'name' => 'JWT TEST USER 2', + 'email' => 'jwt_test_user_2@test.test', + 'roles' => ['ROLE_USER_2', 'ROLE_JWT_USER_2'], +]; + +$ocClaim = OcJwtClaim::createFromArray($userInfoArray); +... +``` + +--- + +#### Calling Endpoints with JWT + +You can call API endpoints using JWT simply by chaining the `withClaims()` method before the desired service: + +```php +use OpencastApi\Opencast; +use OpencastApi\Auth\JWT\OcJwtClaim; +... + +$config = [ + ..., + 'jwt' => [ + 'private_key' => '...', + 'algorithm' => 'ES256', + 'expiration' => 3600, + ], +]; + +$api = new Opencast($config); + +$userInfoArray = [ + 'sub' => 'jwt_test_user_2', + 'name' => 'JWT TEST USER 2', + 'email' => 'jwt_test_user_2@test.test', + 'roles' => ['ROLE_USER_2', 'ROLE_JWT_USER_2'], +]; + +$ocClaim = OcJwtClaim::createFromArray($userInfoArray); + +// Example endpoint call using JWT +$response = $api->info->withClaims($ocClaim)->getInfoMeJson(); +... +``` + +--- + +#### Token Generation and Validation + +This approach is typically used when you only need to generate or validate JWT access tokens. You first need to call `getJwtHandler()` from the Opencast class to obtain an instance of `OcJwtHandler` - the library's core JWT component - which provides access to the `validateToken()` and `issueToken()` methods. + +```php +use OpencastApi\Opencast; +use OpencastApi\Auth\JWT\OcJwtClaim; +... + +$config = [ + ..., + 'jwt' => [ + 'private_key' => '...', + 'algorithm' => 'ES256', + 'expiration' => 3600, + ], +]; + +$api = new Opencast($config); + +$eventId = '1234...'; + +$ocClaim = new OcJwtClaim(); +$eventAcl = [ + "$eventId" => ['read'], // Allowed actions +]; +$ocClaim->setEventAcls($eventAcl); + +// Issue a new token +$accessToken = $api->getJwtHandler()->issueToken($ocClaim); + +// Attach token to a URL or include it in the Authorization header +$staticFileUrl = '.../static/.../test.mp4' . '?jwt=' . $accessToken; + +// Validate the token +$isValid = $api->getJwtHandler()->validateToken($accessToken); + +// Extract and compare claims +$extractedOcClaim = $api->getJwtHandler()->getOcJwtClaimFromTokenString($accessToken); +$comparingAclAction = ['read', 'write']; +$matchedActions = $extractedOcClaim->actionsMatchFor(OcJwtClaim::OC_EVENT, $eventId, $comparingAclAction); +``` + # Response The return result of each call is an `Array` containing the following information: diff --git a/vendor/elan-ev/opencast-api/composer.json b/vendor/elan-ev/opencast-api/composer.json index aeb176bc4..581236ae8 100644 --- a/vendor/elan-ev/opencast-api/composer.json +++ b/vendor/elan-ev/opencast-api/composer.json @@ -18,8 +18,9 @@ }, "homepage": "https://docs.opencast.org/", "require": { - "php": ">=7.2.5", - "guzzlehttp/guzzle": ">=7.5.1" + "php": "^8.1", + "guzzlehttp/guzzle": "^7.5", + "lcobucci/jwt": "^5.3" }, "autoload": { "psr-4": { @@ -30,10 +31,10 @@ } }, "scripts": { - "sniffer:php8.0": "phpcs -p -v ./src --standard=vendor/phpcompatibility/php-compatibility/PHPCompatibility --runtime-set testVersion 8.0", "sniffer:php8.1": "phpcs -p -v ./src --standard=vendor/phpcompatibility/php-compatibility/PHPCompatibility --runtime-set testVersion 8.1", "sniffer:php8.2": "phpcs -p -v ./src --standard=vendor/phpcompatibility/php-compatibility/PHPCompatibility --runtime-set testVersion 8.2", - "sniffer:php8.3": "phpcs -p -v ./src --standard=vendor/phpcompatibility/php-compatibility/PHPCompatibility --runtime-set testVersion 8.3" + "sniffer:php8.3": "phpcs -p -v ./src --standard=vendor/phpcompatibility/php-compatibility/PHPCompatibility --runtime-set testVersion 8.3", + "sniffer:php8.4": "phpcs -p -v ./src --standard=vendor/phpcompatibility/php-compatibility/PHPCompatibility --runtime-set testVersion 8.4" }, "require-dev": { "squizlabs/php_codesniffer": "^3.7", diff --git a/vendor/elan-ev/opencast-api/composer.lock b/vendor/elan-ev/opencast-api/composer.lock deleted file mode 100644 index 157a0cf26..000000000 --- a/vendor/elan-ev/opencast-api/composer.lock +++ /dev/null @@ -1,2388 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "3a547a6db2397de97c79516482b78616", - "packages": [ - { - "name": "guzzlehttp/guzzle", - "version": "7.9.2", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "d281ed313b989f213357e3be1a179f02196ac99b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", - "reference": "d281ed313b989f213357e3be1a179f02196ac99b", - "shasum": "" - }, - "require": { - "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp/psr7": "^2.7.0", - "php": "^7.2.5 || ^8.0", - "psr/http-client": "^1.0", - "symfony/deprecation-contracts": "^2.2 || ^3.0" - }, - "provide": { - "psr/http-client-implementation": "1.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "ext-curl": "*", - "guzzle/client-integration-tests": "3.0.2", - "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.39 || ^9.6.20", - "psr/log": "^1.1 || ^2.0 || ^3.0" - }, - "suggest": { - "ext-curl": "Required for CURL handler support", - "ext-intl": "Required for Internationalized Domain Name (IDN) support", - "psr/log": "Required for using the Log middleware" - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "GuzzleHttp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Jeremy Lindblom", - "email": "jeremeamia@gmail.com", - "homepage": "https://github.com/jeremeamia" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "psr-18", - "psr-7", - "rest", - "web service" - ], - "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.2" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", - "type": "tidelift" - } - ], - "time": "2024-07-24T11:22:20+00:00" - }, - { - "name": "guzzlehttp/promises", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455", - "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", - "type": "tidelift" - } - ], - "time": "2024-10-17T10:06:22+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "2.7.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0", - "ralouphie/getallheaders": "^3.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "0.9.0", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" - }, - "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], - "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.0" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", - "type": "tidelift" - } - ], - "time": "2024-07-18T11:15:46+00:00" - }, - { - "name": "psr/http-client", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", - "shasum": "" - }, - "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", - "keywords": [ - "http", - "http-client", - "psr", - "psr-18" - ], - "support": { - "source": "https://github.com/php-fig/http-client" - }, - "time": "2023-09-23T14:17:50+00:00" - }, - { - "name": "psr/http-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory" - }, - "time": "2024-04-15T12:06:14+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, - "time": "2019-03-08T08:55:37+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.5.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.5-dev" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-25T14:20:29+00:00" - } - ], - "packages-dev": [ - { - "name": "myclabs/deep-copy", - "version": "1.13.0", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" - }, - "type": "library", - "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2025-02-12T12:17:51+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v5.4.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "php": ">=7.4" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" - }, - "time": "2024-12-30T11:07:19+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "54750ef60c58e43759730615a392c31c80e23176" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", - "reference": "54750ef60c58e43759730615a392c31c80e23176", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:33:53+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" - }, - { - "name": "phpcompatibility/php-compatibility", - "version": "9.3.5", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" - }, - "conflict": { - "squizlabs/php_codesniffer": "2.6.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "homepage": "https://github.com/wimg", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", - "role": "lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" - } - ], - "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", - "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", - "keywords": [ - "compatibility", - "phpcs", - "standards" - ], - "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", - "source": "https://github.com/PHPCompatibility/PHPCompatibility" - }, - "time": "2019-12-27T09:44:58+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "10.1.16", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "7e308268858ed6baedc8704a304727d20bc07c77" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", - "reference": "7e308268858ed6baedc8704a304727d20bc07c77", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.19.1 || ^5.1.0", - "php": ">=8.1", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-text-template": "^3.0.1", - "sebastian/code-unit-reverse-lookup": "^3.0.0", - "sebastian/complexity": "^3.2.0", - "sebastian/environment": "^6.1.0", - "sebastian/lines-of-code": "^2.0.2", - "sebastian/version": "^4.0.1", - "theseer/tokenizer": "^1.2.3" - }, - "require-dev": { - "phpunit/phpunit": "^10.1" - }, - "suggest": { - "ext-pcov": "PHP extension that provides line coverage", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "10.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-08-22T04:31:57+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "4.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", - "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-31T06:24:48+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "4.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", - "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^10.0" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:56:09+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "3.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", - "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-31T14:07:24+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "6.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", - "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:57:52+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "10.5.45", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "bd68a781d8e30348bc297449f5234b3458267ae8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8", - "reference": "bd68a781d8e30348bc297449f5234b3458267ae8", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.1", - "phar-io/manifest": "^2.0.4", - "phar-io/version": "^3.2.1", - "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.16", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-invoker": "^4.0.0", - "phpunit/php-text-template": "^3.0.1", - "phpunit/php-timer": "^6.0.0", - "sebastian/cli-parser": "^2.0.1", - "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.3", - "sebastian/diff": "^5.1.1", - "sebastian/environment": "^6.1.0", - "sebastian/exporter": "^5.1.2", - "sebastian/global-state": "^6.0.2", - "sebastian/object-enumerator": "^5.0.0", - "sebastian/recursion-context": "^5.0.0", - "sebastian/type": "^4.0.0", - "sebastian/version": "^4.0.1" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "10.5-dev" - } - }, - "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2025-02-06T16:08:12+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", - "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:12:49+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", - "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:58:43+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", - "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:59:15+00:00" - }, - { - "name": "sebastian/comparator", - "version": "5.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", - "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/diff": "^5.0", - "sebastian/exporter": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-10-18T14:56:07+00:00" - }, - { - "name": "sebastian/complexity", - "version": "3.2.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "68ff824baeae169ec9f2137158ee529584553799" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", - "reference": "68ff824baeae169ec9f2137158ee529584553799", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-21T08:37:17+00:00" - }, - { - "name": "sebastian/diff", - "version": "5.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0", - "symfony/process": "^6.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:15:17+00:00" - }, - { - "name": "sebastian/environment", - "version": "6.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", - "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "https://github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-23T08:47:14+00:00" - }, - { - "name": "sebastian/exporter", - "version": "5.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "955288482d97c19a372d3f31006ab3f37da47adf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", - "reference": "955288482d97c19a372d3f31006ab3f37da47adf", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=8.1", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:17:12+00:00" - }, - { - "name": "sebastian/global-state", - "version": "6.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", - "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "https://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:19:19+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", - "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-21T08:38:20+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "5.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", - "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "sebastian/object-reflector": "^3.0", - "sebastian/recursion-context": "^5.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:08:32+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", - "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:06:18+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "5.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", - "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:05:40+00:00" - }, - { - "name": "sebastian/type", - "version": "4.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", - "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", - "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T07:10:45+00:00" - }, - { - "name": "sebastian/version", - "version": "4.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", - "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-07T11:34:05+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.11.3", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", - "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-01-23T17:04:15+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:36:25+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": {}, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=7.2.5" - }, - "platform-dev": {}, - "plugin-api-version": "2.6.0" -} diff --git a/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtBuilder.php b/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtBuilder.php new file mode 100644 index 000000000..67d05b9d4 --- /dev/null +++ b/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtBuilder.php @@ -0,0 +1,196 @@ + */ + private array $headers = ['typ' => 'JWT', 'alg' => null]; + + /** @var array */ + private array $claims = []; + + /** + * @inheritDoc + * + * Use {@see self::new()} instead of directly instantiating with `new OcJwtBuilder()` as it is deprecated. + */ + public function __construct(private readonly Encoder $encoder, private readonly ClaimsFormatter $claimFormatter) + { + } + + /** + * @inheritDoc + */ + public static function new(Encoder $encoder, ClaimsFormatter $claimFormatter): self + { + return new self($encoder, $claimFormatter); + } + + /** + * @inheritDoc + * @pure + */ + public function permittedFor(string ...$audiences): BuilderInterface + { + $configured = $this->claims[RegisteredClaims::AUDIENCE] ?? []; + $toAppend = array_diff($audiences, $configured); + + return $this->setClaim(RegisteredClaims::AUDIENCE, array_merge($configured, $toAppend)); + } + + /** + * @inheritDoc + * @pure + */ + public function expiresAt(DateTimeImmutable $expiration): BuilderInterface + { + return $this->setClaim(RegisteredClaims::EXPIRATION_TIME, $expiration); + } + + /** + * @inheritDoc + * @pure + */ + public function identifiedBy(string $id): BuilderInterface + { + return $this->setClaim(RegisteredClaims::ID, $id); + } + + /** + * @inheritDoc + * @pure + */ + public function issuedAt(DateTimeImmutable $issuedAt): BuilderInterface + { + return $this->setClaim(RegisteredClaims::ISSUED_AT, $issuedAt); + } + + /** + * @inheritDoc + * @pure + */ + public function issuedBy(string $issuer): BuilderInterface + { + return $this->setClaim(RegisteredClaims::ISSUER, $issuer); + } + + /** + * @inheritDoc + * @pure + */ + public function canOnlyBeUsedAfter(DateTimeImmutable $notBefore): BuilderInterface + { + return $this->setClaim(RegisteredClaims::NOT_BEFORE, $notBefore); + } + + /** + * @inheritDoc + * @pure + */ + public function relatedTo(string $subject): BuilderInterface + { + return $this->setClaim(RegisteredClaims::SUBJECT, $subject); + } + + /** + * @inheritDoc + * @pure + */ + public function withHeader(string $name, mixed $value): BuilderInterface + { + $new = clone $this; + $new->headers[$name] = $value; + + return $new; + } + + /** + * @inheritDoc + * @pure + */ + public function withClaim(string $name, mixed $value): BuilderInterface + { + if (in_array($name, RegisteredClaims::ALL, true)) { + throw RegisteredClaimGiven::forClaim($name); + } + + return $this->setClaim($name, $value); + } + + /** + * @param non-empty-string $name + */ + private function setClaim(string $name, mixed $value): BuilderInterface + { + $new = clone $this; + $new->claims[$name] = $value; + + return $new; + } + + /** + * @param array $items + * + * @throws CannotEncodeContent When data cannot be converted to JSON. + */ + private function encode(array $items): string + { + return $this->encoder->base64UrlEncode( + $this->encoder->jsonEncode($items), + ); + } + + /** + * @inheritDoc + */ + public function getToken(Signer $signer, Key $key): UnencryptedToken + { + $headers = $this->headers; + $headers['alg'] = $signer->algorithmId(); + + $encodedHeaders = $this->encode($headers); + $encodedClaims = $this->encode($this->claimFormatter->formatClaims($this->claims)); + + $signature = $signer->sign($encodedHeaders . '.' . $encodedClaims, $key); + $encodedSignature = $this->encoder->base64UrlEncode($signature); + + return new Plain( + new DataSet($headers, $encodedHeaders), + new DataSet($this->claims, $encodedClaims), + new Signature($signature, $encodedSignature), + ); + } + /** + * Sets Opencast specific claims at one go with opencast jwt claim specifications. + * + * @param OcJwtClaim $ocClaims + * + * @return BuilderInterface + */ + public function setOcClaims(OcJwtClaim $ocClaims): BuilderInterface + { + $new = clone $this; + + foreach ($ocClaims->toArray() as $name => $value) { + if (!in_array($name, OcJwtClaim::OC_CLAIMS, true)) { + throw new \InvalidArgumentException(sprintf('Claim "%s" is not a valid Opencast claim.', $name)); + } + $new->claims[$name] = $value; + } + + return $new; + } +} + diff --git a/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtClaim.php b/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtClaim.php new file mode 100644 index 000000000..d96042164 --- /dev/null +++ b/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtClaim.php @@ -0,0 +1,517 @@ + now() are rejected by Opencast. + * This claim is optional. + */ + private ?int $nbf = null; + + /** @var string Opencast username + * The subject of the JWT. + * This claim is required. + */ + private ?string $sub = null; + + /** @var string Display name of the user + * The display name of the user. + * This claim is required. + */ + private ?string $name = null; + + /** @var string User email + * The email of the user. + * This claim is required. + */ + private ?string $email = null; + + /** @var array Roles + * The roles assigned to the user. + * This claim is optional. + */ + private array $roles = []; + + /** @var array Event ACLs + * The event-specific ACLs for the user. + * This claim is optional. + */ + private array $eventAcls = []; + + /** @var array Series ACLs + * The series-specific ACLs for the user. + * This claim is optional. + */ + private array $seriesAcls = []; + + /** @var array Playlist ACLs + * The playlist-specific ACLs for the user. + * This claim is optional. + */ + private array $playlistAcls = []; + + public function __construct() + { + } + + /** + * Sets the user information claims for the JWT. + * + * @param string $sub The subject (username) of the JWT. + * @param string|null $name The display name of the user (optional). + * @param string|null $email The email address of the user (optional). + * + * @return void + */ + public function setUserInfoClaims(string $sub, ?string $name = null, ?string $email = null): void + { + $this->sub = $sub; + $this->name = $name; + $this->email = $email; + } + + /** + * Gets the subject (username) claim of the JWT. + * + * @return string|null The subject of the JWT, or null if not set. + */ + public function getSub(): ?string + { + return $this->sub; + } + + /** + * Gets the name (name of user) claim of the JWT. + * + * @return string|null The name of the user, or null if not set. + */ + public function getName(): ?string + { + return $this->name; + } + + /** + * Gets the email claim of the JWT. + * + * @return string|null The email of the user, or null if not set. + */ + public function getEmail(): ?string + { + return $this->email; + } + + /** + * Sets Not Before (nbf) claim of the JWT. + * + * @param int $nbf The Not Before time as a Unix timestamp. + * @return void + */ + public function setNbf(int $nbf): void + { + $this->nbf = $nbf; + } + + /** + * Gets the Not Before (nbf) claim of the JWT. + * + * @return int|null The Not Before time as a Unix timestamp, or null if not set. + */ + public function getNbf(): ?int + { + return $this->nbf; + } + + /** + * Sets the expiration time (exp) claim for the JWT. + * + * @param DateTimeImmutable $exp The expiration time as a DateTimeImmutable object. + * @return void + */ + public function setExp(DateTimeImmutable $exp): void + { + $this->exp = $exp; + } + + /** + * Gets the expiration time (exp) claim of the JWT. + * + * @return DateTimeImmutable The expiration time as a DateTimeImmutable object. + */ + public function getExp(): DateTimeImmutable + { + return $this->exp; + } + + /** + * Checks if the object has an expiration time (exp) claim. + * + * @return bool True if the expiration time is set, false otherwise. + */ + public function hasExp(): bool + { + return isset($this->exp); + } + + /** + * Sets the roles claim for the JWT. + * + * @param array $roles The roles to assign to the user. + * @return void + */ + public function setRoles(array $roles): void + { + $this->roles = $roles; + } + + /** + * Gets the roles claim of the JWT. + * + * @return array The roles assigned to the user. + */ + public function getRoles(): array + { + return $this->roles; + } + + /** + * Sets the event access control lists (ACLs) for the JWT. + * + * @param array $acls The event ACLs to assign to the user. + * @return void + */ + public function setEventAcls(array $acls): void + { + foreach ($acls as $identifier => $actions) { + $key = self::OC_EVENT . $identifier; + $this->eventAcls[$key] = $actions; + } + } + + /** + * Sets the series access control lists (ACLs) for the JWT. + * + * @param array $acls The series ACLs to assign to the user. + * @return void + */ + public function setSeriesAcls(array $acls): void + { + foreach ($acls as $identifier => $actions) { + $key = self::OC_SERIES . $identifier; + $this->seriesAcls[$key] = $actions; + } + } + + /** + * Sets the playlist access control lists (ACLs) for the JWT. + * + * @param array $acls The playlist ACLs to assign to the user. + * @return void + */ + public function setPlaylistAcls(array $acls): void + { + foreach ($acls as $identifier => $actions) { + $key = self::OC_PLAYLIST . $identifier; + $this->playlistAcls[$key] = $actions; + } + } + + /** + * Gets the access control lists (ACLs) as for "oc" claims of the JWT. + * it is a combination of event, series and playlist ACLs in "oc" claims format. + * + * @return array The ACLs to access the resource. Keys are "event", "series" and "playlist". + */ + public function getAclsClaims(): array + { + return [ + 'event' => $this->eventAcls, + 'series' => $this->seriesAcls, + 'playlist' => $this->playlistAcls, + ]; + } + + /** + * Converts the Opencast JWT claim object to an array. + * + * @return array The Opencast JWT claims as an array. + * @throws \InvalidArgumentException if opencast claims requirements are not met! + */ + public function toArray(): array + { + if (empty($this->exp)) { + throw new \InvalidArgumentException("JWT: Expiration time is required"); + } + $data = [ + 'exp' => $this->exp, + ]; + if (!empty($this->sub)) { + $data['sub'] = $this->sub; + } + if (!empty($this->name)) { + $data['name'] = $this->name; + } + if (!empty($this->email)) { + $data['email'] = $this->email; + } + if (!empty($this->roles) && is_array($this->roles)) { + $data['roles'] = $this->roles; + } + if ($this->hasOcAcls()) { + $data['oc'] = array_merge( + $this->eventAcls, + $this->seriesAcls, + $this->playlistAcls + ); + } + + if (empty($data['oc']) && empty($data['roles'])) { + throw new \InvalidArgumentException("JWT: At least one of 'oc' or 'roles' claims must be set"); + } + + if ($this->nbf !== null) { + $data['nbf'] = $this->nbf; + } + return $data; + } + + /** + * Converts the Opencast JWT claim object to JSON. + * + * @return string The Opencast JWT claims as a JSON string. + */ + public function toJson(): string + { + return json_encode($this->toArray(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + } + + /** + * Checks if the object has any Opencast ACLs set. + * + * @return bool True if any Opencast ACLs are set, false otherwise. + */ + private function hasOcAcls(): bool + { + return !empty($this->eventAcls) || !empty($this->seriesAcls) || !empty($this->playlistAcls); + } + + /** + * Converts a JWT token to an Opencast JWT claim object. + * + * @param Token $token The JWT token to convert. + * @return self The Opencast JWT claim object. + * @throws \InvalidArgumentException if the token is invalid. + */ + public static function convertFromTokenWithValidation(Token $token): self + { + $instance = new self(); + + if (!$token->claims()->has('exp')) { + throw new \InvalidArgumentException("JWT: Expiration time is required"); + } + + $instance->setExp($token->claims()->get('exp')); + + if (!$token->claims()->has('oc') && !$token->claims()->has('roles') + || (empty($token->claims()->get('oc')) && empty($token->claims()->get('roles')))) { + throw new \InvalidArgumentException("JWT: At least one of 'oc' or 'roles' claims must be set"); + } + + $aclClaims = $token->claims()->get('oc') ?? []; + if (!empty($aclClaims)) { + $eventAcls = []; + $seriesAcls = []; + $playlistAcls = []; + foreach ($aclClaims as $aclKey => $actions) { + $identifier = substr($aclKey, 2); + if (str_starts_with($aclKey, self::OC_EVENT)) { + $eventAcls[$identifier] = $actions; + } elseif (str_starts_with($aclKey, self::OC_SERIES)) { + $seriesAcls[$identifier] = $actions; + } elseif (str_starts_with($aclKey, self::OC_PLAYLIST)) { + $playlistAcls[$identifier] = $actions; + } + } + $instance->setEventAcls($eventAcls); + $instance->setSeriesAcls($seriesAcls); + $instance->setPlaylistAcls($playlistAcls); + } + + $instance->setRoles($token->claims()->get('roles') ?? []); + + if (!empty($token->claims()->get('sub'))) { + $instance->setUserInfoClaims( + $token->claims()->get('sub'), + $token->claims()->get('name') ?? null, + $token->claims()->get('email') ?? null + ); + } + + $nbf = $token->claims()->get('nbf'); + if (!empty($nbf) && is_int($nbf)) { + $instance->setNbf($nbf); + } + + return $instance; + } + + /** + * Converts an array to an Opencast JWT claim object. + * + * @param array $data The array to convert. + * @return self The Opencast JWT claim object. + * @throws \InvalidArgumentException if the array is invalid. + */ + public static function createFromArray(array $data): self + { + $instance = new self(); + + if (isset($data['exp'])) { + $instance->setExp($data['exp']); + } + + if (isset($data['sub'])) { + $instance->setUserInfoClaims( + $data['sub'], + $data['name'] ?? null, + $data['email'] ?? null + ); + } + + if (empty($data['oc']) && empty($data['roles'])) { + throw new \InvalidArgumentException("JWT: At least one of 'oc' or 'roles' claims must be set"); + } + + if (isset($data['roles'])) { + $instance->setRoles($data['roles']); + } + + if (isset($data['oc'])) { + $aclClaims = $data['oc']; + $eventAcls = []; + $seriesAcls = []; + $playlistAcls = []; + foreach ($aclClaims as $aclKey => $actions) { + $identifier = substr($aclKey, 2); + if (str_starts_with($aclKey, self::OC_EVENT)) { + $eventAcls[$identifier] = $actions; + } elseif (str_starts_with($aclKey, self::OC_SERIES)) { + $seriesAcls[$identifier] = $actions; + } elseif (str_starts_with($aclKey, self::OC_PLAYLIST)) { + $playlistAcls[$identifier] = $actions; + } + } + $instance->setEventAcls($eventAcls); + $instance->setSeriesAcls($seriesAcls); + $instance->setPlaylistAcls($playlistAcls); + } + + return $instance; + } + + /** + * Generates a formatted DateTimeImmutable object from a Unix timestamp. + * Using RFC 3339 standards formatting required by Opencast. + * + * @param int $duration_seconds The duration of the token in seconds. + * @return DateTimeImmutable The formatted DateTimeImmutable object. + */ + public static function generateFormattedDateTimeObject(int $duration_seconds): DateTimeImmutable + { + $dt = (new DateTimeImmutable())->modify("+{$duration_seconds} seconds"); + $dtFormatted = DateTimeImmutable::createFromFormat(DateTimeInterface::RFC3339, $dt->format(DateTimeInterface::RFC3339)); + return $dtFormatted; + } + + /** + * Check if the set of actions are matching the current actions of each opencast acl domain. + * + * @param string $key the key could be e:, s:, p: using self::OC_EVENT, self::OC_SERIES and self::OC_PLAYLIST. + * @param string $identifier the resources id, could be event id, series id or playlist id. + * @param array $actions the list of action to compare with. + * + * @return bool return true if both current and incoming actions of the oc claim match, false otherwise. + */ + public function actionsMatchFor(string $key, string $identifier, array $actions): bool { + $acls = $this->getAclsClaims(); + $sets = null; + + switch ($key) { + case self::OC_EVENT: + $sets = $acls['event'] ?? null; + break; + case self::OC_SERIES: + $sets = $acls['series'] ?? null; + break; + case self::OC_PLAYLIST: + $sets = $acls['playlist'] ?? null; + break; + default: + return false; + break; + } + + if (!empty($sets) && !empty($sets[$key . $identifier])) { + $current = array_values($sets[$key . $identifier]); + sort($current); + sort($actions); + + return $current === $actions; + } + + return false; + } +} diff --git a/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtHandler.php b/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtHandler.php new file mode 100644 index 000000000..bc39e93f6 --- /dev/null +++ b/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtHandler.php @@ -0,0 +1,176 @@ + Sha256::class, + 'ES384' => Sha384::class, + 'EdDSA' => Eddsa::class + ]; + + /** @var string default algorithm */ + const DEFAULT_ALGORITHM = 'ES256'; + + /** @var string default audience */ + const AUDIENCE = 'opencast-php-library'; + + /** + * Constructor + */ + public function __construct(string $privateKeyString, ?string $algorithmKey = null, ?int $expDuration = null) + { + $algorithmKey = $algorithmKey ?? self::DEFAULT_ALGORITHM; + + if (!array_key_exists($algorithmKey, self::SUPPORTED_ALGORITHMS)) { + throw new \InvalidArgumentException("JWT: Unsupported algorithm: $algorithmKey"); + } + + if (empty($privateKeyString)) { + throw new \InvalidArgumentException("JWT: Private key is required"); + } + + if (!empty($expDuration) && $expDuration > 0) { + $this->expDuration = $expDuration; + } + + $signerClassname = self::SUPPORTED_ALGORITHMS[$algorithmKey]; + $this->signer = new $signerClassname(); + + $signingKey = InMemory::plainText($privateKeyString); + + // Randomly generated, but not effectively in-use. + $verificationKey = InMemory::base64Encoded(base64_encode(random_bytes(32))); + + $configuration = Configuration::forAsymmetricSigner( + $this->signer, + $signingKey, + $verificationKey + ); + + // Register Opencast specific builder. + $version = \Composer\InstalledVersions::getVersion('lcobucci/jwt'); + if (version_compare($version, '5.5', '>=')) { + $configuration = $configuration->withBuilderFactory( + static function (ClaimsFormatter $formatter) : Builder { + return OcJwtBuilder::new(new JoseEncoder(), $formatter); + } + ); + } else { + $configuration->setBuilderFactory( + static function (ClaimsFormatter $formatter) : Builder { + return OcJwtBuilder::new(new JoseEncoder(), $formatter); + } + ); + } + + $this->config = $configuration; + } + + /** + * Gets the supported JWT algorithms. + * + * @return array The supported JWT algorithms. + */ + public static function getSupportedAlgorithms(): array + { + return array_keys(self::SUPPORTED_ALGORITHMS); + } + + /** + * Issues a JWT token for the given claims. + * + * @param OcJwtClaim $claim The claims to include in the token. + * @return string The signed JWT token. + */ + public function issueToken(OcJwtClaim $claim): string + { + if (!$claim->hasExp()) { + $expiryFormatted = OcJwtClaim::generateFormattedDateTimeObject((int) $this->expDuration); + $claim->setExp($expiryFormatted); + } + + $builder = $this->config->builder()->setOcClaims($claim); + + return $builder->getToken($this->config->signer(), $this->config->signingKey())->toString(); + } + + /** + * Validates a JWT token. + * + * @param string $tokenString The JWT token string to validate. + * @return bool True if the token is valid, false otherwise. + */ + public function validateToken(string $tokenString): bool + { + $token = $this->tokenParser($tokenString); + if ($token === null) { + return false; + } + + return $this->config->validator()->validate($token, new OcJwtValidationConstraint()); + } + + /** + * Parses a JWT token string into a Token object. + * + * @param string $tokenString The JWT token string to parse. + * @return Token|null The parsed Token object, or null if parsing failed. + */ + private function tokenParser(string $tokenString): ?Token + { + $token = null; + try { + $token = $this->config->parser()->parse($tokenString); + } catch (CannotDecodeContent | InvalidTokenStructure | UnsupportedHeaderFound $e) { + throw new \InvalidArgumentException('JWT: Unable to parse token: ' . $e->getMessage()); + } + assert($token instanceof UnencryptedToken, 'Token must be an UnencryptedToken'); + + return $token; + } + + /** + * Returns the OcJwtClaim object from encoded token string. + * + * @param string $tokenString The JWT token string to convert to OcJwtClaim. + * @return OcJwtClaim|null The OcJwtClaim object or null if failed. + */ + public function getOcJwtClaimFromTokenString(string $tokenString): ?OcJwtClaim { + try { + $token = $this->tokenParser($tokenString); + if ($token === null) { + return null; + } + return OcJwtClaim::convertFromTokenWithValidation($token); + } catch (\Throwable $th) { + return null; + } + } +} diff --git a/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtValidationConstraint.php b/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtValidationConstraint.php new file mode 100644 index 000000000..e6dd0ef86 --- /dev/null +++ b/vendor/elan-ev/opencast-api/src/OpencastApi/Auth/JWT/OcJwtValidationConstraint.php @@ -0,0 +1,39 @@ +claims()->has(Token\RegisteredClaims::EXPIRATION_TIME)) { + throw ConstraintViolation::error('"Expiration Time" claim missing', $this); + } + + if ($token->isExpired($now)) { + throw ConstraintViolation::error('The token is expired', $this); + } + + try { + $ocClaim = OcJwtClaim::convertFromTokenWithValidation($token); + } catch (Throwable $th) { + throw ConstraintViolation::error('Invalid Opencast specific claims!', $this); + } + + assert($ocClaim instanceof OcJwtClaim, 'Invalid Opencast JWT claim!'); + } +} diff --git a/vendor/elan-ev/opencast-api/src/OpencastApi/Opencast.php b/vendor/elan-ev/opencast-api/src/OpencastApi/Opencast.php index fe37646ff..8ec40a4bf 100644 --- a/vendor/elan-ev/opencast-api/src/OpencastApi/Opencast.php +++ b/vendor/elan-ev/opencast-api/src/OpencastApi/Opencast.php @@ -3,6 +3,7 @@ use OpencastApi\Rest\OcRestClient; use OpencastApi\Rest\OcIngest; +use OpencastApi\Auth\JWT\OcJwtHandler; class Opencast { @@ -72,6 +73,9 @@ class Opencast /** @var \OpencastApi\Rest\OcListProvidersApi $listProvidersApi */ public $listProvidersApi; + /** @var \OpencastApi\Rest\OcInfo $info */ + public $info; + /* $config = [ 'url' => 'https://develop.opencast.org/', // The API url of the opencast instance (required) @@ -95,6 +99,11 @@ class Opencast 'handler' => null, // The callable Handler or HandlerStack. (Default null). (optional) 'features' => null, // A set of additional features [e.g. lucene search]. (Default null). (optional) 'guzzle' => null, // Additional Guzzle Request Options. These options can overwrite some default options (Default null). (optional) + 'jwt' => [ // JWT Configuration, null will deactivate the guard + 'private_key' => 'your-private-key-content', // Private Key string. + 'algorithm' => 'ES256', // Selected algorithm. @see OpencastApi\Auth\JWT\OcJwtHandler::SUPPORTED_ALGORITHMS + 'expiration' => 15 // Expiration time in seconds. default to 15 seconds. + ], ] */ /** @@ -110,6 +119,16 @@ public function __construct($config, $engageConfig = [], $enableingest = true) $this->setEndpointProperties($config, $enableingest); } + /** + * Get the JWT Handler from the Rest Client. + * + * @return OcJwtHandler|null + */ + public function getRestJwtHandler(): ?OcJwtHandler + { + return $this->restClient->getJwtHandler(); + } + private function setEndpointProperties($config, $enableingest) { foreach(glob(__DIR__ . '/Rest/*.php') as $classPath) { @@ -181,6 +200,9 @@ private function setEngageRestClient($config, $engageConfig) if (!isset($engageConfig['guzzle']) && isset($config['guzzle'])) { $engageConfig['guzzle'] = $config['guzzle']; } + if (!isset($engageConfig['jwt']) && isset($config['jwt'])) { + $engageConfig['jwt'] = $config['jwt']; + } $this->engageRestClient = new OcRestClient($engageConfig); } @@ -193,10 +215,21 @@ private function setIngestProperty($config) if (!empty($servicesJson['body']) && property_exists($servicesJson['body'], 'services')) { $service = $servicesJson['body']->services->service; if (is_array($service)) { - // Choose random ingest service. - $ingestService = $service[array_rand($service)]; + // Filter running ingest services. + $running_services = array_filter($service, function ($s) { + return $s->active && $s->online && !$s->maintenance; + }); + // If no running services, return. + if (empty($running_services)) { + return; + } + // Take the first running service. + $ingestService = reset($running_services); } else { - // There is only one. + // There is only one and is running. + if (!($service->active && $service->online && !$service->maintenance)) { + return; + } $ingestService = $service; } diff --git a/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcInfo.php b/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcInfo.php new file mode 100644 index 000000000..aa4e12148 --- /dev/null +++ b/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcInfo.php @@ -0,0 +1,24 @@ +registerHeaderException('Accept', self::URI); + parent::__construct($restClient); + } + + /** + * Returns information about the current user + * + * @return array the response result ['code' => 200, 'body' => '{The current user information is returned.}'] + */ + public function getInfoMeJson() + { + return $this->restClient->performGet(self::URI . '/me.json'); + } +} +?> diff --git a/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcRest.php b/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcRest.php index 3363815e4..877a8c60e 100644 --- a/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcRest.php +++ b/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcRest.php @@ -1,6 +1,8 @@ restClient->setRequestConnectionTimeout($connectionTimeout); return $this; } + + /** + * Sets the JWT claims of rest client class to be used for the request. + * + * @param OcJwtClaim $jwtClaims The JWT claims to set. + * + * @return object $this the class object where the call is requested from. + */ + public function withClaims(OcJwtClaim $jwtClaims) + { + $this->restClient->setJwtClaims($jwtClaims); + return $this; + } } ?> diff --git a/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcRestClient.php b/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcRestClient.php index 887bda23d..5c456d725 100644 --- a/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcRestClient.php +++ b/vendor/elan-ev/opencast-api/src/OpencastApi/Rest/OcRestClient.php @@ -2,23 +2,29 @@ namespace OpencastApi\Rest; use GuzzleHttp\Client; +use OpencastApi\Auth\JWT\OcJwtClaim; +use OpencastApi\Auth\JWT\OcJwtHandler; +use GuzzleHttp\Exception\RequestException; class OcRestClient extends Client { - private $baseUri; - private $username; - private $password; - private $timeout = 0; - private $connectTimeout = 0; - private $disposableTimeout = null; - private $disposableConnectTimeout = null; - private $version; - private $headerExceptions = []; - private $additionalHeaders = []; - private $noHeader = false; - private $origin; - private $features = []; - private $globalOptions = []; + private string $baseUri; + private string $username; + private string $password; + private int $timeout = 0; + private int $connectTimeout = 0; + private ?int $disposableTimeout = null; + private ?int $disposableConnectTimeout = null; + private ?string $version = null; + private array $headerExceptions = []; + private array $additionalHeaders = []; + private bool $noHeader = false; + private ?array $origin = null; + private array $features = []; + private array $globalOptions = []; + private array $jwtConfig = []; + private ?OcJwtClaim $jwtClaim = null; + private ?OcJwtHandler $jwtHandler = null; /* $config = [ @@ -31,6 +37,11 @@ class OcRestClient extends Client 'handler' => null, // The callable Handler or HandlerStack. (Default null). (optional) 'features' => null, // A set of additional features [e.g. lucene search]. (Default null). (optional) 'guzzle' => null, // Additional Guzzle Request Options. These options can overwrite some default options (Default null). (optional) + 'jwt' => [ // JWT Configuration, null will deactivate the guard + 'private_key' => 'your-private-key-content', // Private Key string. + 'algorithm' => 'ES256', // Selected algorithm. @see OpencastApi\Auth\JWT\OcJwtHandler::SUPPORTED_ALGORITHMS + 'expiration' => 15 // Expiration time in seconds. default to 15 seconds. + ], ] */ public function __construct($config) @@ -65,9 +76,23 @@ public function __construct($config) $this->globalOptions = $config['guzzle']; } + if (isset($config['jwt']) && is_array($config['jwt'])) { + $this->jwtConfig = $config['jwt']; + $this->jwtHandler = new OcJwtHandler( + $this->jwtConfig['private_key'], + $this->jwtConfig['algorithm'] ?? null, + $this->jwtConfig['expiration'] ?? null + ); + } + parent::__construct($parentConstructorConfig); } + public function getJwtHandler(): ?OcJwtHandler + { + return $this->jwtHandler; + } + public function readFeatures($key = null) { if (empty($key)) { return $this->features; @@ -86,6 +111,11 @@ public function registerHeaderException($header, $path) { } } + public function setJwtClaims(OcJwtClaim $jwtClaim) + { + $this->jwtClaim = $jwtClaim; + } + public function registerAdditionalHeader($header, $value) { $this->additionalHeaders[$header] = $value; @@ -162,6 +192,54 @@ private function addRequestOptions($uri, $options) return $requestOptions; } + /** + * Ensures JWT authentication for the request by injecting a JWT token into the request options. + * + * If JWT configuration and claims are set, this method generates a JWT token and adds it to the request + * according to the HTTP method (GET, POST, PUT, etc.). It also removes basic auth credentials if JWT is used. + * + * @param array $requestOptions The original request options. + * @param string $method The HTTP method (e.g., GET, POST, PUT). + * @return array The modified request options with JWT authentication applied. + */ + private function ensureJwtAuthGuard(array $requestOptions, string $method): array + { + if (isset($this->jwtClaim) && !empty($this->jwtConfig)) { + $privateKeyString = $this->jwtConfig['private_key']; + $algorithmKey = $this->jwtConfig['algorithm'] ?? null; + $expDuration = $this->jwtConfig['expiration'] ?? null; + + $jwtHandler = new OcJwtHandler($privateKeyString, $algorithmKey, $expDuration); + $jwtToken = $jwtHandler->issueToken($this->jwtClaim); + + switch ($method) { + case 'GET': + $requestOptions['query']['jwt'] = (string) $jwtToken; + break; + case 'PUT': + case 'POST': + if (isset($requestOptions['form_params'])) { + $requestOptions['form_params']['jwt'] = (string) $jwtToken; + } else if (isset($requestOptions['multipart'])) { + $requestOptions['multipart'][] = [ + 'name' => 'jwt', + 'contents' => (string) $jwtToken + ]; + } + break; + default: + $requestOptions['headers'][] = "Authorization: Bearer " . (string) $jwtToken; + break; + } + + // As we now have a JWT token, we can remove the basic auth credentials. + if (isset($requestOptions['auth'])) { + unset($requestOptions['auth']); + } + } + return $requestOptions; + } + public function hasVersion($version) { if (empty($this->version)) { @@ -197,16 +275,17 @@ public function getVersion() { return $this->version; } - private function resolveResponseBody(string $body) + private function resolveResponseBody($response) { - $result = json_decode($body); + $body = $response->getBody(); + $body->rewind(); + $contents = $body->getContents() ?? ''; + $result = json_decode($contents); if ($result !== null) { return $result; } - // TODO: Here we can add more return type if needed... - - if (!empty($body)) { - return $body; + if (!empty($contents)) { + return $contents; } return null; @@ -217,11 +296,7 @@ private function returnResult($response) $result = []; $result['code'] = $response->getStatusCode(); $result['reason'] = $response->getReasonPhrase(); - $body = ''; - if ($result['code'] < 400 && !empty((string) $response->getBody())) { - $body = $this->resolveResponseBody((string) $response->getBody()); - } - $result['body'] = $body; + $result['body'] = $this->resolveResponseBody($response); $location = ''; if ($response->hasHeader('Location')) { @@ -238,7 +313,9 @@ public function performGet($uri, $options = []) { $this->prepareOrigin($uri, $options, 'GET'); try { - $response = $this->get($uri, $this->addRequestOptions($uri, $options)); + $requestOptions = $this->addRequestOptions($uri, $options); + $requestOptions = $this->ensureJwtAuthGuard($requestOptions, 'GET'); + $response = $this->get($uri, $requestOptions); return $this->returnResult($response); } catch (\Throwable $th) { return $this->resolveException($th); @@ -249,7 +326,9 @@ public function performPost($uri, $options = []) { $this->prepareOrigin($uri, $options, 'POST'); try { - $response = $this->post($uri, $this->addRequestOptions($uri, $options)); + $requestOptions = $this->addRequestOptions($uri, $options); + $requestOptions = $this->ensureJwtAuthGuard($requestOptions, 'POST'); + $response = $this->post($uri, $requestOptions); return $this->returnResult($response); } catch (\Throwable $th) { return $this->resolveException($th); @@ -261,7 +340,9 @@ public function performPut($uri, $options = []) { $this->prepareOrigin($uri, $options, 'PUT'); try { - $response = $this->put($uri, $this->addRequestOptions($uri, $options)); + $requestOptions = $this->addRequestOptions($uri, $options); + $requestOptions = $this->ensureJwtAuthGuard($requestOptions, 'PUT'); + $response = $this->put($uri, $requestOptions); return $this->returnResult($response); } catch (\Throwable $th) { return $this->resolveException($th); @@ -272,7 +353,9 @@ public function performDelete($uri, $options = []) { $this->prepareOrigin($uri, $options, 'DELETE'); try { - $response = $this->delete($uri, $this->addRequestOptions($uri, $options)); + $requestOptions = $this->addRequestOptions($uri, $options); + $requestOptions = $this->ensureJwtAuthGuard($requestOptions, 'DELETE'); + $response = $this->delete($uri, $requestOptions); return $this->returnResult($response); } catch (\Throwable $th) { return $this->resolveException($th); @@ -284,8 +367,18 @@ private function resolveException(\Throwable $th) $error = []; $error['code'] = $th->getCode(); $error['reason'] = $th->getMessage(); - $error['body'] = ''; - $error['location'] = ''; + + $bodyContents = ''; + $location = ''; + if ($th instanceof RequestException && $th->hasResponse()) { + $response = $th->getResponse(); + $bodyContents = $this->resolveResponseBody($response); + if ($response->hasHeader('Location')) { + $location = $response->getHeader('Location'); + } + } + $error['body'] = $bodyContents; + $error['location'] = $location; $error['origin'] = !empty($this->origin) ? $this->origin : null; if (!empty($error['reason'])) { return $error; diff --git a/vendor/elan-ev/opencast-api/tests/DataProvider/EventsDataProvider.php b/vendor/elan-ev/opencast-api/tests/DataProvider/EventsDataProvider.php index 53f1cbc15..33f0bce91 100644 --- a/vendor/elan-ev/opencast-api/tests/DataProvider/EventsDataProvider.php +++ b/vendor/elan-ev/opencast-api/tests/DataProvider/EventsDataProvider.php @@ -72,5 +72,9 @@ public static function getVttFile($lang = 'de', $overwrite = false) $filename = "/test_files/video_test{$overwitestr}_{$lang}.vtt"; return Psr7\Utils::tryFopen(__DIR__ . $filename, 'r'); } + public static function getScheduling($captureId, $startdata, $enddata) + { + return '{"agent_id": "' . $captureId . '","start": "' . $startdata . '","end": "' . $enddata . '", "inputs": ["default"]}'; + } } ?> diff --git a/vendor/elan-ev/opencast-api/tests/DataProvider/SetupDataProvider.php b/vendor/elan-ev/opencast-api/tests/DataProvider/SetupDataProvider.php index 8ff65348e..f8631fd5c 100644 --- a/vendor/elan-ev/opencast-api/tests/DataProvider/SetupDataProvider.php +++ b/vendor/elan-ev/opencast-api/tests/DataProvider/SetupDataProvider.php @@ -27,6 +27,24 @@ public static function getConfig($version = ''): array return $config; } + public static function getConfigWithJwt($version = ''): array + { + $config = self::getConfig($version); + $config['url'] = 'https://oc-dev.elan-ev.de'; + $config['username'] = 'unit_test_api_user'; + $config['password'] = 'opencast'; + $config['jwt'] = [ + 'private_key' => '-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIJyVBVwEP05kgIfOxLEjd7qWZPu1HYZ1lNEZrXDc0CWJoAoGCCqGSM49 +AwEHoUQDQgAENN9jCcHjZ8pCxPeM+rYSDlZm0OCLvTYdldHfs0zG4pks/NASlitO +5N1sUX/zBEsYXdz11v5uGvQIZDivP30TDQ== +-----END EC PRIVATE KEY-----', + 'algorithm' => 'ES256', + 'expiration' => 3600 + ]; + return $config; + } + public static function getMockResponses($data): array { $responseNames = []; diff --git a/vendor/elan-ev/opencast-api/tests/OcTestCase.php b/vendor/elan-ev/opencast-api/tests/OcTestCase.php new file mode 100644 index 000000000..b68abf1f1 --- /dev/null +++ b/vendor/elan-ev/opencast-api/tests/OcTestCase.php @@ -0,0 +1,21 @@ + diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcAgentsApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcAgentsApiTest.php index d7ee9e03d..aa5834f5b 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcAgentsApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcAgentsApiTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcAgentsApiTest extends TestCase +#[\AllowDynamicProperties] +class OcAgentsApiTest extends OcTestCase { + private $ocAgentsApi; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcBaseApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcBaseApiTest.php index 7fadc0efc..6c37a9897 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcBaseApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcBaseApiTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcBaseApiTest extends TestCase +#[\AllowDynamicProperties] +class OcBaseApiTest extends OcTestCase { + private $ocBaseApi; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcEventsApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcEventsApiTest.php index 864b05f0e..f9c5b7aba 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcEventsApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcEventsApiTest.php @@ -3,17 +3,22 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcEventsApiTest extends TestCase +#[\AllowDynamicProperties] +class OcEventsApiTest extends OcTestCase { + private $ocEventsApi; + private $ocCaptureAdmin; + protected function setUp(): void { parent::setUp(); $config = \Tests\DataProvider\SetupDataProvider::getConfig(); $ocRestApi = new Opencast($config, [], false); $this->ocEventsApi = $ocRestApi->eventsApi; + $this->ocCaptureAdmin = $ocRestApi->captureAdmin; } /** @@ -325,5 +330,52 @@ public function get_update_scheduling(string $identifier): void $this->markTestIncomplete('No scheduling to complete the test!'); } } + + /** + * @test + */ + public function scheduling_conflict(): void + { + $startdate = new \DateTime('now', new \DateTimeZone('UTC')); + $startdate->modify('+2 hours'); + $startdateformated = $startdate->format('Y-m-d\TH:i:s.v\Z'); + + $enddate = new \DateTime('now', new \DateTimeZone('UTC')); + $enddate->modify('+3 hours'); + $enddateformated = $enddate->format('Y-m-d\TH:i:s.v\Z'); + + $captureId = 'capture_' . time() . '_' . uniqid(); + $response = $this->ocCaptureAdmin->setAgentState($captureId, 'idle'); + $this->assertSame(200, $response['code'], 'Failed to create Capture Agent!'); + + $scheduling = \Tests\DataProvider\EventsDataProvider::getScheduling($captureId, $startdateformated, $enddateformated); + + $responseScheduling = $this->ocEventsApi->create( + \Tests\DataProvider\EventsDataProvider::getAcls(), + \Tests\DataProvider\EventsDataProvider::getMetadata('presenter'), + \Tests\DataProvider\EventsDataProvider::getProcessing(), + $scheduling, + null, + null, + null, + null + ); + $this->assertContains($responseScheduling['code'], [200, 201], 'Failure to schedule the event'); + + // Now we try to perform another scheudling, which should give us the 409 conflict. + $responseRepeatScheduling = $this->ocEventsApi->create( + \Tests\DataProvider\EventsDataProvider::getAcls(), + \Tests\DataProvider\EventsDataProvider::getMetadata('presenter'), + \Tests\DataProvider\EventsDataProvider::getProcessing(), + $scheduling, + null, + null, + null, + null + ); + $this->assertSame(409, $responseRepeatScheduling['code'], 'Conflict not caught! Therefore something is wrong.'); + $this->assertNotEmpty($responseRepeatScheduling['body']); + $this->assertNotEmpty($responseRepeatScheduling['body'][0]); + } } ?> diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcGroupsApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcGroupsApiTest.php index 050c14eab..55d218f7c 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcGroupsApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcGroupsApiTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcGroupsApiTest extends TestCase +#[\AllowDynamicProperties] +class OcGroupsApiTest extends OcTestCase { + private $ocGroupsApi; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcIngestTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcIngestTest.php index 7daa48a4c..fd070a0c0 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcIngestTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcIngestTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcIngestTest extends TestCase +#[\AllowDynamicProperties] +class OcIngestTest extends OcTestCase { + private $ocIngest; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcJwtAuthTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcJwtAuthTest.php new file mode 100644 index 000000000..1d055edcc --- /dev/null +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcJwtAuthTest.php @@ -0,0 +1,134 @@ +jwtHandler = $ocRestApi->getRestJwtHandler(); + $this->ocInfo = $ocRestApi->info; + $this->ocEventsApi = $ocRestApi->eventsApi; + $this->exOcRestApi = new OcRestClient($config); + } + + /** + * @test + */ + public function get_info_me_with_jwt_claim_setters(): void + { + $ocClaim = new OcJwtClaim(); + $name = 'JWT TEST USER 1'; + $username = 'jwt_test_user_1'; + $email = 'jwt_test_user_1@test.test'; + $ocClaim->setUserInfoClaims($username, $name, $email); + $ocClaim->setRoles(['ROLE_USER_1', 'ROLE_JWT_USER_1']); + $response = $this->ocInfo->withClaims($ocClaim)->getInfoMeJson(); + $this->assertSame(200, $response['code'], 'Failure to get base info'); + $body = $response['body']; + $this->assertEquals($body->user->name, $name, 'JWT Auth failed with invalid name!'); + } + + /** + * @test + */ + public function get_info_me_with_jwt_claim_array_creator(): void + { + $userInfoArray = [ + 'sub' => 'jwt_test_user_2', + 'name' => 'JWT TEST USER 2', + 'email' => 'jwt_test_user_2@test.test', + 'roles' => ['ROLE_USER_2', 'ROLE_JWT_USER_2'], + ]; + $ocClaim = OcJwtClaim::createFromArray($userInfoArray); + $response = $this->ocInfo->withClaims($ocClaim)->getInfoMeJson(); + $this->assertSame(200, $response['code'], 'Failure to get user roles'); + $body = $response['body']; + $this->assertContains($userInfoArray['roles'][0], $body->roles, 'JWT Auth failed with invalid roles!'); + $this->assertContains($userInfoArray['roles'][1], $body->roles, 'JWT Auth failed with invalid roles!'); + } + + /** + * @test + */ + public function static_file_access_with_jwt(): void + { + $response1 = $this->ocEventsApi->getAll(['withpublications' => true, 'limit' => 4]); + $body1 = $response1['body']; + $mediaUrl = $body1[0]->publications[0]->media[0]->url; + $eventId = $body1[0]->identifier; + + $ocClaim = new OcJwtClaim(); + $eventAcl = [ + "$eventId" => ['read'] + ]; + $ocClaim->setEventAcls($eventAcl); + $this->exOcRestApi->setJwtClaims($ocClaim); + $response3 = $this->exOcRestApi->performGet($mediaUrl); + $this->assertSame(200, $response3['code'], 'Failure to access media directly with JWT.'); + } + + /** + * @test + */ + public function generate_validate_token(): void + { + $response1 = $this->ocEventsApi->getAll(['withpublications' => true, 'limit' => 4]); + $body1 = $response1['body']; + $attachmentUrl = $body1[0]->publications[0]->attachments[0]->url; + $eventId = $body1[0]->identifier; + + $ocClaim = new OcJwtClaim(); + $eventAcl = [ + "$eventId" => ['read'] + ]; + $ocClaim->setEventAcls($eventAcl); + // Issue Token. + $accessToken = $this->exOcRestApi->getJwtHandler()->issueToken($ocClaim) ?? null; + $this->assertNotEmpty($accessToken); + + // Attach the token to the url and get the content. + $attachmentUrlWithJwt = $attachmentUrl . '?jwt=' . $accessToken; + $fileContent = file_get_contents($attachmentUrlWithJwt); + $this->assertNotEmpty($fileContent); + + // Validate the token. + $isValid = $this->exOcRestApi->getJwtHandler()->validateToken($accessToken); + $this->assertSame(true, $isValid, 'Invalid Token'); + + // Match ACL actions. + $oldClaim = $this->exOcRestApi->getJwtHandler()->getOcJwtClaimFromTokenString($accessToken); + $this->assertNotEmpty($oldClaim); + + $matchedActions = $oldClaim->actionsMatchFor(OcJwtClaim::OC_EVENT, $eventId, ['read']); + $this->assertSame(true, $matchedActions, 'Actions mismatched.'); + } +} +?> diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcListProvidersApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcListProvidersApiTest.php index 551ee62fa..520a08a5d 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcListProvidersApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcListProvidersApiTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcListProvidersApiTest extends TestCase +#[\AllowDynamicProperties] +class OcListProvidersApiTest extends OcTestCase { + private $ocListProvidersApi; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcPlaylistsApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcPlaylistsApiTest.php index 2838d66ef..036fa7698 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcPlaylistsApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcPlaylistsApiTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcPlaylistsApiTest extends TestCase +#[\AllowDynamicProperties] +class OcPlaylistsApiTest extends OcTestCase { + private $ocPlaylistsApi; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcRestClientWithGuzzleOptionTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcRestClientWithGuzzleOptionTest.php index ac5ef1182..5ad0a6692 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcRestClientWithGuzzleOptionTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcRestClientWithGuzzleOptionTest.php @@ -3,11 +3,16 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcRestClientWithGuzzleOptionTest extends TestCase +#[\AllowDynamicProperties] +class OcRestClientWithGuzzleOptionTest extends OcTestCase { + private $ocBaseApi; + private $ocEventApi; + private $ocBaseApiFaulty; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcSearchTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcSearchTest.php index 6e60cb5f7..1b73f075b 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcSearchTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcSearchTest.php @@ -3,12 +3,15 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use OpencastApi\Util\OcUtils; -class OcSearchTest extends TestCase +#[\AllowDynamicProperties] +class OcSearchTest extends OcTestCase { + private $ocSearch; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcSecurityApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcSecurityApiTest.php index 8ca54e38d..e417851b9 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcSecurityApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcSecurityApiTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcSecurityApiTest extends TestCase +#[\AllowDynamicProperties] +class OcSecurityApiTest extends OcTestCase { + private $ocSecurityApi; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcSeriesApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcSeriesApiTest.php index 970e096ff..d61bbe1ab 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcSeriesApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcSeriesApiTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcSeriesApiTest extends TestCase +#[\AllowDynamicProperties] +class OcSeriesApiTest extends OcTestCase { + private $ocSeriesApi; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcServicesTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcServicesTest.php index eb0a3aa00..600b7c612 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcServicesTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcServicesTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcServicesTest extends TestCase +#[\AllowDynamicProperties] +class OcServicesTest extends OcTestCase { + private $ocServices; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcStatisticsApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcStatisticsApiTest.php index 917335599..29f7e84c1 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcStatisticsApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcStatisticsApiTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcStatisticsApiTest extends TestCase +#[\AllowDynamicProperties] +class OcStatisticsApiTest extends OcTestCase { + private $ocStatisticsApi; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcSysinfoTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcSysinfoTest.php index 6c8569901..8f32fe03e 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcSysinfoTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcSysinfoTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcSysinfoTest extends TestCase +#[\AllowDynamicProperties] +class OcSysinfoTest extends OcTestCase { + private $ocSysinfo; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcWorkflowTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcWorkflowTest.php index a355a5fe0..626bd75bf 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcWorkflowTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcWorkflowTest.php @@ -3,11 +3,14 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcWorkflowTest extends TestCase +#[\AllowDynamicProperties] +class OcWorkflowTest extends OcTestCase { + private $ocWorkflow; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/Unit/OcWorkflowsApiTest.php b/vendor/elan-ev/opencast-api/tests/Unit/OcWorkflowsApiTest.php index 87772fb3a..d515d9a49 100644 --- a/vendor/elan-ev/opencast-api/tests/Unit/OcWorkflowsApiTest.php +++ b/vendor/elan-ev/opencast-api/tests/Unit/OcWorkflowsApiTest.php @@ -3,11 +3,15 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; -class OcWorkflowsApiTest extends TestCase +#[\AllowDynamicProperties] +class OcWorkflowsApiTest extends OcTestCase { + private $ocWorkflowsApi; + private $ocEventsApi; + protected function setUp(): void { parent::setUp(); diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcAgentsApiTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcAgentsApiTestMock.php index 368e33281..b741add9f 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcAgentsApiTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcAgentsApiTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcAgentsApiTestMock extends TestCase +#[\AllowDynamicProperties] +class OcAgentsApiTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcBaseApiTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcBaseApiTestMock.php index f68b7127d..98509b769 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcBaseApiTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcBaseApiTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcBaseApiTestMock extends TestCase +#[\AllowDynamicProperties] +class OcBaseApiTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcEventsApiTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcEventsApiTestMock.php index 071c96cf0..2f969ff01 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcEventsApiTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcEventsApiTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcEventsApiTestMock extends TestCase +#[\AllowDynamicProperties] +class OcEventsApiTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcGroupsApiTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcGroupsApiTestMock.php index b4eef3b82..2e3645107 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcGroupsApiTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcGroupsApiTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcGroupsApiTestMock extends TestCase +#[\AllowDynamicProperties] +class OcGroupsApiTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcIngestTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcIngestTestMock.php index abdece4e7..aadc58309 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcIngestTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcIngestTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcIngestTestMock extends TestCase +#[\AllowDynamicProperties] +class OcIngestTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcPlaylistsApiTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcPlaylistsApiTestMock.php index 1744a34d6..a9b122af6 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcPlaylistsApiTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcPlaylistsApiTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcPlaylistsApiTestMock extends TestCase +#[\AllowDynamicProperties] +class OcPlaylistsApiTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcSearchTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcSearchTestMock.php index f127f1609..f2255583a 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcSearchTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcSearchTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcSearchTestMock extends TestCase +#[\AllowDynamicProperties] +class OcSearchTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcSecurityApiTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcSecurityApiTestMock.php index c71f53d88..15be13c90 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcSecurityApiTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcSecurityApiTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcSecurityApiTestMock extends TestCase +#[\AllowDynamicProperties] +class OcSecurityApiTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcSeriesApiTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcSeriesApiTestMock.php index ec7dc0d74..29af4de5e 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcSeriesApiTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcSeriesApiTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcSeriesApiTestMock extends TestCase +#[\AllowDynamicProperties] +class OcSeriesApiTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcServicesTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcServicesTestMock.php index ada475ac0..9ab60bf16 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcServicesTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcServicesTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcServicesTestMock extends TestCase +#[\AllowDynamicProperties] +class OcServicesTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcStatisticsApiTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcStatisticsApiTestMock.php index 9305a688b..42ff8f3c2 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcStatisticsApiTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcStatisticsApiTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcStatisticsApiTestMock extends TestCase +#[\AllowDynamicProperties] +class OcStatisticsApiTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcSysinfoTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcSysinfoTestMock.php index 0d1f61820..ecf7847c3 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcSysinfoTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcSysinfoTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcSysinfoTestMock extends TestCase +#[\AllowDynamicProperties] +class OcSysinfoTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/elan-ev/opencast-api/tests/UnitMock/OcWorkflowsApiTestMock.php b/vendor/elan-ev/opencast-api/tests/UnitMock/OcWorkflowsApiTestMock.php index 5e567c399..dadca35c6 100644 --- a/vendor/elan-ev/opencast-api/tests/UnitMock/OcWorkflowsApiTestMock.php +++ b/vendor/elan-ev/opencast-api/tests/UnitMock/OcWorkflowsApiTestMock.php @@ -3,11 +3,12 @@ namespace Tests\Unit; -use PHPUnit\Framework\TestCase; +use Tests\OcTestCase; use OpencastApi\Opencast; use \OpencastApi\Mock\OcMockHanlder; -class OcWorkflowsApiTestMock extends TestCase +#[\AllowDynamicProperties] +class OcWorkflowsApiTestMock extends OcTestCase { protected function setUp(): void { diff --git a/vendor/lcobucci/jwt/LICENSE b/vendor/lcobucci/jwt/LICENSE new file mode 100644 index 000000000..cc7e28f16 --- /dev/null +++ b/vendor/lcobucci/jwt/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014, Luís Cobucci +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/lcobucci/jwt/composer.json b/vendor/lcobucci/jwt/composer.json new file mode 100644 index 000000000..5e69871b4 --- /dev/null +++ b/vendor/lcobucci/jwt/composer.json @@ -0,0 +1,63 @@ +{ + "name": "lcobucci/jwt", + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "license": [ + "BSD-3-Clause" + ], + "type": "library", + "keywords": [ + "JWT", + "JWS" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "require": { + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "ext-openssl": "*", + "ext-sodium": "*", + "psr/clock": "^1.0" + }, + "require-dev": { + "infection/infection": "^0.29", + "lcobucci/clock": "^3.2", + "lcobucci/coding-standard": "^11.0", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", + "phpstan/phpstan-strict-rules": "^1.5.0", + "phpunit/phpunit": "^11.1" + }, + "suggest": { + "lcobucci/clock": ">= 3.2" + }, + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Lcobucci\\JWT\\Tests\\": "tests" + } + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "infection/extension-installer": true, + "ocramius/package-versions": true, + "phpstan/extension-installer": true + }, + "platform": { + "php": "8.2.99" + }, + "preferred-install": "dist", + "sort-packages": true + } +} diff --git a/vendor/lcobucci/jwt/src/Builder.php b/vendor/lcobucci/jwt/src/Builder.php new file mode 100644 index 000000000..4295e3f0b --- /dev/null +++ b/vendor/lcobucci/jwt/src/Builder.php @@ -0,0 +1,85 @@ + $claims + * + * @return array + */ + public function formatClaims(array $claims): array; +} diff --git a/vendor/lcobucci/jwt/src/Configuration.php b/vendor/lcobucci/jwt/src/Configuration.php new file mode 100644 index 000000000..ea05e3b9c --- /dev/null +++ b/vendor/lcobucci/jwt/src/Configuration.php @@ -0,0 +1,213 @@ +parser = $parser ?? new Token\Parser($decoder); + $this->validator = $validator ?? new Validation\Validator(); + + $this->builderFactory = $builderFactory + ?? static function (ClaimsFormatter $claimFormatter) use ($encoder): Builder { + return Token\Builder::new($encoder, $claimFormatter); + }; + + $this->validationConstraints = $validationConstraints; + } + + public static function forAsymmetricSigner( + Signer $signer, + Key $signingKey, + Key $verificationKey, + Encoder $encoder = new JoseEncoder(), + Decoder $decoder = new JoseEncoder(), + ): self { + return new self( + $signer, + $signingKey, + $verificationKey, + $encoder, + $decoder, + null, + null, + null, + ); + } + + public static function forSymmetricSigner( + Signer $signer, + Key $key, + Encoder $encoder = new JoseEncoder(), + Decoder $decoder = new JoseEncoder(), + ): self { + return new self( + $signer, + $key, + $key, + $encoder, + $decoder, + null, + null, + null, + ); + } + + /** + * @deprecated Deprecated since v5.5, please use {@see self::withBuilderFactory()} instead + * + * @param callable(ClaimsFormatter): Builder $builderFactory + */ + public function setBuilderFactory(callable $builderFactory): void + { + $this->builderFactory = $builderFactory(...); + } + + /** @param callable(ClaimsFormatter): Builder $builderFactory */ + public function withBuilderFactory(callable $builderFactory): self + { + return new self( + $this->signer, + $this->signingKey, + $this->verificationKey, + $this->encoder, + $this->decoder, + $this->parser, + $this->validator, + $builderFactory(...), + ...$this->validationConstraints, + ); + } + + public function builder(?ClaimsFormatter $claimFormatter = null): Builder + { + return ($this->builderFactory)($claimFormatter ?? ChainedFormatter::default()); + } + + public function parser(): Parser + { + return $this->parser; + } + + /** @deprecated Deprecated since v5.5, please use {@see self::withParser()} instead */ + public function setParser(Parser $parser): void + { + $this->parser = $parser; + } + + public function withParser(Parser $parser): self + { + return new self( + $this->signer, + $this->signingKey, + $this->verificationKey, + $this->encoder, + $this->decoder, + $parser, + $this->validator, + $this->builderFactory, + ...$this->validationConstraints, + ); + } + + public function signer(): Signer + { + return $this->signer; + } + + public function signingKey(): Key + { + return $this->signingKey; + } + + public function verificationKey(): Key + { + return $this->verificationKey; + } + + public function validator(): Validator + { + return $this->validator; + } + + /** @deprecated Deprecated since v5.5, please use {@see self::withValidator()} instead */ + public function setValidator(Validator $validator): void + { + $this->validator = $validator; + } + + public function withValidator(Validator $validator): self + { + return new self( + $this->signer, + $this->signingKey, + $this->verificationKey, + $this->encoder, + $this->decoder, + $this->parser, + $validator, + $this->builderFactory, + ...$this->validationConstraints, + ); + } + + /** @return Constraint[] */ + public function validationConstraints(): array + { + return $this->validationConstraints; + } + + /** @deprecated Deprecated since v5.5, please use {@see self::withValidationConstraints()} instead */ + public function setValidationConstraints(Constraint ...$validationConstraints): void + { + $this->validationConstraints = $validationConstraints; + } + + public function withValidationConstraints(Constraint ...$validationConstraints): self + { + return new self( + $this->signer, + $this->signingKey, + $this->verificationKey, + $this->encoder, + $this->decoder, + $this->parser, + $this->validator, + $this->builderFactory, + ...$validationConstraints, + ); + } +} diff --git a/vendor/lcobucci/jwt/src/Decoder.php b/vendor/lcobucci/jwt/src/Decoder.php new file mode 100644 index 000000000..6b24b9268 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Decoder.php @@ -0,0 +1,29 @@ + */ + private array $formatters; + + public function __construct(ClaimsFormatter ...$formatters) + { + $this->formatters = $formatters; + } + + public static function default(): self + { + return new self(new UnifyAudience(), new MicrosecondBasedDateConversion()); + } + + public static function withUnixTimestampDates(): self + { + return new self(new UnifyAudience(), new UnixTimestampDates()); + } + + /** @inheritdoc */ + public function formatClaims(array $claims): array + { + foreach ($this->formatters as $formatter) { + $claims = $formatter->formatClaims($claims); + } + + return $claims; + } +} diff --git a/vendor/lcobucci/jwt/src/Encoding/JoseEncoder.php b/vendor/lcobucci/jwt/src/Encoding/JoseEncoder.php new file mode 100644 index 000000000..0d9044427 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Encoding/JoseEncoder.php @@ -0,0 +1,56 @@ +convertDate($claims[$claim]); + } + + return $claims; + } + + private function convertDate(DateTimeImmutable $date): int|float + { + if ($date->format('u') === '000000') { + return (int) $date->format('U'); + } + + return (float) $date->format('U.u'); + } +} diff --git a/vendor/lcobucci/jwt/src/Encoding/UnifyAudience.php b/vendor/lcobucci/jwt/src/Encoding/UnifyAudience.php new file mode 100644 index 000000000..cf57252e9 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Encoding/UnifyAudience.php @@ -0,0 +1,29 @@ +convertDate($claims[$claim]); + } + + return $claims; + } + + private function convertDate(DateTimeImmutable $date): int + { + return $date->getTimestamp(); + } +} diff --git a/vendor/lcobucci/jwt/src/Exception.php b/vendor/lcobucci/jwt/src/Exception.php new file mode 100644 index 000000000..4b3916e69 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Exception.php @@ -0,0 +1,10 @@ +clock = $clock ?? new class implements Clock { + public function now(): DateTimeImmutable + { + return new DateTimeImmutable(); + } + }; + } + + /** @param Closure(Builder, DateTimeImmutable):Builder $customiseBuilder */ + public function issue( + Signer $signer, + Key $signingKey, + Closure $customiseBuilder, + ): UnencryptedToken { + $builder = Token\Builder::new(new JoseEncoder(), ChainedFormatter::withUnixTimestampDates()); + + $now = $this->clock->now(); + $builder = $builder + ->issuedAt($now) + ->canOnlyBeUsedAfter($now) + ->expiresAt($now->modify('+5 minutes')); + + return $customiseBuilder($builder, $now)->getToken($signer, $signingKey); + } + + /** @param non-empty-string $jwt */ + public function parse( + string $jwt, + SignedWith $signedWith, + ValidAt $validAt, + Constraint ...$constraints, + ): UnencryptedToken { + $token = $this->parser->parse($jwt); + assert($token instanceof UnencryptedToken); + + (new Validator())->assert( + $token, + $signedWith, + $validAt, + ...$constraints, + ); + + return $token; + } +} diff --git a/vendor/lcobucci/jwt/src/Parser.php b/vendor/lcobucci/jwt/src/Parser.php new file mode 100644 index 000000000..fa77f04ef --- /dev/null +++ b/vendor/lcobucci/jwt/src/Parser.php @@ -0,0 +1,22 @@ +contents()); + + if ($actualKeyLength < self::MINIMUM_KEY_LENGTH_IN_BITS) { + throw InvalidKeyProvided::tooShort(self::MINIMUM_KEY_LENGTH_IN_BITS, $actualKeyLength); + } + + return sodium_crypto_generichash($payload, $key->contents()); + } + + public function verify(string $expected, string $payload, Key $key): bool + { + return hash_equals($expected, $this->sign($payload, $key)); + } +} diff --git a/vendor/lcobucci/jwt/src/Signer/CannotSignPayload.php b/vendor/lcobucci/jwt/src/Signer/CannotSignPayload.php new file mode 100644 index 000000000..35cc4d6dd --- /dev/null +++ b/vendor/lcobucci/jwt/src/Signer/CannotSignPayload.php @@ -0,0 +1,15 @@ +converter->fromAsn1( + $this->createSignature($key->contents(), $key->passphrase(), $payload), + $this->pointLength(), + ); + } + + final public function verify(string $expected, string $payload, Key $key): bool + { + return $this->verifySignature( + $this->converter->toAsn1($expected, $this->pointLength()), + $payload, + $key->contents(), + ); + } + + /** {@inheritDoc} */ + final protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void + { + if ($type !== OPENSSL_KEYTYPE_EC) { + throw InvalidKeyProvided::incompatibleKeyType( + self::KEY_TYPE_MAP[OPENSSL_KEYTYPE_EC], + self::KEY_TYPE_MAP[$type], + ); + } + + $expectedKeyLength = $this->expectedKeyLength(); + + if ($lengthInBits !== $expectedKeyLength) { + throw InvalidKeyProvided::incompatibleKeyLength($expectedKeyLength, $lengthInBits); + } + } + + /** + * @internal + * + * @return positive-int + */ + abstract public function expectedKeyLength(): int; + + /** + * Returns the length of each point in the signature, so that we can calculate and verify R and S points properly + * + * @internal + * + * @return positive-int + */ + abstract public function pointLength(): int; +} diff --git a/vendor/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php b/vendor/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php new file mode 100644 index 000000000..d9ca751d4 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Signer/Ecdsa/ConversionFailed.php @@ -0,0 +1,25 @@ + self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : ''; + + $asn1 = hex2bin( + self::ASN1_SEQUENCE + . $lengthPrefix . dechex($totalLength) + . self::ASN1_INTEGER . dechex($lengthR) . $pointR + . self::ASN1_INTEGER . dechex($lengthS) . $pointS, + ); + assert(is_string($asn1)); + assert($asn1 !== ''); + + return $asn1; + } + + private static function octetLength(string $data): int + { + return (int) (strlen($data) / self::BYTE_SIZE); + } + + private static function preparePositiveInteger(string $data): string + { + if (substr($data, 0, self::BYTE_SIZE) > self::ASN1_BIG_INTEGER_LIMIT) { + return self::ASN1_NEGATIVE_INTEGER . $data; + } + + while ( + substr($data, 0, self::BYTE_SIZE) === self::ASN1_NEGATIVE_INTEGER + && substr($data, 2, self::BYTE_SIZE) <= self::ASN1_BIG_INTEGER_LIMIT + ) { + $data = substr($data, 2, null); + } + + return $data; + } + + public function fromAsn1(string $signature, int $length): string + { + $message = bin2hex($signature); + $position = 0; + + if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_SEQUENCE) { + throw ConversionFailed::incorrectStartSequence(); + } + + // @phpstan-ignore-next-line + if (self::readAsn1Content($message, $position, self::BYTE_SIZE) === self::ASN1_LENGTH_2BYTES) { + $position += self::BYTE_SIZE; + } + + $pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position)); + $pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position)); + + $points = hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT) . str_pad($pointS, $length, '0', STR_PAD_LEFT)); + assert(is_string($points)); + assert($points !== ''); + + return $points; + } + + private static function readAsn1Content(string $message, int &$position, int $length): string + { + $content = substr($message, $position, $length); + $position += $length; + + return $content; + } + + private static function readAsn1Integer(string $message, int &$position): string + { + if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_INTEGER) { + throw ConversionFailed::integerExpected(); + } + + $length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE)); + + return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE); + } + + private static function retrievePositiveInteger(string $data): string + { + while ( + substr($data, 0, self::BYTE_SIZE) === self::ASN1_NEGATIVE_INTEGER + && substr($data, 2, self::BYTE_SIZE) > self::ASN1_BIG_INTEGER_LIMIT + ) { + $data = substr($data, 2, null); + } + + return $data; + } +} diff --git a/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php b/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php new file mode 100644 index 000000000..ff00f4d47 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Signer/Ecdsa/Sha256.php @@ -0,0 +1,31 @@ +contents()); + } catch (SodiumException $sodiumException) { + throw new InvalidKeyProvided($sodiumException->getMessage(), 0, $sodiumException); + } + } + + public function verify(string $expected, string $payload, Key $key): bool + { + try { + return sodium_crypto_sign_verify_detached($expected, $payload, $key->contents()); + } catch (SodiumException $sodiumException) { + throw new InvalidKeyProvided($sodiumException->getMessage(), 0, $sodiumException); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Signer/Hmac.php b/vendor/lcobucci/jwt/src/Signer/Hmac.php new file mode 100644 index 000000000..815f84c30 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Signer/Hmac.php @@ -0,0 +1,44 @@ +contents()); + $expectedKeyLength = $this->minimumBitsLengthForKey(); + + if ($actualKeyLength < $expectedKeyLength) { + throw InvalidKeyProvided::tooShort($expectedKeyLength, $actualKeyLength); + } + + return hash_hmac($this->algorithm(), $payload, $key->contents(), true); + } + + final public function verify(string $expected, string $payload, Key $key): bool + { + return hash_equals($expected, $this->sign($payload, $key)); + } + + /** + * @internal + * + * @return non-empty-string + */ + abstract public function algorithm(): string; + + /** + * @internal + * + * @return positive-int + */ + abstract public function minimumBitsLengthForKey(): int; +} diff --git a/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php b/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php new file mode 100644 index 000000000..e19992ec3 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Signer/Hmac/Sha256.php @@ -0,0 +1,24 @@ +getSize(); + $contents = $fileSize > 0 ? $file->fread($file->getSize()) : ''; + assert(is_string($contents)); + + self::guardAgainstEmptyKey($contents); + + return new self($contents, $passphrase); + } + + /** @phpstan-assert non-empty-string $contents */ + private static function guardAgainstEmptyKey(string $contents): void + { + if ($contents === '') { + throw InvalidKeyProvided::cannotBeEmpty(); + } + } + + public function contents(): string + { + return $this->contents; + } + + public function passphrase(): string + { + return $this->passphrase; + } +} diff --git a/vendor/lcobucci/jwt/src/Signer/OpenSSL.php b/vendor/lcobucci/jwt/src/Signer/OpenSSL.php new file mode 100644 index 000000000..a507752b8 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Signer/OpenSSL.php @@ -0,0 +1,133 @@ + 'RSA', + OPENSSL_KEYTYPE_DSA => 'DSA', + OPENSSL_KEYTYPE_DH => 'DH', + OPENSSL_KEYTYPE_EC => 'EC', + ]; + + /** + * @return non-empty-string + * + * @throws CannotSignPayload + * @throws InvalidKeyProvided + */ + final protected function createSignature( + #[SensitiveParameter] + string $pem, + #[SensitiveParameter] + string $passphrase, + string $payload, + ): string { + $key = $this->getPrivateKey($pem, $passphrase); + + $signature = ''; + + if (! openssl_sign($payload, $signature, $key, $this->algorithm())) { + throw CannotSignPayload::errorHappened($this->fullOpenSSLErrorString()); + } + + return $signature; + } + + /** @throws CannotSignPayload */ + private function getPrivateKey( + #[SensitiveParameter] + string $pem, + #[SensitiveParameter] + string $passphrase, + ): OpenSSLAsymmetricKey { + return $this->validateKey(openssl_pkey_get_private($pem, $passphrase)); + } + + /** @throws InvalidKeyProvided */ + final protected function verifySignature( + string $expected, + string $payload, + string $pem, + ): bool { + $key = $this->getPublicKey($pem); + $result = openssl_verify($payload, $expected, $key, $this->algorithm()); + + return $result === 1; + } + + /** @throws InvalidKeyProvided */ + private function getPublicKey(string $pem): OpenSSLAsymmetricKey + { + return $this->validateKey(openssl_pkey_get_public($pem)); + } + + /** + * Raises an exception when the key type is not the expected type + * + * @throws InvalidKeyProvided + */ + private function validateKey(OpenSSLAsymmetricKey|bool $key): OpenSSLAsymmetricKey + { + if (is_bool($key)) { + throw InvalidKeyProvided::cannotBeParsed($this->fullOpenSSLErrorString()); + } + + $details = openssl_pkey_get_details($key); + assert(is_array($details)); + + assert(array_key_exists('bits', $details)); + assert(is_int($details['bits'])); + assert(array_key_exists('type', $details)); + assert(is_int($details['type'])); + + $this->guardAgainstIncompatibleKey($details['type'], $details['bits']); + + return $key; + } + + private function fullOpenSSLErrorString(): string + { + $error = ''; + + while ($msg = openssl_error_string()) { + $error .= PHP_EOL . '* ' . $msg; + } + + return $error; + } + + /** @throws InvalidKeyProvided */ + abstract protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void; + + /** + * Returns which algorithm to be used to create/verify the signature (using OpenSSL constants) + * + * @internal + */ + abstract public function algorithm(): int; +} diff --git a/vendor/lcobucci/jwt/src/Signer/Rsa.php b/vendor/lcobucci/jwt/src/Signer/Rsa.php new file mode 100644 index 000000000..ba7d72d5e --- /dev/null +++ b/vendor/lcobucci/jwt/src/Signer/Rsa.php @@ -0,0 +1,35 @@ +createSignature($key->contents(), $key->passphrase(), $payload); + } + + final public function verify(string $expected, string $payload, Key $key): bool + { + return $this->verifySignature($expected, $payload, $key->contents()); + } + + final protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void + { + if ($type !== OPENSSL_KEYTYPE_RSA) { + throw InvalidKeyProvided::incompatibleKeyType( + self::KEY_TYPE_MAP[OPENSSL_KEYTYPE_RSA], + self::KEY_TYPE_MAP[$type], + ); + } + + if ($lengthInBits < self::MINIMUM_KEY_LENGTH) { + throw InvalidKeyProvided::tooShort(self::MINIMUM_KEY_LENGTH, $lengthInBits); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php b/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php new file mode 100644 index 000000000..9e56c70f1 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Signer/Rsa/Sha256.php @@ -0,0 +1,21 @@ + */ + private array $headers = ['typ' => 'JWT', 'alg' => null]; + + /** @var array */ + private array $claims = []; + + /** @deprecated Deprecated since v5.5, please use {@see self::new()} instead */ + public function __construct(private readonly Encoder $encoder, private readonly ClaimsFormatter $claimFormatter) + { + } + + public static function new(Encoder $encoder, ClaimsFormatter $claimFormatter): self + { + return new self($encoder, $claimFormatter); + } + + /** + * @inheritDoc + * @pure + */ + public function permittedFor(string ...$audiences): BuilderInterface + { + $configured = $this->claims[RegisteredClaims::AUDIENCE] ?? []; + $toAppend = array_diff($audiences, $configured); + + return $this->setClaim(RegisteredClaims::AUDIENCE, array_merge($configured, $toAppend)); + } + + /** + * @inheritDoc + * @pure + */ + public function expiresAt(DateTimeImmutable $expiration): BuilderInterface + { + return $this->setClaim(RegisteredClaims::EXPIRATION_TIME, $expiration); + } + + /** + * @inheritDoc + * @pure + */ + public function identifiedBy(string $id): BuilderInterface + { + return $this->setClaim(RegisteredClaims::ID, $id); + } + + /** + * @inheritDoc + * @pure + */ + public function issuedAt(DateTimeImmutable $issuedAt): BuilderInterface + { + return $this->setClaim(RegisteredClaims::ISSUED_AT, $issuedAt); + } + + /** + * @inheritDoc + * @pure + */ + public function issuedBy(string $issuer): BuilderInterface + { + return $this->setClaim(RegisteredClaims::ISSUER, $issuer); + } + + /** + * @inheritDoc + * @pure + */ + public function canOnlyBeUsedAfter(DateTimeImmutable $notBefore): BuilderInterface + { + return $this->setClaim(RegisteredClaims::NOT_BEFORE, $notBefore); + } + + /** + * @inheritDoc + * @pure + */ + public function relatedTo(string $subject): BuilderInterface + { + return $this->setClaim(RegisteredClaims::SUBJECT, $subject); + } + + /** + * @inheritDoc + * @pure + */ + public function withHeader(string $name, mixed $value): BuilderInterface + { + $new = clone $this; + $new->headers[$name] = $value; + + return $new; + } + + /** + * @inheritDoc + * @pure + */ + public function withClaim(string $name, mixed $value): BuilderInterface + { + if (in_array($name, RegisteredClaims::ALL, true)) { + throw RegisteredClaimGiven::forClaim($name); + } + + return $this->setClaim($name, $value); + } + + /** @param non-empty-string $name */ + private function setClaim(string $name, mixed $value): BuilderInterface + { + $new = clone $this; + $new->claims[$name] = $value; + + return $new; + } + + /** + * @param array $items + * + * @throws CannotEncodeContent When data cannot be converted to JSON. + */ + private function encode(array $items): string + { + return $this->encoder->base64UrlEncode( + $this->encoder->jsonEncode($items), + ); + } + + public function getToken(Signer $signer, Key $key): UnencryptedToken + { + $headers = $this->headers; + $headers['alg'] = $signer->algorithmId(); + + $encodedHeaders = $this->encode($headers); + $encodedClaims = $this->encode($this->claimFormatter->formatClaims($this->claims)); + + $signature = $signer->sign($encodedHeaders . '.' . $encodedClaims, $key); + $encodedSignature = $this->encoder->base64UrlEncode($signature); + + return new Plain( + new DataSet($headers, $encodedHeaders), + new DataSet($this->claims, $encodedClaims), + new Signature($signature, $encodedSignature), + ); + } +} diff --git a/vendor/lcobucci/jwt/src/Token/DataSet.php b/vendor/lcobucci/jwt/src/Token/DataSet.php new file mode 100644 index 000000000..6c0b98ab1 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Token/DataSet.php @@ -0,0 +1,37 @@ + $data */ + public function __construct(private readonly array $data, private readonly string $encoded) + { + } + + /** @param non-empty-string $name */ + public function get(string $name, mixed $default = null): mixed + { + return $this->data[$name] ?? $default; + } + + /** @param non-empty-string $name */ + public function has(string $name): bool + { + return array_key_exists($name, $this->data); + } + + /** @return array */ + public function all(): array + { + return $this->data; + } + + public function toString(): string + { + return $this->encoded; + } +} diff --git a/vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php b/vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php new file mode 100644 index 000000000..abba344b7 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Token/InvalidTokenStructure.php @@ -0,0 +1,41 @@ +splitJwt($jwt); + + if ($encodedHeaders === '') { + throw InvalidTokenStructure::missingHeaderPart(); + } + + if ($encodedClaims === '') { + throw InvalidTokenStructure::missingClaimsPart(); + } + + if ($encodedSignature === '') { + throw InvalidTokenStructure::missingSignaturePart(); + } + + $header = $this->parseHeader($encodedHeaders); + + return new Plain( + new DataSet($header, $encodedHeaders), + new DataSet($this->parseClaims($encodedClaims), $encodedClaims), + $this->parseSignature($encodedSignature), + ); + } + + /** + * Splits the JWT string into an array + * + * @param non-empty-string $jwt + * + * @return string[] + * + * @throws InvalidTokenStructure When JWT doesn't have all parts. + */ + private function splitJwt(string $jwt): array + { + $data = explode('.', $jwt); + + if (count($data) !== 3) { + throw InvalidTokenStructure::missingOrNotEnoughSeparators(); + } + + return $data; + } + + /** + * Parses the header from a string + * + * @param non-empty-string $data + * + * @return array + * + * @throws UnsupportedHeaderFound When an invalid header is informed. + * @throws InvalidTokenStructure When parsed content isn't an array. + */ + private function parseHeader(string $data): array + { + $header = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data)); + + if (! is_array($header)) { + throw InvalidTokenStructure::arrayExpected('headers'); + } + + $this->guardAgainstEmptyStringKeys($header, 'headers'); + + if (array_key_exists('enc', $header)) { + throw UnsupportedHeaderFound::encryption(); + } + + if (! array_key_exists('typ', $header)) { + $header['typ'] = 'JWT'; + } + + return $header; + } + + /** + * Parses the claim set from a string + * + * @param non-empty-string $data + * + * @return array + * + * @throws InvalidTokenStructure When parsed content isn't an array or contains non-parseable dates. + */ + private function parseClaims(string $data): array + { + $claims = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data)); + + if (! is_array($claims)) { + throw InvalidTokenStructure::arrayExpected('claims'); + } + + $this->guardAgainstEmptyStringKeys($claims, 'claims'); + + if (array_key_exists(RegisteredClaims::AUDIENCE, $claims)) { + $claims[RegisteredClaims::AUDIENCE] = (array) $claims[RegisteredClaims::AUDIENCE]; + } + + foreach (RegisteredClaims::DATE_CLAIMS as $claim) { + if (! array_key_exists($claim, $claims)) { + continue; + } + + $claims[$claim] = $this->convertDate($claims[$claim]); + } + + return $claims; + } + + /** + * @param array $array + * @param non-empty-string $part + * + * @phpstan-assert array $array + */ + private function guardAgainstEmptyStringKeys(array $array, string $part): void + { + foreach ($array as $key => $value) { + if ($key === '') { + throw InvalidTokenStructure::arrayExpected($part); + } + } + } + + /** @throws InvalidTokenStructure */ + private function convertDate(int|float|string $timestamp): DateTimeImmutable + { + if (! is_numeric($timestamp)) { + throw InvalidTokenStructure::dateIsNotParseable($timestamp); + } + + $normalizedTimestamp = number_format((float) $timestamp, self::MICROSECOND_PRECISION, '.', ''); + + $date = DateTimeImmutable::createFromFormat('U.u', $normalizedTimestamp); + + if ($date === false) { + throw InvalidTokenStructure::dateIsNotParseable($normalizedTimestamp); + } + + return $date; + } + + /** + * Returns the signature from given data + * + * @param non-empty-string $data + */ + private function parseSignature(string $data): Signature + { + $hash = $this->decoder->base64UrlDecode($data); + + return new Signature($hash, $data); + } +} diff --git a/vendor/lcobucci/jwt/src/Token/Plain.php b/vendor/lcobucci/jwt/src/Token/Plain.php new file mode 100644 index 000000000..6af388d5f --- /dev/null +++ b/vendor/lcobucci/jwt/src/Token/Plain.php @@ -0,0 +1,85 @@ +headers; + } + + public function claims(): DataSet + { + return $this->claims; + } + + public function signature(): Signature + { + return $this->signature; + } + + public function payload(): string + { + return $this->headers->toString() . '.' . $this->claims->toString(); + } + + public function isPermittedFor(string $audience): bool + { + return in_array($audience, $this->claims->get(RegisteredClaims::AUDIENCE, []), true); + } + + public function isIdentifiedBy(string $id): bool + { + return $this->claims->get(RegisteredClaims::ID) === $id; + } + + public function isRelatedTo(string $subject): bool + { + return $this->claims->get(RegisteredClaims::SUBJECT) === $subject; + } + + public function hasBeenIssuedBy(string ...$issuers): bool + { + return in_array($this->claims->get(RegisteredClaims::ISSUER), $issuers, true); + } + + public function hasBeenIssuedBefore(DateTimeInterface $now): bool + { + return $now >= $this->claims->get(RegisteredClaims::ISSUED_AT); + } + + public function isMinimumTimeBefore(DateTimeInterface $now): bool + { + return $now >= $this->claims->get(RegisteredClaims::NOT_BEFORE); + } + + public function isExpired(DateTimeInterface $now): bool + { + if (! $this->claims->has(RegisteredClaims::EXPIRATION_TIME)) { + return false; + } + + return $now >= $this->claims->get(RegisteredClaims::EXPIRATION_TIME); + } + + public function toString(): string + { + return $this->headers->toString() . '.' + . $this->claims->toString() . '.' + . $this->signature->toString(); + } +} diff --git a/vendor/lcobucci/jwt/src/Token/RegisteredClaimGiven.php b/vendor/lcobucci/jwt/src/Token/RegisteredClaimGiven.php new file mode 100644 index 000000000..ce40a6abd --- /dev/null +++ b/vendor/lcobucci/jwt/src/Token/RegisteredClaimGiven.php @@ -0,0 +1,21 @@ +hash; + } + + /** + * Returns the encoded version of the signature + * + * @return non-empty-string + */ + public function toString(): string + { + return $this->encoded; + } +} diff --git a/vendor/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php b/vendor/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php new file mode 100644 index 000000000..182407844 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Token/UnsupportedHeaderFound.php @@ -0,0 +1,15 @@ +claims(); + + if (! $claims->has($this->claim)) { + throw ConstraintViolation::error('The token does not have the claim "' . $this->claim . '"', $this); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/HasClaimWithValue.php b/vendor/lcobucci/jwt/src/Validation/Constraint/HasClaimWithValue.php new file mode 100644 index 000000000..d3ba1d6e7 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/HasClaimWithValue.php @@ -0,0 +1,42 @@ +claims(); + + if (! $claims->has($this->claim)) { + throw ConstraintViolation::error('The token does not have the claim "' . $this->claim . '"', $this); + } + + if ($claims->get($this->claim) !== $this->expectedValue) { + throw ConstraintViolation::error( + 'The claim "' . $this->claim . '" does not have the expected value', + $this, + ); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/IdentifiedBy.php b/vendor/lcobucci/jwt/src/Validation/Constraint/IdentifiedBy.php new file mode 100644 index 000000000..44541a75b --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/IdentifiedBy.php @@ -0,0 +1,26 @@ +isIdentifiedBy($this->id)) { + throw ConstraintViolation::error( + 'The token is not identified with the expected ID', + $this, + ); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php b/vendor/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php new file mode 100644 index 000000000..8ba3890db --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/IssuedBy.php @@ -0,0 +1,30 @@ +issuers = $issuers; + } + + public function assert(Token $token): void + { + if (! $token->hasBeenIssuedBy(...$this->issuers)) { + throw ConstraintViolation::error( + 'The token was not issued by the given issuers', + $this, + ); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php b/vendor/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php new file mode 100644 index 000000000..53abc0d4e --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/LeewayCannotBeNegative.php @@ -0,0 +1,15 @@ +leeway = $this->guardLeeway($leeway); + } + + private function guardLeeway(?DateInterval $leeway): DateInterval + { + if ($leeway === null) { + return new DateInterval('PT0S'); + } + + if ($leeway->invert === 1) { + throw LeewayCannotBeNegative::create(); + } + + return $leeway; + } + + public function assert(Token $token): void + { + $now = $this->clock->now(); + + $this->assertIssueTime($token, $now->add($this->leeway)); + $this->assertMinimumTime($token, $now->add($this->leeway)); + $this->assertExpiration($token, $now->sub($this->leeway)); + } + + /** @throws ConstraintViolation */ + private function assertExpiration(Token $token, DateTimeInterface $now): void + { + if ($token->isExpired($now)) { + throw ConstraintViolation::error('The token is expired', $this); + } + } + + /** @throws ConstraintViolation */ + private function assertMinimumTime(Token $token, DateTimeInterface $now): void + { + if (! $token->isMinimumTimeBefore($now)) { + throw ConstraintViolation::error('The token cannot be used yet', $this); + } + } + + /** @throws ConstraintViolation */ + private function assertIssueTime(Token $token, DateTimeInterface $now): void + { + if (! $token->hasBeenIssuedBefore($now)) { + throw ConstraintViolation::error('The token was issued in the future', $this); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/PermittedFor.php b/vendor/lcobucci/jwt/src/Validation/Constraint/PermittedFor.php new file mode 100644 index 000000000..48544c9a1 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/PermittedFor.php @@ -0,0 +1,26 @@ +isPermittedFor($this->audience)) { + throw ConstraintViolation::error( + 'The token is not allowed to be used by this audience', + $this, + ); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php b/vendor/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php new file mode 100644 index 000000000..164936234 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/RelatedTo.php @@ -0,0 +1,26 @@ +isRelatedTo($this->subject)) { + throw ConstraintViolation::error( + 'The token is not related to the expected subject', + $this, + ); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWith.php b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWith.php new file mode 100644 index 000000000..5c8e26561 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWith.php @@ -0,0 +1,32 @@ +headers()->get('alg') !== $this->signer->algorithmId()) { + throw ConstraintViolation::error('Token signer mismatch', $this); + } + + if (! $this->signer->verify($token->signature()->hash(), $token->payload(), $this->key)) { + throw ConstraintViolation::error('Token signature mismatch', $this); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithOneInSet.php b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithOneInSet.php new file mode 100644 index 000000000..fb542fb3d --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithOneInSet.php @@ -0,0 +1,38 @@ + */ + private readonly array $constraints; + + public function __construct(SignedWithUntilDate ...$constraints) + { + $this->constraints = $constraints; + } + + public function assert(Token $token): void + { + $errorMessage = 'It was not possible to verify the signature of the token, reasons:'; + + foreach ($this->constraints as $constraint) { + try { + $constraint->assert($token); + + return; + } catch (ConstraintViolation $violation) { + $errorMessage .= PHP_EOL . '- ' . $violation->getMessage(); + } + } + + throw ConstraintViolation::error($errorMessage, $this); + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithUntilDate.php b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithUntilDate.php new file mode 100644 index 000000000..85429e890 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/SignedWithUntilDate.php @@ -0,0 +1,47 @@ +verifySignature = new SignedWith($signer, $key); + + $this->clock = $clock ?? new class () implements ClockInterface { + public function now(): DateTimeImmutable + { + return new DateTimeImmutable(); + } + }; + } + + public function assert(Token $token): void + { + if ($this->validUntil < $this->clock->now()) { + throw ConstraintViolation::error( + 'This constraint was only usable until ' + . $this->validUntil->format(DateTimeInterface::RFC3339), + $this, + ); + } + + $this->verifySignature->assert($token); + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/Constraint/StrictValidAt.php b/vendor/lcobucci/jwt/src/Validation/Constraint/StrictValidAt.php new file mode 100644 index 000000000..93db0a3a3 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/Constraint/StrictValidAt.php @@ -0,0 +1,84 @@ +leeway = $this->guardLeeway($leeway); + } + + private function guardLeeway(?DateInterval $leeway): DateInterval + { + if ($leeway === null) { + return new DateInterval('PT0S'); + } + + if ($leeway->invert === 1) { + throw LeewayCannotBeNegative::create(); + } + + return $leeway; + } + + public function assert(Token $token): void + { + if (! $token instanceof UnencryptedToken) { + throw ConstraintViolation::error('You should pass a plain token', $this); + } + + $now = $this->clock->now(); + + $this->assertIssueTime($token, $now->add($this->leeway)); + $this->assertMinimumTime($token, $now->add($this->leeway)); + $this->assertExpiration($token, $now->sub($this->leeway)); + } + + /** @throws ConstraintViolation */ + private function assertExpiration(UnencryptedToken $token, DateTimeInterface $now): void + { + if (! $token->claims()->has(Token\RegisteredClaims::EXPIRATION_TIME)) { + throw ConstraintViolation::error('"Expiration Time" claim missing', $this); + } + + if ($token->isExpired($now)) { + throw ConstraintViolation::error('The token is expired', $this); + } + } + + /** @throws ConstraintViolation */ + private function assertMinimumTime(UnencryptedToken $token, DateTimeInterface $now): void + { + if (! $token->claims()->has(Token\RegisteredClaims::NOT_BEFORE)) { + throw ConstraintViolation::error('"Not Before" claim missing', $this); + } + + if (! $token->isMinimumTimeBefore($now)) { + throw ConstraintViolation::error('The token cannot be used yet', $this); + } + } + + /** @throws ConstraintViolation */ + private function assertIssueTime(UnencryptedToken $token, DateTimeInterface $now): void + { + if (! $token->claims()->has(Token\RegisteredClaims::ISSUED_AT)) { + throw ConstraintViolation::error('"Issued At" claim missing', $this); + } + + if (! $token->hasBeenIssuedBefore($now)) { + throw ConstraintViolation::error('The token was issued in the future', $this); + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/ConstraintViolation.php b/vendor/lcobucci/jwt/src/Validation/ConstraintViolation.php new file mode 100644 index 000000000..17c754682 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/ConstraintViolation.php @@ -0,0 +1,24 @@ +|null $constraint */ + public function __construct( + string $message = '', + public readonly ?string $constraint = null, + ) { + parent::__construct($message); + } + + /** @param non-empty-string $message */ + public static function error(string $message, Constraint $constraint): self + { + return new self(message: $message, constraint: $constraint::class); + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/NoConstraintsGiven.php b/vendor/lcobucci/jwt/src/Validation/NoConstraintsGiven.php new file mode 100644 index 000000000..0ef80d259 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/NoConstraintsGiven.php @@ -0,0 +1,11 @@ +getMessage(); + }, + $violations, + ); + + $message = "The token violates some mandatory constraints, details:\n"; + $message .= implode("\n", $violations); + + return $message; + } + + /** @return ConstraintViolation[] */ + public function violations(): array + { + return $this->violations; + } +} diff --git a/vendor/lcobucci/jwt/src/Validation/SignedWith.php b/vendor/lcobucci/jwt/src/Validation/SignedWith.php new file mode 100644 index 000000000..e721095f3 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validation/SignedWith.php @@ -0,0 +1,8 @@ +checkConstraint($constraint, $token, $violations); + } + + if ($violations) { + throw RequiredConstraintsViolated::fromViolations(...$violations); + } + } + + /** @param ConstraintViolation[] $violations */ + private function checkConstraint( + Constraint $constraint, + Token $token, + array &$violations, + ): void { + try { + $constraint->assert($token); + } catch (ConstraintViolation $e) { + $violations[] = $e; + } + } + + public function validate(Token $token, Constraint ...$constraints): bool + { + if ($constraints === []) { + throw new NoConstraintsGiven('No constraint given.'); + } + + try { + foreach ($constraints as $constraint) { + $constraint->assert($token); + } + + return true; + } catch (ConstraintViolation) { + return false; + } + } +} diff --git a/vendor/lcobucci/jwt/src/Validator.php b/vendor/lcobucci/jwt/src/Validator.php new file mode 100644 index 000000000..d0ce4b8c7 --- /dev/null +++ b/vendor/lcobucci/jwt/src/Validator.php @@ -0,0 +1,20 @@ +clock = $clock; + } + + public function doSomething() + { + /** @var DateTimeImmutable $currentDateAndTime */ + $currentDateAndTime = $this->clock->now(); + // do something useful with that information + } +} +``` + +You can then pick one of the [implementations][implementation-url] of the interface to get a clock. + +If you want to implement the interface, you can require this package and +implement `Psr\Clock\ClockInterface` in your code. + +Don't forget to add `psr/clock-implementation` to your `composer.json`s `provides`-section like this: + +```json +{ + "provides": { + "psr/clock-implementation": "1.0" + } +} +``` + +And please read the [specification text][specification-url] for details on the interface. + +[psr-url]: https://www.php-fig.org/psr/psr-20 +[package-url]: https://packagist.org/packages/psr/clock +[implementation-url]: https://packagist.org/providers/psr/clock-implementation +[specification-url]: https://github.com/php-fig/fig-standards/blob/master/proposed/clock.md diff --git a/vendor/psr/clock/composer.json b/vendor/psr/clock/composer.json new file mode 100644 index 000000000..77992eda7 --- /dev/null +++ b/vendor/psr/clock/composer.json @@ -0,0 +1,21 @@ +{ + "name": "psr/clock", + "description": "Common interface for reading the clock.", + "keywords": ["psr", "psr-20", "time", "clock", "now"], + "homepage": "https://github.com/php-fig/clock", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": "^7.0 || ^8.0" + }, + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + } +} diff --git a/vendor/psr/clock/src/ClockInterface.php b/vendor/psr/clock/src/ClockInterface.php new file mode 100644 index 000000000..7b6d8d8aa --- /dev/null +++ b/vendor/psr/clock/src/ClockInterface.php @@ -0,0 +1,13 @@ +