@depup/systeminformation 5.31.4-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/users.js ADDED
@@ -0,0 +1,412 @@
1
+ 'use strict';
2
+ // @ts-check
3
+ // ==================================================================================
4
+ // users.js
5
+ // ----------------------------------------------------------------------------------
6
+ // Description: System Information - library
7
+ // for Node.js
8
+ // Copyright: (c) 2014 - 2026
9
+ // Author: Sebastian Hildebrandt
10
+ // ----------------------------------------------------------------------------------
11
+ // License: MIT
12
+ // ==================================================================================
13
+ // 11. Users/Sessions
14
+ // ----------------------------------------------------------------------------------
15
+
16
+ const exec = require('child_process').exec;
17
+ const util = require('./util');
18
+
19
+ const _platform = process.platform;
20
+
21
+ const _linux = _platform === 'linux' || _platform === 'android';
22
+ const _darwin = _platform === 'darwin';
23
+ const _windows = _platform === 'win32';
24
+ const _freebsd = _platform === 'freebsd';
25
+ const _openbsd = _platform === 'openbsd';
26
+ const _netbsd = _platform === 'netbsd';
27
+ const _sunos = _platform === 'sunos';
28
+
29
+ function parseDate(dtMon, dtDay) {
30
+ let dt = new Date().toISOString().slice(0, 10);
31
+ try {
32
+ dt = '' + new Date().getFullYear() + '-' + ('0' + ('JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'.indexOf(dtMon.toUpperCase()) / 3 + 1)).slice(-2) + '-' + ('0' + dtDay).slice(-2);
33
+ if (new Date(dt) > new Date()) {
34
+ dt = '' + (new Date().getFullYear() - 1) + '-' + ('0' + ('JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'.indexOf(dtMon.toUpperCase()) / 3 + 1)).slice(-2) + '-' + ('0' + dtDay).slice(-2);
35
+ }
36
+ } catch {
37
+ util.noop();
38
+ }
39
+ return dt;
40
+ }
41
+
42
+ function parseUsersLinux(lines, phase) {
43
+ const result = [];
44
+ let result_who = [];
45
+ const result_w = {};
46
+ let w_first = true;
47
+ let w_header = [];
48
+ const w_pos = [];
49
+ let who_line = {};
50
+
51
+ let is_whopart = true;
52
+ let is_whoerror = false;
53
+ lines.forEach((line) => {
54
+ if (line === '---') {
55
+ is_whopart = false;
56
+ } else {
57
+ const l = line.replace(/ +/g, ' ').split(' ');
58
+ // who part
59
+ if (is_whopart) {
60
+ if (line.toLowerCase().indexOf('unexpected') >= 0 || line.toLowerCase().indexOf('unrecognized') >= 0) {
61
+ is_whoerror = true;
62
+ result_who = [];
63
+ }
64
+ if (!is_whoerror) {
65
+ const timePos = l && l.length > 4 && l[4].indexOf(':') > 0 ? 4 : 3;
66
+ result_who.push({
67
+ user: l[0],
68
+ tty: l[1],
69
+ date: timePos === 4 ? parseDate(l[2], l[3]) : l[2],
70
+ time: l[timePos],
71
+ ip: l && l.length > timePos + 1 ? l[timePos + 1].replace(/\(/g, '').replace(/\)/g, '') : '',
72
+ command: ''
73
+ });
74
+ }
75
+ } else {
76
+ // w part
77
+ if (w_first) {
78
+ // header
79
+ if (line[0] !== ' ') {
80
+ w_header = l;
81
+ w_header.forEach((item) => {
82
+ w_pos.push(line.indexOf(item));
83
+ });
84
+ w_first = false;
85
+ }
86
+ } else {
87
+ // split by w_pos
88
+ result_w.user = line.substring(w_pos[0], w_pos[1] - 1).trim();
89
+ result_w.tty = line.substring(w_pos[1], w_pos[2] - 1).trim();
90
+ result_w.ip = line
91
+ .substring(w_pos[2], w_pos[3] - 1)
92
+ .replace(/\(/g, '')
93
+ .replace(/\)/g, '')
94
+ .trim();
95
+ result_w.command = line.substring(w_pos[7], 1000).trim();
96
+ // find corresponding 'who' line
97
+ if (result_who.length || phase === 1) {
98
+ who_line = result_who.filter((obj) => {
99
+ return obj.user.substring(0, 8).trim() === result_w.user && obj.tty === result_w.tty;
100
+ });
101
+ } else {
102
+ who_line = [{ user: result_w.user, tty: result_w.tty, date: '', time: '', ip: '' }];
103
+ }
104
+ if (who_line.length === 1 && who_line[0].user !== '') {
105
+ result.push({
106
+ user: who_line[0].user,
107
+ tty: who_line[0].tty,
108
+ date: who_line[0].date,
109
+ time: who_line[0].time,
110
+ ip: who_line[0].ip,
111
+ command: result_w.command
112
+ });
113
+ }
114
+ }
115
+ }
116
+ }
117
+ });
118
+ if (result.length === 0 && phase === 2) {
119
+ return result_who;
120
+ } else {
121
+ return result;
122
+ }
123
+ }
124
+
125
+ function parseUsersDarwin(lines) {
126
+ const result = [];
127
+ const result_who = [];
128
+ const result_w = {};
129
+ let who_line = {};
130
+
131
+ let is_whopart = true;
132
+ lines.forEach((line) => {
133
+ if (line === '---') {
134
+ is_whopart = false;
135
+ } else {
136
+ const l = line.replace(/ +/g, ' ').split(' ');
137
+
138
+ // who part
139
+ if (is_whopart) {
140
+ result_who.push({
141
+ user: l[0],
142
+ tty: l[1],
143
+ date: parseDate(l[2], l[3]),
144
+ time: l[4]
145
+ });
146
+ } else {
147
+ // w part
148
+ // split by w_pos
149
+ result_w.user = l[0];
150
+ result_w.tty = l[1];
151
+ result_w.ip = l[2] !== '-' ? l[2] : '';
152
+ result_w.command = l.slice(5, 1000).join(' ');
153
+ // find corresponding 'who' line
154
+ who_line = result_who.filter((obj) => obj.user.substring(0, 10) === result_w.user.substring(0, 10) && (obj.tty.substring(3, 1000) === result_w.tty || obj.tty === result_w.tty));
155
+ if (who_line.length === 1) {
156
+ result.push({
157
+ user: who_line[0].user,
158
+ tty: who_line[0].tty,
159
+ date: who_line[0].date,
160
+ time: who_line[0].time,
161
+ ip: result_w.ip,
162
+ command: result_w.command
163
+ });
164
+ }
165
+ }
166
+ }
167
+ });
168
+ return result;
169
+ }
170
+
171
+ function users(callback) {
172
+ return new Promise((resolve) => {
173
+ process.nextTick(() => {
174
+ let result = [];
175
+
176
+ // linux
177
+ if (_linux) {
178
+ exec('export LC_ALL=C; who --ips; echo "---"; w; unset LC_ALL | tail -n +2', (error, stdout) => {
179
+ if (!error) {
180
+ // lines / split
181
+ let lines = stdout.toString().split('\n');
182
+ result = parseUsersLinux(lines, 1);
183
+ if (result.length === 0) {
184
+ exec('who; echo "---"; w | tail -n +2', (error, stdout) => {
185
+ if (!error) {
186
+ // lines / split
187
+ lines = stdout.toString().split('\n');
188
+ result = parseUsersLinux(lines, 2);
189
+ }
190
+ if (callback) {
191
+ callback(result);
192
+ }
193
+ resolve(result);
194
+ });
195
+ } else {
196
+ if (callback) {
197
+ callback(result);
198
+ }
199
+ resolve(result);
200
+ }
201
+ } else {
202
+ if (callback) {
203
+ callback(result);
204
+ }
205
+ resolve(result);
206
+ }
207
+ });
208
+ }
209
+ if (_freebsd || _openbsd || _netbsd) {
210
+ exec('who; echo "---"; w -ih', (error, stdout) => {
211
+ if (!error) {
212
+ // lines / split
213
+ const lines = stdout.toString().split('\n');
214
+ result = parseUsersDarwin(lines);
215
+ }
216
+ if (callback) {
217
+ callback(result);
218
+ }
219
+ resolve(result);
220
+ });
221
+ }
222
+ if (_sunos) {
223
+ exec('who; echo "---"; w -h', (error, stdout) => {
224
+ if (!error) {
225
+ // lines / split
226
+ const lines = stdout.toString().split('\n');
227
+ result = parseUsersDarwin(lines);
228
+ }
229
+ if (callback) {
230
+ callback(result);
231
+ }
232
+ resolve(result);
233
+ });
234
+ }
235
+
236
+ if (_darwin) {
237
+ exec('export LC_ALL=C; who; echo "---"; w -ih; unset LC_ALL', (error, stdout) => {
238
+ if (!error) {
239
+ // lines / split
240
+ const lines = stdout.toString().split('\n');
241
+ result = parseUsersDarwin(lines);
242
+ }
243
+ if (callback) {
244
+ callback(result);
245
+ }
246
+ resolve(result);
247
+ });
248
+ }
249
+ if (_windows) {
250
+ try {
251
+ let cmd = 'Get-CimInstance Win32_LogonSession | select LogonId,@{n="StartTime";e={$_.StartTime.ToString("yyyy-MM-dd HH:mm:ss")}} | fl' + "; echo '#-#-#-#';";
252
+ cmd += 'Get-CimInstance Win32_LoggedOnUser | select antecedent,dependent | fl ' + "; echo '#-#-#-#';";
253
+ cmd +=
254
+ "$process = (Get-CimInstance Win32_Process -Filter \"name = 'explorer.exe'\"); Invoke-CimMethod -InputObject $process[0] -MethodName GetOwner | select user, domain | fl; get-process -name explorer | select-object sessionid | fl; echo '#-#-#-#';";
255
+ cmd += 'query user';
256
+ util.powerShell(cmd).then((data) => {
257
+ if (data) {
258
+ data = data.split('#-#-#-#');
259
+ const sessions = parseWinSessions((data[0] || '').split(/\n\s*\n/));
260
+ const loggedons = parseWinLoggedOn((data[1] || '').split(/\n\s*\n/));
261
+ const queryUser = parseWinUsersQuery((data[3] || '').split('\r\n'));
262
+ const users = parseWinUsers((data[2] || '').split(/\n\s*\n/), queryUser);
263
+ for (let id in loggedons) {
264
+ if ({}.hasOwnProperty.call(loggedons, id)) {
265
+ loggedons[id].dateTime = {}.hasOwnProperty.call(sessions, id) ? sessions[id] : '';
266
+ }
267
+ }
268
+ users.forEach((user) => {
269
+ let dateTime = '';
270
+ for (let id in loggedons) {
271
+ if ({}.hasOwnProperty.call(loggedons, id)) {
272
+ if (loggedons[id].user === user.user && (!dateTime || dateTime < loggedons[id].dateTime)) {
273
+ dateTime = loggedons[id].dateTime;
274
+ }
275
+ }
276
+ }
277
+
278
+ result.push({
279
+ user: user.user,
280
+ tty: user.tty,
281
+ date: `${dateTime.substring(0, 10)}`,
282
+ time: `${dateTime.substring(11, 19)}`,
283
+ ip: '',
284
+ command: ''
285
+ });
286
+ });
287
+ }
288
+ if (callback) {
289
+ callback(result);
290
+ }
291
+ resolve(result);
292
+ });
293
+ } catch {
294
+ if (callback) {
295
+ callback(result);
296
+ }
297
+ resolve(result);
298
+ }
299
+ }
300
+ });
301
+ });
302
+ }
303
+
304
+ function parseWinSessions(sessionParts) {
305
+ const sessions = {};
306
+ sessionParts.forEach((session) => {
307
+ const lines = session.split('\r\n');
308
+ const id = util.getValue(lines, 'LogonId');
309
+ const starttime = util.getValue(lines, 'starttime');
310
+ if (id) {
311
+ sessions[id] = starttime;
312
+ }
313
+ });
314
+ return sessions;
315
+ }
316
+
317
+ function fuzzyMatch(name1, name2) {
318
+ name1 = name1.toLowerCase();
319
+ name2 = name2.toLowerCase();
320
+ let eq = 0;
321
+ let len = name1.length;
322
+ if (name2.length > len) {
323
+ len = name2.length;
324
+ }
325
+
326
+ for (let i = 0; i < len; i++) {
327
+ const c1 = name1[i] || '';
328
+ const c2 = name2[i] || '';
329
+ if (c1 === c2) {
330
+ eq++;
331
+ }
332
+ }
333
+ return len > 10 ? eq / len > 0.9 : len > 0 ? eq / len > 0.8 : false;
334
+ }
335
+
336
+ function parseWinUsers(userParts, userQuery) {
337
+ const users = [];
338
+ userParts.forEach((user) => {
339
+ const lines = user.split('\r\n');
340
+
341
+ const domain = util.getValue(lines, 'domain', ':', true);
342
+ const username = util.getValue(lines, 'user', ':', true);
343
+ const sessionid = util.getValue(lines, 'sessionid', ':', true);
344
+
345
+ if (username) {
346
+ const quser = userQuery.filter((item) => fuzzyMatch(item.user, username));
347
+ users.push({
348
+ domain,
349
+ user: username,
350
+ tty: quser && quser[0] && quser[0].tty ? quser[0].tty : sessionid
351
+ });
352
+ }
353
+ });
354
+ return users;
355
+ }
356
+
357
+ function parseWinLoggedOn(loggedonParts) {
358
+ const loggedons = {};
359
+ loggedonParts.forEach((loggedon) => {
360
+ const lines = loggedon.split('\r\n');
361
+
362
+ const antecendent = util.getValue(lines, 'antecedent', ':', true);
363
+ let parts = antecendent.split('=');
364
+ const name = parts.length > 2 ? parts[1].split(',')[0].replace(/"/g, '').trim() : '';
365
+ const domain = parts.length > 2 ? parts[2].replace(/"/g, '').replace(/\)/g, '').trim() : '';
366
+ const dependent = util.getValue(lines, 'dependent', ':', true);
367
+ parts = dependent.split('=');
368
+ const id = parts.length > 1 ? parts[1].replace(/"/g, '').replace(/\)/g, '').trim() : '';
369
+ if (id) {
370
+ loggedons[id] = {
371
+ domain,
372
+ user: name
373
+ };
374
+ }
375
+ });
376
+ return loggedons;
377
+ }
378
+
379
+ function parseWinUsersQuery(lines) {
380
+ lines = lines.filter((item) => item);
381
+ let result = [];
382
+ const header = lines[0];
383
+ const headerDelimiter = [];
384
+ if (header) {
385
+ const start = header[0] === ' ' ? 1 : 0;
386
+ headerDelimiter.push(start - 1);
387
+ let nextSpace = 0;
388
+ for (let i = start + 1; i < header.length; i++) {
389
+ if (header[i] === ' ' && (header[i - 1] === ' ' || header[i - 1] === '.')) {
390
+ nextSpace = i;
391
+ } else {
392
+ if (nextSpace) {
393
+ headerDelimiter.push(nextSpace);
394
+ nextSpace = 0;
395
+ }
396
+ }
397
+ }
398
+ for (let i = 1; i < lines.length; i++) {
399
+ if (lines[i].trim()) {
400
+ const user = lines[i].substring(headerDelimiter[0] + 1, headerDelimiter[1]).trim() || '';
401
+ const tty = lines[i].substring(headerDelimiter[1] + 1, headerDelimiter[2] - 2).trim() || '';
402
+ result.push({
403
+ user: user,
404
+ tty: tty
405
+ });
406
+ }
407
+ }
408
+ }
409
+ return result;
410
+ }
411
+
412
+ exports.users = users;