get_record( $guardforge_user_id ); // On a fresh GET to the enrol page, mint a one-time secret kept ONLY for the // duration of this form submission. We never persist a secret a user hasn't // confirmed via a matching TOTP code. $guardforge_enrol_secret = ''; $guardforge_enrol_uri = ''; $guardforge_enrol_qr = ''; $guardforge_codes = GUARDFORGE_Two_Factor::read_transient( GUARDFORGE_Two_Factor::CODES_TRANSIENT, GUARDFORGE_Two_Factor::LEGACY_CODES_TRANSIENT, $guardforge_user_id ); if ( $guardforge_codes ) { GUARDFORGE_Two_Factor::forget_transient( GUARDFORGE_Two_Factor::CODES_TRANSIENT, GUARDFORGE_Two_Factor::LEGACY_CODES_TRANSIENT, $guardforge_user_id ); } if ( ! $guardforge_record ) { $guardforge_enrol_secret = GUARDFORGE_Totp::generate_secret(); $current_user = wp_get_current_user(); // The otpauth:// URI is handed to the user, never to a third party. An // earlier version rendered a QR through a third-party QR service — that shipped // this account's TOTP secret to someone else's server. Enrolment makes no // outbound request of any kind. (Since 1.2.0 one screen in the free // package can: "Explain this event" posts a log row when an administrator // presses it. Nothing on this page does, and a shared secret is the last // thing that ever should.) $guardforge_enrol_uri = GUARDFORGE_Totp::provisioning_uri( $guardforge_enrol_secret, $current_user->user_email, get_bloginfo( 'name' ) ); // A site name long enough to push the URI past 213 bytes would throw, and // a fatal on the enrolment screen is worse than no QR — the key below it // still enrols the account by hand. try { $guardforge_enrol_qr = GUARDFORGE_QR::svg( $guardforge_enrol_uri, [ 'label' => __( 'Two-factor enrolment QR code', 'guardforge' ) ] ); } catch ( Exception $e ) { $guardforge_enrol_qr = ''; } } ?>
✓
⚠

' . wp_kses( $guardforge_enrol_qr, GUARDFORGE_Admin_Header::allowed_svg() ) . '
'; ?>

enrolled_at ); ?>

last_used_at ? esc_html( $guardforge_record->last_used_at ) : esc_html__( 'never', 'guardforge' ); ?>

render_policy_card(); ?>