Class: IOStreams::Pgp::Writer

Inherits:
Object
  • Object
show all
Defined in:
lib/io_streams/pgp/writer.rb

Class Method Summary collapse

Class Method Details

.default_signer=(default_signer) ⇒ Object

Sign all encrypted files with this users key. Default: Do not sign encyrpted files.



8
9
10
# File 'lib/io_streams/pgp/writer.rb', line 8

def self.default_signer=(default_signer)
  @default_signer = default_signer
end

.default_signer_passphrase=(default_signer_passphrase) ⇒ Object

Passphrase to use to open the private key when signing the file. Default: None.



14
15
16
# File 'lib/io_streams/pgp/writer.rb', line 14

def self.default_signer_passphrase=(default_signer_passphrase)
  @default_signer_passphrase = default_signer_passphrase
end

.open(file_name_or_io, recipient:, signer: default_signer, signer_passphrase: default_signer_passphrase, binary: true, compression: :zip, compress_level: 6, &block) ⇒ Object

Write to a PGP / GPG file or stream, encrypting the contents as it is written

file_name_or_io: [String|IO]

Name of file to write to.
Or, the IO stream to write the encrypted contents to.

recipient: [String]

Email of user for which to encypt the file.

signer: [String]

Name of user with which to sign the encypted file.
Default: default_signer or do not sign.

signer_passphrase: [String]

Passphrase to use to open the private key when signing the file.
Default: default_signer_passphrase

binary: [true|false]

Whether to write binary data.
Default: true

compression: [:none|:zip|:zlib|:bzip2]

Note: Standard PGP only supports :zip.
:zlib is better than zip.
:bzip2 is best, but uses a lot of memory and is much slower.
Default: :zip

compress_level: [Integer]

Compression level
Default: 6


48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/io_streams/pgp/writer.rb', line 48

def self.open(file_name_or_io, recipient:, signer: default_signer, signer_passphrase: default_signer_passphrase, binary: true, compression: :zip, compress_level: 6, &block)
  compress_level = 0 if compression == :none

  if file_name_or_io.is_a?(String)
    IOStreams::File::Path.mkpath(file_name_or_io)
    return write_file(file_name_or_io, recipient: recipient, signer: signer, signer_passphrase: signer_passphrase, binary: binary, compression: compression, compress_level: compress_level, &block)
  end

  # PGP can only work against a file, not a stream, so create temp file.
  IOStreams::File::Path.temp_file_name('iostreams_pgp') do |temp_file_name|
    write_file(temp_file_name, recipient: recipient, signer: signer, signer_passphrase: signer_passphrase, binary: binary, compression: compression, compress_level: compress_level, &block)
    IOStreams.copy(temp_file_name, file_name_or_io, source_options: {streams: []})
  end
end

.write_file(file_name, recipient:, signer: default_signer, signer_passphrase: default_signer_passphrase, binary: true, compression: :zip, compress_level: 6) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/io_streams/pgp/writer.rb', line 63

def self.write_file(file_name, recipient:, signer: default_signer, signer_passphrase: default_signer_passphrase, binary: true, compression: :zip, compress_level: 6)
  # Write to stdin, with encrypted contents being written to the file
  command = "#{IOStreams::Pgp.executable} --batch --no-tty --yes --encrypt"
  command << " --sign --local-user \"#{signer}\"" if signer
  if signer_passphrase
    command << " --pinentry-mode loopback" if IOStreams::Pgp.pgp_version.to_f >= 2.1
    command << " --passphrase \"#{signer_passphrase}\""
  end
  command << " -z #{compress_level}" if compress_level != 6
  command << " --compress-algo #{compression}" unless compression == :none
  command << " --recipient \"#{recipient}\" -o \"#{file_name}\""

  IOStreams::Pgp.logger.debug { "IOStreams::Pgp::Writer.open: #{command}" } if IOStreams::Pgp.logger

  Open3.popen2e(command) do |stdin, out, waith_thr|
    begin
      stdin.binmode if binary
      yield(stdin)
      stdin.close
    rescue Errno::EPIPE
      # Ignore broken pipe because gpg terminates early due to an error
      ::File.delete(file_name) if ::File.exist?(file_name)
      raise(Pgp::Failure, "GPG Failed writing to encrypted file: #{file_name}: #{out.read.chomp}")
    end
    unless waith_thr.value.success?
      ::File.delete(file_name) if ::File.exist?(file_name)
      raise(Pgp::Failure, "GPG Failed to create encrypted file: #{file_name}: #{out.read.chomp}")
    end
  end
end