diff --git a/Dockerfile b/Dockerfile
index 4e88692..4480179 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,6 @@
-FROM wordpress:6.1.0
+ARG wordpress_version
+
+FROM wordpress:$wordpress_version
RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && chmod +x wp-cli.phar && mv wp-cli.phar /usr/local/bin/wp
RUN apt-get update
RUN apt-get -y install vim less
diff --git a/README.md b/README.md
index 72c99b7..99ad51d 100644
--- a/README.md
+++ b/README.md
@@ -71,6 +71,11 @@ container:
compose file. Defaults to the host machine's platform. The image used for the
`db` service does not have `linux/arm64/v8` support. On such hosts (e.g. Apple
Silicon Macs), set this to `linux/amd64`.
+* `WORDPRESS_VERSION`: The WordPress version to use when building the docker
+container. Must be a valid tag per https://hub.docker.com/_/wordpress/tags.
+Defaults to `latest`. Note that only one container at a time is currently
+supported, so when switching versions you'll need to remove the existing
+dev container before running `docker-compose up -d` again.
#### Wordpress CLI
The wordpress installation includes the `wp` command line tool. Note that all
diff --git a/class-duouniversal-settings.php b/class-duouniversal-settings.php
index e87b93d..ce5fce9 100644
--- a/class-duouniversal-settings.php
+++ b/class-duouniversal-settings.php
@@ -1,31 +1,41 @@
duo_utils = $duo_utils;
- $this->wordpress_helper = $duo_utils->wordpress_helper;
+ $this->duo_utils = $duo_utils;
}
function duo_settings_page() {
$this->duo_utils->duo_debug_log( 'Displaying duo setting page' );
?>
Duo Universal Two-Factor Authentication
- wordpress_helper->is_multisite() ) { ?>
+
@@ -33,15 +43,15 @@ function duo_settings_page() {
}
function duo_settings_client_id() {
- $client_id = $this->wordpress_helper->esc_attr( $this->duo_utils->duo_get_option( 'duoup_client_id' ) );
- echo " ";
+ $client_id = \esc_attr( $this->duo_utils->duo_get_option( 'duoup_client_id' ) );
+ echo " ";
}
function duoup_client_id_validate( $client_id ) {
- $client_id = $this->wordpress_helper->sanitize_text_field( $client_id );
+ $client_id = sanitize_text_field( $client_id );
if ( strlen( $client_id ) !== 20 ) {
- $this->wordpress_helper->add_settings_error( 'duoup_client_id', '', 'Client ID is not valid' );
- $current_id = $this->wordpress_helper->esc_attr( $this->duo_utils->duo_get_option( 'duoup_client_id' ) );
+ \add_settings_error( 'duoup_client_id', '', 'Client ID is not valid' );
+ $current_id = \esc_attr( $this->duo_utils->duo_get_option( 'duoup_client_id' ) );
if ( $current_id ) {
return $current_id;
}
@@ -52,26 +62,26 @@ function duoup_client_id_validate( $client_id ) {
}
function duo_settings_client_secret() {
- $client_secret = $this->wordpress_helper->esc_attr( $this->duo_utils->duo_get_option( 'duoup_client_secret' ) );
+ $client_secret = \esc_attr( $this->duo_utils->duo_get_option( 'duoup_client_secret' ) );
if ( $client_secret ) {
$value = SECRET_PLACEHOLDER;
} else {
$value = '';
}
- echo " ";
+ echo " ";
}
function duoup_client_secret_validate( $client_secret ) {
- $client_secret = $this->wordpress_helper->sanitize_text_field( $client_secret );
- $current_secret = $this->wordpress_helper->esc_attr( $this->duo_utils->duo_get_option( 'duoup_client_secret' ) );
+ $client_secret = sanitize_text_field( $client_secret );
+ $current_secret = \esc_attr( $this->duo_utils->duo_get_option( 'duoup_client_secret' ) );
if ( strlen( $client_secret ) !== 40 ) {
- $this->wordpress_helper->add_settings_error( 'duoup_client_secret', '', 'Client secret is not valid' );
+ \add_settings_error( 'duoup_client_secret', '', 'Client secret is not valid' );
if ( $current_secret ) {
return $current_secret;
} else {
return '';
}
- } elseif ( $client_secret === SECRET_PLACEHOLDER ) {
+ } elseif ( SECRET_PLACEHOLDER === $client_secret ) {
return $current_secret;
} else {
return $client_secret;
@@ -79,15 +89,15 @@ function duoup_client_secret_validate( $client_secret ) {
}
function duo_settings_host() {
- $host = $this->wordpress_helper->esc_attr( $this->duo_utils->duo_get_option( 'duoup_api_host' ) );
- echo " ";
+ $host = \esc_attr( $this->duo_utils->duo_get_option( 'duoup_api_host' ) );
+ echo " ";
}
function duoup_api_host_validate( $host ) {
- $host = $this->wordpress_helper->sanitize_text_field( $host );
+ $host = sanitize_text_field( $host );
if ( ! preg_match( '/^api-[a-zA-Z\d\.-]*/', $host ) || str_starts_with( $host, 'api-api-' ) ) {
- $this->wordpress_helper->add_settings_error( 'duoup_api_host', '', 'Host is not valid' );
- $current_host = $this->wordpress_helper->esc_attr( $this->duo_utils->duo_get_option( 'duo_host' ) );
+ \add_settings_error( 'duoup_api_host', '', 'Host is not valid' );
+ $current_host = \esc_attr( $this->duo_utils->duo_get_option( 'duo_host' ) );
if ( $current_host ) {
return $current_host;
}
@@ -98,9 +108,9 @@ function duoup_api_host_validate( $host ) {
}
function duo_settings_failmode() {
- $failmode = $this->wordpress_helper->esc_attr( $this->duo_utils->duo_get_option( 'duoup_failmode', 'open' ) );
+ $failmode = \esc_attr( $this->duo_utils->duo_get_option( 'duoup_failmode', 'open' ) );
echo ' ';
- if ( $failmode === 'open' ) {
+ if ( 'open' === $failmode ) {
echo 'Open ';
echo 'Closed wordpress_helper->sanitize_text_field( $failmode );
- if ( ! in_array( $failmode, array( 'open', 'closed' ) ) ) {
- $this->wordpress_helper->add_settings_error( 'duoup_failmode', '', 'Failmode value is not valid' );
+ $failmode = sanitize_text_field( $failmode );
+ if ( ! in_array( $failmode, array( 'open', 'closed' ), true ) ) {
+ add_settings_error( 'duoup_failmode', '', 'Failmode value is not valid' );
$current_failmode = $this->duo_utils->duo_get_option( 'duoup_failmode', 'open' );
return $current_failmode;
}
@@ -125,7 +135,7 @@ function duo_settings_roles() {
$roles = $wp_roles->get_names();
$newroles = array();
foreach ( $roles as $key => $role ) {
- $newroles[ $this->wordpress_helper->before_last_bar( $key ) ] = $this->wordpress_helper->before_last_bar( $role );
+ $newroles[ \before_last_bar( $key ) ] = \before_last_bar( $role );
}
$selected = $this->duo_utils->duo_get_option( 'duoup_roles', $newroles );
@@ -134,12 +144,12 @@ function duo_settings_roles() {
// create checkbox for each role
echo ( '' .
" wordpress_helper->esc_attr($key)}]' " .
+ "name='duoup_roles[" . \esc_attr( $key ) . "]' " .
"type='checkbox' " .
- "value='{$this->wordpress_helper->esc_attr($role)}' " .
- ( in_array( $role, $selected ) ? 'checked' : '' ) .
+ "value='" . \esc_attr( $role ) . "' " .
+ ( in_array( $role, $selected, true ) ? 'checked' : '' ) .
'/>' .
- $this->wordpress_helper->esc_html( $role ) .
+ \esc_html( $role ) .
' ' );
}
}
@@ -157,7 +167,7 @@ function duoup_roles_validate( $options ) {
if ( ! array_key_exists( $opt, $valid_roles ) ) {
unset( $options[ $opt ] );
} else {
- $options[ $opt ] = $this->wordpress_helper->sanitize_text_field( $value );
+ $options[ $opt ] = sanitize_text_field( $value );
}
}
return $options;
@@ -174,28 +184,28 @@ function duo_settings_xmlrpc() {
if ( $this->duo_utils->duo_get_option( 'duoup_xmlrpc', 'off' ) === 'off' ) {
$val = 'checked';
}
- echo " wordpress_helper->esc_attr($val)} /> Yes ";
+ echo " Yes ';
echo 'Using XML-RPC bypasses two-factor authentication and makes your website less secure. We recommend only using the WordPress web interface for managing your WordPress website.';
}
function duoup_xmlrpc_validate( $option ) {
- $option = $this->wordpress_helper->sanitize_text_field( $option );
- if ( $option === 'off' ) {
+ $option = sanitize_text_field( $option );
+ if ( 'off' === $option ) {
return $option;
}
return 'on';
}
- function duo_add_link( $links, $file ) {
- $settings_link = '' . $this->wordpress_helper->translate( 'Settings', 'duo_universal_wordpress' ) . ' ';
+ function duo_add_link( $links ) {
+ $settings_link = '' . \__( 'Settings', 'duo_universal_wordpress' ) . ' ';
array_unshift( $links, $settings_link );
return $links;
}
function duo_add_page() {
- if ( ! $this->wordpress_helper->is_multisite() ) {
- $this->wordpress_helper->add_options_page( 'Duo Universal Two-Factor', 'Duo Universal Two-Factor', 'manage_options', 'duo_universal_wordpress', array( $this, 'duo_settings_page' ) );
+ if ( ! is_multisite() ) {
+ add_options_page( 'Duo Universal Two-Factor', 'Duo Universal Two-Factor', 'manage_options', 'duo_universal_wordpress', array( $this, 'duo_settings_page' ) );
}
}
@@ -204,18 +214,18 @@ function duo_add_site_option( $option, $value = '' ) {
// Add multisite option only if it doesn't exist already
// With WordPress versions < 3.3, calling add_site_option will override old values
if ( $this->duo_utils->duo_get_option( $option ) === false ) {
- $this->wordpress_helper->add_site_option( $option, $value );
+ \add_site_option( $option, $value );
}
}
function duo_admin_init() {
- if ( $this->wordpress_helper->is_multisite() ) {
+ if ( is_multisite() ) {
$wp_roles = $this->duo_utils->duo_get_roles();
$roles = $wp_roles->get_names();
$allroles = array();
foreach ( $roles as $key => $role ) {
- $allroles[ $this->wordpress_helper->before_last_bar( $key ) ] = $this->wordpress_helper->before_last_bar( $role );
+ $allroles[ \before_last_bar( $key ) ] = \before_last_bar( $role );
}
$this->duo_add_site_option( 'duoup_client_id', '' );
@@ -225,20 +235,20 @@ function duo_admin_init() {
$this->duo_add_site_option( 'duoup_roles', $allroles );
$this->duo_add_site_option( 'duoup_xmlrpc', 'off' );
} else {
- $this->wordpress_helper->add_settings_section( 'duo_universal_settings', 'Main Settings', array( $this, 'duo_settings_text' ), 'duo_universal_settings' );
- $this->wordpress_helper->add_settings_field( 'duoup_client_id', 'Client ID', array( $this, 'duo_settings_client_id' ), 'duo_universal_settings', 'duo_universal_settings' );
- $this->wordpress_helper->add_settings_field( 'duoup_client_secret', 'Client Secret', array( $this, 'duo_settings_client_secret' ), 'duo_universal_settings', 'duo_universal_settings' );
- $this->wordpress_helper->add_settings_field( 'duoup_api_host', 'API hostname', array( $this, 'duo_settings_host' ), 'duo_universal_settings', 'duo_universal_settings' );
- $this->wordpress_helper->add_settings_field( 'duoup_failmode', 'Failmode', array( $this, 'duo_settings_failmode' ), 'duo_universal_settings', 'duo_universal_settings' );
- $this->wordpress_helper->add_settings_field( 'duoup_roles', 'Enable for roles:', array( $this, 'duo_settings_roles' ), 'duo_universal_settings', 'duo_universal_settings' );
- $this->wordpress_helper->add_settings_field( 'duoup_xmlrpc', 'Disable XML-RPC (recommended)', array( $this, 'duo_settings_xmlrpc' ), 'duo_universal_settings', 'duo_universal_settings' );
-
- $this->wordpress_helper->register_setting( 'duo_universal_settings', 'duoup_client_id', array( $this, 'duoup_client_id_validate' ) );
- $this->wordpress_helper->register_setting( 'duo_universal_settings', 'duoup_client_secret', array( $this, 'duoup_client_secret_validate' ) );
- $this->wordpress_helper->register_setting( 'duo_universal_settings', 'duoup_api_host', array( $this, 'duoup_api_host_validate' ) );
- $this->wordpress_helper->register_setting( 'duo_universal_settings', 'duoup_failmode', array( $this, 'duoup_failmode_validate' ) );
- $this->wordpress_helper->register_setting( 'duo_universal_settings', 'duoup_roles', array( $this, 'duoup_roles_validate' ) );
- $this->wordpress_helper->register_setting( 'duo_universal_settings', 'duoup_xmlrpc', array( $this, 'duoup_xmlrpc_validate' ) );
+ \add_settings_section( 'duo_universal_settings', 'Main Settings', array( $this, 'duo_settings_text' ), 'duo_universal_settings' );
+ \add_settings_field( 'duoup_client_id', 'Client ID', array( $this, 'duo_settings_client_id' ), 'duo_universal_settings', 'duo_universal_settings' );
+ \add_settings_field( 'duoup_client_secret', 'Client Secret', array( $this, 'duo_settings_client_secret' ), 'duo_universal_settings', 'duo_universal_settings' );
+ \add_settings_field( 'duoup_api_host', 'API hostname', array( $this, 'duo_settings_host' ), 'duo_universal_settings', 'duo_universal_settings' );
+ \add_settings_field( 'duoup_failmode', 'Failmode', array( $this, 'duo_settings_failmode' ), 'duo_universal_settings', 'duo_universal_settings' );
+ \add_settings_field( 'duoup_roles', 'Enable for roles:', array( $this, 'duo_settings_roles' ), 'duo_universal_settings', 'duo_universal_settings' );
+ \add_settings_field( 'duoup_xmlrpc', 'Disable XML-RPC (recommended)', array( $this, 'duo_settings_xmlrpc' ), 'duo_universal_settings', 'duo_universal_settings' );
+
+ \register_setting( 'duo_universal_settings', 'duoup_client_id', array( $this, 'duoup_client_id_validate' ) );
+ \register_setting( 'duo_universal_settings', 'duoup_client_secret', array( $this, 'duoup_client_secret_validate' ) );
+ \register_setting( 'duo_universal_settings', 'duoup_api_host', array( $this, 'duoup_api_host_validate' ) );
+ \register_setting( 'duo_universal_settings', 'duoup_failmode', array( $this, 'duoup_failmode_validate' ) );
+ \register_setting( 'duo_universal_settings', 'duoup_roles', array( $this, 'duoup_roles_validate' ) );
+ \register_setting( 'duo_universal_settings', 'duoup_xmlrpc', array( $this, 'duoup_xmlrpc_validate' ) );
}
}
@@ -261,39 +271,40 @@ function duo_mu_options() {
function duo_update_mu_options() {
if ( isset( $_POST['duoup_client_id'] ) ) {
- $client_id = $this->duoup_client_id_validate( $_POST['duoup_client_id'] );
- $result = $this->wordpress_helper->update_site_option( 'duoup_client_id', $client_id );
+ $client_id = $this->duoup_client_id_validate( sanitize_text_field( \wp_unslash( $_POST['duoup_client_id'] ) ) );
+ $result = \update_site_option( 'duoup_client_id', $client_id );
}
if ( isset( $_POST['duoup_client_secret'] ) ) {
- $client_secret = $this->duoup_client_secret_validate( $_POST['duoup_client_secret'] );
- $result = $this->wordpress_helper->update_site_option( 'duoup_client_secret', $client_secret );
+ $client_secret = $this->duoup_client_secret_validate( sanitize_text_field( \wp_unslash( $_POST['duoup_client_secret'] ) ) );
+ $result = \update_site_option( 'duoup_client_secret', $client_secret );
}
if ( isset( $_POST['duoup_api_host'] ) ) {
- $host = $this->duoup_api_host_validate( $_POST['duoup_api_host'] );
- $result = $this->wordpress_helper->update_site_option( 'duoup_api_host', $host );
+ $host = $this->duoup_api_host_validate( sanitize_text_field( \wp_unslash( $_POST['duoup_api_host'] ) ) );
+ $result = \update_site_option( 'duoup_api_host', $host );
}
if ( isset( $_POST['duoup_failmode'] ) ) {
- $failmode = $this->duoup_failmode_validate( $_POST['duoup_failmode'] );
- $result = $this->wordpress_helper->update_site_option( 'duoup_failmode', $failmode );
+ $failmode = $this->duoup_failmode_validate( sanitize_text_field( \wp_unslash( $_POST['duoup_failmode'] ) ) );
+ $result = \update_site_option( 'duoup_failmode', $failmode );
} else {
- $result = $this->wordpress_helper->update_site_option( 'duoup_failmode', 'open' );
+ $result = \update_site_option( 'duoup_failmode', 'open' );
}
if ( isset( $_POST['duoup_roles'] ) ) {
- $roles = $this->duoup_roles_validate( $_POST['duoup_roles'] );
- $result = $this->wordpress_helper->update_site_option( 'duoup_roles', $roles );
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ $roles = $this->duoup_roles_validate( \wp_unslash( $_POST['duoup_roles'] ) );
+ $result = \update_site_option( 'duoup_roles', $roles );
} else {
- $result = $this->wordpress_helper->update_site_option( 'duoup_roles', array() );
+ $result = \update_site_option( 'duoup_roles', array() );
}
if ( isset( $_POST['duoup_xmlrpc'] ) ) {
- $xmlrpc = $this->duoup_xmlrpc_validate( $_POST['duoup_xmlrpc'] );
- $result = $this->wordpress_helper->update_site_option( 'duoup_xmlrpc', $xmlrpc );
+ $xmlrpc = $this->duoup_xmlrpc_validate( sanitize_text_field( \wp_unslash( $_POST['duoup_xmlrpc'] ) ) );
+ $result = \update_site_option( 'duoup_xmlrpc', $xmlrpc );
} else {
- $result = $this->wordpress_helper->update_site_option( 'duoup_xmlrpc', 'on' );
+ $result = \update_site_option( 'duoup_xmlrpc', 'on' );
}
}
}
diff --git a/class-duouniversal-utilities.php b/class-duouniversal-utilities.php
index 51909e2..e97a958 100644
--- a/class-duouniversal-utilities.php
+++ b/class-duouniversal-utilities.php
@@ -1,14 +1,20 @@
wordpress_helper = $wordpress_helper;
- }
-
function xmlrpc_enabled() {
return defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST;
}
@@ -16,8 +22,8 @@ function xmlrpc_enabled() {
function duo_get_roles() {
global $wp_roles;
// $wp_roles may not be initially set if WordPress < 3.3
- $wp_roles = isset( $wp_roles ) ? $wp_roles : $this->wordpress_helper->WP_Roles();
- return $wp_roles;
+ $roles = isset( $wp_roles ) ? $wp_roles : \WP_Roles();
+ return $roles;
}
function duo_auth_enabled() {
@@ -26,7 +32,7 @@ function duo_auth_enabled() {
return false; // allows the XML-RPC protocol for remote publishing
}
- if ( $this->duo_get_option( 'duoup_client_id', '' ) === '' || $this->duo_get_option( 'duoup_client_secret', '' ) == ''
+ if ( $this->duo_get_option( 'duoup_client_id', '' ) === '' || $this->duo_get_option( 'duoup_client_secret', '' ) === ''
|| $this->duo_get_option( 'duoup_api_host', '' ) === ''
) {
return false;
@@ -49,7 +55,7 @@ function duo_role_require_mfa( $user ) {
* Don't use get_user_by()
*/
if ( ! isset( $user->roles ) ) {
- $user = $this->wordpress_helper->WP_User( 0, $user->user_login );
+ $user = $this->new_WP_User( 0, $user->user_login );
}
/*
@@ -77,24 +83,31 @@ function duo_get_uri() {
// paths (for which protocols are not required/enforced), and REQUEST_URI
// always includes the leading slash in the URI path.
if ( ! isset( $_SERVER['REQUEST_URI'] )
- || ( ! empty( $_SERVER['QUERY_STRING'] ) && ! strpos( $this->wordpress_helper->sanitize_url( $_SERVER['REQUEST_URI'] ), '?', 0 ) )
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
+ || ( ! empty( $_SERVER['QUERY_STRING'] ) && ! strpos( \sanitize_url( $_SERVER['REQUEST_URI'] ), '?', 0 ) )
) {
- $current_uri = $this->wordpress_helper->sanitize_url( substr( $_SERVER['PHP_SELF'], 1 ) );
+ if ( ! isset( $_SERVER['PHP_SELF'] ) ) {
+ throw new Exception( 'Could not determine request URI' );
+ }
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
+ $current_uri = isset( $_SERVER['PHP_SELF'] ) ? substr( \sanitize_url( $_SERVER['PHP_SELF'] ), 1 ) : null;
if ( isset( $_SERVER['QUERY_STRING'] ) ) {
- $current_uri = $this->wordpress_helper->sanitize_url( $current_uri . '?' . $_SERVER['QUERY_STRING'] );
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
+ $current_uri = \sanitize_url( $current_uri . '?' . $_SERVER['QUERY_STRING'] );
}
return $current_uri;
} else {
- return $this->wordpress_helper->sanitize_url( $_SERVER['REQUEST_URI'] );
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
+ return \sanitize_url( $_SERVER['REQUEST_URI'] );
}
}
- function duo_get_option( $key, $default = '' ) {
- if ( $this->wordpress_helper->is_multisite() ) {
- return $this->wordpress_helper->get_site_option( $key, $default );
+ function duo_get_option( $key, $default_value = '' ) {
+ if ( \is_multisite() ) {
+ return \get_site_option( $key, $default_value );
} else {
- return $this->wordpress_helper->get_option( $key, $default );
+ return \get_option( $key, $default_value );
}
}
@@ -104,4 +117,12 @@ function duo_debug_log( $message ) {
error_log( 'Duo debug: ' . $message );
}
}
+
+ function new_WP_User( $id, $name = '', $site_id = '' ) {
+ return new \WP_User( $id, $name, $site_id );
+ }
+
+ function new_WP_Error( $code, $message = '', $data = '' ) {
+ return new \WP_Error( $code, $message, $data );
+ }
}
diff --git a/class-duouniversal-wordpresshelper.php b/class-duouniversal-wordpresshelper.php
deleted file mode 100644
index d57048c..0000000
--- a/class-duouniversal-wordpresshelper.php
+++ /dev/null
@@ -1,158 +0,0 @@
-duo_client = $duo_client;
- $this->duo_utils = $duo_utils;
- $this->wordpress_helper = $duo_utils->wordpress_helper;
+ $this->duo_client = $duo_client;
+ $this->duo_utils = $duo_utils;
}
- // Sets a user's auth state
- // user: username of the user to update
- // status: whether or not an authentication is in progress or is completed ("in-progress" or "authenticated")
+ /**
+ * Sets a user's auth state
+ * user: username of the user to update
+ * status: whether or not an authentication is in progress or is completed ("in-progress" or "authenticated")
+ **/
function update_user_auth_status( $user, $status, $redirect_url = '', $oidc_state = null ) {
- $this->wordpress_helper->set_transient( 'duo_auth_' . $user . '_status', $status, DUO_TRANSIENT_EXPIRATION );
+ \set_transient( 'duo_auth_' . $user . '_status', $status, DUO_TRANSIENT_EXPIRATION );
if ( $redirect_url ) {
- $this->wordpress_helper->set_transient( 'duo_auth_' . $user . '_redirect_url', $redirect_url, DUO_TRANSIENT_EXPIRATION );
+ \set_transient( 'duo_auth_' . $user . '_redirect_url', $redirect_url, DUO_TRANSIENT_EXPIRATION );
}
if ( $oidc_state ) {
- // we need to track the state in two places so we can clean up later
- $this->wordpress_helper->set_transient( 'duo_auth_' . $user . '_oidc_state', $oidc_state, DUO_TRANSIENT_EXPIRATION );
- $this->wordpress_helper->set_transient( "duo_auth_state_$oidc_state", $user, DUO_TRANSIENT_EXPIRATION );
+ // we need to track the state in two places so we can clean up later.
+ \set_transient( 'duo_auth_' . $user . '_oidc_state', $oidc_state, DUO_TRANSIENT_EXPIRATION );
+ \set_transient( "duo_auth_state_$oidc_state", $user, DUO_TRANSIENT_EXPIRATION );
}
}
@@ -42,7 +53,7 @@ function duo_debug_log( $str ) {
}
function get_user_auth_status( $user ) {
- return $this->wordpress_helper->get_transient( 'duo_auth_' . $user . '_status' );
+ return \get_transient( 'duo_auth_' . $user . '_status' );
}
function duo_verify_auth_status( $user ) {
@@ -50,30 +61,30 @@ function duo_verify_auth_status( $user ) {
}
function get_username_from_oidc_state( $oidc_state ) {
- return $this->wordpress_helper->get_transient( "duo_auth_state_$oidc_state" );
+ return \get_transient( "duo_auth_state_$oidc_state" );
}
function get_redirect_url( $user ) {
- return $this->wordpress_helper->get_transient( 'duo_auth_' . $user . '_redirect_url' );
+ return \get_transient( 'duo_auth_' . $user . '_redirect_url' );
}
function clear_user_auth( $user ) {
$username = $user->user_login;
try {
- $oidc_state = $this->wordpress_helper->get_transient( 'duo_auth_' . $username . '_oidc_state' );
+ $oidc_state = \get_transient( 'duo_auth_' . $username . '_oidc_state' );
- $this->wordpress_helper->delete_transient( 'duo_auth_' . $username . '_status' );
- $this->wordpress_helper->delete_transient( 'duo_auth_' . $username . '_oidc_state' );
- $this->wordpress_helper->delete_transient( "duo_auth_state_$oidc_state" );
- $this->wordpress_helper->delete_transient( 'duo_auth_' . $username . '_redirect_url' );
+ \delete_transient( 'duo_auth_' . $username . '_status' );
+ \delete_transient( 'duo_auth_' . $username . '_oidc_state' );
+ \delete_transient( "duo_auth_state_$oidc_state" );
+ \delete_transient( 'duo_auth_' . $username . '_redirect_url' );
} catch ( Exception $e ) {
- // there's not much we can do but we shouldn't fail the logout because of this
+ // there's not much we can do but we shouldn't fail the logout because of this.
$this->duo_debug_log( $e->getMessage() );
}
}
function clear_current_user_auth() {
- $user = $this->wordpress_helper->wp_get_current_user();
+ $user = \wp_get_current_user();
$this->clear_user_auth( $user );
}
@@ -82,10 +93,20 @@ function get_page_url() {
// the script was queried through HTTPS. However, IIS will set the
// value to 'off' HTTPS was not used, so we have to check that special
// case.
- $https_used = ( ! empty( $_SERVER['HTTPS'] ) && strtolower( $this->wordpress_helper->sanitize_text_field( $_SERVER['HTTPS'] ) ) !== 'off' );
- $port = absint( $_SERVER['SERVER_PORT'] );
- $protocol = ( $https_used || $port === 443 ) ? 'https://' : 'http://';
- return $this->wordpress_helper->sanitize_url( $protocol . $_SERVER['HTTP_HOST'] . $this->duo_utils->duo_get_uri(), array( 'http', 'https' ) );
+ $https_used = ( ! empty( $_SERVER['HTTPS'] ) && strtolower( \sanitize_text_field( wp_unslash( $_SERVER['HTTPS'] ) ) ) !== 'off' );
+
+ if ( ! isset( $_SERVER['SERVER_PORT'] ) ) {
+ throw new Exception( 'Could not determine server port' );
+ }
+
+ $port = isset( $_SERVER['SERVER_PORT'] ) ? absint( $_SERVER['SERVER_PORT'] ) : null;
+ $protocol = ( $https_used || 443 === $port ) ? 'https://' : 'http://';
+
+ if ( ! isset( $_SERVER['HTTP_HOST'] ) ) {
+ throw new Exception( 'Could not determine host' );
+ }
+ $host = ! empty( $_SERVER['HTTP_HOST'] ) ? \sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : null;
+ return \sanitize_url( $protocol . $host . $this->duo_utils->duo_get_uri(), array( 'http', 'https' ) );
}
function exit() {
@@ -104,14 +125,14 @@ function duo_start_second_factor( $user ) {
$this->duo_client->redirect_url = $redirect_url;
$this->update_user_auth_status( $user->user_login, 'in-progress', $redirect_url, $oidc_state );
- $this->wordpress_helper->wp_logout();
+ \wp_logout();
$prompt_uri = $this->duo_client->createAuthUrl( $user->user_login, $oidc_state );
- $this->wordpress_helper->wp_redirect( $prompt_uri );
+ \wp_redirect( $prompt_uri );
$this->exit();
}
function duo_authenticate_user( $user = '', $username = '', $password = '' ) {
- // play nicely with other plugins if they have higher priority than us
+ // play nicely with other plugins if they have higher priority than us.
// if ( is_a( $user, 'WP_User' ) ) {
// return $user;
// }
@@ -122,70 +143,71 @@ function duo_authenticate_user( $user = '', $username = '', $password = '' ) {
}
if ( isset( $_GET['duo_code'] ) ) {
- // secondary auth
+ // doing secondary auth.
if ( isset( $_GET['error'] ) ) {
- $error_msg = $this->wordpress_helper->sanitize_text_field( $_GET['error'] ) . ':' . $this->wordpress_helper->sanitize_text_field( $_GET['error_description'] );
- $error = $this->wordpress_helper->WP_Error(
+ $error_msg = \sanitize_text_field( wp_unslash( $_GET['error'] ) );
+ if ( isset( $_GET['error_description'] ) ) {
+ $error_msg .= ': ' . \sanitize_text_field( wp_unslash( $_GET['error_description'] ) );
+ }
+ $error = $this->duo_utils->new_WP_Error(
'Duo authentication failed',
- $this->wordpress_helper->translate( "ERROR : $error_msg" )
+ // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
+ \__( 'ERROR: ' . $error_msg )
);
- $this->duo_debug_log( $error_msg );
+ $this->duo_debug_log( $error->get_error_message() );
return $error;
}
if ( ! isset( $_GET['state'] ) ) {
- $error_msg = 'Missing state';
- $error = $this->wordpress_helper->WP_Error(
+ $error = $this->duo_utils->new_WP_Error(
'Duo authentication failed',
- $this->wordpress_helper->translate( "ERROR : $error_msg" )
+ \__( 'ERROR: Missing state' )
);
- $this->duo_debug_log( $error_msg );
+ $this->duo_debug_log( $error->get_error_message() );
return $error;
}
$this->duo_debug_log( 'Doing secondary auth' );
- // Get authorization token to trade for 2FA
- $code = $this->wordpress_helper->sanitize_text_field( $_GET['duo_code'] );
+ // Get authorization token to trade for 2FA.
+ $code = \sanitize_text_field( wp_unslash( $_GET['duo_code'] ) );
- // Get state to verify consistency and originality
- $state = $this->wordpress_helper->sanitize_text_field( $_GET['state'] );
+ // Get state to verify consistency and originality.
+ $state = \sanitize_text_field( wp_unslash( $_GET['state'] ) );
- // Retrieve the previously stored state and username from the session
+ // Retrieve the previously stored state and username from the session.
$associated_user = $this->get_username_from_oidc_state( $state );
if ( empty( $associated_user ) ) {
- $error_msg = 'No saved state please login again';
- $error = $this->wordpress_helper->WP_Error(
+ $error = $this->duo_utils->new_WP_Error(
'Duo authentication failed',
- $this->wordpress_helper->translate( "ERROR : $error_msg" )
+ \__( 'ERROR: No saved state please login again' )
);
- $this->duo_debug_log( $error_msg );
+ $this->duo_debug_log( $error->get_error_message() );
return $error;
}
try {
- // Update redirect URL to be one associated with initial authentication
+ // Update redirect URL to be one associated with initial authentication.
$this->duo_client->redirect_url = $this->get_redirect_url( $associated_user );
$decoded_token = $this->duo_client->exchangeAuthorizationCodeFor2FAResult( $code, $associated_user );
} catch ( Duo\DuoUniversal\DuoException $e ) {
$this->duo_debug_log( $e->getMessage() );
- $error_msg = 'Error decoding Duo result. Confirm device clock is correct.';
- $error = $this->wordpress_helper->WP_Error(
+ $error = $this->duo_utils->new_WP_Error(
'Duo authentication failed',
- $this->wordpress_helper->translate( "ERROR : $error_msg" )
+ \__( 'ERROR: Error decoding Duo result. Confirm device clock is correct.' )
);
- $this->duo_debug_log( $error_msg );
+ $this->duo_debug_log( $error->get_error_message() );
return $error;
}
$this->duo_debug_log( "Completed secondary auth for $associated_user" );
$this->update_user_auth_status( $associated_user, 'authenticated' );
- $user = $this->wordpress_helper->WP_User( 0, $associated_user );
+ $user = $this->duo_utils->new_WP_user( 0, $associated_user );
return $user;
}
// if ( strlen( $username ) > 0 ) {
-// // primary auth
-// // Don't use get_user_by(). It doesn't return a WP_User object if WordPress version < 3.3
-// $user = $this->wordpress_helper->WP_User( 0, $username );
+// // primary auth.
+// // Don't use get_user_by(). It doesn't return a WP_User object if WordPress version < 3.3.
+// $user = $this->duo_utils->new_WP_User( 0, $username );
// if ( ! $user ) {
// $this->error_log( "Failed to retrieve WP user $username" );
// return;
@@ -197,15 +219,16 @@ function duo_authenticate_user( $user = '', $username = '', $password = '' ) {
// }
//
// $this->duo_debug_log( 'Doing primary authentication' );
-// $this->wordpress_helper->remove_action( 'authenticate', 'wp_authenticate_username_password', 20 );
-// $user = $this->wordpress_helper->wp_authenticate_username_password( null, $username, $password );
+// \remove_action( 'authenticate', 'wp_authenticate_username_password', 20 );
+//
+// $user = \wp_authenticate_username_password( null, $username, $password );
// if ( ! is_a( $user, 'WP_User' ) ) {
-// // maybe we got an email
-// $user = $this->wordpress_helper->wp_authenticate_email_password( null, $username, $password );
+// // maybe we got an email?
+// $user = \wp_authenticate_email_password( null, $username, $password );
// }
if ( ! is_a( $user, 'WP_User' ) ) {
- // on error, return said error (and skip the remaining plugin chain)
+ // on error, return said error (and skip the remaining plugin chain).
return $user;
} else {
$this->duo_debug_log( "Primary auth succeeded, starting second factor for $username" );
@@ -215,17 +238,16 @@ function duo_authenticate_user( $user = '', $username = '', $password = '' ) {
} catch ( Duo\DuoUniversal\DuoException $e ) {
$this->duo_debug_log( $e->getMessage() );
if ( $this->duo_utils->duo_get_option( 'duoup_failmode' ) === 'open' ) {
- // If we're failing open, errors in 2FA still allow for success
+ // If we're failing open, errors in 2FA still allow for success.
$this->duo_debug_log( "Login 'Successful', but 2FA Not Performed. Confirm Duo client/secret/host values are correct" );
$this->update_user_auth_status( $user->user_login, 'authenticated' );
return $user;
} else {
- $error_msg = '2FA Unavailable. Confirm Duo client/secret/host values are correct';
- $error = $this->wordpress_helper->WP_Error(
- 'Duo authentication_failed',
- $this->wordpress_helper->translate( "Error : $error_msg" )
+ $error = $this->duo_utils->new_WP_Error(
+ 'Duo authentication failed',
+ \__( 'Error: 2FA Unavailable. Confirm Duo client/secret/host values are correct' )
);
- $this->duo_debug_log( $error_msg );
+ $this->duo_debug_log( $error->get_error_message() );
$this->clear_user_auth( $user );
return $error;
}
@@ -235,14 +257,14 @@ function duo_authenticate_user( $user = '', $username = '', $password = '' ) {
// $this->duo_debug_log( 'Starting primary authentication' );
}
+ /**
+ * Verify the user is authenticated with Duo. Start 2FA otherwise
+ */
function duo_verify_auth() {
- /*
- Verify the user is authenticated with Duo. Start 2FA otherwise
- */
if ( ! $this->duo_utils->duo_auth_enabled() ) {
// XXX do we still need this skipping logic?
- if ( $this->wordpress_helper->is_multisite() ) {
- $site_info = $this->wordpress_helper->get_current_site();
+ if ( \is_multisite() ) {
+ $site_info = \get_current_site();
$this->duo_debug_log( 'Duo not enabled on ' . $site_info->site_name );
} else {
$this->duo_debug_log( 'Duo not enabled, skip auth check.' );
@@ -250,8 +272,8 @@ function duo_verify_auth() {
return;
}
- if ( $this->wordpress_helper->is_user_logged_in() ) {
- $user = $this->wordpress_helper->wp_get_current_user();
+ if ( \is_user_logged_in() ) {
+ $user = \wp_get_current_user();
$this->duo_debug_log( "Verifying auth state for user: $user->user_login" );
if ( $this->duo_utils->duo_role_require_mfa( $user ) && ! $this->duo_verify_auth_status( $user->user_login ) ) {
$this->duo_debug_log( "User not authenticated with Duo. Starting second factor for: $user->user_login" );
diff --git a/composer.json b/composer.json
index a0c3c1f..5114bc5 100644
--- a/composer.json
+++ b/composer.json
@@ -15,12 +15,16 @@
"duosecurity/duo_universal_php": ">=1.0.1"
},
"require-dev": {
- "phpunit/phpunit": "^8.0",
- "squizlabs/php_codesniffer": "3.*"
+ "phpunit/phpunit": "^9.0",
+ "squizlabs/php_codesniffer": "3.*",
+ "wp-coding-standards/wpcs": "^3.0",
+ "10up/wp_mock": "^1.0",
+ "mockery/mockery": "^1.6"
},
"config": {
"allow-plugins": {
- "composer/installers": true
+ "composer/installers": true,
+ "dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
diff --git a/composer.lock b/composer.lock
index da1c2e7..92c8918 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "701fdf29593acfbbc3262a1609c1c122",
+ "content-hash": "991a25ed1815de443edb0e8637c74468",
"packages": [
{
"name": "composer/installers",
@@ -260,32 +260,212 @@
}
],
"packages-dev": [
+ {
+ "name": "10up/wp_mock",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/10up/wp_mock.git",
+ "reference": "de812e445e17832703571081aa40f39140497117"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/10up/wp_mock/zipball/de812e445e17832703571081aa40f39140497117",
+ "reference": "de812e445e17832703571081aa40f39140497117",
+ "shasum": ""
+ },
+ "require": {
+ "antecedent/patchwork": "^2.1",
+ "mockery/mockery": "^1.6",
+ "php": ">=7.4 < 8.3",
+ "phpunit/phpunit": "^9.6"
+ },
+ "require-dev": {
+ "behat/behat": "^v3.11.0",
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.7",
+ "friendsofphp/php-cs-fixer": "^3.4",
+ "php-coveralls/php-coveralls": "^v2.5",
+ "php-stubs/wordpress-globals": "^0.2",
+ "php-stubs/wordpress-stubs": "^6.2",
+ "phpcompatibility/php-compatibility": "^9.3",
+ "phpstan/phpstan": "^1.10",
+ "phpstan/phpstan-mockery": "^1.1",
+ "phpstan/phpstan-phpunit": "^1.3",
+ "sebastian/comparator": "^4.0.8",
+ "sempro/phpunit-pretty-print": "^1.4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "WP_Mock\\": "./php/WP_Mock"
+ },
+ "classmap": [
+ "php/WP_Mock.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "A mocking library to take the pain out of unit testing for WordPress",
+ "support": {
+ "issues": "https://github.com/10up/wp_mock/issues",
+ "source": "https://github.com/10up/wp_mock/tree/1.0.0"
+ },
+ "time": "2023-07-26T03:03:21+00:00"
+ },
+ {
+ "name": "antecedent/patchwork",
+ "version": "2.1.26",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/antecedent/patchwork.git",
+ "reference": "f2dae0851b2eae4c51969af740fdd0356d7f8f55"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/antecedent/patchwork/zipball/f2dae0851b2eae4c51969af740fdd0356d7f8f55",
+ "reference": "f2dae0851b2eae4c51969af740fdd0356d7f8f55",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": ">=4"
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ignas Rudaitis",
+ "email": "ignas.rudaitis@gmail.com"
+ }
+ ],
+ "description": "Method redefinition (monkey-patching) functionality for PHP.",
+ "homepage": "http://patchwork2.org/",
+ "keywords": [
+ "aop",
+ "aspect",
+ "interception",
+ "monkeypatching",
+ "redefinition",
+ "runkit",
+ "testing"
+ ],
+ "support": {
+ "issues": "https://github.com/antecedent/patchwork/issues",
+ "source": "https://github.com/antecedent/patchwork/tree/2.1.26"
+ },
+ "time": "2023-09-18T08:18:37+00:00"
+ },
+ {
+ "name": "dealerdirect/phpcodesniffer-composer-installer",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHPCSStandards/composer-installer.git",
+ "reference": "4be43904336affa5c2f70744a348312336afd0da"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da",
+ "reference": "4be43904336affa5c2f70744a348312336afd0da",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0 || ^2.0",
+ "php": ">=5.4",
+ "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0"
+ },
+ "require-dev": {
+ "composer/composer": "*",
+ "ext-json": "*",
+ "ext-zip": "*",
+ "php-parallel-lint/php-parallel-lint": "^1.3.1",
+ "phpcompatibility/php-compatibility": "^9.0",
+ "yoast/phpunit-polyfills": "^1.0"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
+ },
+ "autoload": {
+ "psr-4": {
+ "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Franck Nijhof",
+ "email": "franck.nijhof@dealerdirect.com",
+ "homepage": "http://www.frenck.nl",
+ "role": "Developer / IT Manager"
+ },
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors"
+ }
+ ],
+ "description": "PHP_CodeSniffer Standards Composer Installer Plugin",
+ "homepage": "http://www.dealerdirect.com",
+ "keywords": [
+ "PHPCodeSniffer",
+ "PHP_CodeSniffer",
+ "code quality",
+ "codesniffer",
+ "composer",
+ "installer",
+ "phpcbf",
+ "phpcs",
+ "plugin",
+ "qa",
+ "quality",
+ "standard",
+ "standards",
+ "style guide",
+ "stylecheck",
+ "tests"
+ ],
+ "support": {
+ "issues": "https://github.com/PHPCSStandards/composer-installer/issues",
+ "source": "https://github.com/PHPCSStandards/composer-installer"
+ },
+ "time": "2023-01-05T11:28:13+00:00"
+ },
{
"name": "doctrine/instantiator",
- "version": "1.4.1",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
- "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
+ "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
- "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
+ "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
"shasum": ""
},
"require": {
- "php": "^7.1 || ^8.0"
+ "php": "^8.1"
},
"require-dev": {
- "doctrine/coding-standard": "^9",
+ "doctrine/coding-standard": "^11",
"ext-pdo": "*",
"ext-phar": "*",
- "phpbench/phpbench": "^0.16 || ^1",
- "phpstan/phpstan": "^1.4",
- "phpstan/phpstan-phpunit": "^1",
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
- "vimeo/psalm": "^4.22"
+ "phpbench/phpbench": "^1.2",
+ "phpstan/phpstan": "^1.9.4",
+ "phpstan/phpstan-phpunit": "^1.3",
+ "phpunit/phpunit": "^9.5.27",
+ "vimeo/psalm": "^5.4"
},
"type": "library",
"autoload": {
@@ -312,7 +492,7 @@
],
"support": {
"issues": "https://github.com/doctrine/instantiator/issues",
- "source": "https://github.com/doctrine/instantiator/tree/1.4.1"
+ "source": "https://github.com/doctrine/instantiator/tree/2.0.0"
},
"funding": [
{
@@ -328,20 +508,156 @@
"type": "tidelift"
}
],
- "time": "2022-03-03T08:28:38+00:00"
+ "time": "2022-12-30T00:23:10+00:00"
+ },
+ {
+ "name": "hamcrest/hamcrest-php",
+ "version": "v2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/hamcrest/hamcrest-php.git",
+ "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3",
+ "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3|^7.0|^8.0"
+ },
+ "replace": {
+ "cordoval/hamcrest-php": "*",
+ "davedevelopment/hamcrest-php": "*",
+ "kodova/hamcrest-php": "*"
+ },
+ "require-dev": {
+ "phpunit/php-file-iterator": "^1.4 || ^2.0",
+ "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "hamcrest"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "This is the PHP port of Hamcrest Matchers",
+ "keywords": [
+ "test"
+ ],
+ "support": {
+ "issues": "https://github.com/hamcrest/hamcrest-php/issues",
+ "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1"
+ },
+ "time": "2020-07-09T08:09:16+00:00"
+ },
+ {
+ "name": "mockery/mockery",
+ "version": "1.6.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/mockery/mockery.git",
+ "reference": "b8e0bb7d8c604046539c1115994632c74dcb361e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/mockery/mockery/zipball/b8e0bb7d8c604046539c1115994632c74dcb361e",
+ "reference": "b8e0bb7d8c604046539c1115994632c74dcb361e",
+ "shasum": ""
+ },
+ "require": {
+ "hamcrest/hamcrest-php": "^2.0.1",
+ "lib-pcre": ">=7.0",
+ "php": ">=7.3"
+ },
+ "conflict": {
+ "phpunit/phpunit": "<8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5 || ^9.6.10",
+ "psalm/plugin-phpunit": "^0.18.4",
+ "symplify/easy-coding-standard": "^11.5.0",
+ "vimeo/psalm": "^4.30"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "library/helpers.php",
+ "library/Mockery.php"
+ ],
+ "psr-4": {
+ "Mockery\\": "library/Mockery"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Pádraic Brady",
+ "email": "padraic.brady@gmail.com",
+ "homepage": "https://github.com/padraic",
+ "role": "Author"
+ },
+ {
+ "name": "Dave Marshall",
+ "email": "dave.marshall@atstsolutions.co.uk",
+ "homepage": "https://davedevelopment.co.uk",
+ "role": "Developer"
+ },
+ {
+ "name": "Nathanael Esayeas",
+ "email": "nathanael.esayeas@protonmail.com",
+ "homepage": "https://github.com/ghostwriter",
+ "role": "Lead Developer"
+ }
+ ],
+ "description": "Mockery is a simple yet flexible PHP mock object framework",
+ "homepage": "https://github.com/mockery/mockery",
+ "keywords": [
+ "BDD",
+ "TDD",
+ "library",
+ "mock",
+ "mock objects",
+ "mockery",
+ "stub",
+ "test",
+ "test double",
+ "testing"
+ ],
+ "support": {
+ "docs": "https://docs.mockery.io/",
+ "issues": "https://github.com/mockery/mockery/issues",
+ "rss": "https://github.com/mockery/mockery/releases.atom",
+ "security": "https://github.com/mockery/mockery/security/advisories",
+ "source": "https://github.com/mockery/mockery"
+ },
+ "time": "2023-08-09T00:03:52+00:00"
},
{
"name": "myclabs/deep-copy",
- "version": "1.11.0",
+ "version": "1.11.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
+ "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
- "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
+ "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"shasum": ""
},
"require": {
@@ -379,7 +695,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
},
"funding": [
{
@@ -387,7 +703,63 @@
"type": "tidelift"
}
],
- "time": "2022-03-03T13:19:32+00:00"
+ "time": "2023-03-08T13:26:56+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v4.17.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
+ "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.9-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
+ },
+ "time": "2023-08-13T19:53:39+00:00"
},
{
"name": "phar-io/manifest",
@@ -500,42 +872,182 @@
},
"time": "2022-02-21T01:04:05+00:00"
},
+ {
+ "name": "phpcsstandards/phpcsextra",
+ "version": "1.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHPCSStandards/PHPCSExtra.git",
+ "reference": "746c3190ba8eb2f212087c947ba75f4f5b9a58d5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/746c3190ba8eb2f212087c947ba75f4f5b9a58d5",
+ "reference": "746c3190ba8eb2f212087c947ba75f4f5b9a58d5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4",
+ "phpcsstandards/phpcsutils": "^1.0.8",
+ "squizlabs/php_codesniffer": "^3.7.1"
+ },
+ "require-dev": {
+ "php-parallel-lint/php-console-highlighter": "^1.0",
+ "php-parallel-lint/php-parallel-lint": "^1.3.2",
+ "phpcsstandards/phpcsdevcs": "^1.1.6",
+ "phpcsstandards/phpcsdevtools": "^1.2.1",
+ "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0"
+ },
+ "type": "phpcodesniffer-standard",
+ "extra": {
+ "branch-alias": {
+ "dev-stable": "1.x-dev",
+ "dev-develop": "1.x-dev"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "LGPL-3.0-or-later"
+ ],
+ "authors": [
+ {
+ "name": "Juliette Reinders Folmer",
+ "homepage": "https://github.com/jrfnl",
+ "role": "lead"
+ },
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/PHPCSStandards/PHPCSExtra/graphs/contributors"
+ }
+ ],
+ "description": "A collection of sniffs and standards for use with PHP_CodeSniffer.",
+ "keywords": [
+ "PHP_CodeSniffer",
+ "phpcbf",
+ "phpcodesniffer-standard",
+ "phpcs",
+ "standards",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues",
+ "source": "https://github.com/PHPCSStandards/PHPCSExtra"
+ },
+ "time": "2023-09-20T22:06:18+00:00"
+ },
+ {
+ "name": "phpcsstandards/phpcsutils",
+ "version": "1.0.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHPCSStandards/PHPCSUtils.git",
+ "reference": "69465cab9d12454e5e7767b9041af0cd8cd13be7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/69465cab9d12454e5e7767b9041af0cd8cd13be7",
+ "reference": "69465cab9d12454e5e7767b9041af0cd8cd13be7",
+ "shasum": ""
+ },
+ "require": {
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0",
+ "php": ">=5.4",
+ "squizlabs/php_codesniffer": "^3.7.1 || 4.0.x-dev@dev"
+ },
+ "require-dev": {
+ "ext-filter": "*",
+ "php-parallel-lint/php-console-highlighter": "^1.0",
+ "php-parallel-lint/php-parallel-lint": "^1.3.2",
+ "phpcsstandards/phpcsdevcs": "^1.1.6",
+ "yoast/phpunit-polyfills": "^1.0.5 || ^2.0.0"
+ },
+ "type": "phpcodesniffer-standard",
+ "extra": {
+ "branch-alias": {
+ "dev-stable": "1.x-dev",
+ "dev-develop": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "PHPCSUtils/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "LGPL-3.0-or-later"
+ ],
+ "authors": [
+ {
+ "name": "Juliette Reinders Folmer",
+ "homepage": "https://github.com/jrfnl",
+ "role": "lead"
+ },
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors"
+ }
+ ],
+ "description": "A suite of utility functions for use with PHP_CodeSniffer",
+ "homepage": "https://phpcsutils.com/",
+ "keywords": [
+ "PHP_CodeSniffer",
+ "phpcbf",
+ "phpcodesniffer-standard",
+ "phpcs",
+ "phpcs3",
+ "standards",
+ "static analysis",
+ "tokens",
+ "utility"
+ ],
+ "support": {
+ "docs": "https://phpcsutils.com/",
+ "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues",
+ "source": "https://github.com/PHPCSStandards/PHPCSUtils"
+ },
+ "time": "2023-07-16T21:39:41+00:00"
+ },
{
"name": "phpunit/php-code-coverage",
- "version": "7.0.15",
+ "version": "9.2.29",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "819f92bba8b001d4363065928088de22f25a3a48"
+ "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/819f92bba8b001d4363065928088de22f25a3a48",
- "reference": "819f92bba8b001d4363065928088de22f25a3a48",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
+ "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
"shasum": ""
},
"require": {
"ext-dom": "*",
+ "ext-libxml": "*",
"ext-xmlwriter": "*",
- "php": ">=7.2",
- "phpunit/php-file-iterator": "^2.0.2",
- "phpunit/php-text-template": "^1.2.1",
- "phpunit/php-token-stream": "^3.1.3 || ^4.0",
- "sebastian/code-unit-reverse-lookup": "^1.0.1",
- "sebastian/environment": "^4.2.2",
- "sebastian/version": "^2.0.1",
- "theseer/tokenizer": "^1.1.3"
+ "nikic/php-parser": "^4.15",
+ "php": ">=7.3",
+ "phpunit/php-file-iterator": "^3.0.3",
+ "phpunit/php-text-template": "^2.0.2",
+ "sebastian/code-unit-reverse-lookup": "^2.0.2",
+ "sebastian/complexity": "^2.0",
+ "sebastian/environment": "^5.1.2",
+ "sebastian/lines-of-code": "^1.0.3",
+ "sebastian/version": "^3.0.1",
+ "theseer/tokenizer": "^1.2.0"
},
"require-dev": {
- "phpunit/phpunit": "^8.2.2"
+ "phpunit/phpunit": "^9.3"
},
"suggest": {
- "ext-xdebug": "^2.7.2"
+ "ext-pcov": "PHP extension that provides line coverage",
+ "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "7.0-dev"
+ "dev-master": "9.2-dev"
}
},
"autoload": {
@@ -563,7 +1075,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/7.0.15"
+ "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
},
"funding": [
{
@@ -571,32 +1084,32 @@
"type": "github"
}
],
- "time": "2021-07-26T12:20:09+00:00"
+ "time": "2023-09-19T04:57:46+00:00"
},
{
"name": "phpunit/php-file-iterator",
- "version": "2.0.5",
+ "version": "3.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5"
+ "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5",
- "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
+ "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.3"
},
"require-dev": {
- "phpunit/phpunit": "^8.5"
+ "phpunit/phpunit": "^9.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "3.0-dev"
}
},
"autoload": {
@@ -623,7 +1136,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
- "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.5"
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
},
"funding": [
{
@@ -631,26 +1144,97 @@
"type": "github"
}
],
- "time": "2021-12-02T12:42:26+00:00"
+ "time": "2021-12-02T12:48:52+00:00"
+ },
+ {
+ "name": "phpunit/php-invoker",
+ "version": "3.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+ "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^9.3"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "keywords": [
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T05:58:55+00:00"
},
{
"name": "phpunit/php-text-template",
- "version": "1.2.1",
+ "version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
- "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
+ "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
- "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+ "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
},
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
"autoload": {
"classmap": [
"src/"
@@ -674,37 +1258,135 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
- "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T05:33:50+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "5.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+ "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
},
- "time": "2015-06-21T13:50:34+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-10-26T13:16:10+00:00"
},
{
- "name": "phpunit/php-timer",
- "version": "2.1.3",
+ "name": "phpunit/phpunit",
+ "version": "9.6.13",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662"
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662",
- "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be",
+ "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "doctrine/instantiator": "^1.3.1 || ^2",
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.10.1",
+ "phar-io/manifest": "^2.0.3",
+ "phar-io/version": "^3.0.2",
+ "php": ">=7.3",
+ "phpunit/php-code-coverage": "^9.2.28",
+ "phpunit/php-file-iterator": "^3.0.5",
+ "phpunit/php-invoker": "^3.1.1",
+ "phpunit/php-text-template": "^2.0.3",
+ "phpunit/php-timer": "^5.0.2",
+ "sebastian/cli-parser": "^1.0.1",
+ "sebastian/code-unit": "^1.0.6",
+ "sebastian/comparator": "^4.0.8",
+ "sebastian/diff": "^4.0.3",
+ "sebastian/environment": "^5.1.3",
+ "sebastian/exporter": "^4.0.5",
+ "sebastian/global-state": "^5.0.1",
+ "sebastian/object-enumerator": "^4.0.3",
+ "sebastian/resource-operations": "^3.0.3",
+ "sebastian/type": "^3.2",
+ "sebastian/version": "^3.0.2"
},
- "require-dev": {
- "phpunit/phpunit": "^8.5"
+ "suggest": {
+ "ext-soap": "To be able to generate mocks based on WSDL files",
+ "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
+ "bin": [
+ "phpunit"
+ ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.1-dev"
+ "dev-master": "9.6-dev"
}
},
"autoload": {
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ],
"classmap": [
"src/"
]
@@ -720,48 +1402,58 @@
"role": "lead"
}
],
- "description": "Utility class for timing",
- "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
"keywords": [
- "timer"
+ "phpunit",
+ "testing",
+ "xunit"
],
"support": {
- "issues": "https://github.com/sebastianbergmann/php-timer/issues",
- "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3"
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13"
},
"funding": [
+ {
+ "url": "https://phpunit.de/sponsors.html",
+ "type": "custom"
+ },
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+ "type": "tidelift"
}
],
- "time": "2020-11-30T08:20:02+00:00"
+ "time": "2023-09-19T05:39:22+00:00"
},
{
- "name": "phpunit/php-token-stream",
- "version": "4.0.4",
+ "name": "sebastian/cli-parser",
+ "version": "1.0.1",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3"
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3",
- "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+ "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
"shasum": ""
},
"require": {
- "ext-tokenizer": "*",
- "php": "^7.3 || ^8.0"
+ "php": ">=7.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.0"
+ "phpunit/phpunit": "^9.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "1.0-dev"
}
},
"autoload": {
@@ -776,17 +1468,15 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
}
],
- "description": "Wrapper around PHP's tokenizer extension.",
- "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
- "keywords": [
- "tokenizer"
- ],
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
"support": {
- "issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
- "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
+ "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
},
"funding": [
{
@@ -794,61 +1484,32 @@
"type": "github"
}
],
- "abandoned": true,
- "time": "2020-08-04T08:28:15+00:00"
+ "time": "2020-09-28T06:08:49+00:00"
},
{
- "name": "phpunit/phpunit",
- "version": "8.5.31",
+ "name": "sebastian/code-unit",
+ "version": "1.0.8",
"source": {
"type": "git",
- "url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "33c126b09a42de5c99e5e8032b54e8221264a74e"
+ "url": "https://github.com/sebastianbergmann/code-unit.git",
+ "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33c126b09a42de5c99e5e8032b54e8221264a74e",
- "reference": "33c126b09a42de5c99e5e8032b54e8221264a74e",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
+ "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.3.1",
- "ext-dom": "*",
- "ext-json": "*",
- "ext-libxml": "*",
- "ext-mbstring": "*",
- "ext-xml": "*",
- "ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.10.0",
- "phar-io/manifest": "^2.0.3",
- "phar-io/version": "^3.0.2",
- "php": ">=7.2",
- "phpunit/php-code-coverage": "^7.0.12",
- "phpunit/php-file-iterator": "^2.0.4",
- "phpunit/php-text-template": "^1.2.1",
- "phpunit/php-timer": "^2.1.2",
- "sebastian/comparator": "^3.0.5",
- "sebastian/diff": "^3.0.2",
- "sebastian/environment": "^4.2.3",
- "sebastian/exporter": "^3.1.5",
- "sebastian/global-state": "^3.0.0",
- "sebastian/object-enumerator": "^3.0.3",
- "sebastian/resource-operations": "^2.0.1",
- "sebastian/type": "^1.1.3",
- "sebastian/version": "^2.0.1"
+ "php": ">=7.3"
},
- "suggest": {
- "ext-soap": "*",
- "ext-xdebug": "*",
- "phpunit/php-invoker": "^2.0.0"
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
},
- "bin": [
- "phpunit"
- ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "8.5-dev"
+ "dev-master": "1.0-dev"
}
},
"autoload": {
@@ -867,57 +1528,44 @@
"role": "lead"
}
],
- "description": "The PHP Unit Testing framework.",
- "homepage": "https://phpunit.de/",
- "keywords": [
- "phpunit",
- "testing",
- "xunit"
- ],
+ "description": "Collection of value objects that represent the PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/code-unit",
"support": {
- "issues": "https://github.com/sebastianbergmann/phpunit/issues",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.31"
+ "issues": "https://github.com/sebastianbergmann/code-unit/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
},
"funding": [
- {
- "url": "https://phpunit.de/sponsors.html",
- "type": "custom"
- },
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
- "type": "tidelift"
}
],
- "time": "2022-10-28T05:57:37+00:00"
+ "time": "2020-10-26T13:08:54+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
- "version": "1.0.2",
+ "version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
- "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619"
+ "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619",
- "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+ "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
"shasum": ""
},
"require": {
- "php": ">=5.6"
+ "php": ">=7.3"
},
"require-dev": {
- "phpunit/phpunit": "^8.5"
+ "phpunit/phpunit": "^9.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "2.0-dev"
}
},
"autoload": {
@@ -939,7 +1587,7 @@
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
"support": {
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
- "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2"
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
},
"funding": [
{
@@ -947,34 +1595,34 @@
"type": "github"
}
],
- "time": "2020-11-30T08:15:22+00:00"
+ "time": "2020-09-28T05:30:19+00:00"
},
{
"name": "sebastian/comparator",
- "version": "3.0.5",
+ "version": "4.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770"
+ "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dc7ceb4a24aede938c7af2a9ed1de09609ca770",
- "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
+ "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
"shasum": ""
},
"require": {
- "php": ">=7.1",
- "sebastian/diff": "^3.0",
- "sebastian/exporter": "^3.1"
+ "php": ">=7.3",
+ "sebastian/diff": "^4.0",
+ "sebastian/exporter": "^4.0"
},
"require-dev": {
- "phpunit/phpunit": "^8.5"
+ "phpunit/phpunit": "^9.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -1013,7 +1661,64 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
- "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.5"
+ "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2022-09-14T12:41:17+00:00"
+ },
+ {
+ "name": "sebastian/complexity",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
+ "reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.7",
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
},
"funding": [
{
@@ -1021,33 +1726,33 @@
"type": "github"
}
],
- "time": "2022-09-14T12:31:48+00:00"
+ "time": "2020-10-26T15:52:27+00:00"
},
{
"name": "sebastian/diff",
- "version": "3.0.3",
+ "version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211"
+ "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211",
- "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
+ "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.3"
},
"require-dev": {
- "phpunit/phpunit": "^7.5 || ^8.0",
- "symfony/process": "^2 || ^3.3 || ^4"
+ "phpunit/phpunit": "^9.3",
+ "symfony/process": "^4.2 || ^5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -1079,7 +1784,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
- "source": "https://github.com/sebastianbergmann/diff/tree/3.0.3"
+ "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
},
"funding": [
{
@@ -1087,27 +1792,27 @@
"type": "github"
}
],
- "time": "2020-11-30T07:59:04+00:00"
+ "time": "2023-05-07T05:35:17+00:00"
},
{
"name": "sebastian/environment",
- "version": "4.2.4",
+ "version": "5.1.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0"
+ "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0",
- "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
+ "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.3"
},
"require-dev": {
- "phpunit/phpunit": "^7.5"
+ "phpunit/phpunit": "^9.3"
},
"suggest": {
"ext-posix": "*"
@@ -1115,7 +1820,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.2-dev"
+ "dev-master": "5.1-dev"
}
},
"autoload": {
@@ -1142,7 +1847,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
- "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4"
+ "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
},
"funding": [
{
@@ -1150,34 +1855,34 @@
"type": "github"
}
],
- "time": "2020-11-30T07:53:42+00:00"
+ "time": "2023-02-03T06:03:51+00:00"
},
{
"name": "sebastian/exporter",
- "version": "3.1.5",
+ "version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "73a9676f2833b9a7c36968f9d882589cd75511e6"
+ "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/73a9676f2833b9a7c36968f9d882589cd75511e6",
- "reference": "73a9676f2833b9a7c36968f9d882589cd75511e6",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
+ "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
"shasum": ""
},
"require": {
- "php": ">=7.0",
- "sebastian/recursion-context": "^3.0"
+ "php": ">=7.3",
+ "sebastian/recursion-context": "^4.0"
},
"require-dev": {
"ext-mbstring": "*",
- "phpunit/phpunit": "^8.5"
+ "phpunit/phpunit": "^9.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.1.x-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -1212,14 +1917,14 @@
}
],
"description": "Provides the functionality to export PHP variables for visualization",
- "homepage": "http://www.github.com/sebastianbergmann/exporter",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
- "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.5"
+ "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
},
"funding": [
{
@@ -1227,30 +1932,30 @@
"type": "github"
}
],
- "time": "2022-09-14T06:00:17+00:00"
+ "time": "2022-09-14T06:03:37+00:00"
},
{
"name": "sebastian/global-state",
- "version": "3.0.2",
+ "version": "5.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "de036ec91d55d2a9e0db2ba975b512cdb1c23921"
+ "reference": "bde739e7565280bda77be70044ac1047bc007e34"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/de036ec91d55d2a9e0db2ba975b512cdb1c23921",
- "reference": "de036ec91d55d2a9e0db2ba975b512cdb1c23921",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
+ "reference": "bde739e7565280bda77be70044ac1047bc007e34",
"shasum": ""
},
"require": {
- "php": ">=7.2",
- "sebastian/object-reflector": "^1.1.1",
- "sebastian/recursion-context": "^3.0"
+ "php": ">=7.3",
+ "sebastian/object-reflector": "^2.0",
+ "sebastian/recursion-context": "^4.0"
},
"require-dev": {
"ext-dom": "*",
- "phpunit/phpunit": "^8.0"
+ "phpunit/phpunit": "^9.3"
},
"suggest": {
"ext-uopz": "*"
@@ -1258,7 +1963,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "5.0-dev"
}
},
"autoload": {
@@ -1283,7 +1988,64 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
- "source": "https://github.com/sebastianbergmann/global-state/tree/3.0.2"
+ "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-08-02T09:26:13+00:00"
+ },
+ {
+ "name": "sebastian/lines-of-code",
+ "version": "1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
+ "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.6",
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
},
"funding": [
{
@@ -1291,34 +2053,34 @@
"type": "github"
}
],
- "time": "2022-02-10T06:55:38+00:00"
+ "time": "2020-11-28T06:42:11+00:00"
},
{
"name": "sebastian/object-enumerator",
- "version": "3.0.4",
+ "version": "4.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
- "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2"
+ "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
- "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
+ "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
"shasum": ""
},
"require": {
- "php": ">=7.0",
- "sebastian/object-reflector": "^1.1.1",
- "sebastian/recursion-context": "^3.0"
+ "php": ">=7.3",
+ "sebastian/object-reflector": "^2.0",
+ "sebastian/recursion-context": "^4.0"
},
"require-dev": {
- "phpunit/phpunit": "^6.0"
+ "phpunit/phpunit": "^9.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0.x-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -1340,7 +2102,7 @@
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
- "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4"
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
},
"funding": [
{
@@ -1348,32 +2110,32 @@
"type": "github"
}
],
- "time": "2020-11-30T07:40:27+00:00"
+ "time": "2020-10-26T13:12:34+00:00"
},
{
"name": "sebastian/object-reflector",
- "version": "1.1.2",
+ "version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-reflector.git",
- "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d"
+ "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
- "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+ "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
"shasum": ""
},
"require": {
- "php": ">=7.0"
+ "php": ">=7.3"
},
"require-dev": {
- "phpunit/phpunit": "^6.0"
+ "phpunit/phpunit": "^9.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1-dev"
+ "dev-master": "2.0-dev"
}
},
"autoload": {
@@ -1395,7 +2157,7 @@
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-reflector/issues",
- "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2"
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
},
"funding": [
{
@@ -1403,32 +2165,32 @@
"type": "github"
}
],
- "time": "2020-11-30T07:37:18+00:00"
+ "time": "2020-10-26T13:14:26+00:00"
},
{
"name": "sebastian/recursion-context",
- "version": "3.0.1",
+ "version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb"
+ "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb",
- "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
+ "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
"shasum": ""
},
"require": {
- "php": ">=7.0"
+ "php": ">=7.3"
},
"require-dev": {
- "phpunit/phpunit": "^6.0"
+ "phpunit/phpunit": "^9.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0.x-dev"
+ "dev-master": "4.0-dev"
}
},
"autoload": {
@@ -1455,10 +2217,10 @@
}
],
"description": "Provides functionality to recursively process PHP variables",
- "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+ "homepage": "https://github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
- "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1"
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
},
"funding": [
{
@@ -1466,29 +2228,32 @@
"type": "github"
}
],
- "time": "2020-11-30T07:34:24+00:00"
+ "time": "2023-02-03T06:07:39+00:00"
},
{
"name": "sebastian/resource-operations",
- "version": "2.0.2",
+ "version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/resource-operations.git",
- "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3"
+ "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3",
- "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3",
+ "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+ "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=7.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-master": "3.0-dev"
}
},
"autoload": {
@@ -1510,7 +2275,7 @@
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"support": {
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
- "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2"
+ "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
},
"funding": [
{
@@ -1518,32 +2283,32 @@
"type": "github"
}
],
- "time": "2020-11-30T07:30:19+00:00"
+ "time": "2020-09-28T06:45:17+00:00"
},
{
"name": "sebastian/type",
- "version": "1.1.4",
+ "version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
- "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4"
+ "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0150cfbc4495ed2df3872fb31b26781e4e077eb4",
- "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
+ "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
"shasum": ""
},
"require": {
- "php": ">=7.2"
+ "php": ">=7.3"
},
"require-dev": {
- "phpunit/phpunit": "^8.2"
+ "phpunit/phpunit": "^9.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1-dev"
+ "dev-master": "3.2-dev"
}
},
"autoload": {
@@ -1566,7 +2331,7 @@
"homepage": "https://github.com/sebastianbergmann/type",
"support": {
"issues": "https://github.com/sebastianbergmann/type/issues",
- "source": "https://github.com/sebastianbergmann/type/tree/1.1.4"
+ "source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
},
"funding": [
{
@@ -1574,29 +2339,29 @@
"type": "github"
}
],
- "time": "2020-11-30T07:25:11+00:00"
+ "time": "2023-02-03T06:13:03+00:00"
},
{
"name": "sebastian/version",
- "version": "2.0.1",
+ "version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
- "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
+ "reference": "c6c1022351a901512170118436c764e473f6de8c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
- "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
+ "reference": "c6c1022351a901512170118436c764e473f6de8c",
"shasum": ""
},
"require": {
- "php": ">=5.6"
+ "php": ">=7.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "3.0-dev"
}
},
"autoload": {
@@ -1619,22 +2384,28 @@
"homepage": "https://github.com/sebastianbergmann/version",
"support": {
"issues": "https://github.com/sebastianbergmann/version/issues",
- "source": "https://github.com/sebastianbergmann/version/tree/master"
+ "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
},
- "time": "2016-10-03T07:35:21+00:00"
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2020-09-28T06:39:44+00:00"
},
{
"name": "squizlabs/php_codesniffer",
- "version": "3.7.1",
+ "version": "3.7.2",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
- "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619"
+ "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619",
- "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619",
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879",
+ "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879",
"shasum": ""
},
"require": {
@@ -1670,14 +2441,15 @@
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
"keywords": [
"phpcs",
- "standards"
+ "standards",
+ "static analysis"
],
"support": {
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
},
- "time": "2022-06-18T07:21:10+00:00"
+ "time": "2023-02-22T23:07:41+00:00"
},
{
"name": "theseer/tokenizer",
@@ -1728,6 +2500,72 @@
}
],
"time": "2021-07-28T10:34:58+00:00"
+ },
+ {
+ "name": "wp-coding-standards/wpcs",
+ "version": "3.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
+ "reference": "b4caf9689f1a0e4a4c632679a44e638c1c67aff1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/b4caf9689f1a0e4a4c632679a44e638c1c67aff1",
+ "reference": "b4caf9689f1a0e4a4c632679a44e638c1c67aff1",
+ "shasum": ""
+ },
+ "require": {
+ "ext-filter": "*",
+ "ext-libxml": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlreader": "*",
+ "php": ">=5.4",
+ "phpcsstandards/phpcsextra": "^1.1.0",
+ "phpcsstandards/phpcsutils": "^1.0.8",
+ "squizlabs/php_codesniffer": "^3.7.2"
+ },
+ "require-dev": {
+ "php-parallel-lint/php-console-highlighter": "^1.0.0",
+ "php-parallel-lint/php-parallel-lint": "^1.3.2",
+ "phpcompatibility/php-compatibility": "^9.0",
+ "phpcsstandards/phpcsdevtools": "^1.2.0",
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+ },
+ "suggest": {
+ "ext-iconv": "For improved results",
+ "ext-mbstring": "For improved results"
+ },
+ "type": "phpcodesniffer-standard",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
+ }
+ ],
+ "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
+ "keywords": [
+ "phpcs",
+ "standards",
+ "static analysis",
+ "wordpress"
+ ],
+ "support": {
+ "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues",
+ "source": "https://github.com/WordPress/WordPress-Coding-Standards",
+ "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/thewpcc/contribute/wp-php-63406",
+ "type": "custom"
+ }
+ ],
+ "time": "2023-09-14T07:06:09+00:00"
}
],
"aliases": [],
diff --git a/docker-compose.yml b/docker-compose.yml
index 6ecc1ec..ce09602 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,8 +2,11 @@
version: '3.3'
services:
wordpress:
- image: duo:wordpress
- build: ./
+ image: duo:wordpress-${WORDPRESS_VERSION:-latest}
+ build:
+ context: ./
+ args:
+ wordpress_version: ${WORDPRESS_VERSION:-latest}
restart: always
ports:
- ${HTTP_PORT:-80}:80
diff --git a/duouniversal-wordpress.php b/duouniversal-wordpress.php
new file mode 100644
index 0000000..ee1a3d4
--- /dev/null
+++ b/duouniversal-wordpress.php
@@ -0,0 +1,84 @@
+duo_auth_enabled() ) {
+ try {
+ $duo_client = new Client(
+ $utils->duo_get_option( 'duoup_client_id' ),
+ $utils->duo_get_option( 'duoup_client_secret' ),
+ $utils->duo_get_option( 'duoup_api_host' ),
+ '',
+ );
+ } catch ( Exception $e ) {
+ $utils->duo_debug_log( $e->getMessage() );
+ $duo_client = null;
+ }
+} else {
+ $duo_client = null;
+}
+
+$duoup_plugin = new DuoUniversal_WordpressPlugin(
+ $utils,
+ $duo_client
+);
+
+$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings(
+ $utils
+);
+
+if ( ! \is_multisite() ) {
+ $plugin_name = plugin_basename( __FILE__ );
+ add_filter( 'plugin_action_links_' . $plugin_name, array( $settings, 'duo_add_link' ), 10, 2 );
+}
+
+
+/*-------------XML-RPC Features-----------------*/
+
+if ( $duoup_plugin->duo_utils->duo_get_option( 'duoup_xmlrpc', 'off' ) === 'off' ) {
+ \add_filter( 'xmlrpc_enabled', '__return_false' );
+}
+
+/*-------------Register WordPress Hooks-------------*/
+
+\add_action( 'init', array( $duoup_plugin, 'duo_verify_auth' ), 10 );
+
+\add_action( 'clear_auth_cookie', array( $duoup_plugin, 'clear_current_user_auth' ), 10 );
+
+\add_filter( 'authenticate', array( $plugin, 'duo_authenticate_user' ), 30, 3 );
+
+// add single-site submenu option.
+\add_action( 'admin_menu', array( $settings, 'duo_add_page' ) );
+\add_action( 'admin_init', array( $settings, 'duo_admin_init' ) );
+
+// Custom fields in multi-site network settings.
+\add_action( 'wpmu_options', array( $settings, 'duo_mu_options' ) );
+\add_action( 'update_wpmu_options', array( $settings, 'duo_update_mu_options' ) );
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..7cda7d0
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1 @@
+
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..df5ff20
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,7 @@
+duo_client = $this->createMock(Duo\DuoUniversal\Client::class);
- $this->helper = $this->createMock(Duo\DuoUniversalWordpress\DuoUniversal_WordpressHelper::class);
// For filtering and sanitization methods provided by wordpress,
// simply return the value passed in for filtering unchanged since we
// don't have the wordpress methods in scope
- $this->helper->method('apply_filters')->willReturnArgument(1);
- $this->helper->method('sanitize_url')->willReturnArgument(0);
- $this->helper->method('sanitize_text_field')->willReturnArgument(0);
- $this->helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::passthruFunction('sanitize_url');
+ WP_Mock::passthruFunction('sanitize_text_field');
$this->duo_utils = $this->createMock(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class);
- $this->duo_utils->wordpress_helper = $this->helper;
}
/**
@@ -33,7 +29,7 @@ function testUpdateUserAuthStatus(): void
$callback = function ($key, $value, $expiration) use (&$map) {
$map[$key] = $value;
};
- $this->helper->method('set_transient')->willReturnCallback($callback);
+ WP_Mock::userFunction('set_transient', ['return' => $callback]);
$authentication = new DuoUniversal_WordpressPlugin($this->duo_utils, $this->duo_client);
$authentication->update_user_auth_status("user", "test_status", "redirect", "oidc_state");
$this->assertEquals($map["duo_auth_user_status"], "test_status");
@@ -50,9 +46,9 @@ function testClearAuthException(): void
{
$user = $this->createMock(stdClass::class);
$user->user_login = "test user";
- $this->helper->method('delete_transient')->willThrowException(new Exception());
- $this->helper->method('get_transient')->willReturn('test user');
- $this->helper->method('wp_get_current_user')->willReturn($user);
+ WP_Mock::userFunction('delete_transient', ['return' => function() { throw (new Exception()); } ]);
+ WP_Mock::userFunction('get_transient', ['return' => 'test user']);
+ WP_Mock::userFunction('wp_get_current_user', [ 'return' => $user ]);
$this->duo_utils->expects($this->once())->method('duo_debug_log');
$authentication = new DuoUniversal_WordpressPlugin($this->duo_utils, $this->duo_client);
@@ -75,9 +71,9 @@ function testClearAuthRemovesTransients(): void
$delete_callback = function ($key) use (&$map) {
unset($map[$key]);
};
- $this->helper->method('delete_transient')->willReturnCallback($delete_callback);
- $this->helper->method('get_transient')->willReturn('state');
- $this->helper->method('wp_get_current_user')->willReturn($user);
+ WP_mock::userFunction('delete_transient', ['return' => $delete_callback ]);
+ WP_Mock::userFunction('get_transient', ['return' => 'state']);
+ WP_Mock::userFunction('wp_get_current_user', [ 'return' => $user ]);
$this->duo_utils->expects($this->never())->method('duo_debug_log');
$authentication = new DuoUniversal_WordpressPlugin($this->duo_utils, $this->duo_client);
@@ -98,6 +94,9 @@ function testStartSecondFactorRedirectURL(): void
->onlyMethods(['get_page_url', 'exit'])
->getMock();
$authentication->method('get_page_url')->willReturn('fake url');
+ WP_Mock::passthruFunction('wp_redirect');
+ WP_Mock::passthruFunction('set_transient');
+ WP_Mock::userFunction('wp_logout')->once();
$authentication->duo_start_second_factor($user);
@@ -112,15 +111,16 @@ function testPromptRedirect(): void
$user = $this->createMock(stdClass::class);
$user->user_login = "test user";
$this->duo_client->method('createAuthUrl')->willReturn("prompt url");
- $this->helper->expects($this->once())
- ->method('wp_redirect')
- ->with($this->equalTo("prompt url"));
+ WP_Mock::userFunction('wp_redirect')->with("prompt url")->once();
$authentication = $this->getMockBuilder(DuoUniversal_WordpressPlugin::class)
->setConstructorArgs(array($this->duo_utils, $this->duo_client))
->onlyMethods(['get_page_url', 'exit'])
->getMock();
+ WP_Mock::passthruFunction('set_transient');
+ WP_Mock::userFunction('wp_logout')->once();
$authentication->duo_start_second_factor($user);
+ $this->assertConditionsMet();
}
/**
@@ -139,7 +139,9 @@ function testStartSecondFactorTransients(): void
->onlyMethods(['get_page_url', 'exit'])
->getMock();
$authentication->method('get_page_url')->willReturn("test url");
- $this->helper->method('set_transient')->willReturnCallback($callback);
+ WP_Mock::passthruFunction('wp_redirect');
+ WP_Mock::userFunction('set_transient', ['return' => $callback]);
+ WP_Mock::userFunction('wp_logout')->once();
$this->duo_client->method('generateState')->willReturn("test state");
$authentication->duo_start_second_factor($user);
@@ -161,9 +163,12 @@ function testStartSecondFactorLogout(): void
->setConstructorArgs(array($this->duo_utils, $this->duo_client))
->onlyMethods(['get_page_url', 'exit'])
->getMock();
- $this->helper->expects($this->once())->method('wp_logout');
+ WP_Mock::userFunction('wp_logout')->once();
+ WP_Mock::passthruFunction('set_transient');
+ WP_Mock::passthruFunction('wp_redirect');
$authentication->duo_start_second_factor($user);
+ $this->assertConditionsMet();
}
/**
@@ -178,6 +183,9 @@ function testStartSecondFactorExit(): void
->onlyMethods(['get_page_url', 'exit'])
->getMock();
$authentication->expects($this->once())->method('exit');
+ WP_Mock::passthruFunction('set_transient');
+ WP_Mock::passthruFunction('wp_redirect');
+ WP_Mock::userFunction('wp_logout')->once();
$authentication->duo_start_second_factor($user);
}
@@ -203,6 +211,8 @@ function testUserIsNotAString(): void
$user = $this->getMockBuilder(stdClass::class)
->setMockClassName('WP_User')
->getMock();
+
+ $this->duo_utils->method('new_WP_user')->willReturn($user);
$user->user_login = "test user";
$result = $authentication->duo_authenticate_user($user);
@@ -222,6 +232,7 @@ function testAuthUserAuthNotEnabled(): void
$user = $this->getMockBuilder(stdClass::class)
->setMockClassName('WP_User')
->getMock();
+ $this->duo_utils->method('new_WP_user')->willReturn($user);
$user->user_login = "test user";
$result = $authentication->duo_authenticate_user($user);
@@ -241,15 +252,20 @@ function testAuthUserAPIErrorSet(): void
]
)
->getMock();
+ $error = $this->getMockBuilder(stdClass::class)
+ ->setMockClassName('WP_Error')
+ ->addMethods(["get_error_message"])
+ ->getMock();
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
- $this->helper->method('translate')->willReturnArgument(0);
- $this->helper->method('WP_Error')->willReturnArgument(1);
+ $this->duo_utils->method('new_WP_Error')->willReturn($error)->with("Duo authentication failed", "ERROR: test error: test description");
+ WP_Mock::passthruFunction('__');
+ WP_Mock::passthruFunction('wp_unslash');
$_GET['duo_code'] = "testcode";
$_GET['error'] = "test error";
$_GET['error_description'] = "test description";
$result = $authentication->duo_authenticate_user();
- $this->assertRegExp("/test description/", $result);
+ $this->assertConditionsMet();
}
/**
@@ -265,13 +281,18 @@ function testAuthUserStateMissing(): void
]
)
->getMock();
+ $error = $this->getMockBuilder(stdClass::class)
+ ->setMockClassName('WP_Error')
+ ->addMethods(["get_error_message"])
+ ->getMock();
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
- $this->helper->method('translate')->willReturnArgument(0);
- $this->helper->method('WP_Error')->willReturnArgument(1);
+ $this->duo_utils->method('new_WP_Error')->willReturn($error)->with("Duo authentication failed", "ERROR: Missing state");
+ WP_Mock::passthruFunction('__');
+ WP_Mock::passthruFunction('wp_unslash');
$_GET['duo_code'] = "testcode";
- $result = $authentication->duo_authenticate_user();
- $this->assertRegExp("/Missing state/", $result);
+ $authentication->duo_authenticate_user();
+ $this->assertConditionsMet();
}
/**
@@ -288,16 +309,21 @@ function testAuthUserUserMissing(): void
]
)
->getMock();
+ $error = $this->getMockBuilder(stdClass::class)
+ ->setMockClassName('WP_Error')
+ ->addMethods(["get_error_message"])
+ ->getMock();
$authentication->method('get_username_from_oidc_state')->willReturn(null);
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
- $this->helper->method('translate')->willReturnArgument(0);
- $this->helper->method('WP_Error')->willReturnArgument(1);
+ $this->duo_utils->method('new_WP_Error')->willReturn($error)->with("Duo authentication failed", "ERROR: No saved state please login again");
+ WP_Mock::passthruFunction('__');
+ WP_Mock::passthruFunction('wp_unslash');
$_GET['duo_code'] = "testcode";
$_GET['state'] = "teststate";
- $result = $authentication->duo_authenticate_user();
+ $authentication->duo_authenticate_user();
- $this->assertRegExp("/No saved state/", $result);
+ $this->assertConditionsMet();
}
/**
@@ -315,17 +341,22 @@ function testAuthUserExceptionHandling(): void
]
)
->getMock();
- $this->helper->method('translate')->willReturnArgument(0);
- $this->helper->method('WP_Error')->willReturnArgument(1);
+ $error = $this->getMockBuilder(stdClass::class)
+ ->setMockClassName('WP_Error')
+ ->addMethods(["get_error_message"])
+ ->getMock();
+ WP_Mock::passthruFunction('__');
+ WP_Mock::passthruFunction('wp_unslash');
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
+ $this->duo_utils->method('new_WP_Error')->willReturn($error)->with("Duo authentication failed", "ERROR: Error decoding Duo result. Confirm device clock is correct.");
$authentication->method('get_username_from_oidc_state')->willReturn("test user");
$this->duo_client->method('exchangeAuthorizationCodeFor2FAResult')->willThrowException(new Duo\DuoUniversal\DuoException("there was a problem"));
$_GET['duo_code'] = "testcode";
$_GET['state'] = "teststate";
- $result = $authentication->duo_authenticate_user();
+ $authentication->duo_authenticate_user();
- $this->assertRegExp("/Error decoding Duo result/", $result);
+ $this->assertConditionsMet();
}
/**
@@ -337,7 +368,8 @@ function testAuthUserSuccess(): void
$callback = function ($key, $value, $expiration) use (&$map) {
$map[$key] = $value;
};
- $this->helper->method('set_transient')->willReturnCallback($callback);
+ WP_Mock::userFunction('set_transient', ['return' => $callback]);
+ WP_Mock::passthruFunction('wp_unslash');
$authentication = $this->getMockBuilder(DuoUniversal_WordpressPlugin::class)
->setConstructorArgs(array($this->duo_utils, $this->duo_client))
->onlyMethods(
@@ -350,7 +382,7 @@ function testAuthUserSuccess(): void
->getMock();
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
$authentication->method('get_username_from_oidc_state')->willReturn("test user");
- $this->helper->method("WP_User")->willReturnArgument(1);
+ $this->duo_utils->method('new_WP_user')->willReturnArgument(1);
$_GET['duo_code'] = "testcode";
$_GET['state'] = "teststate";
@@ -399,7 +431,7 @@ function testAuthUserPrimaryNoUser(): void
->getMock();
$authentication->expects($this->once())->method('error_log')->with($this->equalTo("Failed to retrieve WP user test user"));
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
- $this->helper->method('WP_User')->willReturn(null);
+ $this->duo_utils->method('new_WP_user')->willReturn(null);
$result = $authentication->duo_authenticate_user(null, "test user");
}
@@ -424,10 +456,10 @@ function testAuthUserPrimaryEmail(): void
->getMock();
$user->user_login = "test user";
$user->roles = [];
- $this->helper->method('WP_User')->willReturn($user);
- $this->helper->method('wp_authenticate_username_password')->willReturn(null);
- $this->helper->method('wp_authenticate_email_password')->willReturn("EMAIL");
- $this->helper->expects($this->once())->method('wp_authenticate_email_password');
+ $this->duo_utils->method('new_WP_user')->willReturn($user);
+ WP_Mock::userFunction('wp_authenticate_username_password', [ 'return' => null ]);
+ WP_Mock::userFunction('wp_authenticate_email_password', [ 'return' => "EMAIL"])->once();
+ WP_Mock::passthruFunction('remove_action');
$result = $authentication->duo_authenticate_user(null, "test user");
@@ -444,7 +476,7 @@ function testAuthUserPrimaryNo2FARole(): void
$callback = function ($key, $value, $expiration) use (&$map) {
$map[$key] = $value;
};
- $this->helper->method('set_transient')->willReturnCallback($callback);
+ WP_Mock::userFunction('set_transient', ['return' => $callback]);
$authentication = $this->getMockBuilder(DuoUniversal_WordpressPlugin::class)
->setConstructorArgs(array($this->duo_utils, $this->duo_client))
->onlyMethods(
@@ -460,7 +492,7 @@ function testAuthUserPrimaryNo2FARole(): void
->getMock();
$user->user_login = "test user";
$user->roles = [];
- $this->helper->method('WP_User')->willReturn($user);
+ $this->duo_utils->method('new_WP_user')->willReturn($user);
$result = $authentication->duo_authenticate_user(null, "test user");
@@ -488,9 +520,10 @@ function testAuthUserPrimaryErrorValidatingCredentials(): void
->getMock();
$user->user_login = "test user";
$user->roles = [];
- $this->helper->method('WP_User')->willReturn($user);
- $this->helper->method('wp_authenticate_username_password')->willReturn("ERROR");
- $this->helper->method('wp_authenticate_email_password')->willReturn("ERROR");
+ $this->duo_utils->method('new_WP_user')->willReturn($user);
+ WP_Mock::userFunction('wp_authenticate_username_password', [ 'return' => "ERROR" ]);
+ WP_Mock::userFunction('wp_authenticate_email_password', [ 'return' => "ERROR"]);
+ WP_Mock::passthruFunction('remove_action');
$result = $authentication->duo_authenticate_user(null, "test user");
@@ -506,7 +539,7 @@ function testAuthUserPrimaryUpdatesAuthStatus(): void
$callback = function ($key, $value, $expiration) use (&$map) {
$map[$key] = $value;
};
- $this->helper->method('set_transient')->willReturnCallback($callback);
+ WP_Mock::userFunction('set_transient', ['return' => $callback]);
$authentication = $this->getMockBuilder(DuoUniversal_WordpressPlugin::class)
->setConstructorArgs(array($this->duo_utils, $this->duo_client))
->onlyMethods(
@@ -523,8 +556,9 @@ function testAuthUserPrimaryUpdatesAuthStatus(): void
->getMock();
$user->user_login = "test user";
$user->roles = [];
- $this->helper->method('WP_User')->willReturn($user);
- $this->helper->method('wp_authenticate_username_password')->willReturn($user);
+ $this->duo_utils->method('new_WP_user')->willReturn($user);
+ WP_Mock::userFunction('wp_authenticate_username_password', [ 'return' => $user ]);
+ WP_Mock::passthruFunction('remove_action');
$result = $authentication->duo_authenticate_user(null, "test user");
@@ -540,7 +574,7 @@ function testAuthUserSecondaryExceptionFailmodeOpen(): void
$callback = function ($key, $value, $expiration) use (&$map) {
$map[$key] = $value;
};
- $this->helper->method('set_transient')->willReturnCallback($callback);
+ WP_Mock::userFunction('set_transient', ['return' => $callback]);
$authentication = $this->getMockBuilder(DuoUniversal_WordpressPlugin::class)
->setConstructorArgs(array($this->duo_utils, $this->duo_client))
->onlyMethods(
@@ -557,8 +591,9 @@ function testAuthUserSecondaryExceptionFailmodeOpen(): void
->getMock();
$user->user_login = "test user";
$user->roles = [];
- $this->helper->method('WP_User')->willReturn($user);
- $this->helper->method('wp_authenticate_username_password')->willReturn($user);
+ $this->duo_utils->method('new_WP_user')->willReturn($user);
+ WP_Mock::userFunction('wp_authenticate_username_password', [ 'return' => $user ]);
+ WP_Mock::passthruFunction('remove_action');
$this->duo_utils->method('duo_get_option')->willReturn('open');
$result = $authentication->duo_authenticate_user(null, "test user");
@@ -577,8 +612,9 @@ function testAuthUserSecondaryExceptionFailmodeClose(): void
$delete_callback = function ($key) use (&$map) {
unset($map[$key]);
};
- $this->helper->method('set_transient')->willReturnCallback($callback);
- $this->helper->method('delete_transient')->willReturnCallback($delete_callback);
+ WP_Mock::userFunction('set_transient', ['return' => $callback]);
+ WP_Mock::userFunction('delete_transient', ['return' => $delete_callback ]);
+ WP_Mock::passthruFunction('get_transient');
$authentication = $this->getMockBuilder(DuoUniversal_WordpressPlugin::class)
->setConstructorArgs(array($this->duo_utils, $this->duo_client))
->onlyMethods(
@@ -593,18 +629,23 @@ function testAuthUserSecondaryExceptionFailmodeClose(): void
$user = $this->getMockBuilder(stdClass::class)
->setMockClassName('WP_User')
->getMock();
+ $error = $this->getMockBuilder(stdClass::class)
+ ->setMockClassName('WP_Error')
+ ->addMethods(["get_error_message"])
+ ->getMock();
$user->user_login = "test user";
$user->roles = [];
- $this->helper->method('WP_User')->willReturn($user);
- $this->helper->method('WP_Error')->willReturnArgument(1);
- $this->helper->method('translate')->willReturnArgument(0);
- $this->helper->method('wp_authenticate_username_password')->willReturn($user);
+ $this->duo_utils->method('new_WP_user')->willReturn($user);
+ $this->duo_utils->method('new_WP_Error')->willReturn($error)->with("Duo authentication failed", "Error: 2FA Unavailable. Confirm Duo client/secret/host values are correct");
+ WP_Mock::passthruFunction('__');
+ WP_Mock::passthruFunction('remove_action');
+ WP_Mock::userFunction('wp_authenticate_username_password', [ 'return' => $user ]);
$this->duo_utils->method('duo_get_option')->willReturn('closed');
$result = $authentication->duo_authenticate_user(null, "test user");
$this->assertFalse(array_key_exists("duo_auth_test user_status", $map));
- $this->assertRegExp("/2FA Unavailable/", $result);
+ $this->assertConditionsMet();
}
/**
@@ -621,6 +662,7 @@ function testVerifyAuthDisabled(): void
)
->getMock();
$this->duo_utils->method('duo_auth_enabled')->willReturn(false);
+ WP_Mock::userFunction('is_multisite', [ 'return' => false ]);
$authentication->expects($this->once())
->method('duo_debug_log')
->with($this->equalTo("Duo not enabled, skip auth check."));
@@ -628,6 +670,7 @@ function testVerifyAuthDisabled(): void
$result = $authentication->duo_verify_auth();
$this->assertEquals($result, null);
+ $this->assertConditionsMet();
}
/**
@@ -646,8 +689,8 @@ function testVerifyAuthDisabledMultisite(): void
$site = $this->createMock(stdClass::class);
$site->site_name = "test site";
$this->duo_utils->method('duo_auth_enabled')->willReturn(false);
- $this->helper->method('is_multisite')->willReturn(true);
- $this->helper->method('get_current_site')->willReturn($site);
+ WP_Mock::userFunction('is_multisite', [ 'return' => true ]);
+ WP_Mock::userFunction('get_current_site', [ 'return' => $site ]);
$authentication->expects($this->once())
->method('duo_debug_log')
->with($this->equalTo("Duo not enabled on test site"));
@@ -671,7 +714,7 @@ function testVerifyAuthNotLoggedIn(): void
)
->getMock();
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
- $this->helper->method("is_user_logged_in")->willReturn(false);
+ WP_Mock::userFunction('is_user_logged_in', [ 'return' => false ]);
$authentication->expects($this->never())->method('duo_debug_log');
$result = $authentication->duo_verify_auth();
@@ -695,8 +738,8 @@ function testVerifyAuthRoleNotRequire2FA(): void
)
->getMock();
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
- $this->helper->method("is_user_logged_in")->willReturn(true);
- $this->helper->method('wp_get_current_user')->willReturn($user);
+ WP_Mock::userFunction('is_user_logged_in', [ 'return' => true ]);
+ WP_Mock::userFunction('wp_get_current_user', [ 'return' => $user ]);
$this->duo_utils->method('duo_role_require_mfa')->willReturn(false);
$authentication->expects($this->at(1))
->method('duo_debug_log')
@@ -724,8 +767,8 @@ function testVerifyAuthAlreadyVerified(): void
)
->getMock();
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
- $this->helper->method("is_user_logged_in")->willReturn(true);
- $this->helper->method('wp_get_current_user')->willReturn($user);
+ WP_Mock::userFunction('is_user_logged_in', [ 'return' => true ]);
+ WP_Mock::userFunction('wp_get_current_user', [ 'return' => $user ]);
$this->duo_utils->method('duo_role_require_mfa')->willReturn(true);
$authentication->method('duo_verify_auth_status')->willReturn(true);
$authentication->expects($this->at(2))
@@ -754,8 +797,8 @@ function testVerifyAuthNeeds2FA(): void
)
->getMock();
$this->duo_utils->method('duo_auth_enabled')->willReturn(true);
- $this->helper->method("is_user_logged_in")->willReturn(true);
- $this->helper->method('wp_get_current_user')->willReturn($user);
+ WP_Mock::userFunction('is_user_logged_in', [ 'return' => true ]);
+ WP_Mock::userFunction('wp_get_current_user', [ 'return' => $user ]);
$this->duo_utils->method('duo_role_require_mfa')->willReturn(true);
$authentication->method('duo_verify_auth_status')->willReturn(false);
$authentication->expects($this->once())->method('duo_start_second_factor');
diff --git a/tests/duoUniversalSettingsTest.php b/tests/duoUniversalSettingsTest.php
index b0fa339..fc2fab6 100644
--- a/tests/duoUniversalSettingsTest.php
+++ b/tests/duoUniversalSettingsTest.php
@@ -3,25 +3,24 @@
use Duo\DuoUniversal\DuoException;
use Duo\DuoUniversalWordpress;
use PHPUnit\Framework\TestCase;
+use WP_Mock\Tools\TestCase as WPTestCase;
+use WP_Mock;
+
require_once 'class-duouniversal-settings.php';
-require_once 'class-duouniversal-wordpresshelper.php';
-final class SettingsTest extends TestCase
+final class SettingsTest extends WPTestCase
{
function setUp(): void
{
$this->duo_client = $this->createMock(Duo\DuoUniversal\Client::class);
- $this->helper = $this->createMock(Duo\DuoUniversalWordpress\DuoUniversal_WordpressHelper::class);
// For filtering and sanitization methods provided by wordpress,
// simply return the value passed in for filtering unchanged since we
// don't have the wordpress methods in scope
- $this->helper->method('apply_filters')->willReturnArgument(1);
- $this->helper->method('sanitize_url')->willReturnArgument(0);
- $this->helper->method('sanitize_text_field')->willReturnArgument(0);
- $this->helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::passthruFunction('sanitize_url');
+ WP_Mock::passthruFunction('sanitize_text_field');
+ WP_Mock::passthruFunction('esc_attr');
$this->duo_utils = $this->createMock(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class);
- $this->duo_utils->wordpress_helper = $this->helper;
}
/**
@@ -30,10 +29,10 @@ function setUp(): void
*/
public function testSettingsPageMultisite(): void
{
- $this->helper->method('is_multisite')->willReturn(true);
- $this->helper->method('settings_fields')->willReturn(null);
- $this->helper->method('do_settings_sections')->willReturn(null);
- $this->helper->method('esc_attr_e')->willReturn(null);
+ WP_Mock::userFunction('is_multisite', ['return' => true]);
+ WP_Mock::userFunction('settings_fields', ['return' => null]);
+ WP_Mock::userFunction('do_settings_sections', ['return' => null]);
+ WP_Mock::userFunction('esc_attr_e', ['return' => null]);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$settings->duo_settings_page();
@@ -46,10 +45,10 @@ public function testSettingsPageMultisite(): void
*/
public function testSettingsPageSingleSite(): void
{
- $this->helper->method('is_multisite')->willReturn(false);
- $this->helper->method('settings_fields')->willReturn(null);
- $this->helper->method('do_settings_sections')->willReturn(null);
- $this->helper->method('esc_attr_e')->willReturn(null);
+ WP_Mock::userFunction('is_multisite', ['return' => false]);
+ WP_Mock::userFunction('settings_fields', ['return' => null]);
+ WP_Mock::userFunction('do_settings_sections', ['return' => null]);
+ WP_Mock::userFunction('esc_attr_e', ['return' => null]);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$settings->duo_settings_page();
@@ -61,9 +60,9 @@ public function testSettingsPageSingleSite(): void
*/
public function testSettingsClientID(): void
{
- $this->helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::passthruFunction('esc_attr');
+
$duo_utils = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->helper))
->onlyMethods(['duo_get_option'])
->getMock();
$duo_utils->method('duo_get_option')->willReturn("this-is-a-test-value");
@@ -78,7 +77,7 @@ public function testSettingsClientID(): void
*/
public function testDuoClientIDValidateInvalid(): void
{
- $this->helper->method('add_settings_error')->willReturn(null);
+ WP_Mock::userFunction('add_settings_error', ['return' => null]);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$result = $settings->duoup_client_id_validate("invalid id");
@@ -92,8 +91,8 @@ public function testDuoClientIDValidateInvalid(): void
public function testDuoClientIDValidateInvalidNoClear(): void
{
$id = "this is an id";
- $this->helper->method('add_settings_error')->willReturn(null);
- $this->helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::userFunction('add_settings_error', ['return' => null]);
+ WP_Mock::passthruFunction('esc_attr');
$this->duo_utils->method('duo_get_option')->willReturn($id);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
@@ -107,7 +106,7 @@ public function testDuoClientIDValidateInvalidNoClear(): void
*/
public function testDuoClientIDValidateValid(): void
{
- $this->helper->method('add_settings_error')->willReturn(null);
+ WP_Mock::userFunction('add_settings_error', ['return' => null]);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$client_id = "DIXXXXXXXXXXXXXXXXXX";
@@ -121,9 +120,8 @@ public function testDuoClientIDValidateValid(): void
*/
public function testSettingsClientSecret(): void
{
- $this->helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::passthruFunction('esc_attr');
$duo_utils = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->helper))
->onlyMethods(['duo_get_option'])
->getMock();
$duo_utils->method('duo_get_option')->willReturn("this-is-a-fake-secret");
@@ -138,11 +136,10 @@ public function testSettingsClientSecret(): void
*/
public function testDuoClientSecretValidateInvalid(): void
{
- $this->helper->method('add_settings_error')->willReturn(null);
+ WP_Mock::userFunction('add_settings_error', ['return' => null]);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
- $this->helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::passthruFunction('esc_attr');
$duo_utils = $this->createMock(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class);
- $duo_utils->wordpress_helper = $this->helper;
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($duo_utils);
$result = $settings->duoup_client_secret_validate("invalid secret");
@@ -168,11 +165,10 @@ public function testDuoClientSecretValidateDummyDoesntSave(): void
*/
public function testDuoClientSecretValidateValid(): void
{
- $this->helper->method('add_settings_error')->willReturn(null);
- $this->helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::userFunction('add_settings_error', ['return' => null]);
+ WP_Mock::passthruFunction('esc_attr');
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$duo_utils = $this->createMock(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class);
- $duo_utils->wordpress_helper = $this->helper;
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($duo_utils);
$client_secret = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
@@ -186,6 +182,7 @@ public function testDuoClientSecretValidateValid(): void
*/
public function testDuoClientSecretValidateInvalidNoClear(): void
{
+ WP_Mock::userFunction('add_settings_error', ['return' => null]);
$original_secret = "current secret that is 40 character long";
$this->duo_utils->method('duo_get_option')->willReturn($original_secret);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
@@ -215,11 +212,7 @@ public function testDuoHostInvalid(): void
{
$original_host = 'api-duo1.duo.test';
$this->duo_utils->method('duo_get_option')->willReturn($original_host);
- $this->helper->method('add_settings_error')->willReturn(null);
-
- $this->helper->expects($this->once())
- ->method('add_settings_error')
- ->with('duoup_api_host', '', 'Host is not valid');
+ WP_Mock::userFunction('add_settings_error')->once()->with('duoup_api_host', '', 'Host is not valid')->andReturn(null);
// All duo API hostnames start with 'api-'
$invalid_host = 'api.duo.test';
@@ -238,11 +231,7 @@ public function testDuoHostDoubleApiPrefix(): void
{
$original_host = 'api-duo1.duo.test';
$this->duo_utils->method('duo_get_option')->willReturn($original_host);
- $this->helper->method('add_settings_error')->willReturn(null);
-
- $this->helper->expects($this->once())
- ->method('add_settings_error')
- ->with('duoup_api_host', '', 'Host is not valid');
+ WP_Mock::userFunction('add_settings_error')->once()->with('duoup_api_host', '', 'Host is not valid')->andReturn(null);
$invalid_host = 'api-api-duo1.duo.test';
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
@@ -257,9 +246,8 @@ public function testDuoHostDoubleApiPrefix(): void
*/
public function testSettingsHostOutput(): void
{
- $this->helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::passthruFunction('esc_attr');
$duo_utils = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->helper))
->onlyMethods(['duo_get_option'])
->getMock();
$duo_utils->method('duo_get_option')->willReturn("this-is-a-test-host");
@@ -276,9 +264,8 @@ public function testSettingsHostOutput(): void
*/
public function testSettingsFailmode(): void
{
- $this->helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::passthruFunction('esc_attr');
$duo_utils = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->helper))
->onlyMethods(['duo_get_option'])
->getMock();
$duo_utils->method('duo_get_option')->willReturn("closed");
@@ -302,13 +289,12 @@ public function testSettingsRoles(): void
->addMethods(['get_names'])
->getMock();
$roles->method('get_names')->willReturn($duoup_roles);
- $this->helper->method('before_last_bar')->willReturnArgument(0);
+ WP_Mock::passthruFunction('before_last_bar');
$duo_utils = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->helper))
->onlyMethods(['duo_get_option', 'duo_get_roles'])
->getMock();
- $duo_utils->method('duo_get_option')->willReturn(["uses_2fa"]);
+ $duo_utils->method('duo_get_option')->willReturn(["uses_2fa" => true]);
$duo_utils->method('duo_get_roles')->willReturn($roles);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($duo_utils);
@@ -335,16 +321,12 @@ public function testSettingsRoles(): void
*/
public function testDuoSettingsXMLRPC(): void
{
- $helper = $this->getMockBuilder(stdClass::class)
- ->addMethods(['esc_attr'])
- ->getMock();
$duo_utils = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($helper))
->onlyMethods(['duo_get_option'])
->getMock();
$duo_utils->method('duo_get_option')->willReturn('off');
- $helper->method('esc_attr')->willReturnArgument(0);
+ WP_Mock::passthruFunction('esc_attr');
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($duo_utils);
$result = $settings->duo_settings_xmlrpc();
@@ -365,11 +347,7 @@ public function testDuoFailmodeInvalid(): void
{
$original_failmode = 'closed';
$this->duo_utils->method('duo_get_option')->willReturn($original_failmode);
- $this->helper->method('add_settings_error')->willReturn(null);
-
- $this->helper->expects($this->once())
- ->method('add_settings_error')
- ->with('duoup_failmode', '', 'Failmode value is not valid');
+ WP_Mock::userFunction('add_settings_error')->once()->with('duoup_failmode', '', 'Failmode value is not valid')->andReturn(null);
// All duo API hostnames start with 'api-'
$invalid_failmode = 'foobar';
@@ -395,7 +373,7 @@ public function testDuoRolesValidateGood(): void
->getMock();
$roles->method('get_names')->willReturn($duoup_roles);
- $this->helper->method('before_last_bar')->willReturnArgument(0);
+ WP_Mock::passthruFunction('before_last_bar');
$this->duo_utils->method('duo_get_roles')->willReturn($roles);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
@@ -414,7 +392,6 @@ public function testDuoRolesValidateGood(): void
*/
public function testDuoRolesValidateEmpty(): void
{
- $this->duo_utils->wordpress_helper = null;
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$this->assertEmpty($settings->duoup_roles_validate(1));
@@ -436,12 +413,8 @@ public function testDuoRolesValidateBadOptionsAreRemoved(): void
->addMethods(['get_names'])
->getMock();
$roles->method('get_names')->willReturn($duoup_roles);
- $helper = $this->getMockBuilder(stdClass::class)
- ->addMethods(['before_last_bar'])
- ->getMock();
- $helper->method('before_last_bar')->willReturnArgument(0);
+ WP_Mock::passthruFunction('before_last_bar');
$duo_utils = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($helper))
->onlyMethods(['duo_get_roles'])
->getMock();
@@ -462,12 +435,12 @@ public function testDuoRolesValidateBadOptionsAreRemoved(): void
*/
public function testDuoAddPageSingleSite(): void
{
- $this->helper->method('is_multisite')->willReturn(false);
- $this->helper->method('add_options_page');
- $this->helper->expects($this->once())->method('add_options_page');
+ WP_Mock::userFunction('is_multisite', ['return' => false]);
+ WP_Mock::userFunction('add_options_page')->once();
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$settings->duo_add_page();
+ $this->assertConditionsMet();
}
/**
@@ -475,11 +448,12 @@ public function testDuoAddPageSingleSite(): void
*/
public function testDuoAddPageMultisite(): void
{
- $this->helper->method('is_multisite')->willReturn(true);
- $this->helper->expects($this->never())->method('add_options_page');
+ WP_Mock::userFunction('is_multisite', ['return' => true]);
+ WP_Mock::userFunction('add_options_page')->never();
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$settings->duo_add_page();
+ $this->assertConditionsMet();
}
/**
@@ -488,10 +462,11 @@ public function testDuoAddPageMultisite(): void
public function testDuoAddDuplicateSiteOption(): void
{
$this->duo_utils->method('duo_get_option')->willReturn(true);
- $this->helper->expects($this->never())->method('add_site_option');
+ WP_Mock::userFunction('add_site_option')->never();
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$settings->duo_add_site_option("FakeOption");
+ $this->assertConditionsMet();
}
/**
@@ -500,13 +475,11 @@ public function testDuoAddDuplicateSiteOption(): void
public function testDuoAddNewSiteOption(): void
{
$this->duo_utils->method('duo_get_option')->willReturn(false);
- $this->helper
- ->expects($this->once())
- ->method('add_site_option')
- ->with("FakeOption");
+ WP_Mock::userFunction('add_site_option')->once()->with("FakeOption", "");
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$settings->duo_add_site_option("FakeOption");
+ $this->assertConditionsMet();
}
/**
@@ -524,8 +497,8 @@ public function testDuoAdminInitForMultisite(): void
$roles->method('get_names')->willReturn($duoup_roles);
$this->duo_utils->method('duo_get_roles')->willReturn($roles);
- $this->helper->method('is_multisite')->willReturn(true);
- $this->helper->method('before_last_bar')->will($this->returnArgument(0));
+ WP_Mock::userFunction('is_multisite', ['return' => true]);
+ WP_Mock::passthruFunction('before_last_bar');
$settings = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Settings::class)
->setConstructorArgs(array($this->duo_utils))
@@ -552,37 +525,26 @@ public function testDuoAdminInitForMultisite(): void
public function testDuoAdminInitForSingleSite(): void
{
- $this->helper->method('is_multisite')->willReturn(false);
+ WP_Mock::userFunction('is_multisite', ['return' => false]);
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
- $this->helper
- ->expects($this->once())
- ->method('add_settings_section')
- ->withConsecutive(
- ['duo_universal_settings', 'Main Settings', array($settings, 'duo_settings_text'), 'duo_universal_settings']
- );
- $this->helper
- ->expects($this->exactly(6))
- ->method('add_settings_field')
- ->withConsecutive(
- ['duoup_client_id', 'Client ID', array($settings, 'duo_settings_client_id'), 'duo_universal_settings', 'duo_universal_settings'],
- ['duoup_client_secret', 'Client Secret', array($settings, 'duo_settings_client_secret'), 'duo_universal_settings', 'duo_universal_settings'],
- ['duoup_api_host', 'API hostname', array($settings, 'duo_settings_host'), 'duo_universal_settings', 'duo_universal_settings'],
- ['duoup_failmode', 'Failmode', array($settings, 'duo_settings_failmode'), 'duo_universal_settings', 'duo_universal_settings'],
- ['duoup_roles', 'Enable for roles:', array($settings, 'duo_settings_roles'), 'duo_universal_settings', 'duo_universal_settings'],
- ['duoup_xmlrpc', 'Disable XML-RPC (recommended)', array($settings, 'duo_settings_xmlrpc'), 'duo_universal_settings', 'duo_universal_settings']
- );
- $this->helper
- ->expects($this->exactly(6))
- ->method('register_setting')
- ->withConsecutive(
- ['duo_universal_settings', 'duoup_client_id', array($settings, 'duoup_client_id_validate')],
- ['duo_universal_settings', 'duoup_client_secret', array($settings, 'duoup_client_secret_validate')],
- ['duo_universal_settings', 'duoup_api_host'],
- ['duo_universal_settings', 'duoup_failmode'],
- ['duo_universal_settings', 'duoup_roles', array($settings, 'duoup_roles_validate')],
- ['duo_universal_settings', 'duoup_xmlrpc', array($settings, 'duoup_xmlrpc_validate')]
- );
+ WP_Mock::userFunction('add_settings_section')->once()->with('duo_universal_settings', 'Main Settings', array($settings, 'duo_settings_text'), 'duo_universal_settings');
+
+ WP_Mock::userFunction('add_settings_field')->once()->with('duoup_client_id', 'Client ID', array($settings, 'duo_settings_client_id'), 'duo_universal_settings', 'duo_universal_settings');
+ WP_Mock::userFunction('add_settings_field')->once()->with('duoup_client_secret', 'Client Secret', array($settings, 'duo_settings_client_secret'), 'duo_universal_settings', 'duo_universal_settings');
+ WP_Mock::userFunction('add_settings_field')->once()->with('duoup_api_host', 'API hostname', array($settings, 'duo_settings_host'), 'duo_universal_settings', 'duo_universal_settings');
+ WP_Mock::userFunction('add_settings_field')->once()->with('duoup_failmode', 'Failmode', array($settings, 'duo_settings_failmode'), 'duo_universal_settings', 'duo_universal_settings');
+ WP_Mock::userFunction('add_settings_field')->once()->with('duoup_roles', 'Enable for roles:', array($settings, 'duo_settings_roles'), 'duo_universal_settings', 'duo_universal_settings');
+ WP_Mock::userFunction('add_settings_field')->once()->with('duoup_xmlrpc', 'Disable XML-RPC (recommended)', array($settings, 'duo_settings_xmlrpc'), 'duo_universal_settings', 'duo_universal_settings');
+
+ WP_Mock::userFunction('register_setting')->once()->with('duo_universal_settings', 'duoup_client_id', array($settings, 'duoup_client_id_validate'));
+ WP_Mock::userFunction('register_setting')->once()->with('duo_universal_settings', 'duoup_client_secret', array($settings, 'duoup_client_secret_validate'));
+ WP_Mock::userFunction('register_setting')->once()->with('duo_universal_settings', 'duoup_api_host', array($settings, 'duoup_api_host_validate'));
+ WP_Mock::userFunction('register_setting')->once()->with('duo_universal_settings', 'duoup_failmode', array($settings, 'duoup_failmode_validate'));
+ WP_Mock::userFunction('register_setting')->once()->with('duo_universal_settings', 'duoup_roles', array($settings, 'duoup_roles_validate'));
+ WP_Mock::userFunction('register_setting')->once()->with('duo_universal_settings', 'duoup_xmlrpc', array($settings, 'duoup_xmlrpc_validate'));
+
$settings->duo_admin_init();
+ $this->assertConditionsMet();
}
/**
@@ -610,20 +572,18 @@ public function testDuoMultisiteUpdateWithPostValues(): void
'duoup_xmlrpc' => 'off'
);
- $this->helper
- ->expects($this->exactly(6))
- ->method('update_site_option')
- ->withConsecutive(
- ['duoup_client_id', 'DIAAAAAAAAAAAAAAAAAA'],
- ['duoup_client_secret', str_repeat('aBc123As3cr3t4uandme', 2)],
- ['duoup_api_host', 'api-duo1.duo.test'],
- ['duoup_failmode', 'closed'],
- ['duoup_roles', $duoup_roles],
- ['duoup_xmlrpc', 'off'],
- );
+ WP_Mock::userFunction('update_site_option')->once()->with('duoup_client_id', 'DIAAAAAAAAAAAAAAAAAA');
+ WP_Mock::userFunction('update_site_option')->once()->with('duoup_client_secret', str_repeat('aBc123As3cr3t4uandme', 2));
+ WP_Mock::userFunction('update_site_option')->once()->with('duoup_api_host', 'api-duo1.duo.test');
+ WP_Mock::userFunction('update_site_option')->once()->with('duoup_failmode', 'closed');
+ WP_Mock::userFunction('update_site_option')->once()->with('duoup_roles', $duoup_roles);
+ WP_Mock::userFunction('update_site_option')->once()->with('duoup_xmlrpc', 'off');
+ WP_Mock::passthruFunction('wp_unslash');
+
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$settings->duo_update_mu_options();
$_POST = $this->old_POST;
+ $this->assertConditionsMet();
}
/**
@@ -631,16 +591,13 @@ public function testDuoMultisiteUpdateWithPostValues(): void
*/
public function testDuoMultisiteUpdateWithEmptyPostValue(): void
{
- $this->helper
- ->expects($this->exactly(3))
- ->method('update_site_option')
- ->withConsecutive(
- ['duoup_failmode', 'open'],
- ['duoup_roles', []],
- ['duoup_xmlrpc', 'on'],
- );
+ WP_Mock::userFunction('update_site_option')->once()->with('duoup_failmode', 'open');
+ WP_Mock::userFunction('update_site_option')->once()->with('duoup_roles', []);
+ WP_Mock::userFunction('update_site_option')->once()->with('duoup_xmlrpc', 'on');
+
$settings = new Duo\DuoUniversalWordpress\DuoUniversal_Settings($this->duo_utils);
$settings->duo_update_mu_options();
+ $this->assertConditionsMet();
}
}
diff --git a/tests/duoUniversalUtilitiesTest.php b/tests/duoUniversalUtilitiesTest.php
index 906961e..3fcf24a 100644
--- a/tests/duoUniversalUtilitiesTest.php
+++ b/tests/duoUniversalUtilitiesTest.php
@@ -4,16 +4,9 @@
use Duo\DuoUniversalWordpress;
use PHPUnit\Framework\TestCase;
require_once 'class-duouniversal-utilities.php';
-require_once 'class-duouniversal-wordpresshelper.php';
final class UtilitiesTest extends TestCase
{
- protected function setUp(): void
- {
- $helper = new Duo\DuoUniversalWordpress\DuoUniversal_WordpressHelper();
- $this->wordpress_helper = $helper;
- }
-
/**
* Test that test_duo_auth_enabled returns false
* when XMLRPC_REQUEST is defined
@@ -21,7 +14,6 @@ protected function setUp(): void
public function testDuoAuthXMLRPCEnabled(): void
{
$command = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->wordpress_helper))
->onlyMethods(['xmlrpc_enabled'])
->getMock();
$command->method('xmlrpc_enabled')->willReturn(true);
@@ -37,7 +29,6 @@ public function testDuoAuthXMLRPCEnabled(): void
public function testDuoAuthMissingOptions(): void
{
$command = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->wordpress_helper))
->onlyMethods(['duo_debug_log', 'duo_get_option'])
->getMock();
$command->method('duo_get_option')->willReturn('');
@@ -53,7 +44,6 @@ public function testDuoAuthMissingOptions(): void
public function testDuoAuthHappyPath(): void
{
$command = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->wordpress_helper))
->onlyMethods(['duo_debug_log', 'duo_get_option', 'xmlrpc_enabled'])
->getMock();
$command->method('duo_get_option')->willReturn(true);
@@ -79,7 +69,6 @@ public function testDuoRoleRequireMFAEmpty(): void
);
$command = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->wordpress_helper))
->onlyMethods(['duo_get_option', 'duo_get_roles'])
->getMock();
$command->method('duo_get_option')->willReturn([]);
@@ -106,7 +95,6 @@ public function testDuoRoleRequireRoleDisabled(): void
$roles->method('get_names')->willReturn($duoup_roles);
$command = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->wordpress_helper))
->onlyMethods(['duo_get_roles', 'duo_get_option'])
->getMock();
$command->method('duo_get_option')->willReturn($duoup_roles);
@@ -133,7 +121,6 @@ public function testDuoRoleRequireRoleEnabled(): void
$roles->method('get_names')->willReturn($duoup_roles);
$command = $this->getMockBuilder(Duo\DuoUniversalWordpress\DuoUniversal_Utilities::class)
- ->setConstructorArgs(array($this->wordpress_helper))
->onlyMethods(['duo_get_roles', 'duo_get_option'])
->getMock();
$command->method('duo_get_option')->willReturn($duoup_roles);
@@ -151,13 +138,10 @@ public function testDuoRoleRequireRoleEnabled(): void
*/
public function testDuoGetOptionSingleSite(): void
{
- $helper = $this->getMockBuilder(stdClass::class)
- ->addMethods(['is_multisite', 'get_option'])
- ->getMock();
- $helper->method('is_multisite')->willReturn(false);
- $helper->expects($this->once())->method('get_option')->willReturn("value");
+ WP_Mock::userFunction('is_multisite', [ 'return' => false ]);
+ WP_Mock::userFunction('get_option', [ 'return' => "value" ])->once();
- $duo_utils = new Duo\DuoUniversalWordpress\DuoUniversal_Utilities($helper);
+ $duo_utils = new Duo\DuoUniversalWordpress\DuoUniversal_Utilities();
$this->assertEquals($duo_utils->duo_get_option("test"), 'value');
}
@@ -167,13 +151,10 @@ public function testDuoGetOptionSingleSite(): void
*/
public function testDuoGetOptionMultiSite(): void
{
- $helper = $this->getMockBuilder(stdClass::class)
- ->addMethods(['is_multisite', 'get_site_option'])
- ->getMock();
- $helper->method('is_multisite')->willReturn(true);
- $helper->expects($this->once())->method('get_site_option')->willReturn("value");
+ WP_Mock::userFunction('is_multisite', [ 'return' => true ]);
+ WP_Mock::userFunction('get_site_option', [ 'return' => "value" ])->once();
- $duo_utils = new Duo\DuoUniversalWordpress\DuoUniversal_Utilities($helper);
+ $duo_utils = new Duo\DuoUniversalWordpress\DuoUniversal_Utilities();
$this->assertEquals($duo_utils->duo_get_option("test"), 'value');
}
}
diff --git a/uninstall.php b/uninstall.php
index 1ce354a..9385f78 100644
--- a/uninstall.php
+++ b/uninstall.php
@@ -1,4 +1,16 @@