%1$s installed, and %2$s activated', $plugins_count, $count_active ); ?>
- -| - | - | - | - | - |
|---|---|---|---|---|
| %s | %s | %s | %s | %s |
plugin.php.' ); ?>
- - - -Plugin list.' ); ?>
-From 05f16d2b0aed27f0d7609d50f72e7da10f133fc0 Mon Sep 17 00:00:00 2001
From: Chris Gilligan <49878588+UTCGilligan@users.noreply.github.com>
Date: Thu, 8 Jan 2026 09:09:32 -0500
Subject: [PATCH 1/5] UTCT-248: Better backend admin version message; Sleeky
2.6.0.
Signed-off-by: Chris Gilligan <49878588+UTCGilligan@users.noreply.github.com>
---
frontend/package.json | 2 +-
user/plugins/sleeky-backend/assets/js/theme.js | 4 +---
user/plugins/sleeky-backend/plugin.php | 10 +++++-----
3 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/frontend/package.json b/frontend/package.json
index 8760a39..72af22b 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
{
"name": "sleeky-frontend",
- "version": "2.5.0",
+ "version": "2.6.0",
"description": "",
"main": "index.js",
"scripts": {
diff --git a/user/plugins/sleeky-backend/assets/js/theme.js b/user/plugins/sleeky-backend/assets/js/theme.js
index d4b8c78..a067a91 100644
--- a/user/plugins/sleeky-backend/assets/js/theme.js
+++ b/user/plugins/sleeky-backend/assets/js/theme.js
@@ -136,9 +136,7 @@ $( document ).ready(function() {
} else if (/Powered by/.test($(this).text())) {
// Update footer
var content = $(this).html();
- var i = 77
- var updated_content = "Running on" + content.slice(13, i) + ' & Sleeky' + content.slice(i-0)
- $(this).html(updated_content);
+ var updated_content = `${content.replace(/Powered by.*?(?=<|$)/i, '')} %1$s to %2$s of %3$s URLs' ), $display_on_page, $max_on_page, $total_items );
- if( $total_items_clicks !== false )
- echo ", " . sprintf( yourls_n( 'counting 1 click', 'counting %s clicks', $total_items_clicks ), yourls_number_format_i18n( $total_items_clicks ) );
- }
- ?>. %1$s to %2$s of %3$s URLs' ), $display_on_page, $max_on_page, $total_items );
+ if( $total_items_clicks !== false )
+ echo ", " . sprintf( yourls_n( 'counting 1 click', 'counting %s clicks', $total_items_clicks ), yourls_number_format_i18n( $total_items_clicks ) );
+ }
+ ?>. %1$s links, %2$s clicks, and counting!' ), yourls_number_format_i18n( $total_urls ), yourls_number_format_i18n( $total_clicks ) ); ?> %1$s installed, and %2$s activated', $plugins_count, $count_active ); ?> plugin.php.' ); ?> Plugin list.' ); ?> %1$s installed, and %2$s activated', $plugins_count, $count_active ); ?> plugin.php.' ); ?> Plugin list.' ); ?> bookmarklets for easier link shortening and sharing.' ); ?> bookmarklets for easier link shortening and sharing.' ); ?> select text on the page you're viewing before clicking on your bookmarklet link" );
- ?> select text on the page you're viewing before clicking on your bookmarklet link" );
+ ?> Important Note: bookmarklets may fail on websites with https, especially the "Instant" bookrmarklets. There is nothing you can do about this.'); ?>
-
+
-
+
-
Sleeky v 2.6.0`; $(this).html(updated_content);
}
});
});
diff --git a/user/plugins/sleeky-backend/plugin.php b/user/plugins/sleeky-backend/plugin.php
index 1470ebb..93b2d31 100755
--- a/user/plugins/sleeky-backend/plugin.php
+++ b/user/plugins/sleeky-backend/plugin.php
@@ -3,7 +3,7 @@
Plugin Name: Sleeky Backend
Plugin URI: https://sleeky.flynntes.com
Description: UI overhaul of the YOURLS backend
-Version: 2.4.1
+Version: 2.6.0
Author: Flynn Tesoriero
Author URI: https://flynntes.com
*/
@@ -92,14 +92,14 @@ function sleeky_do_settings_page() {
if( isset( $_POST['theme_choice'] ) ) {
// Check nonce
yourls_verify_nonce( 'sleeky_settings' );
-
+
// Process form
sleeky_settings_update();
}
// Get value from database
$theme_choice = yourls_get_option( 'theme_choice' );
-
+
// Create nonce
$nonce = yourls_create_nonce( 'sleeky_settings' );
@@ -124,7 +124,7 @@ function sleeky_do_settings_page() {
// Update option in database
function sleeky_settings_update() {
$in = $_POST['theme_choice'];
-
+
if( $in ) {
// Validate theme_choice. ALWAYS validate and sanitize user input.
// Here, we want an integer
@@ -135,7 +135,7 @@ function sleeky_settings_update() {
} else {
echo "Error";
}
-
+
}
}
From cb4c305d99c791245b5fc76a42378f2e2e29722d Mon Sep 17 00:00:00 2001
From: Chris Gilligan <49878588+UTCGilligan@users.noreply.github.com>
Date: Tue, 13 Jan 2026 17:10:04 -0500
Subject: [PATCH 2/5] UTCT-250: YOURLS 1.10.3 upgrade.
Signed-off-by: Chris Gilligan <49878588+UTCGilligan@users.noreply.github.com>
---
admin/admin-ajax.php | 54 +-
admin/index.php | 361 +++---
admin/install.php | 94 +-
admin/plugins.php | 264 ++---
admin/tools.php | 146 +--
admin/upgrade.php | 104 +-
composer.json | 33 +-
composer.lock | 529 ++-------
css/style.css | 98 +-
includes/Database/Options.php | 2 +-
includes/Database/YDB.php | 40 +-
includes/Views/AdminParams.php | 11 +-
includes/auth.php | 42 +-
includes/class-mysql.php | 57 +-
includes/functions-api.php | 168 +--
includes/functions-auth.php | 514 ++++-----
includes/functions-compat.php | 122 +--
includes/functions-debug.php | 17 +-
includes/functions-deprecated.php | 103 +-
includes/functions-formatting.php | 505 +++++----
includes/functions-html.php | 1326 ++++++++++++-----------
includes/functions-http.php | 290 +++--
includes/functions-infos.php | 480 ++++----
includes/functions-install.php | 395 +++----
includes/functions-kses.php | 1044 +++++++++---------
includes/functions-l10n.php | 1064 +++++++++---------
includes/functions-options.php | 10 +-
includes/functions-plugins.php | 34 +-
includes/functions-shorturls.php | 51 +-
includes/functions-upgrade.php | 489 +++++----
includes/functions.php | 580 +++++-----
includes/geo/COPYRIGHT.txt | 2 +-
includes/geo/GeoLite2-Country.mmdb | Bin 9751408 -> 9651078 bytes
includes/version.php | 4 +-
js/common.js | 6 +-
js/insert.js | 88 +-
user/config-sample.php | 45 +-
user/pages/examplepage.php | 4 +-
user/plugins/hyphens-in-urls/plugin.php | 2 +-
user/plugins/index.html | 4 +-
user/plugins/random-bg/plugin.php | 12 +-
user/plugins/sample-page/plugin.php | 58 +-
user/plugins/sample-plugin/plugin.php | 6 +-
user/plugins/sample-toolbar/plugin.php | 104 +-
yourls-api.php | 28 +-
yourls-go.php | 4 +-
yourls-infos.php | 967 +++++++++--------
yourls-loader.php | 18 +-
48 files changed, 5157 insertions(+), 5222 deletions(-)
diff --git a/admin/admin-ajax.php b/admin/admin-ajax.php
index 88de236..edfa16a 100644
--- a/admin/admin-ajax.php
+++ b/admin/admin-ajax.php
@@ -10,38 +10,38 @@
yourls_no_frame_header();
if( !isset( $_REQUEST['action'] ) )
- die();
+ die();
// Pick action
$action = $_REQUEST['action'];
switch( $action ) {
- case 'add':
- yourls_verify_nonce( 'add_url', $_REQUEST['nonce'], false, 'omg error' );
- $return = yourls_add_new_link( $_REQUEST['url'], $_REQUEST['keyword'], '', $_REQUEST['rowid'] );
- echo json_encode($return);
- break;
-
- case 'edit_display':
- yourls_verify_nonce( 'edit-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' );
- $row = yourls_table_edit_row ( $_REQUEST['keyword'], $_REQUEST['id'] );
- echo json_encode( array('html' => $row) );
- break;
-
- case 'edit_save':
- yourls_verify_nonce( 'edit-save_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' );
- $return = yourls_edit_link( $_REQUEST['url'], $_REQUEST['keyword'], $_REQUEST['newkeyword'], $_REQUEST['title'] );
- echo json_encode($return);
- break;
-
- case 'delete':
- yourls_verify_nonce( 'delete-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' );
- $query = yourls_delete_link_by_keyword( $_REQUEST['keyword'] );
- echo json_encode(array('success'=>$query));
- break;
-
- default:
- yourls_do_action( 'yourls_ajax_'.$action );
+ case 'add':
+ yourls_verify_nonce( 'add_url', $_REQUEST['nonce'], false, 'omg error' );
+ $return = yourls_add_new_link( $_REQUEST['url'], $_REQUEST['keyword'], '', $_REQUEST['rowid'] );
+ echo json_encode($return);
+ break;
+
+ case 'edit_display':
+ yourls_verify_nonce( 'edit-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' );
+ $row = yourls_table_edit_row ( $_REQUEST['keyword'], $_REQUEST['id'] );
+ echo json_encode( array('html' => $row) );
+ break;
+
+ case 'edit_save':
+ yourls_verify_nonce( 'edit-save_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' );
+ $return = yourls_edit_link( $_REQUEST['url'], $_REQUEST['keyword'], $_REQUEST['newkeyword'], $_REQUEST['title'] );
+ echo json_encode($return);
+ break;
+
+ case 'delete':
+ yourls_verify_nonce( 'delete-link_'.$_REQUEST['id'], $_REQUEST['nonce'], false, 'omg error' );
+ $query = yourls_delete_link_by_keyword( $_REQUEST['keyword'] );
+ echo json_encode(array('success'=>$query));
+ break;
+
+ default:
+ yourls_do_action( 'yourls_ajax_'.$action );
}
diff --git a/admin/index.php b/admin/index.php
index da52bca..1e60a56 100644
--- a/admin/index.php
+++ b/admin/index.php
@@ -30,17 +30,20 @@
$search_in = $view_params->get_search_in();
$search_in_text = $view_params->get_param_long_name($search_in);
if( $search && $search_in && $search_in_text ) {
- $search_sentence = yourls_s( 'Searching for %1$s in %2$s.', yourls_esc_html( $search ), yourls_esc_html( $search_in_text ) );
- $search_text = $search;
- $search = str_replace( '*', '%', '*' . $search . '*' );
+ $search_sentence = yourls_s( 'Searching for %1$s in %2$s.', yourls_esc_html( $search ), yourls_esc_html( $search_in_text ) );
+ $search_text = $search;
+ $search = str_replace( '*', '%', '*' . $search . '*' );
if( $search_in == 'all' ) {
- $where['sql'] .= " AND CONCAT_WS('',`keyword`,`url`,`title`,`ip`) LIKE (:search)";
- // Search across all fields. The resulting SQL will be something like:
- // SELECT * FROM `yourls_url` WHERE CONCAT_WS('',`keyword`,`url`,`title`,`ip`) LIKE ("%ozh%")
- // CONCAT_WS because CONCAT('foo', 'bar', NULL) = NULL. NULL wins. Not sure if values can be NULL now or in the future, so better safe.
- // TODO: pay attention to this bit when the DB schema changes
+ $where['sql'] .= " AND `keyword` LIKE (:search)
+ OR `url` LIKE (:search)
+ OR `title` COLLATE utf8mb4_unicode_ci LIKE (:search) COLLATE utf8mb4_unicode_ci
+ OR `ip` LIKE (:search) ";
} else {
- $where['sql'] .= " AND `$search_in` LIKE (:search)";
+ $collate = '';
+ if( $search_in == 'title' ) {
+ $collate = ' COLLATE utf8mb4_unicode_ci';
+ }
+ $where['sql'] .= " AND `$search_in` $collate LIKE (:search) $collate";
}
$where['binds']['search'] = $search;
}
@@ -96,139 +99,139 @@
// Get URLs Count for current filter, total links in DB & total clicks
list( $total_urls, $total_clicks ) = array_values( yourls_get_db_stats() );
if ( !empty($where['sql']) ) {
- list( $total_items, $total_items_clicks ) = array_values( yourls_get_db_stats( $where ) );
+ list( $total_items, $total_items_clicks ) = array_values( yourls_get_db_stats( $where ) );
} else {
- $total_items = $total_urls;
- $total_items_clicks = false;
+ $total_items = $total_urls;
+ $total_items_clicks = false;
}
// This is a bookmarklet
if ( isset( $_GET['u'] ) or isset( $_GET['up'] ) ) {
- $is_bookmark = true;
- yourls_do_action( 'bookmarklet' );
-
- // No sanitization needed here: everything happens in yourls_add_new_link()
- if( isset( $_GET['u'] ) ) {
- // Old school bookmarklet: ?u=
-
-
-
-
-
-
-
-
-
- $plugin ) {
-
- // default fields to read from the plugin header
- $fields = array(
- 'name' => 'Plugin Name',
- 'uri' => 'Plugin URI',
- 'desc' => 'Description',
- 'version' => 'Version',
- 'author' => 'Author',
- 'author_uri' => 'Author URI'
- );
-
- // Loop through all default fields, get value if any and reset it
- foreach( $fields as $field=>$value ) {
- if( isset( $plugin[ $value ] ) ) {
- $data[ $field ] = $plugin[ $value ];
- } else {
- $data[ $field ] = yourls__('(no info)');
- }
- unset( $plugin[$value] );
- }
-
- $plugindir = trim( dirname( $file ), '/' );
-
- if( yourls_is_active_plugin( $file ) ) {
- $class = 'active';
- $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'deactivate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) );
- $action_anchor = yourls__( 'Deactivate' );
- } else {
- $class = 'inactive';
- $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'activate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) );
- $action_anchor = yourls__( 'Activate' );
- }
-
- // Other "Fields: Value" in the header? Get them too
- if( $plugin ) {
- foreach( $plugin as $extra_field=>$extra_value ) {
- $data['desc'] .= "
-
-
-
-
-
\n$extra_field: $extra_value";
- unset( $plugin[$extra_value] );
- }
- }
-
- $data['desc'] .= '
' . yourls_s( 'plugin file location: %s', $file) . '';
-
- printf( " ",
- $class, $data['uri'], $data['name'], $data['version'], $data['desc'], $data['author_uri'], $data['author'], $action_url, $action_anchor
- );
-
- }
- ?>
-
- %s %s %s %s %s
+
+
+
+
+
+
+
+
+
+ $plugin ) {
+
+ // default fields to read from the plugin header
+ $fields = array(
+ 'name' => 'Plugin Name',
+ 'uri' => 'Plugin URI',
+ 'desc' => 'Description',
+ 'version' => 'Version',
+ 'author' => 'Author',
+ 'author_uri' => 'Author URI'
+ );
+
+ // Loop through all default fields, get value if any and reset it
+ foreach( $fields as $field=>$value ) {
+ if( isset( $plugin[ $value ] ) ) {
+ $data[ $field ] = $plugin[ $value ];
+ } else {
+ $data[ $field ] = yourls__('(no info)');
+ # If it's a URL, set to #
+ if( in_array( $field, array('uri', 'author_uri') ) ) {
+ $data[$field] = '#' . $data[$field];
+ }
+ }
+ unset( $plugin[$value] );
+ }
+
+ $plugindir = trim( dirname( $file ), '/' );
+
+ if( yourls_is_active_plugin( $file ) ) {
+ $class = 'active';
+ $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'deactivate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) );
+ $action_anchor = yourls__( 'Deactivate' );
+ } else {
+ $class = 'inactive';
+ $action_url = yourls_nonce_url( 'manage_plugins', yourls_add_query_arg( array('action' => 'activate', 'plugin' => $plugindir ), yourls_admin_url('plugins.php') ) );
+ $action_anchor = yourls__( 'Activate' );
+ }
+
+ // Other "Fields: Value" in the header? Get them too
+ if( $plugin ) {
+ foreach( $plugin as $extra_field=>$extra_value ) {
+ $data['desc'] .= "
+
+
+
+
+
\n$extra_field: $extra_value";
+ unset( $plugin[$extra_value] );
+ }
+ }
+
+ $data['desc'] .= '
' . yourls_s( 'plugin file location: %s', $file) . '';
+
+ printf( " ",
+ $class, $data['uri'], $data['name'], $data['version'], $data['desc'], $data['author_uri'], $data['author'], $action_url, $action_anchor
+ );
+
+ }
+ ?>
+
+ %s %s %s %s %s
-
-
+
+
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
+
+
-
+
+
-
+
-
+
+
-
-
-
+
-
%s\" to the beginning of the current URL (right before its 'http://' part) and hit enter.", preg_replace('@https?://@', '', yourls_get_yourls_site()) . '/' ); ?>
+%s\" to the beginning of the current URL (right before its 'http://' part) and hit enter.", preg_replace('@https?://@', '', yourls_get_yourls_site()) . '/' ); ?>
-.
+.
- + - + -username and password parameters.' ); - echo "\n"; - yourls_e( "If you're worried about sending your credentials into the wild, you can also make API calls without using your login or your password, using a secret signature token." ); - ?>
+username and password parameters.' ); + echo "\n"; + yourls_e( "If you're worried about sending your credentials into the wild, you can also make API calls without using your login or your password, using a secret signature token." ); + ?>
-%s', yourls_auth_signature() ); ?>
+
%s', yourls_auth_signature() ); ?>
signature in your API requests. Example:' ); ?>
-/yourls-api.php?signature=&action=...
signature in your API requests. Example:' ); ?>
+/yourls-api.php?signature=&action=...
<?php
$timestamp = time();
// $time =
@@ -322,19 +322,19 @@
// $signature = ""
?>
- signature and timestamp in your API requests. Example:' ); ?>
-/yourls-api.php?timestamp=$timestamp&signature=$signature&action=...
- /yourls-api.php?timestamp=&signature=&action=...
signature and timestamp in your API requests. Example:' ); ?>
+/yourls-api.php?timestamp=$timestamp&signature=$signature&action=...
+ /yourls-api.php?timestamp=&signature=&action=...
Passwordless API page on the wiki.', 'https://yourls.org/passwordlessapi' ); ?> - API documentation for more', yourls_get_yourls_site() . '/readme.html#API' ); ?>
+Passwordless API page on the wiki.', 'https://yourls.org/passwordlessapi' ); ?> + API documentation for more', yourls_get_yourls_site() . '/readme.html#API' ); ?>
- + - + diff --git a/admin/upgrade.php b/admin/upgrade.php index 536a9f8..957870c 100644 --- a/admin/upgrade.php +++ b/admin/upgrade.php @@ -8,73 +8,73 @@ yourls_html_logo(); yourls_html_menu(); ?> - + ' . yourls_s( 'Upgrade not required. Go back to play!', yourls_admin_url('index.php') ) . ''; + echo '' . yourls_s( 'Upgrade not required. Go back to play!', yourls_admin_url('index.php') ) . '
'; } else { - /* - step 1: create new tables and populate them, update old tables structure, - step 2: convert each row of outdated tables if needed - step 3: - if applicable finish updating outdated tables (indexes etc) - - update version & db_version in options, this is all done! - */ + /* + step 1: create new tables and populate them, update old tables structure, + step 2: convert each row of outdated tables if needed + step 3: - if applicable finish updating outdated tables (indexes etc) + - update version & db_version in options, this is all done! + */ - // From what are we upgrading? - if ( isset( $_GET['oldver'] ) && isset( $_GET['oldsql'] ) ) { - $oldver = yourls_sanitize_version($_GET['oldver']); - $oldsql = intval($_GET['oldsql']); - } else { - list( $oldver, $oldsql ) = yourls_get_current_version_from_sql(); - } + // From what are we upgrading? + if ( isset( $_GET['oldver'] ) && isset( $_GET['oldsql'] ) ) { + $oldver = yourls_sanitize_version($_GET['oldver']); + $oldsql = intval($_GET['oldsql']); + } else { + list( $oldver, $oldsql ) = yourls_get_current_version_from_sql(); + } - // To what are we upgrading ? - $newver = YOURLS_VERSION; - $newsql = YOURLS_DB_VERSION; + // To what are we upgrading ? + $newver = YOURLS_VERSION; + $newsql = YOURLS_DB_VERSION; - // Verbose & ugly details - yourls_debug_mode(true); + // Verbose & ugly details + yourls_debug_mode(true); - // Let's go - $step = ( isset( $_GET['step'] ) ? intval( $_GET['step'] ) : 0 ); - switch( $step ) { + // Let's go + $step = ( isset( $_GET['step'] ) ? intval( $_GET['step'] ) : 0 ); + switch( $step ) { - default: - case 0: - ?> - -backup your database
(you should do this regularly anyway)' ); ?>
should happen, but this doesn't mean it won't happen, right? ;)" ); ?>
-something goes wrong, you'll see a message and hopefully a way to fix." ); ?>
-good for you, let it go :)' ); ?>
- - - - - - - - - "; + default: + case 0: + ?> + +backup your database
(you should do this regularly anyway)' ); ?>
should happen, but this doesn't mean it won't happen, right? ;)" ); ?>
+something goes wrong, you'll see a message and hopefully a way to fix." ); ?>
+good for you, let it go :)' ); ?>
+ + + + + + + + + "; - break; + break; - case 1: - case 2: - $upgrade = yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ); - break; + case 1: + case 2: + $upgrade = yourls_upgrade( $step, $oldver, $newver, $oldsql, $newsql ); + break; - case 3: - $upgrade = yourls_upgrade( 3, $oldver, $newver, $oldsql, $newsql ); - echo '' . yourls__( 'Your installation is now up to date ! ' ) . '
'; - echo '' . yourls_s( 'Go back to the admin interface', yourls_admin_url('index.php') ) . '
'; - } + case 3: + $upgrade = yourls_upgrade( 3, $oldver, $newver, $oldsql, $newsql ); + echo '' . yourls__( 'Your installation is now up to date ! ' ) . '
'; + echo '' . yourls_s( 'Go back to the admin interface', yourls_admin_url('index.php') ) . '
'; + } } diff --git a/composer.json b/composer.json index 53ac504..b77e8ab 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "utcweb/utctiny", - "description": "UTC: Your Own URL Shortener", + "name": "yourls/yourls", + "description": "Your Own URL Shortener", "type": "project", "keywords": [ "shortener", @@ -9,11 +9,11 @@ "url", "bitly" ], - "homepage": "https://go.utc.edu", + "homepage": "https://yourls.org", "license": "MIT", "support": { - "issues": "https://github.com/UTCWeb/utctiny/issues", - "source": "https://github.com/UTCWeb/utctiny" + "issues": "https://github.com/YOURLS/YOURLS/issues", + "source": "https://github.com/YOURLS/YOURLS" }, "require": { "php": "^8.1", @@ -27,25 +27,12 @@ "rmccue/requests" : "^2.0", "pomo/pomo" : "^1.4", "geoip2/geoip2" : "^2.10", - "aura/sql": "^5.0 | ^6.0", + "aura/sql": "^6.0", "jakeasmith/http_build_url": "^1.0", - "platformsh/config-reader": "^3.0", "symfony/polyfill-mbstring": "^1.15", "symfony/polyfill-intl-idn": "^1.17", - "spatie/array-to-xml": "^2.14", - "yourls/seans-qrcode": "dev-develop as 1.x-dev", - "yourls/yourls-saml": "dev-develop as 1.x-dev" + "spatie/array-to-xml": "^3.4" }, - "repositories": [ - { - "type": "path", - "url": "user/plugins/seans-qrcode" - }, - { - "type": "path", - "url": "user/plugins/yourls-saml" - } - ], "require-dev": { "ext-ctype": "*" }, @@ -72,12 +59,6 @@ "ext-zlib": "For best performance" }, "scripts": { - "install-plugin-deps": [ - "bash -c \"find user/plugins -name \\\"composer.json\\\" -type f -exec dirname {} \\; | xargs -I{} bash -c 'echo \\\"Installing dependencies for {}\\\" && cd {} && composer install && cd - > /dev/null'\"" - ], - "post-install-cmd": [ - "@install-plugin-deps" - ], "post-update-cmd": "bash ./includes/vendor/build-script/yourls-build.sh ./includes/vendor" } } diff --git a/composer.lock b/composer.lock index 336ed9f..27941b6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,25 +4,25 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e5787f60ad536cc14e43fd0eb078833f", + "content-hash": "50804e4ad6386df5b147be4320a067e3", "packages": [ { "name": "aura/sql", - "version": "5.0.3", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/auraphp/Aura.Sql.git", - "reference": "fd7a6dd1c9d2a1da5754c50f287f8be8a27db0e7" + "reference": "8e2bb362e8953198df3682c9122e8b9edab5ff20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/auraphp/Aura.Sql/zipball/fd7a6dd1c9d2a1da5754c50f287f8be8a27db0e7", - "reference": "fd7a6dd1c9d2a1da5754c50f287f8be8a27db0e7", + "url": "https://api.github.com/repos/auraphp/Aura.Sql/zipball/8e2bb362e8953198df3682c9122e8b9edab5ff20", + "reference": "8e2bb362e8953198df3682c9122e8b9edab5ff20", "shasum": "" }, "require": { "ext-pdo": "*", - "php": ">=8.1", + "php": "^8.4", "psr/log": "^1.0 || ^2.0 || ^3.0" }, "require-dev": { @@ -60,181 +60,22 @@ ], "support": { "issues": "https://github.com/auraphp/Aura.Sql/issues", - "source": "https://github.com/auraphp/Aura.Sql/tree/5.0.3" + "source": "https://github.com/auraphp/Aura.Sql/tree/6.0.0" }, - "time": "2025-01-22T06:39:17+00:00" - }, - { - "name": "chillerlan/php-qrcode", - "version": "5.0.5", - "source": { - "type": "git", - "url": "https://github.com/chillerlan/php-qrcode.git", - "reference": "7b66282572fc14075c0507d74d9837dab25b38d6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/7b66282572fc14075c0507d74d9837dab25b38d6", - "reference": "7b66282572fc14075c0507d74d9837dab25b38d6", - "shasum": "" - }, - "require": { - "chillerlan/php-settings-container": "^2.1.6 || ^3.2.1", - "ext-mbstring": "*", - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "chillerlan/php-authenticator": "^4.3.1 || ^5.2.1", - "ext-fileinfo": "*", - "phan/phan": "^5.5.2", - "phpcompatibility/php-compatibility": "10.x-dev", - "phpmd/phpmd": "^2.15", - "phpunit/phpunit": "^9.6", - "setasign/fpdf": "^1.8.2", - "slevomat/coding-standard": "^8.23.0", - "squizlabs/php_codesniffer": "^4.0.0" - }, - "suggest": { - "chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.", - "setasign/fpdf": "Required to use the QR FPDF output.", - "simple-icons/simple-icons": "SVG icons that you can use to embed as logos in the QR Code" - }, - "type": "library", - "autoload": { - "psr-4": { - "chillerlan\\QRCode\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT", - "Apache-2.0" - ], - "authors": [ - { - "name": "Kazuhiko Arase", - "homepage": "https://github.com/kazuhikoarase/qrcode-generator" - }, - { - "name": "ZXing Authors", - "homepage": "https://github.com/zxing/zxing" - }, - { - "name": "Ashot Khanamiryan", - "homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder" - }, - { - "name": "Smiley", - "email": "smiley@chillerlan.net", - "homepage": "https://github.com/codemasher" - }, - { - "name": "Contributors", - "homepage": "https://github.com/chillerlan/php-qrcode/graphs/contributors" - } - ], - "description": "A QR Code generator and reader with a user-friendly API. PHP 7.4+", - "homepage": "https://github.com/chillerlan/php-qrcode", - "keywords": [ - "phpqrcode", - "qr", - "qr code", - "qr-reader", - "qrcode", - "qrcode-generator", - "qrcode-reader" - ], - "support": { - "docs": "https://php-qrcode.readthedocs.io", - "issues": "https://github.com/chillerlan/php-qrcode/issues", - "source": "https://github.com/chillerlan/php-qrcode" - }, - "funding": [ - { - "url": "https://ko-fi.com/codemasher", - "type": "Ko-Fi" - } - ], - "time": "2025-11-23T23:51:44+00:00" - }, - { - "name": "chillerlan/php-settings-container", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/chillerlan/php-settings-container.git", - "reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/95ed3e9676a1d47cab2e3174d19b43f5dbf52681", - "reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": "^8.1" - }, - "require-dev": { - "phpmd/phpmd": "^2.15", - "phpstan/phpstan": "^1.11", - "phpstan/phpstan-deprecation-rules": "^1.2", - "phpunit/phpunit": "^10.5", - "squizlabs/php_codesniffer": "^3.10" - }, - "type": "library", - "autoload": { - "psr-4": { - "chillerlan\\Settings\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Smiley", - "email": "smiley@chillerlan.net", - "homepage": "https://github.com/codemasher" - } - ], - "description": "A container class for immutable settings objects. Not a DI container.", - "homepage": "https://github.com/chillerlan/php-settings-container", - "keywords": [ - "Settings", - "configuration", - "container", - "helper" - ], - "support": { - "issues": "https://github.com/chillerlan/php-settings-container/issues", - "source": "https://github.com/chillerlan/php-settings-container" - }, - "funding": [ - { - "url": "https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4", - "type": "custom" - }, - { - "url": "https://ko-fi.com/codemasher", - "type": "ko_fi" - } - ], - "time": "2024-07-16T11:13:48+00:00" + "time": "2025-01-22T06:43:21+00:00" }, { "name": "composer/ca-bundle", - "version": "1.5.10", + "version": "1.5.5", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63" + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/961a5e4056dd2e4a2eedcac7576075947c28bf63", - "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/08c50d5ec4c6ced7d0271d2862dec8c1033283e6", + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6", "shasum": "" }, "require": { @@ -281,7 +122,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.10" + "source": "https://github.com/composer/ca-bundle/tree/1.5.5" }, "funding": [ { @@ -291,9 +132,13 @@ { "url": "https://github.com/composer", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" } ], - "time": "2025-12-08T15:06:51+00:00" + "time": "2025-01-08T16:17:16+00:00" }, { "name": "geoip2/geoip2", @@ -392,16 +237,16 @@ }, { "name": "maxmind-db/reader", - "version": "v1.13.1", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", - "reference": "2194f58d0f024ce923e685cdf92af3daf9951908" + "reference": "5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/2194f58d0f024ce923e685cdf92af3daf9951908", - "reference": "2194f58d0f024ce923e685cdf92af3daf9951908", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90", + "reference": "5b2d7a721dedfaef9dc20822c5fe7d26f9f8eb90", "shasum": "" }, "require": { @@ -414,13 +259,12 @@ "friendsofphp/php-cs-fixer": "3.*", "phpstan/phpstan": "*", "phpunit/phpunit": ">=8.0.0,<10.0.0", - "squizlabs/php_codesniffer": "4.*" + "squizlabs/php_codesniffer": "3.*" }, "suggest": { "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", - "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups", - "maxmind-db/reader-ext": "C extension for significantly faster IP lookups (install via PIE: pie install maxmind-db/reader-ext)" + "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" }, "type": "library", "autoload": { @@ -450,22 +294,22 @@ ], "support": { "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", - "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.13.1" + "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.12.0" }, - "time": "2025-11-21T22:24:26+00:00" + "time": "2024-11-14T22:43:47+00:00" }, { "name": "maxmind/web-service-common", - "version": "v0.11.0", + "version": "v0.10.0", "source": { "type": "git", "url": "https://github.com/maxmind/web-service-common-php.git", - "reference": "5b9e3d3472213361eebdb3ab8879e91b8952091b" + "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/5b9e3d3472213361eebdb3ab8879e91b8952091b", - "reference": "5b9e3d3472213361eebdb3ab8879e91b8952091b", + "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4", + "reference": "d7c7c42fc31bff26e0ded73a6e187bcfb193f9c4", "shasum": "" }, "require": { @@ -478,7 +322,7 @@ "friendsofphp/php-cs-fixer": "3.*", "phpstan/phpstan": "*", "phpunit/phpunit": "^8.0 || ^9.0", - "squizlabs/php_codesniffer": "4.*" + "squizlabs/php_codesniffer": "3.*" }, "type": "library", "autoload": { @@ -501,95 +345,31 @@ "homepage": "https://github.com/maxmind/web-service-common-php", "support": { "issues": "https://github.com/maxmind/web-service-common-php/issues", - "source": "https://github.com/maxmind/web-service-common-php/tree/v0.11.0" + "source": "https://github.com/maxmind/web-service-common-php/tree/v0.10.0" }, - "time": "2025-11-20T18:33:17+00:00" - }, - { - "name": "onelogin/php-saml", - "version": "4.3.1", - "source": { - "type": "git", - "url": "https://github.com/SAML-Toolkits/php-saml.git", - "reference": "b009f160e4ac11f49366a45e0d45706b48429353" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/SAML-Toolkits/php-saml/zipball/b009f160e4ac11f49366a45e0d45706b48429353", - "reference": "b009f160e4ac11f49366a45e0d45706b48429353", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "robrichards/xmlseclibs": ">=3.1.4" - }, - "require-dev": { - "pdepend/pdepend": "^2.8.0", - "php-coveralls/php-coveralls": "^2.0", - "phploc/phploc": "^4.0 || ^5.0 || ^6.0 || ^7.0", - "phpunit/phpunit": "^9.5", - "sebastian/phpcpd": "^4.0 || ^5.0 || ^6.0 ", - "squizlabs/php_codesniffer": "^3.5.8" - }, - "suggest": { - "ext-curl": "Install curl lib to be able to use the IdPMetadataParser for parsing remote XMLs", - "ext-dom": "Install xml lib", - "ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)", - "ext-zlib": "Install zlib" - }, - "type": "library", - "autoload": { - "psr-4": { - "OneLogin\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHP SAML Toolkit", - "homepage": "https://github.com/SAML-Toolkits/php-saml", - "keywords": [ - "Federation", - "SAML2", - "SSO", - "identity", - "saml" - ], - "support": { - "email": "sixto.martin.garcia@gmail.com", - "issues": "https://github.com/onelogin/SAML-Toolkits/issues", - "source": "https://github.com/onelogin/SAML-Toolkits/" - }, - "funding": [ - { - "url": "https://github.com/SAML-Toolkits", - "type": "github" - } - ], - "time": "2025-12-09T10:50:49+00:00" + "time": "2024-11-14T23:14:52+00:00" }, { "name": "ozh/bookmarkletgen", - "version": "1.3", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/ozh/bookmarkletgen.git", - "reference": "7b462817642aa599c558a6376c0c0d7bf3ffc949" + "reference": "65fffa64bb11f70470d398d7baf6d9bb84411cfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ozh/bookmarkletgen/zipball/7b462817642aa599c558a6376c0c0d7bf3ffc949", - "reference": "7b462817642aa599c558a6376c0c0d7bf3ffc949", + "url": "https://api.github.com/repos/ozh/bookmarkletgen/zipball/65fffa64bb11f70470d398d7baf6d9bb84411cfc", + "reference": "65fffa64bb11f70470d398d7baf6d9bb84411cfc", "shasum": "" }, "require": { - "php": ">=8.0" + "php": ">=7.2" }, "type": "library", "autoload": { - "psr-4": { - "Ozh\\Bookmarkletgen\\": "src" + "psr-0": { + "Ozh\\Bookmarkletgen\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -610,52 +390,9 @@ ], "support": { "issues": "https://github.com/ozh/bookmarkletgen/issues", - "source": "https://github.com/ozh/bookmarkletgen/tree/1.3" - }, - "time": "2025-11-07T17:20:10+00:00" - }, - { - "name": "platformsh/config-reader", - "version": "3.0.1", - "source": { - "type": "git", - "url": "https://github.com/platformsh/config-reader-php.git", - "reference": "cab2b6c0cdfc318df09a64136957dc1fc308f418" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/platformsh/config-reader-php/zipball/cab2b6c0cdfc318df09a64136957dc1fc308f418", - "reference": "cab2b6c0cdfc318df09a64136957dc1fc308f418", - "shasum": "" - }, - "require": { - "php": ">=7.4" - }, - "require-dev": { - "phpunit/phpunit": "^8.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Platformsh\\ConfigReader\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Larry Garfield", - "email": "larry@platform.sh" - } - ], - "description": "Small helper to access Platform.sh environment variables", - "support": { - "issues": "https://github.com/platformsh/config-reader-php/issues", - "source": "https://github.com/platformsh/config-reader-php/tree/3.0.1" + "source": "https://github.com/ozh/bookmarkletgen/tree/1.2.2" }, - "time": "2025-02-25T17:22:15+00:00" + "time": "2022-05-04T13:05:16+00:00" }, { "name": "pomo/pomo", @@ -777,16 +514,16 @@ }, { "name": "rmccue/requests", - "version": "v2.0.17", + "version": "v2.0.15", "source": { "type": "git", "url": "https://github.com/WordPress/Requests.git", - "reference": "74d1648cc34e16a42ea25d548fc73ec107a90421" + "reference": "877cd66169755899682f1595e057334b40d9d149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/Requests/zipball/74d1648cc34e16a42ea25d548fc73ec107a90421", - "reference": "74d1648cc34e16a42ea25d548fc73ec107a90421", + "url": "https://api.github.com/repos/WordPress/Requests/zipball/877cd66169755899682f1595e057334b40d9d149", + "reference": "877cd66169755899682f1595e057334b40d9d149", "shasum": "" }, "require": { @@ -794,14 +531,15 @@ "php": ">=5.6" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", "php-parallel-lint/php-console-highlighter": "^0.5.0", "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpcompatibility/php-compatibility": "^10.0.0@dev", + "phpcompatibility/php-compatibility": "^9.0", "requests/test-server": "dev-main", + "roave/security-advisories": "dev-latest", "squizlabs/php_codesniffer": "^3.6", "wp-coding-standards/wpcs": "^2.0", - "yoast/phpunit-polyfills": "^1.1.5" + "yoast/phpunit-polyfills": "^1.0.0" }, "suggest": { "art4/requests-psr18-adapter": "For using Requests as a PSR-18 HTTP Client", @@ -859,75 +597,37 @@ "issues": "https://github.com/WordPress/Requests/issues", "source": "https://github.com/WordPress/Requests" }, - "time": "2025-12-12T17:47:19+00:00" - }, - { - "name": "robrichards/xmlseclibs", - "version": "3.1.4", - "source": { - "type": "git", - "url": "https://github.com/robrichards/xmlseclibs.git", - "reference": "bc87389224c6de95802b505e5265b0ec2c5bcdbd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/bc87389224c6de95802b505e5265b0ec2c5bcdbd", - "reference": "bc87389224c6de95802b505e5265b0ec2c5bcdbd", - "shasum": "" - }, - "require": { - "ext-openssl": "*", - "php": ">= 5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "RobRichards\\XMLSecLibs\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "A PHP library for XML Security", - "homepage": "https://github.com/robrichards/xmlseclibs", - "keywords": [ - "security", - "signature", - "xml", - "xmldsig" - ], - "support": { - "issues": "https://github.com/robrichards/xmlseclibs/issues", - "source": "https://github.com/robrichards/xmlseclibs/tree/3.1.4" - }, - "time": "2025-12-08T11:57:53+00:00" + "time": "2025-01-21T10:13:31+00:00" }, { "name": "spatie/array-to-xml", - "version": "2.17.1", + "version": "3.4.4", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "5cbec9c6ab17e320c58a259f0cebe88bde4a7c46" + "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/5cbec9c6ab17e320c58a259f0cebe88bde4a7c46", - "reference": "5cbec9c6ab17e320c58a259f0cebe88bde4a7c46", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/88b2f3852a922dd73177a68938f8eb2ec70c7224", + "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224", "shasum": "" }, "require": { "ext-dom": "*", - "php": "^7.4|^8.0" + "php": "^8.0" }, "require-dev": { "mockery/mockery": "^1.2", "pestphp/pest": "^1.21", - "phpunit/phpunit": "^9.0", "spatie/pest-plugin-snapshots": "^1.1" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, "autoload": { "psr-4": { "Spatie\\ArrayToXml\\": "src" @@ -953,7 +653,7 @@ "xml" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/2.17.1" + "source": "https://github.com/spatie/array-to-xml/tree/3.4.4" }, "funding": [ { @@ -965,20 +665,20 @@ "type": "github" } ], - "time": "2022-12-26T08:22:07+00:00" + "time": "2025-12-15T09:00:41+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.33.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", - "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", "shasum": "" }, "require": { @@ -1032,7 +732,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" }, "funding": [ { @@ -1043,20 +743,16 @@ "url": "https://github.com/fabpot", "type": "github" }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-10T14:38:51+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -1117,7 +813,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -1128,10 +824,6 @@ "url": "https://github.com/fabpot", "type": "github" }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -1141,20 +833,19 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "ext-iconv": "*", "php": ">=7.2" }, "provide": { @@ -1202,7 +893,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -1213,76 +904,18 @@ "url": "https://github.com/fabpot", "type": "github" }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" - }, - { - "name": "yourls/seans-qrcode", - "version": "dev-develop", - "dist": { - "type": "path", - "url": "user/plugins/seans-qrcode", - "reference": "d162de53f08a19e0b27335362a74788712f1d20e" - }, - "require": { - "chillerlan/php-qrcode": "^4.4.0 || ^5.0.3", - "ext-gd": "*", - "ext-mbstring": "*", - "php": "^8.0" - }, - "type": "yourls-plugin", - "description": "QR Code plugin for YOURLS", - "transport-options": { - "relative": true - } - }, - { - "name": "yourls/yourls-saml", - "version": "dev-develop", - "dist": { - "type": "path", - "url": "user/plugins/yourls-saml", - "reference": "4df0a07eac5bca340fd5f814af24daf5d6a316c2" - }, - "require": { - "onelogin/php-saml": "^4.0", - "platformsh/config-reader": "^3.0" - }, - "type": "yourls-plugin", - "description": "SAML Authentication for YOURLS", - "transport-options": { - "relative": true - } + "time": "2024-09-09T11:45:10+00:00" } ], "packages-dev": [], - "aliases": [ - { - "package": "yourls/seans-qrcode", - "version": "dev-develop", - "alias": "1.x-dev", - "alias_normalized": "1.9999999.9999999.9999999-dev" - }, - { - "package": "yourls/yourls-saml", - "version": "dev-develop", - "alias": "1.x-dev", - "alias_normalized": "1.9999999.9999999.9999999-dev" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "yourls/seans-qrcode": 20, - "yourls/yourls-saml": 20 - }, + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -1298,7 +931,7 @@ "ext-ctype": "*" }, "platform-overrides": { - "php": "8.1.0" + "php": "8.1" }, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.6.0" } diff --git a/css/style.css b/css/style.css index e1d350d..1f10841 100644 --- a/css/style.css +++ b/css/style.css @@ -18,8 +18,6 @@ body { border-right:3px solid #2a85b3; border-bottom:3px solid #2a85b3; border-top:3px solid #2a85b3; - -moz-border-radius:20px; - -webkit-border-radius:20px; border-radius:20px; } .hide-if-no-js {display: none;} @@ -68,8 +66,6 @@ tt { } input, textarea { - -moz-border-radius:3px; - -webkit-border-radius:3px; border-radius:3px; } Input.text, select, textarea { @@ -129,8 +125,11 @@ tr.edit-row td { td.url small a{ color:#bbc; } -body.desktop td.actions input,body.desktop td.actions a { - visibility:hidden; +/* Hide buttons visually but keep them accessible to screen readers */ +body.desktop td.actions input, body.desktop td.actions a { + opacity: 0; + pointer-events: none; + transition: opacity 0.2s ease; } td.timestamp span.timestamp { display:none; @@ -138,8 +137,20 @@ td.timestamp span.timestamp { td.actions input.disabled, td.actions input.loading { visibility:visible; } +/* Show buttons on row hover */ tr:hover td.actions input, tr:hover td.actions a { - visibility:visible; + opacity: 1; + pointer-events: auto; +} +/* Show buttons when any button in the actions cell receives focus */ +td.actions:focus-within input, td.actions:focus-within a { + opacity: 1; + pointer-events: auto; +} +/* Show all buttons when any element in the row receives focus (for keyboard nav through the entire row) */ +tr:focus-within td.actions input, tr:focus-within td.actions a { + opacity: 1; + pointer-events: auto; } td.actions .button { font-family: Verdana, Arial; @@ -148,8 +159,6 @@ td.actions .button { font-weight: bold; background-color: #FFFFFF; border: 1px solid #88c0eb; - -moz-border-radius:3px; - -webkit-border-radius:3px; border-radius:3px; cursor:pointer; height:22px; @@ -240,8 +249,6 @@ td.actions .button_stats { } a.bookmarklet { border:2px solid #2a85b3; - -moz-border-radius:3px; - -webkit-border-radius:3px; border-radius:3px; padding:5px 5px 5px 20px; background:#eef url(../images/favicon.svg) 2px center no-repeat; @@ -262,14 +269,8 @@ a.bookmarklet:hover { background:white; margin:0 auto; max-width:950px; - -moz-border-radius:10px; - -webkit-border-radius:10px; border-radius:10px; border:2px solid #2a85b3; - -moz-border-radius-bottomleft:30px; - -moz-border-radius-bottomright:30px; - -webkit-border-bottom-left-radius:25px; - -webkit-border-bottom-right-radius:25px; border-bottom-left-radius:25px; border-bottom-right-radius:25px; } @@ -281,8 +282,6 @@ a.bookmarklet:hover { .notice { border:1px solid #2a85b3; background: #F3FAFD; - -moz-border-radius:6px; - -webkit-border-radius:6px; border-radius:6px; width:70%; margin-left:15%; @@ -290,7 +289,6 @@ a.bookmarklet:hover { margin-bottom:5px; } - .jquery-notify-bar { width:100%; position:fixed; @@ -305,11 +303,7 @@ a.bookmarklet:hover { padding:20px 0px; border-bottom:1px solid #bbb; filter:alpha(opacity=95); - -moz-opacity:0.95; - -khtml-opacity:0.95; opacity:0.95; - -moz-box-shadow: 0 1px 5px rgba(0,0,0,0.5); - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5); text-shadow: 0 1px 1px rgba(0,0,0,0.1); } .jquery-notify-bar.error ,.jquery-notify-bar.fail { @@ -335,3 +329,59 @@ a.bookmarklet:hover { tr.plugin.active a{ font-weight:bolder;} body.desktop tr.plugin td.plugin_desc small{ visibility:hidden;} tr:hover.plugin td.plugin_desc small{ visibility:visible;} + +#delete-confirm-dialog { + background-color: #ffffff; + width: 50em; + height: 19em; + padding: 0px; + border: 3px solid #2a85b3; + border-radius: 20px; +} +#delete-confirm-dialog > div[name="dialog_title"] { + background-color: #c7e7ff; + font-size: 20px; + color: #026090; + text-align: center; + padding-top: 0.5em; + padding-bottom: 0.5em; + border-start-start-radius: 17px 17px; + border-start-end-radius: 17px 17px; +} +#delete-confirm-dialog div.confirm-message { + background-color: #ffffff; + width: calc(50em - 4em); + height: calc(20em - 50px - 5em - 2em + 6px); + float: none; + text-align: left; + padding: 1em 2em; + overflow: hidden; +} +#delete-confirm-dialog div.confirm-message ul { + border-left: 5px solid #026090; + list-style-type: none; + padding: 0 1em; +} +#delete-confirm-dialog div.confirm-message ul li { + margin-bottom: 0.5em; +} +#delete-confirm-dialog div.confirm-message ul li span { + border: 1px solid #c7e7ff; + border-radius: 3px; + padding: 1px 5px; + color:#333; +} +#delete-confirm-dialog div.button-group { + background-color: #e3f3ff; + width: calc(50em - 4em); + height: 2em; + float: none; + text-align: right; + padding: 1em 2em; + border-end-start-radius: 17px 17px; + border-end-end-radius: 17px 17px; +} +#delete-confirm-dialog::backdrop { + background-color: #666; + opacity: 80%; +} diff --git a/includes/Database/Options.php b/includes/Database/Options.php index b35224d..f175f08 100644 --- a/includes/Database/Options.php +++ b/includes/Database/Options.php @@ -172,7 +172,7 @@ public function update($name, $newvalue) { // Cache option value to save a DB query if needed later $this->ydb->set_option($name, $newvalue); - yourls_do_action( 'update_option', $name, $oldvalue, $newvalue ); + yourls_do_action( 'update_option', $name, $oldvalue, $newvalue ); return true; } diff --git a/includes/Database/YDB.php b/includes/Database/YDB.php index c3313c3..803f345 100644 --- a/includes/Database/YDB.php +++ b/includes/Database/YDB.php @@ -1,12 +1,12 @@ option, or $ydb->set_option(), use yourls_*_options() functions instead). + * function wrappers (e.g. don't use $ydb->option, or $ydb->set_option(), use yourls_*_options() functions instead). * * @since 1.7.3 */ @@ -33,7 +33,7 @@ class YDB extends ExtendedPdo { protected $context = ''; /** - * Information related to a short URL keyword (eg timestamp, long URL, ...) + * Information related to a short URL keyword (e.g. timestamp, long URL, ...) * * @var array * @@ -53,13 +53,13 @@ class YDB extends ExtendedPdo { protected $option = []; /** - * Plugin admin pages informations + * Plugin admin pages information * @var array */ protected $plugin_pages = []; /** - * Plugin informations + * Plugin information * @var array */ protected $plugins = []; @@ -86,7 +86,7 @@ public function __construct($dsn, $user, $pass, $options) { * Init everything needed * * Everything we need to set up is done here in init(), not in the constructor, so even - * when the connection fails (eg config error or DB dead), the constructor has worked + * when the connection fails (e.g. config error or DB dead), the constructor has worked, * and we have a $ydb object properly instantiated (and for instance yourls_die() can * correctly die, even if using $ydb methods) * @@ -276,7 +276,20 @@ public function get_infos($keyword) { * @return void */ public function delete_infos($keyword) { - unset($this->infos[$keyword]); + if (isset($this->infos[$keyword])) { + unset($this->infos[$keyword]); + } + } + + /** + * @param string $keyword + * @param mixed $infos + * @return void + */ + public function update_infos_if_exists($keyword, $infos) { + if ($this->has_infos($keyword) && $this->infos[$keyword]) { + $this->infos[$keyword] = array_merge($this->infos[$keyword], $infos); + } } /** @@ -405,22 +418,13 @@ public function is_installed() { } /** - * Return standardized DB version - * - * The regex removes everything that's not a number at the start of the string, or remove anything that's not a number and what - * follows after that. - * 'omgmysql-5.5-ubuntu-4.20' => '5.5' - * 'mysql5.5-ubuntu-4.20' => '5.5' - * '5.5-ubuntu-4.20' => '5.5' - * '5.5-beta2' => '5.5' - * '5.5' => '5.5' + * Return MySQL version * * @since 1.7.3 * @return string */ public function mysql_version() { - $version = $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION); - return $version; + return $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION); } } diff --git a/includes/Views/AdminParams.php b/includes/Views/AdminParams.php index 9116fb5..892684d 100644 --- a/includes/Views/AdminParams.php +++ b/includes/Views/AdminParams.php @@ -222,8 +222,15 @@ public function get_click_filter() public function get_click_limit() { // @hook Default link click threshold (unset) - return (!empty($_GET['click_limit']) && intval($_GET['click_limit']) >= 0) ? - intval($_GET['click_limit']) : yourls_apply_filter('admin_view_click_limit', ''); + if ( + isset($_GET['click_limit']) // Exists in the query string + && ($_GET['click_limit'] !== '') // Not empty (&stuff=&click_limit=&otherstuff=) + && intval($_GET['click_limit']) >= 0 // A number >= 0 + ) { + return intval($_GET['click_limit']); + } else { + return yourls_apply_filter('admin_view_click_limit', ''); + } } diff --git a/includes/auth.php b/includes/auth.php index ad9f9a8..be98a87 100644 --- a/includes/auth.php +++ b/includes/auth.php @@ -6,23 +6,23 @@ if( $auth !== true ) { - // API mode, - if ( yourls_is_API() ) { - $format = ( isset($_REQUEST['format']) ? $_REQUEST['format'] : 'xml' ); - $callback = ( isset($_REQUEST['callback']) ? $_REQUEST['callback'] : '' ); - yourls_api_output( $format, array( - 'simple' => $auth, - 'message' => $auth, - 'errorCode' => '403', - 'callback' => $callback, - ) ); - - // Regular mode - } else { - yourls_login_screen( $auth ); - } - - die(); + // API mode, + if ( yourls_is_API() ) { + $format = ( isset($_REQUEST['format']) ? $_REQUEST['format'] : 'xml' ); + $callback = ( isset($_REQUEST['callback']) ? $_REQUEST['callback'] : '' ); + yourls_api_output( $format, array( + 'simple' => $auth, + 'message' => $auth, + 'errorCode' => '403', + 'callback' => $callback, + ) ); + + // Regular mode + } else { + yourls_login_screen( $auth ); + } + + die(); } yourls_do_action( 'auth_successful' ); @@ -36,12 +36,12 @@ // Did we just fail at encrypting passwords ? if ( isset( $_GET['dismiss'] ) && $_GET['dismiss'] == 'hasherror' ) { - yourls_update_option( 'defer_hashing_error', time() + 86400 * 7 ); // now + 1 week + yourls_update_option( 'defer_hashing_error', time() + 86400 * 7 ); // now + 1 week } else { - // Encrypt passwords that are clear text - if ( yourls_maybe_hash_passwords() ) { + // Encrypt passwords that are clear text + if ( yourls_maybe_hash_passwords() ) { $hash = yourls_hash_passwords_now( YOURLS_CONFIGFILE ); if ( $hash === true ) { // Hashing successful. Remove flag from DB if any. @@ -59,5 +59,5 @@ yourls_add_notice( $message ); } } - } + } } diff --git a/includes/class-mysql.php b/includes/class-mysql.php index c25c183..603c87c 100644 --- a/includes/class-mysql.php +++ b/includes/class-mysql.php @@ -4,9 +4,10 @@ * Connect to DB * * @since 1.0 + * @param string $context Optional context. Default: ''. * @return \YOURLS\Database\YDB */ -function yourls_db_connect() { +function yourls_db_connect($context = '') { global $ydb; if ( !defined( 'YOURLS_DB_USER' ) @@ -26,12 +27,12 @@ function yourls_db_connect() { yourls_do_action( 'set_DB_driver', 'deprecated' ); // Get custom port if any - if ( false !== strpos( $dbhost, ':' ) ) { + if (str_contains($dbhost, ':')) { list( $dbhost, $dbport ) = explode( ':', $dbhost ); $dbhost = sprintf( '%1$s;port=%2$d', $dbhost, $dbport ); } - $charset = yourls_apply_filter( 'db_connect_charset', 'utf8mb4' ); + $charset = yourls_apply_filter( 'db_connect_charset', 'utf8mb4', $context ); /** * Data Source Name (dsn) used to connect the DB @@ -42,7 +43,7 @@ function yourls_db_connect() { * 'pgsql:host=192.168.13.37;port=5432;dbname=omgwtf' */ $dsn = sprintf( 'mysql:host=%s;dbname=%s;charset=%s', $dbhost, $dbname, $charset ); - $dsn = yourls_apply_filter( 'db_connect_custom_dsn', $dsn ); + $dsn = yourls_apply_filter( 'db_connect_custom_dsn', $dsn, $context ); /** * PDO driver options and attributes @@ -52,14 +53,18 @@ function yourls_db_connect() { * The driver options are passed to the PDO constructor, eg array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) * The attribute options are then set in a foreach($attr as $k=>$v){$db->setAttribute($k, $v)} loop */ - $driver_options = yourls_apply_filter( 'db_connect_driver_option', [] ); // driver options as key-value pairs - $attributes = yourls_apply_filter( 'db_connect_attributes', [] ); // attributes as key-value pairs + $driver_options = yourls_apply_filter( 'db_connect_driver_option', [], $context ); // driver options as key-value pairs + $attributes = yourls_apply_filter( 'db_connect_attributes', [], $context ); // attributes as key-value pairs $ydb = new \YOURLS\Database\YDB( $dsn, $user, $pass, $driver_options, $attributes ); $ydb->init(); // Past this point, we're connected - yourls_debug_log( sprintf( 'Connected to database %s on %s ', $dbname, $dbhost ) ); + $msg = 'Connected to ' . $dsn; + if ($context !== '') { + $msg .= ', context: ' . $context; + } + yourls_debug_log( $msg ); yourls_debug_mode( YOURLS_DEBUG ); @@ -67,7 +72,7 @@ function yourls_db_connect() { } /** - * Helper function : return instance of the DB + * Helper function: return instance of the DB * * Instead of: * global $ydb; @@ -76,18 +81,46 @@ function yourls_db_connect() { * yourls_get_db()->do_stuff() * * @since 1.7.10 + * @param string $context Optional context. Default: ''. + * If not provided, the function will trigger a notice to encourage developers to provide a context while not + * breaking existing code. A context is a string describing the operation for which the DB is requested. + * Use a naming schema starting with a prefix describing the operation, followed by a short description: + * - Prefix should be either "read-" or "write-", as follows: + * * "read-" for operations that only read from the DB (eg get_keyword_infos) + * * "write-" for operations that write to the DB (eg insert_link_in_db) + * - The description should be lowercase, words separated with underscores, eg "insert_link_in_db". + * Examples: + * - read-fetch_keyword + * - write-insert_link_in_db * @return \YOURLS\Database\YDB */ -function yourls_get_db() { +function yourls_get_db($context = '') { // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_get_db', false ); + $pre = yourls_apply_filter( 'shunt_get_db', false, $context ); if ( false !== $pre ) { return $pre; } + // Validate context and raise notice if missing or malformed + if ($context == '' || !preg_match('/^(read|write)-[a-z0-9_]+$/', $context)) { + $db = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + $file = $db[0]['file']; + $line = $db[0]['line']; + + if ($context == '') { + $msg = 'Undefined yourls_get_db() context'; + } else { + $msg = 'Improperly formatted yourls_get_db() context ("' . $context . '")'; + } + + trigger_error( $msg . ' at ' . $file . ':' . $line .'', E_USER_NOTICE ); + } + + yourls_do_action( 'get_db_action', $context ); + global $ydb; - $ydb = ( isset( $ydb ) ) ? $ydb : yourls_db_connect(); - return yourls_apply_filter('get_db', $ydb); + $ydb = ( isset( $ydb ) ) ? $ydb : yourls_db_connect($context); + return yourls_apply_filter('get_db', $ydb, $context); } /** diff --git a/includes/functions-api.php b/includes/functions-api.php index b32f1cc..bd97237 100644 --- a/includes/functions-api.php +++ b/includes/functions-api.php @@ -15,13 +15,13 @@ * @return array Result of API call */ function yourls_api_action_shorturl() { - $url = ( isset( $_REQUEST['url'] ) ? $_REQUEST['url'] : '' ); - $keyword = ( isset( $_REQUEST['keyword'] ) ? $_REQUEST['keyword'] : '' ); - $title = ( isset( $_REQUEST['title'] ) ? $_REQUEST['title'] : '' ); - $return = yourls_add_new_link( $url, $keyword, $title ); - $return['simple'] = ( isset( $return['shorturl'] ) ? $return['shorturl'] : '' ); // This one will be used in case output mode is 'simple' - unset( $return['html'] ); // in API mode, no need for our internal HTML output - return yourls_apply_filter( 'api_result_shorturl', $return ); + $url = ( isset( $_REQUEST['url'] ) ? $_REQUEST['url'] : '' ); + $keyword = ( isset( $_REQUEST['keyword'] ) ? $_REQUEST['keyword'] : '' ); + $title = ( isset( $_REQUEST['title'] ) ? $_REQUEST['title'] : '' ); + $return = yourls_add_new_link( $url, $keyword, $title ); + $return['simple'] = ( isset( $return['shorturl'] ) ? $return['shorturl'] : '' ); // This one will be used in case output mode is 'simple' + unset( $return['html'] ); // in API mode, no need for our internal HTML output + return yourls_apply_filter( 'api_result_shorturl', $return ); } /** @@ -31,10 +31,10 @@ function yourls_api_action_shorturl() { * @return array Result of API call */ function yourls_api_action_stats() { - $filter = ( isset( $_REQUEST['filter'] ) ? $_REQUEST['filter'] : '' ); - $limit = ( isset( $_REQUEST['limit'] ) ? $_REQUEST['limit'] : '' ); - $start = ( isset( $_REQUEST['start'] ) ? $_REQUEST['start'] : '' ); - return yourls_apply_filter( 'api_result_stats', yourls_api_stats( $filter, $limit, $start ) ); + $filter = ( isset( $_REQUEST['filter'] ) ? $_REQUEST['filter'] : '' ); + $limit = ( isset( $_REQUEST['limit'] ) ? $_REQUEST['limit'] : '' ); + $start = ( isset( $_REQUEST['start'] ) ? $_REQUEST['start'] : '' ); + return yourls_apply_filter( 'api_result_stats', yourls_api_stats( $filter, $limit, $start ) ); } /** @@ -44,7 +44,7 @@ function yourls_api_action_stats() { * @return array Result of API call */ function yourls_api_action_db_stats() { - return yourls_apply_filter( 'api_result_db_stats', yourls_api_db_stats() ); + return yourls_apply_filter( 'api_result_db_stats', yourls_api_db_stats() ); } /** @@ -54,8 +54,8 @@ function yourls_api_action_db_stats() { * @return array Result of API call */ function yourls_api_action_url_stats() { - $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); - return yourls_apply_filter( 'api_result_url_stats', yourls_api_url_stats( $shorturl ) ); + $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); + return yourls_apply_filter( 'api_result_url_stats', yourls_api_url_stats( $shorturl ) ); } /** @@ -65,8 +65,8 @@ function yourls_api_action_url_stats() { * @return array Result of API call */ function yourls_api_action_expand() { - $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); - return yourls_apply_filter( 'api_result_expand', yourls_api_expand( $shorturl ) ); + $shorturl = ( isset( $_REQUEST['shorturl'] ) ? $_REQUEST['shorturl'] : '' ); + return yourls_apply_filter( 'api_result_expand', yourls_api_expand( $shorturl ) ); } /** @@ -76,10 +76,10 @@ function yourls_api_action_expand() { * @return array Result of API call */ function yourls_api_action_version() { - $return['version'] = $return['simple'] = YOURLS_VERSION; - if( isset( $_REQUEST['db'] ) && $_REQUEST['db'] == 1 ) - $return['db_version'] = YOURLS_DB_VERSION; - return yourls_apply_filter( 'api_result_version', $return ); + $return['version'] = $return['simple'] = YOURLS_VERSION; + if( isset( $_REQUEST['db'] ) && $_REQUEST['db'] == 1 ) + $return['db_version'] = YOURLS_DB_VERSION; + return yourls_apply_filter( 'api_result_version', $return ); } /** @@ -99,12 +99,12 @@ function yourls_api_action_version() { * @return string API output, as an XML / JSON / JSONP / raw text string */ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) { - if( isset( $output['simple'] ) ) { - $simple = $output['simple']; - unset( $output['simple'] ); - } + if( isset( $output['simple'] ) ) { + $simple = $output['simple']; + unset( $output['simple'] ); + } - yourls_do_action( 'pre_api_output', $mode, $output, $send_headers, $echo ); + yourls_do_action( 'pre_api_output', $mode, $output, $send_headers, $echo ); if( $send_headers ) { if( isset( $output['statusCode'] ) ) { @@ -119,43 +119,49 @@ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) $result = ''; - switch ( $mode ) { - case 'jsonp': + switch ( $mode ) { + case 'jsonp': if( $send_headers ) yourls_content_type_header( 'application/javascript' ); - $callback = isset( $output['callback'] ) ? $output['callback'] : ''; - $result = $callback . '(' . json_encode( $output ) . ')'; - break; + $callback = isset( $output['callback'] ) ? yourls_validate_jsonp_callback($output['callback'] ) : ''; + if( $callback === false ) { + yourls_status_header( 400 ); + $result = json_encode( ['errorCode' => '400', 'error' => 'Invalid callback parameter'] ); + } else { + $result = $callback . '(' . json_encode( $output ) . ')'; + } + + break; - case 'json': + case 'json': if( $send_headers ) yourls_content_type_header( 'application/json' ); - $result = json_encode( $output ); - break; + $result = json_encode( $output ); + break; - case 'xml': + case 'xml': if( $send_headers ) yourls_content_type_header( 'application/xml' ); - $result = yourls_xml_encode( $output ); - break; + $result = yourls_xml_encode( $output ); + break; - case 'simple': - default: + case 'simple': + default: if( $send_headers ) yourls_content_type_header( 'text/plain' ); - $result = isset( $simple ) ? $simple : ''; - break; - } + $result = isset( $simple ) ? $simple : ''; + break; + } if( $echo ) { echo $result; } - yourls_do_action( 'api_output', $mode, $output, $send_headers, $echo ); + yourls_do_action( 'api_output', $mode, $output, $send_headers, $echo ); return $result; } @@ -169,10 +175,10 @@ function yourls_api_output( $mode, $output, $send_headers = true, $echo = true ) * @return array */ function yourls_api_stats($filter = 'top', $limit = 10, $start = 0 ) { - $return = yourls_get_stats( $filter, $limit, $start ); - $return['simple'] = 'Need either XML or JSON format for stats'; - $return['message'] = 'success'; - return yourls_apply_filter( 'api_stats', $return, $filter, $limit, $start ); + $return = yourls_get_stats( $filter, $limit, $start ); + $return['simple'] = 'Need either XML or JSON format for stats'; + $return['message'] = 'success'; + return yourls_apply_filter( 'api_stats', $return, $filter, $limit, $start ); } /** @@ -181,14 +187,14 @@ function yourls_api_stats($filter = 'top', $limit = 10, $start = 0 ) { * @return array */ function yourls_api_db_stats() { - $return = array( - 'db-stats' => yourls_get_db_stats(), - 'statusCode' => '200', - 'simple' => 'Need either XML or JSON format for stats', - 'message' => 'success', - ); - - return yourls_apply_filter( 'api_db_stats', $return ); + $return = array( + 'db-stats' => yourls_get_db_stats(), + 'statusCode' => '200', + 'simple' => 'Need either XML or JSON format for stats', + 'message' => 'success', + ); + + return yourls_apply_filter( 'api_db_stats', $return ); } /** @@ -198,12 +204,12 @@ function yourls_api_db_stats() { * @return array */ function yourls_api_url_stats( $shorturl ) { - $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' - $keyword = yourls_sanitize_keyword( $keyword ); + $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' + $keyword = yourls_sanitize_keyword( $keyword ); - $return = yourls_get_keyword_stats( $keyword ); - $return['simple'] = 'Need either XML or JSON format for stats'; - return yourls_apply_filter( 'api_url_stats', $return, $shorturl ); + $return = yourls_get_keyword_stats( $keyword ); + $return['simple'] = 'Need either XML or JSON format for stats'; + return yourls_apply_filter( 'api_url_stats', $return, $shorturl ); } /** @@ -213,29 +219,29 @@ function yourls_api_url_stats( $shorturl ) { * @return array */ function yourls_api_expand( $shorturl ) { - $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' - $keyword = yourls_sanitize_keyword( $keyword ); + $keyword = str_replace( yourls_get_yourls_site() . '/' , '', $shorturl ); // accept either 'http://ozh.in/abc' or 'abc' + $keyword = yourls_sanitize_keyword( $keyword ); - $longurl = yourls_get_keyword_longurl( $keyword ); + $longurl = yourls_get_keyword_longurl( $keyword ); - if( $longurl ) { - $return = array( - 'keyword' => $keyword, - 'shorturl' => yourls_link($keyword), - 'longurl' => $longurl, + if( $longurl ) { + $return = array( + 'keyword' => $keyword, + 'shorturl' => yourls_link($keyword), + 'longurl' => $longurl, 'title' => yourls_get_keyword_title( $keyword ), - 'simple' => $longurl, - 'message' => 'success', - 'statusCode' => '200', - ); - } else { - $return = array( - 'keyword' => $keyword, - 'simple' => 'not found', - 'message' => 'Error: short URL not found', - 'errorCode' => '404', - ); - } - - return yourls_apply_filter( 'api_expand', $return, $shorturl ); + 'simple' => $longurl, + 'message' => 'success', + 'statusCode' => '200', + ); + } else { + $return = array( + 'keyword' => $keyword, + 'simple' => 'not found', + 'message' => 'Error: short URL not found', + 'errorCode' => '404', + ); + } + + return yourls_apply_filter( 'api_expand', $return, $shorturl ); } diff --git a/includes/functions-auth.php b/includes/functions-auth.php index f074c21..cadf538 100644 --- a/includes/functions-auth.php +++ b/includes/functions-auth.php @@ -10,12 +10,12 @@ * @return void */ function yourls_maybe_require_auth() { - if( yourls_is_private() ) { - yourls_do_action( 'require_auth' ); - require_once( YOURLS_INC.'/auth.php' ); - } else { - yourls_do_action( 'require_no_auth' ); - } + if( yourls_is_private() ) { + yourls_do_action( 'require_auth' ); + require_once( YOURLS_INC.'/auth.php' ); + } else { + yourls_do_action( 'require_no_auth' ); + } } /** @@ -24,102 +24,102 @@ function yourls_maybe_require_auth() { * @return bool|string|mixed true if valid user, error message otherwise. Can also call yourls_die() or redirect to login page. Oh my. */ function yourls_is_valid_user() { - // Allow plugins to short-circuit the whole function - $pre = yourls_apply_filter( 'shunt_is_valid_user', null ); - if ( null !== $pre ) { - return $pre; - } + // Allow plugins to short-circuit the whole function + $pre = yourls_apply_filter( 'shunt_is_valid_user', null ); + if ( null !== $pre ) { + return $pre; + } - // $unfiltered_valid : are credentials valid? Boolean value. It's "unfiltered" to allow plugins to eventually filter it. - $unfiltered_valid = false; + // $unfiltered_valid : are credentials valid? Boolean value. It's "unfiltered" to allow plugins to eventually filter it. + $unfiltered_valid = false; - // Logout request - if( isset( $_GET['action'] ) && $_GET['action'] == 'logout' && isset( $_REQUEST['nonce'] ) ) { + // Logout request + if( isset( $_GET['action'] ) && $_GET['action'] == 'logout' && isset( $_REQUEST['nonce'] ) ) { // The logout nonce is associated to fake user 'logout' since at this point we don't know the real user yourls_verify_nonce('admin_logout', $_REQUEST['nonce'], 'logout'); - yourls_do_action( 'logout' ); - yourls_store_cookie( '' ); - return yourls__( 'Logged out successfully' ); - } - - // Check cookies or login request. Login form has precedence. - - yourls_do_action( 'pre_login' ); - - // Determine auth method and check credentials - if - // API only: Secure (no login or pwd) and time limited token - // ?timestamp=12345678&signature=md5(totoblah12345678) - ( yourls_is_API() && - isset( $_REQUEST['timestamp'] ) && !empty($_REQUEST['timestamp'] ) && - isset( $_REQUEST['signature'] ) && !empty($_REQUEST['signature'] ) - ) - { - yourls_do_action( 'pre_login_signature_timestamp' ); - $unfiltered_valid = yourls_check_signature_timestamp(); - } - - elseif - // API only: Secure (no login or pwd) - // ?signature=md5(totoblah) - ( yourls_is_API() && - !isset( $_REQUEST['timestamp'] ) && - isset( $_REQUEST['signature'] ) && !empty( $_REQUEST['signature'] ) - ) - { - yourls_do_action( 'pre_login_signature' ); - $unfiltered_valid = yourls_check_signature(); - } - - elseif - // API or normal: login with username & pwd - ( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) - && !empty( $_REQUEST['username'] ) && !empty( $_REQUEST['password'] ) ) - { - yourls_do_action( 'pre_login_username_password' ); - $unfiltered_valid = yourls_check_username_password(); - } - - elseif - // Normal only: cookies - ( !yourls_is_API() && - isset( $_COOKIE[ yourls_cookie_name() ] ) ) - { - yourls_do_action( 'pre_login_cookie' ); - $unfiltered_valid = yourls_check_auth_cookie(); - } - - // Regardless of validity, allow plugins to filter the boolean and have final word - $valid = yourls_apply_filter( 'is_valid_user', $unfiltered_valid ); - - // Login for the win! - if ( $valid ) { - yourls_do_action( 'login' ); - - // (Re)store encrypted cookie if needed - if ( !yourls_is_API() ) { - yourls_store_cookie( YOURLS_USER ); - - // Login form : redirect to requested URL to avoid re-submitting the login form on page reload - if( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) && isset( $_SERVER['REQUEST_URI'] ) ) { - // The return makes sure we exit this function before waiting for redirection. + yourls_do_action( 'logout' ); + yourls_store_cookie( '' ); + return yourls__( 'Logged out successfully' ); + } + + // Check cookies or login request. Login form has precedence. + + yourls_do_action( 'pre_login' ); + + // Determine auth method and check credentials + if + // API only: Secure (no login or pwd) and time limited token + // ?timestamp=12345678&signature=md5(totoblah12345678) + ( yourls_is_API() && + isset( $_REQUEST['timestamp'] ) && !empty($_REQUEST['timestamp'] ) && + isset( $_REQUEST['signature'] ) && !empty($_REQUEST['signature'] ) + ) + { + yourls_do_action( 'pre_login_signature_timestamp' ); + $unfiltered_valid = yourls_check_signature_timestamp(); + } + + elseif + // API only: Secure (no login or pwd) + // ?signature=md5(totoblah) + ( yourls_is_API() && + !isset( $_REQUEST['timestamp'] ) && + isset( $_REQUEST['signature'] ) && !empty( $_REQUEST['signature'] ) + ) + { + yourls_do_action( 'pre_login_signature' ); + $unfiltered_valid = yourls_check_signature(); + } + + elseif + // API or normal: login with username & pwd + ( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) + && !empty( $_REQUEST['username'] ) && !empty( $_REQUEST['password'] ) ) + { + yourls_do_action( 'pre_login_username_password' ); + $unfiltered_valid = yourls_check_username_password(); + } + + elseif + // Normal only: cookies + ( !yourls_is_API() && + isset( $_COOKIE[ yourls_cookie_name() ] ) ) + { + yourls_do_action( 'pre_login_cookie' ); + $unfiltered_valid = yourls_check_auth_cookie(); + } + + // Regardless of validity, allow plugins to filter the boolean and have final word + $valid = yourls_apply_filter( 'is_valid_user', $unfiltered_valid ); + + // Login for the win! + if ( $valid ) { + yourls_do_action( 'login' ); + + // (Re)store encrypted cookie if needed + if ( !yourls_is_API() ) { + yourls_store_cookie( YOURLS_USER ); + + // Login form : redirect to requested URL to avoid re-submitting the login form on page reload + if( isset( $_REQUEST['username'] ) && isset( $_REQUEST['password'] ) && isset( $_SERVER['REQUEST_URI'] ) ) { + // The return makes sure we exit this function before waiting for redirection. // See #3189 and note in yourls_redirect() - return yourls_redirect( yourls_sanitize_url_safe($_SERVER['REQUEST_URI']) ); - } - } + return yourls_redirect( yourls_sanitize_url_safe($_SERVER['REQUEST_URI']) ); + } + } - // Login successful - return true; - } + // Login successful + return true; + } - // Login failed - yourls_do_action( 'login_failed' ); + // Login failed + yourls_do_action( 'login_failed' ); - if ( isset( $_REQUEST['username'] ) || isset( $_REQUEST['password'] ) ) { - return yourls__( 'Invalid username or password' ); - } else { - return yourls__( 'Please log in' ); - } + if ( isset( $_REQUEST['username'] ) || isset( $_REQUEST['password'] ) ) { + return yourls__( 'Invalid username or password' ); + } else { + return yourls__( 'Please log in' ); + } } /** @@ -128,18 +128,18 @@ function yourls_is_valid_user() { * @return bool true if login/pwd pair is valid (and sets user if applicable), false otherwise */ function yourls_check_username_password() { - global $yourls_user_passwords; + global $yourls_user_passwords; - // If login form (not API), check for nonce + // If login form (not API), check for nonce if(!yourls_is_API()) { yourls_verify_nonce('admin_login'); } - if( isset( $yourls_user_passwords[ $_REQUEST['username'] ] ) && yourls_check_password_hash( $_REQUEST['username'], $_REQUEST['password'] ) ) { - yourls_set_user( $_REQUEST['username'] ); - return true; - } - return false; + if( isset( $yourls_user_passwords[ $_REQUEST['username'] ] ) && yourls_check_password_hash( $_REQUEST['username'], $_REQUEST['password'] ) ) { + yourls_set_user( $_REQUEST['username'] ); + return true; + } + return false; } /** @@ -150,24 +150,24 @@ function yourls_check_username_password() { * @return bool */ function yourls_check_password_hash($user, $submitted_password ) { - global $yourls_user_passwords; + global $yourls_user_passwords; - if( !isset( $yourls_user_passwords[ $user ] ) ) - return false; + if( !isset( $yourls_user_passwords[ $user ] ) ) + return false; - if ( yourls_has_phpass_password( $user ) ) { - // Stored password is hashed - list( , $hash ) = explode( ':', $yourls_user_passwords[ $user ] ); - $hash = str_replace( '!', '$', $hash ); - return ( yourls_phpass_check( $submitted_password, $hash ) ); - } else if( yourls_has_md5_password( $user ) ) { - // Stored password is a salted md5 hash: "md5:<$r = rand(10000,99999)>:'; - echo join( "\n", yourls_get_debug_log() ); - echo ''; - } ?> - - - - + + +
'; + echo join( "\n", yourls_get_debug_log() ); + echo ''; + } ?> + +