tigerstyle-scent/tigerstyle-scent.php
Ryan Malloy 120f0b616d Add release tooling and update for v1.0.0 release
- Add .distignore (operator-private files excluded)
- Add build.sh for WordPress-installable release ZIPs
- Update CLAUDE.md references (now operator-private only)
2026-05-27 14:32:07 -06:00

605 lines
22 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Plugin Name: TigerStyle Scent
* Plugin URI: https://tigerstyle.com/scent-plugin
* Description: Enterprise OAuth2 authentication server - leave your digital scent trail for secure access control. Like cats authenticate each other through scent, TigerStyle Scent provides secure OAuth2 authentication for your WordPress territory.
* Version: 1.0.0
* Author: TigerStyle
* Author URI: https://tigerstyle.com
* License: GPL v2 or later
* Text Domain: tigerstyle-scent
* Domain Path: /languages
* Requires at least: 5.0
* Tested up to: 6.4
* Requires PHP: 7.4
* Network: false
*/
// Prevent direct access to maintain territory security
defined('ABSPATH') or die('🐯 Direct access to TigerStyle territory forbidden.');
// Plugin constants for scent trail management
define('TIGERSTYLE_SCENT_VERSION', '1.0.0');
define('TIGERSTYLE_SCENT_PLUGIN_FILE', __FILE__);
define('TIGERSTYLE_SCENT_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('TIGERSTYLE_SCENT_PLUGIN_URL', plugin_dir_url(__FILE__));
define('TIGERSTYLE_SCENT_PLUGIN_BASENAME', plugin_basename(__FILE__));
// Debug mode for scent trail tracking
if (!defined('TIGERSTYLE_SCENT_DEBUG')) {
define('TIGERSTYLE_SCENT_DEBUG', WP_DEBUG);
}
/**
* Main TigerStyle Scent Plugin Class
*
* Manages the entire OAuth2 authentication ecosystem like an alpha cat managing territory
*/
class TigerStyleScent {
/**
* Single instance of the plugin (singleton pattern like a territorial cat)
* @var TigerStyleScent|null
*/
private static $instance = null;
/**
* Plugin modules (like different scent detection systems)
* @var array
*/
private $modules = array();
/**
* Plugin settings
* @var array
*/
private $settings = array();
/**
* Scent server instance
* @var TigerStyleScent_ScentServer|null
*/
private $scent_server = null;
/**
* Get singleton instance (territorial control)
*
* @return TigerStyleScent
*/
public static function instance() {
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor - Initialize the TigerStyle Scent territory
*/
private function __construct() {
$this->load_dependencies();
$this->init_hooks();
$this->load_settings();
$this->init_modules();
// Log plugin initialization
$this->log_scent_event('plugin_initialized', [
'version' => TIGERSTYLE_SCENT_VERSION,
'php_version' => PHP_VERSION,
'wp_version' => get_bloginfo('version')
]);
}
/**
* Load plugin dependencies like gathering scent detection tools
*/
private function load_dependencies(): void {
// Load interface first
require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'includes/class-authenticator-interface.php';
// Load security components first
require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'includes/class-security-logger.php';
require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'includes/class-rate-limiter.php';
require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'includes/class-input-validator.php';
// Load core modules
require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'includes/modules/class-scent-server.php';
require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'includes/modules/class-scent-authenticator.php';
// Load admin components if in admin area
if (is_admin()) {
$this->load_admin_dependencies();
}
}
/**
* Load admin-specific dependencies
*/
private function load_admin_dependencies(): void {
// Admin components will be loaded here
// require_once TIGERSTYLE_SCENT_PLUGIN_DIR . 'admin/class-admin.php';
}
/**
* Initialize WordPress hooks like setting up scent detection points
*/
private function init_hooks(): void {
// Plugin lifecycle hooks
register_activation_hook(TIGERSTYLE_SCENT_PLUGIN_FILE, array($this, 'activate_territory'));
register_deactivation_hook(TIGERSTYLE_SCENT_PLUGIN_FILE, array($this, 'deactivate_territory'));
// Core WordPress hooks
add_action('init', array($this, 'init_oauth_endpoints'));
add_action('template_redirect', array($this, 'handle_oauth_requests'));
add_filter('determine_current_user', array($this, 'authenticate_user'), 20);
add_action('rest_api_init', array($this, 'setup_rest_authentication'));
// Admin hooks
if (is_admin()) {
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
}
// Custom post type for OAuth clients (scent profiles)
add_action('init', array($this, 'register_client_post_type'));
// AJAX hooks for admin interface
add_action('wp_ajax_tigerstyle_scent_test_auth', array($this, 'ajax_test_authentication'));
}
/**
* Load plugin settings from WordPress options
*/
private function load_settings(): void {
// 🔐 SECURITY: Secure-by-default configuration - WordPress community gold standard
$defaults = array(
// Core security settings
'enable_scent_authentication' => true,
'require_https' => true, // Mandatory HTTPS - no exceptions
'enforce_security_headers' => true, // Full security header suite
'enable_rate_limiting' => true, // Progressive rate limiting enabled
'enable_security_logging' => true, // Comprehensive threat monitoring
'enable_input_validation' => true, // Multi-layer validation framework
// Token security settings (conservative defaults)
'scent_token_lifetime' => 1800, // 30 minutes (reduced from 1 hour)
'refresh_scent_lifetime' => 604800, // 7 days (reduced from 30 days)
'territory_code_lifetime' => 300, // 5 minutes (reduced from 10)
'token_entropy_level' => 'maximum', // 384-512 bit tokens
// Client security settings
'require_client_secrets' => true, // Force confidential clients
'min_client_secret_length' => 32, // Strong secret requirements
'auto_block_attacks' => true, // Auto-block repeated violations
'client_secret_rotation_days' => 90, // Encourage regular rotation
// Validation & monitoring
'strict_parameter_validation' => true, // Zero tolerance for invalid input
'log_all_auth_attempts' => true, // Complete audit trail
'alert_on_security_events' => true, // Real-time admin alerts
'auto_cleanup_logs_days' => 90, // Automatic log management
// Development vs production
'debug_scent_trails' => false, // Disabled by default for security
'development_mode' => false, // Production-first approach
'detailed_error_messages' => false, // Generic errors by default
// Access control
'allowed_scent_origins' => array(), // Explicit allowlist required
'scent_strength' => 'high', // Maximum security level by default
'require_state_parameter' => true, // CSRF protection mandatory
'enforce_pkce' => true, // PKCE required for all public clients
// Security monitoring thresholds
'max_failed_attempts_per_hour' => 5, // Conservative limit
'suspicious_pattern_detection' => true, // ML-style pattern analysis
'geo_blocking_enabled' => false, // Optional geo-restrictions
'honeypot_endpoints' => true, // Decoy endpoints for threat intel
);
$this->settings = wp_parse_args(
get_option('tigerstyle_scent_settings', array()),
$defaults
);
}
/**
* Initialize plugin modules like different scent detection systems
*/
private function init_modules(): void {
// Initialize scent server
$this->scent_server = new TigerStyleScent_ScentServer($this->settings);
// Initialize authenticator modules
$this->modules['scent_authenticator'] = new TigerStyleScent_ScentAuthenticator();
// Allow other plugins to add custom authenticators
$this->modules = apply_filters('tigerstyle_scent_authenticators', $this->modules);
// Sort by priority (like cat hierarchy)
uasort($this->modules, function($a, $b) {
return $b->get_priority() - $a->get_priority();
});
}
/**
* Plugin activation - Set up territory
*/
public function activate_territory(): void {
// Create database tables for scent storage
$this->create_scent_tables();
// Set up rewrite rules for OAuth endpoints
$this->setup_rewrite_rules();
flush_rewrite_rules();
// Create default settings
if (!get_option('tigerstyle_scent_settings')) {
update_option('tigerstyle_scent_settings', $this->settings);
}
// Log activation
$this->log_scent_event('territory_activated', [
'version' => TIGERSTYLE_SCENT_VERSION,
'timestamp' => current_time('mysql')
]);
}
/**
* Plugin deactivation - Secure territory
*/
public function deactivate_territory(): void {
// Remove rewrite rules
flush_rewrite_rules();
// Log deactivation
$this->log_scent_event('territory_deactivated', [
'version' => TIGERSTYLE_SCENT_VERSION,
'timestamp' => current_time('mysql')
]);
}
/**
* Initialize OAuth endpoints like setting up scent detection points
*/
public function init_oauth_endpoints(): void {
// Add query vars for OAuth endpoints
add_rewrite_tag('%oauth_endpoint%', '([^&]+)');
// Setup rewrite rules
$this->setup_rewrite_rules();
}
/**
* Setup rewrite rules for OAuth endpoints (scent detection points)
*/
private function setup_rewrite_rules(): void {
// OAuth2 endpoints with TigerStyle branding
add_rewrite_rule('^oauth/authorize/?$', 'index.php?oauth_endpoint=authorize', 'top');
add_rewrite_rule('^oauth/token/?$', 'index.php?oauth_endpoint=token', 'top');
add_rewrite_rule('^oauth/introspect/?$', 'index.php?oauth_endpoint=introspect', 'top');
add_rewrite_rule('^oauth/revoke/?$', 'index.php?oauth_endpoint=revoke', 'top');
// OpenID Connect discovery
add_rewrite_rule('^\.well-known/openid_configuration/?$', 'index.php?oauth_endpoint=openid_config', 'top');
add_rewrite_rule('^well-known/openid_configuration/?$', 'index.php?oauth_endpoint=openid_config', 'top');
// TigerStyle specific endpoints
add_rewrite_rule('^tigerstyle/scent-analysis/?$', 'index.php?oauth_endpoint=introspect', 'top');
add_rewrite_rule('^tigerstyle/territory-status/?$', 'index.php?oauth_endpoint=status', 'top');
}
/**
* Handle OAuth requests like processing scent detection
*/
public function handle_oauth_requests(): void {
$oauth_endpoint = get_query_var('oauth_endpoint');
if ($oauth_endpoint && $this->scent_server) {
// Log request
$this->log_scent_event('oauth_request', [
'endpoint' => $oauth_endpoint,
'method' => $_SERVER['REQUEST_METHOD'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
]);
$this->scent_server->handle_scent_request();
}
}
/**
* Authenticate user via scent detection
*/
public function authenticate_user($user_id) {
// Don't override if user is already authenticated
if ($user_id) {
return $user_id;
}
// Try each authenticator in priority order
foreach ($this->modules as $authenticator) {
if ($authenticator->can_handle_request()) {
$authenticated_user = $authenticator->authenticate();
if ($authenticated_user) {
$this->log_scent_event('user_authenticated', [
'user_id' => $authenticated_user,
'authenticator' => $authenticator->get_type(),
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
]);
return $authenticated_user;
}
}
}
return $user_id;
}
/**
* Setup REST API authentication like territorial access control
*/
public function setup_rest_authentication(): void {
// Remove WordPress cookie authentication for REST if using scent tokens
remove_filter('rest_authentication_errors', 'rest_cookie_check_errors', 100);
// Add custom authentication error handling
add_filter('rest_authentication_errors', array($this, 'rest_authentication_errors'));
}
/**
* Handle REST authentication errors with cat-themed messages
*/
public function rest_authentication_errors($result): WP_Error {
if (!empty($result)) {
return $result;
}
if (!is_user_logged_in()) {
return new WP_Error(
'tigerstyle_scent_unauthorized',
'🐯 Territory access denied. Valid scent token required.',
array('status' => 401)
);
}
return $result;
}
/**
* Register OAuth client custom post type (scent profiles)
*/
public function register_client_post_type(): void {
register_post_type('oauth2_client', array(
'labels' => array(
'name' => '🐾 Scent Profiles',
'singular_name' => '🐾 Scent Profile',
'add_new' => 'Add New Profile',
'add_new_item' => 'Add New Scent Profile',
'edit_item' => 'Edit Scent Profile',
'new_item' => 'New Scent Profile',
'view_item' => 'View Scent Profile',
'search_items' => 'Search Scent Profiles',
'not_found' => 'No scent profiles found',
'not_found_in_trash' => 'No scent profiles found in trash'
),
'public' => false,
'show_ui' => true,
'show_in_menu' => 'tigerstyle-scent',
'capability_type' => 'post',
'supports' => array('title'),
'menu_icon' => 'dashicons-shield'
));
}
/**
* Add admin menu for TigerStyle Scent
*/
public function add_admin_menu(): void {
add_menu_page(
'TigerStyle Scent',
'🐯 TigerStyle Scent',
'manage_options',
'tigerstyle-scent',
array($this, 'admin_page'),
'dashicons-shield-alt',
30
);
add_submenu_page(
'tigerstyle-scent',
'Territory Settings',
'⚙️ Territory Settings',
'manage_options',
'tigerstyle-scent',
array($this, 'admin_page')
);
add_submenu_page(
'tigerstyle-scent',
'Scent Analysis',
'👃 Scent Analysis',
'manage_options',
'tigerstyle-scent-analysis',
array($this, 'scent_analysis_page')
);
}
/**
* Admin page content
*/
public function admin_page(): void {
?>
<div class="wrap">
<h1>🐯 TigerStyle Scent - Territory Control</h1>
<p>Welcome to your OAuth2 authentication territory! Manage your digital scent trails and access control.</p>
<div class="tigerstyle-dashboard">
<div class="tigerstyle-card">
<h2>🏰 Territory Status</h2>
<p><strong>Plugin Version:</strong> <?php echo TIGERSTYLE_SCENT_VERSION; ?></p>
<p><strong>Scent Detection:</strong> <?php echo $this->settings['enable_scent_authentication'] ? '✅ Active' : '❌ Inactive'; ?></p>
<p><strong>Territory Security:</strong> <?php echo $this->settings['scent_strength']; ?></p>
</div>
<div class="tigerstyle-card">
<h2>🐾 Quick Actions</h2>
<p><a href="<?php echo admin_url('post-new.php?post_type=oauth2_client'); ?>" class="button button-primary"> Add New Scent Profile</a></p>
<p><a href="<?php echo admin_url('admin.php?page=tigerstyle-scent-analysis'); ?>" class="button">👃 Analyze Scent Trails</a></p>
<p><button id="test-scent-auth" class="button">🧪 Test Scent Recognition</button></p>
</div>
</div>
<style>
.tigerstyle-dashboard { display: flex; gap: 20px; margin-top: 20px; }
.tigerstyle-card { background: white; padding: 20px; border: 1px solid #ccd0d4; border-radius: 8px; flex: 1; }
.tigerstyle-card h2 { margin-top: 0; color: #ff6b35; }
</style>
</div>
<?php
}
/**
* Scent analysis page
*/
public function scent_analysis_page(): void {
?>
<div class="wrap">
<h1>👃 Scent Analysis - Territory Monitoring</h1>
<p>Monitor and analyze scent token activity in your territory.</p>
<div class="tigerstyle-analysis">
<h2>Recent Scent Activity</h2>
<p><em>Scent trail monitoring coming soon...</em></p>
</div>
</div>
<?php
}
/**
* Enqueue admin assets
*/
public function enqueue_admin_assets($hook): void {
if (strpos($hook, 'tigerstyle-scent') !== false) {
wp_enqueue_script(
'tigerstyle-scent-admin',
TIGERSTYLE_SCENT_PLUGIN_URL . 'admin/js/admin.js',
array('jquery'),
TIGERSTYLE_SCENT_VERSION,
true
);
wp_localize_script('tigerstyle-scent-admin', 'tigerStyleScent', array(
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('tigerstyle_scent_admin')
));
}
}
/**
* AJAX test authentication
*/
public function ajax_test_authentication(): void {
check_ajax_referer('tigerstyle_scent_admin', 'nonce');
wp_send_json_success(array(
'message' => '🐯 Scent recognition system is operational!',
'territory' => 'secure',
'timestamp' => current_time('mysql')
));
}
/**
* Create database tables for scent storage
*/
private function create_scent_tables(): void {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// Access tokens (scent tokens)
$sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}oauth_access_tokens (
access_token varchar(255) NOT NULL,
client_id varchar(255) NOT NULL,
user_id int(11) NOT NULL,
expires datetime NOT NULL,
scope text,
PRIMARY KEY (access_token),
KEY client_id (client_id),
KEY user_id (user_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// Refresh tokens (scent memory)
$sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}oauth_refresh_tokens (
refresh_token varchar(255) NOT NULL,
client_id varchar(255) NOT NULL,
user_id int(11) NOT NULL,
expires datetime NOT NULL,
scope text,
PRIMARY KEY (refresh_token),
KEY client_id (client_id),
KEY user_id (user_id)
) $charset_collate;";
dbDelta($sql);
// Authorization codes (territory codes)
$sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}oauth_authorization_codes (
authorization_code varchar(255) NOT NULL,
client_id varchar(255) NOT NULL,
user_id int(11) NOT NULL,
redirect_uri text NOT NULL,
expires datetime NOT NULL,
scope text,
code_challenge varchar(255),
code_challenge_method varchar(10),
PRIMARY KEY (authorization_code),
KEY client_id (client_id),
KEY user_id (user_id)
) $charset_collate;";
dbDelta($sql);
}
/**
* Log scent events for debugging and monitoring
*/
private function log_scent_event(string $event, array $data = []): void {
if (TIGERSTYLE_SCENT_DEBUG) {
error_log(sprintf(
'[TigerStyle Scent] %s: %s',
$event,
json_encode($data)
));
}
// Fire action for external logging systems
do_action('tigerstyle_scent_event', $event, $data);
}
/**
* Get plugin settings
*/
public function get_settings(): array {
return $this->settings;
}
/**
* Get scent server instance
*/
public function get_scent_server(): ?TigerStyleScent_ScentServer {
return $this->scent_server;
}
}
/**
* Helper function to get main plugin instance
* Like calling an alpha cat
*/
function tigerstyle_scent(): TigerStyleScent {
return TigerStyleScent::instance();
}
// Initialize the TigerStyle Scent territory
tigerstyle_scent();