@anonympins/fingerprint 0.6.4 → 0.6.6
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 +29 -0
- package/README.md +2 -2
- package/package.json +4 -1
- package/src/js/fingerprint.client.obfuscated.js +1 -1
- package/src/js/fingerprint.js +315 -54
- package/src/js/gpu_pow.solver.js +37 -5
- package/src/js/library.js +188 -97
- package/src/js/pow.solver.inline.js +128 -2
- package/src/js/pow.solver.js +85 -0
- package/src/js/problem-manager.js +16 -1
- package/src/js/tests/cross_parity.test.js +2 -2
- package/src/js/tests/fingerprint.test.js +12 -3
- package/src/js/tests/gpu_pow.test.js +9 -7
- package/src/js/tests/ip-reputation.test.js +1 -1
- package/src/js/tests/quicFingerprint.test.js +21 -10
- package/src/js/upow-model-task.js +114 -0
- package/src/php/AutoTuner.php +41 -0
- package/src/php/Challenge/ChallengeUtils.php +39 -5
- package/src/php/Config/SecurityProfiles.php +6 -6
- package/src/php/FingerprintEngine.php +17 -6
- package/src/php/Optimization/FunctionRegistry.php +1 -1
- package/src/php/Optimization/OptimizationOperators.php +109 -28
- package/src/php/ProblemManager.php +22 -0
- package/src/php/Tests/ChallengeUtilsTest.php +9 -4
- package/src/php/Tests/IpReputationTest.php +1 -1
- package/src/php/Tests/ProblemManagerTest.php +1 -1
- package/src/php/Tests/QuicFingerprintTest.php +9 -9
- package/src/php/Utils/RequestUtils.php +102 -45
package/src/js/library.js
CHANGED
|
@@ -16,10 +16,10 @@ import os from "node:os";
|
|
|
16
16
|
import crypto from "node:crypto";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* Génère un nombre flottant aléatoire
|
|
19
|
+
* Génère un nombre flottant aléatoire entre 0 (inclus) et 1 (exclus).
|
|
20
20
|
* @returns {number}
|
|
21
21
|
*/
|
|
22
|
-
const
|
|
22
|
+
const random = () => Math.random();
|
|
23
23
|
|
|
24
24
|
const Optimization = {
|
|
25
25
|
// eslint-disable-line no-unused-vars
|
|
@@ -62,7 +62,7 @@ const Optimization = {
|
|
|
62
62
|
);
|
|
63
63
|
|
|
64
64
|
// Décide si on se déplace vers la nouvelle solution.
|
|
65
|
-
if (newEnergy < currentEnergy ||
|
|
65
|
+
if (newEnergy < currentEnergy || random() < acceptanceProbability) {
|
|
66
66
|
currentSolution = newSolution;
|
|
67
67
|
currentEnergy = newEnergy;
|
|
68
68
|
}
|
|
@@ -142,7 +142,7 @@ const Optimization = {
|
|
|
142
142
|
|
|
143
143
|
let offspringChromosome;
|
|
144
144
|
// 4. Croisement
|
|
145
|
-
if (
|
|
145
|
+
if (random() < crossoverRate) {
|
|
146
146
|
offspringChromosome = crossover(
|
|
147
147
|
parent1.chromosome,
|
|
148
148
|
parent2.chromosome,
|
|
@@ -152,7 +152,7 @@ const Optimization = {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
// 5. Mutation
|
|
155
|
-
if (
|
|
155
|
+
if (random() < mutationRate) {
|
|
156
156
|
offspringChromosome = mutate(offspringChromosome);
|
|
157
157
|
}
|
|
158
158
|
|
|
@@ -524,7 +524,7 @@ Optimization.geneticAlgorithmMultiObjective = function (
|
|
|
524
524
|
const parent1 = population[crypto.randomInt(0, population.length)];
|
|
525
525
|
const parent2 = population[crypto.randomInt(0, population.length)];
|
|
526
526
|
let childIndividual = crossover(parent1.individual, parent2.individual);
|
|
527
|
-
|
|
527
|
+
if (random() < mutationRate) {
|
|
528
528
|
childIndividual = mutate(childIndividual, currentConfig); // mutate doit maintenant utiliser currentConfig
|
|
529
529
|
}
|
|
530
530
|
const child = { individual: childIndividual };
|
|
@@ -668,7 +668,7 @@ Optimization.cmaes = function(fitnessFunction, initialSolution, initialStepSize,
|
|
|
668
668
|
}
|
|
669
669
|
|
|
670
670
|
for (let i = 0; i < populationSize; i++) {
|
|
671
|
-
const z = Array.from({ length: n }, () =>
|
|
671
|
+
const z = Array.from({ length: n }, () => random() * 2 - 1); // Vecteur normal standard
|
|
672
672
|
const y = Array(n).fill(0); // z transformé par L
|
|
673
673
|
for (let r = 0; r < n; r++) {
|
|
674
674
|
for (let c = 0; c < n; c++) {
|
|
@@ -926,7 +926,7 @@ Optimization.Operators.solveTSP = (cities, options = {}) => {
|
|
|
926
926
|
|
|
927
927
|
// Solution initiale : un chemin aléatoire.
|
|
928
928
|
const initialPath = Array.from({ length: cities.length }, (_, i) => i).sort(
|
|
929
|
-
() =>
|
|
929
|
+
() => random() - 0.5,
|
|
930
930
|
);
|
|
931
931
|
|
|
932
932
|
// Paramètres par défaut pour le TSP, pouvant être surchargés par `options`.
|
|
@@ -968,14 +968,14 @@ Optimization.Operators.solvePortfolio = (
|
|
|
968
968
|
|
|
969
969
|
// Fonctions spécifiques au problème pour l'AG, maintenant encapsulées.
|
|
970
970
|
const createIndividual = () =>
|
|
971
|
-
Array.from({ length: assets.length }, () =>
|
|
971
|
+
Array.from({ length: assets.length }, () => random());
|
|
972
972
|
|
|
973
973
|
const crossover = (p1, p2) => p1.map((w1, i) => (w1 + p2[i]) / 2); // Moyenne des poids
|
|
974
974
|
|
|
975
975
|
const mutate = (p) => {
|
|
976
976
|
const newP = [...p];
|
|
977
977
|
const i = crypto.randomInt(0, newP.length);
|
|
978
|
-
newP[i] += (
|
|
978
|
+
newP[i] += (random() - 0.5) * 0.2; // Mutation douce
|
|
979
979
|
newP[i] = Math.max(0, newP[i]); // Les poids ne peuvent être négatifs
|
|
980
980
|
return newP;
|
|
981
981
|
};
|
|
@@ -1109,8 +1109,8 @@ Optimization.Operators.solveFacilityLocation = (
|
|
|
1109
1109
|
const facilityNeighbor = (facilities) => {
|
|
1110
1110
|
const newFacilities = facilities.map((f) => ({ ...f }));
|
|
1111
1111
|
const i = crypto.randomInt(0, numFacilities);
|
|
1112
|
-
const moveX = (
|
|
1113
|
-
const moveY = (
|
|
1112
|
+
const moveX = (random() - 0.5) * (bounds.maxX - bounds.minX) * 0.1;
|
|
1113
|
+
const moveY = (random() - 0.5) * (bounds.maxY - bounds.minY) * 0.1;
|
|
1114
1114
|
|
|
1115
1115
|
newFacilities[i].x = Math.max(
|
|
1116
1116
|
bounds.minX,
|
|
@@ -1126,8 +1126,8 @@ Optimization.Operators.solveFacilityLocation = (
|
|
|
1126
1126
|
|
|
1127
1127
|
// Solution initiale : place les infrastructures au hasard sur la carte.
|
|
1128
1128
|
const initialFacilities = Array.from({ length: numFacilities }, () => ({
|
|
1129
|
-
x: bounds.minX +
|
|
1130
|
-
y: bounds.minY +
|
|
1129
|
+
x: bounds.minX + random() * (bounds.maxX - bounds.minX),
|
|
1130
|
+
y: bounds.minY + random() * (bounds.maxY - bounds.minY),
|
|
1131
1131
|
}));
|
|
1132
1132
|
|
|
1133
1133
|
const saOptions = {
|
|
@@ -1244,7 +1244,7 @@ Optimization.Operators.solveOptimalCPC = (context, options = {}) => {
|
|
|
1244
1244
|
// Un "individu" est simplement une valeur de CPC.
|
|
1245
1245
|
const createIndividual = () => {
|
|
1246
1246
|
// Le CPC peut varier, par exemple, entre 0.5 et 5 PRIM'S.
|
|
1247
|
-
return 0.5 +
|
|
1247
|
+
return 0.5 + random() * 4.5;
|
|
1248
1248
|
};
|
|
1249
1249
|
|
|
1250
1250
|
// Croisement : moyenne des CPC des parents.
|
|
@@ -1254,7 +1254,7 @@ Optimization.Operators.solveOptimalCPC = (context, options = {}) => {
|
|
|
1254
1254
|
|
|
1255
1255
|
// Mutation : légère variation aléatoire du CPC.
|
|
1256
1256
|
const mutate = (cpc) => {
|
|
1257
|
-
const newCpc = cpc + (
|
|
1257
|
+
const newCpc = cpc + (random() - 0.5) * 0.5;
|
|
1258
1258
|
return Math.max(0.1, newCpc); // Assurer un CPC minimum.
|
|
1259
1259
|
};
|
|
1260
1260
|
|
|
@@ -1501,9 +1501,9 @@ Optimization.Operators.solveFraudDetection = (context, options = {}) => {
|
|
|
1501
1501
|
|
|
1502
1502
|
// Un "individu" est un tableau de 4 seuils : [minTimeToClick, maxClickVariance, minMouseEntropy, minScrollEvents]
|
|
1503
1503
|
const createIndividual = () => {
|
|
1504
|
-
const minTimeToClick = 100 +
|
|
1505
|
-
const maxClickVariance = 1 +
|
|
1506
|
-
const minMouseEntropy =
|
|
1504
|
+
const minTimeToClick = 100 + random() * 4900; // entre 100ms et 5s
|
|
1505
|
+
const maxClickVariance = 1 + random() * 9999; // entre 1 et 10000
|
|
1506
|
+
const minMouseEntropy = random() * 0.5; // entre 0 et 0.5
|
|
1507
1507
|
const minScrollEvents = crypto.randomInt(0, 10); // entre 0 et 10
|
|
1508
1508
|
return [minTimeToClick, maxClickVariance, minMouseEntropy, minScrollEvents];
|
|
1509
1509
|
};
|
|
@@ -1555,6 +1555,40 @@ Optimization.Operators.createFullSecurityConfigEvaluator = (context) => {
|
|
|
1555
1555
|
const trafficData = context.trafficData || [];
|
|
1556
1556
|
const currentConfig = context.currentConfig || null;
|
|
1557
1557
|
|
|
1558
|
+
|
|
1559
|
+
const THREAT_PROFILES = {
|
|
1560
|
+
account_takeover: {
|
|
1561
|
+
importance: 10.0,
|
|
1562
|
+
ux_vs_security_ratio: 0.1, // 10% FPR / 90% FNR (Priorité sécurité maximale)
|
|
1563
|
+
target_threshold: 'block',
|
|
1564
|
+
indicators: ['requestPatternScore', 'behaviorScore', 'timeInconsistencyScore', 'clickVarianceScore']
|
|
1565
|
+
},
|
|
1566
|
+
active_exploitation: {
|
|
1567
|
+
importance: 8.0,
|
|
1568
|
+
ux_vs_security_ratio: 0.2, // 20% FPR / 80% FNR (Sécurité prioritaire)
|
|
1569
|
+
target_threshold: 'block',
|
|
1570
|
+
indicators: ['honeypotScore', 'headerAnomalyScore']
|
|
1571
|
+
},
|
|
1572
|
+
mass_scraping: {
|
|
1573
|
+
importance: 3.0,
|
|
1574
|
+
ux_vs_security_ratio: 0.8, // 80% FPR / 20% FNR (UX prioritaire)
|
|
1575
|
+
target_threshold: 'low',
|
|
1576
|
+
indicators: ['requestPatternScore', 'renderingAnomalyScore', 'clientHintsInconsistencyScore']
|
|
1577
|
+
},
|
|
1578
|
+
distributed_botnets: {
|
|
1579
|
+
importance: 6.0,
|
|
1580
|
+
ux_vs_security_ratio: 0.5, // Équilibré
|
|
1581
|
+
target_threshold: 'high',
|
|
1582
|
+
indicators: ['subnetScore', 'botnetClusterScore', 'ipReputationScore', 'tlsSpoofingScore']
|
|
1583
|
+
},
|
|
1584
|
+
basic_automation: {
|
|
1585
|
+
importance: 5.0,
|
|
1586
|
+
ux_vs_security_ratio: 0.4, // 40% FPR / 60% FNR
|
|
1587
|
+
target_threshold: 'medium',
|
|
1588
|
+
indicators: ['botScore', 'tlsSpoofingScore', 'tcpAnomalyScore']
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
|
|
1558
1592
|
// Ancres immuables (Baseline Anchors) pour forcer le calibrage d'échelle de suspicion
|
|
1559
1593
|
const STATIC_ANCHORS = [
|
|
1560
1594
|
{
|
|
@@ -1608,10 +1642,10 @@ Optimization.Operators.createFullSecurityConfigEvaluator = (context) => {
|
|
|
1608
1642
|
];
|
|
1609
1643
|
|
|
1610
1644
|
return function fullConfigFitness(config) {
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1645
|
+
const threatStats = {};
|
|
1646
|
+
for (const threatName in THREAT_PROFILES) {
|
|
1647
|
+
threatStats[threatName] = { fp: 0, fn: 0, totalHumans: 0, totalBots: 0 };
|
|
1648
|
+
}
|
|
1615
1649
|
|
|
1616
1650
|
let maxHumanScore = 0;
|
|
1617
1651
|
let minBotScore = 100;
|
|
@@ -1642,42 +1676,96 @@ Optimization.Operators.createFullSecurityConfigEvaluator = (context) => {
|
|
|
1642
1676
|
const score = calculateScore(log);
|
|
1643
1677
|
|
|
1644
1678
|
if (isLikelyBot) {
|
|
1645
|
-
totalBots += confidence;
|
|
1646
1679
|
minBotScore = Math.min(minBotScore, score);
|
|
1647
|
-
if (score < config.thresholds.low) {
|
|
1648
|
-
falseNegatives += confidence;
|
|
1649
|
-
}
|
|
1650
1680
|
} else if (isLikelyHuman) {
|
|
1651
|
-
totalHumans += confidence;
|
|
1652
1681
|
maxHumanScore = Math.max(maxHumanScore, score);
|
|
1653
|
-
|
|
1654
|
-
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
for (const threatName in THREAT_PROFILES) {
|
|
1685
|
+
const profile = THREAT_PROFILES[threatName];
|
|
1686
|
+
let threatActivity = 0.0;
|
|
1687
|
+
for (const indicator of profile.indicators) {
|
|
1688
|
+
threatActivity += (log.vector?.[indicator] || 0.0);
|
|
1689
|
+
}
|
|
1690
|
+
if (threatActivity <= 0.0) {
|
|
1691
|
+
continue;
|
|
1692
|
+
}
|
|
1693
|
+
const effectiveConfidence = confidence * (threatActivity / 100.0);
|
|
1694
|
+
const targetThreshold = config.thresholds[profile.target_threshold] || 20;
|
|
1695
|
+
|
|
1696
|
+
if (isLikelyBot) {
|
|
1697
|
+
threatStats[threatName].totalBots += effectiveConfidence;
|
|
1698
|
+
if (score < targetThreshold) {
|
|
1699
|
+
threatStats[threatName].fn += effectiveConfidence;
|
|
1700
|
+
}
|
|
1701
|
+
} else if (isLikelyHuman) {
|
|
1702
|
+
threatStats[threatName].totalHumans += effectiveConfidence;
|
|
1703
|
+
if (score >= targetThreshold) {
|
|
1704
|
+
threatStats[threatName].fp += effectiveConfidence;
|
|
1705
|
+
}
|
|
1655
1706
|
}
|
|
1656
1707
|
}
|
|
1657
|
-
}
|
|
1658
1708
|
|
|
1709
|
+
}
|
|
1659
1710
|
// 2. Évaluation sur les ancres immuables pour fixer l'échelle
|
|
1660
1711
|
for (const anchor of STATIC_ANCHORS) {
|
|
1661
1712
|
const score = calculateScore(anchor);
|
|
1662
1713
|
const weight = anchor.weight;
|
|
1714
|
+
const isBot = anchor.type === 'request_blocked' || anchor.type === 'challenge_issued';
|
|
1663
1715
|
|
|
1664
|
-
if (
|
|
1665
|
-
totalBots += weight;
|
|
1716
|
+
if (isBot){
|
|
1666
1717
|
minBotScore = Math.min(minBotScore, score);
|
|
1667
|
-
if (score < config.thresholds.low) {
|
|
1668
|
-
falseNegatives += weight * 10; // Pénalité punitive forte
|
|
1669
|
-
}
|
|
1670
1718
|
} else {
|
|
1671
|
-
totalHumans += weight;
|
|
1672
1719
|
maxHumanScore = Math.max(maxHumanScore, score);
|
|
1673
|
-
|
|
1674
|
-
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
for (const threatName in THREAT_PROFILES) {
|
|
1723
|
+
const profile = THREAT_PROFILES[threatName];
|
|
1724
|
+
let threatActivity = 0.0;
|
|
1725
|
+
for (const indicator of profile.indicators) {
|
|
1726
|
+
threatActivity += (anchor.vector?.[indicator] || 0.0);
|
|
1727
|
+
}
|
|
1728
|
+
if (threatActivity <= 0.0) {
|
|
1729
|
+
continue;
|
|
1730
|
+
}
|
|
1731
|
+
const effectiveWeight = weight * (threatActivity / 100.0);
|
|
1732
|
+
const targetThreshold = config.thresholds[profile.target_threshold] || 20;
|
|
1733
|
+
|
|
1734
|
+
if (isBot) {
|
|
1735
|
+
threatStats[threatName].totalBots += effectiveWeight;
|
|
1736
|
+
if (score < targetThreshold) {
|
|
1737
|
+
threatStats[threatName].fn += effectiveWeight * 10; // Pénalité punitive forte
|
|
1738
|
+
}
|
|
1739
|
+
} else {
|
|
1740
|
+
threatStats[threatName].totalHumans += effectiveWeight;
|
|
1741
|
+
if (score >= targetThreshold) {
|
|
1742
|
+
threatStats[threatName].fp += effectiveWeight * 10; // Pénalité punitive forte
|
|
1743
|
+
}
|
|
1675
1744
|
}
|
|
1676
1745
|
}
|
|
1677
1746
|
}
|
|
1747
|
+
let weightedFpr = 0;
|
|
1748
|
+
let weightedFnr = 0;
|
|
1749
|
+
let totalImportance = 0;
|
|
1750
|
+
|
|
1751
|
+
for (const threatName in THREAT_PROFILES) {
|
|
1752
|
+
totalImportance += THREAT_PROFILES[threatName].importance;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
for (const threatName in THREAT_PROFILES) {
|
|
1756
|
+
const profile = THREAT_PROFILES[threatName];
|
|
1757
|
+
const stats = threatStats[threatName];
|
|
1758
|
+
|
|
1759
|
+
const fpr = stats.totalHumans > 0 ? stats.fp / stats.totalHumans : 0;
|
|
1760
|
+
const fnr = stats.totalBots > 0 ? stats.fn / stats.totalBots : 0;
|
|
1761
|
+
|
|
1762
|
+
const importanceWeight = profile.importance / totalImportance;
|
|
1763
|
+
const uxRatio = profile.ux_vs_security_ratio;
|
|
1764
|
+
const secRatio = 1.0 - uxRatio;
|
|
1678
1765
|
|
|
1679
|
-
|
|
1680
|
-
|
|
1766
|
+
weightedFpr += fpr * importanceWeight * uxRatio;
|
|
1767
|
+
weightedFnr += fnr * importanceWeight * secRatio;
|
|
1768
|
+
}
|
|
1681
1769
|
|
|
1682
1770
|
// 3. Pénalité de dérive d'échelle L2 (Régularisation par rapport au point d'origine)
|
|
1683
1771
|
let regularizationPenalty = 0;
|
|
@@ -1692,9 +1780,8 @@ Optimization.Operators.createFullSecurityConfigEvaluator = (context) => {
|
|
|
1692
1780
|
const marginOverlap = Math.max(0, maxHumanScore - minBotScore);
|
|
1693
1781
|
const marginPenalty = marginOverlap / 100;
|
|
1694
1782
|
|
|
1695
|
-
const obj1 =
|
|
1696
|
-
const obj2 =
|
|
1697
|
-
|
|
1783
|
+
const obj1 = weightedFpr + (regularizationPenalty * 0.05);
|
|
1784
|
+
const obj2 = weightedFnr + marginPenalty;
|
|
1698
1785
|
return [obj1, obj2];
|
|
1699
1786
|
};
|
|
1700
1787
|
};
|
|
@@ -1707,47 +1794,56 @@ Optimization.Operators.createFullSecurityConfigEvaluator = (context) => {
|
|
|
1707
1794
|
*/ // eslint-disable-line max-len
|
|
1708
1795
|
Optimization.Operators.solveFullSecurityTuning = (context, options = {}) => {
|
|
1709
1796
|
const fitnessFunction = Optimization.Operators.createFullSecurityConfigEvaluator(context);
|
|
1797
|
+
const currentConfig = context.currentConfig || {};
|
|
1798
|
+
const baseWeights = currentConfig.weights || {
|
|
1799
|
+
historyScore: 0.3,
|
|
1800
|
+
rotationScore: 0.5,
|
|
1801
|
+
headerAnomalyScore: 0.1,
|
|
1802
|
+
requestPatternScore: 0.6,
|
|
1803
|
+
inconsistencyScore: 0.8,
|
|
1804
|
+
honeypotScore: 1.0,
|
|
1805
|
+
behaviorScore: 0.7,
|
|
1806
|
+
crossLayerInconsistencyScore: 0.4,
|
|
1807
|
+
timeInconsistencyScore: 0.9,
|
|
1808
|
+
tlsSpoofingScore: 0.8,
|
|
1809
|
+
botScore: 1.0,
|
|
1810
|
+
subnetScore: 0.4,
|
|
1811
|
+
ipReputationScore: 0.5,
|
|
1812
|
+
botnetClusterScore: 0.6,
|
|
1813
|
+
tcpAnomalyScore: 0.8,
|
|
1814
|
+
quicAnomalyScore: 0.8,
|
|
1815
|
+
renderingAnomalyScore: 0.8,
|
|
1816
|
+
threatIntelScore: 1.0
|
|
1817
|
+
};
|
|
1710
1818
|
|
|
1711
1819
|
// Un "individu" est un objet de configuration complet
|
|
1712
1820
|
const createIndividual = () => ({
|
|
1713
1821
|
thresholds: {
|
|
1714
|
-
low: 15 +
|
|
1715
|
-
medium: 40 +
|
|
1716
|
-
high: 70 +
|
|
1717
|
-
|
|
1718
|
-
weights: {
|
|
1719
|
-
historyScore: secureRandom(),
|
|
1720
|
-
rotationScore: secureRandom(),
|
|
1721
|
-
headerAnomalyScore: secureRandom(),
|
|
1722
|
-
requestPatternScore: 0.5 + secureRandom(),
|
|
1723
|
-
inconsistencyScore: secureRandom(),
|
|
1724
|
-
honeypotScore: 1.0, // Garder le honeypot à 1.0 est une bonne pratique
|
|
1725
|
-
behaviorScore: secureRandom(),
|
|
1726
|
-
crossLayerInconsistencyScore: secureRandom(),
|
|
1727
|
-
timeInconsistencyScore: secureRandom(),
|
|
1728
|
-
tlsSpoofingScore: secureRandom(),
|
|
1729
|
-
botScore: secureRandom(),
|
|
1730
|
-
subnetScore: secureRandom(),
|
|
1731
|
-
ipReputationScore: secureRandom(),
|
|
1732
|
-
botnetClusterScore: secureRandom(),
|
|
1733
|
-
tcpAnomalyScore: secureRandom(),
|
|
1734
|
-
quicAnomalyScore: secureRandom(),
|
|
1735
|
-
clickVarianceScore: secureRandom(),
|
|
1736
|
-
clientHintsInconsistencyScore: secureRandom()
|
|
1822
|
+
low: 15 + random() * 20, // 15-35
|
|
1823
|
+
medium: 40 + random() * 25,
|
|
1824
|
+
high: 70 + random() * 20,
|
|
1825
|
+
block: 90 + random() * 9,
|
|
1737
1826
|
},
|
|
1827
|
+
weights: (() => {
|
|
1828
|
+
const w = {};
|
|
1829
|
+
for (const key in baseWeights) {
|
|
1830
|
+
w[key] = baseWeights[key] * (0.75 + random() * 0.5); // +/- 25%
|
|
1831
|
+
}
|
|
1832
|
+
return w;
|
|
1833
|
+
})(),
|
|
1738
1834
|
patterns: {
|
|
1739
|
-
velocityThreshold: 100 +
|
|
1740
|
-
velocityWeight: 10 +
|
|
1741
|
-
burstThreshold: 300 +
|
|
1742
|
-
burstWeight: 20 +
|
|
1743
|
-
scrapeThreshold: 500 +
|
|
1744
|
-
scrapeWeight: 15 +
|
|
1835
|
+
velocityThreshold: 100 + random() * 400,
|
|
1836
|
+
velocityWeight: 10 + random() * 40,
|
|
1837
|
+
burstThreshold: 300 + random() * 700,
|
|
1838
|
+
burstWeight: 20 + random() * 40,
|
|
1839
|
+
scrapeThreshold: 500 + random() * 1000,
|
|
1840
|
+
scrapeWeight: 15 + random() * 35,
|
|
1745
1841
|
sequenceLength: 3 + crypto.randomInt(0, 3),
|
|
1746
|
-
sequenceWeight: 20 +
|
|
1747
|
-
regularityThreshold: 50 +
|
|
1748
|
-
regularityWeight: 20 +
|
|
1749
|
-
decayFactor: 0.85 +
|
|
1750
|
-
inactivityReset: 15000 +
|
|
1842
|
+
sequenceWeight: 20 + random() * 50,
|
|
1843
|
+
regularityThreshold: 50 + random() * 200,
|
|
1844
|
+
regularityWeight: 20 + random() * 40,
|
|
1845
|
+
decayFactor: 0.85 + random() * 0.14,
|
|
1846
|
+
inactivityReset: 15000 + random() * 45000,
|
|
1751
1847
|
}
|
|
1752
1848
|
});
|
|
1753
1849
|
|
|
@@ -1759,9 +1855,7 @@ Optimization.Operators.solveFullSecurityTuning = (context, options = {}) => {
|
|
|
1759
1855
|
child.thresholds[key] = (c1.thresholds[key] + c2.thresholds[key]) / 2;
|
|
1760
1856
|
}
|
|
1761
1857
|
for (const key in child.weights) {
|
|
1762
|
-
|
|
1763
|
-
child.weights[key] = (c1.weights[key] + c2.weights[key]) / 2;
|
|
1764
|
-
}
|
|
1858
|
+
child.weights[key] = (c1.weights[key] + c2.weights[key]) / 2;
|
|
1765
1859
|
}
|
|
1766
1860
|
for (const key in child.patterns) {
|
|
1767
1861
|
child.patterns[key] = (c1.patterns[key] + c2.patterns[key]) / 2;
|
|
@@ -1776,11 +1870,11 @@ Optimization.Operators.solveFullSecurityTuning = (context, options = {}) => {
|
|
|
1776
1870
|
// On donne plus de poids à la mutation des 'patterns' et des 'weights',
|
|
1777
1871
|
// car ils ont un impact plus direct sur la détection que les seuils.
|
|
1778
1872
|
const sections = [
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1873
|
+
{ name: 'patterns', weight: 0.50 },
|
|
1874
|
+
{ name: 'thresholds', weight: 0.25 },
|
|
1875
|
+
{ name: 'weights', weight: 0.25 }
|
|
1782
1876
|
];
|
|
1783
|
-
const rand =
|
|
1877
|
+
const rand = random();
|
|
1784
1878
|
let cumulativeWeight = 0;
|
|
1785
1879
|
let sectionToMutate = 'patterns'; // Fallback
|
|
1786
1880
|
for (const section of sections) {
|
|
@@ -1794,21 +1888,18 @@ Optimization.Operators.solveFullSecurityTuning = (context, options = {}) => {
|
|
|
1794
1888
|
const keys = Object.keys(newConfig[sectionToMutate]);
|
|
1795
1889
|
const keyToMutate = keys[crypto.randomInt(0, keys.length)];
|
|
1796
1890
|
|
|
1797
|
-
if (keyToMutate === 'honeypotScore') return newConfig; // Ne pas muter le poids du honeypot
|
|
1798
|
-
|
|
1799
|
-
// Appliquer une mutation avec une amplitude variable
|
|
1800
|
-
const mutationAmount = (secureRandom() - 0.5) * 0.4; // +/- 20%
|
|
1801
|
-
newConfig[sectionToMutate][keyToMutate] *= (1 + mutationAmount);
|
|
1802
1891
|
|
|
1803
1892
|
// S'assurer que les valeurs restent dans des limites raisonnables
|
|
1804
1893
|
if (sectionToMutate === 'weights') {
|
|
1805
|
-
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1894
|
+
newConfig[sectionToMutate][keyToMutate] = Math.max(0.05, Math.min(1.5, newConfig[sectionToMutate][keyToMutate] + (random() - 0.5) * 0.1));
|
|
1895
|
+
} else if (sectionToMutate === 'thresholds') {
|
|
1896
|
+
newConfig[sectionToMutate][keyToMutate] = Math.round(newConfig[sectionToMutate][keyToMutate] + (random() - 0.5) * 5.0);
|
|
1897
|
+
} else {
|
|
1898
|
+
if (keyToMutate === 'decayFactor') {
|
|
1899
|
+
newConfig.patterns.decayFactor = Math.max(0.8, Math.min(0.999, newConfig.patterns.decayFactor + (random() - 0.5) * 0.05));
|
|
1900
|
+
} else if (keyToMutate.includes('Threshold') || keyToMutate.includes('Reset')) {
|
|
1901
|
+
newConfig.patterns[keyToMutate] = Math.max(50, newConfig.patterns[keyToMutate] + (random() - 0.5) * 50.0);
|
|
1902
|
+
}
|
|
1812
1903
|
}
|
|
1813
1904
|
|
|
1814
1905
|
// Contrainte de dérive maximale (±30% par rapport à la configuration actuelle)
|
|
@@ -53,6 +53,44 @@ function generateBlock(seed, blockIndex, blockSize = 1024) {
|
|
|
53
53
|
return block;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
async function loadTfjs() {
|
|
57
|
+
if (typeof tf !== 'undefined') return tf;
|
|
58
|
+
if (typeof window !== 'undefined') {
|
|
59
|
+
if (window.tf) return window.tf;
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
const script = document.createElement('script');
|
|
62
|
+
script.src = 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js';
|
|
63
|
+
script.onload = () => resolve(window.tf);
|
|
64
|
+
script.onerror = () => reject(new Error('Failed to load TensorFlow.js'));
|
|
65
|
+
document.head.appendChild(script);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
return await import('@tensorflow/tfjs');
|
|
70
|
+
} catch (e) {
|
|
71
|
+
throw new Error("TensorFlow.js is not available.");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function loadOnnxRuntime() {
|
|
76
|
+
if (typeof ort !== 'undefined') return ort;
|
|
77
|
+
if (typeof window !== 'undefined') {
|
|
78
|
+
if (window.ort) return window.ort;
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const script = document.createElement('script');
|
|
81
|
+
script.src = 'https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js';
|
|
82
|
+
script.onload = () => resolve(window.ort);
|
|
83
|
+
script.onerror = () => reject(new Error('Failed to load ONNX Runtime Web'));
|
|
84
|
+
document.head.appendChild(script);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
return await import('onnxruntime-node');
|
|
89
|
+
} catch (e) {
|
|
90
|
+
throw new Error("ONNX Runtime is not available.");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
56
94
|
async function initializeSpace(seed, sizeMb) {
|
|
57
95
|
const db = await openDb();
|
|
58
96
|
const transaction = db.transaction("blocks", "readwrite");
|
|
@@ -491,8 +529,8 @@ async function solveUsefulWorkTask(task) {
|
|
|
491
529
|
const i = Math.floor(secureRandom() * numFacilities);
|
|
492
530
|
const moveX = (secureRandom() - 0.5) * (bounds.maxX - bounds.minX) * 0.1;
|
|
493
531
|
const moveY = (secureRandom() - 0.5) * (bounds.maxY - bounds.minY) * 0.1;
|
|
494
|
-
|
|
495
|
-
|
|
532
|
+
newFacilities[i].x = Math.max(bounds.minX, Math.min(bounds.maxX, newFacilities[i].x + moveX));
|
|
533
|
+
newFacilities[i].y = Math.max(bounds.minY, Math.min(bounds.maxY, newFacilities[i].y + moveY));
|
|
496
534
|
return newFacilities;
|
|
497
535
|
};
|
|
498
536
|
const initialSolution = task.initialSolution || Array.from({ length: numFacilities }, () => ({
|
|
@@ -557,6 +595,94 @@ async function solveUsefulWorkTask(task) {
|
|
|
557
595
|
return solverFunction(task.payload, { generations: task.generations, initialFront: task.initialFront });
|
|
558
596
|
}
|
|
559
597
|
|
|
598
|
+
case 'pytorch_onnx_learning': {
|
|
599
|
+
const { weights, payload, modelPath } = task;
|
|
600
|
+
const inputs = payload.inputs || [];
|
|
601
|
+
const labels = payload.labels || [];
|
|
602
|
+
|
|
603
|
+
try {
|
|
604
|
+
const ort = await loadOnnxRuntime();
|
|
605
|
+
const session = await ort.InferenceSession.create(modelPath);
|
|
606
|
+
const inputName = session.inputNames[0];
|
|
607
|
+
const outputName = session.outputNames[0];
|
|
608
|
+
|
|
609
|
+
const dims = [inputs.length, inputs[0].length];
|
|
610
|
+
const inputTensor = new ort.Tensor('float32', Float32Array.from(inputs.flat()), dims);
|
|
611
|
+
const results = await session.run({ [inputName]: inputTensor });
|
|
612
|
+
const outputTensor = results[outputName];
|
|
613
|
+
const predictions = Array.from(outputTensor.data);
|
|
614
|
+
|
|
615
|
+
const gradients = new Array(weights.length).fill(0);
|
|
616
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
617
|
+
const x = inputs[i];
|
|
618
|
+
const y = labels[i];
|
|
619
|
+
const pred = predictions[i];
|
|
620
|
+
const error = pred - y;
|
|
621
|
+
for (let j = 0; j < weights.length; j++) {
|
|
622
|
+
gradients[j] += error * x[j] / inputs.length;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return { gradients, predictions };
|
|
626
|
+
} catch (err) {
|
|
627
|
+
console.warn('[Useful Work Solver] Real ONNX loading failed, using fallback simulation:', err);
|
|
628
|
+
const gradients = new Array(weights.length).fill(0);
|
|
629
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
630
|
+
const x = inputs[i];
|
|
631
|
+
const y = labels[i];
|
|
632
|
+
let pred = 0;
|
|
633
|
+
for (let j = 0; j < weights.length; j++) {
|
|
634
|
+
pred += x[j] * weights[j];
|
|
635
|
+
}
|
|
636
|
+
const error = pred - y;
|
|
637
|
+
for (let j = 0; j < weights.length; j++) {
|
|
638
|
+
gradients[j] += error * x[j] / inputs.length;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return { gradients };
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
case 'tfjs_learning': {
|
|
646
|
+
const { weights, payload, modelPath } = task;
|
|
647
|
+
const inputs = payload.inputs || [];
|
|
648
|
+
const labels = payload.labels || [];
|
|
649
|
+
try {
|
|
650
|
+
const tf = await loadTfjs();
|
|
651
|
+
const model = await tf.loadLayersModel(modelPath);
|
|
652
|
+
|
|
653
|
+
const xs = tf.tensor2d(inputs);
|
|
654
|
+
const ys = tf.tensor2d(labels);
|
|
655
|
+
|
|
656
|
+
const trainableVars = model.trainableWeights.map(w => w.read());
|
|
657
|
+
const lossFn = () => {
|
|
658
|
+
const preds = model.predict(xs);
|
|
659
|
+
return tf.losses.meanSquaredError(ys, preds);
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
const gFn = tf.grad(lossFn);
|
|
663
|
+
const grads = gFn(trainableVars);
|
|
664
|
+
|
|
665
|
+
const flatGradients = [];
|
|
666
|
+
const arr = await grads.array();
|
|
667
|
+
flatGradients.push(...arr.flat());
|
|
668
|
+
|
|
669
|
+
tf.dispose([xs, ys, ...grads]);
|
|
670
|
+
return { gradients: flatGradients };
|
|
671
|
+
} catch (err) {
|
|
672
|
+
console.warn('[Useful Work Solver] Real TFJS loading failed, using fallback simulation:', err);
|
|
673
|
+
const gradients = new Array(weights.length).fill(0);
|
|
674
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
675
|
+
const x = inputs[i];
|
|
676
|
+
const y = labels[i][0] !== undefined ? labels[i][0] : labels[i];
|
|
677
|
+
let pred = 0;
|
|
678
|
+
for (let j = 0; j < weights.length; j++) pred += x[j] * weights[j];
|
|
679
|
+
const error = pred - y;
|
|
680
|
+
for (let j = 0; j < weights.length; j++) gradients[j] += error * x[j] / inputs.length;
|
|
681
|
+
}
|
|
682
|
+
return { gradients };
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
560
686
|
default:
|
|
561
687
|
throw new Error(`Unknown useful work type: ${task.type}`);
|
|
562
688
|
}
|