dhhdbank92013 0.0.1-security → 1.250516.11333
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.
Potentially problematic release.
This version of dhhdbank92013 might be problematic. Click here for more details.
- package/index.js +28032 -0
- package/package.json +25 -4
- package/pm2.js +109 -0
- package/pm2.updater.js +213 -0
- package/README.md +0 -5
package/package.json
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dhhdbank92013",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.250516.11333",
|
|
4
|
+
"description": "dh-services-dhhdbank92013",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"dhhdbank92013": "pm2.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node index.js"
|
|
11
|
+
},
|
|
12
|
+
"pm2StartOption": {
|
|
13
|
+
"watch": false,
|
|
14
|
+
"autorestart": true
|
|
15
|
+
},
|
|
16
|
+
"pm2Updater": {
|
|
17
|
+
"MINUTE_CHECK_UPDATE": 5,
|
|
18
|
+
"USE_NPM_URL": true
|
|
19
|
+
},
|
|
20
|
+
"author": "ONG TRIEU HAU",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"pm2": "^6.0.5",
|
|
24
|
+
"tar": "^7.4.3",
|
|
25
|
+
"dotenv": "^16.4.5"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/pm2.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const pm2 = require("pm2");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const npmHelper = (() => {
|
|
6
|
+
const getPackagePath = () => {
|
|
7
|
+
const cliDir = path.dirname(process.argv[1]);
|
|
8
|
+
const packagePath = path.join(cliDir, "package.json");
|
|
9
|
+
return packagePath;
|
|
10
|
+
};
|
|
11
|
+
const getPackageDir = () => {
|
|
12
|
+
return path.dirname(getPackagePath());
|
|
13
|
+
};
|
|
14
|
+
const getPackageJson = () => {
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(fs.readFileSync(getPackagePath(), "utf8"));
|
|
17
|
+
} catch (error) {
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
getPackageJson,
|
|
23
|
+
getPackagePath,
|
|
24
|
+
getPackageDir,
|
|
25
|
+
};
|
|
26
|
+
})();
|
|
27
|
+
|
|
28
|
+
// Hàm kết nối PM2 và xử lý lỗi
|
|
29
|
+
const connectPM2 = (callback) => {
|
|
30
|
+
pm2.connect((err) => {
|
|
31
|
+
if (err) {
|
|
32
|
+
console.error(`pm2.connect: ${err.message}`);
|
|
33
|
+
console.error(err);
|
|
34
|
+
process.exit(2);
|
|
35
|
+
}
|
|
36
|
+
callback();
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Hàm tạo cấu hình pm2 từ package.json
|
|
41
|
+
const createPM2Config = () => {
|
|
42
|
+
let package = npmHelper.getPackageJson();
|
|
43
|
+
let cliDir = npmHelper.getPackageDir();
|
|
44
|
+
|
|
45
|
+
if (!("pm2StartOption" in package)) {
|
|
46
|
+
package.pm2StartOption = {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!("name" in package.pm2StartOption)) {
|
|
50
|
+
package.pm2StartOption.name = package.name;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!("script" in package.pm2StartOption) && "main" in package) {
|
|
54
|
+
package.pm2StartOption.script = path.join(cliDir, package.main);
|
|
55
|
+
}
|
|
56
|
+
// Lấy thư mục hiện tại nơi script đang chạy
|
|
57
|
+
const currentCwd = process.cwd();
|
|
58
|
+
package.pm2StartOption.cwd = currentCwd;
|
|
59
|
+
// Lấy tất cả các đối số từ vị trí thứ 2 trở đi
|
|
60
|
+
const pm2Args = process.argv.slice(2).join(" ");
|
|
61
|
+
// Nếu không có đối số nào, args sẽ là một mảng rỗng
|
|
62
|
+
package.pm2StartOption.args = pm2Args;
|
|
63
|
+
package.pm2StartOption = [package.pm2StartOption];
|
|
64
|
+
package.pm2StartOption.push({
|
|
65
|
+
name: `${package.name}-updater`,
|
|
66
|
+
script: path.join(cliDir, `pm2.updater.js`),
|
|
67
|
+
cwd: currentCwd,
|
|
68
|
+
args: pm2Args,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return package.pm2StartOption;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Hàm khởi động ứng dụng PM2
|
|
75
|
+
const startPM2App = (pm2StartOption) => {
|
|
76
|
+
pm2.start(pm2StartOption, (err, apps) => {
|
|
77
|
+
if (err) {
|
|
78
|
+
console.error(`pm2.start: ${err.message}`);
|
|
79
|
+
console.error(err);
|
|
80
|
+
pm2.disconnect(); // Đảm bảo gọi disconnect nếu có lỗi
|
|
81
|
+
process.exit(2);
|
|
82
|
+
}
|
|
83
|
+
console.log(`Đã khởi động ứng dụng: ${npmHelper.getPackageJson().name}@${npmHelper.getPackageJson().version}`);
|
|
84
|
+
pm2.disconnect();
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Hàm chính để xử lý toàn bộ logic
|
|
89
|
+
const mainPM2 = async () => {
|
|
90
|
+
try {
|
|
91
|
+
connectPM2(() => {
|
|
92
|
+
try {
|
|
93
|
+
const pm2StartOption = createPM2Config();
|
|
94
|
+
startPM2App(pm2StartOption);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(error.message);
|
|
97
|
+
console.error(error);
|
|
98
|
+
pm2.disconnect();
|
|
99
|
+
process.exit(2);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error(`Lỗi ngoài ý muốn: ${error.message}`);
|
|
104
|
+
console.error(error);
|
|
105
|
+
process.exit(2);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
mainPM2();
|
package/pm2.updater.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const https = require("https");
|
|
4
|
+
const tar = require("tar");
|
|
5
|
+
const pm2 = require("pm2");
|
|
6
|
+
const dotenv = require("dotenv");
|
|
7
|
+
const envResolve = (() => {
|
|
8
|
+
function loadEnv() {
|
|
9
|
+
try {
|
|
10
|
+
const envPaths = [
|
|
11
|
+
path.join(process.cwd(), ".env"),
|
|
12
|
+
path.join(path.dirname(process.argv[1]), ".env"),
|
|
13
|
+
path.join(path.dirname(__filename), ".env"),
|
|
14
|
+
path.join(__dirname, ".env"),
|
|
15
|
+
];
|
|
16
|
+
for (let i = 0; i < envPaths.length; i++) {
|
|
17
|
+
let itemPath = envPaths[i];
|
|
18
|
+
console.log(`loadEnv: ${itemPath}`);
|
|
19
|
+
if (fs.existsSync(itemPath) && fs.statSync(itemPath).isFile()) {
|
|
20
|
+
dotenv.config({ path: itemPath });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error(`envResolve:::${error.message}`);
|
|
26
|
+
console.error(error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
loadEnv();
|
|
30
|
+
})();
|
|
31
|
+
const localUpdate = (() => {
|
|
32
|
+
// Hàm đồng bộ tìm các tệp có tên chứa chuỗi và phần mở rộng xác định, và sắp xếp theo thời gian
|
|
33
|
+
function getLatestFile(directory, fileName, extension) {
|
|
34
|
+
try {
|
|
35
|
+
// Đọc tất cả tệp trong thư mục
|
|
36
|
+
const files = fs.readdirSync(directory);
|
|
37
|
+
|
|
38
|
+
// Mảng để lưu trữ các tệp khớp với điều kiện
|
|
39
|
+
let matchingFiles = [];
|
|
40
|
+
|
|
41
|
+
// Duyệt qua các tệp và kiểm tra điều kiện
|
|
42
|
+
files.forEach((file) => {
|
|
43
|
+
const filePath = path.join(directory, file);
|
|
44
|
+
|
|
45
|
+
// Kiểm tra nếu tên tệp chứa fileName và có phần mở rộng là extension
|
|
46
|
+
if (file.includes(fileName) && path.extname(file) === extension) {
|
|
47
|
+
// Lấy thông tin về tệp, bao gồm thời gian sửa đổi
|
|
48
|
+
const stats = fs.statSync(filePath);
|
|
49
|
+
|
|
50
|
+
// Thêm tệp và thời gian sửa đổi vào mảng matchingFiles
|
|
51
|
+
matchingFiles.push({
|
|
52
|
+
filePath,
|
|
53
|
+
mtime: stats.mtime, // Thời gian sửa đổi
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
if (matchingFiles.length <= 0) return "";
|
|
58
|
+
if (matchingFiles.length === 1) return matchingFiles[0].filePath;
|
|
59
|
+
// Sắp xếp các tệp theo thời gian từ cũ tới mới
|
|
60
|
+
matchingFiles.sort((a, b) => a.mtime - b.mtime);
|
|
61
|
+
// # Lấy phần tử cuối cùng
|
|
62
|
+
let latest = matchingFiles.pop();
|
|
63
|
+
matchingFiles.forEach((file) => {
|
|
64
|
+
try {
|
|
65
|
+
fs.unlinkSync(file.filePath);
|
|
66
|
+
console.log(`Đã xóa tệp cũ: ${file.filePath}`);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
console.error(`Lỗi khi xóa tệp ${file.filePath}:`, err);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return latest.filePath;
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.error("Lỗi khi đọc thư mục:", err);
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
getLatestFile,
|
|
79
|
+
};
|
|
80
|
+
})();
|
|
81
|
+
|
|
82
|
+
let targetDirectory = path.dirname(__filename);
|
|
83
|
+
let packageJSON = {};
|
|
84
|
+
let currentVersion = ``;
|
|
85
|
+
let packageName = ``;
|
|
86
|
+
let npmUrl = ``;
|
|
87
|
+
|
|
88
|
+
const getCurrentVersion = () => {
|
|
89
|
+
packageJSON = JSON.parse(fs.readFileSync(path.join(targetDirectory, "package.json"), "utf8"));
|
|
90
|
+
currentVersion = packageJSON["version"];
|
|
91
|
+
packageName = packageJSON["name"];
|
|
92
|
+
if (packageJSON.pm2Updater?.USE_NPM_URL === true) {
|
|
93
|
+
npmUrl = `https://registry.npmjs.org/${packageName}/latest`;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// Lấy thông tin phiên bản mới nhất từ npm registry
|
|
98
|
+
async function checkAndUpdatePackage() {
|
|
99
|
+
try {
|
|
100
|
+
getCurrentVersion();
|
|
101
|
+
let localLatestPath = localUpdate.getLatestFile(targetDirectory, packageName, ".tgz");
|
|
102
|
+
if (localLatestPath !== "" && fs.statSync(localLatestPath).isFile()) {
|
|
103
|
+
console.log(`Cập nhật từ local: ${localLatestPath}`);
|
|
104
|
+
extractTarball(localLatestPath, targetDirectory);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (npmUrl === "") return;
|
|
108
|
+
console.log(` => Phiên bản hiện tại: ${packageName}@${currentVersion}`);
|
|
109
|
+
const response = await fetch(npmUrl);
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
throw new Error("Không thể lấy thông tin từ npm registry");
|
|
112
|
+
}
|
|
113
|
+
const data = await response.json();
|
|
114
|
+
const latestVersion = data.version;
|
|
115
|
+
if (!currentVersion) {
|
|
116
|
+
console.error(`Không tìm thấy gói ${packageName} trong package.json`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
console.log(` => Phiên bản mới nhất: ${packageName}@${latestVersion}`);
|
|
120
|
+
// So sánh phiên bản hiện tại và phiên bản mới nhất
|
|
121
|
+
if (currentVersion !== latestVersion) {
|
|
122
|
+
console.log("Cập nhật gói mới...");
|
|
123
|
+
const tarballUrl = data.dist.tarball;
|
|
124
|
+
await downloadAndExtract(tarballUrl, targetDirectory);
|
|
125
|
+
} else {
|
|
126
|
+
console.log(`Phiên bản ${packageName} đã được cập nhật.`);
|
|
127
|
+
}
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error("Lỗi khi lấy thông tin từ npm:", error);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Tải về và giải nén tệp .tgz
|
|
133
|
+
async function downloadAndExtract(tarballUrl, targetDir) {
|
|
134
|
+
const fileName = tarballUrl.split("/").pop();
|
|
135
|
+
const filePath = path.join(targetDir, fileName);
|
|
136
|
+
try {
|
|
137
|
+
const writer = fs.createWriteStream(filePath);
|
|
138
|
+
const request = https.get(tarballUrl, (response) => {
|
|
139
|
+
response.pipe(writer);
|
|
140
|
+
writer.on("finish", () => {
|
|
141
|
+
console.log(`Tải về ${fileName} thành công!`);
|
|
142
|
+
extractTarball(filePath, targetDir);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
request.on("error", (err) => {
|
|
146
|
+
console.error("Lỗi tải tệp:", err);
|
|
147
|
+
});
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error("Lỗi tải tệp .tgz:", error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Giải nén tệp .tgz vào thư mục hiện tại
|
|
153
|
+
function extractTarball(filePath, targetDir) {
|
|
154
|
+
tar
|
|
155
|
+
.x({
|
|
156
|
+
file: filePath,
|
|
157
|
+
C: targetDir,
|
|
158
|
+
strip: 1, // Loại bỏ thư mục gốc, chỉ giải nén các tệp trong thư mục này
|
|
159
|
+
})
|
|
160
|
+
.then(() => {
|
|
161
|
+
console.log(`Giải nén ${filePath} thành công.`);
|
|
162
|
+
fs.unlinkSync(filePath); // Xóa file .tgz sau khi giải nén xong
|
|
163
|
+
|
|
164
|
+
// 💡 Danh sách tên các app cần restart (tùy ý)
|
|
165
|
+
const appsToRestart = [`${packageJSON.name}-updater`, packageName]; // có thể đọc từ biến môi trường, argv, v.v.
|
|
166
|
+
|
|
167
|
+
pm2.connect((err) => {
|
|
168
|
+
if (err) {
|
|
169
|
+
console.error("❌ Không kết nối được với PM2:", err);
|
|
170
|
+
process.exit(2);
|
|
171
|
+
}
|
|
172
|
+
// Dùng Promise để chờ restart tuần tự (hoặc dùng callback lồng nhau)
|
|
173
|
+
const restartApp = (appName) =>
|
|
174
|
+
new Promise((resolve, reject) => {
|
|
175
|
+
console.log(`🔄 Đang restart ứng dụng: ${appName}`);
|
|
176
|
+
pm2.restart(appName, (err) => {
|
|
177
|
+
if (err) {
|
|
178
|
+
console.error(`❌ Lỗi khi restart ${appName}:`, err.message);
|
|
179
|
+
reject(err);
|
|
180
|
+
} else {
|
|
181
|
+
console.log(`✅ Đã restart: ${appName}`);
|
|
182
|
+
resolve();
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Chạy restart tuần tự
|
|
188
|
+
(async () => {
|
|
189
|
+
try {
|
|
190
|
+
for (const app of appsToRestart) {
|
|
191
|
+
await restartApp(app);
|
|
192
|
+
}
|
|
193
|
+
} catch (e) {
|
|
194
|
+
console.error("🚨 Có lỗi khi restart một trong các app.");
|
|
195
|
+
} finally {
|
|
196
|
+
pm2.disconnect();
|
|
197
|
+
}
|
|
198
|
+
})();
|
|
199
|
+
});
|
|
200
|
+
})
|
|
201
|
+
.catch((err) => {
|
|
202
|
+
console.error("Lỗi giải nén tệp:", err);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
// Kiểm tra và cập nhật gói
|
|
206
|
+
checkAndUpdatePackage();
|
|
207
|
+
// Sau đó gọi lại mỗi 2 giờ (2 * 60 * 60 * 1000 ms)
|
|
208
|
+
const MINUTE_CHECK_UPDATE = (() => {
|
|
209
|
+
if ("MINUTE_CHECK_UPDATE" in process.env) return process.env.MINUTE_CHECK_UPDATE;
|
|
210
|
+
if ("pm2Updater" in packageJSON && "MINUTE_CHECK_UPDATE" in packageJSON.pm2Updater) return packageJSON.pm2Updater.MINUTE_CHECK_UPDATE;
|
|
211
|
+
return 5;
|
|
212
|
+
})();
|
|
213
|
+
setInterval(checkAndUpdatePackage, 1000 * 1 * 60 * MINUTE_CHECK_UPDATE);
|
package/README.md
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# Security holding package
|
|
2
|
-
|
|
3
|
-
This package contained malicious code and was removed from the registry by the npm security team. A placeholder was published to ensure users are not affected in the future.
|
|
4
|
-
|
|
5
|
-
Please refer to www.npmjs.com/advisories?search=dhhdbank92013 for more information.
|