Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

node-process-watcher

Package Overview
Dependencies
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-process-watcher - npm Package Compare versions

Comparing version
1.6.2
to
1.6.3
+2
-2
package.json
{
"name": "node-process-watcher",
"version": "1.6.2",
"version": "1.6.3",
"description": "Get process information in real time",

@@ -47,3 +47,3 @@ "main": "./src/index.js",

"mocha": "^10.7.3",
"node-addon-api": "^8.5.0",
"node-addon-api": "^8.6.0",
"node-gyp": "^10.3.1",

@@ -50,0 +50,0 @@ "prebuild": "^13.0.1"

@@ -435,2 +435,34 @@

return processes;
}
Napi::Value getUsernameByUid(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 1 || !info[0].IsNumber()) {
Napi::TypeError::New(env, "UID required").ThrowAsJavaScriptException();
return env.Null();
}
uid_t uid = static_cast<uid_t>(info[0].As<Napi::Number>().Uint32Value());
struct passwd *pw = getpwuid(uid);
if (!pw) return env.Null();
return Napi::String::New(env, pw->pw_name);
}
Napi::Array getAllUsers(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::Array arr = Napi::Array::New(env);
struct passwd *pw;
setpwent();
uint32_t idx = 0;
while ((pw = getpwent()) != nullptr) {
Napi::Object obj = Napi::Object::New(env);
obj.Set("uid", static_cast<uint32_t>(pw->pw_uid));
obj.Set("username", pw->pw_name);
arr.Set(idx++, obj);
}
endpwent();
return arr;
}

@@ -651,2 +651,35 @@ #include <napi.h>

return result;
}
Napi::Value getUsernameByUid(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 1 || !info[0].IsNumber()) {
Napi::TypeError::New(env, "UID required").ThrowAsJavaScriptException();
return env.Null();
}
uid_t uid = static_cast<uid_t>(info[0].As<Napi::Number>().Uint32Value());
struct passwd *pw = getpwuid(uid);
if (!pw) return env.Null();
return Napi::String::New(env, pw->pw_name);
}
Napi::Array getAllUsers(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::Array arr = Napi::Array::New(env);
struct passwd *pw;
setpwent();
uint32_t idx = 0;
while ((pw = getpwent()) != nullptr) {
Napi::Object obj = Napi::Object::New(env);
obj.Set("uid", static_cast<uint32_t>(pw->pw_uid));
obj.Set("username", pw->pw_name);
arr.Set(idx++, obj);
}
endpwent();
return arr;
}

@@ -418,2 +418,4 @@

Napi::Function::New(env, get_all_processes));
exports.Set("get_username_by_uid", Napi::Function::New(env, getUsernameByUid));
exports.Set("get_all_users", Napi::Function::New(env, getAllUsers));
#ifdef _WIN32

@@ -425,2 +427,3 @@ // windwos 下才注册的函数

);
exports.Set("get_file_owner", Napi::Function::New(env, GetFileOwner));
#endif

@@ -427,0 +430,0 @@

@@ -63,2 +63,11 @@ //

// 根据 UID 获取用户名
Napi::Value getUsernameByUid(const Napi::CallbackInfo& info);
// 获取全部用户 [{ uid, username }, ...]
Napi::Array getAllUsers(const Napi::CallbackInfo& info);
#ifdef _WIN32

@@ -71,2 +80,11 @@ // windwos 下才注册的函数

struct WindowsUser {
std::string username;
std::string domain;
std::string sid;
std::vector<std::string> groups;
};
Napi::Object GetFileOwner(const Napi::CallbackInfo& info);
#endif

@@ -10,2 +10,3 @@ #ifdef _WIN32

#pragma ide diagnostic ignored "UnreachableCode"
#pragma comment(lib, "netapi32.lib")

@@ -26,2 +27,4 @@

#include <userenv.h>
#include <lm.h>
#include <sddl.h>

@@ -677,4 +680,194 @@ #pragma comment(lib, "wininet.lib")

std::vector<WindowsUser> listWindowsUsersWithGroups() {
std::vector<WindowsUser> users;
LPUSER_INFO_1 pBuf = nullptr;
DWORD dwLevel = 1;
DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
DWORD dwEntriesRead = 0;
DWORD dwTotalEntries = 0;
DWORD dwResumeHandle = 0;
NET_API_STATUS nStatus;
do {
nStatus = NetUserEnum(
nullptr,
dwLevel,
FILTER_NORMAL_ACCOUNT,
(LPBYTE*)&pBuf,
dwPrefMaxLen,
&dwEntriesRead,
&dwTotalEntries,
&dwResumeHandle
);
if ((nStatus == NERR_Success || nStatus == ERROR_MORE_DATA) && pBuf != nullptr) {
LPUSER_INFO_1 pTmpBuf = pBuf;
for (DWORD i = 0; i < dwEntriesRead; i++) {
LPUSER_INFO_1 userInfo = &pTmpBuf[i];
WindowsUser user;
// 用户名和域
int unameLen = WideCharToMultiByte(CP_UTF8, 0, userInfo->usri1_name, -1, nullptr, 0, nullptr, nullptr);
std::vector<char> unameBuf(unameLen);
WideCharToMultiByte(CP_UTF8, 0, userInfo->usri1_name, -1, unameBuf.data(), unameLen, nullptr, nullptr);
user.username = unameBuf.data();
wchar_t domainName[256];
DWORD domainSize = 256;
SID_NAME_USE sidType;
DWORD cbSid = 0;
// 先获取 SID 大小
LookupAccountNameW(nullptr, userInfo->usri1_name, nullptr, &cbSid, nullptr, &domainSize, &sidType);
if (cbSid > 0) {
PSID pSid = (PSID)malloc(cbSid);
domainSize = 256;
if (LookupAccountNameW(nullptr, userInfo->usri1_name, pSid, &cbSid, domainName, &domainSize, &sidType)) {
// 转域名 UTF-8
int dLen = WideCharToMultiByte(CP_UTF8, 0, domainName, -1, nullptr, 0, nullptr, nullptr);
std::vector<char> domainBuf(dLen);
WideCharToMultiByte(CP_UTF8, 0, domainName, -1, domainBuf.data(), dLen, nullptr, nullptr);
user.domain = domainBuf.data();
// 转 SID 字符串
LPSTR sidString = nullptr;
ConvertSidToStringSidA(pSid, &sidString);
user.sid = sidString ? sidString : "";
if (sidString) LocalFree(sidString);
}
free(pSid);
}
// 获取用户所属本地组
LPLOCALGROUP_USERS_INFO_0 pGroupBuf = nullptr;
DWORD dwEntries = 0, dwTotal = 0;
if (NetUserGetLocalGroups(nullptr, userInfo->usri1_name, 0, LG_INCLUDE_INDIRECT, (LPBYTE*)&pGroupBuf, MAX_PREFERRED_LENGTH, &dwEntries, &dwTotal) == NERR_Success) {
for (DWORD j = 0; j < dwEntries; ++j) {
int gLen = WideCharToMultiByte(CP_UTF8, 0, pGroupBuf[j].lgrui0_name, -1, nullptr, 0, nullptr, nullptr);
std::vector<char> gBuf(gLen);
WideCharToMultiByte(CP_UTF8, 0, pGroupBuf[j].lgrui0_name, -1, gBuf.data(), gLen, nullptr, nullptr);
user.groups.push_back(gBuf.data());
}
if (pGroupBuf) NetApiBufferFree(pGroupBuf);
}
users.push_back(user);
}
NetApiBufferFree(pBuf);
pBuf = nullptr;
}
} while (nStatus == ERROR_MORE_DATA);
return users;
}
// 返回全部用户
Napi::Array getAllUsers(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::Array arr = Napi::Array::New(env);
std::vector<WindowsUser> users = listWindowsUsersWithGroups();
for (size_t i = 0; i < users.size(); i++) {
Napi::Object obj = Napi::Object::New(env);
obj.Set("username", users[i].username);
obj.Set("domain", users[i].domain);
obj.Set("sid", users[i].sid);
// groups 数组
Napi::Array groupArr = Napi::Array::New(env, users[i].groups.size());
for (size_t j = 0; j < users[i].groups.size(); j++) {
groupArr.Set(j, users[i].groups[j]);
}
obj.Set("groups", groupArr);
arr.Set(i, obj);
}
return arr;
}
// 根据 UID 获取用户名 → Windows 下返回 null
Napi::Value getUsernameByUid(const Napi::CallbackInfo& info) {
return info.Env().Null();
}
Napi::Object GetFileOwner(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 1 || !info[0].IsString()) {
Napi::TypeError::New(env, "File path expected").ThrowAsJavaScriptException();
return Napi::Object::New(env);
}
std::string filePath = info[0].As<Napi::String>().Utf8Value();
// 转为宽字符
int wlen = MultiByteToWideChar(CP_UTF8, 0, filePath.c_str(), -1, nullptr, 0);
std::wstring wFilePath(wlen, 0);
MultiByteToWideChar(CP_UTF8, 0, filePath.c_str(), -1, &wFilePath[0], wlen);
DWORD size = 0;
GetFileSecurityW(wFilePath.c_str(), OWNER_SECURITY_INFORMATION, nullptr, 0, &size);
PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)malloc(size);
if (!GetFileSecurityW(wFilePath.c_str(), OWNER_SECURITY_INFORMATION, pSD, size, &size)) {
free(pSD);
Napi::Error::New(env, "Failed to get security descriptor").ThrowAsJavaScriptException();
return Napi::Object::New(env);
}
PSID pOwner = nullptr;
BOOL ownerDefaulted = FALSE;
if (!GetSecurityDescriptorOwner(pSD, &pOwner, &ownerDefaulted)) {
free(pSD);
Napi::Error::New(env, "Failed to get owner from security descriptor").ThrowAsJavaScriptException();
return Napi::Object::New(env);
}
// 获取用户名和域名
char username[256] = {0}, domain[256] = {0};
DWORD unameLen = sizeof(username), domainLen = sizeof(domain);
SID_NAME_USE sidType;
LookupAccountSidA(nullptr, pOwner, username, &unameLen, domain, &domainLen, &sidType);
// 获取 SID 字符串
LPSTR sidString = nullptr;
ConvertSidToStringSidA(pOwner, &sidString);
// 构造返回对象
Napi::Object result = Napi::Object::New(env);
result.Set("username", std::string(username, strnlen(username, 256)));
result.Set("domain", std::string(domain, strnlen(domain, 256)));
result.Set("sid", sidString ? sidString : "");
// 根据 SID 类型判断是 user 还是 group
std::string typeStr = "unknown";
switch (sidType) {
case SidTypeUser: typeStr = "user"; break;
case SidTypeGroup: typeStr = "group"; break;
case SidTypeWellKnownGroup: typeStr = "well-known-group"; break;
case SidTypeAlias: typeStr = "alias"; break;
case SidTypeDeletedAccount: typeStr = "deleted-account"; break;
case SidTypeInvalid: typeStr = "invalid"; break;
case SidTypeUnknown: typeStr = "unknown"; break;
case SidTypeComputer: typeStr = "computer"; break;
default: typeStr = "other"; break;
}
result.Set("type", typeStr);
if (sidString) LocalFree(sidString);
free(pSD);
return result;
}
#pragma clang diagnostic pop
#endif

@@ -9,3 +9,3 @@ export interface process_info {

export interface node_process_watcher {
export interface node_process_watcher_type {

@@ -127,4 +127,21 @@ /**

get_all_processes():{pid:number,name:string}[];
get_username_by_uid(uid:number):string;
get_all_users(): ({uid:number,username:string} |
{
groups:string[],
username:string,
domain:string,
sid:string
})[];
get_file_owner(file_path:string):{
username:string,
domain:string,
sid:string,
type:string
}
}
export declare const node_process_watcher: node_process_watcher;
export declare const node_process_watcher: node_process_watcher_type;