Class: IOStreams::Pgp::Writer

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

Class Attribute Summary collapse

Attributes inherited from Writer

#output_stream

Class Method Summary collapse

Methods inherited from Writer

#initialize, open, stream

Constructor Details

This class inherits a constructor from IOStreams::Writer

Class Attribute Details

.audit_recipientObject

Encrypt all pgp output files with this recipient for audit purposes. Allows the generated pgp files to be decrypted with this email address. Useful for audit or problem resolution purposes.



18
19
20
# File 'lib/io_streams/pgp/writer.rb', line 18

def audit_recipient
  @audit_recipient
end

.default_signer=(value) ⇒ Object

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



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

def default_signer=(value)
  @default_signer = value
end

.default_signer_passphrase=(value) ⇒ Object

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



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

def default_signer_passphrase=(value)
  @default_signer_passphrase = value
end

Class Method Details

.file(file_name, recipient: nil, import_and_trust_key: nil, signer: default_signer, signer_passphrase: default_signer_passphrase, compression: :zip, compress_level: 6, original_file_name: nil) ⇒ Object

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

file_name: [String]

Name of file to write to.

recipient: [String|Array<String>]

One or more emails of users for which to encrypt the file.

import_and_trust_key: [String|Array<String>]

One or more pgp keys to import and then use to encrypt the file.
Note: Ascii Keys can contain multiple keys, only the last one in the file is used.

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

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

Raises:

  • (ArgumentError)


59
60
61
62
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/io_streams/pgp/writer.rb', line 59

def self.file(file_name,
              recipient: nil,
              import_and_trust_key: nil,
              signer: default_signer,
              signer_passphrase: default_signer_passphrase,
              compression: :zip,
              compress_level: 6,
              original_file_name: nil)

  raise(ArgumentError, "Requires either :recipient or :import_and_trust_key") unless recipient || import_and_trust_key

  compress_level = 0 if compression == :none

  recipients = Array(recipient)
  recipients << audit_recipient if audit_recipient

  Array(import_and_trust_key).each do |key|
    recipients << IOStreams::Pgp.import_and_trust(key: key)
  end

  # 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
  recipients.each { |address| command << " --recipient \"#{address}\"" }
  command << " -o \"#{file_name}\""

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

  Open3.popen2e(command) do |stdin, out, waith_thr|
    begin
      stdin.binmode
      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