├── .editorconfig ├── .gitattributes ├── .github ├── funding.yml ├── security.md └── workflows │ └── main.yml ├── .gitignore ├── .npmrc ├── index.d.ts ├── index.js ├── index.test-d.ts ├── license ├── package.json ├── readme.md └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | github: sindresorhus 2 | open_collective: sindresorhus 3 | tidelift: npm/passwd-user 4 | custom: https://sindresorhus.com/donate 5 | -------------------------------------------------------------------------------- /.github/security.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. 4 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | - push 4 | - pull_request 5 | jobs: 6 | test: 7 | name: Node.js ${{ matrix.node-version }} on ${{ matrix.os }} 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | node-version: 13 | - 16 14 | - 14 15 | - 12 16 | os: 17 | - ubuntu-latest 18 | - macos-latest 19 | steps: 20 | - uses: actions/checkout@v2 21 | - uses: actions/setup-node@v2 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm install 25 | - run: npm test 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | export interface UserData { 2 | readonly username: string; 3 | readonly password: string; 4 | 5 | /** 6 | Also known as [UID](https://en.wikipedia.org/wiki/User_identifier). 7 | */ 8 | readonly userIdentifier: number; 9 | 10 | /** 11 | Also known as [GID](https://en.wikipedia.org/wiki/Group_identifier). 12 | */ 13 | readonly groupIdentifier: number; 14 | 15 | /** 16 | Name of user. 17 | */ 18 | readonly fullName: string; 19 | 20 | /** 21 | Home directory. 22 | */ 23 | readonly homeDirectory: string; 24 | 25 | /** 26 | Default shell. 27 | */ 28 | readonly shell: string; 29 | } 30 | 31 | /** 32 | Get the [passwd](https://en.wikipedia.org/wiki/Passwd) user entry from a username or [user identifier (UID)](https://en.wikipedia.org/wiki/User_identifier_(Unix)). 33 | 34 | @param username - The username or the [user identifier (UID)](https://en.wikipedia.org/wiki/User_identifier) to look up. Default: [`process.getuid()`](https://nodejs.org/api/process.html#process_process_getuid) (The current user). 35 | 36 | @example 37 | ``` 38 | import {passwdUser} from 'passwd-user'; 39 | 40 | console.log(await passwdUser('sindresorhus')); 41 | // { 42 | // username: 'sindresorhus', 43 | // password: '*', 44 | // userIdentifier: 501, 45 | // groupIdentifier: 20, 46 | // fullName: 'Sindre Sorhus', 47 | // homeDirectory: '/home/sindresorhus', 48 | // shell: '/bin/zsh' 49 | // } 50 | 51 | await passwdUser(501); 52 | console.log('Got entry for user 501'); 53 | 54 | const user = await passwdUser(); 55 | console.log(`Got entry for user ${user.userIdentifier}`); 56 | ``` 57 | */ 58 | export function passwdUser(username?: string | number): Promise; 59 | 60 | /** 61 | Synchronously get the [passwd](https://en.wikipedia.org/wiki/Passwd) user entry from a username or [user identifier (UID)](https://en.wikipedia.org/wiki/User_identifier_(Unix)). 62 | 63 | @param username - The user name or the [user identifier (UID)](https://en.wikipedia.org/wiki/User_identifier) to look up. Default: [`process.getuid()`](https://nodejs.org/api/process.html#process_process_getuid) (The current user). 64 | 65 | @example 66 | ``` 67 | import {passwdUserSync} from 'passwd-user'; 68 | 69 | console.log(passwdUserSync('sindresorhus')); 70 | // { 71 | // username: 'sindresorhus', 72 | // password: '*', 73 | // userIdentifier: 501, 74 | // groupIdentifier: 20, 75 | // fullName: 'Sindre Sorhus', 76 | // homeDirectory: '/home/sindresorhus', 77 | // shell: '/bin/zsh' 78 | // } 79 | 80 | passwdUserSync(501); 81 | console.log('Got entry for user 501'); 82 | 83 | const user = passwdUserSync(); 84 | console.log(`Got entry for user ${user.userIdentifier}`); 85 | ``` 86 | */ 87 | export function passwdUserSync(username?: string | number): UserData | undefined; 88 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import fs, {promises as fsPromises} from 'node:fs'; 3 | import execa from 'execa'; 4 | 5 | function extractDarwin(line) { 6 | const columns = line.split(':'); 7 | 8 | // Darwin passwd(5) 9 | // 0 name User's login name. 10 | // 1 password User's encrypted password. 11 | // 2 uid User's id. 12 | // 3 gid User's login group id. 13 | // 4 class User's general classification (unused). 14 | // 5 change Password change time. 15 | // 6 expire Account expiration time. 16 | // 7 gecos User's full name. 17 | // 8 home_dir User's home directory. 18 | // 9 shell User's login shell. 19 | 20 | return { 21 | username: columns[0], 22 | password: columns[1], 23 | userIdentifier: Number(columns[2]), 24 | groupIdentifier: Number(columns[3]), 25 | fullName: columns[7], 26 | homeDirectory: columns[8], 27 | shell: columns[9], 28 | }; 29 | } 30 | 31 | function extractLinux(line) { 32 | const columns = line.split(':'); 33 | 34 | // Linux passwd(5): 35 | // 0 login name 36 | // 1 optional encrypted password 37 | // 2 numerical user ID 38 | // 3 numerical group ID 39 | // 4 user name or comment field 40 | // 5 user home directory 41 | // 6 optional user command interpreter 42 | 43 | return { 44 | username: columns[0], 45 | password: columns[1], 46 | userIdentifier: Number(columns[2]), 47 | groupIdentifier: Number(columns[3]), 48 | fullName: columns[4] && columns[4].split(',')[0], 49 | homeDirectory: columns[5], 50 | shell: columns[6], 51 | }; 52 | } 53 | 54 | const extract = process.platform === 'linux' ? extractLinux : extractDarwin; 55 | 56 | function getUser(passwd, username) { 57 | const lines = passwd.split('\n'); 58 | const linesCount = lines.length; 59 | let index = 0; 60 | 61 | while (index < linesCount) { 62 | const user = extract(lines[index++]); 63 | 64 | if (user.username === username || user.userIdentifier === Number(username)) { 65 | return user; 66 | } 67 | } 68 | } 69 | 70 | export async function passwdUser(username) { 71 | if (username === undefined) { 72 | if (typeof process.getuid !== 'function') { 73 | // eslint-disable-next-line unicorn/prefer-type-error 74 | throw new Error('Platform not supported'); 75 | } 76 | 77 | username = process.getuid(); 78 | } 79 | 80 | if (process.platform === 'linux') { 81 | return getUser(await fsPromises.readFile('/etc/passwd', 'utf8'), username); 82 | } 83 | 84 | if (process.platform === 'darwin') { 85 | const {stdout} = await execa('/usr/bin/id', ['-P', username]); 86 | return getUser(stdout, username); 87 | } 88 | 89 | throw new Error('Platform not supported'); 90 | } 91 | 92 | export function passwdUserSync(username) { 93 | if (username === undefined) { 94 | if (typeof process.getuid !== 'function') { 95 | // eslint-disable-next-line unicorn/prefer-type-error 96 | throw new Error('Platform not supported'); 97 | } 98 | 99 | username = process.getuid(); 100 | } 101 | 102 | if (process.platform === 'linux') { 103 | return getUser(fs.readFileSync('/etc/passwd', 'utf8'), username); 104 | } 105 | 106 | if (process.platform === 'darwin') { 107 | return getUser(execa.sync('/usr/bin/id', ['-P', username]).stdout, username); 108 | } 109 | 110 | throw new Error('Platform not supported'); 111 | } 112 | -------------------------------------------------------------------------------- /index.test-d.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import {passwdUser, passwdUserSync, UserData} from './index.js'; 3 | 4 | expectType>(passwdUser()); 5 | expectType>(passwdUser('sindresorhus')); 6 | expectType>(passwdUser(501)); 7 | expectType(passwdUserSync()); 8 | expectType(passwdUserSync('sindresorhus')); 9 | expectType(passwdUserSync(501)); 10 | 11 | const userData = passwdUserSync(); 12 | 13 | if (userData) { 14 | expectType(userData.username); 15 | expectType(userData.password); 16 | expectType(userData.userIdentifier); 17 | expectType(userData.groupIdentifier); 18 | expectType(userData.fullName); 19 | expectType(userData.homeDirectory); 20 | expectType(userData.shell); 21 | } 22 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Sindre Sorhus (https://sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passwd-user", 3 | "version": "4.0.0", 4 | "description": "Get the passwd user entry from a username or user identifier (UID)", 5 | "license": "MIT", 6 | "repository": "sindresorhus/passwd-user", 7 | "funding": "https://github.com/sponsors/sindresorhus", 8 | "author": { 9 | "name": "Sindre Sorhus", 10 | "email": "sindresorhus@gmail.com", 11 | "url": "https://sindresorhus.com" 12 | }, 13 | "type": "module", 14 | "exports": "./index.js", 15 | "engines": { 16 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 17 | }, 18 | "scripts": { 19 | "test": "xo && ava && tsd" 20 | }, 21 | "files": [ 22 | "index.js", 23 | "index.d.ts" 24 | ], 25 | "keywords": [ 26 | "passwd", 27 | "linux", 28 | "macos", 29 | "osx", 30 | "uid", 31 | "gid", 32 | "pw", 33 | "getpwuid", 34 | "posix", 35 | "unix", 36 | "shell", 37 | "home", 38 | "dir", 39 | "username", 40 | "user", 41 | "etc", 42 | "password", 43 | "passwords", 44 | "identifier" 45 | ], 46 | "dependencies": { 47 | "execa": "^5.1.1" 48 | }, 49 | "devDependencies": { 50 | "ava": "^3.15.0", 51 | "tsd": "^0.18.0", 52 | "xo": "^0.46.4" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # passwd-user 2 | 3 | > Get the [passwd](https://en.wikipedia.org/wiki/Passwd) user entry from a username or [user identifier (UID)](https://en.wikipedia.org/wiki/User_identifier_(Unix)) 4 | 5 | Works on macOS and Linux. See [`user-info`](https://github.com/sindresorhus/user-info) if you need cross-platform support. 6 | 7 | ## Install 8 | 9 | ```sh 10 | npm install passwd-user 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```js 16 | import {passwdUser} from 'passwd-user'; 17 | 18 | console.log(await passwdUser('sindresorhus')); 19 | /* 20 | { 21 | username: 'sindresorhus', 22 | password: '*', 23 | userIdentifier: 501, 24 | groupIdentifier: 20, 25 | fullName: 'Sindre Sorhus', 26 | homeDirectory: '/home/sindresorhus', 27 | shell: '/bin/zsh' 28 | } 29 | */ 30 | 31 | await passwdUser(501); 32 | console.log('Got entry for user 501'); 33 | 34 | const user = await passwdUser(); 35 | console.log(`Got entry for user ${user.userIdentifier}`); 36 | ``` 37 | 38 | ## API 39 | 40 | Returns an object with: 41 | 42 | - `username` 43 | - `password` 44 | - `userIdentifier`: [UID](https://en.wikipedia.org/wiki/User_identifier) 45 | - `groupIdentifier`: [GID](https://en.wikipedia.org/wiki/Group_identifier) 46 | - `fullName`: Name of user 47 | - `homeDirectory`: Home directory 48 | - `shell`: Default shell 49 | 50 | ### passwdUser(username?) 51 | ### passwdUser(userIdentifier?) 52 | 53 | Returns a `Promise` with the user entry. 54 | 55 | ### passwdUserSync(username?) 56 | ### passwdUserSync(userIdentifier?) 57 | 58 | Returns an `object` with the user entry. 59 | 60 | #### username 61 | 62 | Type: `string` 63 | 64 | The username to look up. 65 | 66 | #### userIdentifier 67 | 68 | Type: `number`\ 69 | Default: [`process.getuid()`](https://nodejs.org/api/process.html#process_process_getuid) (The current user) 70 | 71 | The [user identifier (UID)](https://en.wikipedia.org/wiki/User_identifier) to look up. 72 | 73 | ## Related 74 | 75 | - [username](https://github.com/sindresorhus/username) - Get the user's username *(cross-platform)* 76 | - [fullname](https://github.com/sindresorhus/fullname) - Get the user's fullname *(cross-platform)* 77 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import process from 'node:process'; 2 | import test from 'ava'; 3 | import {passwdUser, passwdUserSync} from './index.js'; 4 | 5 | const homeDirectory = process.platform === 'linux' ? '/root' : '/var/root'; 6 | 7 | test('async', async t => { 8 | t.is((await passwdUser('root')).homeDirectory, homeDirectory); 9 | }); 10 | 11 | test('sync', t => { 12 | t.is(passwdUserSync('root').userIdentifier, 0); 13 | t.is(passwdUserSync(0).username, 'root'); 14 | t.is(passwdUserSync('root').homeDirectory, homeDirectory); 15 | }); 16 | --------------------------------------------------------------------------------