@anonympins/fingerprint 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +1 -1
- package/package.json +3 -2
- package/public/anonympins-bot-mitigation-pow.zip +0 -0
- package/src/js/asn-lookup.js +223 -0
- package/src/js/fingerprint.client.obfuscated.js +1 -1
- package/src/js/fingerprint.js +48 -22
- package/src/js/tests/asn-lookup.test.js +57 -0
- package/src/php/AsnLookupEngine.php +173 -0
- package/src/php/Challenge/ChallengeUtils.php +66 -49
- package/src/php/DirectFingerprint.php +25 -5
- package/src/php/FingerprintEngine.php +51 -30
- package/src/php/NetworkProfile.php +68 -0
- package/src/php/ProblemManager.php +12 -2
- package/src/php/Tests/AsnLookupTest.php +61 -0
- package/src/php/Tests/FingerprintEngineTest.php +4 -2
- package/src/php/Utils/Env.php +7 -2
- package/src/php/Utils/RequestUtils.php +21 -4
- package/src/php/WordPress/WpDbStore.php +27 -0
- package/src/php/WordPress/anonympins-bot-mitigation-pow.php +109 -8
- package/src/php/WordPress/languages/anonympins-bot-mitigation-pow-fr_FR.po +1 -1
- package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.po +1 -1
- package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.po +1 -1
- package/src/php/WordPress/package.php +10 -0
- package/src/php/WordPress/readme.txt +8 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Plugin Name: Anonympins Bot Mitigation with Proof-of-Work
|
|
4
4
|
* Plugin URI: https://github.com/anonympins/fingerprint
|
|
5
5
|
* Description: High-performance client-side anti-bot protection and Proof-of-Work challenge verification for WordPress.
|
|
6
|
-
* Version: 0.8.
|
|
6
|
+
* Version: 0.8.1
|
|
7
7
|
* Author: anonympins
|
|
8
8
|
* Requires at least: 5.9
|
|
9
9
|
* Requires PHP: 8.0
|
|
@@ -25,7 +25,11 @@ if (!defined('ABSPATH')) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
if (!defined('ANONYMPINS_BOT_MITIGATION_VERSION')) {
|
|
28
|
-
define('ANONYMPINS_BOT_MITIGATION_VERSION', '0.8.
|
|
28
|
+
define('ANONYMPINS_BOT_MITIGATION_VERSION', '0.8.1');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!defined('ANONYMPINS_BOT_MITIGATION_DIR')) {
|
|
32
|
+
define('ANONYMPINS_BOT_MITIGATION_DIR', plugin_dir_path(__FILE__));
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
// =============================================================================
|
|
@@ -126,12 +130,25 @@ function fingerprint_get_sandbox_config(): array {
|
|
|
126
130
|
];
|
|
127
131
|
}
|
|
128
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Retrieves the configured direct endpoint path for Prometheus metrics scraping.
|
|
135
|
+
*/
|
|
136
|
+
function fingerprint_get_metrics_endpoint(): string {
|
|
137
|
+
$saved = get_option('anonympins_security_options', get_option('fingerprint_security_options', []));
|
|
138
|
+
if (!isset($saved['metrics_endpoint'])) {
|
|
139
|
+
return '/metrics';
|
|
140
|
+
}
|
|
141
|
+
$path = trim((string)$saved['metrics_endpoint']);
|
|
142
|
+
if ($path === '') {
|
|
143
|
+
return '';
|
|
144
|
+
}
|
|
145
|
+
return str_starts_with($path, '/') ? $path : '/' . $path;
|
|
146
|
+
}
|
|
147
|
+
|
|
129
148
|
// 1. PSR-4 autoloader for the Fingerprint engine.
|
|
130
149
|
if (!class_exists(DirectFingerprint::class)) {
|
|
131
150
|
$fingerprint_composer_paths = [
|
|
132
151
|
__DIR__ . '/vendor/autoload.php',
|
|
133
|
-
dirname(__DIR__, 2) . '/vendor/autoload.php',
|
|
134
|
-
dirname(__DIR__, 3) . '/vendor/autoload.php',
|
|
135
152
|
(defined('ABSPATH') ? ABSPATH . 'vendor/autoload.php' : ''),
|
|
136
153
|
];
|
|
137
154
|
foreach ($fingerprint_composer_paths as $fingerprint_composer_path) {
|
|
@@ -361,6 +378,21 @@ add_action('plugins_loaded', function () use ($fingerprint_security_profiles) {
|
|
|
361
378
|
|
|
362
379
|
$securityConfig = SecurityProfiles::createSecurityProfile($contextConfig['profile'], $contextConfig['overrides'] ?? []);
|
|
363
380
|
$guard = new DirectFingerprint($securityConfig);
|
|
381
|
+
|
|
382
|
+
// Handle direct metrics endpoint if requested
|
|
383
|
+
$metricsPath = fingerprint_get_metrics_endpoint();
|
|
384
|
+
$path = (string)wp_parse_url($requestUri, PHP_URL_PATH);
|
|
385
|
+
if ($metricsPath !== '' && ($path === $metricsPath || str_ends_with($path, $metricsPath))) {
|
|
386
|
+
$context = $guard->buildRequestContext();
|
|
387
|
+
$isAuth = current_user_can('manage_options') || apply_filters('fingerprint_metrics_authorization', false, $context);
|
|
388
|
+
if (!$isAuth) {
|
|
389
|
+
status_header(403);
|
|
390
|
+
echo "Access to metrics denied.";
|
|
391
|
+
exit;
|
|
392
|
+
}
|
|
393
|
+
$guard->handleMetricsRequest($context);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
364
396
|
$guard->protect();
|
|
365
397
|
}, 0);
|
|
366
398
|
|
|
@@ -431,19 +463,37 @@ function fingerprint_inject_client_suspicion_event(): void {
|
|
|
431
463
|
// SPECIAL SANDBOX ROUTES: REST & SERVER-SENT EVENTS (SSE)
|
|
432
464
|
// =============================================================================
|
|
433
465
|
add_action('rest_api_init', function () {
|
|
466
|
+
// 1. Prometheus Metrics (registered under plugin namespace and legacy namespace)
|
|
467
|
+
register_rest_route('anonympins/v1', '/metrics', [
|
|
468
|
+
'methods' => 'GET',
|
|
469
|
+
'callback' => 'fingerprint_rest_prometheus_metrics',
|
|
470
|
+
'permission_callback' => function () {
|
|
471
|
+
return current_user_can('manage_options') || apply_filters('fingerprint_metrics_access', false);
|
|
472
|
+
},
|
|
473
|
+
]);
|
|
474
|
+
|
|
434
475
|
register_rest_route('fingerprint/v1', '/sandbox/telemetry', [
|
|
435
476
|
'methods' => 'GET',
|
|
436
477
|
'callback' => 'fingerprint_rest_sandbox_telemetry',
|
|
437
478
|
'permission_callback' => function () {
|
|
438
|
-
return current_user_can('manage_options')
|
|
479
|
+
return current_user_can('manage_options');
|
|
439
480
|
},
|
|
440
481
|
]);
|
|
441
482
|
|
|
483
|
+
// 2. Sandbox Inspection Routes (Strictly restricted to manage_options)
|
|
442
484
|
register_rest_route('fingerprint/v1', '/sandbox/sse', [
|
|
443
485
|
'methods' => 'GET',
|
|
444
486
|
'callback' => 'fingerprint_rest_sandbox_sse',
|
|
445
487
|
'permission_callback' => function () {
|
|
446
|
-
return current_user_can('manage_options')
|
|
488
|
+
return current_user_can('manage_options');
|
|
489
|
+
},
|
|
490
|
+
]);
|
|
491
|
+
|
|
492
|
+
register_rest_route('fingerprint/v1', '/metrics', [
|
|
493
|
+
'methods' => 'GET',
|
|
494
|
+
'callback' => 'fingerprint_rest_prometheus_metrics',
|
|
495
|
+
'permission_callback' => function () {
|
|
496
|
+
return current_user_can('manage_options') || apply_filters('fingerprint_metrics_access', false);
|
|
447
497
|
},
|
|
448
498
|
]);
|
|
449
499
|
|
|
@@ -478,7 +528,21 @@ function fingerprint_rest_sandbox_clear_challenges(): \WP_REST_Response {
|
|
|
478
528
|
return new \WP_REST_Response(['cleared' => true], 200);
|
|
479
529
|
}
|
|
480
530
|
|
|
531
|
+
function fingerprint_rest_prometheus_metrics(\WP_REST_Request $request): \WP_REST_Response {
|
|
532
|
+
$effectiveProfiles = fingerprint_get_effective_profiles($GLOBALS['fingerprint_security_profiles'] ?? []);
|
|
533
|
+
$securityConfig = SecurityProfiles::createSecurityProfile($effectiveProfiles['frontend']['profile'] ?? 'blog', $effectiveProfiles['frontend']['overrides'] ?? []);
|
|
534
|
+
$metricsOutput = MetricsManager::getPrometheusMetrics($securityConfig);
|
|
535
|
+
|
|
536
|
+
$response = new \WP_REST_Response($metricsOutput, 200);
|
|
537
|
+
$response->header('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');
|
|
538
|
+
return $response;
|
|
539
|
+
}
|
|
540
|
+
|
|
481
541
|
function fingerprint_rest_sandbox_sse(): void {
|
|
542
|
+
if (!current_user_can('manage_options')) {
|
|
543
|
+
wp_die(esc_html__('Unauthorized access.', 'anonympins-bot-mitigation-pow'), '', ['response' => 403]);
|
|
544
|
+
}
|
|
545
|
+
|
|
482
546
|
if (function_exists('apache_setenv')) {
|
|
483
547
|
apache_setenv('no-gzip', '1');
|
|
484
548
|
}
|
|
@@ -803,6 +867,22 @@ function fingerprint_render_admin_page(): void {
|
|
|
803
867
|
echo '<div class="notice notice-success is-dismissible"><p><strong>' . esc_html__('Sandbox settings updated successfully.', 'anonympins-bot-mitigation-pow') . '</strong></p></div>';
|
|
804
868
|
}
|
|
805
869
|
|
|
870
|
+
if (isset($_POST['fingerprint_save_prometheus']) && check_admin_referer('fingerprint_prometheus_nonce', 'fingerprint_nonce_prometheus')) {
|
|
871
|
+
$saved = get_option('anonympins_security_options', get_option('fingerprint_security_options', []));
|
|
872
|
+
if (!is_array($saved)) {
|
|
873
|
+
$saved = [];
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
$rawEndpoint = isset($_POST['metrics_endpoint']) ? sanitize_text_field(wp_unslash($_POST['metrics_endpoint'])) : '/metrics';
|
|
877
|
+
$rawEndpoint = trim($rawEndpoint);
|
|
878
|
+
if ($rawEndpoint !== '' && !str_starts_with($rawEndpoint, '/')) {
|
|
879
|
+
$rawEndpoint = '/' . $rawEndpoint;
|
|
880
|
+
}
|
|
881
|
+
$saved['metrics_endpoint'] = $rawEndpoint;
|
|
882
|
+
update_option('anonympins_security_options', $saved);
|
|
883
|
+
echo '<div class="notice notice-success is-dismissible"><p><strong>' . esc_html__('Prometheus settings updated successfully.', 'anonympins-bot-mitigation-pow') . '</strong></p></div>';
|
|
884
|
+
}
|
|
885
|
+
|
|
806
886
|
if (isset($_POST['fingerprint_clear_store']) && check_admin_referer('fingerprint_clear_nonce', 'fingerprint_nonce_clear')) {
|
|
807
887
|
$store = new WpDbStore();
|
|
808
888
|
$store->clear();
|
|
@@ -813,12 +893,13 @@ function fingerprint_render_admin_page(): void {
|
|
|
813
893
|
$effective = fingerprint_get_effective_profiles($fingerprint_security_profiles);
|
|
814
894
|
$frontendConfig = SecurityProfiles::createSecurityProfile($effective['frontend']['profile'], $effective['frontend']['overrides'] ?? []);
|
|
815
895
|
|
|
896
|
+
$store = new WpDbStore();
|
|
897
|
+
$totalRows = $store->getTotalCount();
|
|
898
|
+
$expiredRows = $store->getExpiredCount();
|
|
816
899
|
$tableName = esc_sql($wpdb->prefix . 'fingerprint_store');
|
|
817
900
|
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter
|
|
818
|
-
$totalRows = (int)$wpdb->get_var("SELECT COUNT(*) FROM `{$tableName}`");
|
|
819
901
|
$now = time();
|
|
820
902
|
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter
|
|
821
|
-
$expiredRows = (int)$wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM `{$tableName}` WHERE expires_at IS NOT NULL AND expires_at < %d", $now));
|
|
822
903
|
|
|
823
904
|
$prometheusRaw = MetricsManager::getPrometheusMetrics($frontendConfig);
|
|
824
905
|
?>
|
|
@@ -1114,6 +1195,26 @@ function fingerprint_render_admin_page(): void {
|
|
|
1114
1195
|
|
|
1115
1196
|
<div id="tab-prometheus" class="fingerprint-tab-content" style="display:none;background:#fff;padding:20px;border:1px solid #ccd0d4;border-top:none;">
|
|
1116
1197
|
<h3><?php esc_html_e('Real-Time Prometheus Metrics', 'anonympins-bot-mitigation-pow'); ?></h3>
|
|
1198
|
+
<form method="post" action="" style="margin-bottom:20px;">
|
|
1199
|
+
<?php wp_nonce_field('fingerprint_prometheus_nonce', 'fingerprint_nonce_prometheus'); ?>
|
|
1200
|
+
<table class="form-table">
|
|
1201
|
+
<tr>
|
|
1202
|
+
<th scope="row"><label for="metrics_endpoint"><?php esc_html_e('Metrics Endpoint Path', 'anonympins-bot-mitigation-pow'); ?></label></th>
|
|
1203
|
+
<td>
|
|
1204
|
+
<input type="text" name="metrics_endpoint" id="metrics_endpoint" value="<?php echo esc_attr(fingerprint_get_metrics_endpoint()); ?>" class="regular-text" placeholder="/metrics">
|
|
1205
|
+
<p class="description">
|
|
1206
|
+
<?php esc_html_e('Custom path for direct Prometheus scraping (default: /metrics). Leave empty to disable direct path scraping.', 'anonympins-bot-mitigation-pow'); ?>
|
|
1207
|
+
</p>
|
|
1208
|
+
<?php if (fingerprint_get_metrics_endpoint() !== ''): ?>
|
|
1209
|
+
<p class="description">
|
|
1210
|
+
<strong><?php esc_html_e('Scrape URL:', 'anonympins-bot-mitigation-pow'); ?></strong> <code><?php echo esc_html(home_url(fingerprint_get_metrics_endpoint())); ?></code>
|
|
1211
|
+
</p>
|
|
1212
|
+
<?php endif; ?>
|
|
1213
|
+
</td>
|
|
1214
|
+
</tr>
|
|
1215
|
+
</table>
|
|
1216
|
+
<?php submit_button(esc_html__('Save Prometheus Settings', 'anonympins-bot-mitigation-pow'), 'primary', 'fingerprint_save_prometheus'); ?>
|
|
1217
|
+
</form>
|
|
1117
1218
|
<textarea readonly style="width:100%;height:380px;font-family:monospace;background:#f6f7f7;padding:12px;"><?php echo esc_textarea($prometheusRaw); ?></textarea>
|
|
1118
1219
|
</div>
|
|
1119
1220
|
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
msgid ""
|
|
2
2
|
msgstr ""
|
|
3
|
-
"Project-Id-Version: Anonympins Bot Mitigation with Proof-of-Work 0.8.
|
|
3
|
+
"Project-Id-Version: Anonympins Bot Mitigation with Proof-of-Work 0.8.1\n"
|
|
4
4
|
"Report-Msgid-Bugs-To: https://github.com/anonympins/fingerprint/issues\n"
|
|
5
5
|
"POT-Creation-Date: 2026-09-24 12:00+0000\n"
|
|
6
6
|
"PO-Revision-Date: 2026-09-24 12:00+0000\n"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
msgid ""
|
|
2
2
|
msgstr ""
|
|
3
|
-
"Project-Id-Version: Fingerprint Anti-Bot 0.8.
|
|
3
|
+
"Project-Id-Version: Fingerprint Anti-Bot 0.8.1\n"
|
|
4
4
|
"Report-Msgid-Bugs-To: https://github.com/anonympins/fingerprint/issues\n"
|
|
5
5
|
"POT-Creation-Date: 2026-09-24 12:00+0000\n"
|
|
6
6
|
"PO-Revision-Date: 2026-09-24 12:00+0000\n"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
msgid ""
|
|
2
2
|
msgstr ""
|
|
3
|
-
"Project-Id-Version: Fingerprint Anti-Bot 0.8.
|
|
3
|
+
"Project-Id-Version: Fingerprint Anti-Bot 0.8.1\n"
|
|
4
4
|
"Report-Msgid-Bugs-To: https://github.com/anonympins/fingerprint/issues\n"
|
|
5
5
|
"POT-Creation-Date: 2026-09-24 12:00+0000\n"
|
|
6
6
|
"PO-Revision-Date: 2026-09-24 12:00+0000\n"
|
|
@@ -44,6 +44,7 @@ if (file_exists($zipFile)) {
|
|
|
44
44
|
@mkdir($buildDir . '/src', 0777, true);
|
|
45
45
|
@mkdir($buildDir . '/assets', 0777, true);
|
|
46
46
|
@mkdir($buildDir . '/languages', 0777, true);
|
|
47
|
+
@mkdir($buildDir . '/config', 0777, true);
|
|
47
48
|
|
|
48
49
|
// 2. Copy main WordPress plugin files
|
|
49
50
|
copy($wpDir . '/anonympins-bot-mitigation-pow.php', $buildDir . '/anonympins-bot-mitigation-pow.php');
|
|
@@ -131,6 +132,15 @@ if (file_exists($clientSource)) {
|
|
|
131
132
|
copy($clientSource, $buildDir . '/assets/fingerprint.client.js');
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
// 3.b Copy problem/bot configuration assets
|
|
136
|
+
$configSourceDir = $rootDir . '/config';
|
|
137
|
+
if (is_dir($configSourceDir)) {
|
|
138
|
+
$configFiles = glob($configSourceDir . '/*.json') ?: [];
|
|
139
|
+
foreach ($configFiles as $cfgFile) {
|
|
140
|
+
copy($cfgFile, $buildDir . '/config/' . basename($cfgFile));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
134
144
|
// 4. Recursively copy PHP library (src/php -> build/src), excluding dev folders
|
|
135
145
|
$excludeDirs = ['WordPress', 'Tests', 'bin'];
|
|
136
146
|
$phpIterator = new RecursiveIteratorIterator(
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Contributors: anonympins
|
|
3
3
|
Tags: bot protection, security, proof of work, firewall, anti scraping
|
|
4
4
|
Requires at least: 5.9
|
|
5
|
-
Tested up to: 7
|
|
5
|
+
Tested up to: 6.7
|
|
6
6
|
Requires PHP: 8.0
|
|
7
|
-
Stable tag: 0.8.
|
|
7
|
+
Stable tag: 0.8.1
|
|
8
8
|
License: MIT
|
|
9
9
|
License URI: https://opensource.org/licenses/MIT
|
|
10
10
|
|
|
@@ -37,6 +37,12 @@ No. All evaluations, challenges, and validations occur directly on your WordPres
|
|
|
37
37
|
= Is HTTPS required? =
|
|
38
38
|
HTTPS is strongly recommended. Under unencrypted HTTP, modern browsers disable the Web Cryptography API (`crypto.subtle`), which reduces challenge verification performance.
|
|
39
39
|
|
|
40
|
+
= How do I scrape the Prometheus metrics endpoint? =
|
|
41
|
+
Metrics can be accessed in standard Prometheus text exposition format via:
|
|
42
|
+
1. The REST API endpoint: `GET /wp-json/fingerprint/v1/metrics` (Requires `manage_options` permission or a custom authorization callback hooked into the `fingerprint_metrics_access` filter).
|
|
43
|
+
2. Direct path endpoint: `GET /metrics` (Evaluated in early execution lifecycle; filterable with `fingerprint_metrics_authorization`).
|
|
44
|
+
3. The admin dashboard: **Settings -> Anonympins Bot Mitigation -> Prometheus Stream**.
|
|
45
|
+
|
|
40
46
|
= How can I monitor incoming request suspicion scores in real time? =
|
|
41
47
|
Under **Settings -> Anonympins Bot Mitigation -> Sandbox / Test Mode**, the plugin provides real-time observability interfaces for all challenged visitors across the website:
|
|
42
48
|
|