Event Tickets - Version 5.5.2

Version Description

Download this release

Release Info

Developer bordoni
Plugin Icon 128x128 Event Tickets
Version 5.5.2
Comparing to
See all releases

Code changes from version 5.5.1 to 5.5.2

Files changed (39) hide show
  1. common/lang/tribe-common-de_DE.mo +0 -0
  2. common/lang/tribe-common.pot +21 -21
  3. common/src/Tribe/App_Shop.php +1 -1
  4. common/src/Tribe/Date_Utils.php +76 -4
  5. common/src/Tribe/Main.php +1 -1
  6. common/src/Tribe/PUE/Checker.php +10 -4
  7. common/src/Tribe/Promoter/Connector.php +2 -2
  8. common/src/Tribe/Repository.php +34 -0
  9. common/src/Tribe/Repository/Decorator.php +9 -0
  10. common/src/Tribe/Repository/Interface.php +18 -0
  11. common/src/Tribe/Settings_Manager.php +2 -12
  12. common/src/Tribe/Utils/Lazy_Events.php +1 -1
  13. common/src/Tribe/Utils/Taxonomy.php +13 -1
  14. common/src/functions/utils.php +1 -0
  15. common/vendor/autoload.php +1 -1
  16. common/vendor/autoload_52.php +1 -1
  17. common/vendor/composer/autoload_classmap.php +3 -0
  18. common/vendor/composer/autoload_real.php +4 -4
  19. common/vendor/composer/autoload_real_52.php +3 -3
  20. common/vendor/composer/autoload_static.php +8 -5
  21. common/vendor/composer/installed.json +21 -9
  22. common/vendor/firebase/php-jwt/src/BeforeValidException.php +1 -1
  23. common/vendor/firebase/php-jwt/src/CachedKeySet.php +229 -0
  24. common/vendor/firebase/php-jwt/src/ExpiredException.php +1 -1
  25. common/vendor/firebase/php-jwt/src/JWK.php +322 -0
  26. common/vendor/firebase/php-jwt/src/JWT.php +387 -139
  27. common/vendor/firebase/php-jwt/src/Key.php +64 -0
  28. common/vendor/firebase/php-jwt/src/SignatureInvalidException.php +1 -1
  29. event-tickets.php +1 -1
  30. lang/event-tickets-de_DE.mo +0 -0
  31. lang/event-tickets-es_ES.mo +0 -0
  32. lang/event-tickets-nl_NL.mo +0 -0
  33. lang/event-tickets-ro_RO.mo +0 -0
  34. readme.txt +7 -3
  35. src/Tribe/Main.php +2 -2
  36. src/Tribe/Promoter/Triggers/Dispatcher.php +1 -1
  37. vendor/autoload.php +1 -1
  38. vendor/composer/autoload_real.php +4 -4
  39. vendor/composer/autoload_static.php +4 -4
common/lang/tribe-common-de_DE.mo CHANGED
Binary file
common/lang/tribe-common.pot CHANGED
@@ -2,13 +2,13 @@
2
  # This file is distributed under the same license as the Tribe Common package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Tribe Common 5.0.0\n"
6
  "Report-Msgid-Bugs-To: http://m.tri.be/191x\n"
7
- "POT-Creation-Date: 2022-08-25 17:54:31+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
- "PO-Revision-Date: 2022-08-25 17:54\n"
12
  "Last-Translator: \n"
13
  "Language-Team: \n"
14
 
@@ -58,7 +58,7 @@ msgctxt "Error status label for system info optin"
58
  msgid "Status:"
59
  msgstr ""
60
 
61
- #. #-#-#-#-# tribe-common.pot (Tribe Common 5.0.0) #-#-#-#-#
62
  #. Author of the plugin/theme
63
  #: src/Tribe/Admin/Help_Page.php:116 src/Tribe/Customizer.php:664
64
  #: src/Tribe/Plugins_API.php:25 src/admin-views/help-calendar.php:97
@@ -2476,55 +2476,55 @@ msgstr ""
2476
  msgid "Sorry, key validation server is not available."
2477
  msgstr ""
2478
 
2479
- #: src/Tribe/PUE/Checker.php:1054
2480
  msgid "Valid Key! Expires on %s"
2481
  msgstr ""
2482
 
2483
- #: src/Tribe/PUE/Checker.php:1059
2484
  msgid "Thanks for setting up a valid key. It will expire on %s"
2485
  msgstr ""
2486
 
2487
- #: src/Tribe/PUE/Checker.php:1088 src/Tribe/PUE/Notices.php:360
2488
  msgid "Renew Your License Now"
2489
  msgstr ""
2490
 
2491
- #: src/Tribe/PUE/Checker.php:1090 src/Tribe/PUE/Notices.php:362
2492
  msgid " (opens in a new window)"
2493
  msgstr ""
2494
 
2495
- #: src/Tribe/PUE/Checker.php:1107
2496
  msgid "Please refresh the page and try your request again."
2497
  msgstr ""
2498
 
2499
- #: src/Tribe/PUE/Checker.php:1127
2500
  msgid ""
2501
  "There is an update for %s. You'll need to %scheck your license%s to have "
2502
  "access to updates, downloads, and support."
2503
  msgstr ""
2504
 
2505
- #: src/Tribe/PUE/Checker.php:1184
2506
  msgid ""
2507
  "There is an update for %s. %sRenew your license%s to get access to bug "
2508
  "fixes, security updates, and new features."
2509
  msgstr ""
2510
 
2511
- #: src/Tribe/PUE/Checker.php:1214
2512
  msgid "Update now to version %s."
2513
  msgstr ""
2514
 
2515
- #: src/Tribe/PUE/Checker.php:1225
2516
  msgid "There is a new version of %1$s available. %2$s"
2517
  msgstr ""
2518
 
2519
- #: src/Tribe/PUE/Checker.php:1806
2520
  msgid "A valid license has been entered by your network administrator."
2521
  msgstr ""
2522
 
2523
- #: src/Tribe/PUE/Checker.php:1807
2524
  msgid "No license entered. Consult your network administrator."
2525
  msgstr ""
2526
 
2527
- #: src/Tribe/PUE/Checker.php:1808
2528
  msgid "Expired license. Consult your network administrator."
2529
  msgstr ""
2530
 
@@ -2943,15 +2943,11 @@ msgstr[1] ""
2943
  msgid "Settings saved."
2944
  msgstr ""
2945
 
2946
- #: src/Tribe/Settings_Manager.php:297
2947
  #: src/admin-views/tribe-options-licenses.php:57
2948
  msgid "Licenses"
2949
  msgstr ""
2950
 
2951
- #: src/Tribe/Settings_Manager.php:327 src/admin-views/help.php:30
2952
- msgid "Help"
2953
- msgstr ""
2954
-
2955
  #: src/Tribe/Settings_Tab.php:222
2956
  msgid "There are no fields setup for this tab yet."
2957
  msgstr ""
@@ -3490,6 +3486,10 @@ msgstr ""
3490
  msgid "(Event Tickets Plus)"
3491
  msgstr ""
3492
 
 
 
 
 
3493
  #: src/admin-views/help.php:31
3494
  msgid ""
3495
  "We're committed to helping make your calendar spectacular and have a wealth "
2
  # This file is distributed under the same license as the Tribe Common package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Tribe Common 5.0.1\n"
6
  "Report-Msgid-Bugs-To: http://m.tri.be/191x\n"
7
+ "POT-Creation-Date: 2022-10-18 16:01:22+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2022-10-18 16:01\n"
12
  "Last-Translator: \n"
13
  "Language-Team: \n"
14
 
58
  msgid "Status:"
59
  msgstr ""
60
 
61
+ #. #-#-#-#-# tribe-common.pot (Tribe Common 5.0.1) #-#-#-#-#
62
  #. Author of the plugin/theme
63
  #: src/Tribe/Admin/Help_Page.php:116 src/Tribe/Customizer.php:664
64
  #: src/Tribe/Plugins_API.php:25 src/admin-views/help-calendar.php:97
2476
  msgid "Sorry, key validation server is not available."
2477
  msgstr ""
2478
 
2479
+ #: src/Tribe/PUE/Checker.php:1060
2480
  msgid "Valid Key! Expires on %s"
2481
  msgstr ""
2482
 
2483
+ #: src/Tribe/PUE/Checker.php:1065
2484
  msgid "Thanks for setting up a valid key. It will expire on %s"
2485
  msgstr ""
2486
 
2487
+ #: src/Tribe/PUE/Checker.php:1094 src/Tribe/PUE/Notices.php:360
2488
  msgid "Renew Your License Now"
2489
  msgstr ""
2490
 
2491
+ #: src/Tribe/PUE/Checker.php:1096 src/Tribe/PUE/Notices.php:362
2492
  msgid " (opens in a new window)"
2493
  msgstr ""
2494
 
2495
+ #: src/Tribe/PUE/Checker.php:1113
2496
  msgid "Please refresh the page and try your request again."
2497
  msgstr ""
2498
 
2499
+ #: src/Tribe/PUE/Checker.php:1133
2500
  msgid ""
2501
  "There is an update for %s. You'll need to %scheck your license%s to have "
2502
  "access to updates, downloads, and support."
2503
  msgstr ""
2504
 
2505
+ #: src/Tribe/PUE/Checker.php:1190
2506
  msgid ""
2507
  "There is an update for %s. %sRenew your license%s to get access to bug "
2508
  "fixes, security updates, and new features."
2509
  msgstr ""
2510
 
2511
+ #: src/Tribe/PUE/Checker.php:1220
2512
  msgid "Update now to version %s."
2513
  msgstr ""
2514
 
2515
+ #: src/Tribe/PUE/Checker.php:1231
2516
  msgid "There is a new version of %1$s available. %2$s"
2517
  msgstr ""
2518
 
2519
+ #: src/Tribe/PUE/Checker.php:1812
2520
  msgid "A valid license has been entered by your network administrator."
2521
  msgstr ""
2522
 
2523
+ #: src/Tribe/PUE/Checker.php:1813
2524
  msgid "No license entered. Consult your network administrator."
2525
  msgstr ""
2526
 
2527
+ #: src/Tribe/PUE/Checker.php:1814
2528
  msgid "Expired license. Consult your network administrator."
2529
  msgstr ""
2530
 
2943
  msgid "Settings saved."
2944
  msgstr ""
2945
 
2946
+ #: src/Tribe/Settings_Manager.php:296
2947
  #: src/admin-views/tribe-options-licenses.php:57
2948
  msgid "Licenses"
2949
  msgstr ""
2950
 
 
 
 
 
2951
  #: src/Tribe/Settings_Tab.php:222
2952
  msgid "There are no fields setup for this tab yet."
2953
  msgstr ""
3486
  msgid "(Event Tickets Plus)"
3487
  msgstr ""
3488
 
3489
+ #: src/admin-views/help.php:30
3490
+ msgid "Help"
3491
+ msgstr ""
3492
+
3493
  #: src/admin-views/help.php:31
3494
  msgid ""
3495
  "We're committed to helping make your calendar spectacular and have a wealth "
common/src/Tribe/App_Shop.php CHANGED
@@ -343,7 +343,7 @@ if ( ! class_exists( 'Tribe__App_Shop' ) ) {
343
  'image' => 'images/shop/stellar-iconic-cta.jpg',
344
  'logo' => 'images/shop/stellar-iconic-logo.png',
345
  'title' => __( 'Sales-boosting WooCommerce plugins.', 'tribe-common' ),
346
- 'link' => 'https://iconicwp.com/?utm_source=theeventscalendar&utm_medium=in-app&utm_campaign=cross-brand-add-on-shop',
347
  'linktext' => __( 'Add Commerce Tools', 'tribe-common' ),
348
  'description' => __( 'Easy-to-use WooCommerce plugins work perfectly together, with any theme. Create a fast and profitable eCommerce store without any technical knowledge.
349
  ', 'tribe-common' ),
343
  'image' => 'images/shop/stellar-iconic-cta.jpg',
344
  'logo' => 'images/shop/stellar-iconic-logo.png',
345
  'title' => __( 'Sales-boosting WooCommerce plugins.', 'tribe-common' ),
346
+ 'link' => 'https://evnt.is/iconic',
347
  'linktext' => __( 'Add Commerce Tools', 'tribe-common' ),
348
  'description' => __( 'Easy-to-use WooCommerce plugins work perfectly together, with any theme. Create a fast and profitable eCommerce store without any technical knowledge.
349
  ', 'tribe-common' ),
common/src/Tribe/Date_Utils.php CHANGED
@@ -572,6 +572,78 @@ if ( ! class_exists( 'Tribe__Date_Utils' ) ) {
572
  );
573
  }
574
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
575
  /**
576
  * Given 2 datetime ranges, return whether the 2nd one occurs during the 1st one
577
  * Note: all params should be unix timestamps
@@ -1241,7 +1313,7 @@ if ( ! class_exists( 'Tribe__Date_Utils' ) ) {
1241
  *
1242
  * @since 4.9.5
1243
  *
1244
- * @param string|DateTime|int $datetime A `strtotime` parse-able string, a DateTime object or
1245
  * a timestamp; defaults to `now`.
1246
  * @param string|DateTimeZone|null $timezone A timezone string, UTC offset or DateTimeZone object;
1247
  * defaults to the site timezone; this parameter is ignored
@@ -1302,7 +1374,7 @@ if ( ! class_exists( 'Tribe__Date_Utils' ) ) {
1302
  *
1303
  * @param string $date The date string that should validated.
1304
  *
1305
- * @return bool Whether the date string can be used to build DateTime objects, and is thus parse-able by functions
1306
  * like `strtotime`, or not.
1307
  */
1308
  public static function is_valid_date( $date ) {
@@ -1540,7 +1612,7 @@ if ( ! class_exists( 'Tribe__Date_Utils' ) ) {
1540
  *
1541
  * @since 4.10.2
1542
  *
1543
- * @param string|DateTime|int $datetime A `strtotime` parse-able string, a DateTime object or
1544
  * a timestamp; defaults to `now`.
1545
  * @param string|DateTimeZone|null $timezone A timezone string, UTC offset or DateTimeZone object;
1546
  * defaults to the site timezone; this parameter is ignored
@@ -1588,7 +1660,7 @@ if ( ! class_exists( 'Tribe__Date_Utils' ) ) {
1588
  *
1589
  * @since 4.10.2
1590
  *
1591
- * @param string|DateTime|int $datetime A `strtotime` parse-able string, a DateTime object or
1592
  * a timestamp; defaults to `now`.
1593
  * @param string|DateTimeZone|null $timezone A timezone string, UTC offset or DateTimeZone object;
1594
  * defaults to the site timezone; this parameter is ignored
572
  );
573
  }
574
 
575
+ /**
576
+ * Determine if "now" is between two dates.
577
+ *
578
+ * @since 5.0.2
579
+ *
580
+ * @param string|DateTime|int $start_date A `strtotime` parsable string, a DateTime object or a timestamp.
581
+ * @param string|DateTime|int $end_date A `strtotime` parsable string, a DateTime object or a timestamp.
582
+ * @param string|DateTime|int $now A `strtotime` parsable string, a DateTime object or a timestamp. Defaults to 'now'.
583
+ *
584
+ * @return boolean Whether the current datetime (or passed "now") is between the passed start and end dates.
585
+ */
586
+ public static function is_now( $start_date, $end_date, $now = 'now' ) : bool {
587
+ $now = self::build_date_object( $now );
588
+ $start_date = self::build_date_object( $start_date );
589
+ $end_date = self::build_date_object( $end_date );
590
+
591
+ // If the dates are identical, bail early.
592
+ if ( $start_date === $end_date ) {
593
+ return false;
594
+ }
595
+
596
+ // Handle dates passed out of chronological order.
597
+ [ $start_date, $end_date ] = self::sort( [ $start_date, $end_date ] );
598
+
599
+ // If span starts after now, return false.
600
+ if ( $start_date > $now ) {
601
+ return false;
602
+ }
603
+
604
+ // If span ends on or before now, return false.
605
+ if ( $end_date <= $now ) {
606
+ return false;
607
+ }
608
+
609
+ return true;
610
+ }
611
+
612
+ /**
613
+ * Sort an array of dates.
614
+ *
615
+ * @since 5.0.2
616
+ *
617
+ * @param mixed $dates A single array of dates, or dates passed as individual params.
618
+ * Individual dates can be a `strtotime` parsable string, a DateTime object or a timestamp.
619
+ * @param string $direction 'ASC' or 'DESC' for ascending/descending sorting. Defaults to 'ASC'.
620
+ *
621
+ * @return array<DateTime> A sorted array of DateTime objects.
622
+ */
623
+ public static function sort( array $dates, string $direction = 'ASC' ) :array {
624
+ // If we get passed a single array, break it out of the containing array.
625
+ if ( is_array( $dates[0] ) ) {
626
+ $dates = $dates[0];
627
+ }
628
+
629
+ // Ensure we're always dealing with date objects here.
630
+ $dates = array_map(
631
+ function( $date ) {
632
+ return self::build_date_object( $date );
633
+ },
634
+ $dates
635
+ );
636
+
637
+ // If anything other than 'DESC' gets passed (or nothing) we sort ascending.
638
+ if ( 'DESC' === $direction ) {
639
+ rsort( $dates );
640
+ } else {
641
+ sort( $dates );
642
+ }
643
+
644
+ return $dates;
645
+ }
646
+
647
  /**
648
  * Given 2 datetime ranges, return whether the 2nd one occurs during the 1st one
649
  * Note: all params should be unix timestamps
1313
  *
1314
  * @since 4.9.5
1315
  *
1316
+ * @param string|DateTime|int $datetime A `strtotime` parsable string, a DateTime object or
1317
  * a timestamp; defaults to `now`.
1318
  * @param string|DateTimeZone|null $timezone A timezone string, UTC offset or DateTimeZone object;
1319
  * defaults to the site timezone; this parameter is ignored
1374
  *
1375
  * @param string $date The date string that should validated.
1376
  *
1377
+ * @return bool Whether the date string can be used to build DateTime objects, and is thus parsable by functions
1378
  * like `strtotime`, or not.
1379
  */
1380
  public static function is_valid_date( $date ) {
1612
  *
1613
  * @since 4.10.2
1614
  *
1615
+ * @param string|DateTime|int $datetime A `strtotime` parsable string, a DateTime object or
1616
  * a timestamp; defaults to `now`.
1617
  * @param string|DateTimeZone|null $timezone A timezone string, UTC offset or DateTimeZone object;
1618
  * defaults to the site timezone; this parameter is ignored
1660
  *
1661
  * @since 4.10.2
1662
  *
1663
+ * @param string|DateTime|int $datetime A `strtotime` parsable string, a DateTime object or
1664
  * a timestamp; defaults to `now`.
1665
  * @param string|DateTimeZone|null $timezone A timezone string, UTC offset or DateTimeZone object;
1666
  * defaults to the site timezone; this parameter is ignored
common/src/Tribe/Main.php CHANGED
@@ -21,7 +21,7 @@ class Tribe__Main {
21
  const OPTIONNAME = 'tribe_events_calendar_options';
22
  const OPTIONNAMENETWORK = 'tribe_events_calendar_network_options';
23
 
24
- const VERSION = '5.0.1';
25
 
26
  const FEED_URL = 'https://theeventscalendar.com/feed/';
27
 
21
  const OPTIONNAME = 'tribe_events_calendar_options';
22
  const OPTIONNAMENETWORK = 'tribe_events_calendar_network_options';
23
 
24
+ const VERSION = '5.0.2';
25
 
26
  const FEED_URL = 'https://theeventscalendar.com/feed/';
27
 
common/src/Tribe/PUE/Checker.php CHANGED
@@ -1049,16 +1049,22 @@ if ( ! class_exists( 'Tribe__PUE__Checker' ) ) {
1049
  }
1050
 
1051
  $current_install_key = $this->get_key( $key_type );
 
1052
 
1053
- if ( $current_install_key && $current_install_key === $query_args['key'] ) {
 
 
 
 
 
1054
  $default_success_msg = esc_html( sprintf( __( 'Valid Key! Expires on %s', 'tribe-common' ), $expiration ) );
1055
  } else {
1056
- // Set the key
1057
- $this->update_key( $query_args['key'], $key_type );
1058
 
1059
  $default_success_msg = esc_html( sprintf( __( 'Thanks for setting up a valid key. It will expire on %s', 'tribe-common' ), $expiration ) );
1060
 
1061
- //Set SysInfo Key on Tec.com After Successful Validation of License
1062
  $optin_key = get_option( 'tribe_systeminfo_optin' );
1063
  if ( $optin_key ) {
1064
  Tribe__Support::send_sysinfo_key( $optin_key, $query_args['domain'], false, true );
1049
  }
1050
 
1051
  $current_install_key = $this->get_key( $key_type );
1052
+ $replacement_key = $query_args['key'];
1053
 
1054
+ if ( ! empty( $plugin_info->replacement_key ) ) {
1055
+ // The PUE service might send over a new key upon validation.
1056
+ $replacement_key = $plugin_info->replacement_key;
1057
+ }
1058
+
1059
+ if ( $current_install_key && $current_install_key === $replacement_key ) {
1060
  $default_success_msg = esc_html( sprintf( __( 'Valid Key! Expires on %s', 'tribe-common' ), $expiration ) );
1061
  } else {
1062
+ // Set the key.
1063
+ $this->update_key( $replacement_key, $key_type );
1064
 
1065
  $default_success_msg = esc_html( sprintf( __( 'Thanks for setting up a valid key. It will expire on %s', 'tribe-common' ), $expiration ) );
1066
 
1067
+ // Set system info key on TEC.com after successful validation of license.
1068
  $optin_key = get_option( 'tribe_systeminfo_optin' );
1069
  if ( $optin_key ) {
1070
  Tribe__Support::send_sysinfo_key( $optin_key, $query_args['domain'], false, true );
common/src/Tribe/Promoter/Connector.php CHANGED
@@ -54,7 +54,7 @@ class Tribe__Promoter__Connector {
54
  'userId' => $user_id,
55
  ];
56
 
57
- $token = \Firebase\JWT\JWT::encode( $payload, $promoter_key );
58
 
59
  $response = $this->make_call( $url, [
60
  'body' => [ 'token' => $token ],
@@ -196,7 +196,7 @@ class Tribe__Promoter__Connector {
196
  'sourceId' => $post_id instanceof WP_Post ? $post_id->ID : $post_id,
197
  ];
198
 
199
- $token = \Firebase\JWT\JWT::encode( $payload, $secret_key );
200
 
201
  $url = $this->base_url() . 'connect/notify';
202
 
54
  'userId' => $user_id,
55
  ];
56
 
57
+ $token = \Firebase\JWT\JWT::encode( $payload, $promoter_key, 'HS256' );
58
 
59
  $response = $this->make_call( $url, [
60
  'body' => [ 'token' => $token ],
196
  'sourceId' => $post_id instanceof WP_Post ? $post_id->ID : $post_id,
197
  ];
198
 
199
+ $token = \Firebase\JWT\JWT::encode( $payload, $secret_key, 'HS256' );
200
 
201
  $url = $this->base_url() . 'connect/notify';
202
 
common/src/Tribe/Repository.php CHANGED
@@ -2429,6 +2429,40 @@ abstract class Tribe__Repository
2429
  return $this;
2430
  }
2431
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2432
  /**
2433
  * {@inheritdoc}
2434
  */
2429
  return $this;
2430
  }
2431
 
2432
+ /**
2433
+ * {@inheritdoc}
2434
+ */
2435
+ public function by_not_related_to( $by_meta_keys, $keys = null, $values = null ) {
2436
+
2437
+ /** @var wpdb $wpdb */
2438
+ global $wpdb;
2439
+
2440
+ $by_meta_keys = $this->prepare_interval( $by_meta_keys );
2441
+
2442
+ $join = '';
2443
+ $and_where = '';
2444
+ if ( ! empty( $keys ) || ! empty( $values ) ) {
2445
+ $join = "\nJOIN {$wpdb->postmeta} pm2 ON pm1.post_id = pm2.post_id\n";
2446
+ }
2447
+ if ( ! empty( $keys ) ) {
2448
+ $keys = $this->prepare_interval( $keys );
2449
+ $and_where .= "\nAND pm2.meta_key IN {$keys}\n";
2450
+ }
2451
+ if ( ! empty( $values ) ) {
2452
+ $values = $this->prepare_interval( $values );
2453
+ $and_where .= "\nAND pm2.meta_value IN {$values}\n";
2454
+ }
2455
+
2456
+ $this->where_clause( "{$wpdb->posts}.ID NOT IN (
2457
+ SELECT pm1.meta_value
2458
+ FROM {$wpdb->postmeta} pm1 {$join}
2459
+ WHERE pm1.meta_key IN {$by_meta_keys} {$and_where}
2460
+ GROUP BY( pm1.meta_value )
2461
+ )" );
2462
+
2463
+ return $this;
2464
+ }
2465
+
2466
  /**
2467
  * {@inheritdoc}
2468
  */
common/src/Tribe/Repository/Decorator.php CHANGED
@@ -354,6 +354,15 @@ abstract class Tribe__Repository__Decorator implements Tribe__Repository__Interf
354
  return $this;
355
  }
356
 
 
 
 
 
 
 
 
 
 
357
  /**
358
  * {@inheritdoc}
359
  */
354
  return $this;
355
  }
356
 
357
+ /**
358
+ * {@inheritdoc}
359
+ */
360
+ public function by_not_related_to( $by_meta_keys, $keys = null, $values = null ) {
361
+ $this->decorated->by_not_related_to( $by_meta_keys, $keys, $values );
362
+
363
+ return $this;
364
+ }
365
+
366
  /**
367
  * {@inheritdoc}
368
  */
common/src/Tribe/Repository/Interface.php CHANGED
@@ -186,6 +186,24 @@ interface Tribe__Repository__Interface
186
  */
187
  public function by_related_to_between( $by_meta_keys, $min, $max, $keys = null, $values = null );
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  /**
190
  * Adds an entry to the repository filter schema.
191
  *
186
  */
187
  public function by_related_to_between( $by_meta_keys, $min, $max, $keys = null, $values = null );
188
 
189
+ /**
190
+ * Filters the query to return posts that are not related to posts that have a specific meta value.
191
+ *
192
+ * @since TBD
193
+ *
194
+ * @param string|array $by_meta_keys One or more `meta_keys` relating
195
+ * another post TO this post type.
196
+ *
197
+ * @param string|array $keys One or more meta_keys to check on the post type in relation
198
+ * with the query post type(s); if the `$values` parameter is
199
+ * not provided then this will trigger an EXISTS check.
200
+ * @param string|array $values One or more value the meta_key specified with `$keys` should
201
+ * match.
202
+ *
203
+ * @return $this
204
+ */
205
+ public function by_not_related_to( $by_meta_keys, $keys = null, $values = null );
206
+
207
  /**
208
  * Adds an entry to the repository filter schema.
209
  *
common/src/Tribe/Settings_Manager.php CHANGED
@@ -26,7 +26,6 @@ class Tribe__Settings_Manager {
26
  add_action( '_network_admin_menu', [ $this, 'init_options' ] );
27
  add_action( '_admin_menu', [ $this, 'init_options' ] );
28
 
29
- add_action( 'admin_menu', [ $this, 'add_help_admin_menu_item' ], 50 );
30
  add_action( 'tribe_settings_do_tabs', [ $this, 'do_setting_tabs' ] );
31
  add_action( 'tribe_settings_validate_tab_network', [ $this, 'save_all_tabs_hidden' ] );
32
  add_action( 'updated_option', [ $this, 'update_options_cache' ], 10, 3 );
@@ -315,19 +314,10 @@ class Tribe__Settings_Manager {
315
  /**
316
  * Add help menu item to the admin (unless blocked via network admin settings).
317
  *
318
- * @todo move to an admin class
319
  */
320
  public function add_help_admin_menu_item() {
321
- $hidden_settings_tabs = self::get_network_option( 'hideSettingsTabs', [] );
322
- if ( in_array( 'help', $hidden_settings_tabs ) ) {
323
- return;
324
- }
325
-
326
- $parent = class_exists( 'Tribe__Events__Main' ) ? Tribe__Settings::$parent_page : Tribe__Settings::$parent_slug;
327
- $title = esc_html__( 'Help', 'tribe-common' );
328
- $slug = 'tribe-help';
329
-
330
- add_submenu_page( $parent, $title, $title, 'manage_options', $slug, [ $this, 'do_help_tab' ] );
331
  }
332
 
333
  /**
26
  add_action( '_network_admin_menu', [ $this, 'init_options' ] );
27
  add_action( '_admin_menu', [ $this, 'init_options' ] );
28
 
 
29
  add_action( 'tribe_settings_do_tabs', [ $this, 'do_setting_tabs' ] );
30
  add_action( 'tribe_settings_validate_tab_network', [ $this, 'save_all_tabs_hidden' ] );
31
  add_action( 'updated_option', [ $this, 'update_options_cache' ], 10, 3 );
314
  /**
315
  * Add help menu item to the admin (unless blocked via network admin settings).
316
  *
317
+ * @deprecated 5.0.2
318
  */
319
  public function add_help_admin_menu_item() {
320
+ _deprecated_function( __METHOD__, '5.0.2', 'Now handled by Tribe\Events\Admin\Settings::add_admin_pages()' );
 
 
 
 
 
 
 
 
 
321
  }
322
 
323
  /**
common/src/Tribe/Utils/Lazy_Events.php CHANGED
@@ -160,7 +160,7 @@ trait Lazy_Events {
160
 
161
  $hooked = has_action( $action, $this->lazy_resolve_callback );
162
 
163
- // Let's play it safe and move the resoloution as late as possible.
164
  $new_priority = false !== $hooked ? max( $hooked, $priority ) : $priority;
165
 
166
  if ( is_numeric( $hooked ) && $hooked !== $new_priority ) {
160
 
161
  $hooked = has_action( $action, $this->lazy_resolve_callback );
162
 
163
+ // Let's play it safe and move the resolution as late as possible.
164
  $new_priority = false !== $hooked ? max( $hooked, $priority ) : $priority;
165
 
166
  if ( is_numeric( $hooked ) && $hooked !== $new_priority ) {
common/src/Tribe/Utils/Taxonomy.php CHANGED
@@ -136,10 +136,11 @@ class Taxonomy {
136
  *
137
  * @param array $posts
138
  * @param array $taxonomies
 
139
  *
140
  * @return array<int, array>
141
  */
142
- public static function prime_term_cache( array $posts = [], array $taxonomies = [ 'post_tag', \Tribe__Events__Main::TAXONOMY ], $prime_term_meta = false ) {
143
  $first = reset( $posts );
144
  $is_numeric = ( ! $first instanceof \WP_Post );
145
  if ( $is_numeric ) {
@@ -169,7 +170,18 @@ class Taxonomy {
169
  }
170
 
171
  foreach ( $cache as $id => $object_taxonomies ) {
 
 
 
 
 
172
  foreach ( $object_taxonomies as $taxonomy => $term_ids ) {
 
 
 
 
 
 
173
  wp_cache_add( $id, $term_ids, $taxonomy . '_relationships' );
174
  }
175
  }
136
  *
137
  * @param array $posts
138
  * @param array $taxonomies
139
+ * @param bool $prime_term_meta
140
  *
141
  * @return array<int, array>
142
  */
143
+ public static function prime_term_cache( array $posts = [], array $taxonomies = [ 'post_tag', \Tribe__Events__Main::TAXONOMY ], bool $prime_term_meta = false ): array {
144
  $first = reset( $posts );
145
  $is_numeric = ( ! $first instanceof \WP_Post );
146
  if ( $is_numeric ) {
170
  }
171
 
172
  foreach ( $cache as $id => $object_taxonomies ) {
173
+ // Skip when invalid object id is passed.
174
+ if ( empty( $id ) ) {
175
+ continue;
176
+ }
177
+
178
  foreach ( $object_taxonomies as $taxonomy => $term_ids ) {
179
+ // Skip when invalid taxonomy is passed.
180
+ if ( empty( $taxonomy ) ) {
181
+ continue;
182
+ }
183
+
184
+ // Do not skip when `term_ids` are empty.
185
  wp_cache_add( $id, $term_ids, $taxonomy . '_relationships' );
186
  }
187
  }
common/src/functions/utils.php CHANGED
@@ -260,6 +260,7 @@ if ( ! function_exists( 'tribe_is_truthy' ) ) {
260
  'yes',
261
  'true',
262
  ] );
 
263
  // Makes sure we are dealing with lowercase for testing
264
  if ( is_string( $var ) ) {
265
  $var = strtolower( $var );
260
  'yes',
261
  'true',
262
  ] );
263
+
264
  // Makes sure we are dealing with lowercase for testing
265
  if ( is_string( $var ) ) {
266
  $var = strtolower( $var );
common/vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit881fdf7d174fe7f99b7faaf6bda53d99::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit46586e50609ff65f96658fb5e4e2c9e8::getLoader();
common/vendor/autoload_52.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
- return ComposerAutoloaderInit232a9e5fc4fb96ba622ed0ddf0210ab6::getLoader();
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
+ return ComposerAutoloaderInit10017778b88eefa5ac363af5e02e4d1e::getLoader();
common/vendor/composer/autoload_classmap.php CHANGED
@@ -7,8 +7,11 @@ $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
  'Firebase\\JWT\\BeforeValidException' => $vendorDir . '/firebase/php-jwt/src/BeforeValidException.php',
 
10
  'Firebase\\JWT\\ExpiredException' => $vendorDir . '/firebase/php-jwt/src/ExpiredException.php',
 
11
  'Firebase\\JWT\\JWT' => $vendorDir . '/firebase/php-jwt/src/JWT.php',
 
12
  'Firebase\\JWT\\SignatureInvalidException' => $vendorDir . '/firebase/php-jwt/src/SignatureInvalidException.php',
13
  'Monolog\\ErrorHandler' => $vendorDir . '/monolog/monolog/src/Monolog/ErrorHandler.php',
14
  'Monolog\\Formatter\\ChromePHPFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php',
7
 
8
  return array(
9
  'Firebase\\JWT\\BeforeValidException' => $vendorDir . '/firebase/php-jwt/src/BeforeValidException.php',
10
+ 'Firebase\\JWT\\CachedKeySet' => $vendorDir . '/firebase/php-jwt/src/CachedKeySet.php',
11
  'Firebase\\JWT\\ExpiredException' => $vendorDir . '/firebase/php-jwt/src/ExpiredException.php',
12
+ 'Firebase\\JWT\\JWK' => $vendorDir . '/firebase/php-jwt/src/JWK.php',
13
  'Firebase\\JWT\\JWT' => $vendorDir . '/firebase/php-jwt/src/JWT.php',
14
+ 'Firebase\\JWT\\Key' => $vendorDir . '/firebase/php-jwt/src/Key.php',
15
  'Firebase\\JWT\\SignatureInvalidException' => $vendorDir . '/firebase/php-jwt/src/SignatureInvalidException.php',
16
  'Monolog\\ErrorHandler' => $vendorDir . '/monolog/monolog/src/Monolog/ErrorHandler.php',
17
  'Monolog\\Formatter\\ChromePHPFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php',
common/vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit881fdf7d174fe7f99b7faaf6bda53d99
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit881fdf7d174fe7f99b7faaf6bda53d99
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit881fdf7d174fe7f99b7faaf6bda53d99', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit881fdf7d174fe7f99b7faaf6bda53d99', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInit881fdf7d174fe7f99b7faaf6bda53d99::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit46586e50609ff65f96658fb5e4e2c9e8
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit46586e50609ff65f96658fb5e4e2c9e8', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit46586e50609ff65f96658fb5e4e2c9e8', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit46586e50609ff65f96658fb5e4e2c9e8::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
common/vendor/composer/autoload_real_52.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real_52.php generated by xrstf/composer-php52
4
 
5
- class ComposerAutoloaderInit232a9e5fc4fb96ba622ed0ddf0210ab6 {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit232a9e5fc4fb96ba622ed0ddf0210ab6 {
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit232a9e5fc4fb96ba622ed0ddf0210ab6', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit232a9e5fc4fb96ba622ed0ddf0210ab6', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(dirname(__FILE__));
27
  $baseDir = dirname($vendorDir);
2
 
3
  // autoload_real_52.php generated by xrstf/composer-php52
4
 
5
+ class ComposerAutoloaderInit10017778b88eefa5ac363af5e02e4d1e {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit10017778b88eefa5ac363af5e02e4d1e', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit10017778b88eefa5ac363af5e02e4d1e', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(dirname(__FILE__));
27
  $baseDir = dirname($vendorDir);
common/vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit881fdf7d174fe7f99b7faaf6bda53d99
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'T' =>
@@ -68,8 +68,11 @@ class ComposerStaticInit881fdf7d174fe7f99b7faaf6bda53d99
68
 
69
  public static $classMap = array (
70
  'Firebase\\JWT\\BeforeValidException' => __DIR__ . '/..' . '/firebase/php-jwt/src/BeforeValidException.php',
 
71
  'Firebase\\JWT\\ExpiredException' => __DIR__ . '/..' . '/firebase/php-jwt/src/ExpiredException.php',
 
72
  'Firebase\\JWT\\JWT' => __DIR__ . '/..' . '/firebase/php-jwt/src/JWT.php',
 
73
  'Firebase\\JWT\\SignatureInvalidException' => __DIR__ . '/..' . '/firebase/php-jwt/src/SignatureInvalidException.php',
74
  'Monolog\\ErrorHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/ErrorHandler.php',
75
  'Monolog\\Formatter\\ChromePHPFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php',
@@ -270,10 +273,10 @@ class ComposerStaticInit881fdf7d174fe7f99b7faaf6bda53d99
270
  public static function getInitializer(ClassLoader $loader)
271
  {
272
  return \Closure::bind(function () use ($loader) {
273
- $loader->prefixLengthsPsr4 = ComposerStaticInit881fdf7d174fe7f99b7faaf6bda53d99::$prefixLengthsPsr4;
274
- $loader->prefixDirsPsr4 = ComposerStaticInit881fdf7d174fe7f99b7faaf6bda53d99::$prefixDirsPsr4;
275
- $loader->prefixesPsr0 = ComposerStaticInit881fdf7d174fe7f99b7faaf6bda53d99::$prefixesPsr0;
276
- $loader->classMap = ComposerStaticInit881fdf7d174fe7f99b7faaf6bda53d99::$classMap;
277
 
278
  }, null, ClassLoader::class);
279
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit46586e50609ff65f96658fb5e4e2c9e8
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'T' =>
68
 
69
  public static $classMap = array (
70
  'Firebase\\JWT\\BeforeValidException' => __DIR__ . '/..' . '/firebase/php-jwt/src/BeforeValidException.php',
71
+ 'Firebase\\JWT\\CachedKeySet' => __DIR__ . '/..' . '/firebase/php-jwt/src/CachedKeySet.php',
72
  'Firebase\\JWT\\ExpiredException' => __DIR__ . '/..' . '/firebase/php-jwt/src/ExpiredException.php',
73
+ 'Firebase\\JWT\\JWK' => __DIR__ . '/..' . '/firebase/php-jwt/src/JWK.php',
74
  'Firebase\\JWT\\JWT' => __DIR__ . '/..' . '/firebase/php-jwt/src/JWT.php',
75
+ 'Firebase\\JWT\\Key' => __DIR__ . '/..' . '/firebase/php-jwt/src/Key.php',
76
  'Firebase\\JWT\\SignatureInvalidException' => __DIR__ . '/..' . '/firebase/php-jwt/src/SignatureInvalidException.php',
77
  'Monolog\\ErrorHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/ErrorHandler.php',
78
  'Monolog\\Formatter\\ChromePHPFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php',
273
  public static function getInitializer(ClassLoader $loader)
274
  {
275
  return \Closure::bind(function () use ($loader) {
276
+ $loader->prefixLengthsPsr4 = ComposerStaticInit46586e50609ff65f96658fb5e4e2c9e8::$prefixLengthsPsr4;
277
+ $loader->prefixDirsPsr4 = ComposerStaticInit46586e50609ff65f96658fb5e4e2c9e8::$prefixDirsPsr4;
278
+ $loader->prefixesPsr0 = ComposerStaticInit46586e50609ff65f96658fb5e4e2c9e8::$prefixesPsr0;
279
+ $loader->classMap = ComposerStaticInit46586e50609ff65f96658fb5e4e2c9e8::$classMap;
280
 
281
  }, null, ClassLoader::class);
282
  }
common/vendor/composer/installed.json CHANGED
@@ -1,26 +1,34 @@
1
  [
2
  {
3
  "name": "firebase/php-jwt",
4
- "version": "v5.0.0",
5
- "version_normalized": "5.0.0.0",
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/firebase/php-jwt.git",
9
- "reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e"
10
  },
11
  "dist": {
12
  "type": "zip",
13
- "url": "https://api.github.com/repos/firebase/php-jwt/zipball/9984a4d3a32ae7673d6971ea00bae9d0a1abba0e",
14
- "reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e",
15
  "shasum": ""
16
  },
17
  "require": {
18
- "php": ">=5.3.0"
19
  },
20
  "require-dev": {
21
- "phpunit/phpunit": " 4.8.35"
 
 
 
 
 
 
 
 
22
  },
23
- "time": "2017-06-27T22:17:23+00:00",
24
  "type": "library",
25
  "installation-source": "dist",
26
  "autoload": {
@@ -45,7 +53,11 @@
45
  }
46
  ],
47
  "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
48
- "homepage": "https://github.com/firebase/php-jwt"
 
 
 
 
49
  },
50
  {
51
  "name": "lucatume/di52",
1
  [
2
  {
3
  "name": "firebase/php-jwt",
4
+ "version": "v6.3.0",
5
+ "version_normalized": "6.3.0.0",
6
  "source": {
7
  "type": "git",
8
  "url": "https://github.com/firebase/php-jwt.git",
9
+ "reference": "018dfc4e1da92ad8a1b90adc4893f476a3b41cb8"
10
  },
11
  "dist": {
12
  "type": "zip",
13
+ "url": "https://api.github.com/repos/firebase/php-jwt/zipball/018dfc4e1da92ad8a1b90adc4893f476a3b41cb8",
14
+ "reference": "018dfc4e1da92ad8a1b90adc4893f476a3b41cb8",
15
  "shasum": ""
16
  },
17
  "require": {
18
+ "php": "^7.1||^8.0"
19
  },
20
  "require-dev": {
21
+ "guzzlehttp/guzzle": "^6.5||^7.4",
22
+ "phpspec/prophecy-phpunit": "^1.1",
23
+ "phpunit/phpunit": "^7.5||^9.5",
24
+ "psr/cache": "^1.0||^2.0",
25
+ "psr/http-client": "^1.0",
26
+ "psr/http-factory": "^1.0"
27
+ },
28
+ "suggest": {
29
+ "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
30
  },
31
+ "time": "2022-07-15T16:48:45+00:00",
32
  "type": "library",
33
  "installation-source": "dist",
34
  "autoload": {
53
  }
54
  ],
55
  "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
56
+ "homepage": "https://github.com/firebase/php-jwt",
57
+ "keywords": [
58
+ "jwt",
59
+ "php"
60
+ ]
61
  },
62
  {
63
  "name": "lucatume/di52",
common/vendor/firebase/php-jwt/src/BeforeValidException.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
 
2
  namespace Firebase\JWT;
3
 
4
  class BeforeValidException extends \UnexpectedValueException
5
  {
6
-
7
  }
1
  <?php
2
+
3
  namespace Firebase\JWT;
4
 
5
  class BeforeValidException extends \UnexpectedValueException
6
  {
 
7
  }
common/vendor/firebase/php-jwt/src/CachedKeySet.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Firebase\JWT;
4
+
5
+ use ArrayAccess;
6
+ use LogicException;
7
+ use OutOfBoundsException;
8
+ use Psr\Cache\CacheItemInterface;
9
+ use Psr\Cache\CacheItemPoolInterface;
10
+ use Psr\Http\Client\ClientInterface;
11
+ use Psr\Http\Message\RequestFactoryInterface;
12
+ use RuntimeException;
13
+
14
+ /**
15
+ * @implements ArrayAccess<string, Key>
16
+ */
17
+ class CachedKeySet implements ArrayAccess
18
+ {
19
+ /**
20
+ * @var string
21
+ */
22
+ private $jwksUri;
23
+ /**
24
+ * @var ClientInterface
25
+ */
26
+ private $httpClient;
27
+ /**
28
+ * @var RequestFactoryInterface
29
+ */
30
+ private $httpFactory;
31
+ /**
32
+ * @var CacheItemPoolInterface
33
+ */
34
+ private $cache;
35
+ /**
36
+ * @var ?int
37
+ */
38
+ private $expiresAfter;
39
+ /**
40
+ * @var ?CacheItemInterface
41
+ */
42
+ private $cacheItem;
43
+ /**
44
+ * @var array<string, Key>
45
+ */
46
+ private $keySet;
47
+ /**
48
+ * @var string
49
+ */
50
+ private $cacheKey;
51
+ /**
52
+ * @var string
53
+ */
54
+ private $cacheKeyPrefix = 'jwks';
55
+ /**
56
+ * @var int
57
+ */
58
+ private $maxKeyLength = 64;
59
+ /**
60
+ * @var bool
61
+ */
62
+ private $rateLimit;
63
+ /**
64
+ * @var string
65
+ */
66
+ private $rateLimitCacheKey;
67
+ /**
68
+ * @var int
69
+ */
70
+ private $maxCallsPerMinute = 10;
71
+ /**
72
+ * @var string|null
73
+ */
74
+ private $defaultAlg;
75
+
76
+ public function __construct(
77
+ string $jwksUri,
78
+ ClientInterface $httpClient,
79
+ RequestFactoryInterface $httpFactory,
80
+ CacheItemPoolInterface $cache,
81
+ int $expiresAfter = null,
82
+ bool $rateLimit = false,
83
+ string $defaultAlg = null
84
+ ) {
85
+ $this->jwksUri = $jwksUri;
86
+ $this->httpClient = $httpClient;
87
+ $this->httpFactory = $httpFactory;
88
+ $this->cache = $cache;
89
+ $this->expiresAfter = $expiresAfter;
90
+ $this->rateLimit = $rateLimit;
91
+ $this->defaultAlg = $defaultAlg;
92
+ $this->setCacheKeys();
93
+ }
94
+
95
+ /**
96
+ * @param string $keyId
97
+ * @return Key
98
+ */
99
+ public function offsetGet($keyId): Key
100
+ {
101
+ if (!$this->keyIdExists($keyId)) {
102
+ throw new OutOfBoundsException('Key ID not found');
103
+ }
104
+ return $this->keySet[$keyId];
105
+ }
106
+
107
+ /**
108
+ * @param string $keyId
109
+ * @return bool
110
+ */
111
+ public function offsetExists($keyId): bool
112
+ {
113
+ return $this->keyIdExists($keyId);
114
+ }
115
+
116
+ /**
117
+ * @param string $offset
118
+ * @param Key $value
119
+ */
120
+ public function offsetSet($offset, $value): void
121
+ {
122
+ throw new LogicException('Method not implemented');
123
+ }
124
+
125
+ /**
126
+ * @param string $offset
127
+ */
128
+ public function offsetUnset($offset): void
129
+ {
130
+ throw new LogicException('Method not implemented');
131
+ }
132
+
133
+ private function keyIdExists(string $keyId): bool
134
+ {
135
+ if (null === $this->keySet) {
136
+ $item = $this->getCacheItem();
137
+ // Try to load keys from cache
138
+ if ($item->isHit()) {
139
+ // item found! Return it
140
+ $jwks = $item->get();
141
+ $this->keySet = JWK::parseKeySet(json_decode($jwks, true), $this->defaultAlg);
142
+ }
143
+ }
144
+
145
+ if (!isset($this->keySet[$keyId])) {
146
+ if ($this->rateLimitExceeded()) {
147
+ return false;
148
+ }
149
+ $request = $this->httpFactory->createRequest('get', $this->jwksUri);
150
+ $jwksResponse = $this->httpClient->sendRequest($request);
151
+ $jwks = (string) $jwksResponse->getBody();
152
+ $this->keySet = JWK::parseKeySet(json_decode($jwks, true), $this->defaultAlg);
153
+
154
+ if (!isset($this->keySet[$keyId])) {
155
+ return false;
156
+ }
157
+
158
+ $item = $this->getCacheItem();
159
+ $item->set($jwks);
160
+ if ($this->expiresAfter) {
161
+ $item->expiresAfter($this->expiresAfter);
162
+ }
163
+ $this->cache->save($item);
164
+ }
165
+
166
+ return true;
167
+ }
168
+
169
+ private function rateLimitExceeded(): bool
170
+ {
171
+ if (!$this->rateLimit) {
172
+ return false;
173
+ }
174
+
175
+ $cacheItem = $this->cache->getItem($this->rateLimitCacheKey);
176
+ if (!$cacheItem->isHit()) {
177
+ $cacheItem->expiresAfter(1); // # of calls are cached each minute
178
+ }
179
+
180
+ $callsPerMinute = (int) $cacheItem->get();
181
+ if (++$callsPerMinute > $this->maxCallsPerMinute) {
182
+ return true;
183
+ }
184
+ $cacheItem->set($callsPerMinute);
185
+ $this->cache->save($cacheItem);
186
+ return false;
187
+ }
188
+
189
+ private function getCacheItem(): CacheItemInterface
190
+ {
191
+ if (\is_null($this->cacheItem)) {
192
+ $this->cacheItem = $this->cache->getItem($this->cacheKey);
193
+ }
194
+
195
+ return $this->cacheItem;
196
+ }
197
+
198
+ private function setCacheKeys(): void
199
+ {
200
+ if (empty($this->jwksUri)) {
201
+ throw new RuntimeException('JWKS URI is empty');
202
+ }
203
+
204
+ // ensure we do not have illegal characters
205
+ $key = preg_replace('|[^a-zA-Z0-9_\.!]|', '', $this->jwksUri);
206
+
207
+ // add prefix
208
+ $key = $this->cacheKeyPrefix . $key;
209
+
210
+ // Hash keys if they exceed $maxKeyLength of 64
211
+ if (\strlen($key) > $this->maxKeyLength) {
212
+ $key = substr(hash('sha256', $key), 0, $this->maxKeyLength);
213
+ }
214
+
215
+ $this->cacheKey = $key;
216
+
217
+ if ($this->rateLimit) {
218
+ // add prefix
219
+ $rateLimitKey = $this->cacheKeyPrefix . 'ratelimit' . $key;
220
+
221
+ // Hash keys if they exceed $maxKeyLength of 64
222
+ if (\strlen($rateLimitKey) > $this->maxKeyLength) {
223
+ $rateLimitKey = substr(hash('sha256', $rateLimitKey), 0, $this->maxKeyLength);
224
+ }
225
+
226
+ $this->rateLimitCacheKey = $rateLimitKey;
227
+ }
228
+ }
229
+ }
common/vendor/firebase/php-jwt/src/ExpiredException.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
 
2
  namespace Firebase\JWT;
3
 
4
  class ExpiredException extends \UnexpectedValueException
5
  {
6
-
7
  }
1
  <?php
2
+
3
  namespace Firebase\JWT;
4
 
5
  class ExpiredException extends \UnexpectedValueException
6
  {
 
7
  }
common/vendor/firebase/php-jwt/src/JWK.php ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Firebase\JWT;
4
+
5
+ use DomainException;
6
+ use InvalidArgumentException;
7
+ use UnexpectedValueException;
8
+
9
+ /**
10
+ * JSON Web Key implementation, based on this spec:
11
+ * https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
12
+ *
13
+ * PHP version 5
14
+ *
15
+ * @category Authentication
16
+ * @package Authentication_JWT
17
+ * @author Bui Sy Nguyen <nguyenbs@gmail.com>
18
+ * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
19
+ * @link https://github.com/firebase/php-jwt
20
+ */
21
+ class JWK
22
+ {
23
+ private const OID = '1.2.840.10045.2.1';
24
+ private const ASN1_OBJECT_IDENTIFIER = 0x06;
25
+ private const ASN1_SEQUENCE = 0x10; // also defined in JWT
26
+ private const ASN1_BIT_STRING = 0x03;
27
+ private const EC_CURVES = [
28
+ 'P-256' => '1.2.840.10045.3.1.7', // Len: 64
29
+ // 'P-384' => '1.3.132.0.34', // Len: 96 (not yet supported)
30
+ // 'P-521' => '1.3.132.0.35', // Len: 132 (not supported)
31
+ ];
32
+
33
+ /**
34
+ * Parse a set of JWK keys
35
+ *
36
+ * @param array<mixed> $jwks The JSON Web Key Set as an associative array
37
+ * @param string $defaultAlg The algorithm for the Key object if "alg" is not set in the
38
+ * JSON Web Key Set
39
+ *
40
+ * @return array<string, Key> An associative array of key IDs (kid) to Key objects
41
+ *
42
+ * @throws InvalidArgumentException Provided JWK Set is empty
43
+ * @throws UnexpectedValueException Provided JWK Set was invalid
44
+ * @throws DomainException OpenSSL failure
45
+ *
46
+ * @uses parseKey
47
+ */
48
+ public static function parseKeySet(array $jwks, string $defaultAlg = null): array
49
+ {
50
+ $keys = [];
51
+
52
+ if (!isset($jwks['keys'])) {
53
+ throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
54
+ }
55
+
56
+ if (empty($jwks['keys'])) {
57
+ throw new InvalidArgumentException('JWK Set did not contain any keys');
58
+ }
59
+
60
+ foreach ($jwks['keys'] as $k => $v) {
61
+ $kid = isset($v['kid']) ? $v['kid'] : $k;
62
+ if ($key = self::parseKey($v, $defaultAlg)) {
63
+ $keys[(string) $kid] = $key;
64
+ }
65
+ }
66
+
67
+ if (0 === \count($keys)) {
68
+ throw new UnexpectedValueException('No supported algorithms found in JWK Set');
69
+ }
70
+
71
+ return $keys;
72
+ }
73
+
74
+ /**
75
+ * Parse a JWK key
76
+ *
77
+ * @param array<mixed> $jwk An individual JWK
78
+ * @param string $defaultAlg The algorithm for the Key object if "alg" is not set in the
79
+ * JSON Web Key Set
80
+ *
81
+ * @return Key The key object for the JWK
82
+ *
83
+ * @throws InvalidArgumentException Provided JWK is empty
84
+ * @throws UnexpectedValueException Provided JWK was invalid
85
+ * @throws DomainException OpenSSL failure
86
+ *
87
+ * @uses createPemFromModulusAndExponent
88
+ */
89
+ public static function parseKey(array $jwk, string $defaultAlg = null): ?Key
90
+ {
91
+ if (empty($jwk)) {
92
+ throw new InvalidArgumentException('JWK must not be empty');
93
+ }
94
+
95
+ if (!isset($jwk['kty'])) {
96
+ throw new UnexpectedValueException('JWK must contain a "kty" parameter');
97
+ }
98
+
99
+ if (!isset($jwk['alg'])) {
100
+ if (\is_null($defaultAlg)) {
101
+ // The "alg" parameter is optional in a KTY, but an algorithm is required
102
+ // for parsing in this library. Use the $defaultAlg parameter when parsing the
103
+ // key set in order to prevent this error.
104
+ // @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
105
+ throw new UnexpectedValueException('JWK must contain an "alg" parameter');
106
+ }
107
+ $jwk['alg'] = $defaultAlg;
108
+ }
109
+
110
+ switch ($jwk['kty']) {
111
+ case 'RSA':
112
+ if (!empty($jwk['d'])) {
113
+ throw new UnexpectedValueException('RSA private keys are not supported');
114
+ }
115
+ if (!isset($jwk['n']) || !isset($jwk['e'])) {
116
+ throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"');
117
+ }
118
+
119
+ $pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']);
120
+ $publicKey = \openssl_pkey_get_public($pem);
121
+ if (false === $publicKey) {
122
+ throw new DomainException(
123
+ 'OpenSSL error: ' . \openssl_error_string()
124
+ );
125
+ }
126
+ return new Key($publicKey, $jwk['alg']);
127
+ case 'EC':
128
+ if (isset($jwk['d'])) {
129
+ // The key is actually a private key
130
+ throw new UnexpectedValueException('Key data must be for a public key');
131
+ }
132
+
133
+ if (empty($jwk['crv'])) {
134
+ throw new UnexpectedValueException('crv not set');
135
+ }
136
+
137
+ if (!isset(self::EC_CURVES[$jwk['crv']])) {
138
+ throw new DomainException('Unrecognised or unsupported EC curve');
139
+ }
140
+
141
+ if (empty($jwk['x']) || empty($jwk['y'])) {
142
+ throw new UnexpectedValueException('x and y not set');
143
+ }
144
+
145
+ $publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']);
146
+ return new Key($publicKey, $jwk['alg']);
147
+ default:
148
+ // Currently only RSA is supported
149
+ break;
150
+ }
151
+
152
+ return null;
153
+ }
154
+
155
+ /**
156
+ * Converts the EC JWK values to pem format.
157
+ *
158
+ * @param string $crv The EC curve (only P-256 is supported)
159
+ * @param string $x The EC x-coordinate
160
+ * @param string $y The EC y-coordinate
161
+ *
162
+ * @return string
163
+ */
164
+ private static function createPemFromCrvAndXYCoordinates(string $crv, string $x, string $y): string
165
+ {
166
+ $pem =
167
+ self::encodeDER(
168
+ self::ASN1_SEQUENCE,
169
+ self::encodeDER(
170
+ self::ASN1_SEQUENCE,
171
+ self::encodeDER(
172
+ self::ASN1_OBJECT_IDENTIFIER,
173
+ self::encodeOID(self::OID)
174
+ )
175
+ . self::encodeDER(
176
+ self::ASN1_OBJECT_IDENTIFIER,
177
+ self::encodeOID(self::EC_CURVES[$crv])
178
+ )
179
+ ) .
180
+ self::encodeDER(
181
+ self::ASN1_BIT_STRING,
182
+ \chr(0x00) . \chr(0x04)
183
+ . JWT::urlsafeB64Decode($x)
184
+ . JWT::urlsafeB64Decode($y)
185
+ )
186
+ );
187
+
188
+ return sprintf(
189
+ "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n",
190
+ wordwrap(base64_encode($pem), 64, "\n", true)
191
+ );
192
+ }
193
+
194
+ /**
195
+ * Create a public key represented in PEM format from RSA modulus and exponent information
196
+ *
197
+ * @param string $n The RSA modulus encoded in Base64
198
+ * @param string $e The RSA exponent encoded in Base64
199
+ *
200
+ * @return string The RSA public key represented in PEM format
201
+ *
202
+ * @uses encodeLength
203
+ */
204
+ private static function createPemFromModulusAndExponent(
205
+ string $n,
206
+ string $e
207
+ ): string {
208
+ $mod = JWT::urlsafeB64Decode($n);
209
+ $exp = JWT::urlsafeB64Decode($e);
210
+
211
+ $modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
212
+ $publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);
213
+
214
+ $rsaPublicKey = \pack(
215
+ 'Ca*a*a*',
216
+ 48,
217
+ self::encodeLength(\strlen($modulus) + \strlen($publicExponent)),
218
+ $modulus,
219
+ $publicExponent
220
+ );
221
+
222
+ // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
223
+ $rsaOID = \pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
224
+ $rsaPublicKey = \chr(0) . $rsaPublicKey;
225
+ $rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey;
226
+
227
+ $rsaPublicKey = \pack(
228
+ 'Ca*a*',
229
+ 48,
230
+ self::encodeLength(\strlen($rsaOID . $rsaPublicKey)),
231
+ $rsaOID . $rsaPublicKey
232
+ );
233
+
234
+ return "-----BEGIN PUBLIC KEY-----\r\n" .
235
+ \chunk_split(\base64_encode($rsaPublicKey), 64) .
236
+ '-----END PUBLIC KEY-----';
237
+ }
238
+
239
+ /**
240
+ * DER-encode the length
241
+ *
242
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
243
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
244
+ *
245
+ * @param int $length
246
+ * @return string
247
+ */
248
+ private static function encodeLength(int $length): string
249
+ {
250
+ if ($length <= 0x7F) {
251
+ return \chr($length);
252
+ }
253
+
254
+ $temp = \ltrim(\pack('N', $length), \chr(0));
255
+
256
+ return \pack('Ca*', 0x80 | \strlen($temp), $temp);
257
+ }
258
+
259
+ /**
260
+ * Encodes a value into a DER object.
261
+ * Also defined in Firebase\JWT\JWT
262
+ *
263
+ * @param int $type DER tag
264
+ * @param string $value the value to encode
265
+ * @return string the encoded object
266
+ */
267
+ private static function encodeDER(int $type, string $value): string
268
+ {
269
+ $tag_header = 0;
270
+ if ($type === self::ASN1_SEQUENCE) {
271
+ $tag_header |= 0x20;
272
+ }
273
+
274
+ // Type
275
+ $der = \chr($tag_header | $type);
276
+
277
+ // Length
278
+ $der .= \chr(\strlen($value));
279
+
280
+ return $der . $value;
281
+ }
282
+
283
+ /**
284
+ * Encodes a string into a DER-encoded OID.
285
+ *
286
+ * @param string $oid the OID string
287
+ * @return string the binary DER-encoded OID
288
+ */
289
+ private static function encodeOID(string $oid): string
290
+ {
291
+ $octets = explode('.', $oid);
292
+
293
+ // Get the first octet
294
+ $first = (int) array_shift($octets);
295
+ $second = (int) array_shift($octets);
296
+ $oid = \chr($first * 40 + $second);
297
+
298
+ // Iterate over subsequent octets
299
+ foreach ($octets as $octet) {
300
+ if ($octet == 0) {
301
+ $oid .= \chr(0x00);
302
+ continue;
303
+ }
304
+ $bin = '';
305
+
306
+ while ($octet) {
307
+ $bin .= \chr(0x80 | ($octet & 0x7f));
308
+ $octet >>= 7;
309
+ }
310
+ $bin[0] = $bin[0] & \chr(0x7f);
311
+
312
+ // Convert to big endian if necessary
313
+ if (pack('V', 65534) == pack('L', 65534)) {
314
+ $oid .= strrev($bin);
315
+ } else {
316
+ $oid .= $bin;
317
+ }
318
+ }
319
+
320
+ return $oid;
321
+ }
322
+ }
common/vendor/firebase/php-jwt/src/JWT.php CHANGED
@@ -1,10 +1,16 @@
1
  <?php
2
 
3
  namespace Firebase\JWT;
4
- use \DomainException;
5
- use \InvalidArgumentException;
6
- use \UnexpectedValueException;
7
- use \DateTime;
 
 
 
 
 
 
8
 
9
  /**
10
  * JSON Web Token implementation, based on this spec:
@@ -21,42 +27,57 @@ use \DateTime;
21
  */
22
  class JWT
23
  {
 
 
 
24
 
25
  /**
26
  * When checking nbf, iat or expiration times,
27
  * we want to provide some extra leeway time to
28
  * account for clock skew.
 
 
29
  */
30
  public static $leeway = 0;
31
 
32
  /**
33
  * Allow the current timestamp to be specified.
34
  * Useful for fixing a value within unit testing.
35
- *
36
  * Will default to PHP time() value if null.
 
 
37
  */
38
  public static $timestamp = null;
39
 
40
- public static $supported_algs = array(
41
- 'HS256' => array('hash_hmac', 'SHA256'),
42
- 'HS512' => array('hash_hmac', 'SHA512'),
43
- 'HS384' => array('hash_hmac', 'SHA384'),
44
- 'RS256' => array('openssl', 'SHA256'),
45
- 'RS384' => array('openssl', 'SHA384'),
46
- 'RS512' => array('openssl', 'SHA512'),
47
- );
 
 
 
 
 
 
48
 
49
  /**
50
  * Decodes a JWT string into a PHP object.
51
  *
52
- * @param string $jwt The JWT
53
- * @param string|array $key The key, or map of keys.
54
- * If the algorithm used is asymmetric, this is the public key
55
- * @param array $allowed_algs List of supported verification algorithms
56
- * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
 
57
  *
58
- * @return object The JWT's payload as a PHP object
59
  *
 
 
60
  * @throws UnexpectedValueException Provided JWT was invalid
61
  * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed
62
  * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf'
@@ -66,57 +87,64 @@ class JWT
66
  * @uses jsonDecode
67
  * @uses urlsafeB64Decode
68
  */
69
- public static function decode($jwt, $key, array $allowed_algs = array())
70
- {
71
- $timestamp = is_null(static::$timestamp) ? time() : static::$timestamp;
 
 
 
72
 
73
- if (empty($key)) {
74
  throw new InvalidArgumentException('Key may not be empty');
75
  }
76
- $tks = explode('.', $jwt);
77
- if (count($tks) != 3) {
78
  throw new UnexpectedValueException('Wrong number of segments');
79
  }
80
  list($headb64, $bodyb64, $cryptob64) = $tks;
81
- if (null === ($header = static::jsonDecode(static::urlsafeB64Decode($headb64)))) {
 
82
  throw new UnexpectedValueException('Invalid header encoding');
83
  }
84
- if (null === $payload = static::jsonDecode(static::urlsafeB64Decode($bodyb64))) {
 
85
  throw new UnexpectedValueException('Invalid claims encoding');
86
  }
87
- if (false === ($sig = static::urlsafeB64Decode($cryptob64))) {
88
- throw new UnexpectedValueException('Invalid signature encoding');
 
89
  }
 
 
 
 
90
  if (empty($header->alg)) {
91
  throw new UnexpectedValueException('Empty algorithm');
92
  }
93
  if (empty(static::$supported_algs[$header->alg])) {
94
  throw new UnexpectedValueException('Algorithm not supported');
95
  }
96
- if (!in_array($header->alg, $allowed_algs)) {
97
- throw new UnexpectedValueException('Algorithm not allowed');
 
 
 
 
 
98
  }
99
- if (is_array($key) || $key instanceof \ArrayAccess) {
100
- if (isset($header->kid)) {
101
- if (!isset($key[$header->kid])) {
102
- throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
103
- }
104
- $key = $key[$header->kid];
105
- } else {
106
- throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
107
- }
108
  }
109
-
110
- // Check the signature
111
- if (!static::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) {
112
  throw new SignatureInvalidException('Signature verification failed');
113
  }
114
 
115
- // Check if the nbf if it is defined. This is the time that the
116
  // token can actually be used. If it's not yet that time, abort.
117
  if (isset($payload->nbf) && $payload->nbf > ($timestamp + static::$leeway)) {
118
  throw new BeforeValidException(
119
- 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->nbf)
120
  );
121
  }
122
 
@@ -125,7 +153,7 @@ class JWT
125
  // correctly used the nbf claim).
126
  if (isset($payload->iat) && $payload->iat > ($timestamp + static::$leeway)) {
127
  throw new BeforeValidException(
128
- 'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->iat)
129
  );
130
  }
131
 
@@ -140,118 +168,161 @@ class JWT
140
  /**
141
  * Converts and signs a PHP object or array into a JWT string.
142
  *
143
- * @param object|array $payload PHP object or array
144
- * @param string $key The secret key.
145
- * If the algorithm used is asymmetric, this is the private key
146
- * @param string $alg The signing algorithm.
147
- * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
148
- * @param mixed $keyId
149
- * @param array $head An array with header elements to attach
150
  *
151
  * @return string A signed JWT
152
  *
153
  * @uses jsonEncode
154
  * @uses urlsafeB64Encode
155
  */
156
- public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null)
157
- {
158
- $header = array('typ' => 'JWT', 'alg' => $alg);
 
 
 
 
 
159
  if ($keyId !== null) {
160
  $header['kid'] = $keyId;
161
  }
162
- if ( isset($head) && is_array($head) ) {
163
- $header = array_merge($head, $header);
164
  }
165
- $segments = array();
166
- $segments[] = static::urlsafeB64Encode(static::jsonEncode($header));
167
- $segments[] = static::urlsafeB64Encode(static::jsonEncode($payload));
168
- $signing_input = implode('.', $segments);
169
 
170
  $signature = static::sign($signing_input, $key, $alg);
171
  $segments[] = static::urlsafeB64Encode($signature);
172
 
173
- return implode('.', $segments);
174
  }
175
 
176
  /**
177
  * Sign a string with a given key and algorithm.
178
  *
179
- * @param string $msg The message to sign
180
- * @param string|resource $key The secret key
181
- * @param string $alg The signing algorithm.
182
- * Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
183
  *
184
  * @return string An encrypted message
185
  *
186
- * @throws DomainException Unsupported algorithm was specified
187
  */
188
- public static function sign($msg, $key, $alg = 'HS256')
189
- {
 
 
 
190
  if (empty(static::$supported_algs[$alg])) {
191
  throw new DomainException('Algorithm not supported');
192
  }
193
  list($function, $algorithm) = static::$supported_algs[$alg];
194
- switch($function) {
195
  case 'hash_hmac':
196
- return hash_hmac($algorithm, $msg, $key, true);
 
 
 
197
  case 'openssl':
198
  $signature = '';
199
- $success = openssl_sign($msg, $signature, $key, $algorithm);
200
  if (!$success) {
201
- throw new DomainException("OpenSSL unable to sign data");
202
- } else {
203
- return $signature;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  }
205
  }
 
 
206
  }
207
 
208
  /**
209
  * Verify a signature with the message, key and method. Not all methods
210
  * are symmetric, so we must have a separate verify and sign method.
211
  *
212
- * @param string $msg The original message (header and body)
213
- * @param string $signature The original signature
214
- * @param string|resource $key For HS*, a string key works. for RS*, must be a resource of an openssl public key
215
- * @param string $alg The algorithm
216
  *
217
  * @return bool
218
  *
219
- * @throws DomainException Invalid Algorithm or OpenSSL failure
220
  */
221
- private static function verify($msg, $signature, $key, $alg)
222
- {
 
 
 
 
223
  if (empty(static::$supported_algs[$alg])) {
224
  throw new DomainException('Algorithm not supported');
225
  }
226
 
227
  list($function, $algorithm) = static::$supported_algs[$alg];
228
- switch($function) {
229
  case 'openssl':
230
- $success = openssl_verify($msg, $signature, $key, $algorithm);
231
  if ($success === 1) {
232
  return true;
233
- } elseif ($success === 0) {
 
234
  return false;
235
  }
236
  // returns 1 on success, 0 on failure, -1 on error.
237
  throw new DomainException(
238
- 'OpenSSL error: ' . openssl_error_string()
239
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  case 'hash_hmac':
241
  default:
242
- $hash = hash_hmac($algorithm, $msg, $key, true);
243
- if (function_exists('hash_equals')) {
244
- return hash_equals($signature, $hash);
245
- }
246
- $len = min(static::safeStrlen($signature), static::safeStrlen($hash));
247
-
248
- $status = 0;
249
- for ($i = 0; $i < $len; $i++) {
250
- $status |= (ord($signature[$i]) ^ ord($hash[$i]));
251
  }
252
- $status |= (static::safeStrlen($signature) ^ static::safeStrlen($hash));
253
-
254
- return ($status === 0);
255
  }
256
  }
257
 
@@ -260,30 +331,16 @@ class JWT
260
  *
261
  * @param string $input JSON string
262
  *
263
- * @return object Object representation of JSON string
264
  *
265
  * @throws DomainException Provided string was invalid JSON
266
  */
267
- public static function jsonDecode($input)
268
  {
269
- if (version_compare(PHP_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) {
270
- /** In PHP >=5.4.0, json_decode() accepts an options parameter, that allows you
271
- * to specify that large ints (like Steam Transaction IDs) should be treated as
272
- * strings, rather than the PHP default behaviour of converting them to floats.
273
- */
274
- $obj = json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
275
- } else {
276
- /** Not all servers will support that, however, so for older versions we must
277
- * manually detect large ints in the JSON string and quote them (thus converting
278
- *them to strings) before decoding, hence the preg_replace() call.
279
- */
280
- $max_int_length = strlen((string) PHP_INT_MAX) - 1;
281
- $json_without_bigints = preg_replace('/:\s*(-?\d{'.$max_int_length.',})/', ': "$1"', $input);
282
- $obj = json_decode($json_without_bigints);
283
- }
284
 
285
- if (function_exists('json_last_error') && $errno = json_last_error()) {
286
- static::handleJsonError($errno);
287
  } elseif ($obj === null && $input !== 'null') {
288
  throw new DomainException('Null result with non-null input');
289
  }
@@ -291,22 +348,30 @@ class JWT
291
  }
292
 
293
  /**
294
- * Encode a PHP object into a JSON string.
295
  *
296
- * @param object|array $input A PHP object or array
297
  *
298
- * @return string JSON representation of the PHP object or array
299
  *
300
  * @throws DomainException Provided object could not be encoded to valid JSON
301
  */
302
- public static function jsonEncode($input)
303
  {
304
- $json = json_encode($input);
305
- if (function_exists('json_last_error') && $errno = json_last_error()) {
306
- static::handleJsonError($errno);
 
 
 
 
 
307
  } elseif ($json === 'null' && $input !== null) {
308
  throw new DomainException('Null result with non-null input');
309
  }
 
 
 
310
  return $json;
311
  }
312
 
@@ -316,15 +381,17 @@ class JWT
316
  * @param string $input A Base64 encoded string
317
  *
318
  * @return string A decoded string
 
 
319
  */
320
- public static function urlsafeB64Decode($input)
321
  {
322
- $remainder = strlen($input) % 4;
323
  if ($remainder) {
324
  $padlen = 4 - $remainder;
325
- $input .= str_repeat('=', $padlen);
326
  }
327
- return base64_decode(strtr($input, '-_', '+/'));
328
  }
329
 
330
  /**
@@ -334,9 +401,64 @@ class JWT
334
  *
335
  * @return string The base64 encode of what you passed in
336
  */
337
- public static function urlsafeB64Encode($input)
338
  {
339
- return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  }
341
 
342
  /**
@@ -344,17 +466,19 @@ class JWT
344
  *
345
  * @param int $errno An error number from json_last_error()
346
  *
 
 
347
  * @return void
348
  */
349
- private static function handleJsonError($errno)
350
  {
351
- $messages = array(
352
  JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
353
  JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
354
  JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
355
  JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
356
  JSON_ERROR_UTF8 => 'Malformed UTF-8 characters' //PHP >= 5.3.3
357
- );
358
  throw new DomainException(
359
  isset($messages[$errno])
360
  ? $messages[$errno]
@@ -365,15 +489,139 @@ class JWT
365
  /**
366
  * Get the number of bytes in cryptographic strings.
367
  *
368
- * @param string
369
  *
370
  * @return int
371
  */
372
- private static function safeStrlen($str)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  {
374
- if (function_exists('mb_strlen')) {
375
- return mb_strlen($str, '8bit');
 
376
  }
377
- return strlen($str);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  }
379
  }
1
  <?php
2
 
3
  namespace Firebase\JWT;
4
+
5
+ use ArrayAccess;
6
+ use DateTime;
7
+ use DomainException;
8
+ use Exception;
9
+ use InvalidArgumentException;
10
+ use OpenSSLAsymmetricKey;
11
+ use OpenSSLCertificate;
12
+ use stdClass;
13
+ use UnexpectedValueException;
14
 
15
  /**
16
  * JSON Web Token implementation, based on this spec:
27
  */
28
  class JWT
29
  {
30
+ private const ASN1_INTEGER = 0x02;
31
+ private const ASN1_SEQUENCE = 0x10;
32
+ private const ASN1_BIT_STRING = 0x03;
33
 
34
  /**
35
  * When checking nbf, iat or expiration times,
36
  * we want to provide some extra leeway time to
37
  * account for clock skew.
38
+ *
39
+ * @var int
40
  */
41
  public static $leeway = 0;
42
 
43
  /**
44
  * Allow the current timestamp to be specified.
45
  * Useful for fixing a value within unit testing.
 
46
  * Will default to PHP time() value if null.
47
+ *
48
+ * @var ?int
49
  */
50
  public static $timestamp = null;
51
 
52
+ /**
53
+ * @var array<string, string[]>
54
+ */
55
+ public static $supported_algs = [
56
+ 'ES384' => ['openssl', 'SHA384'],
57
+ 'ES256' => ['openssl', 'SHA256'],
58
+ 'HS256' => ['hash_hmac', 'SHA256'],
59
+ 'HS384' => ['hash_hmac', 'SHA384'],
60
+ 'HS512' => ['hash_hmac', 'SHA512'],
61
+ 'RS256' => ['openssl', 'SHA256'],
62
+ 'RS384' => ['openssl', 'SHA384'],
63
+ 'RS512' => ['openssl', 'SHA512'],
64
+ 'EdDSA' => ['sodium_crypto', 'EdDSA'],
65
+ ];
66
 
67
  /**
68
  * Decodes a JWT string into a PHP object.
69
  *
70
+ * @param string $jwt The JWT
71
+ * @param Key|array<string,Key> $keyOrKeyArray The Key or associative array of key IDs (kid) to Key objects.
72
+ * If the algorithm used is asymmetric, this is the public key
73
+ * Each Key object contains an algorithm and matching key.
74
+ * Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
75
+ * 'HS512', 'RS256', 'RS384', and 'RS512'
76
  *
77
+ * @return stdClass The JWT's payload as a PHP object
78
  *
79
+ * @throws InvalidArgumentException Provided key/key-array was empty
80
+ * @throws DomainException Provided JWT is malformed
81
  * @throws UnexpectedValueException Provided JWT was invalid
82
  * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed
83
  * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf'
87
  * @uses jsonDecode
88
  * @uses urlsafeB64Decode
89
  */
90
+ public static function decode(
91
+ string $jwt,
92
+ $keyOrKeyArray
93
+ ): stdClass {
94
+ // Validate JWT
95
+ $timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp;
96
 
97
+ if (empty($keyOrKeyArray)) {
98
  throw new InvalidArgumentException('Key may not be empty');
99
  }
100
+ $tks = \explode('.', $jwt);
101
+ if (\count($tks) !== 3) {
102
  throw new UnexpectedValueException('Wrong number of segments');
103
  }
104
  list($headb64, $bodyb64, $cryptob64) = $tks;
105
+ $headerRaw = static::urlsafeB64Decode($headb64);
106
+ if (null === ($header = static::jsonDecode($headerRaw))) {
107
  throw new UnexpectedValueException('Invalid header encoding');
108
  }
109
+ $payloadRaw = static::urlsafeB64Decode($bodyb64);
110
+ if (null === ($payload = static::jsonDecode($payloadRaw))) {
111
  throw new UnexpectedValueException('Invalid claims encoding');
112
  }
113
+ if (\is_array($payload)) {
114
+ // prevent PHP Fatal Error in edge-cases when payload is empty array
115
+ $payload = (object) $payload;
116
  }
117
+ if (!$payload instanceof stdClass) {
118
+ throw new UnexpectedValueException('Payload must be a JSON object');
119
+ }
120
+ $sig = static::urlsafeB64Decode($cryptob64);
121
  if (empty($header->alg)) {
122
  throw new UnexpectedValueException('Empty algorithm');
123
  }
124
  if (empty(static::$supported_algs[$header->alg])) {
125
  throw new UnexpectedValueException('Algorithm not supported');
126
  }
127
+
128
+ $key = self::getKey($keyOrKeyArray, property_exists($header, 'kid') ? $header->kid : null);
129
+
130
+ // Check the algorithm
131
+ if (!self::constantTimeEquals($key->getAlgorithm(), $header->alg)) {
132
+ // See issue #351
133
+ throw new UnexpectedValueException('Incorrect key for this algorithm');
134
  }
135
+ if ($header->alg === 'ES256' || $header->alg === 'ES384') {
136
+ // OpenSSL expects an ASN.1 DER sequence for ES256/ES384 signatures
137
+ $sig = self::signatureToDER($sig);
 
 
 
 
 
 
138
  }
139
+ if (!self::verify("${headb64}.${bodyb64}", $sig, $key->getKeyMaterial(), $header->alg)) {
 
 
140
  throw new SignatureInvalidException('Signature verification failed');
141
  }
142
 
143
+ // Check the nbf if it is defined. This is the time that the
144
  // token can actually be used. If it's not yet that time, abort.
145
  if (isset($payload->nbf) && $payload->nbf > ($timestamp + static::$leeway)) {
146
  throw new BeforeValidException(
147
+ 'Cannot handle token prior to ' . \date(DateTime::ISO8601, $payload->nbf)
148
  );
149
  }
150
 
153
  // correctly used the nbf claim).
154
  if (isset($payload->iat) && $payload->iat > ($timestamp + static::$leeway)) {
155
  throw new BeforeValidException(
156
+ 'Cannot handle token prior to ' . \date(DateTime::ISO8601, $payload->iat)
157
  );
158
  }
159
 
168
  /**
169
  * Converts and signs a PHP object or array into a JWT string.
170
  *
171
+ * @param array<mixed> $payload PHP array
172
+ * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
173
+ * @param string $alg Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
174
+ * 'HS512', 'RS256', 'RS384', and 'RS512'
175
+ * @param string $keyId
176
+ * @param array<string, string> $head An array with header elements to attach
 
177
  *
178
  * @return string A signed JWT
179
  *
180
  * @uses jsonEncode
181
  * @uses urlsafeB64Encode
182
  */
183
+ public static function encode(
184
+ array $payload,
185
+ $key,
186
+ string $alg,
187
+ string $keyId = null,
188
+ array $head = null
189
+ ): string {
190
+ $header = ['typ' => 'JWT', 'alg' => $alg];
191
  if ($keyId !== null) {
192
  $header['kid'] = $keyId;
193
  }
194
+ if (isset($head) && \is_array($head)) {
195
+ $header = \array_merge($head, $header);
196
  }
197
+ $segments = [];
198
+ $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($header));
199
+ $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($payload));
200
+ $signing_input = \implode('.', $segments);
201
 
202
  $signature = static::sign($signing_input, $key, $alg);
203
  $segments[] = static::urlsafeB64Encode($signature);
204
 
205
+ return \implode('.', $segments);
206
  }
207
 
208
  /**
209
  * Sign a string with a given key and algorithm.
210
  *
211
+ * @param string $msg The message to sign
212
+ * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
213
+ * @param string $alg Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
214
+ * 'HS512', 'RS256', 'RS384', and 'RS512'
215
  *
216
  * @return string An encrypted message
217
  *
218
+ * @throws DomainException Unsupported algorithm or bad key was specified
219
  */
220
+ public static function sign(
221
+ string $msg,
222
+ $key,
223
+ string $alg
224
+ ): string {
225
  if (empty(static::$supported_algs[$alg])) {
226
  throw new DomainException('Algorithm not supported');
227
  }
228
  list($function, $algorithm) = static::$supported_algs[$alg];
229
+ switch ($function) {
230
  case 'hash_hmac':
231
+ if (!\is_string($key)) {
232
+ throw new InvalidArgumentException('key must be a string when using hmac');
233
+ }
234
+ return \hash_hmac($algorithm, $msg, $key, true);
235
  case 'openssl':
236
  $signature = '';
237
+ $success = \openssl_sign($msg, $signature, $key, $algorithm); // @phpstan-ignore-line
238
  if (!$success) {
239
+ throw new DomainException('OpenSSL unable to sign data');
240
+ }
241
+ if ($alg === 'ES256') {
242
+ $signature = self::signatureFromDER($signature, 256);
243
+ } elseif ($alg === 'ES384') {
244
+ $signature = self::signatureFromDER($signature, 384);
245
+ }
246
+ return $signature;
247
+ case 'sodium_crypto':
248
+ if (!\function_exists('sodium_crypto_sign_detached')) {
249
+ throw new DomainException('libsodium is not available');
250
+ }
251
+ if (!\is_string($key)) {
252
+ throw new InvalidArgumentException('key must be a string when using EdDSA');
253
+ }
254
+ try {
255
+ // The last non-empty line is used as the key.
256
+ $lines = array_filter(explode("\n", $key));
257
+ $key = base64_decode((string) end($lines));
258
+ return sodium_crypto_sign_detached($msg, $key);
259
+ } catch (Exception $e) {
260
+ throw new DomainException($e->getMessage(), 0, $e);
261
  }
262
  }
263
+
264
+ throw new DomainException('Algorithm not supported');
265
  }
266
 
267
  /**
268
  * Verify a signature with the message, key and method. Not all methods
269
  * are symmetric, so we must have a separate verify and sign method.
270
  *
271
+ * @param string $msg The original message (header and body)
272
+ * @param string $signature The original signature
273
+ * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
274
+ * @param string $alg The algorithm
275
  *
276
  * @return bool
277
  *
278
+ * @throws DomainException Invalid Algorithm, bad key, or OpenSSL failure
279
  */
280
+ private static function verify(
281
+ string $msg,
282
+ string $signature,
283
+ $keyMaterial,
284
+ string $alg
285
+ ): bool {
286
  if (empty(static::$supported_algs[$alg])) {
287
  throw new DomainException('Algorithm not supported');
288
  }
289
 
290
  list($function, $algorithm) = static::$supported_algs[$alg];
291
+ switch ($function) {
292
  case 'openssl':
293
+ $success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm); // @phpstan-ignore-line
294
  if ($success === 1) {
295
  return true;
296
+ }
297
+ if ($success === 0) {
298
  return false;
299
  }
300
  // returns 1 on success, 0 on failure, -1 on error.
301
  throw new DomainException(
302
+ 'OpenSSL error: ' . \openssl_error_string()
303
  );
304
+ case 'sodium_crypto':
305
+ if (!\function_exists('sodium_crypto_sign_verify_detached')) {
306
+ throw new DomainException('libsodium is not available');
307
+ }
308
+ if (!\is_string($keyMaterial)) {
309
+ throw new InvalidArgumentException('key must be a string when using EdDSA');
310
+ }
311
+ try {
312
+ // The last non-empty line is used as the key.
313
+ $lines = array_filter(explode("\n", $keyMaterial));
314
+ $key = base64_decode((string) end($lines));
315
+ return sodium_crypto_sign_verify_detached($signature, $msg, $key);
316
+ } catch (Exception $e) {
317
+ throw new DomainException($e->getMessage(), 0, $e);
318
+ }
319
  case 'hash_hmac':
320
  default:
321
+ if (!\is_string($keyMaterial)) {
322
+ throw new InvalidArgumentException('key must be a string when using hmac');
 
 
 
 
 
 
 
323
  }
324
+ $hash = \hash_hmac($algorithm, $msg, $keyMaterial, true);
325
+ return self::constantTimeEquals($hash, $signature);
 
326
  }
327
  }
328
 
331
  *
332
  * @param string $input JSON string
333
  *
334
+ * @return mixed The decoded JSON string
335
  *
336
  * @throws DomainException Provided string was invalid JSON
337
  */
338
+ public static function jsonDecode(string $input)
339
  {
340
+ $obj = \json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
+ if ($errno = \json_last_error()) {
343
+ self::handleJsonError($errno);
344
  } elseif ($obj === null && $input !== 'null') {
345
  throw new DomainException('Null result with non-null input');
346
  }
348
  }
349
 
350
  /**
351
+ * Encode a PHP array into a JSON string.
352
  *
353
+ * @param array<mixed> $input A PHP array
354
  *
355
+ * @return string JSON representation of the PHP array
356
  *
357
  * @throws DomainException Provided object could not be encoded to valid JSON
358
  */
359
+ public static function jsonEncode(array $input): string
360
  {
361
+ if (PHP_VERSION_ID >= 50400) {
362
+ $json = \json_encode($input, \JSON_UNESCAPED_SLASHES);
363
+ } else {
364
+ // PHP 5.3 only
365
+ $json = \json_encode($input);
366
+ }
367
+ if ($errno = \json_last_error()) {
368
+ self::handleJsonError($errno);
369
  } elseif ($json === 'null' && $input !== null) {
370
  throw new DomainException('Null result with non-null input');
371
  }
372
+ if ($json === false) {
373
+ throw new DomainException('Provided object could not be encoded to valid JSON');
374
+ }
375
  return $json;
376
  }
377
 
381
  * @param string $input A Base64 encoded string
382
  *
383
  * @return string A decoded string
384
+ *
385
+ * @throws InvalidArgumentException invalid base64 characters
386
  */
387
+ public static function urlsafeB64Decode(string $input): string
388
  {
389
+ $remainder = \strlen($input) % 4;
390
  if ($remainder) {
391
  $padlen = 4 - $remainder;
392
+ $input .= \str_repeat('=', $padlen);
393
  }
394
+ return \base64_decode(\strtr($input, '-_', '+/'));
395
  }
396
 
397
  /**
401
  *
402
  * @return string The base64 encode of what you passed in
403
  */
404
+ public static function urlsafeB64Encode(string $input): string
405
  {
406
+ return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
407
+ }
408
+
409
+
410
+ /**
411
+ * Determine if an algorithm has been provided for each Key
412
+ *
413
+ * @param Key|ArrayAccess<string,Key>|array<string,Key> $keyOrKeyArray
414
+ * @param string|null $kid
415
+ *
416
+ * @throws UnexpectedValueException
417
+ *
418
+ * @return Key
419
+ */
420
+ private static function getKey(
421
+ $keyOrKeyArray,
422
+ ?string $kid
423
+ ): Key {
424
+ if ($keyOrKeyArray instanceof Key) {
425
+ return $keyOrKeyArray;
426
+ }
427
+
428
+ if ($keyOrKeyArray instanceof CachedKeySet) {
429
+ // Skip "isset" check, as this will automatically refresh if not set
430
+ return $keyOrKeyArray[$kid];
431
+ }
432
+
433
+ if (empty($kid)) {
434
+ throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
435
+ }
436
+ if (!isset($keyOrKeyArray[$kid])) {
437
+ throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
438
+ }
439
+
440
+ return $keyOrKeyArray[$kid];
441
+ }
442
+
443
+ /**
444
+ * @param string $left The string of known length to compare against
445
+ * @param string $right The user-supplied string
446
+ * @return bool
447
+ */
448
+ public static function constantTimeEquals(string $left, string $right): bool
449
+ {
450
+ if (\function_exists('hash_equals')) {
451
+ return \hash_equals($left, $right);
452
+ }
453
+ $len = \min(self::safeStrlen($left), self::safeStrlen($right));
454
+
455
+ $status = 0;
456
+ for ($i = 0; $i < $len; $i++) {
457
+ $status |= (\ord($left[$i]) ^ \ord($right[$i]));
458
+ }
459
+ $status |= (self::safeStrlen($left) ^ self::safeStrlen($right));
460
+
461
+ return ($status === 0);
462
  }
463
 
464
  /**
466
  *
467
  * @param int $errno An error number from json_last_error()
468
  *
469
+ * @throws DomainException
470
+ *
471
  * @return void
472
  */
473
+ private static function handleJsonError(int $errno): void
474
  {
475
+ $messages = [
476
  JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
477
  JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
478
  JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
479
  JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
480
  JSON_ERROR_UTF8 => 'Malformed UTF-8 characters' //PHP >= 5.3.3
481
+ ];
482
  throw new DomainException(
483
  isset($messages[$errno])
484
  ? $messages[$errno]
489
  /**
490
  * Get the number of bytes in cryptographic strings.
491
  *
492
+ * @param string $str
493
  *
494
  * @return int
495
  */
496
+ private static function safeStrlen(string $str): int
497
+ {
498
+ if (\function_exists('mb_strlen')) {
499
+ return \mb_strlen($str, '8bit');
500
+ }
501
+ return \strlen($str);
502
+ }
503
+
504
+ /**
505
+ * Convert an ECDSA signature to an ASN.1 DER sequence
506
+ *
507
+ * @param string $sig The ECDSA signature to convert
508
+ * @return string The encoded DER object
509
+ */
510
+ private static function signatureToDER(string $sig): string
511
+ {
512
+ // Separate the signature into r-value and s-value
513
+ $length = max(1, (int) (\strlen($sig) / 2));
514
+ list($r, $s) = \str_split($sig, $length);
515
+
516
+ // Trim leading zeros
517
+ $r = \ltrim($r, "\x00");
518
+ $s = \ltrim($s, "\x00");
519
+
520
+ // Convert r-value and s-value from unsigned big-endian integers to
521
+ // signed two's complement
522
+ if (\ord($r[0]) > 0x7f) {
523
+ $r = "\x00" . $r;
524
+ }
525
+ if (\ord($s[0]) > 0x7f) {
526
+ $s = "\x00" . $s;
527
+ }
528
+
529
+ return self::encodeDER(
530
+ self::ASN1_SEQUENCE,
531
+ self::encodeDER(self::ASN1_INTEGER, $r) .
532
+ self::encodeDER(self::ASN1_INTEGER, $s)
533
+ );
534
+ }
535
+
536
+ /**
537
+ * Encodes a value into a DER object.
538
+ *
539
+ * @param int $type DER tag
540
+ * @param string $value the value to encode
541
+ *
542
+ * @return string the encoded object
543
+ */
544
+ private static function encodeDER(int $type, string $value): string
545
  {
546
+ $tag_header = 0;
547
+ if ($type === self::ASN1_SEQUENCE) {
548
+ $tag_header |= 0x20;
549
  }
550
+
551
+ // Type
552
+ $der = \chr($tag_header | $type);
553
+
554
+ // Length
555
+ $der .= \chr(\strlen($value));
556
+
557
+ return $der . $value;
558
+ }
559
+
560
+ /**
561
+ * Encodes signature from a DER object.
562
+ *
563
+ * @param string $der binary signature in DER format
564
+ * @param int $keySize the number of bits in the key
565
+ *
566
+ * @return string the signature
567
+ */
568
+ private static function signatureFromDER(string $der, int $keySize): string
569
+ {
570
+ // OpenSSL returns the ECDSA signatures as a binary ASN.1 DER SEQUENCE
571
+ list($offset, $_) = self::readDER($der);
572
+ list($offset, $r) = self::readDER($der, $offset);
573
+ list($offset, $s) = self::readDER($der, $offset);
574
+
575
+ // Convert r-value and s-value from signed two's compliment to unsigned
576
+ // big-endian integers
577
+ $r = \ltrim($r, "\x00");
578
+ $s = \ltrim($s, "\x00");
579
+
580
+ // Pad out r and s so that they are $keySize bits long
581
+ $r = \str_pad($r, $keySize / 8, "\x00", STR_PAD_LEFT);
582
+ $s = \str_pad($s, $keySize / 8, "\x00", STR_PAD_LEFT);
583
+
584
+ return $r . $s;
585
+ }
586
+
587
+ /**
588
+ * Reads binary DER-encoded data and decodes into a single object
589
+ *
590
+ * @param string $der the binary data in DER format
591
+ * @param int $offset the offset of the data stream containing the object
592
+ * to decode
593
+ *
594
+ * @return array{int, string|null} the new offset and the decoded object
595
+ */
596
+ private static function readDER(string $der, int $offset = 0): array
597
+ {
598
+ $pos = $offset;
599
+ $size = \strlen($der);
600
+ $constructed = (\ord($der[$pos]) >> 5) & 0x01;
601
+ $type = \ord($der[$pos++]) & 0x1f;
602
+
603
+ // Length
604
+ $len = \ord($der[$pos++]);
605
+ if ($len & 0x80) {
606
+ $n = $len & 0x1f;
607
+ $len = 0;
608
+ while ($n-- && $pos < $size) {
609
+ $len = ($len << 8) | \ord($der[$pos++]);
610
+ }
611
+ }
612
+
613
+ // Value
614
+ if ($type === self::ASN1_BIT_STRING) {
615
+ $pos++; // Skip the first contents octet (padding indicator)
616
+ $data = \substr($der, $pos, $len - 1);
617
+ $pos += $len - 1;
618
+ } elseif (!$constructed) {
619
+ $data = \substr($der, $pos, $len);
620
+ $pos += $len;
621
+ } else {
622
+ $data = null;
623
+ }
624
+
625
+ return [$pos, $data];
626
  }
627
  }
common/vendor/firebase/php-jwt/src/Key.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Firebase\JWT;
4
+
5
+ use InvalidArgumentException;
6
+ use OpenSSLAsymmetricKey;
7
+ use OpenSSLCertificate;
8
+ use TypeError;
9
+
10
+ class Key
11
+ {
12
+ /** @var string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate */
13
+ private $keyMaterial;
14
+ /** @var string */
15
+ private $algorithm;
16
+
17
+ /**
18
+ * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
19
+ * @param string $algorithm
20
+ */
21
+ public function __construct(
22
+ $keyMaterial,
23
+ string $algorithm
24
+ ) {
25
+ if (
26
+ !\is_string($keyMaterial)
27
+ && !$keyMaterial instanceof OpenSSLAsymmetricKey
28
+ && !$keyMaterial instanceof OpenSSLCertificate
29
+ && !\is_resource($keyMaterial)
30
+ ) {
31
+ throw new TypeError('Key material must be a string, resource, or OpenSSLAsymmetricKey');
32
+ }
33
+
34
+ if (empty($keyMaterial)) {
35
+ throw new InvalidArgumentException('Key material must not be empty');
36
+ }
37
+
38
+ if (empty($algorithm)) {
39
+ throw new InvalidArgumentException('Algorithm must not be empty');
40
+ }
41
+
42
+ // TODO: Remove in PHP 8.0 in favor of class constructor property promotion
43
+ $this->keyMaterial = $keyMaterial;
44
+ $this->algorithm = $algorithm;
45
+ }
46
+
47
+ /**
48
+ * Return the algorithm valid for this key
49
+ *
50
+ * @return string
51
+ */
52
+ public function getAlgorithm(): string
53
+ {
54
+ return $this->algorithm;
55
+ }
56
+
57
+ /**
58
+ * @return string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate
59
+ */
60
+ public function getKeyMaterial()
61
+ {
62
+ return $this->keyMaterial;
63
+ }
64
+ }
common/vendor/firebase/php-jwt/src/SignatureInvalidException.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
 
2
  namespace Firebase\JWT;
3
 
4
  class SignatureInvalidException extends \UnexpectedValueException
5
  {
6
-
7
  }
1
  <?php
2
+
3
  namespace Firebase\JWT;
4
 
5
  class SignatureInvalidException extends \UnexpectedValueException
6
  {
 
7
  }
event-tickets.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Event Tickets
4
  Plugin URI: https://evnt.is/1acb
5
  Description: Event Tickets allows you to sell basic tickets and collect RSVPs from any post, page, or event.
6
- Version: 5.5.1
7
  Author: The Events Calendar
8
  Author URI: https://evnt.is/1aor
9
  License: GPLv2 or later
3
  Plugin Name: Event Tickets
4
  Plugin URI: https://evnt.is/1acb
5
  Description: Event Tickets allows you to sell basic tickets and collect RSVPs from any post, page, or event.
6
+ Version: 5.5.2
7
  Author: The Events Calendar
8
  Author URI: https://evnt.is/1aor
9
  License: GPLv2 or later
lang/event-tickets-de_DE.mo CHANGED
Binary file
lang/event-tickets-es_ES.mo CHANGED
Binary file
lang/event-tickets-nl_NL.mo CHANGED
Binary file
lang/event-tickets-ro_RO.mo CHANGED
Binary file
readme.txt CHANGED
@@ -2,9 +2,9 @@
2
 
3
  Contributors: theeventscalendar, brianjessee, camwynsp, aguseo, bordoni, borkweb, GeoffBel, jentheo, leahkoerper, lucatume, neillmcshea, vicskf, zbtirrell, juanfra, moraleida.me
4
  Tags: tickets, registration, event registration, RSVP, ticket sales, attendee management
5
- Requires at least: 5.8.4
6
- Tested up to: 6.0.2
7
- Stable tag: 5.5.1
8
  Requires PHP: 7.3
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -188,6 +188,10 @@ Check out our extensive [knowledgebase](https://evnt.is/18wm) for articles on us
188
 
189
  == Changelog ==
190
 
 
 
 
 
191
  = [5.5.1] 2022-09-22 =
192
 
193
  * Fix - Listing tickets is no longer limited by the global settings. [ET-1584]
2
 
3
  Contributors: theeventscalendar, brianjessee, camwynsp, aguseo, bordoni, borkweb, GeoffBel, jentheo, leahkoerper, lucatume, neillmcshea, vicskf, zbtirrell, juanfra, moraleida.me
4
  Tags: tickets, registration, event registration, RSVP, ticket sales, attendee management
5
+ Requires at least: 5.8.5
6
+ Tested up to: 6.0.3
7
+ Stable tag: 5.5.2
8
  Requires PHP: 7.3
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
188
 
189
  == Changelog ==
190
 
191
+ = [5.5.2] 2022-10-20 =
192
+
193
+ * Fix - Update version of Firebase/JWT in Common from 5.x to 6.3.0
194
+
195
  = [5.5.1] 2022-09-22 =
196
 
197
  * Fix - Listing tickets is no longer limited by the global settings. [ET-1584]
src/Tribe/Main.php CHANGED
@@ -8,7 +8,7 @@ class Tribe__Tickets__Main {
8
  /**
9
  * Current version of this plugin
10
  */
11
- const VERSION = '5.5.1';
12
 
13
  /**
14
  * Used to store the version history.
@@ -43,7 +43,7 @@ class Tribe__Tickets__Main {
43
  *
44
  * @since 4.10
45
  */
46
- protected $min_tec_version = '6.0.0-dev';
47
 
48
  /**
49
  * Name of the provider
8
  /**
9
  * Current version of this plugin
10
  */
11
+ const VERSION = '5.5.2';
12
 
13
  /**
14
  * Used to store the version history.
43
  *
44
  * @since 4.10
45
  */
46
+ protected $min_tec_version = '6.0.2-dev';
47
 
48
  /**
49
  * Name of the provider
src/Tribe/Promoter/Triggers/Dispatcher.php CHANGED
@@ -75,7 +75,7 @@ class Dispatcher {
75
 
76
  $args = [
77
  'body' => [
78
- 'token' => JWT::encode( $this->get_payload( $trigger ), $this->secret ),
79
  ],
80
  'sslverify' => false,
81
  'timeout' => 30,
75
 
76
  $args = [
77
  'body' => [
78
+ 'token' => JWT::encode( $this->get_payload( $trigger ), $this->secret, 'HS256' ),
79
  ],
80
  'sslverify' => false,
81
  'timeout' => 30,
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit3d3c0ab6e205f0d5423c3fbf5d9784d1::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInitfeb5d36e4a1fabfe35197a0cc78305ee::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit3d3c0ab6e205f0d5423c3fbf5d9784d1
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit3d3c0ab6e205f0d5423c3fbf5d9784d1
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit3d3c0ab6e205f0d5423c3fbf5d9784d1', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit3d3c0ab6e205f0d5423c3fbf5d9784d1', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInit3d3c0ab6e205f0d5423c3fbf5d9784d1::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInitfeb5d36e4a1fabfe35197a0cc78305ee
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInitfeb5d36e4a1fabfe35197a0cc78305ee', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInitfeb5d36e4a1fabfe35197a0cc78305ee', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInitfeb5d36e4a1fabfe35197a0cc78305ee::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit3d3c0ab6e205f0d5423c3fbf5d9784d1
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'T' =>
@@ -213,9 +213,9 @@ class ComposerStaticInit3d3c0ab6e205f0d5423c3fbf5d9784d1
213
  public static function getInitializer(ClassLoader $loader)
214
  {
215
  return \Closure::bind(function () use ($loader) {
216
- $loader->prefixLengthsPsr4 = ComposerStaticInit3d3c0ab6e205f0d5423c3fbf5d9784d1::$prefixLengthsPsr4;
217
- $loader->prefixDirsPsr4 = ComposerStaticInit3d3c0ab6e205f0d5423c3fbf5d9784d1::$prefixDirsPsr4;
218
- $loader->classMap = ComposerStaticInit3d3c0ab6e205f0d5423c3fbf5d9784d1::$classMap;
219
 
220
  }, null, ClassLoader::class);
221
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInitfeb5d36e4a1fabfe35197a0cc78305ee
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'T' =>
213
  public static function getInitializer(ClassLoader $loader)
214
  {
215
  return \Closure::bind(function () use ($loader) {
216
+ $loader->prefixLengthsPsr4 = ComposerStaticInitfeb5d36e4a1fabfe35197a0cc78305ee::$prefixLengthsPsr4;
217
+ $loader->prefixDirsPsr4 = ComposerStaticInitfeb5d36e4a1fabfe35197a0cc78305ee::$prefixDirsPsr4;
218
+ $loader->classMap = ComposerStaticInitfeb5d36e4a1fabfe35197a0cc78305ee::$classMap;
219
 
220
  }, null, ClassLoader::class);
221
  }