feat: auto-create .well-known files on activation, remove on deactivation, no hardcoded URLs
This commit is contained in:
+161
-5
@@ -4,21 +4,23 @@ namespace AskTamMCP\Core;
|
|||||||
|
|
||||||
defined('ABSPATH') || exit;
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles DB table creation on activation, cleanup on deactivation.
|
|
||||||
*/
|
|
||||||
class Installer {
|
class Installer {
|
||||||
|
|
||||||
public static function activate(): void {
|
public static function activate(): void {
|
||||||
self::createTables();
|
self::createTables();
|
||||||
self::setDefaults();
|
self::setDefaults();
|
||||||
|
self::createWellKnownFiles();
|
||||||
flush_rewrite_rules();
|
flush_rewrite_rules();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function deactivate(): void {
|
public static function deactivate(): void {
|
||||||
|
self::removeWellKnownFiles();
|
||||||
flush_rewrite_rules();
|
flush_rewrite_rules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// DB
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
private static function createTables(): void {
|
private static function createTables(): void {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$charset = $wpdb->get_charset_collate();
|
$charset = $wpdb->get_charset_collate();
|
||||||
@@ -44,11 +46,165 @@ class Installer {
|
|||||||
private static function setDefaults(): void {
|
private static function setDefaults(): void {
|
||||||
if (!get_option('asktam_mcp_settings')) {
|
if (!get_option('asktam_mcp_settings')) {
|
||||||
update_option('asktam_mcp_settings', [
|
update_option('asktam_mcp_settings', [
|
||||||
'rate_limit' => 60, // requests per minute per key
|
'rate_limit' => 60,
|
||||||
'log_requests' => true,
|
'log_requests' => true,
|
||||||
'allow_raw_sql' => false,
|
'allow_raw_sql'=> false,
|
||||||
'wc_enabled' => class_exists('WooCommerce'),
|
'wc_enabled' => class_exists('WooCommerce'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// .well-known files — created dynamically using the site's own ABSPATH
|
||||||
|
// No hardcoded URLs — works on any WordPress installation
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
public static function createWellKnownFiles(): void {
|
||||||
|
$dir = ABSPATH . '.well-known';
|
||||||
|
|
||||||
|
if (!file_exists($dir)) {
|
||||||
|
wp_mkdir_p($dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared PHP bootstrap — no hardcoded URL
|
||||||
|
$bootstrap = <<<'PHP'
|
||||||
|
<?php
|
||||||
|
// Dynamic bootstrap — works on any WordPress installation
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
// Find wp-load.php by walking up from this file's location
|
||||||
|
$dir = dirname(dirname(__FILE__)); // two levels up from .well-known/
|
||||||
|
$wpLoad = $dir . '/wp-load.php';
|
||||||
|
if (!file_exists($wpLoad)) {
|
||||||
|
http_response_code(500);
|
||||||
|
exit('WordPress not found');
|
||||||
|
}
|
||||||
|
// Set minimal server vars WordPress needs
|
||||||
|
if (!isset($_SERVER['HTTP_HOST'])) {
|
||||||
|
$_SERVER['HTTP_HOST'] = parse_url(get_option('siteurl'), PHP_URL_HOST) ?? 'localhost';
|
||||||
|
}
|
||||||
|
if (!isset($_SERVER['REQUEST_URI'])) {
|
||||||
|
$_SERVER['REQUEST_URI'] = '/';
|
||||||
|
}
|
||||||
|
require $wpLoad;
|
||||||
|
}
|
||||||
|
PHP;
|
||||||
|
|
||||||
|
// oauth-authorization-server
|
||||||
|
$authServer = $bootstrap . <<<'PHP'
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
header('Cache-Control: no-cache');
|
||||||
|
|
||||||
|
$base = rest_url('asktam-mcp/v1');
|
||||||
|
echo json_encode([
|
||||||
|
'issuer' => get_site_url(),
|
||||||
|
'authorization_endpoint' => $base . '/oauth/authorize',
|
||||||
|
'token_endpoint' => $base . '/oauth/token',
|
||||||
|
'token_endpoint_auth_methods_supported' => ['client_secret_post', 'client_secret_basic', 'none'],
|
||||||
|
'grant_types_supported' => ['authorization_code', 'client_credentials'],
|
||||||
|
'response_types_supported' => ['code'],
|
||||||
|
'code_challenge_methods_supported' => ['S256', 'plain'],
|
||||||
|
'scopes_supported' => ['read', 'write', 'admin', 'woocommerce'],
|
||||||
|
], JSON_UNESCAPED_SLASHES);
|
||||||
|
PHP;
|
||||||
|
|
||||||
|
// oauth-protected-resource
|
||||||
|
$protectedResource = $bootstrap . <<<'PHP'
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
header('Cache-Control: no-cache');
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'resource' => rest_url('asktam-mcp/v1/sse'),
|
||||||
|
'authorization_servers' => [get_site_url()],
|
||||||
|
'bearer_methods_supported' => ['header'],
|
||||||
|
'scopes_supported' => ['read', 'write', 'admin', 'woocommerce'],
|
||||||
|
], JSON_UNESCAPED_SLASHES);
|
||||||
|
PHP;
|
||||||
|
|
||||||
|
// .htaccess inside .well-known — forces PHP execution on extensionless files
|
||||||
|
$htaccess = <<<'HTACCESS'
|
||||||
|
<Files "oauth-authorization-server">
|
||||||
|
ForceType application/x-httpd-php
|
||||||
|
</Files>
|
||||||
|
<Files "oauth-protected-resource">
|
||||||
|
ForceType application/x-httpd-php
|
||||||
|
</Files>
|
||||||
|
HTACCESS;
|
||||||
|
|
||||||
|
file_put_contents($dir . '/oauth-authorization-server', $authServer);
|
||||||
|
file_put_contents($dir . '/oauth-protected-resource', $protectedResource);
|
||||||
|
file_put_contents($dir . '/.htaccess', $htaccess);
|
||||||
|
|
||||||
|
// Also add rewrite rules in main .htaccess for the subpath variant
|
||||||
|
// /.well-known/oauth-protected-resource/{anything} → same file
|
||||||
|
self::addHtaccessRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function removeWellKnownFiles(): void {
|
||||||
|
$dir = ABSPATH . '.well-known';
|
||||||
|
$files = [
|
||||||
|
$dir . '/oauth-authorization-server',
|
||||||
|
$dir . '/oauth-protected-resource',
|
||||||
|
$dir . '/.htaccess',
|
||||||
|
];
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if (file_exists($file)) {
|
||||||
|
@unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove dir if empty
|
||||||
|
if (file_exists($dir) && count(scandir($dir)) === 2) {
|
||||||
|
@rmdir($dir);
|
||||||
|
}
|
||||||
|
self::removeHtaccessRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Main .htaccess — add/remove rewrite rules for .well-known subpaths
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
private static function addHtaccessRules(): void {
|
||||||
|
$htaccessFile = ABSPATH . '.htaccess';
|
||||||
|
if (!file_exists($htaccessFile) || !is_writable($htaccessFile)) return;
|
||||||
|
|
||||||
|
$content = file_get_contents($htaccessFile);
|
||||||
|
|
||||||
|
$marker = '# BEGIN AskTam MCP';
|
||||||
|
$marker2 = '# END AskTam MCP';
|
||||||
|
|
||||||
|
// Don't add twice
|
||||||
|
if (str_contains($content, $marker)) return;
|
||||||
|
|
||||||
|
$rules = <<<'RULES'
|
||||||
|
|
||||||
|
# BEGIN AskTam MCP
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteRule ^.well-known/oauth-authorization-server$ .well-known/oauth-authorization-server [L,T=application/x-httpd-php]
|
||||||
|
RewriteRule ^.well-known/oauth-protected-resource.*$ .well-known/oauth-protected-resource [L,T=application/x-httpd-php]
|
||||||
|
</IfModule>
|
||||||
|
# END AskTam MCP
|
||||||
|
|
||||||
|
RULES;
|
||||||
|
|
||||||
|
// Insert before # BEGIN WordPress
|
||||||
|
$wpMarker = '# BEGIN WordPress';
|
||||||
|
if (str_contains($content, $wpMarker)) {
|
||||||
|
$content = str_replace($wpMarker, $rules . $wpMarker, $content);
|
||||||
|
} else {
|
||||||
|
$content = $rules . $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($htaccessFile, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function removeHtaccessRules(): void {
|
||||||
|
$htaccessFile = ABSPATH . '.htaccess';
|
||||||
|
if (!file_exists($htaccessFile)) return;
|
||||||
|
|
||||||
|
$content = file_get_contents($htaccessFile);
|
||||||
|
$content = preg_replace('/\n# BEGIN AskTam MCP.*?# END AskTam MCP\n/s', '', $content);
|
||||||
|
file_put_contents($htaccessFile, $content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user