user321418
user321418

Reputation: 27

Send string to pipe without echoing to terminal

I am trying to write a simple wrapper for the command line tool pwsafe. I am doing something like this:

def fetch_app_password
  master_password = driver.get # this reliably fetches the correct master password
  open( "| pwsafe", 'r+' ) do |pwsafe-pipe|
    pwsafe_pipe.write(master_password + "\n")
    app_password = pwsafe_pipe.read()
    return app_password
  end
  raise 'an error occurred'
end

This code is correct in that it fetches the correct application password. The trouble is that you can see the exchange on the terminal:

enter passphrase for /home/user/pwsafe.dat: $oup3rSeKr!T

This is not so secure against shoulder surfers. I'd like to prevent the password being sent to the pipe from ending up on my terminal in cleartext. I would appreciate suggestions.

Update: some code I've tried

def fetch_app_password
  master_password = driver.get
  open( "| pwsafe", 'r+' ).noecho do |pwsafe-pipe|
    pwsafe_pipe.write(master_password + "\n")
    app_password = pwsafe_pipe.read()
    return app_password
  end
  raise 'an error occurred'
end

def fetch_app_password
  master_password = driver.get
  open3.Popen("pwsafe") do |stdin, stdout, stderr, ignored|
    stdin.noecho { |stdin| stdin.write( master_password + "\n") }
    app_password = stdout.noecho { |stdout| stdout.readline() }
    return app_password
  end
  raise 'an error occurred'
end

Both of those implementtions raise the exception inappropriate ioctl for device (errno::NOTTY) when I try to call noecho. Calling noecho on the outside console has no effect.

Upvotes: 0

Views: 666

Answers (1)

Max
Max

Reputation: 22325

I believe the problem lies with pwsafe itself. To demonstrate why, I made a little test script with Ruby that reads stdin and writes to both stdout and stderr:

# streams.rb
STDERR.print "Input text to reverse: "
STDOUT.puts STDIN.read.reverse

Then I ran it using open3

require 'open3'
Open3.popen3('./streams.rb') do |stdin, stdout, stderr, thr|
  stdin.write("Super secret password")
  stdin.close

  puts "OUT: #{stdout.read}"
  puts "ERR: #{stderr.read}"
end

And the only output that appears are the two puts:

OUT: drowssap terces repuS
ERR: Input text to reverse:

If your script is still outputting other stuff to the command line, either you aren't showing us all the relevant code or the problem lies entirely outside Ruby.

Upvotes: 1

Related Questions