sirius-press/plugins/sirius-press-auth/sirius-press-auth.php
Local Dev c403a42904 sirius-press: let the sign-in screen move off wp-login.php
wp-login.php is the most-requested path on the internet. There is no
password here to guess, so this is not about brute force — it is that a
wallet login screen answering that path tells every scanner that goes
past exactly what is running, and serves a few hundred bots a day a page
they cannot use.

Setting a login address moves the screen and makes wp-login.php answer
404 through the theme's own template. A 404 and not a redirect: a
redirect would hand the new address to the first scanner that asked for
the old one. Everything that builds a login URL follows it, because they
all go through site_url() or network_site_url() with a wp-login.php
path, and there is a wp_redirect backstop for code that builds the URL
by hand.

Refusing wp-login.php has to happen at wp_loaded and has to end the
request there. The web server sends that path to the file directly
rather than through index.php, so by the time anything of ours runs we
are already inside its require of wp-load.php — rewriting $pagenow
changes what WordPress thinks the request is, but it does not stop the
script that is already running.

What this does not do is rename wp-admin. WordPress has no supported way
to, and faking it with a proxy and a filtered admin_url() gets most of
the way before breaking plugins quietly. Breaking plugins is the one
thing this fork promises not to do, so the setting says as much on the
screen rather than implying more than it delivers.
2026-10-03 18:42:45 +02:00

84 lines
2.8 KiB
PHP

<?php
/**
* Plugin Name: Sirius Press Auth
* Plugin URI: https://code.silentmode.st/silentmode/sirius-press
* Description: Sign in by signing a challenge with a Bitcoin Cash wallet. Replaces email as the account identity; leaves roles, capabilities and sessions exactly as WordPress made them.
* Version: 0.1.0
* Requires at least: 6.5
* Requires PHP: 7.4
* Requires Plugins: sirius-press-core
* Author: Silent Mode
* Author URI: https://silentmode.st
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: sirius-press
*
* @package SiriusPress
*/
defined( 'ABSPATH' ) || exit;
define( 'SIRIUS_PRESS_AUTH_VERSION', '0.2.0' );
define( 'SIRIUS_PRESS_AUTH_DIR', plugin_dir_path( __FILE__ ) );
define( 'SIRIUS_PRESS_AUTH_URL', plugin_dir_url( __FILE__ ) );
/*
* The login address is decided before everything else, and outside the
* `plugins_loaded` callback below, because it has to hook `plugins_loaded`
* itself at a priority earlier than that callback runs. It depends on nothing
* but WordPress, so there is nothing to wait for.
*/
require_once SIRIUS_PRESS_AUTH_DIR . 'includes/class-spa-login-url.php';
SPA_Login_URL::hooks();
add_action(
'plugins_loaded',
function () {
// `Requires Plugins` keeps this from being activated without the core
// plugin, but an installation can still be mid-upgrade or have core
// deactivated by hand. Failing with a notice beats a fatal on the
// login screen, which would lock everyone out of the site.
if ( ! class_exists( 'SP_Message' ) ) {
add_action(
'admin_notices',
function () {
printf(
'<div class="notice notice-error"><p>%s</p></div>',
esc_html__( 'Sirius Press Auth needs Sirius Press Core to be active. Wallet sign-in is off until it is.', 'sirius-press' )
);
}
);
return;
}
foreach ( array( 'challenge', 'login', 'register', 'recovery', 'rest', 'profile', 'settings' ) as $part ) {
require_once SIRIUS_PRESS_AUTH_DIR . 'includes/class-spa-' . $part . '.php';
}
SPA_Login::hooks();
SPA_Register::hooks();
SPA_Recovery::hooks();
SPA_REST::hooks();
SPA_Profile::hooks();
SPA_Settings::hooks();
},
5
);
/**
* Ask the current user to re-prove their key before something irreversible.
*
* Intended for other plugins: hand it a purpose string and it returns the
* challenge to render; verify the answer with the `/sirius-press/v1/confirm`
* endpoint. Exposed as a plain function so a plugin does not have to know
* this fork's class names to use it.
*
* @return array{nonce:string,message:string}
*/
function sirius_press_confirmation_challenge() {
$nonce = SPA_Challenge::issue();
return array(
'nonce' => $nonce,
'message' => SPA_Challenge::message( $nonce, SPA_Challenge::PURPOSE_CONFIRM ),
);
}