Some checks are pending
CI / PHP lint (7.4) (pull_request) Waiting to run
CI / PHP lint (8.0) (pull_request) Waiting to run
CI / PHP lint (8.1) (pull_request) Waiting to run
CI / PHP lint (8.2) (pull_request) Waiting to run
CI / PHP lint (8.3) (pull_request) Waiting to run
CI / PHP lint (8.4) (pull_request) Waiting to run
CI / WordPress Coding Standards (pull_request) Waiting to run
CI / WordPress.org Plugin Check (pull_request) Waiting to run
Privileged accounts are never linked through the settable mail attribute. Two new ways make that workable when UPN and e-mail differ: - "Link Microsoft account" on the profile screen: the signed-in user (nonce, same browser via the state cookie, same user at the callback) signs in with Microsoft once and binds that identity. Existing links can only be removed by an administrator; an object ID bound elsewhere is refused. - "Assigned Microsoft account (UPN)" per user, editable by administrators, used by sign-in and user sync; with an option to remove a link. Sign-in now finds accounts by bound object ID first, then by assigned UPN, then by e-mail, so linked users sign in whatever their addresses. Also: third-audit report (docs/security-audit.md section 7), README section on linking administrator accounts, translations, tests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
69 lines
2.4 KiB
PHP
69 lines
2.4 KiB
PHP
<?php
|
|
/**
|
|
* Removes all plugin data on uninstall.
|
|
*
|
|
* @package M365_Login
|
|
*/
|
|
|
|
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
|
|
exit;
|
|
}
|
|
|
|
global $wpdb;
|
|
|
|
/**
|
|
* Deletes options, transients and user meta for one site.
|
|
*/
|
|
function m365_login_uninstall_site() {
|
|
global $wpdb;
|
|
|
|
// Cached Graph app token (may live in a persistent object cache instead of the options table).
|
|
$settings = get_option( 'm365_login_settings', array() );
|
|
if ( is_array( $settings ) && ! empty( $settings['client_id'] ) ) {
|
|
$tenant = ! empty( $settings['tenant_id'] ) ? $settings['tenant_id'] : 'organizations';
|
|
foreach ( array( 'secret', 'certificate' ) as $method ) {
|
|
delete_transient( 'm365_login_apptoken_' . md5( $tenant . '|' . $settings['client_id'] . '|' . $method ) );
|
|
}
|
|
}
|
|
|
|
delete_option( 'm365_login_settings' );
|
|
delete_option( 'm365_login_sync_lock' );
|
|
delete_option( 'm365_login_version' );
|
|
delete_option( 'm365_login_sync_report' );
|
|
wp_clear_scheduled_hook( 'm365_login_sync' );
|
|
|
|
// Synced profile photos (uploads/m365-login-avatars/).
|
|
$uploads = wp_get_upload_dir();
|
|
$dir = trailingslashit( $uploads['basedir'] ) . 'm365-login-avatars';
|
|
if ( is_dir( $dir ) ) {
|
|
foreach ( (array) glob( $dir . '/m365-*' ) as $file ) {
|
|
wp_delete_file( $file );
|
|
}
|
|
@rmdir( $dir ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- best effort, may contain foreign files.
|
|
}
|
|
|
|
// Transients: state records and JWKS cache.
|
|
$wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
|
|
$wpdb->prepare(
|
|
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
|
|
$wpdb->esc_like( '_transient_m365_login_' ) . '%',
|
|
$wpdb->esc_like( '_transient_timeout_m365_login_' ) . '%'
|
|
)
|
|
);
|
|
}
|
|
|
|
if ( is_multisite() ) {
|
|
$m365_login_site_ids = get_sites( array( 'fields' => 'ids', 'number' => 0 ) );
|
|
foreach ( $m365_login_site_ids as $m365_login_site_id ) {
|
|
switch_to_blog( $m365_login_site_id );
|
|
m365_login_uninstall_site();
|
|
restore_current_blog();
|
|
}
|
|
} else {
|
|
m365_login_uninstall_site();
|
|
}
|
|
|
|
// User meta is global. Imported accounts stay; copied profile fields (m365_*) are kept as ordinary user data.
|
|
foreach ( array( '_m365_login_oid', '_m365_login_last_login', '_m365_login_synced', '_m365_login_disabled', '_m365_login_last_sync', '_m365_login_photo', '_m365_login_tid', '_m365_login_upn' ) as $m365_login_meta_key ) {
|
|
delete_metadata( 'user', 0, $m365_login_meta_key, '', true );
|
|
}
|