benefit to reading sensitive file chunks via a "middleman" shell script?
tldr: is using a script spawned by my main process, which reads only a chunk of a sensitive file then passing the result to my main process - of any benefit?
in contrast to loading the file in my main process?
background:
I'm building my first CLI app as a personal project. The CLI app is supposed to be downloadable/installable by 3rd party users.
The app uses a Personal Access Token to authenticate the user with service A (which they already use) and perform some useful utilities.
- The user is instructed to:
- Log in to his account with service A.
- Create a token (with the smallest amount of scope/least-priviledges) as possible..
- Save the token in their netrc file.
This is an atrocious UX flow, but for starters it does the job.
The problem I have is that the .netrc
file contains credentials for other services.
I absolutely do not want to compromise those credentials for my users and bearing
in mind I am a careless person that doesn't know any better sometimes, I have thought
of the following process:
Rather than read the entire file in my own process:
- Create a script that searches for a match in
netrc
. - The scripts takes only 1 parameter, an env. variable
FILEPATH
which points to the.netrc
location. The matching keyword and the number of lines to match are not parameterised. - If a match is found, it reads the next 2 lines + the matching line.
- Echoes it back to my process.
The purpose of this is simple (to me at least):
I don't want to load the entire netrc
of the user in my own process.
Is this an entirely stupid idea? Semi-stupid?
Here's the scripts I'm using:
get-netrc-chunk
.
greps for "api.foo.com". If found, fetch it, plus the next 2 lines.
reads env. var
NRCPATH
which points to the.netrc
path.unix-only for now.
#!/usr/bin/env bash
CLEAN_NRCPATH=${NRCPATH//[^/a-zA-Z0-9]/}
grep -A2 "api.foo.com" "$CLEAN_NRCPATH" | grep -v -- "^--$"
get-netrc-chunk.js
.
executes the shell script: get-netrc-chunk
via childProcess.execFile
:
- does not pass shell arguments
- sets an env. var:
NRCPATH
pointing to the.netrc
file path, which it calculates by joininghomedir
and~/.netrc
import { join } from 'node:path'
import { promisify } from 'node:util'
import { execFile as execFileAsync } from 'node:child_process'
import { chmod } from 'node:fs/promises'
import { homedir } from 'node:os'
const execFile = promisify(execFileAsync)
const grepChunkFromNetRC = async () => {
// import the shell script file
const netrcEntry = join(import.meta.dirname, 'grep-netrc-chunk')
// elevate permissions to "read & execute"
await chmod(netrcEntry, 0o500)
// execute the shell script
const { stdout, stderr } = await execFile(netrcEntry, {
windowsHide: true,
maxBuffer: 256,
env: Object.freeze({ NRCPATH: join(homedir(), '.netrc') })
})
// downgrade permissions
await chmod(netrcEntry, 0o000)
if (stderr.length)
throw new Error(stderr)
// split stdout by newline and return the first 3 lines
// this is already done by the shell script, but since
// today is an all-you-can-eat paranoia buffet, do it here too.
return Object.freeze(stdout.trim().split('\n').slice(0, 3))
}
export { grepChunkFromNetRC }