blueprint-tsa 1.0.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.
- package/README.md +0 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.js +54 -0
- package/dist/commands/audit.d.ts +19 -0
- package/dist/commands/audit.js +296 -0
- package/dist/commands/bounce-check.d.ts +15 -0
- package/dist/commands/bounce-check.js +152 -0
- package/dist/commands/clean.d.ts +1 -0
- package/dist/commands/clean.js +20 -0
- package/dist/commands/drain-check.d.ts +32 -0
- package/dist/commands/drain-check.js +218 -0
- package/dist/commands/opcode-info.d.ts +23 -0
- package/dist/commands/opcode-info.js +176 -0
- package/dist/commands/owner-hijack-check.d.ts +20 -0
- package/dist/commands/owner-hijack-check.js +290 -0
- package/dist/commands/replay-attack-check.d.ts +20 -0
- package/dist/commands/replay-attack-check.js +149 -0
- package/dist/commands/reproduce.d.ts +3 -0
- package/dist/commands/reproduce.js +102 -0
- package/dist/common/analyzer-wrapper.d.ts +69 -0
- package/dist/common/analyzer-wrapper.js +198 -0
- package/dist/common/analyzer.d.ts +10 -0
- package/dist/common/analyzer.js +49 -0
- package/dist/common/build-utils.d.ts +3 -0
- package/dist/common/build-utils.js +68 -0
- package/dist/common/constants.d.ts +41 -0
- package/dist/common/constants.js +45 -0
- package/dist/common/draw.d.ts +7 -0
- package/dist/common/draw.js +33 -0
- package/dist/common/file-utils.d.ts +7 -0
- package/dist/common/file-utils.js +20 -0
- package/dist/common/format-utils.d.ts +13 -0
- package/dist/common/format-utils.js +30 -0
- package/dist/common/opcode-extractor.d.ts +7 -0
- package/dist/common/opcode-extractor.js +60 -0
- package/dist/common/paths.d.ts +19 -0
- package/dist/common/paths.js +139 -0
- package/dist/common/result-parsing.d.ts +4 -0
- package/dist/common/result-parsing.js +40 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +16 -0
- package/dist/install/architecture.d.ts +5 -0
- package/dist/install/architecture.js +51 -0
- package/dist/install/downloading.d.ts +1 -0
- package/dist/install/downloading.js +44 -0
- package/dist/install/java.d.ts +1 -0
- package/dist/install/java.js +89 -0
- package/dist/install/postinstall.d.ts +1 -0
- package/dist/install/postinstall.js +12 -0
- package/dist/install/tsa-jar.d.ts +1 -0
- package/dist/install/tsa-jar.js +23 -0
- package/dist/install/unzip.d.ts +1 -0
- package/dist/install/unzip.js +14 -0
- package/dist/reproduce/build-config.d.ts +3 -0
- package/dist/reproduce/build-config.js +24 -0
- package/dist/reproduce/concrete-analysis.d.ts +15 -0
- package/dist/reproduce/concrete-analysis.js +21 -0
- package/dist/reproduce/network.d.ts +19 -0
- package/dist/reproduce/network.js +70 -0
- package/dist/reproduce/reproduce-config.d.ts +30 -0
- package/dist/reproduce/reproduce-config.js +59 -0
- package/dist/reproduce/utils.d.ts +4 -0
- package/dist/reproduce/utils.js +34 -0
- package/dist/tsa.d.ts +2 -0
- package/dist/tsa.js +22 -0
- package/package.json +45 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getThrowerPath = exports.getTsaRunLogPath = exports.getMsgBodyTypesPath = exports.getMsgBodyBocPath = exports.getContractDataTypesPath = exports.getContractDataBocPath = exports.getReproduceConfigPath = exports.getInputsPath = exports.getSummaryPath = exports.getSarifReportPath = exports.getCheckerPath = exports.findTsaPath = exports.findJavaBinPath = exports.findCompiledContract = exports.getReportDirectory = exports.findTSAReportsDirectory = exports.findTSAProjectDirectory = exports.findTSAHomeDirectory = exports.BUILD_DIR = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const architecture_js_1 = require("../install/architecture.js");
|
|
11
|
+
const constants_js_1 = require("./constants.js");
|
|
12
|
+
exports.BUILD_DIR = path_1.default.join(process.cwd(), "build");
|
|
13
|
+
const findTSAHomeDirectory = () => {
|
|
14
|
+
const tsaDir = path_1.default.join(os_1.default.homedir(), ".tsa");
|
|
15
|
+
if (!fs_1.default.existsSync(tsaDir)) {
|
|
16
|
+
fs_1.default.mkdirSync(tsaDir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
return tsaDir;
|
|
19
|
+
};
|
|
20
|
+
exports.findTSAHomeDirectory = findTSAHomeDirectory;
|
|
21
|
+
const findTSAProjectDirectory = () => {
|
|
22
|
+
const tsaDir = path_1.default.join(process.cwd(), "tsa");
|
|
23
|
+
if (!fs_1.default.existsSync(tsaDir)) {
|
|
24
|
+
fs_1.default.mkdirSync(tsaDir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
return tsaDir;
|
|
27
|
+
};
|
|
28
|
+
exports.findTSAProjectDirectory = findTSAProjectDirectory;
|
|
29
|
+
const findTSAReportsDirectory = () => {
|
|
30
|
+
const tsaDir = (0, exports.findTSAProjectDirectory)();
|
|
31
|
+
const result = path_1.default.join(tsaDir, "reports");
|
|
32
|
+
if (!fs_1.default.existsSync(result)) {
|
|
33
|
+
fs_1.default.mkdirSync(result, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
exports.findTSAReportsDirectory = findTSAReportsDirectory;
|
|
38
|
+
const getReportDirectory = (id) => {
|
|
39
|
+
const reportsDir = (0, exports.findTSAReportsDirectory)();
|
|
40
|
+
const result = path_1.default.join(reportsDir, `run-${id}`);
|
|
41
|
+
if (!fs_1.default.existsSync(result)) {
|
|
42
|
+
fs_1.default.mkdirSync(result, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
exports.getReportDirectory = getReportDirectory;
|
|
47
|
+
const findCompiledContract = (name) => {
|
|
48
|
+
return path_1.default.join(exports.BUILD_DIR, name + ".compiled.json");
|
|
49
|
+
};
|
|
50
|
+
exports.findCompiledContract = findCompiledContract;
|
|
51
|
+
const findJavaBinPath = () => {
|
|
52
|
+
const tsaHome = (0, exports.findTSAHomeDirectory)();
|
|
53
|
+
const jre = path_1.default.join(tsaHome, "jre");
|
|
54
|
+
if (!fs_1.default.existsSync(jre)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const contents = fs_1.default.readdirSync(jre);
|
|
58
|
+
// Return null if directory is empty
|
|
59
|
+
if (contents.length === 0) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
// If exactly one item, use it as the jre path
|
|
63
|
+
if (contents.length != 1) {
|
|
64
|
+
throw new Error(`Unexpected content in JRE directory: expected empty or single directory, found ${contents.length} items`);
|
|
65
|
+
}
|
|
66
|
+
const javaHomePath = path_1.default.join(jre, contents[0]);
|
|
67
|
+
let binPath = path_1.default.join(javaHomePath, "bin");
|
|
68
|
+
if (process.platform == "darwin") {
|
|
69
|
+
binPath = `${javaHomePath}/Contents/Home/bin`;
|
|
70
|
+
}
|
|
71
|
+
const javaBinPath = path_1.default.join(binPath, (0, architecture_js_1.mapOSToJavaBinary)());
|
|
72
|
+
if (!fs_1.default.existsSync(javaBinPath)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return javaBinPath;
|
|
76
|
+
};
|
|
77
|
+
exports.findJavaBinPath = findJavaBinPath;
|
|
78
|
+
const findTsaPath = () => {
|
|
79
|
+
const tsaHome = (0, exports.findTSAHomeDirectory)();
|
|
80
|
+
const result = path_1.default.join(tsaHome, constants_js_1.TSA_NAME);
|
|
81
|
+
if (!fs_1.default.existsSync(result)) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
};
|
|
86
|
+
exports.findTsaPath = findTsaPath;
|
|
87
|
+
const getCheckerPath = (checkerName) => {
|
|
88
|
+
return path_1.default.join(path_1.default.dirname(__filename), "../../src/checkers", checkerName);
|
|
89
|
+
};
|
|
90
|
+
exports.getCheckerPath = getCheckerPath;
|
|
91
|
+
const getSarifReportPath = (id) => {
|
|
92
|
+
const reportDir = (0, exports.getReportDirectory)(id);
|
|
93
|
+
return path_1.default.join(reportDir, "report.sarif");
|
|
94
|
+
};
|
|
95
|
+
exports.getSarifReportPath = getSarifReportPath;
|
|
96
|
+
const getSummaryPath = (id) => {
|
|
97
|
+
const reportDir = (0, exports.getReportDirectory)(id);
|
|
98
|
+
return path_1.default.join(reportDir, "summary.txt");
|
|
99
|
+
};
|
|
100
|
+
exports.getSummaryPath = getSummaryPath;
|
|
101
|
+
const getInputsPath = (id, index) => {
|
|
102
|
+
const reportDir = (0, exports.getReportDirectory)(id);
|
|
103
|
+
return path_1.default.join(reportDir, `execution_${index}`);
|
|
104
|
+
};
|
|
105
|
+
exports.getInputsPath = getInputsPath;
|
|
106
|
+
const getReproduceConfigPath = (id) => {
|
|
107
|
+
const reportDir = (0, exports.getReportDirectory)(id);
|
|
108
|
+
return path_1.default.join(reportDir, "tsa-reproduce-config.json");
|
|
109
|
+
};
|
|
110
|
+
exports.getReproduceConfigPath = getReproduceConfigPath;
|
|
111
|
+
const getContractDataBocPath = (id, index) => {
|
|
112
|
+
const inputsPath = (0, exports.getInputsPath)(id, index);
|
|
113
|
+
return path_1.default.join(path_1.default.join(inputsPath, "c4_1"), "cell.boc");
|
|
114
|
+
};
|
|
115
|
+
exports.getContractDataBocPath = getContractDataBocPath;
|
|
116
|
+
const getContractDataTypesPath = (id, index) => {
|
|
117
|
+
const inputsPath = (0, exports.getInputsPath)(id, index);
|
|
118
|
+
return path_1.default.join(path_1.default.join(inputsPath, "c4_1"), "cell-types.yaml");
|
|
119
|
+
};
|
|
120
|
+
exports.getContractDataTypesPath = getContractDataTypesPath;
|
|
121
|
+
const getMsgBodyBocPath = (id, index) => {
|
|
122
|
+
const inputsPath = (0, exports.getInputsPath)(id, index);
|
|
123
|
+
return path_1.default.join(path_1.default.join(inputsPath, "msgBody_0"), "cell.boc");
|
|
124
|
+
};
|
|
125
|
+
exports.getMsgBodyBocPath = getMsgBodyBocPath;
|
|
126
|
+
const getMsgBodyTypesPath = (id, index) => {
|
|
127
|
+
const inputsPath = (0, exports.getInputsPath)(id, index);
|
|
128
|
+
return path_1.default.join(path_1.default.join(inputsPath, "msgBody_0"), "cell-types.yaml");
|
|
129
|
+
};
|
|
130
|
+
exports.getMsgBodyTypesPath = getMsgBodyTypesPath;
|
|
131
|
+
const getTsaRunLogPath = (id) => {
|
|
132
|
+
const reportDir = (0, exports.getReportDirectory)(id);
|
|
133
|
+
return path_1.default.join(reportDir, "tsa.log");
|
|
134
|
+
};
|
|
135
|
+
exports.getTsaRunLogPath = getTsaRunLogPath;
|
|
136
|
+
const getThrowerPath = () => {
|
|
137
|
+
return path_1.default.join(path_1.default.dirname(__filename), "../../src/checkers", "thrower.fc");
|
|
138
|
+
};
|
|
139
|
+
exports.getThrowerPath = getThrowerPath;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const findExploitExecutionIndex: (sarifPath: string) => number | undefined;
|
|
2
|
+
export declare const findNonFailingExecution: (sarifPath: string) => number | undefined;
|
|
3
|
+
export declare const getMessageValue: (sarifPath: string, index: number) => bigint | null;
|
|
4
|
+
export declare const getInitialBalance: (sarifPath: string, index: number) => bigint;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getInitialBalance = exports.getMessageValue = exports.findNonFailingExecution = exports.findExploitExecutionIndex = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const constants_js_1 = require("./constants.js");
|
|
6
|
+
const findExecutionByMessage = (sarifPath, expectedMessage) => {
|
|
7
|
+
const sarifContent = (0, fs_1.readFileSync)(sarifPath, "utf-8");
|
|
8
|
+
const parsedObject = JSON.parse(sarifContent);
|
|
9
|
+
const results = parsedObject.runs[0].results || [];
|
|
10
|
+
const index = results.findIndex((result) => result.message?.text === expectedMessage);
|
|
11
|
+
return index >= 0 ? index : undefined;
|
|
12
|
+
};
|
|
13
|
+
const findExploitExecutionIndex = (sarifPath) => {
|
|
14
|
+
return findExecutionByMessage(sarifPath, constants_js_1.EXPECTED_MESSAGE_IN_SARIF);
|
|
15
|
+
};
|
|
16
|
+
exports.findExploitExecutionIndex = findExploitExecutionIndex;
|
|
17
|
+
const findNonFailingExecution = (sarifPath) => {
|
|
18
|
+
return findExecutionByMessage(sarifPath, constants_js_1.EXPECTED_MESSAGE_NON_FAILING);
|
|
19
|
+
};
|
|
20
|
+
exports.findNonFailingExecution = findNonFailingExecution;
|
|
21
|
+
const getMessageValue = (sarifPath, index) => {
|
|
22
|
+
const sarifContent = (0, fs_1.readFileSync)(sarifPath, "utf-8");
|
|
23
|
+
const parsedObject = JSON.parse(sarifContent);
|
|
24
|
+
const results = parsedObject.runs[0].results || [];
|
|
25
|
+
const result = results[index];
|
|
26
|
+
const input = result.properties.additionalInputs["0"];
|
|
27
|
+
if (input.type == "recvExternalInput") {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return BigInt(input.msgValue);
|
|
31
|
+
};
|
|
32
|
+
exports.getMessageValue = getMessageValue;
|
|
33
|
+
const getInitialBalance = (sarifPath, index) => {
|
|
34
|
+
const sarifContent = (0, fs_1.readFileSync)(sarifPath, "utf-8");
|
|
35
|
+
const parsedObject = JSON.parse(sarifContent);
|
|
36
|
+
const results = parsedObject.runs[0].results || [];
|
|
37
|
+
const result = results[index];
|
|
38
|
+
return BigInt(result.properties.initialBalance["1"]);
|
|
39
|
+
};
|
|
40
|
+
exports.getInitialBalance = getInitialBalance;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TsaPlugin = void 0;
|
|
4
|
+
const tsa_js_1 = require("./tsa.js");
|
|
5
|
+
class TsaPlugin {
|
|
6
|
+
runners() {
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
name: "tsa",
|
|
10
|
+
runner: tsa_js_1.tsa,
|
|
11
|
+
help: "TON Symbolic Analyzer",
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.TsaPlugin = TsaPlugin;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.mapOSToJavaBinary = exports.adoptiumArch = exports.adoptiumOS = void 0;
|
|
5
|
+
function mapPlatformToAdoptium(osName, arch) {
|
|
6
|
+
let adoptiumOS;
|
|
7
|
+
switch (osName) {
|
|
8
|
+
case "darwin":
|
|
9
|
+
adoptiumOS = "mac";
|
|
10
|
+
break;
|
|
11
|
+
case "linux":
|
|
12
|
+
adoptiumOS = "linux";
|
|
13
|
+
break;
|
|
14
|
+
case "win32":
|
|
15
|
+
adoptiumOS = "windows";
|
|
16
|
+
break;
|
|
17
|
+
default:
|
|
18
|
+
throw new Error(`unsupported OS for java runtime bootstrap: ${osName}`);
|
|
19
|
+
}
|
|
20
|
+
let adoptiumArch;
|
|
21
|
+
switch (arch) {
|
|
22
|
+
case "arm64":
|
|
23
|
+
adoptiumArch = "aarch64";
|
|
24
|
+
break;
|
|
25
|
+
case "x64":
|
|
26
|
+
adoptiumArch = "x64";
|
|
27
|
+
break;
|
|
28
|
+
default:
|
|
29
|
+
throw new Error(`unsupported arch for java runtime bootstrap: ${arch}`);
|
|
30
|
+
}
|
|
31
|
+
return [adoptiumOS, adoptiumArch];
|
|
32
|
+
}
|
|
33
|
+
_a = mapPlatformToAdoptium(process.platform, process.arch), exports.adoptiumOS = _a[0], exports.adoptiumArch = _a[1];
|
|
34
|
+
const mapOSToJavaBinary = () => {
|
|
35
|
+
let javaBinary;
|
|
36
|
+
switch (exports.adoptiumOS) {
|
|
37
|
+
case "mac":
|
|
38
|
+
javaBinary = "java";
|
|
39
|
+
break;
|
|
40
|
+
case "linux":
|
|
41
|
+
javaBinary = "java";
|
|
42
|
+
break;
|
|
43
|
+
case "windows":
|
|
44
|
+
javaBinary = "java.exe";
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
throw new Error(`unsupported OS for java runtime bootstrap: ${exports.adoptiumOS}`);
|
|
48
|
+
}
|
|
49
|
+
return javaBinary;
|
|
50
|
+
};
|
|
51
|
+
exports.mapOSToJavaBinary = mapOSToJavaBinary;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const downloadWithRedirect: (url: string, filePath: string) => Promise<void>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.downloadWithRedirect = void 0;
|
|
7
|
+
const https_1 = __importDefault(require("https"));
|
|
8
|
+
const http_1 = __importDefault(require("http"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const REDIRECT_STATUS_CODES = [301, 302, 303, 307, 308];
|
|
11
|
+
const downloadWithRedirect = (url, filePath) => {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const protocol = url.startsWith("https") ? https_1.default : http_1.default;
|
|
14
|
+
protocol
|
|
15
|
+
.get(url, (response) => {
|
|
16
|
+
if (response.statusCode &&
|
|
17
|
+
REDIRECT_STATUS_CODES.includes(response.statusCode)) {
|
|
18
|
+
const redirectUrl = response.headers.location;
|
|
19
|
+
if (redirectUrl) {
|
|
20
|
+
response.resume();
|
|
21
|
+
(0, exports.downloadWithRedirect)(redirectUrl, filePath)
|
|
22
|
+
.then(resolve)
|
|
23
|
+
.catch(reject);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const file = fs_1.default.createWriteStream(filePath);
|
|
28
|
+
response.pipe(file);
|
|
29
|
+
file.on("finish", () => {
|
|
30
|
+
file.close();
|
|
31
|
+
resolve();
|
|
32
|
+
});
|
|
33
|
+
file.on("error", (err) => {
|
|
34
|
+
fs_1.default.unlink(filePath, () => { });
|
|
35
|
+
reject(err);
|
|
36
|
+
});
|
|
37
|
+
})
|
|
38
|
+
.on("error", (err) => {
|
|
39
|
+
fs_1.default.unlink(filePath, () => { });
|
|
40
|
+
reject(err);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
exports.downloadWithRedirect = downloadWithRedirect;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ensureJavaInstalled: () => Promise<string>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ensureJavaInstalled = void 0;
|
|
40
|
+
const architecture_js_1 = require("./architecture.js");
|
|
41
|
+
const paths_js_1 = require("../common/paths.js");
|
|
42
|
+
const downloading_js_1 = require("./downloading.js");
|
|
43
|
+
const fs_1 = __importDefault(require("fs"));
|
|
44
|
+
const path_1 = __importDefault(require("path"));
|
|
45
|
+
const tar = __importStar(require("tar"));
|
|
46
|
+
const unzip_js_1 = require("./unzip.js");
|
|
47
|
+
const apiLink = `https://api.adoptium.net/v3/binary/latest/17/ga/${architecture_js_1.adoptiumOS}/${architecture_js_1.adoptiumArch}/jre/hotspot/normal/eclipse`;
|
|
48
|
+
const downloadArchiveWithJava = (filePath) => {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const dir = path_1.default.dirname(filePath);
|
|
51
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
52
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
(0, downloading_js_1.downloadWithRedirect)(apiLink, filePath).then(resolve).catch(reject);
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const unpackArchive = (archivePath, extractPath) => {
|
|
58
|
+
if (!fs_1.default.existsSync(extractPath)) {
|
|
59
|
+
fs_1.default.mkdirSync(extractPath, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
if (archivePath.endsWith(".zip")) {
|
|
62
|
+
return (0, unzip_js_1.extractZip)(archivePath, extractPath);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
return tar.extract({
|
|
66
|
+
file: archivePath,
|
|
67
|
+
cwd: extractPath,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const ensureJavaInstalled = async () => {
|
|
72
|
+
const javaPath = (0, paths_js_1.findJavaBinPath)();
|
|
73
|
+
if (javaPath != null) {
|
|
74
|
+
return javaPath;
|
|
75
|
+
}
|
|
76
|
+
const tsaHome = (0, paths_js_1.findTSAHomeDirectory)();
|
|
77
|
+
const archiveExtension = architecture_js_1.adoptiumOS === "windows" ? "zip" : "tar.gz";
|
|
78
|
+
const archivePath = path_1.default.join(tsaHome, `jre.${archiveExtension}`);
|
|
79
|
+
const jrePath = path_1.default.join(tsaHome, "jre");
|
|
80
|
+
await downloadArchiveWithJava(archivePath);
|
|
81
|
+
await unpackArchive(archivePath, jrePath);
|
|
82
|
+
fs_1.default.unlinkSync(archivePath);
|
|
83
|
+
const result = (0, paths_js_1.findJavaBinPath)();
|
|
84
|
+
if (result == null) {
|
|
85
|
+
throw new Error("Java was not installed");
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
};
|
|
89
|
+
exports.ensureJavaInstalled = ensureJavaInstalled;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const java_js_1 = require("./java.js");
|
|
4
|
+
const tsa_jar_js_1 = require("./tsa-jar.js");
|
|
5
|
+
/**
|
|
6
|
+
* Postinstall script for blueprint-tsa
|
|
7
|
+
* Runs after the package is installed
|
|
8
|
+
*/
|
|
9
|
+
async function main() {
|
|
10
|
+
await Promise.all([(0, java_js_1.ensureJavaInstalled)(), (0, tsa_jar_js_1.ensureTsaInstalled)()]);
|
|
11
|
+
}
|
|
12
|
+
main();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ensureTsaInstalled: () => Promise<string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ensureTsaInstalled = void 0;
|
|
7
|
+
const constants_js_1 = require("../common/constants.js");
|
|
8
|
+
const paths_js_1 = require("../common/paths.js");
|
|
9
|
+
const downloading_js_1 = require("./downloading.js");
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const ensureTsaInstalled = async () => {
|
|
12
|
+
const tsaPath = (0, paths_js_1.findTsaPath)();
|
|
13
|
+
if (tsaPath != null) {
|
|
14
|
+
return tsaPath;
|
|
15
|
+
}
|
|
16
|
+
await (0, downloading_js_1.downloadWithRedirect)(constants_js_1.TSA_URL, path_1.default.join((0, paths_js_1.findTSAHomeDirectory)(), constants_js_1.TSA_NAME));
|
|
17
|
+
const result = (0, paths_js_1.findTsaPath)();
|
|
18
|
+
if (result == null) {
|
|
19
|
+
throw new Error("TSA was not installed");
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
};
|
|
23
|
+
exports.ensureTsaInstalled = ensureTsaInstalled;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const extractZip: (zipPath: string, extractPath: string) => Promise<void>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractZip = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const unzipper_1 = require("unzipper");
|
|
6
|
+
const extractZip = (zipPath, extractPath) => {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
(0, fs_1.createReadStream)(zipPath)
|
|
9
|
+
.pipe((0, unzipper_1.Extract)({ path: extractPath }))
|
|
10
|
+
.on("close", resolve)
|
|
11
|
+
.on("error", reject);
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
exports.extractZip = extractZip;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { VulnerabilityDescription } from "../common/analyzer-wrapper.js";
|
|
2
|
+
import { ConcreteCheckerOptions } from "./reproduce-config.js";
|
|
3
|
+
export declare const writeReproduceConfig: (vulnerability: VulnerabilityDescription, command: string, timeout: number | null, id: string, concreteCheckerOptions: ConcreteCheckerOptions) => void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeReproduceConfig = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const paths_js_1 = require("../common/paths.js");
|
|
6
|
+
const constants_js_1 = require("../common/constants.js");
|
|
7
|
+
const writeReproduceConfig = (vulnerability, command, timeout, id, concreteCheckerOptions) => {
|
|
8
|
+
if (vulnerability.value == null) {
|
|
9
|
+
throw new Error("Unexpected external message");
|
|
10
|
+
}
|
|
11
|
+
const config = {
|
|
12
|
+
mode: constants_js_1.DEPLOY_AND_REPRODUCE_COMMAND,
|
|
13
|
+
command,
|
|
14
|
+
codePath: vulnerability.codePath,
|
|
15
|
+
dataPath: vulnerability.dataPath,
|
|
16
|
+
suggestedValue: vulnerability.value.toString(),
|
|
17
|
+
suggestedBalance: vulnerability.balance.toString(),
|
|
18
|
+
timeout,
|
|
19
|
+
concreteCheckerOptions,
|
|
20
|
+
};
|
|
21
|
+
const filePath = (0, paths_js_1.getReproduceConfigPath)(id);
|
|
22
|
+
(0, fs_1.writeFileSync)(filePath, JSON.stringify(config));
|
|
23
|
+
};
|
|
24
|
+
exports.writeReproduceConfig = writeReproduceConfig;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { UIProvider } from "@ton/blueprint";
|
|
2
|
+
import { Address } from "@ton/core";
|
|
3
|
+
import { ReproduceParameters } from "./network.js";
|
|
4
|
+
import { ConcreteCheckerOptions } from "./reproduce-config.js";
|
|
5
|
+
export interface ConcreteAnalysisConfig {
|
|
6
|
+
codePath: string;
|
|
7
|
+
dataPath: string;
|
|
8
|
+
balance: bigint;
|
|
9
|
+
contractAddress: Address;
|
|
10
|
+
senderAddress: Address;
|
|
11
|
+
ui: UIProvider;
|
|
12
|
+
timeout: number | null;
|
|
13
|
+
concreteCheckerOptions: ConcreteCheckerOptions;
|
|
14
|
+
}
|
|
15
|
+
export declare const runConcreteAnalysis: (mode: string, config: ConcreteAnalysisConfig) => Promise<ReproduceParameters | null>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runConcreteAnalysis = void 0;
|
|
4
|
+
const constants_js_1 = require("../common/constants.js");
|
|
5
|
+
const drain_check_js_1 = require("../commands/drain-check.js");
|
|
6
|
+
const owner_hijack_check_js_1 = require("../commands/owner-hijack-check.js");
|
|
7
|
+
const runConcreteAnalysis = async (mode, config) => {
|
|
8
|
+
const ui = config.ui;
|
|
9
|
+
const concreteCheckerOptions = config.concreteCheckerOptions;
|
|
10
|
+
if (concreteCheckerOptions.kind === "drain-check") {
|
|
11
|
+
return await (0, drain_check_js_1.drainCheckConcrete)(config);
|
|
12
|
+
}
|
|
13
|
+
else if (concreteCheckerOptions.kind === "owner-hijack-check") {
|
|
14
|
+
return await (0, owner_hijack_check_js_1.ownerHijackCheckConcrete)(config, concreteCheckerOptions);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
ui.write(`${constants_js_1.Sym.ERR} Invalid command: ${mode}`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.runConcreteAnalysis = runConcreteAnalysis;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Address, Cell } from "@ton/core";
|
|
2
|
+
import { NetworkProvider } from "@ton/blueprint";
|
|
3
|
+
export interface DeployConfig {
|
|
4
|
+
code: Cell;
|
|
5
|
+
data: Cell;
|
|
6
|
+
suggestedBalance: bigint;
|
|
7
|
+
suggestedValue: bigint;
|
|
8
|
+
}
|
|
9
|
+
export interface DeployResult {
|
|
10
|
+
address: Address;
|
|
11
|
+
balance: bigint;
|
|
12
|
+
}
|
|
13
|
+
export declare const deployViaChameleon: (network: NetworkProvider, config: DeployConfig, nonces: bigint[]) => Promise<DeployResult>;
|
|
14
|
+
export interface ReproduceParameters {
|
|
15
|
+
address: Address;
|
|
16
|
+
msgBody: Cell;
|
|
17
|
+
suggestedValue: bigint;
|
|
18
|
+
}
|
|
19
|
+
export declare const reproduce: (network: NetworkProvider, config: ReproduceParameters) => Promise<void>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reproduce = exports.deployViaChameleon = void 0;
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
|
+
const constants_js_1 = require("../common/constants.js");
|
|
6
|
+
const build_utils_js_1 = require("../common/build-utils.js");
|
|
7
|
+
const format_utils_js_1 = require("../common/format-utils.js");
|
|
8
|
+
const paths_js_1 = require("../common/paths.js");
|
|
9
|
+
async function ensureDeployed(network, chameleonAddress, chameleonStateInit, tonsForSendingMessage, messageToChameleon) {
|
|
10
|
+
const ui = network.ui();
|
|
11
|
+
const isDeployed = await network.isContractDeployed(chameleonAddress);
|
|
12
|
+
// ensure chameleon deployed
|
|
13
|
+
if (!isDeployed) {
|
|
14
|
+
ui.write(`${constants_js_1.Sym.WAIT} Sending a message to deploy the contract under test`);
|
|
15
|
+
await network.sender().send({
|
|
16
|
+
to: chameleonAddress,
|
|
17
|
+
value: tonsForSendingMessage,
|
|
18
|
+
init: chameleonStateInit,
|
|
19
|
+
body: messageToChameleon,
|
|
20
|
+
});
|
|
21
|
+
await network.waitForDeploy(chameleonAddress, constants_js_1.DEPLOY_WAIT_ATTEMPTS);
|
|
22
|
+
const chameleonState = await network.getContractState(chameleonAddress);
|
|
23
|
+
if (chameleonState.state.type !== "active") {
|
|
24
|
+
throw new Error(`Failed to deploy ${chameleonAddress}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const deployViaChameleon = async (network, config, nonces) => {
|
|
29
|
+
const ui = network.ui();
|
|
30
|
+
const chameleonContractFilename = "chameleon-contract.fc";
|
|
31
|
+
const path = (0, paths_js_1.getCheckerPath)(chameleonContractFilename);
|
|
32
|
+
const chameleonContract = core_1.Cell.fromBase64(await (0, build_utils_js_1.compileFuncFileToBase64Boc)(path, chameleonContractFilename));
|
|
33
|
+
const chameleonStateInit = {
|
|
34
|
+
code: chameleonContract,
|
|
35
|
+
data: nonces
|
|
36
|
+
.reduce((prevCell, nextNoncePart) => prevCell.storeInt(nextNoncePart, 32), (0, core_1.beginCell)())
|
|
37
|
+
.endCell(),
|
|
38
|
+
};
|
|
39
|
+
const chameleonAddress = (0, core_1.contractAddress)(0, chameleonStateInit);
|
|
40
|
+
const suggested = (0, format_utils_js_1.nanotonToTon)(config.suggestedValue + config.suggestedBalance);
|
|
41
|
+
const tonsForSendingMessageInput = await ui.input(`Enter amount of TONs for deployment message (suggested: ${suggested} + fees):`);
|
|
42
|
+
const tonsForSendingMessage = (0, core_1.toNano)(tonsForSendingMessageInput);
|
|
43
|
+
const messageToChameleon = (0, core_1.beginCell)()
|
|
44
|
+
.storeRef(config.data)
|
|
45
|
+
.storeRef(config.code)
|
|
46
|
+
.endCell();
|
|
47
|
+
await ensureDeployed(network, chameleonAddress, chameleonStateInit, tonsForSendingMessage, messageToChameleon);
|
|
48
|
+
const chameleonState = await network.getContractState(chameleonAddress);
|
|
49
|
+
if (chameleonState.state.type !== "active") {
|
|
50
|
+
throw new Error(`Failed to deploy ${chameleonAddress}`);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
address: chameleonAddress,
|
|
54
|
+
balance: chameleonState.balance,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
exports.deployViaChameleon = deployViaChameleon;
|
|
58
|
+
const reproduce = async (network, config) => {
|
|
59
|
+
const ui = network.ui();
|
|
60
|
+
ui.write(`Number of TONs for reproduction message: ${(0, format_utils_js_1.nanotonToTon)(config.suggestedValue)}`);
|
|
61
|
+
ui.write(`${constants_js_1.Sym.WAIT} Sending a reproduction message`);
|
|
62
|
+
await network.sender().send({
|
|
63
|
+
to: config.address,
|
|
64
|
+
value: config.suggestedValue,
|
|
65
|
+
body: config.msgBody,
|
|
66
|
+
});
|
|
67
|
+
await network.waitForLastTransaction(constants_js_1.DEPLOY_WAIT_ATTEMPTS);
|
|
68
|
+
ui.write(`${constants_js_1.Sym.OK} Reproduction message sent!`);
|
|
69
|
+
};
|
|
70
|
+
exports.reproduce = reproduce;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
declare const OwnerHijackOptionsSchema: z.ZodObject<{
|
|
3
|
+
kind: z.ZodLiteral<"owner-hijack-check">;
|
|
4
|
+
methodId: z.ZodString;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export type OwnerHijackOptions = z.infer<typeof OwnerHijackOptionsSchema>;
|
|
7
|
+
export declare const ConcreteCheckerOptionsSchema: z.ZodXor<readonly [z.ZodObject<{
|
|
8
|
+
kind: z.ZodLiteral<"drain-check">;
|
|
9
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
10
|
+
kind: z.ZodLiteral<"owner-hijack-check">;
|
|
11
|
+
methodId: z.ZodString;
|
|
12
|
+
}, z.core.$strip>]>;
|
|
13
|
+
export type ConcreteCheckerOptions = z.infer<typeof ConcreteCheckerOptionsSchema>;
|
|
14
|
+
export declare const TsaVulnerabilityConfigSchema: z.ZodObject<{
|
|
15
|
+
mode: z.ZodString;
|
|
16
|
+
command: z.ZodString;
|
|
17
|
+
codePath: z.ZodString;
|
|
18
|
+
dataPath: z.ZodString;
|
|
19
|
+
suggestedValue: z.ZodString;
|
|
20
|
+
suggestedBalance: z.ZodString;
|
|
21
|
+
timeout: z.ZodNullable<z.ZodInt>;
|
|
22
|
+
concreteCheckerOptions: z.ZodXor<readonly [z.ZodObject<{
|
|
23
|
+
kind: z.ZodLiteral<"drain-check">;
|
|
24
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
25
|
+
kind: z.ZodLiteral<"owner-hijack-check">;
|
|
26
|
+
methodId: z.ZodString;
|
|
27
|
+
}, z.core.$strip>]>;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
export type TsaVulnerabilityConfig = z.infer<typeof TsaVulnerabilityConfigSchema>;
|
|
30
|
+
export {};
|