Skip to content

Commit

Permalink
os: add userInfo() method
Browse files Browse the repository at this point in the history
os.userInfo() calls libuv's uv_os_get_passwd() function. It returns
an object containing the current effective user's username, uid,
gid, shell, and home directory. On Windows, the uid and gid are
-1, and the shell is null.

Refs: nodejs#5582
PR-URL: nodejs#6104
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
cjihrig committed Apr 12, 2016
1 parent aba035f commit d6e56fd
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 0 deletions.
16 changes: 16 additions & 0 deletions doc/api/os.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,21 @@ on OS X and `'Windows_NT'` on Windows.

Returns the system uptime in seconds.

## os.userInfo([options])

* `options` {Object}
* `encoding` {String} Character encoding used to interpret resulting strings.
If `encoding` is set to `'buffer'`, the `username`, `shell`, and `homedir`
values will be `Buffer` instances. (Default: 'utf8')

Returns a subset of the password file entry for the current effective user. The
returned object includes the `username`, `uid`, `gid`, `shell`, and `homedir`.
On Windows, the `uid` and `gid` fields are `-1`, and `shell` is `null`.

The value of `homedir` returned by `userInfo()` comes directly from the
operating system. This differs from the result of `os.homedir()`, which queries
several environment variables for the home directory before falling back to the
operating system response.

[`process.arch`]: process.html#process_process_arch
[`process.platform`]: process.html#process_process_platform
1 change: 1 addition & 0 deletions lib/os.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ exports.type = binding.getOSType;
exports.release = binding.getOSRelease;
exports.networkInterfaces = binding.getInterfaceAddresses;
exports.homedir = binding.getHomeDirectory;
exports.userInfo = binding.getUserInfo;


exports.arch = function() {
Expand Down
4 changes: 4 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ namespace node {
V(exchange_string, "exchange") \
V(idle_string, "idle") \
V(irq_string, "irq") \
V(encoding_string, "encoding") \
V(enter_string, "enter") \
V(env_pairs_string, "envPairs") \
V(env_string, "env") \
Expand Down Expand Up @@ -121,6 +122,7 @@ namespace node {
V(handle_string, "handle") \
V(heap_total_string, "heapTotal") \
V(heap_used_string, "heapUsed") \
V(homedir_string, "homedir") \
V(hostmaster_string, "hostmaster") \
V(ignore_string, "ignore") \
V(immediate_callback_string, "_immediateCallback") \
Expand Down Expand Up @@ -206,6 +208,7 @@ namespace node {
V(service_string, "service") \
V(servername_string, "servername") \
V(session_id_string, "sessionId") \
V(shell_string, "shell") \
V(signal_string, "signal") \
V(size_string, "size") \
V(sni_context_err_string, "Invalid SNI context") \
Expand Down Expand Up @@ -235,6 +238,7 @@ namespace node {
V(uid_string, "uid") \
V(unknown_string, "<unknown>") \
V(user_string, "user") \
V(username_string, "username") \
V(uv_string, "uv") \
V(valid_from_string, "valid_from") \
V(valid_to_string, "valid_to") \
Expand Down
69 changes: 69 additions & 0 deletions src/node_os.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "v8.h"
#include "env.h"
#include "env-inl.h"
#include "string_bytes.h"

#include <errno.h>
#include <string.h>
Expand Down Expand Up @@ -32,6 +33,7 @@ using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Integer;
using v8::Local;
using v8::Null;
using v8::Number;
using v8::Object;
using v8::String;
Expand Down Expand Up @@ -290,6 +292,72 @@ static void GetHomeDirectory(const FunctionCallbackInfo<Value>& args) {
}


static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
uv_passwd_t pwd;
enum encoding encoding;

if (args[0]->IsObject()) {
Local<Object> options = args[0].As<Object>();
Local<Value> encoding_opt = options->Get(env->encoding_string());
encoding = ParseEncoding(env->isolate(), encoding_opt, UTF8);
} else {
encoding = UTF8;
}

const int err = uv_os_get_passwd(&pwd);

if (err) {
return env->ThrowUVException(err, "uv_os_get_passwd");
}

Local<Value> uid = Number::New(env->isolate(), pwd.uid);
Local<Value> gid = Number::New(env->isolate(), pwd.gid);
Local<Value> username = StringBytes::Encode(env->isolate(),
pwd.username,
encoding);
Local<Value> homedir = StringBytes::Encode(env->isolate(),
pwd.homedir,
encoding);
Local<Value> shell;

if (pwd.shell == NULL)
shell = Null(env->isolate());
else
shell = StringBytes::Encode(env->isolate(), pwd.shell, encoding);

uv_os_free_passwd(&pwd);

if (username.IsEmpty()) {
return env->ThrowUVException(UV_EINVAL,
"uv_os_get_passwd",
"Invalid character encoding for username");
}

if (homedir.IsEmpty()) {
return env->ThrowUVException(UV_EINVAL,
"uv_os_get_passwd",
"Invalid character encoding for homedir");
}

if (shell.IsEmpty()) {
return env->ThrowUVException(UV_EINVAL,
"uv_os_get_passwd",
"Invalid character encoding for shell");
}

Local<Object> entry = Object::New(env->isolate());

entry->Set(env->uid_string(), uid);
entry->Set(env->gid_string(), gid);
entry->Set(env->username_string(), username);
entry->Set(env->homedir_string(), homedir);
entry->Set(env->shell_string(), shell);

args.GetReturnValue().Set(entry);
}


void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context) {
Expand All @@ -304,6 +372,7 @@ void Initialize(Local<Object> target,
env->SetMethod(target, "getOSRelease", GetOSRelease);
env->SetMethod(target, "getInterfaceAddresses", GetInterfaceAddresses);
env->SetMethod(target, "getHomeDirectory", GetHomeDirectory);
env->SetMethod(target, "getUserInfo", GetUserInfo);
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"),
Boolean::New(env->isolate(), IsBigEndian()));
}
Expand Down
24 changes: 24 additions & 0 deletions test/parallel/test-os.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,27 @@ if (common.isWindows && process.env.USERPROFILE) {
assert.ok(os.homedir().indexOf(path.sep) !== -1);
process.env.HOME = home;
}

const pwd = os.userInfo();
const pwdBuf = os.userInfo({ encoding: 'buffer' });

if (common.isWindows) {
assert.strictEqual(pwd.uid, -1);
assert.strictEqual(pwd.gid, -1);
assert.strictEqual(pwd.shell, null);
assert.strictEqual(pwdBuf.uid, -1);
assert.strictEqual(pwdBuf.gid, -1);
assert.strictEqual(pwdBuf.shell, null);
} else {
assert.strictEqual(typeof pwd.uid, 'number');
assert.strictEqual(typeof pwd.gid, 'number');
assert.notStrictEqual(pwd.shell.indexOf(path.sep), -1);
assert.strictEqual(pwd.uid, pwdBuf.uid);
assert.strictEqual(pwd.gid, pwdBuf.gid);
assert.strictEqual(pwd.shell, pwdBuf.shell.toString('utf8'));
}

assert.strictEqual(typeof pwd.username, 'string');
assert.notStrictEqual(pwd.homedir.indexOf(path.sep), -1);
assert.strictEqual(pwd.username, pwdBuf.username.toString('utf8'));
assert.strictEqual(pwd.homedir, pwdBuf.homedir.toString('utf8'));

0 comments on commit d6e56fd

Please sign in to comment.