@agirails/sdk 2.0.0 → 2.0.1-beta
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/README.md +108 -116
- package/dist/ACTPClient.d.ts +33 -456
- package/dist/ACTPClient.d.ts.map +1 -1
- package/dist/ACTPClient.js +93 -477
- package/dist/ACTPClient.js.map +1 -1
- package/dist/abi/EscrowVault.json +38 -106
- package/dist/builders/DeliveryProofBuilder.d.ts +1 -60
- package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -1
- package/dist/builders/DeliveryProofBuilder.js +5 -81
- package/dist/builders/DeliveryProofBuilder.js.map +1 -1
- package/dist/builders/QuoteBuilder.d.ts +0 -101
- package/dist/builders/QuoteBuilder.d.ts.map +1 -1
- package/dist/builders/QuoteBuilder.js +3 -120
- package/dist/builders/QuoteBuilder.js.map +1 -1
- package/dist/builders/index.d.ts +0 -4
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +0 -4
- package/dist/builders/index.js.map +1 -1
- package/dist/config/networks.d.ts +0 -28
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +12 -60
- package/dist/config/networks.js.map +1 -1
- package/dist/errors/index.d.ts +2 -165
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +2 -260
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +13 -61
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -141
- package/dist/index.js.map +1 -1
- package/dist/protocol/ACTPKernel.d.ts +2 -229
- package/dist/protocol/ACTPKernel.d.ts.map +1 -1
- package/dist/protocol/ACTPKernel.js +33 -367
- package/dist/protocol/ACTPKernel.js.map +1 -1
- package/dist/protocol/EASHelper.d.ts +2 -57
- package/dist/protocol/EASHelper.d.ts.map +1 -1
- package/dist/protocol/EASHelper.js +37 -230
- package/dist/protocol/EASHelper.js.map +1 -1
- package/dist/protocol/EscrowVault.d.ts +2 -93
- package/dist/protocol/EscrowVault.d.ts.map +1 -1
- package/dist/protocol/EscrowVault.js +33 -122
- package/dist/protocol/EscrowVault.js.map +1 -1
- package/dist/protocol/EventMonitor.d.ts +1 -45
- package/dist/protocol/EventMonitor.d.ts.map +1 -1
- package/dist/protocol/EventMonitor.js +8 -64
- package/dist/protocol/EventMonitor.js.map +1 -1
- package/dist/protocol/MessageSigner.d.ts +2 -116
- package/dist/protocol/MessageSigner.d.ts.map +1 -1
- package/dist/protocol/MessageSigner.js +9 -215
- package/dist/protocol/MessageSigner.js.map +1 -1
- package/dist/protocol/ProofGenerator.d.ts +0 -93
- package/dist/protocol/ProofGenerator.d.ts.map +1 -1
- package/dist/protocol/ProofGenerator.js +9 -194
- package/dist/protocol/ProofGenerator.js.map +1 -1
- package/dist/protocol/QuoteBuilder.d.ts +0 -8
- package/dist/protocol/QuoteBuilder.d.ts.map +1 -1
- package/dist/protocol/QuoteBuilder.js +0 -8
- package/dist/protocol/QuoteBuilder.js.map +1 -1
- package/dist/types/eip712.d.ts +0 -34
- package/dist/types/eip712.d.ts.map +1 -1
- package/dist/types/eip712.js +5 -31
- package/dist/types/eip712.js.map +1 -1
- package/dist/types/escrow.d.ts +10 -17
- package/dist/types/escrow.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -8
- package/dist/types/index.js.map +1 -1
- package/dist/types/message.d.ts +0 -32
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js +0 -4
- package/dist/types/message.js.map +1 -1
- package/dist/types/state.d.ts +0 -28
- package/dist/types/state.d.ts.map +1 -1
- package/dist/types/state.js +6 -37
- package/dist/types/state.js.map +1 -1
- package/dist/types/transaction.d.ts +0 -17
- package/dist/types/transaction.d.ts.map +1 -1
- package/dist/utils/IPFSClient.d.ts +0 -113
- package/dist/utils/IPFSClient.d.ts.map +1 -1
- package/dist/utils/IPFSClient.js +7 -128
- package/dist/utils/IPFSClient.js.map +1 -1
- package/dist/utils/NonceManager.d.ts +1 -234
- package/dist/utils/NonceManager.d.ts.map +1 -1
- package/dist/utils/NonceManager.js +7 -372
- package/dist/utils/NonceManager.js.map +1 -1
- package/dist/utils/ReceivedNonceTracker.d.ts +0 -175
- package/dist/utils/ReceivedNonceTracker.d.ts.map +1 -1
- package/dist/utils/ReceivedNonceTracker.js +5 -261
- package/dist/utils/ReceivedNonceTracker.js.map +1 -1
- package/dist/utils/canonicalJson.d.ts +0 -22
- package/dist/utils/canonicalJson.d.ts.map +1 -1
- package/dist/utils/canonicalJson.js +3 -26
- package/dist/utils/canonicalJson.js.map +1 -1
- package/dist/utils/computeTypeHash.d.ts +0 -14
- package/dist/utils/computeTypeHash.d.ts.map +1 -1
- package/dist/utils/computeTypeHash.js +2 -19
- package/dist/utils/computeTypeHash.js.map +1 -1
- package/dist/utils/validation.d.ts +0 -40
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +7 -184
- package/dist/utils/validation.js.map +1 -1
- package/package.json +37 -54
- package/src/ACTPClient.ts +178 -692
- package/src/__tests__/ProofGenerator.test.ts +124 -0
- package/src/__tests__/QuoteBuilder.test.ts +516 -0
- package/src/__tests__/StateMachine.test.ts +82 -0
- package/src/__tests__/builders/DeliveryProofBuilder.test.ts +581 -0
- package/src/__tests__/integration/ACTPClient.test.ts +263 -0
- package/src/__tests__/integration.test.ts +289 -0
- package/src/__tests__/protocol/EASHelper.test.ts +472 -0
- package/src/__tests__/protocol/EventMonitor.test.ts +382 -0
- package/src/__tests__/security/ACTPKernel.security.test.ts +1167 -0
- package/src/__tests__/security/EscrowVault.security.test.ts +570 -0
- package/src/__tests__/security/MessageSigner.security.test.ts +286 -0
- package/src/__tests__/security/NonceReplay.security.test.ts +501 -0
- package/src/__tests__/security/validation.security.test.ts +376 -0
- package/src/__tests__/utils/IPFSClient.test.ts +262 -0
- package/src/__tests__/utils/NonceManager.test.ts +205 -0
- package/src/__tests__/utils/canonicalJson.test.ts +153 -0
- package/src/abi/EscrowVault.json +38 -106
- package/src/builders/DeliveryProofBuilder.ts +2 -3
- package/src/config/networks.ts +9 -32
- package/src/errors/index.ts +1 -298
- package/src/index.ts +71 -207
- package/src/protocol/ACTPKernel.ts +23 -175
- package/src/protocol/EASHelper.ts +46 -230
- package/src/protocol/EscrowVault.ts +50 -68
- package/src/protocol/EventMonitor.ts +15 -44
- package/src/protocol/MessageSigner.ts +13 -193
- package/src/protocol/ProofGenerator.ts +4 -223
- package/src/types/escrow.ts +11 -12
- package/src/types/index.ts +1 -5
- package/src/types/state.ts +3 -12
- package/src/types/transaction.ts +1 -4
- package/src/utils/IPFSClient.ts +5 -122
- package/src/utils/NonceManager.ts +8 -305
- package/src/utils/ReceivedNonceTracker.ts +0 -170
- package/src/utils/validation.ts +0 -164
- package/LICENSE +0 -190
- package/bin/actp +0 -10
- package/dist/abi/AgentRegistry.json +0 -782
- package/dist/abi/IdentityRegistry.json +0 -316
- package/dist/adapters/BaseAdapter.d.ts +0 -231
- package/dist/adapters/BaseAdapter.d.ts.map +0 -1
- package/dist/adapters/BaseAdapter.js +0 -393
- package/dist/adapters/BaseAdapter.js.map +0 -1
- package/dist/adapters/BeginnerAdapter.d.ts +0 -152
- package/dist/adapters/BeginnerAdapter.d.ts.map +0 -1
- package/dist/adapters/BeginnerAdapter.js +0 -168
- package/dist/adapters/BeginnerAdapter.js.map +0 -1
- package/dist/adapters/IntermediateAdapter.d.ts +0 -211
- package/dist/adapters/IntermediateAdapter.d.ts.map +0 -1
- package/dist/adapters/IntermediateAdapter.js +0 -260
- package/dist/adapters/IntermediateAdapter.js.map +0 -1
- package/dist/adapters/index.d.ts +0 -15
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -26
- package/dist/adapters/index.js.map +0 -1
- package/dist/cli/commands/balance.d.ts +0 -13
- package/dist/cli/commands/balance.d.ts.map +0 -1
- package/dist/cli/commands/balance.js +0 -89
- package/dist/cli/commands/balance.js.map +0 -1
- package/dist/cli/commands/batch.d.ts +0 -24
- package/dist/cli/commands/batch.d.ts.map +0 -1
- package/dist/cli/commands/batch.js +0 -424
- package/dist/cli/commands/batch.js.map +0 -1
- package/dist/cli/commands/config.d.ts +0 -13
- package/dist/cli/commands/config.d.ts.map +0 -1
- package/dist/cli/commands/config.js +0 -192
- package/dist/cli/commands/config.js.map +0 -1
- package/dist/cli/commands/init.d.ts +0 -19
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/commands/init.js +0 -143
- package/dist/cli/commands/init.js.map +0 -1
- package/dist/cli/commands/mint.d.ts +0 -13
- package/dist/cli/commands/mint.d.ts.map +0 -1
- package/dist/cli/commands/mint.js +0 -91
- package/dist/cli/commands/mint.js.map +0 -1
- package/dist/cli/commands/pay.d.ts +0 -18
- package/dist/cli/commands/pay.d.ts.map +0 -1
- package/dist/cli/commands/pay.js +0 -87
- package/dist/cli/commands/pay.js.map +0 -1
- package/dist/cli/commands/simulate.d.ts +0 -32
- package/dist/cli/commands/simulate.d.ts.map +0 -1
- package/dist/cli/commands/simulate.js +0 -290
- package/dist/cli/commands/simulate.js.map +0 -1
- package/dist/cli/commands/time.d.ts +0 -29
- package/dist/cli/commands/time.d.ts.map +0 -1
- package/dist/cli/commands/time.js +0 -252
- package/dist/cli/commands/time.js.map +0 -1
- package/dist/cli/commands/tx.d.ts +0 -16
- package/dist/cli/commands/tx.d.ts.map +0 -1
- package/dist/cli/commands/tx.js +0 -379
- package/dist/cli/commands/tx.js.map +0 -1
- package/dist/cli/commands/watch.d.ts +0 -20
- package/dist/cli/commands/watch.d.ts.map +0 -1
- package/dist/cli/commands/watch.js +0 -160
- package/dist/cli/commands/watch.js.map +0 -1
- package/dist/cli/index.d.ts +0 -17
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -104
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/utils/client.d.ts +0 -70
- package/dist/cli/utils/client.d.ts.map +0 -1
- package/dist/cli/utils/client.js +0 -240
- package/dist/cli/utils/client.js.map +0 -1
- package/dist/cli/utils/config.d.ts +0 -91
- package/dist/cli/utils/config.d.ts.map +0 -1
- package/dist/cli/utils/config.js +0 -240
- package/dist/cli/utils/config.js.map +0 -1
- package/dist/cli/utils/output.d.ts +0 -174
- package/dist/cli/utils/output.d.ts.map +0 -1
- package/dist/cli/utils/output.js +0 -380
- package/dist/cli/utils/output.js.map +0 -1
- package/dist/level0/Provider.d.ts +0 -106
- package/dist/level0/Provider.d.ts.map +0 -1
- package/dist/level0/Provider.js +0 -10
- package/dist/level0/Provider.js.map +0 -1
- package/dist/level0/ServiceDirectory.d.ts +0 -74
- package/dist/level0/ServiceDirectory.d.ts.map +0 -1
- package/dist/level0/ServiceDirectory.js +0 -122
- package/dist/level0/ServiceDirectory.js.map +0 -1
- package/dist/level0/index.d.ts +0 -10
- package/dist/level0/index.d.ts.map +0 -1
- package/dist/level0/index.js +0 -15
- package/dist/level0/index.js.map +0 -1
- package/dist/level0/provide.d.ts +0 -51
- package/dist/level0/provide.d.ts.map +0 -1
- package/dist/level0/provide.js +0 -113
- package/dist/level0/provide.js.map +0 -1
- package/dist/level0/request.d.ts +0 -53
- package/dist/level0/request.d.ts.map +0 -1
- package/dist/level0/request.js +0 -462
- package/dist/level0/request.js.map +0 -1
- package/dist/level1/Agent.d.ts +0 -472
- package/dist/level1/Agent.d.ts.map +0 -1
- package/dist/level1/Agent.js +0 -1091
- package/dist/level1/Agent.js.map +0 -1
- package/dist/level1/index.d.ts +0 -10
- package/dist/level1/index.d.ts.map +0 -1
- package/dist/level1/index.js +0 -30
- package/dist/level1/index.js.map +0 -1
- package/dist/level1/pricing/PriceCalculator.d.ts +0 -62
- package/dist/level1/pricing/PriceCalculator.d.ts.map +0 -1
- package/dist/level1/pricing/PriceCalculator.js +0 -237
- package/dist/level1/pricing/PriceCalculator.js.map +0 -1
- package/dist/level1/pricing/PricingStrategy.d.ts +0 -179
- package/dist/level1/pricing/PricingStrategy.d.ts.map +0 -1
- package/dist/level1/pricing/PricingStrategy.js +0 -11
- package/dist/level1/pricing/PricingStrategy.js.map +0 -1
- package/dist/level1/types/Job.d.ts +0 -166
- package/dist/level1/types/Job.d.ts.map +0 -1
- package/dist/level1/types/Job.js +0 -11
- package/dist/level1/types/Job.js.map +0 -1
- package/dist/level1/types/Options.d.ts +0 -258
- package/dist/level1/types/Options.d.ts.map +0 -1
- package/dist/level1/types/Options.js +0 -8
- package/dist/level1/types/Options.js.map +0 -1
- package/dist/level1/types/index.d.ts +0 -8
- package/dist/level1/types/index.d.ts.map +0 -1
- package/dist/level1/types/index.js +0 -8
- package/dist/level1/types/index.js.map +0 -1
- package/dist/protocol/AgentRegistry.d.ts +0 -177
- package/dist/protocol/AgentRegistry.d.ts.map +0 -1
- package/dist/protocol/AgentRegistry.js +0 -449
- package/dist/protocol/AgentRegistry.js.map +0 -1
- package/dist/protocol/DIDManager.d.ts +0 -289
- package/dist/protocol/DIDManager.d.ts.map +0 -1
- package/dist/protocol/DIDManager.js +0 -481
- package/dist/protocol/DIDManager.js.map +0 -1
- package/dist/protocol/DIDResolver.d.ts +0 -236
- package/dist/protocol/DIDResolver.d.ts.map +0 -1
- package/dist/protocol/DIDResolver.js +0 -495
- package/dist/protocol/DIDResolver.js.map +0 -1
- package/dist/runtime/BlockchainRuntime.d.ts +0 -360
- package/dist/runtime/BlockchainRuntime.d.ts.map +0 -1
- package/dist/runtime/BlockchainRuntime.js +0 -767
- package/dist/runtime/BlockchainRuntime.js.map +0 -1
- package/dist/runtime/IACTPRuntime.d.ts +0 -271
- package/dist/runtime/IACTPRuntime.d.ts.map +0 -1
- package/dist/runtime/IACTPRuntime.js +0 -15
- package/dist/runtime/IACTPRuntime.js.map +0 -1
- package/dist/runtime/MockRuntime.d.ts +0 -445
- package/dist/runtime/MockRuntime.d.ts.map +0 -1
- package/dist/runtime/MockRuntime.js +0 -1065
- package/dist/runtime/MockRuntime.js.map +0 -1
- package/dist/runtime/MockStateManager.d.ts +0 -233
- package/dist/runtime/MockStateManager.d.ts.map +0 -1
- package/dist/runtime/MockStateManager.js +0 -533
- package/dist/runtime/MockStateManager.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -14
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/index.js +0 -42
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/types/MockState.d.ts +0 -167
- package/dist/runtime/types/MockState.d.ts.map +0 -1
- package/dist/runtime/types/MockState.js +0 -43
- package/dist/runtime/types/MockState.js.map +0 -1
- package/dist/types/agent.d.ts +0 -76
- package/dist/types/agent.d.ts.map +0 -1
- package/dist/types/agent.js +0 -8
- package/dist/types/agent.js.map +0 -1
- package/dist/types/did.d.ts +0 -192
- package/dist/types/did.d.ts.map +0 -1
- package/dist/types/did.js +0 -38
- package/dist/types/did.js.map +0 -1
- package/dist/utils/ErrorRecoveryGuide.d.ts +0 -125
- package/dist/utils/ErrorRecoveryGuide.d.ts.map +0 -1
- package/dist/utils/ErrorRecoveryGuide.js +0 -579
- package/dist/utils/ErrorRecoveryGuide.js.map +0 -1
- package/dist/utils/Helpers.d.ts +0 -453
- package/dist/utils/Helpers.d.ts.map +0 -1
- package/dist/utils/Helpers.js +0 -623
- package/dist/utils/Helpers.js.map +0 -1
- package/dist/utils/Logger.d.ts +0 -195
- package/dist/utils/Logger.d.ts.map +0 -1
- package/dist/utils/Logger.js +0 -382
- package/dist/utils/Logger.js.map +0 -1
- package/dist/utils/RateLimiter.d.ts +0 -253
- package/dist/utils/RateLimiter.d.ts.map +0 -1
- package/dist/utils/RateLimiter.js +0 -424
- package/dist/utils/RateLimiter.js.map +0 -1
- package/dist/utils/SDKLifecycle.d.ts +0 -156
- package/dist/utils/SDKLifecycle.d.ts.map +0 -1
- package/dist/utils/SDKLifecycle.js +0 -347
- package/dist/utils/SDKLifecycle.js.map +0 -1
- package/dist/utils/SecureNonce.d.ts +0 -57
- package/dist/utils/SecureNonce.d.ts.map +0 -1
- package/dist/utils/SecureNonce.js +0 -80
- package/dist/utils/SecureNonce.js.map +0 -1
- package/dist/utils/Semaphore.d.ts +0 -123
- package/dist/utils/Semaphore.d.ts.map +0 -1
- package/dist/utils/Semaphore.js +0 -247
- package/dist/utils/Semaphore.js.map +0 -1
- package/dist/utils/UsedAttestationTracker.d.ts +0 -167
- package/dist/utils/UsedAttestationTracker.d.ts.map +0 -1
- package/dist/utils/UsedAttestationTracker.js +0 -309
- package/dist/utils/UsedAttestationTracker.js.map +0 -1
- package/dist/utils/fsSafe.d.ts +0 -14
- package/dist/utils/fsSafe.d.ts.map +0 -1
- package/dist/utils/fsSafe.js +0 -89
- package/dist/utils/fsSafe.js.map +0 -1
- package/dist/utils/index.d.ts +0 -15
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -51
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/security.d.ts +0 -147
- package/dist/utils/security.d.ts.map +0 -1
- package/dist/utils/security.js +0 -391
- package/dist/utils/security.js.map +0 -1
- package/src/abi/AgentRegistry.json +0 -782
- package/src/abi/IdentityRegistry.json +0 -316
- package/src/adapters/BaseAdapter.ts +0 -473
- package/src/adapters/BeginnerAdapter.ts +0 -232
- package/src/adapters/IntermediateAdapter.ts +0 -316
- package/src/adapters/index.ts +0 -25
- package/src/cli/commands/balance.ts +0 -110
- package/src/cli/commands/batch.ts +0 -487
- package/src/cli/commands/config.ts +0 -231
- package/src/cli/commands/init.ts +0 -161
- package/src/cli/commands/mint.ts +0 -116
- package/src/cli/commands/pay.ts +0 -113
- package/src/cli/commands/simulate.ts +0 -345
- package/src/cli/commands/time.ts +0 -303
- package/src/cli/commands/tx.ts +0 -448
- package/src/cli/commands/watch.ts +0 -211
- package/src/cli/index.ts +0 -116
- package/src/cli/utils/client.ts +0 -249
- package/src/cli/utils/config.ts +0 -282
- package/src/cli/utils/output.ts +0 -465
- package/src/level0/Provider.ts +0 -117
- package/src/level0/ServiceDirectory.ts +0 -131
- package/src/level0/index.ts +0 -10
- package/src/level0/provide.ts +0 -131
- package/src/level0/request.ts +0 -494
- package/src/level1/Agent.ts +0 -1432
- package/src/level1/index.ts +0 -10
- package/src/level1/pricing/PriceCalculator.ts +0 -255
- package/src/level1/pricing/PricingStrategy.ts +0 -198
- package/src/level1/types/Job.ts +0 -179
- package/src/level1/types/Options.ts +0 -291
- package/src/level1/types/index.ts +0 -8
- package/src/protocol/AgentRegistry.ts +0 -559
- package/src/protocol/DIDManager.ts +0 -629
- package/src/protocol/DIDResolver.ts +0 -554
- package/src/runtime/BlockchainRuntime.ts +0 -993
- package/src/runtime/IACTPRuntime.ts +0 -284
- package/src/runtime/MockRuntime.ts +0 -1244
- package/src/runtime/MockStateManager.ts +0 -576
- package/src/runtime/index.ts +0 -25
- package/src/runtime/types/MockState.ts +0 -227
- package/src/types/agent.ts +0 -79
- package/src/types/did.ts +0 -223
- package/src/utils/ErrorRecoveryGuide.ts +0 -675
- package/src/utils/Helpers.ts +0 -688
- package/src/utils/Logger.ts +0 -484
- package/src/utils/RateLimiter.ts +0 -534
- package/src/utils/SDKLifecycle.ts +0 -416
- package/src/utils/SecureNonce.ts +0 -78
- package/src/utils/Semaphore.ts +0 -276
- package/src/utils/UsedAttestationTracker.ts +0 -387
- package/src/utils/fsSafe.ts +0 -75
- package/src/utils/index.ts +0 -80
- package/src/utils/security.ts +0 -418
|
@@ -2,21 +2,7 @@
|
|
|
2
2
|
* Nonce Manager Implementation
|
|
3
3
|
* Tracks nonces per DID + message type for AIP-4 delivery proofs
|
|
4
4
|
* Reference: AIP-4 §3.2 (nonce field requirement)
|
|
5
|
-
*
|
|
6
|
-
* SECURITY FIXES:
|
|
7
|
-
* - C-2: Added atomic nonce allocation with locking
|
|
8
|
-
* - H-1: Added persistent nonce storage option
|
|
9
|
-
* - H-5: Added nonce upper bound validation
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { assertSafeFileForRead, ensureSafeDir, ensureSafeFile } from './fsSafe';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Maximum allowed nonce value.
|
|
16
|
-
* SECURITY FIX (H-5): Prevents nonce overflow attacks.
|
|
17
|
-
* Using Number.MAX_SAFE_INTEGER (2^53 - 1) to ensure safe JavaScript integer operations.
|
|
18
5
|
*/
|
|
19
|
-
export const MAX_NONCE_VALUE = Number.MAX_SAFE_INTEGER;
|
|
20
6
|
|
|
21
7
|
/**
|
|
22
8
|
* Nonce Manager Interface (from DeliveryProofBuilder)
|
|
@@ -54,10 +40,6 @@ export interface NonceManager {
|
|
|
54
40
|
* In-Memory Nonce Manager
|
|
55
41
|
* Simple implementation using Map for per-message-type nonce tracking
|
|
56
42
|
*
|
|
57
|
-
* SECURITY FIXES:
|
|
58
|
-
* - C-2: Added atomic getAndIncrementNonce() to prevent race conditions
|
|
59
|
-
* - H-5: Added nonce upper bound validation
|
|
60
|
-
*
|
|
61
43
|
* ⚠️ WARNING: Nonces are lost on process restart. For production:
|
|
62
44
|
* - Use persistent storage (Redis, PostgreSQL, etc.)
|
|
63
45
|
* - Implement nonce recovery from blockchain events
|
|
@@ -65,9 +47,6 @@ export interface NonceManager {
|
|
|
65
47
|
*/
|
|
66
48
|
export class InMemoryNonceManager implements NonceManager {
|
|
67
49
|
private nonces: Map<string, number> = new Map();
|
|
68
|
-
// SECURITY FIX (C-2): Mutex for atomic nonce operations
|
|
69
|
-
// Store both the promise and its resolver for proper lock release
|
|
70
|
-
private locks: Map<string, { promise: Promise<void>; resolve: () => void }> = new Map();
|
|
71
50
|
|
|
72
51
|
/**
|
|
73
52
|
* Create in-memory nonce manager
|
|
@@ -76,58 +55,11 @@ export class InMemoryNonceManager implements NonceManager {
|
|
|
76
55
|
constructor(initialNonces?: Record<string, number>) {
|
|
77
56
|
if (initialNonces) {
|
|
78
57
|
Object.entries(initialNonces).forEach(([messageType, nonce]) => {
|
|
79
|
-
// SECURITY FIX (H-5): Validate initial nonces
|
|
80
|
-
if (nonce > MAX_NONCE_VALUE) {
|
|
81
|
-
throw new Error(
|
|
82
|
-
`Initial nonce ${nonce} for ${messageType} exceeds maximum allowed value ${MAX_NONCE_VALUE}`
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
58
|
this.nonces.set(messageType, nonce);
|
|
86
59
|
});
|
|
87
60
|
}
|
|
88
61
|
}
|
|
89
62
|
|
|
90
|
-
/**
|
|
91
|
-
* SECURITY FIX (C-2 + DEADLOCK-FIX): Acquire lock for message type
|
|
92
|
-
* Ensures atomic nonce operations.
|
|
93
|
-
*
|
|
94
|
-
* FIXED: Previous implementation had a deadlock bug where:
|
|
95
|
-
* - The resolver was stored in a closure but never accessible to releaseLock()
|
|
96
|
-
* - releaseLock() just deleted the entry without resolving waiting Promises
|
|
97
|
-
*
|
|
98
|
-
* New implementation stores both promise AND resolver together.
|
|
99
|
-
*/
|
|
100
|
-
private async acquireLock(messageType: string): Promise<void> {
|
|
101
|
-
// Wait for any existing lock to be released
|
|
102
|
-
while (this.locks.has(messageType)) {
|
|
103
|
-
const existingLock = this.locks.get(messageType);
|
|
104
|
-
if (existingLock) {
|
|
105
|
-
await existingLock.promise;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Create new lock with stored resolver
|
|
110
|
-
let resolver: () => void = () => {};
|
|
111
|
-
const lockPromise = new Promise<void>((resolve) => {
|
|
112
|
-
resolver = resolve;
|
|
113
|
-
});
|
|
114
|
-
this.locks.set(messageType, { promise: lockPromise, resolve: resolver });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* SECURITY FIX (C-2 + DEADLOCK-FIX): Release lock for message type
|
|
119
|
-
*
|
|
120
|
-
* FIXED: Now properly resolves the Promise before deleting,
|
|
121
|
-
* so any waiting acquireLock() calls can proceed.
|
|
122
|
-
*/
|
|
123
|
-
private releaseLock(messageType: string): void {
|
|
124
|
-
const lock = this.locks.get(messageType);
|
|
125
|
-
if (lock) {
|
|
126
|
-
lock.resolve(); // Resolve the promise first
|
|
127
|
-
this.locks.delete(messageType); // Then delete the entry
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
63
|
/**
|
|
132
64
|
* Get next nonce for message type
|
|
133
65
|
* @param messageType - Message type identifier
|
|
@@ -135,44 +67,7 @@ export class InMemoryNonceManager implements NonceManager {
|
|
|
135
67
|
*/
|
|
136
68
|
getNextNonce(messageType: string): number {
|
|
137
69
|
const current = this.nonces.get(messageType) || 0;
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
// SECURITY FIX (H-5): Check upper bound
|
|
141
|
-
if (next > MAX_NONCE_VALUE) {
|
|
142
|
-
throw new Error(
|
|
143
|
-
`Nonce overflow: next nonce ${next} exceeds maximum allowed value ${MAX_NONCE_VALUE}. ` +
|
|
144
|
-
`Consider resetting nonces or using a larger storage type.`
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return next;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* SECURITY FIX (C-2): Atomic get-and-increment nonce
|
|
153
|
-
* Returns the next nonce and records it atomically to prevent race conditions.
|
|
154
|
-
*
|
|
155
|
-
* @param messageType - Message type identifier
|
|
156
|
-
* @returns Atomically allocated nonce
|
|
157
|
-
*/
|
|
158
|
-
async getAndIncrementNonce(messageType: string): Promise<number> {
|
|
159
|
-
await this.acquireLock(messageType);
|
|
160
|
-
try {
|
|
161
|
-
const current = this.nonces.get(messageType) || 0;
|
|
162
|
-
const next = current + 1;
|
|
163
|
-
|
|
164
|
-
// SECURITY FIX (H-5): Check upper bound
|
|
165
|
-
if (next > MAX_NONCE_VALUE) {
|
|
166
|
-
throw new Error(
|
|
167
|
-
`Nonce overflow: next nonce ${next} exceeds maximum allowed value ${MAX_NONCE_VALUE}`
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
this.nonces.set(messageType, next);
|
|
172
|
-
return next;
|
|
173
|
-
} finally {
|
|
174
|
-
this.releaseLock(messageType);
|
|
175
|
-
}
|
|
70
|
+
return current + 1;
|
|
176
71
|
}
|
|
177
72
|
|
|
178
73
|
/**
|
|
@@ -183,13 +78,6 @@ export class InMemoryNonceManager implements NonceManager {
|
|
|
183
78
|
recordNonce(messageType: string, nonce: number): void {
|
|
184
79
|
const current = this.nonces.get(messageType) || 0;
|
|
185
80
|
|
|
186
|
-
// SECURITY FIX (H-5): Check upper bound
|
|
187
|
-
if (nonce > MAX_NONCE_VALUE) {
|
|
188
|
-
throw new Error(
|
|
189
|
-
`Nonce ${nonce} exceeds maximum allowed value ${MAX_NONCE_VALUE}`
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
81
|
// Ensure monotonic increase
|
|
194
82
|
if (nonce <= current) {
|
|
195
83
|
throw new Error(
|
|
@@ -388,203 +276,18 @@ export class DIDScopedNonceManager implements NonceManager {
|
|
|
388
276
|
}
|
|
389
277
|
}
|
|
390
278
|
|
|
391
|
-
/**
|
|
392
|
-
* File-based Nonce Manager for Persistent Storage
|
|
393
|
-
*
|
|
394
|
-
* SECURITY FIX (H-1): Persists nonces to disk to survive process restarts.
|
|
395
|
-
* SECURITY FIX (NEW-H-4): File locking to prevent concurrent write corruption.
|
|
396
|
-
* Uses atomic file writes (temp file + rename) for crash safety.
|
|
397
|
-
*
|
|
398
|
-
* @module utils/NonceManager
|
|
399
|
-
*/
|
|
400
|
-
export class FileBasedNonceManager implements NonceManager {
|
|
401
|
-
private inMemory: InMemoryNonceManager;
|
|
402
|
-
private filePath: string;
|
|
403
|
-
private fs: typeof import('fs');
|
|
404
|
-
private path: typeof import('path');
|
|
405
|
-
private lockfile: typeof import('proper-lockfile');
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Create file-based nonce manager
|
|
409
|
-
* @param stateDirectory - Directory to store nonces file
|
|
410
|
-
*/
|
|
411
|
-
constructor(stateDirectory: string) {
|
|
412
|
-
this.fs = require('fs');
|
|
413
|
-
this.path = require('path');
|
|
414
|
-
// SECURITY FIX (NEW-H-4): File locking to prevent race conditions
|
|
415
|
-
this.lockfile = require('proper-lockfile');
|
|
416
|
-
|
|
417
|
-
// Ensure .actp directory exists
|
|
418
|
-
const actpDir = this.path.join(stateDirectory, '.actp');
|
|
419
|
-
ensureSafeDir(actpDir, 0o755);
|
|
420
|
-
|
|
421
|
-
this.filePath = this.path.join(actpDir, 'nonces.json');
|
|
422
|
-
|
|
423
|
-
// Load existing nonces
|
|
424
|
-
const initialNonces = this.loadFromFile();
|
|
425
|
-
this.inMemory = new InMemoryNonceManager(initialNonces);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Load nonces from file
|
|
430
|
-
*/
|
|
431
|
-
private loadFromFile(): Record<string, number> | undefined {
|
|
432
|
-
if (!this.fs.existsSync(this.filePath)) {
|
|
433
|
-
return undefined;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
try {
|
|
437
|
-
// SECURITY: Refuse to read from symlinked nonce files
|
|
438
|
-
assertSafeFileForRead(this.filePath);
|
|
439
|
-
|
|
440
|
-
const MAX_NONCE_FILE_SIZE = 5 * 1024 * 1024; // 5MB
|
|
441
|
-
const st = this.fs.statSync(this.filePath);
|
|
442
|
-
if (st.size > MAX_NONCE_FILE_SIZE) {
|
|
443
|
-
throw new Error(
|
|
444
|
-
`nonces.json exceeds ${MAX_NONCE_FILE_SIZE / 1024 / 1024}MB limit: ${this.filePath}`
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
const data = JSON.parse(this.fs.readFileSync(this.filePath, 'utf-8'));
|
|
449
|
-
return data as Record<string, number>;
|
|
450
|
-
} catch (e: any) {
|
|
451
|
-
// Fail closed: nonce resets can enable replay.
|
|
452
|
-
throw new Error(
|
|
453
|
-
`Failed to parse nonces.json (replay protection would be weakened). ` +
|
|
454
|
-
`Fix/delete the file: ${this.filePath}. Error: ${e?.message || String(e)}`
|
|
455
|
-
);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Save nonces to file atomically with file locking
|
|
461
|
-
*
|
|
462
|
-
* SECURITY FIX (NEW-H-4): File locking prevents concurrent write corruption
|
|
463
|
-
*/
|
|
464
|
-
private async saveToFile(): Promise<void> {
|
|
465
|
-
const data = this.inMemory.getAllNonces();
|
|
466
|
-
const tempPath = `${this.filePath}.tmp`;
|
|
467
|
-
|
|
468
|
-
// SECURITY FIX: Ensure file exists before locking (proper-lockfile requirement)
|
|
469
|
-
ensureSafeFile(this.filePath, '{}', 0o644);
|
|
470
|
-
|
|
471
|
-
// SECURITY FIX (NEW-H-4): Acquire file lock before writing
|
|
472
|
-
let release: (() => Promise<void>) | null = null;
|
|
473
|
-
try {
|
|
474
|
-
release = await this.lockfile.lock(this.filePath, {
|
|
475
|
-
stale: 10000, // Lock expires after 10 seconds if process crashes
|
|
476
|
-
retries: {
|
|
477
|
-
retries: 5,
|
|
478
|
-
minTimeout: 100,
|
|
479
|
-
maxTimeout: 500
|
|
480
|
-
}
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
// Atomic write: temp file + rename
|
|
484
|
-
if (this.fs.existsSync(tempPath)) {
|
|
485
|
-
this.fs.unlinkSync(tempPath);
|
|
486
|
-
}
|
|
487
|
-
this.fs.writeFileSync(tempPath, JSON.stringify(data, null, 2), {
|
|
488
|
-
encoding: 'utf-8',
|
|
489
|
-
mode: 0o644,
|
|
490
|
-
flag: 'wx'
|
|
491
|
-
});
|
|
492
|
-
this.fs.renameSync(tempPath, this.filePath);
|
|
493
|
-
} catch (error) {
|
|
494
|
-
// Clean up temp file on error
|
|
495
|
-
if (this.fs.existsSync(tempPath)) {
|
|
496
|
-
try {
|
|
497
|
-
this.fs.unlinkSync(tempPath);
|
|
498
|
-
} catch {
|
|
499
|
-
// Ignore cleanup errors
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
throw error;
|
|
503
|
-
} finally {
|
|
504
|
-
if (release) {
|
|
505
|
-
await release();
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
getNextNonce(messageType: string): number {
|
|
511
|
-
return this.inMemory.getNextNonce(messageType);
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/**
|
|
515
|
-
* Atomic get and increment with persistence
|
|
516
|
-
*/
|
|
517
|
-
async getAndIncrementNonce(messageType: string): Promise<number> {
|
|
518
|
-
const nonce = await this.inMemory.getAndIncrementNonce(messageType);
|
|
519
|
-
// SECURITY FIX (NEW-H-4): saveToFile is now async
|
|
520
|
-
await this.saveToFile();
|
|
521
|
-
return nonce;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
recordNonce(messageType: string, nonce: number): void {
|
|
525
|
-
this.inMemory.recordNonce(messageType, nonce);
|
|
526
|
-
// Fire-and-forget to maintain sync interface
|
|
527
|
-
this.saveToFile().catch((err) => {
|
|
528
|
-
console.error('Failed to save nonce manager state:', err);
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
getCurrentNonce(messageType: string): number {
|
|
533
|
-
return this.inMemory.getCurrentNonce(messageType);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
resetNonce(messageType: string): void {
|
|
537
|
-
this.inMemory.resetNonce(messageType);
|
|
538
|
-
// Fire-and-forget to maintain sync interface
|
|
539
|
-
this.saveToFile().catch((err) => {
|
|
540
|
-
console.error('Failed to save nonce manager state:', err);
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
getAllNonces(): Record<string, number> {
|
|
545
|
-
return this.inMemory.getAllNonces();
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
clearAll(): void {
|
|
549
|
-
this.inMemory.clearAll();
|
|
550
|
-
if (this.fs.existsSync(this.filePath)) {
|
|
551
|
-
this.fs.unlinkSync(this.filePath);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
|
|
556
279
|
/**
|
|
557
280
|
* Create nonce manager based on environment
|
|
558
|
-
* @param
|
|
281
|
+
* @param did - Optional DID for scoped tracking
|
|
282
|
+
* @param initialNonces - Optional initial nonces
|
|
559
283
|
* @returns NonceManager instance
|
|
560
|
-
*
|
|
561
|
-
* @example
|
|
562
|
-
* ```typescript
|
|
563
|
-
* // In-memory (default)
|
|
564
|
-
* const manager = createNonceManager();
|
|
565
|
-
*
|
|
566
|
-
* // DID-scoped
|
|
567
|
-
* const manager = createNonceManager({ did: 'did:ethr:0x...' });
|
|
568
|
-
*
|
|
569
|
-
* // Persistent (survives restarts)
|
|
570
|
-
* const manager = createNonceManager({ stateDirectory: '/path/to/project' });
|
|
571
|
-
* ```
|
|
572
284
|
*/
|
|
573
285
|
export function createNonceManager(
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
initialNonces?: Record<string, number>;
|
|
577
|
-
stateDirectory?: string;
|
|
578
|
-
}
|
|
286
|
+
did?: string,
|
|
287
|
+
initialNonces?: Record<string, number>
|
|
579
288
|
): NonceManager {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
return new FileBasedNonceManager(options.stateDirectory);
|
|
289
|
+
if (did) {
|
|
290
|
+
return new DIDScopedNonceManager(did, initialNonces);
|
|
583
291
|
}
|
|
584
|
-
|
|
585
|
-
if (options?.did) {
|
|
586
|
-
return new DIDScopedNonceManager(options.did, options?.initialNonces);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
return new InMemoryNonceManager(options?.initialNonces);
|
|
292
|
+
return new InMemoryNonceManager(initialNonces);
|
|
590
293
|
}
|
|
@@ -228,10 +228,6 @@ export class InMemoryReceivedNonceTracker implements IReceivedNonceTracker {
|
|
|
228
228
|
* - Reject duplicate nonces (replay attack)
|
|
229
229
|
* - Allows non-sequential nonces (nonce gaps are OK)
|
|
230
230
|
*
|
|
231
|
-
* SECURITY FIX (NEW-H-2): Max size enforcement to prevent memory exhaustion
|
|
232
|
-
* SECURITY FIX (HIGH-2): Global total entries limit to prevent DoS via many sender combinations
|
|
233
|
-
* SECURITY FIX (H-2): Rate limiting per sender to prevent flood attacks
|
|
234
|
-
*
|
|
235
231
|
* Trade-off:
|
|
236
232
|
* - Higher memory usage (stores every nonce)
|
|
237
233
|
* - More flexible (allows out-of-order delivery)
|
|
@@ -241,94 +237,8 @@ export class SetBasedReceivedNonceTracker implements IReceivedNonceTracker {
|
|
|
241
237
|
// Map: sender -> messageType -> Set of used nonces
|
|
242
238
|
private usedNonces: Map<string, Map<string, Set<string>>> = new Map();
|
|
243
239
|
|
|
244
|
-
// SECURITY FIX (NEW-H-2): Maximum entries per sender+messageType
|
|
245
|
-
private readonly maxSizePerType: number;
|
|
246
|
-
|
|
247
|
-
// SECURITY FIX (HIGH-2): Global limit across ALL sender+messageType combinations
|
|
248
|
-
private readonly maxTotalEntries: number;
|
|
249
|
-
private totalEntries: number = 0;
|
|
250
|
-
|
|
251
|
-
// SECURITY FIX (H-2): Rate limiting per sender
|
|
252
|
-
// Map: sender -> { count: number, windowStart: number }
|
|
253
|
-
private rateLimitState: Map<string, { count: number; windowStart: number }> = new Map();
|
|
254
|
-
private readonly maxNoncesPerMinute: number;
|
|
255
|
-
private readonly rateLimitWindowMs: number = 60000; // 1 minute window
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Create set-based tracker with optional max size
|
|
259
|
-
* @param maxSizePerType - Maximum nonces per sender+messageType (default: 10,000)
|
|
260
|
-
* @param maxTotalEntries - Maximum total nonces across all combinations (default: 100,000)
|
|
261
|
-
* @param maxNoncesPerMinute - Maximum nonces per sender per minute (default: 100)
|
|
262
|
-
*/
|
|
263
|
-
constructor(
|
|
264
|
-
maxSizePerType: number = 10000,
|
|
265
|
-
maxTotalEntries: number = 100000,
|
|
266
|
-
maxNoncesPerMinute: number = 100
|
|
267
|
-
) {
|
|
268
|
-
if (maxSizePerType <= 0) {
|
|
269
|
-
throw new Error('maxSizePerType must be positive');
|
|
270
|
-
}
|
|
271
|
-
if (maxTotalEntries <= 0) {
|
|
272
|
-
throw new Error('maxTotalEntries must be positive');
|
|
273
|
-
}
|
|
274
|
-
if (maxNoncesPerMinute <= 0) {
|
|
275
|
-
throw new Error('maxNoncesPerMinute must be positive');
|
|
276
|
-
}
|
|
277
|
-
this.maxSizePerType = maxSizePerType;
|
|
278
|
-
this.maxTotalEntries = maxTotalEntries;
|
|
279
|
-
this.maxNoncesPerMinute = maxNoncesPerMinute;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* SECURITY FIX (H-2): Check rate limit for sender
|
|
284
|
-
* @param sender - Sender DID
|
|
285
|
-
* @returns true if rate limit exceeded
|
|
286
|
-
*/
|
|
287
|
-
private checkRateLimit(sender: string): boolean {
|
|
288
|
-
const now = Date.now();
|
|
289
|
-
const state = this.rateLimitState.get(sender);
|
|
290
|
-
|
|
291
|
-
if (!state) {
|
|
292
|
-
// First nonce from this sender
|
|
293
|
-
this.rateLimitState.set(sender, { count: 1, windowStart: now });
|
|
294
|
-
return false; // Not rate limited
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Check if window expired (reset counter)
|
|
298
|
-
if (now - state.windowStart >= this.rateLimitWindowMs) {
|
|
299
|
-
state.count = 1;
|
|
300
|
-
state.windowStart = now;
|
|
301
|
-
return false; // Not rate limited
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Increment counter
|
|
305
|
-
state.count++;
|
|
306
|
-
|
|
307
|
-
// Check if rate limit exceeded
|
|
308
|
-
return state.count > this.maxNoncesPerMinute;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* SECURITY FIX (H-2): Periodic cleanup of rate limit state
|
|
313
|
-
* Removes expired rate limit entries (older than 5 minutes)
|
|
314
|
-
*/
|
|
315
|
-
private cleanupRateLimitState(): void {
|
|
316
|
-
const now = Date.now();
|
|
317
|
-
const expiryThreshold = 5 * 60 * 1000; // 5 minutes
|
|
318
|
-
|
|
319
|
-
for (const [sender, state] of this.rateLimitState.entries()) {
|
|
320
|
-
if (now - state.windowStart > expiryThreshold) {
|
|
321
|
-
this.rateLimitState.delete(sender);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
240
|
/**
|
|
327
241
|
* Validate and record a received nonce
|
|
328
|
-
*
|
|
329
|
-
* SECURITY FIX (NEW-H-2): Automatic cleanup when max size reached
|
|
330
|
-
* SECURITY FIX (HIGH-2): Global limit check to prevent DoS
|
|
331
|
-
* SECURITY FIX (H-2): Rate limiting per sender (max 100 nonces/minute)
|
|
332
242
|
*/
|
|
333
243
|
validateAndRecord(sender: string, messageType: string, nonce: string): NonceValidationResult {
|
|
334
244
|
// Validate nonce format
|
|
@@ -340,34 +250,6 @@ export class SetBasedReceivedNonceTracker implements IReceivedNonceTracker {
|
|
|
340
250
|
};
|
|
341
251
|
}
|
|
342
252
|
|
|
343
|
-
// SECURITY FIX (H-2): Rate limit check (BEFORE global limit to avoid unnecessary work)
|
|
344
|
-
if (this.checkRateLimit(sender)) {
|
|
345
|
-
return {
|
|
346
|
-
valid: false,
|
|
347
|
-
reason: `Rate limit exceeded for sender ${sender}: ` +
|
|
348
|
-
`Maximum ${this.maxNoncesPerMinute} nonces per minute allowed. ` +
|
|
349
|
-
`This may indicate a flood attack or misconfigured client. ` +
|
|
350
|
-
`Wait 1 minute before retrying.`,
|
|
351
|
-
receivedNonce: nonce
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// SECURITY FIX (H-2): Periodic cleanup every 100 validations (amortized cost)
|
|
356
|
-
if (this.totalEntries % 100 === 0) {
|
|
357
|
-
this.cleanupRateLimitState();
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// SECURITY FIX (HIGH-2): Check global limit BEFORE adding
|
|
361
|
-
if (this.totalEntries >= this.maxTotalEntries) {
|
|
362
|
-
return {
|
|
363
|
-
valid: false,
|
|
364
|
-
reason: `Global nonce tracker limit reached (${this.maxTotalEntries} entries). ` +
|
|
365
|
-
`This may indicate a DoS attack or need for cleanup. ` +
|
|
366
|
-
`Current usage: ${this.totalEntries} entries across ${this.getCombinationCount()} sender+type combinations.`,
|
|
367
|
-
receivedNonce: nonce
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
|
|
371
253
|
// Get sender's nonce map
|
|
372
254
|
let senderNonces = this.usedNonces.get(sender);
|
|
373
255
|
if (!senderNonces) {
|
|
@@ -391,53 +273,11 @@ export class SetBasedReceivedNonceTracker implements IReceivedNonceTracker {
|
|
|
391
273
|
};
|
|
392
274
|
}
|
|
393
275
|
|
|
394
|
-
// SECURITY FIX (NEW-H-2): Auto-cleanup if max size per type reached
|
|
395
|
-
if (usedSet.size >= this.maxSizePerType) {
|
|
396
|
-
// Keep only last 80% of entries (sorted by nonce value)
|
|
397
|
-
const keepCount = Math.floor(this.maxSizePerType * 0.8);
|
|
398
|
-
const sortedNonces = Array.from(usedSet).sort((a, b) => {
|
|
399
|
-
const aVal = BigInt(a);
|
|
400
|
-
const bVal = BigInt(b);
|
|
401
|
-
return aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
|
|
402
|
-
});
|
|
403
|
-
const removedCount = usedSet.size - keepCount;
|
|
404
|
-
usedSet = new Set(sortedNonces.slice(-keepCount));
|
|
405
|
-
senderNonces.set(messageType, usedSet);
|
|
406
|
-
// SECURITY FIX (HIGH-2): Update global counter
|
|
407
|
-
this.totalEntries -= removedCount;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
276
|
// Valid nonce - record it
|
|
411
277
|
usedSet.add(nonce);
|
|
412
|
-
// SECURITY FIX (HIGH-2): Update global counter
|
|
413
|
-
this.totalEntries++;
|
|
414
278
|
return { valid: true };
|
|
415
279
|
}
|
|
416
280
|
|
|
417
|
-
/**
|
|
418
|
-
* Get number of sender+messageType combinations (for monitoring)
|
|
419
|
-
* SECURITY FIX (HIGH-2): Monitoring method
|
|
420
|
-
*/
|
|
421
|
-
private getCombinationCount(): number {
|
|
422
|
-
let count = 0;
|
|
423
|
-
this.usedNonces.forEach(senderMap => {
|
|
424
|
-
count += senderMap.size;
|
|
425
|
-
});
|
|
426
|
-
return count;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Get memory usage statistics
|
|
431
|
-
* SECURITY FIX (HIGH-2): Monitoring method for DoS detection
|
|
432
|
-
*/
|
|
433
|
-
getMemoryUsage(): { totalEntries: number; combinations: number; maxTotalEntries: number } {
|
|
434
|
-
return {
|
|
435
|
-
totalEntries: this.totalEntries,
|
|
436
|
-
combinations: this.getCombinationCount(),
|
|
437
|
-
maxTotalEntries: this.maxTotalEntries
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
|
|
441
281
|
/**
|
|
442
282
|
* Check if a nonce has been used
|
|
443
283
|
*/
|
|
@@ -487,11 +327,6 @@ export class SetBasedReceivedNonceTracker implements IReceivedNonceTracker {
|
|
|
487
327
|
reset(sender: string, messageType: string): void {
|
|
488
328
|
const senderNonces = this.usedNonces.get(sender);
|
|
489
329
|
if (senderNonces) {
|
|
490
|
-
const usedSet = senderNonces.get(messageType);
|
|
491
|
-
if (usedSet) {
|
|
492
|
-
// SECURITY FIX (HIGH-2): Update global counter
|
|
493
|
-
this.totalEntries -= usedSet.size;
|
|
494
|
-
}
|
|
495
330
|
senderNonces.delete(messageType);
|
|
496
331
|
if (senderNonces.size === 0) {
|
|
497
332
|
this.usedNonces.delete(sender);
|
|
@@ -504,8 +339,6 @@ export class SetBasedReceivedNonceTracker implements IReceivedNonceTracker {
|
|
|
504
339
|
*/
|
|
505
340
|
clearAll(): void {
|
|
506
341
|
this.usedNonces.clear();
|
|
507
|
-
// SECURITY FIX (HIGH-2): Reset global counter
|
|
508
|
-
this.totalEntries = 0;
|
|
509
342
|
}
|
|
510
343
|
|
|
511
344
|
/**
|
|
@@ -544,11 +377,8 @@ export class SetBasedReceivedNonceTracker implements IReceivedNonceTracker {
|
|
|
544
377
|
});
|
|
545
378
|
|
|
546
379
|
// Keep only the last N nonces
|
|
547
|
-
const removedCount = usedSet.size - keepLast;
|
|
548
380
|
const toKeep = new Set(sortedNonces.slice(-keepLast));
|
|
549
381
|
senderNonces.set(messageType, toKeep);
|
|
550
|
-
// SECURITY FIX (HIGH-2): Update global counter
|
|
551
|
-
this.totalEntries -= removedCount;
|
|
552
382
|
}
|
|
553
383
|
}
|
|
554
384
|
|