@aiot-toolkit/aiotpack 2.0.3-beta.7 → 2.0.3-beta.8
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/lib/afterCompile/ux/UxAfterCompile.js +301 -266
- package/lib/afterCompile/xts/entryTemplate.js +111 -113
- package/lib/afterCompile/xts/generateRpk.js +25 -54
- package/lib/afterCompile/xts/ts2wasm.js +62 -63
- package/lib/afterWorks/ux/UxAfterWorks.js +12 -19
- package/lib/beforeCompile/ux/UxBeforeCompile.js +26 -25
- package/lib/beforeCompile/xts/preInstall.js +50 -55
- package/lib/beforeWorks/ux/UxBeforeWorks.js +12 -19
- package/lib/compiler/enum/CompileMode.js +16 -23
- package/lib/compiler/interface/ICompileParam.js +1 -2
- package/lib/compiler/interface/ICompiler.js +1 -2
- package/lib/compiler/interface/ISignConfig.js +1 -2
- package/lib/compiler/javascript/JavascriptCompiler.js +147 -154
- package/lib/compiler/javascript/JavascriptDefaultCompileOption.js +20 -16
- package/lib/compiler/javascript/android/AndroidWebpackConfigurator.js +13 -11
- package/lib/compiler/javascript/android/plugin/WrapPlugin.js +52 -48
- package/lib/compiler/javascript/interface/IJavascriptCompileOption.js +1 -2
- package/lib/compiler/javascript/interface/IWebpackConfigurator.js +4 -1
- package/lib/compiler/javascript/vela/VelaWebpackConfigurator.js +78 -75
- package/lib/compiler/javascript/vela/enum/BuildNameFormatType.js +30 -41
- package/lib/compiler/javascript/vela/enum/EntryType.js +15 -29
- package/lib/compiler/javascript/vela/interface/IChunk.js +4 -1
- package/lib/compiler/javascript/vela/interface/IManifest.js +1 -2
- package/lib/compiler/javascript/vela/interface/IQuickAppConfig.js +1 -2
- package/lib/compiler/javascript/vela/model/Package.js +80 -51
- package/lib/compiler/javascript/vela/plugin/WrapPlugin.js +30 -26
- package/lib/compiler/javascript/vela/utils/Jsc.js +30 -33
- package/lib/compiler/javascript/vela/utils/UxCompileUtil.js +152 -130
- package/lib/compiler/javascript/vela/utils/ZipUtil.js +282 -276
- package/lib/compiler/javascript/vela/utils/signature/Base64.js +65 -67
- package/lib/compiler/javascript/vela/utils/signature/CRC32.js +37 -35
- package/lib/compiler/javascript/vela/utils/signature/SignUtil.js +755 -731
- package/lib/compiler/javascript/vela/utils/signature/Signer.js +24 -22
- package/lib/compiler/javascript/vela/utils/webpackLoader/addColSourceMap.js +47 -52
- package/lib/compiler/javascript/vela/utils/webpackLoader/extractMapData.js +21 -17
- package/lib/config/UxConfig.js +145 -173
- package/lib/config/XtsConfig.js +30 -40
- package/lib/index.js +88 -41
- package/lib/interface/ICompileOptions.js +5 -2
- package/lib/interface/IDeviceList.js +1 -2
- package/lib/loader/ux/JsLoader.js +32 -30
- package/lib/loader/ux/PngLoader.js +47 -53
- package/lib/loader/ux/android/UxLoader.js +30 -31
- package/lib/loader/ux/vela/AppUxLoader.js +23 -24
- package/lib/loader/ux/vela/HmlLoader.js +59 -55
- package/lib/loader/ux/vela/UxLoader.js +29 -35
- package/lib/loader/xts/XtsLoader.js +55 -41
- package/lib/utils/BeforeCompileUtils.js +100 -92
- package/lib/utils/PngUtils.js +42 -36
- package/lib/utils/ux/ManifestSchema.js +198 -194
- package/lib/utils/ux/UxFileUtils.js +130 -116
- package/lib/utils/ux/UxLoaderUtils.js +292 -307
- package/lib/utils/ux/android/AndroidUx.js +88 -90
- package/lib/utils/xts/XtsFileLaneUtils.js +58 -65
- package/lib/utils/xts/XtsFollowWorks.js +122 -129
- package/package.json +6 -6
|
@@ -1,764 +1,788 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const jszip_1 = __importDefault(require("jszip"));
|
|
20
|
-
const path_1 = __importDefault(require("path"));
|
|
21
|
-
const CompileMode_1 = __importDefault(require("../../../../enum/CompileMode"));
|
|
22
|
-
const ZipUtil_1 = __importDefault(require("../ZipUtil"));
|
|
23
|
-
const Base64_1 = __importDefault(require("./Base64"));
|
|
24
|
-
const CRC32_1 = __importDefault(require("./CRC32"));
|
|
25
|
-
const Signer_1 = __importDefault(require("./Signer"));
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _sharedUtils = require("@aiot-toolkit/shared-utils");
|
|
8
|
+
var _crypto = _interopRequireDefault(require("crypto"));
|
|
9
|
+
var _fsExtra = _interopRequireDefault(require("fs-extra"));
|
|
10
|
+
var _jsrsasign = _interopRequireDefault(require("jsrsasign"));
|
|
11
|
+
var _jszip = _interopRequireDefault(require("jszip"));
|
|
12
|
+
var _path = _interopRequireDefault(require("path"));
|
|
13
|
+
var _CompileMode = _interopRequireDefault(require("../../../../enum/CompileMode"));
|
|
14
|
+
var _ZipUtil = _interopRequireDefault(require("../ZipUtil"));
|
|
15
|
+
var _Base = _interopRequireDefault(require("./Base64"));
|
|
16
|
+
var _CRC = _interopRequireDefault(require("./CRC32"));
|
|
17
|
+
var _Signer = _interopRequireDefault(require("./Signer"));
|
|
18
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
26
19
|
/**
|
|
27
20
|
* SignUtil
|
|
28
21
|
*/
|
|
29
22
|
class SignUtil {
|
|
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
|
-
const findPath = modeSignConfig.find(({ privatekey, certificate }) => shared_utils_1.FileUtil.checkFilePath([privatekey, certificate]));
|
|
80
|
-
if (findPath) {
|
|
81
|
-
let { privatekey: privatekeyPath, certificate: certificatePath } = findPath;
|
|
82
|
-
shared_utils_1.ColorConsole.info('privatekeyPath is ', {
|
|
83
|
-
word: privatekeyPath
|
|
84
|
-
}, `\ncertificatePath is `, {
|
|
85
|
-
word: certificatePath
|
|
86
|
-
});
|
|
87
|
-
// 读取证书内容
|
|
88
|
-
signConfig = {
|
|
89
|
-
privatekey: fs_extra_1.default.readFileSync(privatekeyPath),
|
|
90
|
-
certificate: fs_extra_1.default.readFileSync(certificatePath)
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
// 抛出错误,在指定模式下未找到证书
|
|
95
|
-
throw new Error(`The current mode is ${mode}, and there is a problem with the certification path`);
|
|
96
|
-
}
|
|
97
|
-
return signConfig;
|
|
23
|
+
/**
|
|
24
|
+
* 获取签名相关的配置内容
|
|
25
|
+
* @param param IJavascriptCompileOption参数中获取签名目录等内容
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
static getProjectSignConfig(param) {
|
|
29
|
+
const {
|
|
30
|
+
mode,
|
|
31
|
+
projectPath,
|
|
32
|
+
signRoot
|
|
33
|
+
} = param;
|
|
34
|
+
const signPathFolder = _path.default.join(projectPath, signRoot || 'sign');
|
|
35
|
+
const signPathConfig = {
|
|
36
|
+
debug: {
|
|
37
|
+
privatekey: _path.default.join(signPathFolder, 'debug', 'private.pem'),
|
|
38
|
+
certificate: _path.default.join(signPathFolder, 'debug', 'certificate.pem')
|
|
39
|
+
},
|
|
40
|
+
sign: {
|
|
41
|
+
privatekey: _path.default.join(signPathFolder, 'private.pem'),
|
|
42
|
+
certificate: _path.default.join(signPathFolder, 'certificate.pem')
|
|
43
|
+
},
|
|
44
|
+
defaultDevelopment: {
|
|
45
|
+
privatekey: _path.default.join(__dirname, 'pem', 'private.pem'),
|
|
46
|
+
certificate: _path.default.join(__dirname, 'pem', 'certificate.pem')
|
|
47
|
+
},
|
|
48
|
+
oldRelease: {
|
|
49
|
+
privatekey: _path.default.join(signPathFolder, 'release', 'private.pem'),
|
|
50
|
+
certificate: _path.default.join(signPathFolder, 'release', 'certificate.pem')
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
// build模式 优先sign/debug/证书 其次sign/证书 最后toolkit中默认的证书
|
|
54
|
+
const developmentSignConfig = [signPathConfig.debug, signPathConfig.sign, signPathConfig.defaultDevelopment];
|
|
55
|
+
// release模式 优先sign/release/证书 其次sign/证书
|
|
56
|
+
const releaseSignConfig = [signPathConfig.oldRelease, signPathConfig.sign];
|
|
57
|
+
let modeSignConfig = [];
|
|
58
|
+
let signConfig;
|
|
59
|
+
switch (mode) {
|
|
60
|
+
case _CompileMode.default.DEVELOPMENT:
|
|
61
|
+
modeSignConfig = developmentSignConfig;
|
|
62
|
+
break;
|
|
63
|
+
case _CompileMode.default.PRODUCTION:
|
|
64
|
+
modeSignConfig = releaseSignConfig;
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
// 打印信息, 模式未定义
|
|
68
|
+
_sharedUtils.ColorConsole.error(`Error: mode ${mode} undefined`);
|
|
69
|
+
break;
|
|
98
70
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
};
|
|
126
|
-
const signedMetaBuffer = SignUtil.doSign(metaBuffer, [metaHash], privatekey, certificate);
|
|
127
|
-
if (signedMetaBuffer === false) {
|
|
128
|
-
// META-INF/CERT签名失败
|
|
129
|
-
shared_utils_1.ColorConsole.throw('META-INF/CERT signature failed');
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
fileList.push({
|
|
133
|
-
path: ZipUtil_1.default.CERT_PATH,
|
|
134
|
-
content: signedMetaBuffer
|
|
135
|
-
});
|
|
136
|
-
fileDigestHash.push({
|
|
137
|
-
name: ZipUtil_1.default.CERT_PATH,
|
|
138
|
-
hash: shared_utils_1.CommonUtil.calcDataDigest(signedMetaBuffer)
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
// 2
|
|
143
|
-
const files = target.resourceList;
|
|
144
|
-
files
|
|
145
|
-
.map((item) => {
|
|
146
|
-
return {
|
|
147
|
-
path: item.fileBuildPath,
|
|
148
|
-
content: item.fileContentBuffer
|
|
149
|
-
};
|
|
150
|
-
})
|
|
151
|
-
.filter(SignUtil.fileFilter)
|
|
152
|
-
.map((item) => {
|
|
153
|
-
fileList.push(item);
|
|
154
|
-
fileDigestHash.push({
|
|
155
|
-
name: item.path,
|
|
156
|
-
hash: shared_utils_1.CommonUtil.calcDataDigest(item.content)
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
// 因为META变化,重新创建ZIP流
|
|
160
|
-
const newZipBuffer = yield ZipUtil_1.default.createZipBufferFromFileList(fileList, target.comment);
|
|
161
|
-
// 3
|
|
162
|
-
const signedZipBuffer = SignUtil.doSign(newZipBuffer, fileDigestHash, privatekey, certificate);
|
|
163
|
-
if (signedZipBuffer === false) {
|
|
164
|
-
// 签名失败
|
|
165
|
-
shared_utils_1.ColorConsole.throw('package signature failed');
|
|
166
|
-
}
|
|
167
|
-
return signedZipBuffer;
|
|
168
|
-
});
|
|
71
|
+
// 寻找有效的证书路径
|
|
72
|
+
const findPath = modeSignConfig.find(_ref => {
|
|
73
|
+
let {
|
|
74
|
+
privatekey,
|
|
75
|
+
certificate
|
|
76
|
+
} = _ref;
|
|
77
|
+
return _sharedUtils.FileUtil.checkFilePath([privatekey, certificate]);
|
|
78
|
+
});
|
|
79
|
+
if (findPath) {
|
|
80
|
+
let {
|
|
81
|
+
privatekey: privatekeyPath,
|
|
82
|
+
certificate: certificatePath
|
|
83
|
+
} = findPath;
|
|
84
|
+
_sharedUtils.ColorConsole.info('privatekeyPath is ', {
|
|
85
|
+
word: privatekeyPath
|
|
86
|
+
}, `\ncertificatePath is `, {
|
|
87
|
+
word: certificatePath
|
|
88
|
+
});
|
|
89
|
+
// 读取证书内容
|
|
90
|
+
signConfig = {
|
|
91
|
+
privatekey: _fsExtra.default.readFileSync(privatekeyPath),
|
|
92
|
+
certificate: _fsExtra.default.readFileSync(certificatePath)
|
|
93
|
+
};
|
|
94
|
+
} else {
|
|
95
|
+
// 抛出错误,在指定模式下未找到证书
|
|
96
|
+
throw new Error(`The current mode is ${mode}, and there is a problem with the certification path`);
|
|
169
97
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
98
|
+
return signConfig;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 对二进制zipBuffer签名
|
|
103
|
+
*
|
|
104
|
+
* 1. 对`META-INF/CERT`做签名,并生成新的`META-INF/CERT` buffer
|
|
105
|
+
* 2. "新`META-INF/CERT` + 其它文件"生成新的 zipBuffer
|
|
106
|
+
* 3. 对“新zipBuffer”,做整体签名
|
|
107
|
+
* @param zipBuffer
|
|
108
|
+
* @param privatekey
|
|
109
|
+
* @param certificate
|
|
110
|
+
* @returns
|
|
111
|
+
*/
|
|
112
|
+
static async signPackage(target, privatekey, certificate) {
|
|
113
|
+
const getFileBuffer = path => {
|
|
114
|
+
return target.getResource(path);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// 摘要 和 文件列表
|
|
118
|
+
const fileDigestHash = [];
|
|
119
|
+
const fileList = [];
|
|
120
|
+
|
|
121
|
+
// 1
|
|
122
|
+
const metaBuffer = getFileBuffer(_ZipUtil.default.CERT_PATH)?.fileContentBuffer;
|
|
123
|
+
if (metaBuffer) {
|
|
124
|
+
const metaHash = {
|
|
125
|
+
name: _ZipUtil.default.DIGEST_HASH_JSON,
|
|
126
|
+
hash: _sharedUtils.CommonUtil.calcDataDigest(metaBuffer)
|
|
127
|
+
};
|
|
128
|
+
const signedMetaBuffer = SignUtil.doSign(metaBuffer, [metaHash], privatekey, certificate);
|
|
129
|
+
if (signedMetaBuffer === false) {
|
|
130
|
+
// META-INF/CERT签名失败
|
|
131
|
+
_sharedUtils.ColorConsole.throw('META-INF/CERT signature failed');
|
|
132
|
+
} else {
|
|
133
|
+
fileList.push({
|
|
134
|
+
path: _ZipUtil.default.CERT_PATH,
|
|
135
|
+
content: signedMetaBuffer
|
|
201
136
|
});
|
|
137
|
+
fileDigestHash.push({
|
|
138
|
+
name: _ZipUtil.default.CERT_PATH,
|
|
139
|
+
hash: _sharedUtils.CommonUtil.calcDataDigest(signedMetaBuffer)
|
|
140
|
+
});
|
|
141
|
+
}
|
|
202
142
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* 解析buffer
|
|
226
|
-
* @param fileBuffer
|
|
227
|
-
* @param files
|
|
228
|
-
*/
|
|
229
|
-
static unZipFiles(fileBuffer, files) {
|
|
230
|
-
// 1. 读取zip文件
|
|
231
|
-
if (!fileBuffer || fileBuffer.length <= 4) {
|
|
232
|
-
shared_utils_1.ColorConsole.error('Zip file open failed');
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
// 2. 检查文件格式是否正确
|
|
236
|
-
const fileMagic = fileBuffer.readInt32LE(0);
|
|
237
|
-
if (fileMagic !== 0x4034b50) {
|
|
238
|
-
shared_utils_1.ColorConsole.error('Zip file format is wrong');
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
|
-
// 3. 解析数据块
|
|
242
|
-
const chunks = SignUtil.parserZip(fileBuffer);
|
|
243
|
-
chunks.options = { files };
|
|
244
|
-
// 解析成功,生成签名块
|
|
245
|
-
if (chunks.tag) {
|
|
246
|
-
// 分别处理三个签名块
|
|
247
|
-
Object.keys(chunks.sections).forEach((item) => {
|
|
248
|
-
const chunk = chunks.sections[item];
|
|
249
|
-
SignUtil.processChunk(fileBuffer, chunk);
|
|
250
|
-
});
|
|
251
|
-
return [chunks, fileBuffer];
|
|
252
|
-
}
|
|
253
|
-
return false;
|
|
143
|
+
// 2
|
|
144
|
+
const files = target.resourceList;
|
|
145
|
+
files.map(item => {
|
|
146
|
+
return {
|
|
147
|
+
path: item.fileBuildPath,
|
|
148
|
+
content: item.fileContentBuffer
|
|
149
|
+
};
|
|
150
|
+
}).filter(SignUtil.fileFilter).map(item => {
|
|
151
|
+
fileList.push(item);
|
|
152
|
+
fileDigestHash.push({
|
|
153
|
+
name: item.path,
|
|
154
|
+
hash: _sharedUtils.CommonUtil.calcDataDigest(item.content)
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
// 因为META变化,重新创建ZIP流
|
|
158
|
+
const newZipBuffer = await _ZipUtil.default.createZipBufferFromFileList(fileList, target.comment);
|
|
159
|
+
// 3
|
|
160
|
+
const signedZipBuffer = SignUtil.doSign(newZipBuffer, fileDigestHash, privatekey, certificate);
|
|
161
|
+
if (signedZipBuffer === false) {
|
|
162
|
+
// 签名失败
|
|
163
|
+
_sharedUtils.ColorConsole.throw('package signature failed');
|
|
254
164
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
central: {
|
|
276
|
-
tag: false,
|
|
277
|
-
startIndex: 0,
|
|
278
|
-
len: 0,
|
|
279
|
-
previous: 0,
|
|
280
|
-
sign: undefined
|
|
281
|
-
},
|
|
282
|
-
footer: {
|
|
283
|
-
tag: false,
|
|
284
|
-
startIndex: 0,
|
|
285
|
-
len: 0,
|
|
286
|
-
previous: 0,
|
|
287
|
-
sign: undefined
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
// fileBuffer至少22个字节
|
|
292
|
-
chunk.sections.footer = SignUtil.readEOCD(fileBuffer);
|
|
293
|
-
if (chunk.sections.footer.tag) {
|
|
294
|
-
chunk.sections.central = SignUtil.readCD(fileBuffer, chunk.sections.footer.previous, chunk.sections.footer.startIndex - chunk.sections.footer.previous);
|
|
295
|
-
if (chunk.sections.central.tag) {
|
|
296
|
-
chunk.sections.header = SignUtil.readFH(fileBuffer, chunk.sections.central.previous, chunk.sections.central.startIndex - chunk.sections.central.previous);
|
|
297
|
-
if (chunk.sections.header.tag) {
|
|
298
|
-
chunk.tag = true;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
return chunk;
|
|
165
|
+
return signedZipBuffer;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 根据ZIP流获取文件实例
|
|
169
|
+
*
|
|
170
|
+
* 1. zipbuffer转换为JSZip对象
|
|
171
|
+
* 2. 提取文件列表,并生成每个文件的 buffer
|
|
172
|
+
* 3. 创建获取文件buffer的函数
|
|
173
|
+
*
|
|
174
|
+
* @param zipBuffer
|
|
175
|
+
* @returns
|
|
176
|
+
*/
|
|
177
|
+
static async createFileListFromZipBuffer(zipBuffer) {
|
|
178
|
+
const zipInst = await _jszip.default.loadAsync(zipBuffer, _ZipUtil.default.ZIP_OPTION);
|
|
179
|
+
async function iterator(filePath) {
|
|
180
|
+
const content = await zipInst.files[filePath].async('nodebuffer');
|
|
181
|
+
return {
|
|
182
|
+
path: filePath,
|
|
183
|
+
content
|
|
184
|
+
};
|
|
303
185
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
offset -= 1;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
return chunk;
|
|
186
|
+
const fileList = await Promise.all(Object.keys(zipInst.files).map(iterator));
|
|
187
|
+
return {
|
|
188
|
+
fileList,
|
|
189
|
+
comment: zipInst.comment,
|
|
190
|
+
getFileBuffer(path) {
|
|
191
|
+
const buffer = fileList.find(item => item.path === path);
|
|
192
|
+
return buffer?.content;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* 为 zip buffer 签名,返回签名后的buffer
|
|
198
|
+
*
|
|
199
|
+
* @description 根据zipBuffer + zip的文件列表 + 私钥 + 证书,对 zipbuffer 签名
|
|
200
|
+
* @param fileBuffer
|
|
201
|
+
* @param files
|
|
202
|
+
* @param privatekey
|
|
203
|
+
* @param certificate
|
|
204
|
+
*/
|
|
205
|
+
static doSign(fileBuffer, files, privatekey, certificate) {
|
|
206
|
+
const result = SignUtil.unZipFiles(fileBuffer, files);
|
|
207
|
+
if (!result) {
|
|
208
|
+
return false;
|
|
331
209
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
return chunk;
|
|
210
|
+
const [chunks] = result;
|
|
211
|
+
|
|
212
|
+
// 生成整体签名
|
|
213
|
+
SignUtil.signChunk(chunks, privatekey, certificate);
|
|
214
|
+
// 写入zip文件
|
|
215
|
+
const signContent = SignUtil.saveChunk(fileBuffer, chunks);
|
|
216
|
+
return signContent;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 解析buffer
|
|
220
|
+
* @param fileBuffer
|
|
221
|
+
* @param files
|
|
222
|
+
*/
|
|
223
|
+
static unZipFiles(fileBuffer, files) {
|
|
224
|
+
// 1. 读取zip文件
|
|
225
|
+
if (!fileBuffer || fileBuffer.length <= 4) {
|
|
226
|
+
_sharedUtils.ColorConsole.error('Zip file open failed');
|
|
227
|
+
return false;
|
|
353
228
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
* @returns
|
|
360
|
-
*/
|
|
361
|
-
static readFH(buffer, offset, size) {
|
|
362
|
-
let chunk;
|
|
363
|
-
if (buffer && buffer.length >= offset) {
|
|
364
|
-
const tag = buffer.readInt32LE(offset);
|
|
365
|
-
// 找到起始位置
|
|
366
|
-
if (tag === 0x4034b50) {
|
|
367
|
-
chunk = {
|
|
368
|
-
tag: true,
|
|
369
|
-
startIndex: offset,
|
|
370
|
-
len: size,
|
|
371
|
-
previous: -1
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
return chunk;
|
|
229
|
+
// 2. 检查文件格式是否正确
|
|
230
|
+
const fileMagic = fileBuffer.readInt32LE(0);
|
|
231
|
+
if (fileMagic !== 0x4034b50) {
|
|
232
|
+
_sharedUtils.ColorConsole.error('Zip file format is wrong');
|
|
233
|
+
return false;
|
|
376
234
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
header[0] = 0xa5;
|
|
391
|
-
// 从第二个字节位置开始填充,长度为4字节,填充内容为chk.length
|
|
392
|
-
header.writeInt32LE(chk.length, 1);
|
|
393
|
-
// 从第六个开始填充chk的内容
|
|
394
|
-
chk.copy(header, 5);
|
|
395
|
-
// 将buffer进行hash计算并存储到chunk对象上
|
|
396
|
-
const signer = crypto_1.default.createHash('SHA256');
|
|
397
|
-
signer.update(header);
|
|
398
|
-
chunk.sign = signer.digest();
|
|
235
|
+
// 3. 解析数据块
|
|
236
|
+
const chunks = SignUtil.parserZip(fileBuffer);
|
|
237
|
+
chunks.options = {
|
|
238
|
+
files
|
|
239
|
+
};
|
|
240
|
+
// 解析成功,生成签名块
|
|
241
|
+
if (chunks.tag) {
|
|
242
|
+
// 分别处理三个签名块
|
|
243
|
+
Object.keys(chunks.sections).forEach(item => {
|
|
244
|
+
const chunk = chunks.sections[item];
|
|
245
|
+
SignUtil.processChunk(fileBuffer, chunk);
|
|
246
|
+
});
|
|
247
|
+
return [chunks, fileBuffer];
|
|
399
248
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* 解析ZIP 分解为数据块
|
|
253
|
+
* @param fileBuffer
|
|
254
|
+
*/
|
|
255
|
+
static parserZip(fileBuffer) {
|
|
256
|
+
let chunk = {
|
|
257
|
+
signchunk: Buffer.from(''),
|
|
258
|
+
tag: false,
|
|
259
|
+
length: fileBuffer.length,
|
|
260
|
+
options: {
|
|
261
|
+
files: []
|
|
262
|
+
},
|
|
263
|
+
sections: {
|
|
264
|
+
header: {
|
|
265
|
+
tag: false,
|
|
266
|
+
startIndex: 0,
|
|
267
|
+
len: 0,
|
|
268
|
+
previous: 0,
|
|
269
|
+
sign: undefined
|
|
270
|
+
},
|
|
271
|
+
central: {
|
|
272
|
+
tag: false,
|
|
273
|
+
startIndex: 0,
|
|
274
|
+
len: 0,
|
|
275
|
+
previous: 0,
|
|
276
|
+
sign: undefined
|
|
277
|
+
},
|
|
278
|
+
footer: {
|
|
279
|
+
tag: false,
|
|
280
|
+
startIndex: 0,
|
|
281
|
+
len: 0,
|
|
282
|
+
previous: 0,
|
|
283
|
+
sign: undefined
|
|
406
284
|
}
|
|
407
|
-
|
|
408
|
-
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
// fileBuffer至少22个字节
|
|
288
|
+
chunk.sections.footer = SignUtil.readEOCD(fileBuffer);
|
|
289
|
+
if (chunk.sections.footer.tag) {
|
|
290
|
+
chunk.sections.central = SignUtil.readCD(fileBuffer, chunk.sections.footer.previous, chunk.sections.footer.startIndex - chunk.sections.footer.previous);
|
|
291
|
+
if (chunk.sections.central.tag) {
|
|
292
|
+
chunk.sections.header = SignUtil.readFH(fileBuffer, chunk.sections.central.previous, chunk.sections.central.startIndex - chunk.sections.central.previous);
|
|
293
|
+
if (chunk.sections.header.tag) {
|
|
294
|
+
chunk.tag = true;
|
|
409
295
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return chunk;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* 从后往前读取buffer,读取尾部buffer
|
|
302
|
+
* @param buffer
|
|
303
|
+
* @returns
|
|
304
|
+
*/
|
|
305
|
+
static readEOCD(buffer) {
|
|
306
|
+
let chunk;
|
|
307
|
+
if (buffer && buffer.length >= 22) {
|
|
308
|
+
let offset = buffer.length - 22;
|
|
309
|
+
let tag;
|
|
310
|
+
// 从开始位置往前单个字节读取,检查
|
|
311
|
+
while (offset >= 0) {
|
|
312
|
+
tag = buffer.readInt32LE(offset);
|
|
313
|
+
if (tag === 0x6054b50) {
|
|
314
|
+
// 如果找到起始位置
|
|
315
|
+
chunk = {
|
|
316
|
+
tag: true,
|
|
317
|
+
startIndex: offset,
|
|
318
|
+
len: buffer.length - offset,
|
|
319
|
+
previous: buffer.readInt32LE(offset + 16)
|
|
320
|
+
};
|
|
321
|
+
break;
|
|
421
322
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
sections.footer.sign && writeBuffer(sections.footer.sign);
|
|
425
|
-
// 计算整体摘要
|
|
426
|
-
const signer = crypto_1.default.createHash('SHA256');
|
|
427
|
-
signer.update(wholeData);
|
|
428
|
-
const signature = signer.digest();
|
|
429
|
-
// 生成sign block, 计算block总长度, 向buf中考入数据
|
|
430
|
-
const signchunk = SignUtil.makeSignChunk(chunks.options, signature, privatekey, certificate);
|
|
431
|
-
chunks.signchunk = SignUtil.saveSignChunk(signchunk);
|
|
323
|
+
offset -= 1;
|
|
324
|
+
}
|
|
432
325
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
cert.copy(certBuf, 4);
|
|
453
|
-
const certBlock = {
|
|
454
|
-
len: certBuf.length,
|
|
455
|
-
buffer: certBuf
|
|
456
|
-
};
|
|
457
|
-
// 签名数据
|
|
458
|
-
const signdataBlock = {
|
|
459
|
-
len: 12,
|
|
460
|
-
digests: {
|
|
461
|
-
size: 0,
|
|
462
|
-
data: []
|
|
463
|
-
},
|
|
464
|
-
certs: {
|
|
465
|
-
size: 0,
|
|
466
|
-
data: []
|
|
467
|
-
},
|
|
468
|
-
additional: 0
|
|
469
|
-
};
|
|
470
|
-
signdataBlock.digests.data.push(digestBlock);
|
|
471
|
-
signdataBlock.digests.size += digestBlock.len;
|
|
472
|
-
signdataBlock.len += digestBlock.len;
|
|
473
|
-
signdataBlock.certs.data.push(certBlock);
|
|
474
|
-
signdataBlock.certs.size += certBlock.len;
|
|
475
|
-
signdataBlock.len += certBlock.len;
|
|
476
|
-
// 将public.pem转化为der
|
|
477
|
-
const pubbuf = Buffer.from(Base64_1.default.unarmor(pubKey));
|
|
478
|
-
const signBlock = {
|
|
479
|
-
len: 16 + pubbuf.length,
|
|
480
|
-
size: 12 + pubbuf.length,
|
|
481
|
-
signdata: {
|
|
482
|
-
size: 0,
|
|
483
|
-
buffer: null
|
|
484
|
-
},
|
|
485
|
-
signatures: {
|
|
486
|
-
size: 0,
|
|
487
|
-
data: []
|
|
488
|
-
},
|
|
489
|
-
pubkey: {
|
|
490
|
-
size: pubbuf.length,
|
|
491
|
-
buffer: pubbuf
|
|
492
|
-
}
|
|
493
|
-
};
|
|
494
|
-
signBlock.signdata.buffer = SignUtil.makeSignDataBuffer(signdataBlock);
|
|
495
|
-
signBlock.signdata.size = signdataBlock.len;
|
|
496
|
-
signBlock.size += signdataBlock.len;
|
|
497
|
-
signBlock.len += signdataBlock.len;
|
|
498
|
-
// 生成签名
|
|
499
|
-
const signature = SignUtil.callCryptoSignFunction(signBlock.signdata.buffer, privatekey, certificate);
|
|
500
|
-
const signatureBlock = {
|
|
501
|
-
len: signature.length + 12,
|
|
502
|
-
size: signature.length + 8,
|
|
503
|
-
id: 0x0103,
|
|
504
|
-
buffer: signature
|
|
326
|
+
return chunk;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* 读取中部buffer
|
|
330
|
+
* @param buffer
|
|
331
|
+
* @param offset
|
|
332
|
+
* @param size
|
|
333
|
+
*/
|
|
334
|
+
static readCD(buffer, offset, size) {
|
|
335
|
+
let chunk;
|
|
336
|
+
if (buffer && buffer.length >= offset) {
|
|
337
|
+
const tag = buffer.readInt32LE(offset);
|
|
338
|
+
// 找到起始位置
|
|
339
|
+
if (tag === 0x2014b50) {
|
|
340
|
+
chunk = {
|
|
341
|
+
tag: true,
|
|
342
|
+
startIndex: offset,
|
|
343
|
+
len: size,
|
|
344
|
+
previous: buffer.readInt32LE(offset + 42)
|
|
505
345
|
};
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
data: []
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return chunk;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* 读取前部buffer
|
|
352
|
+
* @param buffer
|
|
353
|
+
* @param offset
|
|
354
|
+
* @param size
|
|
355
|
+
* @returns
|
|
356
|
+
*/
|
|
357
|
+
static readFH(buffer, offset, size) {
|
|
358
|
+
let chunk;
|
|
359
|
+
if (buffer && buffer.length >= offset) {
|
|
360
|
+
const tag = buffer.readInt32LE(offset);
|
|
361
|
+
// 找到起始位置
|
|
362
|
+
if (tag === 0x4034b50) {
|
|
363
|
+
chunk = {
|
|
364
|
+
tag: true,
|
|
365
|
+
startIndex: offset,
|
|
366
|
+
len: size,
|
|
367
|
+
previous: -1
|
|
529
368
|
};
|
|
530
|
-
|
|
531
|
-
signchunk.size += kvBlock.len;
|
|
532
|
-
signchunk.len += kvBlock.len;
|
|
533
|
-
// 添加文件列表hash kvblock
|
|
534
|
-
if (options.files) {
|
|
535
|
-
const filehashChunk = SignUtil.signFiles(options.files, privatekey, certificate);
|
|
536
|
-
if (filehashChunk) {
|
|
537
|
-
const filesignBlocks = {
|
|
538
|
-
len: 4,
|
|
539
|
-
size: 0,
|
|
540
|
-
data: []
|
|
541
|
-
};
|
|
542
|
-
filesignBlocks.data.push(filehashChunk);
|
|
543
|
-
filesignBlocks.size += filehashChunk.length;
|
|
544
|
-
filesignBlocks.len += filehashChunk.length;
|
|
545
|
-
const filekvBlock = {
|
|
546
|
-
len: filesignBlocks.len + 12,
|
|
547
|
-
size: filesignBlocks.len + 4,
|
|
548
|
-
id: 0x01000201,
|
|
549
|
-
value: filesignBlocks
|
|
550
|
-
};
|
|
551
|
-
signchunk.data.push(filekvBlock);
|
|
552
|
-
signchunk.size += filekvBlock.len;
|
|
553
|
-
signchunk.len += filekvBlock.len;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
return signchunk;
|
|
369
|
+
}
|
|
557
370
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
371
|
+
return chunk;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* 数据块hash
|
|
375
|
+
* @param buffer
|
|
376
|
+
* @param chunk
|
|
377
|
+
*/
|
|
378
|
+
static processChunk(buffer, chunk) {
|
|
379
|
+
const cur = chunk.startIndex;
|
|
380
|
+
const end = chunk.startIndex + chunk.len;
|
|
381
|
+
// 取数据块对应的buffer内容
|
|
382
|
+
const chk = buffer.subarray(cur, end);
|
|
383
|
+
// 创建指定长度Buffer对象,并确保分配内存区域被清零
|
|
384
|
+
const header = Buffer.alloc(5 + chunk.len);
|
|
385
|
+
// 给第一个字节赋值
|
|
386
|
+
header[0] = 0xa5;
|
|
387
|
+
// 从第二个字节位置开始填充,长度为4字节,填充内容为chk.length
|
|
388
|
+
header.writeInt32LE(chk.length, 1);
|
|
389
|
+
// 从第六个开始填充chk的内容
|
|
390
|
+
chk.copy(header, 5);
|
|
391
|
+
|
|
392
|
+
// 将buffer进行hash计算并存储到chunk对象上
|
|
393
|
+
const signer = _crypto.default.createHash('SHA256');
|
|
394
|
+
signer.update(header);
|
|
395
|
+
chunk.sign = signer.digest();
|
|
396
|
+
}
|
|
397
|
+
static signChunk(chunks, privatekey, certificate) {
|
|
398
|
+
const {
|
|
399
|
+
sections
|
|
400
|
+
} = chunks;
|
|
401
|
+
|
|
402
|
+
// 二进制拼接每个块摘要
|
|
403
|
+
let length = 5;
|
|
404
|
+
if (sections.header.sign) {
|
|
405
|
+
length += sections.header.sign.length;
|
|
575
406
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
if (!Signer_1.default.getRemoteCryptoSignFunction()) {
|
|
579
|
-
// 使用默认
|
|
580
|
-
signature = Signer_1.default.defaultCryptoSignFunction(buffer, prikey);
|
|
581
|
-
}
|
|
582
|
-
else {
|
|
583
|
-
// 使用外部:传递原文件内容、证书内容
|
|
584
|
-
const remoteCryptoSignFunction = Signer_1.default.getRemoteCryptoSignFunction();
|
|
585
|
-
signature = remoteCryptoSignFunction(buffer, certpem);
|
|
586
|
-
}
|
|
587
|
-
return signature;
|
|
407
|
+
if (sections.central.sign) {
|
|
408
|
+
length += sections.central.sign.length;
|
|
588
409
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
* @param filehashs
|
|
592
|
-
* @param prikey
|
|
593
|
-
* @param certpem
|
|
594
|
-
*/
|
|
595
|
-
static signFiles(filehashs, prikey, certpem) {
|
|
596
|
-
const chunk = {
|
|
597
|
-
len: 8,
|
|
598
|
-
size: 4,
|
|
599
|
-
digests: [],
|
|
600
|
-
sign: null
|
|
601
|
-
};
|
|
602
|
-
// 生成hash块
|
|
603
|
-
filehashs.forEach((item) => {
|
|
604
|
-
// name hash
|
|
605
|
-
const namehash = CRC32_1.default.digest(item.name);
|
|
606
|
-
// 计算大小
|
|
607
|
-
const sum = 6 + item.hash.length;
|
|
608
|
-
const chk = Buffer.alloc(sum);
|
|
609
|
-
let offset = 0;
|
|
610
|
-
chk.writeInt32LE(namehash, offset);
|
|
611
|
-
offset += 4;
|
|
612
|
-
chk.writeInt16LE(item.hash.length, offset);
|
|
613
|
-
offset += 2;
|
|
614
|
-
item.hash.copy(chk, offset);
|
|
615
|
-
offset += item.hash.length;
|
|
616
|
-
chunk.digests.push(chk);
|
|
617
|
-
chunk.size += sum;
|
|
618
|
-
chunk.len += sum;
|
|
619
|
-
});
|
|
620
|
-
// 生成整体签名
|
|
621
|
-
SignUtil.signDigestChunk(chunk, prikey, certpem);
|
|
622
|
-
// 写入文件
|
|
623
|
-
return SignUtil.saveDigestChunk(chunk);
|
|
410
|
+
if (sections.footer.sign) {
|
|
411
|
+
length += sections.footer.sign.length;
|
|
624
412
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
413
|
+
const wholeData = Buffer.alloc(length);
|
|
414
|
+
let offset = 0;
|
|
415
|
+
wholeData.writeInt8(0x5a, 0);
|
|
416
|
+
wholeData.writeInt32LE(3, 1);
|
|
417
|
+
offset += 5;
|
|
418
|
+
function writeBuffer(buf) {
|
|
419
|
+
buf.copy(wholeData, offset);
|
|
420
|
+
offset += buf.length;
|
|
421
|
+
}
|
|
422
|
+
sections.header.sign && writeBuffer(sections.header.sign);
|
|
423
|
+
sections.central.sign && writeBuffer(sections.central.sign);
|
|
424
|
+
sections.footer.sign && writeBuffer(sections.footer.sign);
|
|
425
|
+
|
|
426
|
+
// 计算整体摘要
|
|
427
|
+
const signer = _crypto.default.createHash('SHA256');
|
|
428
|
+
signer.update(wholeData);
|
|
429
|
+
const signature = signer.digest();
|
|
430
|
+
|
|
431
|
+
// 生成sign block, 计算block总长度, 向buf中考入数据
|
|
432
|
+
const signchunk = SignUtil.makeSignChunk(chunks.options, signature, privatekey, certificate);
|
|
433
|
+
chunks.signchunk = SignUtil.saveSignChunk(signchunk);
|
|
434
|
+
}
|
|
435
|
+
static makeSignChunk(options, sign, privatekey, certificate) {
|
|
436
|
+
// 提取公钥
|
|
437
|
+
const cert = Buffer.from(_Base.default.unarmor(certificate));
|
|
438
|
+
const c = new _jsrsasign.default.X509();
|
|
439
|
+
c.readCertPEM(certificate.toString());
|
|
440
|
+
const pubKey = _jsrsasign.default.KEYUTIL.getPEM(c.getPublicKey());
|
|
441
|
+
// 摘要块
|
|
442
|
+
const digestBuf = Buffer.alloc(sign.length + 12);
|
|
443
|
+
digestBuf.writeInt32LE(sign.length + 8, 0);
|
|
444
|
+
digestBuf.writeInt32LE(0x0103, 4);
|
|
445
|
+
digestBuf.writeInt32LE(sign.length, 8);
|
|
446
|
+
sign.copy(digestBuf, 12);
|
|
447
|
+
const digestBlock = {
|
|
448
|
+
len: digestBuf.length,
|
|
449
|
+
buffer: digestBuf
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
// 证书块
|
|
453
|
+
const certBuf = Buffer.alloc(cert.length + 4);
|
|
454
|
+
certBuf.writeInt32LE(cert.length, 0);
|
|
455
|
+
cert.copy(certBuf, 4);
|
|
456
|
+
const certBlock = {
|
|
457
|
+
len: certBuf.length,
|
|
458
|
+
buffer: certBuf
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// 签名数据
|
|
462
|
+
const signdataBlock = {
|
|
463
|
+
len: 12,
|
|
464
|
+
digests: {
|
|
465
|
+
size: 0,
|
|
466
|
+
data: []
|
|
467
|
+
},
|
|
468
|
+
certs: {
|
|
469
|
+
size: 0,
|
|
470
|
+
data: []
|
|
471
|
+
},
|
|
472
|
+
additional: 0
|
|
473
|
+
};
|
|
474
|
+
signdataBlock.digests.data.push(digestBlock);
|
|
475
|
+
signdataBlock.digests.size += digestBlock.len;
|
|
476
|
+
signdataBlock.len += digestBlock.len;
|
|
477
|
+
signdataBlock.certs.data.push(certBlock);
|
|
478
|
+
signdataBlock.certs.size += certBlock.len;
|
|
479
|
+
signdataBlock.len += certBlock.len;
|
|
480
|
+
|
|
481
|
+
// 将public.pem转化为der
|
|
482
|
+
const pubbuf = Buffer.from(_Base.default.unarmor(pubKey));
|
|
483
|
+
const signBlock = {
|
|
484
|
+
len: 16 + pubbuf.length,
|
|
485
|
+
size: 12 + pubbuf.length,
|
|
486
|
+
signdata: {
|
|
487
|
+
size: 0,
|
|
488
|
+
buffer: null
|
|
489
|
+
},
|
|
490
|
+
signatures: {
|
|
491
|
+
size: 0,
|
|
492
|
+
data: []
|
|
493
|
+
},
|
|
494
|
+
pubkey: {
|
|
495
|
+
size: pubbuf.length,
|
|
496
|
+
buffer: pubbuf
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
signBlock.signdata.buffer = SignUtil.makeSignDataBuffer(signdataBlock);
|
|
500
|
+
signBlock.signdata.size = signdataBlock.len;
|
|
501
|
+
signBlock.size += signdataBlock.len;
|
|
502
|
+
signBlock.len += signdataBlock.len;
|
|
503
|
+
|
|
504
|
+
// 生成签名
|
|
505
|
+
const signature = SignUtil.callCryptoSignFunction(signBlock.signdata.buffer, privatekey, certificate);
|
|
506
|
+
const signatureBlock = {
|
|
507
|
+
len: signature.length + 12,
|
|
508
|
+
size: signature.length + 8,
|
|
509
|
+
id: 0x0103,
|
|
510
|
+
buffer: signature
|
|
511
|
+
};
|
|
512
|
+
signBlock.signatures.data.push(signatureBlock);
|
|
513
|
+
signBlock.signatures.size += signatureBlock.len;
|
|
514
|
+
signBlock.size += signatureBlock.len;
|
|
515
|
+
signBlock.len += signatureBlock.len;
|
|
516
|
+
const signBlocks = {
|
|
517
|
+
len: 4,
|
|
518
|
+
size: 0,
|
|
519
|
+
data: []
|
|
520
|
+
};
|
|
521
|
+
signBlocks.data.push(signBlock);
|
|
522
|
+
signBlocks.size += signBlock.len;
|
|
523
|
+
signBlocks.len += signBlock.len;
|
|
524
|
+
|
|
525
|
+
// 生成key-value
|
|
526
|
+
const kvBlock = {
|
|
527
|
+
len: signBlocks.len + 12,
|
|
528
|
+
size: signBlocks.len + 4,
|
|
529
|
+
id: 0x01000101,
|
|
530
|
+
value: signBlocks
|
|
531
|
+
};
|
|
532
|
+
const signchunk = {
|
|
533
|
+
len: 32,
|
|
534
|
+
size: 24,
|
|
535
|
+
data: []
|
|
536
|
+
};
|
|
537
|
+
signchunk.data.push(kvBlock);
|
|
538
|
+
signchunk.size += kvBlock.len;
|
|
539
|
+
signchunk.len += kvBlock.len;
|
|
540
|
+
|
|
541
|
+
// 添加文件列表hash kvblock
|
|
542
|
+
if (options.files) {
|
|
543
|
+
const filehashChunk = SignUtil.signFiles(options.files, privatekey, certificate);
|
|
544
|
+
if (filehashChunk) {
|
|
545
|
+
const filesignBlocks = {
|
|
546
|
+
len: 4,
|
|
547
|
+
size: 0,
|
|
548
|
+
data: []
|
|
549
|
+
};
|
|
550
|
+
filesignBlocks.data.push(filehashChunk);
|
|
551
|
+
filesignBlocks.size += filehashChunk.length;
|
|
552
|
+
filesignBlocks.len += filehashChunk.length;
|
|
553
|
+
const filekvBlock = {
|
|
554
|
+
len: filesignBlocks.len + 12,
|
|
555
|
+
size: filesignBlocks.len + 4,
|
|
556
|
+
id: 0x01000201,
|
|
557
|
+
value: filesignBlocks
|
|
642
558
|
};
|
|
643
|
-
|
|
559
|
+
signchunk.data.push(filekvBlock);
|
|
560
|
+
signchunk.size += filekvBlock.len;
|
|
561
|
+
signchunk.len += filekvBlock.len;
|
|
562
|
+
}
|
|
644
563
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
564
|
+
return signchunk;
|
|
565
|
+
}
|
|
566
|
+
static makeSignDataBuffer(block) {
|
|
567
|
+
const buffer = Buffer.alloc(block.len);
|
|
568
|
+
let offset = 0;
|
|
569
|
+
buffer.writeInt32LE(block.digests.size, offset);
|
|
570
|
+
offset += 4;
|
|
571
|
+
block.digests.data.forEach(item => {
|
|
572
|
+
item.buffer.copy(buffer, offset);
|
|
573
|
+
offset += item.len;
|
|
574
|
+
});
|
|
575
|
+
buffer.writeInt32LE(block.certs.size, offset);
|
|
576
|
+
offset += 4;
|
|
577
|
+
block.certs.data.forEach(item => {
|
|
578
|
+
item.buffer.copy(buffer, offset);
|
|
579
|
+
offset += item.len;
|
|
580
|
+
});
|
|
581
|
+
buffer.writeInt32LE(block.additional, offset);
|
|
582
|
+
return buffer;
|
|
583
|
+
}
|
|
584
|
+
static callCryptoSignFunction(buffer, prikey, certpem) {
|
|
585
|
+
let signature = null;
|
|
586
|
+
if (!_Signer.default.getRemoteCryptoSignFunction()) {
|
|
587
|
+
// 使用默认
|
|
588
|
+
signature = _Signer.default.defaultCryptoSignFunction(buffer, prikey);
|
|
589
|
+
} else {
|
|
590
|
+
// 使用外部:传递原文件内容、证书内容
|
|
591
|
+
const remoteCryptoSignFunction = _Signer.default.getRemoteCryptoSignFunction();
|
|
592
|
+
signature = remoteCryptoSignFunction(buffer, certpem);
|
|
664
593
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
594
|
+
return signature;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* 加签名文件
|
|
598
|
+
* @param filehashs
|
|
599
|
+
* @param prikey
|
|
600
|
+
* @param certpem
|
|
601
|
+
*/
|
|
602
|
+
static signFiles(filehashs, prikey, certpem) {
|
|
603
|
+
const chunk = {
|
|
604
|
+
len: 8,
|
|
605
|
+
size: 4,
|
|
606
|
+
digests: [],
|
|
607
|
+
sign: null
|
|
608
|
+
};
|
|
609
|
+
// 生成hash块
|
|
610
|
+
filehashs.forEach(item => {
|
|
611
|
+
// name hash
|
|
612
|
+
const namehash = _CRC.default.digest(item.name);
|
|
613
|
+
|
|
614
|
+
// 计算大小
|
|
615
|
+
const sum = 6 + item.hash.length;
|
|
616
|
+
const chk = Buffer.alloc(sum);
|
|
617
|
+
let offset = 0;
|
|
618
|
+
chk.writeInt32LE(namehash, offset);
|
|
619
|
+
offset += 4;
|
|
620
|
+
chk.writeInt16LE(item.hash.length, offset);
|
|
621
|
+
offset += 2;
|
|
622
|
+
item.hash.copy(chk, offset);
|
|
623
|
+
offset += item.hash.length;
|
|
624
|
+
chunk.digests.push(chk);
|
|
625
|
+
chunk.size += sum;
|
|
626
|
+
chunk.len += sum;
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
// 生成整体签名
|
|
630
|
+
SignUtil.signDigestChunk(chunk, prikey, certpem);
|
|
631
|
+
|
|
632
|
+
// 写入文件
|
|
633
|
+
return SignUtil.saveDigestChunk(chunk);
|
|
634
|
+
}
|
|
635
|
+
static signDigestChunk(chunk, prikey, certpem) {
|
|
636
|
+
const buf = Buffer.alloc(chunk.size);
|
|
637
|
+
let offset = 0;
|
|
638
|
+
buf.writeInt32LE(0x0103, offset);
|
|
639
|
+
offset += 4;
|
|
640
|
+
chunk.digests.forEach(chk => {
|
|
641
|
+
chk.copy(buf, offset);
|
|
642
|
+
offset += chk.length;
|
|
643
|
+
});
|
|
644
|
+
chunk.digests = buf.slice();
|
|
645
|
+
|
|
646
|
+
// 生成签名
|
|
647
|
+
const signature = SignUtil.callCryptoSignFunction(buf, prikey, certpem);
|
|
648
|
+
chunk.sign = {
|
|
649
|
+
len: 12 + signature.length,
|
|
650
|
+
size: 8 + signature.length,
|
|
651
|
+
id: 0x0103,
|
|
652
|
+
data: signature
|
|
653
|
+
};
|
|
654
|
+
chunk.len += chunk.sign.len;
|
|
655
|
+
}
|
|
656
|
+
static saveDigestChunk(chunk) {
|
|
657
|
+
// 创建新buffer
|
|
658
|
+
const newBuffer = Buffer.alloc(chunk.len);
|
|
659
|
+
let offset = 0;
|
|
660
|
+
newBuffer.writeInt32LE(chunk.size, offset);
|
|
661
|
+
offset += 4;
|
|
662
|
+
|
|
663
|
+
// 文件hash列表
|
|
664
|
+
chunk.digests.copy(newBuffer, offset);
|
|
665
|
+
offset += chunk.digests.length;
|
|
666
|
+
|
|
667
|
+
// 写入签名
|
|
668
|
+
newBuffer.writeInt32LE(chunk.sign.size, offset);
|
|
669
|
+
offset += 4;
|
|
670
|
+
newBuffer.writeInt32LE(chunk.sign.id, offset);
|
|
671
|
+
offset += 4;
|
|
672
|
+
newBuffer.writeInt32LE(chunk.sign.data.length, offset);
|
|
673
|
+
offset += 4;
|
|
674
|
+
chunk.sign.data.copy(newBuffer, offset);
|
|
675
|
+
offset += chunk.sign.data.length;
|
|
676
|
+
return newBuffer;
|
|
677
|
+
}
|
|
678
|
+
static SigMagic = 'RPK Sig Block 42';
|
|
679
|
+
static saveSignChunk(signchunk) {
|
|
680
|
+
const buffer = Buffer.alloc(signchunk.len);
|
|
681
|
+
let offset = 0;
|
|
682
|
+
|
|
683
|
+
// 大小
|
|
684
|
+
buffer.writeInt32LE(signchunk.size, offset);
|
|
685
|
+
offset += 4;
|
|
686
|
+
buffer.writeInt32LE(0, offset);
|
|
687
|
+
offset += 4;
|
|
688
|
+
|
|
689
|
+
// key-value
|
|
690
|
+
signchunk.data.forEach(kv => {
|
|
691
|
+
buffer.writeInt32LE(kv.size, offset);
|
|
692
|
+
offset += 4;
|
|
693
|
+
buffer.writeInt32LE(0, offset);
|
|
694
|
+
offset += 4;
|
|
695
|
+
buffer.writeInt32LE(kv.id, offset);
|
|
696
|
+
offset += 4;
|
|
697
|
+
|
|
698
|
+
// value
|
|
699
|
+
buffer.writeInt32LE(kv.value.size, offset);
|
|
700
|
+
offset += 4;
|
|
701
|
+
if (kv.id === 0x01000101) {
|
|
702
|
+
// sign blocks
|
|
703
|
+
kv.value.data.forEach(block => {
|
|
704
|
+
buffer.writeInt32LE(block.size, offset);
|
|
705
|
+
offset += 4;
|
|
706
|
+
|
|
707
|
+
// signdata
|
|
708
|
+
buffer.writeInt32LE(block.signdata.size, offset);
|
|
709
|
+
offset += 4;
|
|
710
|
+
block.signdata.buffer.copy(buffer, offset);
|
|
711
|
+
offset += block.signdata.buffer.length;
|
|
712
|
+
|
|
713
|
+
// signature
|
|
714
|
+
buffer.writeInt32LE(block.signatures.size, offset);
|
|
715
|
+
offset += 4;
|
|
716
|
+
block.signatures.data.forEach(signature => {
|
|
717
|
+
buffer.writeInt32LE(signature.size, offset);
|
|
678
718
|
offset += 4;
|
|
679
|
-
buffer.writeInt32LE(
|
|
719
|
+
buffer.writeInt32LE(signature.id, offset);
|
|
680
720
|
offset += 4;
|
|
681
|
-
|
|
682
|
-
buffer.writeInt32LE(kv.value.size, offset);
|
|
721
|
+
buffer.writeInt32LE(signature.buffer.length, offset);
|
|
683
722
|
offset += 4;
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
offset += block.signdata.buffer.length;
|
|
694
|
-
// signature
|
|
695
|
-
buffer.writeInt32LE(block.signatures.size, offset);
|
|
696
|
-
offset += 4;
|
|
697
|
-
block.signatures.data.forEach((signature) => {
|
|
698
|
-
buffer.writeInt32LE(signature.size, offset);
|
|
699
|
-
offset += 4;
|
|
700
|
-
buffer.writeInt32LE(signature.id, offset);
|
|
701
|
-
offset += 4;
|
|
702
|
-
buffer.writeInt32LE(signature.buffer.length, offset);
|
|
703
|
-
offset += 4;
|
|
704
|
-
signature.buffer.copy(buffer, offset);
|
|
705
|
-
offset += signature.buffer.length;
|
|
706
|
-
});
|
|
707
|
-
// pubkey
|
|
708
|
-
buffer.writeInt32LE(block.pubkey.size, offset);
|
|
709
|
-
offset += 4;
|
|
710
|
-
block.pubkey.buffer.copy(buffer, offset);
|
|
711
|
-
offset += block.pubkey.buffer.length;
|
|
712
|
-
});
|
|
713
|
-
}
|
|
714
|
-
else if (kv.id === 0x01000201) {
|
|
715
|
-
// files blocks
|
|
716
|
-
kv.value.data.forEach((block) => {
|
|
717
|
-
block.copy(buffer, offset);
|
|
718
|
-
offset += block.length;
|
|
719
|
-
});
|
|
720
|
-
}
|
|
723
|
+
signature.buffer.copy(buffer, offset);
|
|
724
|
+
offset += signature.buffer.length;
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
// pubkey
|
|
728
|
+
buffer.writeInt32LE(block.pubkey.size, offset);
|
|
729
|
+
offset += 4;
|
|
730
|
+
block.pubkey.buffer.copy(buffer, offset);
|
|
731
|
+
offset += block.pubkey.buffer.length;
|
|
721
732
|
});
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
733
|
+
} else if (kv.id === 0x01000201) {
|
|
734
|
+
// files blocks
|
|
735
|
+
kv.value.data.forEach(block => {
|
|
736
|
+
block.copy(buffer, offset);
|
|
737
|
+
offset += block.length;
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
// 大小
|
|
743
|
+
buffer.writeInt32LE(signchunk.size, offset);
|
|
744
|
+
offset += 4;
|
|
745
|
+
buffer.writeInt32LE(0, offset);
|
|
746
|
+
offset += 4;
|
|
747
|
+
|
|
748
|
+
// 魔法值
|
|
749
|
+
const magic = Buffer.from(SignUtil.SigMagic);
|
|
750
|
+
magic.copy(buffer, offset);
|
|
751
|
+
return buffer;
|
|
752
|
+
}
|
|
753
|
+
static saveChunk(buf, chunks) {
|
|
754
|
+
// 创建新buffer
|
|
755
|
+
const newBuffer = Buffer.alloc(buf.length + chunks.signchunk.length);
|
|
756
|
+
let offset = 0;
|
|
757
|
+
const sections = chunks.sections;
|
|
758
|
+
|
|
759
|
+
// 拷贝header
|
|
760
|
+
buf.copy(newBuffer, offset, sections.header.startIndex, sections.header.startIndex + sections.header.len);
|
|
761
|
+
offset += sections.header.len;
|
|
762
|
+
|
|
763
|
+
// 拷贝signblock
|
|
764
|
+
chunks.signchunk.copy(newBuffer, offset);
|
|
765
|
+
offset += chunks.signchunk.length;
|
|
766
|
+
|
|
767
|
+
// 拷贝central
|
|
768
|
+
buf.copy(newBuffer, offset, sections.central.startIndex, sections.central.startIndex + sections.central.len);
|
|
769
|
+
offset += sections.central.len;
|
|
770
|
+
|
|
771
|
+
// 修改eocd
|
|
772
|
+
buf.writeInt32LE(sections.central.startIndex + chunks.signchunk.length, sections.footer.startIndex + 16);
|
|
773
|
+
// 拷贝eocd
|
|
774
|
+
buf.copy(newBuffer, offset, sections.footer.startIndex, sections.footer.startIndex + sections.footer.len);
|
|
775
|
+
offset += sections.footer.len;
|
|
776
|
+
return newBuffer;
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* 过滤掉文件夹和META文件
|
|
780
|
+
* @param item
|
|
781
|
+
* @returns
|
|
782
|
+
*/
|
|
783
|
+
static fileFilter(item) {
|
|
784
|
+
const path = item.path;
|
|
785
|
+
return !path.endsWith('/') && path !== _ZipUtil.default.CERT_PATH;
|
|
786
|
+
}
|
|
762
787
|
}
|
|
763
|
-
|
|
764
|
-
exports.default = SignUtil;
|
|
788
|
+
var _default = exports.default = SignUtil;
|