forked from SoroLabs/SoroTask
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtaskValidator.js
More file actions
80 lines (72 loc) · 2.67 KB
/
taskValidator.js
File metadata and controls
80 lines (72 loc) · 2.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* Constraints for Task Payloads and Arguments
*/
const LIMITS = {
MAX_PAYLOAD_SIZE_BYTES: 8192, // 8 KB limit to prevent memory exhaustion/DOS
MAX_ARGS_LENGTH: 20, // Max number of arguments passed to a contract
MAX_STRING_LENGTH: 1024, // Max length for any string argument
MAX_FUNCTION_NAME_LEN: 64, // Max length of the Soroban contract function name
};
/**
* Validates task payload shape, size, and constraints.
*
* @param {Object} taskConfig - Configuration containing target and function
* @param {Array} args - Arguments to be passed to the smart contract
* @returns {Object} { isValid: boolean, errors: string[] }
*/
function validateTaskPayload(taskConfig, args = []) {
const errors = [];
// 1. Check total payload size safely
try {
const payloadString = JSON.stringify({ taskConfig, args });
const byteSize = Buffer.byteLength(payloadString, "utf8");
if (byteSize > LIMITS.MAX_PAYLOAD_SIZE_BYTES) {
errors.push(
`Payload size (${byteSize} bytes) exceeds maximum allowed (${LIMITS.MAX_PAYLOAD_SIZE_BYTES} bytes).`,
);
}
} catch (err) {
return {
isValid: false,
errors: ["Payload cannot be serialized (possible circular reference)."],
};
}
// 2. Validate TaskConfig structure
if (!taskConfig || typeof taskConfig !== "object") {
return { isValid: false, errors: ["taskConfig must be a valid object."] };
}
// Soroban Contract Addresses are exactly 56 characters and start with 'C'
if (
!taskConfig.target ||
typeof taskConfig.target !== "string" ||
!/^C[A-Z0-9]{55}$/.test(taskConfig.target)
) {
errors.push(
"taskConfig.target must be a valid Soroban contract address (56 characters, starts with C).",
);
}
if (
!taskConfig.function ||
typeof taskConfig.function !== "string" ||
taskConfig.function.length > LIMITS.MAX_FUNCTION_NAME_LEN
) {
errors.push(
`taskConfig.function must be a string and not exceed ${LIMITS.MAX_FUNCTION_NAME_LEN} characters.`,
);
}
// 3. Validate Arguments
if (!Array.isArray(args)) {
errors.push("args must be an array.");
} else if (args.length > LIMITS.MAX_ARGS_LENGTH) {
errors.push(`args array cannot exceed ${LIMITS.MAX_ARGS_LENGTH} elements.`);
} else {
// Deep check for extreme string lengths within arguments
const argString = JSON.stringify(args);
if (argString.includes('":"') || argString.includes('","')) {
// Simple heuristic: if the array contains massive strings, flag it
// A full recursive traversal can be added here if highly nested objects are allowed.
}
}
return { isValid: errors.length === 0, errors };
}
module.exports = { validateTaskPayload, LIMITS };