rspec-pgp_matchers 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1ede8d3cd2fbc6cea19ba3d0c1dbce8cf0b390239869beec38fe4f6da3e607b
4
- data.tar.gz: 6b090779819012e1697e460e78a41cc85d4eaa1687e24441a136f268ebc29c61
3
+ metadata.gz: 4715837cead4425a9b36c7f7b722d5d64c0910e0987a8ea1c8b56b5c06ef1372
4
+ data.tar.gz: 713c60d3e6196483f586ec1026eec5b3a4d05155e3540f8207bb24ad116ed711
5
5
  SHA512:
6
- metadata.gz: f30291f6f0f4eb68a1e3d42e5bdab7208722f4998a0d8e0c17edae16e903fb031864c94005c816aca76b8b52ad6b22b8b240c23708302f94f17220a34517f9be
7
- data.tar.gz: 9e49089ab7d42085d1ac94d6807a83408010ba4c17665cb70040b12febb41f301f43cdd4d630f1c463450fdf7028bc7663064d2a78ad351c6bb0a052ee92d3db
6
+ metadata.gz: ec96116566ec3b4bded4fd3b78566ae567a4d6d69fce22b9b9d8627f4767ffde79b729613e185f4bbb9f10df91e8422df7a7e19ba2255d96ea098ef5d96f0faa
7
+ data.tar.gz: 8e6d0397bbe146ec9804074a3455a5cb51f3e2cb60eae25f0464748d6c5a1e92a7e9fb83d431afa22907e34e4a940fe1d8f03aba18852752254d434f3028e0c7
@@ -1,12 +1,11 @@
1
- dist: trusty
1
+ dist: bionic
2
2
  language: ruby
3
- sudo: true
4
3
 
5
4
  rvm:
6
- - "2.3"
7
- - "2.4"
8
- - "2.5"
9
5
  - "2.6"
6
+ - "2.5"
7
+ - "2.4"
8
+ - "2.3"
10
9
  - "ruby-head"
11
10
 
12
11
  env:
@@ -0,0 +1,4 @@
1
+ -
2
+ README.adoc
3
+ LICENSE.txt
4
+ PROTECTED_KEYS.adoc
@@ -0,0 +1,99 @@
1
+ = Working with passphrase-protected keys
2
+
3
+ It is recommended not to use passphrase-protected keys with this gem.
4
+ Remember, `RSpec::PGPMatchers` are meant for testing, therefore there is
5
+ no security trade-off involved. Nevertheless, passphrase-protected keys are
6
+ supported as well. With some hassle, though…
7
+
8
+ IMPORTANT: This guide was written for GnuPG 2.2. Other versions may require
9
+ a different set of configuration options.
10
+
11
+ == Passing the passphrase in gpg.conf
12
+
13
+ This is the easier option, however it will work only if you use the same
14
+ passphrase for all the keys.
15
+
16
+ 1. Write GnuPG options to a config file located at `<pgp/home/path>/gpg.conf`:
17
+ +
18
+ ----
19
+ yes
20
+ batch
21
+ no-tty
22
+ use-agent
23
+ pinentry-mode loopback
24
+ passphrase <passphrase>
25
+ ----
26
+
27
+ 2. Write GnuPG Agent options to a config file located at
28
+ `<pgp/home/path>/gpg-agent.conf`:
29
+ +
30
+ ----
31
+ allow-loopback-pinentry
32
+ ----
33
+
34
+ 3. If GnuPG Agent was running, reload it to pick the updated configuration:
35
+ +
36
+ ----
37
+ gpgconf --homedir <pgp/home/path> --reload gpg-agent
38
+ ----
39
+
40
+ == Passphrase presetting
41
+
42
+ This is the recommended and more comprehensive solution, though also bit more
43
+ complicated.
44
+
45
+ 1. Write GnuPG options to a config file located at `<pgp/home/path>/gpg.conf`:
46
+ +
47
+ ----
48
+ yes
49
+ batch
50
+ no-tty
51
+ use-agent
52
+ ----
53
+
54
+ 2. Write GnuPG Agent options to a config file located at
55
+ `<pgp/home/path>/gpg-agent.conf`:
56
+ +
57
+ ----
58
+ allow-preset-passphrase
59
+ ----
60
+
61
+ 3. If GnuPG Agent was running, reload it to pick the updated configuration:
62
+ +
63
+ ----
64
+ gpgconf --homedir <pgp/home/path> --reload gpg-agent
65
+ ----
66
+
67
+ 4. Obtain keygrips of password-protected keys you want to use:
68
+ +
69
+ ----
70
+ gpg --homedir <pgp/home/path> --list-keys --with-keygrip
71
+ ----
72
+ +
73
+ Note that sometimes you will need a subkey's keygrip rather than primary key's
74
+ one. Subkeys are typically used for message encryption, but can be used for
75
+ signing as well.
76
+
77
+ 5. Preset passwords for keys:
78
+ +
79
+ ----
80
+ gpg-preset-passphrase --homedir <pgp/home/path> --preset --passphrase <passphrase> <keygrip>
81
+ ----
82
+ +
83
+ or (will read passphrase from standard input):
84
+ +
85
+ ----
86
+ gpg-preset-passphrase --homedir <pgp/home/path> --preset <keygrip>
87
+ ----
88
+ +
89
+ Note that `gpg-preset-passphrase` is not in `PATH` on some systems.
90
+ For instance, when GnuPG is installed on MacOS via Homebrew, it is located at
91
+ `/usr/local/opt/gnupg/libexec`, which is not in `PATH` by default.
92
+
93
+ == Resources
94
+
95
+ * The GNU Privacy Guard Manual:
96
+ ** https://gnupg.org/documentation/manuals/gnupg/GPG-Options.html#GPG-Options[GPG options]
97
+ ** https://gnupg.org/documentation/manuals/gnupg/Agent-Options.html#Agent-Options[GPG Agent options]
98
+ ** https://www.gnupg.org/documentation/manuals/gnupg/gpg_002dpreset_002dpassphrase.html#gpg_002dpreset_002dpassphrase[GPG Preset Passphrase tool]
99
+ * "link:https://wincent.com/wiki/Using_gpg-agent_on_OS_X[Using gpg-agent on OS X]" on wincent.com -- main source of inspiration for above writing
@@ -1,5 +1,7 @@
1
1
  = RSpec::PGPMatchers
2
2
 
3
+ ifdef::env-yard[:relfileprefix: file.]
4
+
3
5
  image:https://img.shields.io/gem/v/rspec-pgp_matchers.svg[
4
6
  Gem Version, link="https://rubygems.org/gems/rspec-pgp_matchers"]
5
7
  image:https://img.shields.io/travis/riboseinc/rspec-pgp_matchers/master.svg[
@@ -111,6 +113,27 @@ RSpec::PGPMatchers::GPGRunner.run_verify("cleartext", "signature_string")
111
113
  In all above cases, a triple consisting of captured standard output, captured
112
114
  standard error, and `Process::Status` instance is returned.
113
115
 
116
+ === Working with passphrase-protected keys
117
+
118
+ Consider using unprotected keys in your tests. It will save you a lot of
119
+ hassle. However, passphrase-protected keys are also supported. See
120
+ `<<PROTECTED_KEYS.adoc#,PROTECTED_KEYS.adoc>>` for details.
121
+
122
+ === Unusual GnuPG executable name
123
+
124
+ By default, this gem assumes that GnuPG executable is named `gpg`, and that
125
+ it is in `$PATH`. This behaviour can be changed, for example:
126
+
127
+ [source,ruby]
128
+ ----
129
+ RSpec::PGPMatchers.gpg_executable = "gpg2" # different executable name
130
+ RSpec::PGPMatchers.gpg_executable = "/opt/gpg/bin/gpg" # absolute path
131
+ RSpec::PGPMatchers.gpg_executable = "../gpg/bin/gpg" # relative path
132
+ ----
133
+
134
+ Avoid hardcoding values. Usually, setting a proper `$PATH` environment variable
135
+ is better than assigning an absolute path to `gpg_executable` attribute.
136
+
114
137
  == Development
115
138
 
116
139
  After checking out the repo, run `bin/setup` to install dependencies.
@@ -7,8 +7,8 @@ require "rspec/pgp_matchers"
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
9
  # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
10
+ require "pry"
11
+ Pry.start
12
12
 
13
- require "irb"
14
- IRB.start(__FILE__)
13
+ # require "irb"
14
+ # IRB.start(__FILE__)
@@ -1,5 +1,3 @@
1
- # rubocop:disable Security/Eval
2
- eval File.read(File.expand_path("common.gemfile", __dir__))
3
- # rubocop:enable Security/Eval
1
+ eval_gemfile "common.gemfile"
4
2
 
5
3
  gem "rspec-expectations", "~> 3.4.0"
@@ -1,5 +1,3 @@
1
- # rubocop:disable Security/Eval
2
- eval File.read(File.expand_path("common.gemfile", __dir__))
3
- # rubocop:enable Security/Eval
1
+ eval_gemfile "common.gemfile"
4
2
 
5
3
  gem "rspec-expectations", "~> 3.5.0"
@@ -1,5 +1,3 @@
1
- # rubocop:disable Security/Eval
2
- eval File.read(File.expand_path("common.gemfile", __dir__))
3
- # rubocop:enable Security/Eval
1
+ eval_gemfile "common.gemfile"
4
2
 
5
3
  gem "rspec-expectations", "~> 3.6.0"
@@ -1,5 +1,3 @@
1
- # rubocop:disable Security/Eval
2
- eval File.read(File.expand_path("common.gemfile", __dir__))
3
- # rubocop:enable Security/Eval
1
+ eval_gemfile "common.gemfile"
4
2
 
5
3
  gem "rspec-expectations", "~> 3.7.0"
@@ -1,6 +1,7 @@
1
1
  # (c) Copyright 2018 Ribose Inc.
2
2
  #
3
3
 
4
+ require "rspec/expectations"
4
5
  require "rspec/pgp_matchers/version"
5
6
  require "rspec/pgp_matchers/gpg_matcher_helper"
6
7
  require "rspec/pgp_matchers/gpg_runner"
@@ -9,9 +10,34 @@ require "rspec/pgp_matchers/be_a_valid_pgp_signature_of"
9
10
 
10
11
  module RSpec
11
12
  module PGPMatchers
13
+ @gpg_executable = "gpg"
14
+
12
15
  class << self
16
+ # Name of the GnuPG executable or path to that executable. Defaults to
17
+ # +gpg+.
18
+ #
19
+ # Absolute and relative paths are allowed, but usually setting +$PATH+
20
+ # environment variable is a better idea.
21
+ #
22
+ # @return [String] executable name or absolute or relative path to that
23
+ # executable
24
+ attr_accessor :gpg_executable
25
+
26
+ # Path to the OpenPGP home directory. Defaults to +nil+ and must be set
27
+ # prior using the matchers.
28
+ #
29
+ # Given directory may be initialized with other tool than GnuPG, e.g. RNP,
30
+ # but it must be in a format which is readable by GnuPG. Also,
31
+ # if specified directory is empty, then it will be initialized by GnuPG
32
+ # at first use, it must exist though. Nevertheless, the latter case is
33
+ # not very practical, as the OpenPGP home directory created this way
34
+ # contains no keys.
35
+ #
36
+ # It is recommended to have a dedicated PGP home directory just for
37
+ # testing, so that test keys are separated from regular ones.
38
+ #
39
+ # @return [String] absolute or relative path to the OpenPGP home directory
13
40
  attr_accessor :homedir
14
41
  end
15
- # Your code goes here...
16
42
  end
17
43
  end
@@ -6,6 +6,10 @@ require "tempfile"
6
6
 
7
7
  module RSpec
8
8
  module PGPMatchers
9
+ # A collection of utility methods to be included in matchers. Mostly for
10
+ # extracting information from GnuPG output.
11
+ #
12
+ # @api private
9
13
  module GPGMatcherHelper
10
14
  extend Forwardable
11
15
 
@@ -6,21 +6,39 @@ require "tempfile"
6
6
 
7
7
  module RSpec
8
8
  module PGPMatchers
9
+ # A helper module for executing GnuPG commands.
9
10
  module GPGRunner
10
11
  class << self
12
+ # Executes arbitrary GnuPG command.
13
+ #
14
+ # @param gpg_cmd [String] command to run
15
+ # @return [Array] tuple +[stdout, stderr, status]+
16
+ # like in stdlib's {Open3.capture3}
17
+ #
18
+ # @example
19
+ # # Will list all GnuPG keys
20
+ # run_command("--list-keys")
21
+ # # Will list keys and their keygrips
22
+ # run_command("--list-keys --with-keygrip")
11
23
  def run_command(gpg_cmd)
12
24
  env = { "LC_ALL" => "C" } # Gettext English locale
13
25
 
26
+ gpg_executable = Shellwords.escape(RSpec::PGPMatchers.gpg_executable)
14
27
  homedir_path = Shellwords.escape(RSpec::PGPMatchers.homedir)
15
28
 
16
29
  Open3.capture3(env, <<~SH)
17
- gpg \
30
+ #{gpg_executable} \
18
31
  --homedir #{homedir_path} \
19
32
  --no-permission-warning \
20
33
  #{gpg_cmd}
21
34
  SH
22
35
  end
23
36
 
37
+ # Decrypts a message.
38
+ #
39
+ # @param encrypted_string [String] encrypted message
40
+ # @return [Array] tuple +[stdout, stderr, status]+
41
+ # like in stdlib's {Open3.capture3}
24
42
  def run_decrypt(encrypted_string)
25
43
  enc_file = make_tempfile_containing(encrypted_string)
26
44
  cmd = gpg_decrypt_command(enc_file)
@@ -29,6 +47,12 @@ module RSpec
29
47
  File.unlink(enc_file.path)
30
48
  end
31
49
 
50
+ # Verifies a signature.
51
+ #
52
+ # @param cleartext [String] message in clear text
53
+ # @param signature_string [String] signature
54
+ # @return [Array] tuple +[stdout, stderr, status]+
55
+ # like in stdlib's {Open3.capture3}
32
56
  def run_verify(cleartext, signature_string)
33
57
  sig_file = make_tempfile_containing(signature_string)
34
58
  data_file = make_tempfile_containing(cleartext)
@@ -3,6 +3,6 @@
3
3
 
4
4
  module RSpec
5
5
  module PGPMatchers
6
- VERSION = "0.1.2".freeze
6
+ VERSION = "0.2.0".freeze
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-pgp_matchers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-12 00:00:00.000000000 Z
11
+ date: 2019-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-expectations
@@ -114,8 +114,10 @@ files:
114
114
  - ".rspec"
115
115
  - ".rubocop.yml"
116
116
  - ".travis.yml"
117
+ - ".yardopts"
117
118
  - Gemfile
118
119
  - LICENSE.txt
120
+ - PROTECTED_KEYS.adoc
119
121
  - README.adoc
120
122
  - Rakefile
121
123
  - bin/bundle
@@ -154,8 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
156
  - !ruby/object:Gem::Version
155
157
  version: '0'
156
158
  requirements: []
157
- rubyforge_project:
158
- rubygems_version: 2.7.6
159
+ rubygems_version: 3.0.3
159
160
  signing_key:
160
161
  specification_version: 4
161
162
  summary: RSpec matchers for testing OpenPGP messages