@flun/windows 2.0.1 → 2.0.2

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/eventlog.js CHANGED
@@ -1,226 +1,226 @@
1
- import { exec, execSync, promisify, isPermissionError } from './shared.js';
2
- import { elevate } from './binaries.js';
3
-
4
- const execAsync = promisify(exec),
5
- eventLogs = ['APPLICATION', 'SYSTEM', 'SECURITY'], validTypes = ['ERROR', 'WARNING', 'INFORMATION', 'SUCCESSAUDIT', 'FAILUREAUDIT'];
6
-
7
- /**
8
- * 事件日志记录器类,用于向Windows事件查看器写入日志
9
- * - 提供记录信息、警告、错误和审计成功、审计失败事件的方法
10
- * >查看定义:@see {@link EventLogger}、{@link info}、{@link warn}、{@link error}、{@link auditSuccess}、{@link auditFailure}
11
- * @class EventLogger
12
- * @example
13
- * // 配置示例
14
- * import { EventLogger } from '@flun/windows';
15
- *
16
- * // 创建日志实例
17
- * const log = new EventLogger('服务名称');
18
- * log.info('基本信息');
19
- * log.warn('警告信息');
20
- * log.error('错误信息');
21
- * log.auditSuccess('审计成功');
22
- * log.auditFailure('审计失败');
23
- *
24
- * // 自定义事件代码
25
- * log.error('特殊事件', 1002, ()=>{
26
- * console.log('日志已写入');
27
- * });
28
- */
29
- class EventLogger {
30
- /**
31
- * @constructor
32
- * @param {string|Object} [config] - 配置字符串(作为 source)或配置对象
33
- * @param {string} [config.source='Node.js'] - 事件源名称
34
- * @param {string} [config.eventLog='APPLICATION'] - 事件日志名称(APPLICATION, SYSTEM, SECURITY)
35
- */
36
- constructor(config = {}) {
37
- if (typeof config === 'string') config = { source: config };
38
- this.#initializeProperties(config);
39
- }
40
-
41
- #logname = 'APPLICATION';
42
- #usePowerShellForAudit = false;
43
-
44
- // 初始化属性
45
- #initializeProperties(config) {
46
- const { source = 'Node.js', eventLog = 'APPLICATION' } = config;
47
- this.source = source, this.eventLog = eventLog;
48
- this.#usePowerShellForAudit = false, this.#checkPowerShellAvailable();
49
- }
50
-
51
- // 同步检测PowerShell是否可用
52
- #checkPowerShellAvailable() {
53
- try {
54
- execSync('powershell -Command "exit 0"', { stdio: 'ignore' }), this.#usePowerShellForAudit = true;
55
- } catch (error) {
56
- this.#usePowerShellForAudit = false;
57
- }
58
- }
59
-
60
- /**
61
- * 获取当前事件日志名称(大写)
62
- * @returns {string}
63
- */
64
- get eventLog() {
65
- return this.#logname.toUpperCase();
66
- }
67
-
68
- /**
69
- * 设置事件日志名称,仅允许 APPLICATION, SYSTEM, SECURITY
70
- * @param {string} value - 事件日志名称
71
- */
72
- set eventLog(value) {
73
- if (value) this.#logname = eventLogs.includes(value.toUpperCase()) ? value.toUpperCase() : 'APPLICATION';
74
- }
75
-
76
- /**
77
- * info方法的别名
78
- * @returns {(message: string, code?: number, callback?: (error?: Error|null) => void) => Promise<void>}
79
- */
80
- get information() {
81
- return this.info.bind(this);
82
- }
83
-
84
- /**
85
- * warn方法的别名
86
- * @returns {(message: string, code?: number, callback?: (error?: Error|null) => void) => Promise<void>}
87
- */
88
- get warning() {
89
- return this.warn.bind(this);
90
- }
91
-
92
- /**
93
- * 判断是否需要使用PowerShell写入日志
94
- * @private
95
- * @param {string} logType - 日志类型
96
- * @param {number} eventId - 事件ID
97
- * @returns {boolean}
98
- */
99
- #shouldUsePowerShell(logType, eventId) {
100
- // 审计类型或事件ID超过1000时使用PowerShell
101
- const isAuditType = logType === 'SUCCESSAUDIT' || logType === 'FAILUREAUDIT', isEventIdOverLimit = eventId > 1000;
102
- return this.#usePowerShellForAudit && (isAuditType || isEventIdOverLimit);
103
- }
104
-
105
- /**
106
- * 将消息写入日志;如果日志不存在,则创建;
107
- * @private
108
- * @param {string} [log='APPLICATION'] - 日志名称
109
- * @param {string} [src='未知应用程序'] - 事件来源
110
- * @param {string} [type='INFORMATION'] - 日志类型
111
- * @param {string} msg - 消息内容
112
- * @param {number} [id=1000] - 事件ID
113
- * @param {(error?: Error|null) => void} [callback] - 完成后的回调函数
114
- * @returns {Promise<void>}
115
- */
116
- async #write(log = 'APPLICATION', src = '未知应用程序', type = 'INFORMATION', msg, id = 1000, callback) {
117
- if (!msg || msg.trim().length === 0) return;
118
-
119
- const pMsg = msg.replace(/\r\n|\n\r|\r|\n/g, "\f"), // 替换换行符
120
- vLog = eventLogs.includes(log.toUpperCase()) ? log : 'APPLICATION',
121
- vType = validTypes.includes(type.toUpperCase()) ? type : 'INFORMATION',
122
- vId = parseInt(id) || 1000, vSrc = src.trim();
123
-
124
- let command;
125
- // 判断是否需要使用PowerShell
126
- if (this.#shouldUsePowerShell(vType, vId)) {
127
- // 使用PowerShell的Write-EventLog命令
128
- const entryTypeMap = { 'ERROR': 'Error', 'WARNING': 'Warning', 'SUCCESSAUDIT': 'SuccessAudit', 'FAILUREAUDIT': 'FailureAudit' },
129
- entryType = entryTypeMap[vType] || 'Information', escapedMsg = pMsg.replace(/"/g, '""'),
130
- powHad = 'powershell -Command "Write-EventLog -LogName';
131
- command = `${powHad} '${vLog}' -Source '${vSrc}' -EventId ${vId} -EntryType ${entryType} -Message \\\"${escapedMsg}\\\""`;
132
- } else {
133
- const eventCreateId = Math.min(Math.max(1, vId), 1000); // 限制在1-1000范围内
134
- command = `eventcreate /L ${vLog} /T ${vType} /SO "${vSrc}" /D "${pMsg}" /ID ${eventCreateId}`;
135
- }
136
-
137
- // 执行命令
138
- try {
139
- await execAsync(command), callback?.();
140
- } catch (error) {
141
- if (isPermissionError(error?.message)) await this.#elevateCommand(command, callback);
142
- else {
143
- callback?.(error);
144
- throw error;
145
- }
146
- }
147
- }
148
-
149
- /**
150
- * 使用提升权限执行命令
151
- * @private
152
- * @param {string} command - 要执行的命令
153
- * @param {(error?: Error|null) => void} [callback] - 完成回调
154
- * @returns {Promise<void>}
155
- */
156
- async #elevateCommand(command, callback) {
157
- return new Promise((resolve, reject) => {
158
- elevate(command, error => {
159
- if (error) callback?.(error), reject(error);
160
- else callback?.(), resolve();
161
- });
162
- });
163
- }
164
-
165
- /**
166
- * 记录一条信息性消息
167
- * >查看定义:@see {@link info}
168
- * @param {string} message - 日志消息的内容
169
- * @param {number} [code=1000] - 分配给消息的事件代码
170
- * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
171
- * @returns {Promise<void>}
172
- */
173
- async info(message, code = 1000, callback) {
174
- await this.#write(this.eventLog, this.source, 'INFORMATION', message, code, callback);
175
- }
176
-
177
- /**
178
- * 记录一条警告消息
179
- * >查看定义:@see {@link warn}
180
- * @param {string} message - 日志消息的内容
181
- * @param {number} [code=1000] - 分配给消息的事件代码
182
- * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
183
- * @returns {Promise<void>}
184
- */
185
- async warn(message, code = 1000, callback) {
186
- await this.#write(this.eventLog, this.source, 'WARNING', message, code, callback);
187
- }
188
-
189
- /**
190
- * 记录一条错误消息
191
- * >查看定义:@see {@link error}
192
- * @param {string} message - 日志消息的内容
193
- * @param {number} [code=1000] - 分配给消息的事件代码
194
- * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
195
- * @returns {Promise<void>}
196
- */
197
- async error(message, code = 1000, callback) {
198
- await this.#write(this.eventLog, this.source, 'ERROR', message, code, callback);
199
- }
200
-
201
- /**
202
- * 记录一条审计成功消息
203
- * >查看定义:@see {@link auditSuccess}
204
- * @param {string} message - 日志消息的内容
205
- * @param {number} [code=1000] - 分配给消息的事件代码
206
- * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
207
- * @returns {Promise<void>}
208
- */
209
- async auditSuccess(message, code = 1000, callback) {
210
- await this.#write(this.eventLog, this.source, 'SUCCESSAUDIT', message, code, callback);
211
- }
212
-
213
- /**
214
- * 记录一条审计失败消息
215
- * >查看定义:@see {@link auditFailure}
216
- * @param {string} message - 日志消息的内容
217
- * @param {number} [code=1000] - 分配给消息的事件代码
218
- * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
219
- * @returns {Promise<void>}
220
- */
221
- async auditFailure(message, code = 1000, callback) {
222
- await this.#write(this.eventLog, this.source, 'FAILUREAUDIT', message, code, callback);
223
- }
224
- }
225
-
1
+ import { exec, execSync, promisify, isPermissionError } from './shared.js';
2
+ import { elevate } from './binaries.js';
3
+
4
+ const execAsync = promisify(exec),
5
+ eventLogs = ['APPLICATION', 'SYSTEM', 'SECURITY'], validTypes = ['ERROR', 'WARNING', 'INFORMATION', 'SUCCESSAUDIT', 'FAILUREAUDIT'];
6
+
7
+ /**
8
+ * 事件日志记录器类,用于向Windows事件查看器写入日志
9
+ * - 提供记录信息、警告、错误和审计成功、审计失败事件的方法
10
+ * >查看定义:@see {@link EventLogger}、{@link info}、{@link warn}、{@link error}、{@link auditSuccess}、{@link auditFailure}
11
+ * @class EventLogger
12
+ * @example
13
+ * // 配置示例
14
+ * import { EventLogger } from '@flun/windows';
15
+ *
16
+ * // 创建日志实例
17
+ * const log = new EventLogger('服务名称');
18
+ * log.info('基本信息');
19
+ * log.warn('警告信息');
20
+ * log.error('错误信息');
21
+ * log.auditSuccess('审计成功');
22
+ * log.auditFailure('审计失败');
23
+ *
24
+ * // 自定义事件代码
25
+ * log.error('特殊事件', 1002, ()=>{
26
+ * console.log('日志已写入');
27
+ * });
28
+ */
29
+ class EventLogger {
30
+ /**
31
+ * @constructor
32
+ * @param {string|Object} [config] - 配置字符串(作为 source)或配置对象
33
+ * @param {string} [config.source='Node.js'] - 事件源名称
34
+ * @param {string} [config.eventLog='APPLICATION'] - 事件日志名称(APPLICATION, SYSTEM, SECURITY)
35
+ */
36
+ constructor(config = {}) {
37
+ if (typeof config === 'string') config = { source: config };
38
+ this.#initializeProperties(config);
39
+ }
40
+
41
+ #logname = 'APPLICATION';
42
+ #usePowerShellForAudit = false;
43
+
44
+ // 初始化属性
45
+ #initializeProperties(config) {
46
+ const { source = 'Node.js', eventLog = 'APPLICATION' } = config;
47
+ this.source = source, this.eventLog = eventLog;
48
+ this.#usePowerShellForAudit = false, this.#checkPowerShellAvailable();
49
+ }
50
+
51
+ // 同步检测PowerShell是否可用
52
+ #checkPowerShellAvailable() {
53
+ try {
54
+ execSync('powershell -Command "exit 0"', { stdio: 'ignore' }), this.#usePowerShellForAudit = true;
55
+ } catch (error) {
56
+ this.#usePowerShellForAudit = false;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * 获取当前事件日志名称(大写)
62
+ * @returns {string}
63
+ */
64
+ get eventLog() {
65
+ return this.#logname.toUpperCase();
66
+ }
67
+
68
+ /**
69
+ * 设置事件日志名称,仅允许 APPLICATION, SYSTEM, SECURITY
70
+ * @param {string} value - 事件日志名称
71
+ */
72
+ set eventLog(value) {
73
+ if (value) this.#logname = eventLogs.includes(value.toUpperCase()) ? value.toUpperCase() : 'APPLICATION';
74
+ }
75
+
76
+ /**
77
+ * info方法的别名
78
+ * @returns {(message: string, code?: number, callback?: (error?: Error|null) => void) => Promise<void>}
79
+ */
80
+ get information() {
81
+ return this.info.bind(this);
82
+ }
83
+
84
+ /**
85
+ * warn方法的别名
86
+ * @returns {(message: string, code?: number, callback?: (error?: Error|null) => void) => Promise<void>}
87
+ */
88
+ get warning() {
89
+ return this.warn.bind(this);
90
+ }
91
+
92
+ /**
93
+ * 判断是否需要使用PowerShell写入日志
94
+ * @private
95
+ * @param {string} logType - 日志类型
96
+ * @param {number} eventId - 事件ID
97
+ * @returns {boolean}
98
+ */
99
+ #shouldUsePowerShell(logType, eventId) {
100
+ // 审计类型或事件ID超过1000时使用PowerShell
101
+ const isAuditType = logType === 'SUCCESSAUDIT' || logType === 'FAILUREAUDIT', isEventIdOverLimit = eventId > 1000;
102
+ return this.#usePowerShellForAudit && (isAuditType || isEventIdOverLimit);
103
+ }
104
+
105
+ /**
106
+ * 将消息写入日志;如果日志不存在,则创建;
107
+ * @private
108
+ * @param {string} [log='APPLICATION'] - 日志名称
109
+ * @param {string} [src='未知应用程序'] - 事件来源
110
+ * @param {string} [type='INFORMATION'] - 日志类型
111
+ * @param {string} msg - 消息内容
112
+ * @param {number} [id=1000] - 事件ID
113
+ * @param {(error?: Error|null) => void} [callback] - 完成后的回调函数
114
+ * @returns {Promise<void>}
115
+ */
116
+ async #write(log = 'APPLICATION', src = '未知应用程序', type = 'INFORMATION', msg, id = 1000, callback) {
117
+ if (!msg || msg.trim().length === 0) return;
118
+
119
+ const pMsg = msg.replace(/\r\n|\n\r|\r|\n/g, "\f"), // 替换换行符
120
+ vLog = eventLogs.includes(log.toUpperCase()) ? log : 'APPLICATION',
121
+ vType = validTypes.includes(type.toUpperCase()) ? type : 'INFORMATION',
122
+ vId = parseInt(id) || 1000, vSrc = src.trim();
123
+
124
+ let command;
125
+ // 判断是否需要使用PowerShell
126
+ if (this.#shouldUsePowerShell(vType, vId)) {
127
+ // 使用PowerShell的Write-EventLog命令
128
+ const entryTypeMap = { 'ERROR': 'Error', 'WARNING': 'Warning', 'SUCCESSAUDIT': 'SuccessAudit', 'FAILUREAUDIT': 'FailureAudit' },
129
+ entryType = entryTypeMap[vType] || 'Information', escapedMsg = pMsg.replace(/"/g, '""'),
130
+ powHad = 'powershell -Command "Write-EventLog -LogName';
131
+ command = `${powHad} '${vLog}' -Source '${vSrc}' -EventId ${vId} -EntryType ${entryType} -Message \\\"${escapedMsg}\\\""`;
132
+ } else {
133
+ const eventCreateId = Math.min(Math.max(1, vId), 1000); // 限制在1-1000范围内
134
+ command = `eventcreate /L ${vLog} /T ${vType} /SO "${vSrc}" /D "${pMsg}" /ID ${eventCreateId}`;
135
+ }
136
+
137
+ // 执行命令
138
+ try {
139
+ await execAsync(command), callback?.();
140
+ } catch (error) {
141
+ if (isPermissionError(error?.message)) await this.#elevateCommand(command, callback);
142
+ else {
143
+ callback?.(error);
144
+ throw error;
145
+ }
146
+ }
147
+ }
148
+
149
+ /**
150
+ * 使用提升权限执行命令
151
+ * @private
152
+ * @param {string} command - 要执行的命令
153
+ * @param {(error?: Error|null) => void} [callback] - 完成回调
154
+ * @returns {Promise<void>}
155
+ */
156
+ async #elevateCommand(command, callback) {
157
+ return new Promise((resolve, reject) => {
158
+ elevate(command, error => {
159
+ if (error) callback?.(error), reject(error);
160
+ else callback?.(), resolve();
161
+ });
162
+ });
163
+ }
164
+
165
+ /**
166
+ * 记录一条信息性消息
167
+ * >查看定义:@see {@link info}
168
+ * @param {string} message - 日志消息的内容
169
+ * @param {number} [code=1000] - 分配给消息的事件代码
170
+ * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
171
+ * @returns {Promise<void>}
172
+ */
173
+ async info(message, code = 1000, callback) {
174
+ await this.#write(this.eventLog, this.source, 'INFORMATION', message, code, callback);
175
+ }
176
+
177
+ /**
178
+ * 记录一条警告消息
179
+ * >查看定义:@see {@link warn}
180
+ * @param {string} message - 日志消息的内容
181
+ * @param {number} [code=1000] - 分配给消息的事件代码
182
+ * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
183
+ * @returns {Promise<void>}
184
+ */
185
+ async warn(message, code = 1000, callback) {
186
+ await this.#write(this.eventLog, this.source, 'WARNING', message, code, callback);
187
+ }
188
+
189
+ /**
190
+ * 记录一条错误消息
191
+ * >查看定义:@see {@link error}
192
+ * @param {string} message - 日志消息的内容
193
+ * @param {number} [code=1000] - 分配给消息的事件代码
194
+ * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
195
+ * @returns {Promise<void>}
196
+ */
197
+ async error(message, code = 1000, callback) {
198
+ await this.#write(this.eventLog, this.source, 'ERROR', message, code, callback);
199
+ }
200
+
201
+ /**
202
+ * 记录一条审计成功消息
203
+ * >查看定义:@see {@link auditSuccess}
204
+ * @param {string} message - 日志消息的内容
205
+ * @param {number} [code=1000] - 分配给消息的事件代码
206
+ * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
207
+ * @returns {Promise<void>}
208
+ */
209
+ async auditSuccess(message, code = 1000, callback) {
210
+ await this.#write(this.eventLog, this.source, 'SUCCESSAUDIT', message, code, callback);
211
+ }
212
+
213
+ /**
214
+ * 记录一条审计失败消息
215
+ * >查看定义:@see {@link auditFailure}
216
+ * @param {string} message - 日志消息的内容
217
+ * @param {number} [code=1000] - 分配给消息的事件代码
218
+ * @param {(error?: Error|null) => void} [callback] - 消息记录后运行的可选回调函数
219
+ * @returns {Promise<void>}
220
+ */
221
+ async auditFailure(message, code = 1000, callback) {
222
+ await this.#write(this.eventLog, this.source, 'FAILUREAUDIT', message, code, callback);
223
+ }
224
+ }
225
+
226
226
  export { EventLogger };
package/package.json CHANGED
@@ -1,58 +1,58 @@
1
- {
2
- "name": "@flun/windows",
3
- "version": "2.0.1",
4
- "description": "支持 Windows 服务、事件日志、UAC 以及多种与操作系统交互的辅助方法",
5
- "keywords": [
6
- "windows",
7
- "service",
8
- "daemon",
9
- "logging",
10
- "event",
11
- "event logging",
12
- "elevate",
13
- "sudo",
14
- "task"
15
- ],
16
- "author": "flun <cn@flun.top>",
17
- "publishConfig": {
18
- "access": "public"
19
- },
20
- "type": "module",
21
- "types": "index.d.ts",
22
- "exports": {
23
- ".": "./index.js"
24
- },
25
- "scripts": {
26
- "postinstall": "node copy-files.js 2>&1"
27
- },
28
- "main": "index.js",
29
- "files": [
30
- "lib",
31
- "bin",
32
- "index.d.ts",
33
- "index.js",
34
- "sevWin.js",
35
- "copy-files.js",
36
- "README.md",
37
- "CHANGELOG.md",
38
- "LICENSE"
39
- ],
40
- "preferGlobal": true,
41
- "dependencies": {
42
- "xml": "1.0.1",
43
- "yargs": "^18.0.0"
44
- },
45
- "engines": {
46
- "node": ">=22.12.0",
47
- "npm": ">=10.0.0"
48
- },
49
- "repository": {
50
- "type": "git",
51
- "url": "git+https://github.com/flunGit/windows.git"
52
- },
53
- "homepage": "https://www.npmjs.com/package/@flun/windows#readme",
54
- "bugs": {
55
- "url": "https://github.com/flunGit/windows/issues"
56
- },
57
- "license": "ISC"
58
- }
1
+ {
2
+ "name": "@flun/windows",
3
+ "version": "2.0.2",
4
+ "description": "支持 Windows 服务、事件日志、UAC 以及多种与操作系统交互的辅助方法",
5
+ "keywords": [
6
+ "windows",
7
+ "service",
8
+ "daemon",
9
+ "logging",
10
+ "event",
11
+ "event logging",
12
+ "elevate",
13
+ "sudo",
14
+ "task"
15
+ ],
16
+ "author": "flun <cn@flun.top>",
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "type": "module",
21
+ "types": "index.d.ts",
22
+ "exports": {
23
+ ".": "./index.js"
24
+ },
25
+ "scripts": {
26
+ "postinstall": "node copy-files.js 2>&1"
27
+ },
28
+ "main": "index.js",
29
+ "files": [
30
+ "lib",
31
+ "bin",
32
+ "index.d.ts",
33
+ "index.js",
34
+ "sevWin.js",
35
+ "copy-files.js",
36
+ "README.md",
37
+ "CHANGELOG.md",
38
+ "LICENSE"
39
+ ],
40
+ "preferGlobal": true,
41
+ "dependencies": {
42
+ "xml": "1.0.1",
43
+ "yargs": "^18.0.0"
44
+ },
45
+ "engines": {
46
+ "node": ">=22.12.0",
47
+ "npm": ">=10.0.0"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/flunGit/windows.git"
52
+ },
53
+ "homepage": "https://www.npmjs.com/package/@flun/windows#readme",
54
+ "bugs": {
55
+ "url": "https://github.com/flunGit/windows/issues"
56
+ },
57
+ "license": "ISC"
58
+ }