fuse-core-express 1.0.2 → 1.0.3
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 +226 -480
- package/decryptor.js +106 -0
- package/{index.mjs → index.js} +167 -22
- package/keys/README.md +47 -0
- package/keys/build-version.json +5 -0
- package/keys/recipient-keys-1.0.3.json +7 -0
- package/keys/signer-keys-1.0.3.json +5 -0
- package/package.json +18 -68
- package/secure-package.vxz +0 -0
- package/CHANGELOG.md +0 -128
- package/LICENSE +0 -21
- package/decrypt-loader.mjs +0 -301
- package/private-1.0.2.pem +0 -28
package/decryptor.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
|
|
2
|
+
// FuseCore Secure Decryptor - 二进制格式
|
|
3
|
+
// 使用接收者私钥解密,使用签名者公钥验证
|
|
4
|
+
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const { createGunzip } = require('zlib');
|
|
8
|
+
const { promisify } = require('util');
|
|
9
|
+
|
|
10
|
+
class SecureDecryptor {
|
|
11
|
+
constructor(recipientPrivateKey, signerPublicKey) {
|
|
12
|
+
this.recipientPrivateKey = recipientPrivateKey;
|
|
13
|
+
this.signerPublicKey = signerPublicKey;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async decompressData(compressedData) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
const gunzip = createGunzip();
|
|
19
|
+
const chunks = [];
|
|
20
|
+
|
|
21
|
+
gunzip.on('data', chunk => chunks.push(chunk));
|
|
22
|
+
gunzip.on('end', () => resolve(Buffer.concat(chunks)));
|
|
23
|
+
gunzip.on('error', reject);
|
|
24
|
+
|
|
25
|
+
gunzip.write(compressedData);
|
|
26
|
+
gunzip.end();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async decrypt(packagePath) {
|
|
31
|
+
console.log('🔓 Starting decryption process...');
|
|
32
|
+
|
|
33
|
+
// 1. 读取二进制加密包
|
|
34
|
+
const binaryData = fs.readFileSync(packagePath);
|
|
35
|
+
|
|
36
|
+
// 2. 解析二进制格式
|
|
37
|
+
// 格式: [元数据长度(4字节)][元数据][签名长度(4字节)][签名][IV长度(4字节)][IV][加密密钥长度(4字节)][加密密钥][认证标签长度(4字节)][认证标签][密文长度(4字节)][密文]
|
|
38
|
+
|
|
39
|
+
let offset = 0;
|
|
40
|
+
|
|
41
|
+
// 读取元数据
|
|
42
|
+
const metaLength = binaryData.readUInt32BE(offset);
|
|
43
|
+
offset += 4;
|
|
44
|
+
const metaBuf = binaryData.slice(offset, offset + metaLength);
|
|
45
|
+
offset += metaLength;
|
|
46
|
+
|
|
47
|
+
// 读取签名
|
|
48
|
+
const signatureLength = binaryData.readUInt32BE(offset);
|
|
49
|
+
offset += 4;
|
|
50
|
+
const signature = binaryData.slice(offset, offset + signatureLength);
|
|
51
|
+
offset += signatureLength;
|
|
52
|
+
|
|
53
|
+
// 读取IV
|
|
54
|
+
const ivLength = binaryData.readUInt32BE(offset);
|
|
55
|
+
offset += 4;
|
|
56
|
+
const iv = binaryData.slice(offset, offset + ivLength);
|
|
57
|
+
offset += ivLength;
|
|
58
|
+
|
|
59
|
+
// 读取加密密钥
|
|
60
|
+
const encKeyLength = binaryData.readUInt32BE(offset);
|
|
61
|
+
offset += 4;
|
|
62
|
+
const encKey = binaryData.slice(offset, offset + encKeyLength);
|
|
63
|
+
offset += encKeyLength;
|
|
64
|
+
|
|
65
|
+
// 读取认证标签
|
|
66
|
+
const authTagLength = binaryData.readUInt32BE(offset);
|
|
67
|
+
offset += 4;
|
|
68
|
+
const authTag = binaryData.slice(offset, offset + authTagLength);
|
|
69
|
+
offset += authTagLength;
|
|
70
|
+
|
|
71
|
+
// 读取密文
|
|
72
|
+
const ciphertextLength = binaryData.readUInt32BE(offset);
|
|
73
|
+
offset += 4;
|
|
74
|
+
const ciphertext = binaryData.slice(offset, offset + ciphertextLength);
|
|
75
|
+
|
|
76
|
+
// 3. 解密AES密钥
|
|
77
|
+
const aesKey = crypto.privateDecrypt({
|
|
78
|
+
key: this.recipientPrivateKey,
|
|
79
|
+
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
|
80
|
+
}, encKey);
|
|
81
|
+
|
|
82
|
+
// 4. 验证签名(在解密之前)
|
|
83
|
+
const toVerify = Buffer.concat([ciphertext, authTag, encKey, iv, metaBuf]);
|
|
84
|
+
const isValid = crypto.verify('sha256', toVerify, {
|
|
85
|
+
key: this.signerPublicKey,
|
|
86
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
87
|
+
}, signature);
|
|
88
|
+
|
|
89
|
+
if (!isValid) {
|
|
90
|
+
throw new Error('❌ Signature verification failed');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 5. 使用IV解密数据
|
|
94
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', aesKey, iv);
|
|
95
|
+
decipher.setAuthTag(authTag);
|
|
96
|
+
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
97
|
+
|
|
98
|
+
// 6. 解压缩
|
|
99
|
+
const decompressed = await this.decompressData(decrypted);
|
|
100
|
+
|
|
101
|
+
console.log('✅ Decryption completed successfully');
|
|
102
|
+
return JSON.parse(decompressed.toString());
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = SecureDecryptor;
|
package/{index.mjs → index.js}
RENAMED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* FuseCore Encrypted Entry Point
|
|
3
3
|
* 加密版本入口文件 - 解密后代理到原始API
|
|
4
4
|
*/
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
5
|
+
import crypto from 'crypto';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { createGunzip } from 'zlib';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
10
11
|
|
|
11
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
12
13
|
const __dirname = path.dirname(__filename);
|
|
@@ -26,21 +27,7 @@ const TEMP_DIR = path.join(__dirname, '.temp_fusecore');
|
|
|
26
27
|
function cleanupTempFiles() {
|
|
27
28
|
if (fs.existsSync(TEMP_DIR)) {
|
|
28
29
|
try {
|
|
29
|
-
|
|
30
|
-
const files = fs.readdirSync(dir);
|
|
31
|
-
for (const file of files) {
|
|
32
|
-
const filePath = path.join(dir, file);
|
|
33
|
-
const stat = fs.statSync(filePath);
|
|
34
|
-
if (stat.isDirectory()) {
|
|
35
|
-
cleanupDir(filePath);
|
|
36
|
-
fs.rmdirSync(filePath);
|
|
37
|
-
} else {
|
|
38
|
-
fs.unlinkSync(filePath);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
cleanupDir(TEMP_DIR);
|
|
43
|
-
fs.rmdirSync(TEMP_DIR);
|
|
30
|
+
fs.rmSync(TEMP_DIR, { recursive: true, force: true });
|
|
44
31
|
console.log("🧹 Temporary files cleaned up");
|
|
45
32
|
} catch (error) {
|
|
46
33
|
console.warn("⚠️ Failed to cleanup temporary files:", error.message);
|
|
@@ -57,6 +44,164 @@ function resetState() {
|
|
|
57
44
|
}
|
|
58
45
|
}
|
|
59
46
|
|
|
47
|
+
// 解密器类
|
|
48
|
+
class SecureDecryptor {
|
|
49
|
+
constructor(privateKeyPath) {
|
|
50
|
+
this.privateKeyPath = privateKeyPath;
|
|
51
|
+
this.loadedFiles = [];
|
|
52
|
+
this.memoryCache = new Map();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async loadBundle(bundlePath) {
|
|
56
|
+
console.log('🔓 Loading encrypted bundle...');
|
|
57
|
+
|
|
58
|
+
// 如果bundlePath是相对路径,则相对于当前目录
|
|
59
|
+
const fullBundlePath = path.resolve(bundlePath);
|
|
60
|
+
|
|
61
|
+
if (!fs.existsSync(fullBundlePath)) {
|
|
62
|
+
throw new Error(`Bundle file not found: ${fullBundlePath}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 解密包
|
|
66
|
+
const bundle = await this.decryptPackage(fullBundlePath);
|
|
67
|
+
|
|
68
|
+
// 缓存所有文件
|
|
69
|
+
for (const [filePath, fileData] of Object.entries(bundle)) {
|
|
70
|
+
this.memoryCache.set(filePath, fileData);
|
|
71
|
+
this.loadedFiles.push(filePath);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(`📦 Loaded ${this.loadedFiles.length} files from bundle`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async loadKeysFromPath(privateKeyPath) {
|
|
78
|
+
// 从私钥路径推断其他密钥路径
|
|
79
|
+
const keyDir = path.dirname(privateKeyPath);
|
|
80
|
+
|
|
81
|
+
// 尝试加载私钥和公钥
|
|
82
|
+
if (!fs.existsSync(privateKeyPath)) {
|
|
83
|
+
throw new Error(`Private key not found: ${privateKeyPath}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 解析私钥JSON文件
|
|
87
|
+
const recipientData = JSON.parse(fs.readFileSync(privateKeyPath, 'utf8'));
|
|
88
|
+
const recipientPrivateKey = recipientData.privateKey;
|
|
89
|
+
|
|
90
|
+
// 推断对应的公钥文件路径
|
|
91
|
+
const basename = path.basename(privateKeyPath, path.extname(privateKeyPath));
|
|
92
|
+
const publicKeyPath = path.join(keyDir, basename.replace('recipient-keys', 'signer-keys') + '.json');
|
|
93
|
+
|
|
94
|
+
if (!fs.existsSync(publicKeyPath)) {
|
|
95
|
+
throw new Error(`Signer public key not found: ${publicKeyPath}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const signerData = JSON.parse(fs.readFileSync(publicKeyPath, 'utf8'));
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
recipientPrivateKey,
|
|
102
|
+
signerPublicKey: signerData.publicKey
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async decryptPackage(packagePath) {
|
|
107
|
+
console.log('🔓 Starting decryption process...');
|
|
108
|
+
|
|
109
|
+
// 读取加密包
|
|
110
|
+
const binaryData = fs.readFileSync(packagePath);
|
|
111
|
+
|
|
112
|
+
// 解析二进制格式
|
|
113
|
+
let offset = 0;
|
|
114
|
+
|
|
115
|
+
// 读取元数据
|
|
116
|
+
const metaLength = binaryData.readUInt32BE(offset);
|
|
117
|
+
offset += 4;
|
|
118
|
+
const metaBuf = binaryData.slice(offset, offset + metaLength);
|
|
119
|
+
offset += metaLength;
|
|
120
|
+
|
|
121
|
+
// 读取签名
|
|
122
|
+
const signatureLength = binaryData.readUInt32BE(offset);
|
|
123
|
+
offset += 4;
|
|
124
|
+
const signature = binaryData.slice(offset, offset + signatureLength);
|
|
125
|
+
offset += signatureLength;
|
|
126
|
+
|
|
127
|
+
// 读取IV
|
|
128
|
+
const ivLength = binaryData.readUInt32BE(offset);
|
|
129
|
+
offset += 4;
|
|
130
|
+
const iv = binaryData.slice(offset, offset + ivLength);
|
|
131
|
+
offset += ivLength;
|
|
132
|
+
|
|
133
|
+
// 读取加密密钥
|
|
134
|
+
const encKeyLength = binaryData.readUInt32BE(offset);
|
|
135
|
+
offset += 4;
|
|
136
|
+
const encKey = binaryData.slice(offset, offset + encKeyLength);
|
|
137
|
+
offset += encKeyLength;
|
|
138
|
+
|
|
139
|
+
// 读取认证标签
|
|
140
|
+
const authTagLength = binaryData.readUInt32BE(offset);
|
|
141
|
+
offset += 4;
|
|
142
|
+
const authTag = binaryData.slice(offset, offset + authTagLength);
|
|
143
|
+
offset += authTagLength;
|
|
144
|
+
|
|
145
|
+
// 读取密文
|
|
146
|
+
const ciphertextLength = binaryData.readUInt32BE(offset);
|
|
147
|
+
offset += 4;
|
|
148
|
+
const ciphertext = binaryData.slice(offset, offset + ciphertextLength);
|
|
149
|
+
|
|
150
|
+
// 加载密钥
|
|
151
|
+
const keys = await this.loadKeysFromPath(this.privateKeyPath);
|
|
152
|
+
|
|
153
|
+
// 解密AES密钥
|
|
154
|
+
const aesKey = crypto.privateDecrypt({
|
|
155
|
+
key: keys.recipientPrivateKey,
|
|
156
|
+
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
|
157
|
+
}, encKey);
|
|
158
|
+
|
|
159
|
+
// 验证签名
|
|
160
|
+
const toVerify = Buffer.concat([ciphertext, authTag, encKey, iv, metaBuf]);
|
|
161
|
+
const isValid = crypto.verify('sha256', toVerify, {
|
|
162
|
+
key: keys.signerPublicKey,
|
|
163
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
164
|
+
}, signature);
|
|
165
|
+
|
|
166
|
+
if (!isValid) {
|
|
167
|
+
throw new Error('❌ Signature verification failed');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 解密数据
|
|
171
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', aesKey, iv);
|
|
172
|
+
decipher.setAuthTag(authTag);
|
|
173
|
+
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
174
|
+
|
|
175
|
+
// 解压缩
|
|
176
|
+
const decompressed = await this.decompressData(decrypted);
|
|
177
|
+
|
|
178
|
+
console.log('✅ Decryption completed successfully');
|
|
179
|
+
return JSON.parse(decompressed.toString());
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async decompressData(compressedData) {
|
|
183
|
+
return new Promise((resolve, reject) => {
|
|
184
|
+
const gunzip = createGunzip();
|
|
185
|
+
const chunks = [];
|
|
186
|
+
|
|
187
|
+
gunzip.on('data', chunk => chunks.push(chunk));
|
|
188
|
+
gunzip.on('end', () => resolve(Buffer.concat(chunks)));
|
|
189
|
+
gunzip.on('error', reject);
|
|
190
|
+
|
|
191
|
+
gunzip.write(compressedData);
|
|
192
|
+
gunzip.end();
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
getLoadedFiles() {
|
|
197
|
+
return this.loadedFiles;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// 创建解密加载器
|
|
202
|
+
function createDecryptLoader(privateKeyPath) {
|
|
203
|
+
return new SecureDecryptor(privateKeyPath);
|
|
204
|
+
}
|
|
60
205
|
|
|
61
206
|
// 核心方法
|
|
62
207
|
const initDecryption = async function(privateKeyPath) {
|
|
@@ -75,7 +220,7 @@ const initDecryption = async function(privateKeyPath) {
|
|
|
75
220
|
|
|
76
221
|
try {
|
|
77
222
|
// 1. 加载并解密bundle
|
|
78
|
-
await state.decryptLoader.loadBundle(path.resolve(__dirname, '
|
|
223
|
+
await state.decryptLoader.loadBundle(path.resolve(__dirname, 'secure-package.vxz'));
|
|
79
224
|
|
|
80
225
|
// 2. 创建临时目录
|
|
81
226
|
if (!fs.existsSync(TEMP_DIR)) {
|
|
@@ -215,4 +360,4 @@ const FuseCore = new Proxy({}, {
|
|
|
215
360
|
}
|
|
216
361
|
});
|
|
217
362
|
|
|
218
|
-
export default FuseCore;
|
|
363
|
+
export default FuseCore;
|
package/keys/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# 密钥使用说明
|
|
2
|
+
|
|
3
|
+
这个目录包含了使用加密版本 FuseCore 所需的密钥文件。
|
|
4
|
+
|
|
5
|
+
## 文件说明
|
|
6
|
+
|
|
7
|
+
- `build-version.json`: 构建版本信息
|
|
8
|
+
- `recipient-keys-1.0.3.json`: 接收者密钥(包含解密所需的私钥)
|
|
9
|
+
- `signer-keys-1.0.3.json`: 签名者公钥(用于验证签名)
|
|
10
|
+
|
|
11
|
+
## 使用方法
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import FuseCore from 'fuse-core-express';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import { fileURLToPath } from 'url';
|
|
17
|
+
|
|
18
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
|
|
20
|
+
// 初始化解密,使用包内的密钥文件
|
|
21
|
+
const privateKeyPath = path.join(__dirname, 'keys/recipient-keys-1.0.3.json');
|
|
22
|
+
await FuseCore.initDecryption(privateKeyPath);
|
|
23
|
+
|
|
24
|
+
// 初始化 FuseCore
|
|
25
|
+
await FuseCore.init({
|
|
26
|
+
// 您的配置
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 安全注意事项
|
|
31
|
+
|
|
32
|
+
⚠️ **重要**: 在生产环境中:
|
|
33
|
+
- 不要将接收者私钥暴露在客户端
|
|
34
|
+
- 考虑使用环境变量或密钥管理服务
|
|
35
|
+
- 定期轮换密钥
|
|
36
|
+
- 监控密钥使用情况
|
|
37
|
+
|
|
38
|
+
## 环境变量方式(推荐)
|
|
39
|
+
|
|
40
|
+
您也可以使用环境变量来提供密钥:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
export FUSECORE_RECIPIENT_PRIVATE_KEY="$(cat path/to/recipient-private-key.pem)"
|
|
44
|
+
export FUSECORE_SIGNER_PUBLIC_KEY="$(cat path/to/signer-public-key.pem)"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
当设置了这些环境变量时,`initDecryption()` 会自动使用它们,无需传递文件路径。
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuFs1oGSJB9Pj/yRv0/cf\nJRfTcGP1qO2aBQrVwW35ajqXpAQPcFue1mZo1aKSk6323YdeJmbOqg8+QMoGTl/0\nmmf10+hajD8QxhUAJKMAh/o6/cyZB3eyvUkic1UsjSAGb4/W62rcKyc7nw3WZ0n4\n+CPLTemgj9EE6+aBVPAYZHL3VCuNB8qtlAUxwapPS8IPLLsARPSFJdpjO5Ym55Ae\nAqx9918VSy8vMU3hgxqnB6JVvTK5pZFwJCNqqatuLYORXS2k3TORv9ZfLQnhHE9d\nrI3zqoJVAH/4Yv128vY8Jl2tFkCq/Od6Nyhe3R6JMsNrnolunZvl0jUTvP5TrRyz\nswIDAQAB\n-----END PUBLIC KEY-----\n",
|
|
3
|
+
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4WzWgZIkH0+P/\nJG/T9x8lF9NwY/Wo7ZoFCtXBbflqOpekBA9wW57WZmjVopKTrfbdh14mZs6qDz5A\nygZOX/SaZ/XT6FqMPxDGFQAkowCH+jr9zJkHd7K9SSJzVSyNIAZvj9bratwrJzuf\nDdZnSfj4I8tN6aCP0QTr5oFU8BhkcvdUK40Hyq2UBTHBqk9Lwg8suwBE9IUl2mM7\nlibnkB4CrH33XxVLLy8xTeGDGqcHolW9MrmlkXAkI2qpq24tg5FdLaTdM5G/1l8t\nCeEcT12sjfOqglUAf/hi/Xby9jwmXa0WQKr853o3KF7dHokyw2ueiW6dm+XSNRO8\n/lOtHLOzAgMBAAECggEATVlveZlU6STdD0rRZKTVu3FwtEIsazEtoxn1r4+dyxVE\nVHujoqe+UARtzdzFFRMzdaT7Oq993FpC61oYJUAbV8FwofVmMFuxhPqAsd52NZcm\nsx/pwPlW1BZgTvWYmKmsKZi3OtT+BVkTqdtbbsDZpfsWrNzuEglHwFZZQzLteQ8O\n1IKVN7xQOJUL6sww4L7w+IX67A3uPSH9+Dh4cM7aDBTq7hEkUQemHC3IA+PPKd9r\n0pmM2xGARQLvlEN3dRAAIol267SFlVx9dpbKWl4uJr/l/ftULZA0HT3cxrIKE8ko\n7RdxwDmtJZ97Wg4gZYOK1+IDynP+bdV0AWWpwXdheQKBgQD+9/Qfyb8xBUSFONZV\n3Vdttq14R7flVBrnm9KN3be0kc7X3CcDK1Y6WTFVTUmg4cQttC1y3c8B7dBeGj77\nxAHncbTKSuMjtcznNjMfiqI1KU+/mMz/KK0hLmTV3A/CjNru/miGwNVXetvF1omi\nrNEwYVQgVsm28HfsshINyVSjhwKBgQC5GiEo1Cf1Dy7dHbbYlfoS+/hKa9B3T3qT\n7kgJh6ZtYTJ94wXGJv9695lsHxBxp5lDsgOiN+o/J3asYCyluXnejdzZcYUVyjAF\n/TknujUny+On3C56GP2kZ8YqMbcR7uj9I4stJcKFgPEBUmOu3Ifg9H0BhQ+j5vG/\nLjYZyV4RdQKBgQDqKJYPS51HS+st3pEZsnnEzOxrdpIxDxjWdIjeuS0prG8mV42M\nn5RFafygtqZUFoOw5bSHtaWTw/CFO910IwMMp6S91CDefux7u48f/JYT9KjE8XPz\nMkwuGQmKTtw6dFns+8DLYPWNrcuA2hL1T3me0QQN3ybJ1/aLbs6d0rTkqQKBgQC2\n5uDZLToGZmhSSWhBf4DJfX0MXJhzLG/c+NjpwcZr0l1IEynDcQmFgl9xfQiMpaVG\nRQJeKo4mtWIIVkgHwcxwYxFVM1zj+ROW926gmNipaEidt22dbFBFQd2IF/PjnoVO\njO6bP/KEZLLAMZ8aTANf/3X+KHMZ67v4wzrmJBn1eQKBgQCDLn52JQ1ZjLV+5U5I\nedbNRru2ugcwgJDZV96s8F29uejxv1ixasfdDBBL7s6+Q0/DWSqPCY/4yWNQ0pfG\nl9fPjfb8tKM1tEwDj44lrLI+JMBAdavUVDbWFfzD1StDlgWlbvbTIUAZ47oxeZTP\nEJUSV9t0TCjrj85UFxzJzv9Yhg==\n-----END PRIVATE KEY-----\n",
|
|
4
|
+
"owner": "recipient",
|
|
5
|
+
"version": "1.0.3",
|
|
6
|
+
"timestamp": "2025-08-01T15:58:34.641Z"
|
|
7
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy5vjXhcgGlN+DTdW7c+Q\nEYj1gSHb8WwiSXTWL8NAA/YajXXn0RjbktzMST/n5ls62PlHI63AcDkHy/PP8FWM\nw8kGgl/fzJAVxVf0jYEx+C/7iPeT85YMMZasSp54FJBmSaefCARPCO42WmQM3E3m\nKnqU5A58aO7QUOng58LGrTcg0A5GJmmLljlYupNO3/wq4hVjtkf5NKgIBtMuMtx8\nOEl93iZpvAa90iw57ItRymCgtBDAWEkSouwvAY94Swz/b4yG+xNccIPuLjVLVCOC\n8ye3JsUCtFsB8py3dBGyVO/zzgYMD1ctVsTqSaskDbvAHxkCM56GGYs67NP8D2QS\nvQIDAQAB\n-----END PUBLIC KEY-----\n",
|
|
3
|
+
"owner": "signer",
|
|
4
|
+
"timestamp": "2025-08-01T15:58:34.531Z"
|
|
5
|
+
}
|
package/package.json
CHANGED
|
@@ -1,76 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fuse-core-express",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "FuseCore
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "FuseCore Express Encrypted Package",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
5
7
|
"scripts": {
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"main": "index.mjs",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"node": {
|
|
12
|
-
"import": "./index.mjs",
|
|
13
|
-
"require": "./index.mjs"
|
|
14
|
-
},
|
|
15
|
-
"default": "./index.mjs"
|
|
16
|
-
},
|
|
17
|
-
"./package.json": "./package.json"
|
|
18
|
-
},
|
|
19
|
-
"module": "./index.mjs",
|
|
20
|
-
"repository": {
|
|
21
|
-
"type": "git",
|
|
22
|
-
"url": "git+https://github.com/ds3783/FuseCore.git"
|
|
23
|
-
},
|
|
24
|
-
"author": "Ds.3783",
|
|
25
|
-
"license": "MIT",
|
|
26
|
-
"bugs": {
|
|
27
|
-
"url": "https://github.com/ds3783/FuseCore/issues"
|
|
28
|
-
},
|
|
29
|
-
"homepage": "https://github.com/ds3783/FuseCore#readme",
|
|
30
|
-
"publishConfig": {
|
|
31
|
-
"registry": "https://registry.npmjs.org"
|
|
32
|
-
},
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"better-https-proxy-agent": "^1.0.8",
|
|
35
|
-
"cookie": "~0.7.0",
|
|
36
|
-
"dot-prop": "^9.0.0",
|
|
37
|
-
"form-data": "^4.0.0",
|
|
38
|
-
"node-cron": "^4.2.1",
|
|
39
|
-
"on-finished": "^2.3.0",
|
|
40
|
-
"redis": "^4.6.0",
|
|
41
|
-
"tracer": "^1.3.0"
|
|
8
|
+
"start": "node index.js",
|
|
9
|
+
"test": "node index.js"
|
|
42
10
|
},
|
|
43
|
-
"
|
|
44
|
-
"hooks": {
|
|
45
|
-
"pre-commit": "npm run build",
|
|
46
|
-
"pre-push": "npm test"
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
"type": "module",
|
|
11
|
+
"dependencies": {},
|
|
50
12
|
"files": [
|
|
51
|
-
"index.
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"README.md",
|
|
57
|
-
"CHANGELOG.md",
|
|
58
|
-
"LICENSE"
|
|
13
|
+
"index.js",
|
|
14
|
+
"secure-package.vxz",
|
|
15
|
+
"decryptor.js",
|
|
16
|
+
"keys/",
|
|
17
|
+
"README.md"
|
|
59
18
|
],
|
|
60
|
-
"
|
|
61
|
-
"encrypted",
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"engines": {
|
|
67
|
-
"node": ">=14.0.0"
|
|
68
|
-
},
|
|
69
|
-
"encrypted": {
|
|
70
|
-
"version": "1.0.2",
|
|
71
|
-
"algorithm": "AES-256-CBC + RSA-2048",
|
|
72
|
-
"obfuscated": true,
|
|
73
|
-
"integrity": "RSA-SHA256",
|
|
74
|
-
"keyRequired": "private-1.0.2.pem"
|
|
19
|
+
"security": {
|
|
20
|
+
"note": "This package contains encrypted content. Use the provided decryptor with appropriate keys to access the content.",
|
|
21
|
+
"keyRequirements": {
|
|
22
|
+
"recipientPrivateKey": "Required for decryption",
|
|
23
|
+
"signerPublicKey": "Required for signature verification"
|
|
24
|
+
}
|
|
75
25
|
}
|
|
76
26
|
}
|
|
Binary file
|
package/CHANGELOG.md
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
# FuseCore Changelog
|
|
2
|
-
|
|
3
|
-
## [Unreleased]
|
|
4
|
-
|
|
5
|
-
### Added
|
|
6
|
-
- **Redis TLS Support**: Added `enableTls` parameter to Redis socket configuration
|
|
7
|
-
- New `enableTls` option in Redis configuration for secure connections
|
|
8
|
-
- Default value is `false` for backward compatibility
|
|
9
|
-
- Supports both standard Redis connections and TLS-enabled connections
|
|
10
|
-
- Updated documentation and examples to include TLS configuration
|
|
11
|
-
- **Redis Configuration Cleanup**: Removed unsupported parameters from Redis configuration
|
|
12
|
-
- Removed `connectTimeout` and `commandTimeout` parameters (not in official docs)
|
|
13
|
-
- Kept only officially supported socket parameters: `tls`, `reconnectStrategy`
|
|
14
|
-
- Configuration now strictly follows Redis official documentation
|
|
15
|
-
|
|
16
|
-
### Changed
|
|
17
|
-
- **Build Process**: Separated version bumping from crypto build process
|
|
18
|
-
- Version increment and key generation moved to `npm run version:bump`
|
|
19
|
-
- Crypto build now uses existing keys instead of generating new ones
|
|
20
|
-
- New keys and version changes are automatically committed to git
|
|
21
|
-
- Added git tag creation for version tracking
|
|
22
|
-
|
|
23
|
-
### Added
|
|
24
|
-
- **Version & Keys Management**: New `build/version-keys.mjs` script for version and key management
|
|
25
|
-
- Automatic version increment with SemVer compliance
|
|
26
|
-
- Git integration for committing keys and version changes
|
|
27
|
-
- Git tag creation for release tracking
|
|
28
|
-
- Clean working directory validation
|
|
29
|
-
- **MIT License Compliance**: Private keys now included in published packages
|
|
30
|
-
- Private key automatically copied to `dist-encrypted` directory
|
|
31
|
-
- Package `files` field updated to include private key
|
|
32
|
-
- README updated with MIT compliance notices
|
|
33
|
-
- Users can now use the package without external key management
|
|
34
|
-
- **MIT License Documentation**: Added complete MIT license documentation
|
|
35
|
-
- Created `LICENSE` file with full MIT license text
|
|
36
|
-
- Added MIT license badge to README header
|
|
37
|
-
- Added complete MIT license text to README
|
|
38
|
-
- Updated package `files` field to include LICENSE file
|
|
39
|
-
- **Package Name Update**: Changed npm package name from `fuse-core` to `fusecore` to `fuse-core-express`
|
|
40
|
-
- Updated package.json name field
|
|
41
|
-
- Updated all README examples to use new package name
|
|
42
|
-
- Updated encrypted version documentation
|
|
43
|
-
- **Encrypted Version Path Fix**: Fixed module path resolution in encrypted version
|
|
44
|
-
- Fixed decrypt loader to correctly resolve `.fec` file paths
|
|
45
|
-
- Updated path resolution to include `cjs/` directory prefix
|
|
46
|
-
- Resolved ENOENT errors when loading encrypted modules
|
|
47
|
-
- **ESM/CJS Compatibility**: Enhanced encrypted version to support both module systems
|
|
48
|
-
- Added intelligent path resolution for ESM and CJS directories
|
|
49
|
-
- Prioritizes ESM modules when available (ESM-first approach)
|
|
50
|
-
- Falls back to CJS modules when ESM not available
|
|
51
|
-
- Maintains backward compatibility with existing installations
|
|
52
|
-
- **ESM Runtime Compatibility**: Fixed `require is not defined` error in ESM environments
|
|
53
|
-
- Implemented dual-mode module loading system for CommonJS and ESM
|
|
54
|
-
- Added async/await support for ESM module execution
|
|
55
|
-
- Updated decrypt loader to handle both runtime environments seamlessly
|
|
56
|
-
- Fixed module execution context for encrypted code in ESM mode
|
|
57
|
-
- **Global Singleton Pattern**: Fixed ESM module import inconsistency issues
|
|
58
|
-
- Implemented global singleton using Symbol.for() to ensure single instance across all imports
|
|
59
|
-
- Fixed issue where multiple imports of FuseCore created different instances
|
|
60
|
-
- Ensured consistent state across app.mjs and route1.mjs imports
|
|
61
|
-
- Added proper state management for initialization status across module boundaries
|
|
62
|
-
- **Proxy Architecture**: Redesigned encrypted version to proxy to original API
|
|
63
|
-
- Generated index.mjs now only handles decryption logic
|
|
64
|
-
- After decryption, all API calls are proxied to the original source code
|
|
65
|
-
- Maintains complete compatibility with original FuseCore API
|
|
66
|
-
- Simplified architecture: decrypt once, then use original functionality
|
|
67
|
-
- Eliminates need to reimplement API logic in encrypted version
|
|
68
|
-
|
|
69
|
-
## [1.1.0] - 2025-07-31
|
|
70
|
-
|
|
71
|
-
### Added
|
|
72
|
-
- **Redis Cache Support**: FuseCore now supports Redis as a cache backend
|
|
73
|
-
- Full Redis integration with connection management
|
|
74
|
-
- Support for Redis-specific operations: `exists`, `expire`, `ttl`, `keys`, `flushAll`
|
|
75
|
-
- Configurable connection options including timeout and client settings
|
|
76
|
-
- Automatic reconnection and error handling
|
|
77
|
-
|
|
78
|
-
### Fixed
|
|
79
|
-
- **Redis Cache Type Preservation**: Fixed critical bug where JSON strings were incorrectly parsed as objects
|
|
80
|
-
- JSON strings now maintain their string type when stored and retrieved
|
|
81
|
-
- Objects are properly serialized/deserialized
|
|
82
|
-
- Backward compatibility with existing cached data
|
|
83
|
-
|
|
84
|
-
### Removed
|
|
85
|
-
- **Nestia-specific UA Properties**: Removed Nestia-related properties from getUAInfo function
|
|
86
|
-
- Removed: `isNestiaServer`, `isNestiaClient`, `isNestiaAgentClient`, `nestiaClientId`
|
|
87
|
-
- Removed: `isNestiaBusClient`, `isNestiaAppClient`, `isNestiaLotteryClient`, `isNestiaMalaysiaLotteryClient`
|
|
88
|
-
- Cleaned up function implementation and documentation
|
|
89
|
-
- Updated README documentation to reflect changes
|
|
90
|
-
- Fixed code quality warnings (assignment in conditions, unused variables, logic errors)
|
|
91
|
-
|
|
92
|
-
### Changed
|
|
93
|
-
- **Cache API**: All cache operations are now asynchronous (`async/await`)
|
|
94
|
-
- Memory cache methods updated to return Promises for consistency
|
|
95
|
-
- Tests updated to use async/await pattern
|
|
96
|
-
|
|
97
|
-
### Configuration
|
|
98
|
-
New Redis cache configuration options:
|
|
99
|
-
```javascript
|
|
100
|
-
{
|
|
101
|
-
cache: {
|
|
102
|
-
impl: 'redis', // 'memory' or 'redis'
|
|
103
|
-
redis: {
|
|
104
|
-
url: 'redis://localhost:6379',
|
|
105
|
-
enableTls: false, // Enable TLS/SSL connection
|
|
106
|
-
clientOptions: {}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Migration Guide
|
|
113
|
-
- Update cache usage to use `await` for all cache operations
|
|
114
|
-
- No breaking changes for existing memory cache usage
|
|
115
|
-
- Redis cache requires `redis` npm package (automatically installed)
|
|
116
|
-
|
|
117
|
-
## [1.0.0] - 2025-07-31
|
|
118
|
-
|
|
119
|
-
### Added
|
|
120
|
-
- Initial release
|
|
121
|
-
- Migrated from nestia-web to FuseCore
|
|
122
|
-
- Core modules: Ajax, Cache (memory), Logger, Manifest, Monitor
|
|
123
|
-
- Complete test suite
|
|
124
|
-
- Documentation and examples
|
|
125
|
-
|
|
126
|
-
### Removed
|
|
127
|
-
- Config module (deprecated)
|
|
128
|
-
- Internal network dependencies replaced with public APIs
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 Ds.3783
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|