rspec-pgp_matchers 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -5
- data/.yardopts +4 -0
- data/PROTECTED_KEYS.adoc +99 -0
- data/README.adoc +23 -0
- data/bin/console +4 -4
- data/ci/gemfiles/rspec-3.4.gemfile +1 -3
- data/ci/gemfiles/rspec-3.5.gemfile +1 -3
- data/ci/gemfiles/rspec-3.6.gemfile +1 -3
- data/ci/gemfiles/rspec-3.7.gemfile +1 -3
- data/lib/rspec/pgp_matchers.rb +27 -1
- data/lib/rspec/pgp_matchers/gpg_matcher_helper.rb +4 -0
- data/lib/rspec/pgp_matchers/gpg_runner.rb +25 -1
- data/lib/rspec/pgp_matchers/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4715837cead4425a9b36c7f7b722d5d64c0910e0987a8ea1c8b56b5c06ef1372
|
4
|
+
data.tar.gz: 713c60d3e6196483f586ec1026eec5b3a4d05155e3540f8207bb24ad116ed711
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec96116566ec3b4bded4fd3b78566ae567a4d6d69fce22b9b9d8627f4767ffde79b729613e185f4bbb9f10df91e8422df7a7e19ba2255d96ea098ef5d96f0faa
|
7
|
+
data.tar.gz: 8e6d0397bbe146ec9804074a3455a5cb51f3e2cb60eae25f0464748d6c5a1e92a7e9fb83d431afa22907e34e4a940fe1d8f03aba18852752254d434f3028e0c7
|
data/.travis.yml
CHANGED
data/.yardopts
ADDED
data/PROTECTED_KEYS.adoc
ADDED
@@ -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
|
data/README.adoc
CHANGED
@@ -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.
|
data/bin/console
CHANGED
@@ -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
|
-
|
11
|
-
|
10
|
+
require "pry"
|
11
|
+
Pry.start
|
12
12
|
|
13
|
-
require "irb"
|
14
|
-
IRB.start(__FILE__)
|
13
|
+
# require "irb"
|
14
|
+
# IRB.start(__FILE__)
|
data/lib/rspec/pgp_matchers.rb
CHANGED
@@ -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,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
|
-
|
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)
|
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.
|
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-
|
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
|
-
|
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
|