@ocap/tx-protocols 1.29.13 → 1.29.15
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.
|
@@ -6,6 +6,7 @@ import get from "lodash/get.js";
|
|
|
6
6
|
import pick from "lodash/pick.js";
|
|
7
7
|
import { toDelegateAddress } from "@arcblock/did-util";
|
|
8
8
|
import { account, delegation } from "@ocap/state";
|
|
9
|
+
import { scopeMatchAny } from "@ocap/util";
|
|
9
10
|
import Debug from "debug";
|
|
10
11
|
import { formatMessage } from "@ocap/message";
|
|
11
12
|
import cloneDeep from "lodash/cloneDeep.js";
|
|
@@ -48,6 +49,8 @@ const schema = Joi.object({
|
|
|
48
49
|
assetsList: []
|
|
49
50
|
})
|
|
50
51
|
})).unique((a, b) => a.typeUrl === b.typeUrl).min(1).required(),
|
|
52
|
+
denyList: Joi.array().items(Joi.string().pattern(/^fg:/).max(256)).max(128).unique().optional().allow(null).default([]),
|
|
53
|
+
validUntil: Joi.number().integer().min(0).optional().allow(null).default(0),
|
|
51
54
|
data: Joi.any().optional().allow(null)
|
|
52
55
|
}).options({
|
|
53
56
|
stripUnknown: true,
|
|
@@ -73,7 +76,7 @@ runner.use(pipes.VerifyInfo([{
|
|
|
73
76
|
fn: (ctx) => {
|
|
74
77
|
const context = ctx;
|
|
75
78
|
const allowed = get(context.config, "transaction.delegate.typeUrls", []);
|
|
76
|
-
return (context.formattedItx?.ops || []).every((op) =>
|
|
79
|
+
return (context.formattedItx?.ops || []).every((op) => scopeMatchAny(op.typeUrl, allowed));
|
|
77
80
|
}
|
|
78
81
|
}]));
|
|
79
82
|
runner.use(pipes.ExtractState({
|
|
@@ -125,6 +128,8 @@ runner.use(async (context, next) => {
|
|
|
125
128
|
const { tx: tx$1, itx, formattedItx, validatedItx, statedb, senderState, receiverState, delegationState, senderUpdates, updateVaults } = context;
|
|
126
129
|
const ops = formattedItx?.ops || [];
|
|
127
130
|
const opsList = validatedItx?.opsList || [];
|
|
131
|
+
const deny = itx.denyList || [];
|
|
132
|
+
const validUntil = itx.validUntil || 0;
|
|
128
133
|
const merged = cloneDeep(ops).reduce((acc, x, i) => {
|
|
129
134
|
const tokens = x.limit?.tokens || [];
|
|
130
135
|
const assets = x.limit?.assets || [];
|
|
@@ -174,11 +179,15 @@ runner.use(async (context, next) => {
|
|
|
174
179
|
delegationState ? statedb.delegation.update(itx.address, delegation.update(delegationState, {
|
|
175
180
|
...itx,
|
|
176
181
|
from: sender,
|
|
177
|
-
ops: merged
|
|
182
|
+
ops: merged,
|
|
183
|
+
deny,
|
|
184
|
+
validUntil
|
|
178
185
|
}, context), context) : statedb.delegation.create(itx.address, delegation.create({
|
|
179
186
|
...itx,
|
|
180
187
|
from: sender,
|
|
181
|
-
ops: merged
|
|
188
|
+
ops: merged,
|
|
189
|
+
deny,
|
|
190
|
+
validUntil
|
|
182
191
|
}, context), context)
|
|
183
192
|
]);
|
|
184
193
|
if (updateVaults) await updateVaults();
|
|
@@ -10,6 +10,7 @@ let lodash_pick = require("lodash/pick");
|
|
|
10
10
|
lodash_pick = require_rolldown_runtime.__toESM(lodash_pick);
|
|
11
11
|
let _arcblock_did_util = require("@arcblock/did-util");
|
|
12
12
|
let _ocap_state = require("@ocap/state");
|
|
13
|
+
let _ocap_util = require("@ocap/util");
|
|
13
14
|
let debug = require("debug");
|
|
14
15
|
debug = require_rolldown_runtime.__toESM(debug);
|
|
15
16
|
let _ocap_message = require("@ocap/message");
|
|
@@ -54,6 +55,8 @@ const schema = _arcblock_validator.Joi.object({
|
|
|
54
55
|
assetsList: []
|
|
55
56
|
})
|
|
56
57
|
})).unique((a, b) => a.typeUrl === b.typeUrl).min(1).required(),
|
|
58
|
+
denyList: _arcblock_validator.Joi.array().items(_arcblock_validator.Joi.string().pattern(/^fg:/).max(256)).max(128).unique().optional().allow(null).default([]),
|
|
59
|
+
validUntil: _arcblock_validator.Joi.number().integer().min(0).optional().allow(null).default(0),
|
|
57
60
|
data: _arcblock_validator.Joi.any().optional().allow(null)
|
|
58
61
|
}).options({
|
|
59
62
|
stripUnknown: true,
|
|
@@ -79,7 +82,7 @@ runner.use(_ocap_tx_pipeline.pipes.VerifyInfo([{
|
|
|
79
82
|
fn: (ctx) => {
|
|
80
83
|
const context = ctx;
|
|
81
84
|
const allowed = (0, lodash_get.default)(context.config, "transaction.delegate.typeUrls", []);
|
|
82
|
-
return (context.formattedItx?.ops || []).every((op) =>
|
|
85
|
+
return (context.formattedItx?.ops || []).every((op) => (0, _ocap_util.scopeMatchAny)(op.typeUrl, allowed));
|
|
83
86
|
}
|
|
84
87
|
}]));
|
|
85
88
|
runner.use(_ocap_tx_pipeline.pipes.ExtractState({
|
|
@@ -131,6 +134,8 @@ runner.use(async (context, next) => {
|
|
|
131
134
|
const { tx, itx, formattedItx, validatedItx, statedb, senderState, receiverState, delegationState, senderUpdates, updateVaults } = context;
|
|
132
135
|
const ops = formattedItx?.ops || [];
|
|
133
136
|
const opsList = validatedItx?.opsList || [];
|
|
137
|
+
const deny = itx.denyList || [];
|
|
138
|
+
const validUntil = itx.validUntil || 0;
|
|
134
139
|
const merged = (0, lodash_cloneDeep.default)(ops).reduce((acc, x, i) => {
|
|
135
140
|
const tokens = x.limit?.tokens || [];
|
|
136
141
|
const assets = x.limit?.assets || [];
|
|
@@ -180,11 +185,15 @@ runner.use(async (context, next) => {
|
|
|
180
185
|
delegationState ? statedb.delegation.update(itx.address, _ocap_state.delegation.update(delegationState, {
|
|
181
186
|
...itx,
|
|
182
187
|
from: sender,
|
|
183
|
-
ops: merged
|
|
188
|
+
ops: merged,
|
|
189
|
+
deny,
|
|
190
|
+
validUntil
|
|
184
191
|
}, context), context) : statedb.delegation.create(itx.address, _ocap_state.delegation.create({
|
|
185
192
|
...itx,
|
|
186
193
|
from: sender,
|
|
187
|
-
ops: merged
|
|
194
|
+
ops: merged,
|
|
195
|
+
deny,
|
|
196
|
+
validUntil
|
|
188
197
|
}, context), context)
|
|
189
198
|
]);
|
|
190
199
|
if (updateVaults) await updateVaults();
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.29.
|
|
6
|
+
"version": "1.29.15",
|
|
7
7
|
"description": "Predefined tx pipeline sets to execute certain type of transactions",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "./lib/index.cjs",
|
|
@@ -46,34 +46,34 @@
|
|
|
46
46
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
47
47
|
"license": "MIT",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@arcblock/did": "1.29.
|
|
50
|
-
"@arcblock/did-util": "1.29.
|
|
51
|
-
"@arcblock/jwt": "1.29.
|
|
52
|
-
"@arcblock/validator": "1.29.
|
|
53
|
-
"@arcblock/vc": "1.29.
|
|
49
|
+
"@arcblock/did": "1.29.15",
|
|
50
|
+
"@arcblock/did-util": "1.29.15",
|
|
51
|
+
"@arcblock/jwt": "1.29.15",
|
|
52
|
+
"@arcblock/validator": "1.29.15",
|
|
53
|
+
"@arcblock/vc": "1.29.15",
|
|
54
54
|
"@blocklet/xss": "^0.3.7",
|
|
55
|
-
"@ocap/asset": "1.29.
|
|
56
|
-
"@ocap/client": "1.29.
|
|
57
|
-
"@ocap/mcrypto": "1.29.
|
|
58
|
-
"@ocap/merkle-tree": "1.29.
|
|
59
|
-
"@ocap/message": "1.29.
|
|
60
|
-
"@ocap/state": "1.29.
|
|
61
|
-
"@ocap/tx-pipeline": "1.29.
|
|
62
|
-
"@ocap/types": "1.29.
|
|
63
|
-
"@ocap/util": "1.29.
|
|
64
|
-
"@ocap/wallet": "1.29.
|
|
55
|
+
"@ocap/asset": "1.29.15",
|
|
56
|
+
"@ocap/client": "1.29.15",
|
|
57
|
+
"@ocap/mcrypto": "1.29.15",
|
|
58
|
+
"@ocap/merkle-tree": "1.29.15",
|
|
59
|
+
"@ocap/message": "1.29.15",
|
|
60
|
+
"@ocap/state": "1.29.15",
|
|
61
|
+
"@ocap/tx-pipeline": "1.29.15",
|
|
62
|
+
"@ocap/types": "1.29.15",
|
|
63
|
+
"@ocap/util": "1.29.15",
|
|
64
|
+
"@ocap/wallet": "1.29.15",
|
|
65
65
|
"debug": "^4.4.3",
|
|
66
66
|
"deep-diff": "^1.0.2",
|
|
67
67
|
"lodash": "^4.17.23",
|
|
68
68
|
"url-join": "^4.0.1"
|
|
69
69
|
},
|
|
70
70
|
"resolutions": {
|
|
71
|
-
"bn.js": "5.2.
|
|
71
|
+
"bn.js": "5.2.3",
|
|
72
72
|
"elliptic": "6.5.3"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@ocap/e2e-test": "1.29.
|
|
76
|
-
"@ocap/statedb-memory": "1.29.
|
|
75
|
+
"@ocap/e2e-test": "1.29.15",
|
|
76
|
+
"@ocap/statedb-memory": "1.29.15",
|
|
77
77
|
"@types/debug": "^4.1.12",
|
|
78
78
|
"@types/lodash": "^4.17.16",
|
|
79
79
|
"start-server-and-test": "^1.14.0"
|
package/tools/fixtures.ts
CHANGED
|
@@ -14,8 +14,7 @@ import { create as createVC } from '@arcblock/vc';
|
|
|
14
14
|
import { getTestChain, closeTestChain } from '@ocap/e2e-test/fixture';
|
|
15
15
|
import defaultConfigModule from '@ocap/e2e-test/config';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
import { execute, createExecutor } from '../lib';
|
|
17
|
+
import { execute, createExecutor } from '../src';
|
|
19
18
|
|
|
20
19
|
const defaultConfig = cloneDeep(defaultConfigModule);
|
|
21
20
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helper utilities for IDD six-dimension testing.
|
|
3
|
+
*
|
|
4
|
+
* - assertNoSensitiveData: Data Leak detection
|
|
5
|
+
* - captureStateSnapshot / assertStateUnchanged: Data Damage verification
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Patterns that match sensitive data commonly found in blockchain SDKs.
|
|
10
|
+
* Used by Data Leak tests to verify error messages and outputs don't leak secrets.
|
|
11
|
+
*/
|
|
12
|
+
export const SENSITIVE_PATTERNS: { pattern: RegExp; label: string }[] = [
|
|
13
|
+
{ pattern: /-----BEGIN.*PRIVATE KEY-----/, label: 'PEM private key' },
|
|
14
|
+
{ pattern: /\b(mnemonic|seed\s*phrase)\b/i, label: 'mnemonic keyword' },
|
|
15
|
+
{ pattern: /sk[A-Za-z0-9+/]{40,}/, label: 'base58-encoded secret key' },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Assert that a string or object does not contain sensitive data patterns.
|
|
20
|
+
* Throws if any SENSITIVE_PATTERNS match.
|
|
21
|
+
*/
|
|
22
|
+
export function assertNoSensitiveData(data: string | object, context = 'output'): void {
|
|
23
|
+
const str = typeof data === 'string' ? data : JSON.stringify(data);
|
|
24
|
+
for (const { pattern, label } of SENSITIVE_PATTERNS) {
|
|
25
|
+
if (pattern.test(str)) {
|
|
26
|
+
throw new Error(`Data leak detected in ${context}: matches ${label} (${pattern})`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Capture a deep-cloned snapshot of account states for the given addresses.
|
|
33
|
+
* Returns a Map<address, state>. Addresses with no state are skipped.
|
|
34
|
+
*/
|
|
35
|
+
export async function captureStateSnapshot(
|
|
36
|
+
statedb: { account: { get(address: string): Promise<any> } },
|
|
37
|
+
addresses: string[]
|
|
38
|
+
): Promise<Map<string, any>> {
|
|
39
|
+
const snapshot = new Map<string, any>();
|
|
40
|
+
for (const addr of addresses) {
|
|
41
|
+
const state = await statedb.account.get(addr);
|
|
42
|
+
if (state) {
|
|
43
|
+
snapshot.set(addr, JSON.parse(JSON.stringify(state)));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return snapshot;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Assert that account states have not changed between two snapshots.
|
|
51
|
+
* Compares by JSON serialization (deep equality).
|
|
52
|
+
*
|
|
53
|
+
* @param fields - If provided, only compare these fields on each state.
|
|
54
|
+
* Useful when dynamic fields (e.g. _retrievedAt) differ.
|
|
55
|
+
*/
|
|
56
|
+
export function assertStateUnchanged(
|
|
57
|
+
before: Map<string, any>,
|
|
58
|
+
after: Map<string, any>,
|
|
59
|
+
message = '',
|
|
60
|
+
fields?: string[]
|
|
61
|
+
): void {
|
|
62
|
+
for (const [addr, beforeState] of before) {
|
|
63
|
+
const afterState = after.get(addr);
|
|
64
|
+
const pick = (obj: any) => {
|
|
65
|
+
if (!fields || !obj) return obj;
|
|
66
|
+
const result: Record<string, any> = {};
|
|
67
|
+
for (const f of fields) {
|
|
68
|
+
result[f] = obj[f];
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
};
|
|
72
|
+
const beforeStr = JSON.stringify(pick(beforeState));
|
|
73
|
+
const afterStr = JSON.stringify(pick(afterState));
|
|
74
|
+
if (beforeStr !== afterStr) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`State changed for ${addr}${message ? ': ' + message : ''}\n` +
|
|
77
|
+
` before: ${beforeStr}\n` +
|
|
78
|
+
` after: ${afterStr}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|