enmail 0.1.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.
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.14.6
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at ronald.tse@ribose.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in enmail.gemspec
4
+ gemspec
@@ -0,0 +1,115 @@
1
+ # EnMail
2
+
3
+ [![Build
4
+ Status](https://travis-ci.org/riboseinc/enmail.svg?branch=master)](https://travis-ci.org/riboseinc/enmail)
5
+
6
+ EnMail (Encrypted mail) helps the Ruby mail gem send secure encrypted messages.
7
+
8
+ The two ways for secure mail are:
9
+ * OpenPGP
10
+ * S/MIME
11
+
12
+ This gem allows you to select different OpenPGP implementations
13
+ including NetPGP and GnuPG as different OpenPGP adapters, and also
14
+ S/MIME.
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem "enmail"
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ ```sh
27
+ bundle install
28
+ ```
29
+
30
+ Or install it yourself as:
31
+
32
+ ```sh
33
+ gem install enmail
34
+ ```
35
+
36
+ ## Configure
37
+
38
+ The `EnMail` gem provides a very easier interface to set custom configurations
39
+ or configure the underlying dependencies, we can configure it by adding an
40
+ initializer with the following code
41
+
42
+ ```ruby
43
+ EnMail.configure do |config|
44
+ config.sign_message = true
45
+ config.smime_adapter = :openssl
46
+ config.secret_key = "Secret Key String"
47
+
48
+ config.certificates_path = "CERTIFICATES_ROOT_PAH"
49
+ end
50
+ ```
51
+
52
+ Or
53
+
54
+ ```ruby
55
+ EnMail.configuration.certificates_path = "CERTIFICATES_ROOT_PAH"
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ```sh
61
+ bin/console
62
+ ```
63
+
64
+ ## Development
65
+
66
+ We are following Sandi Metz's Rules for this gem, you can read the
67
+ [description of the rules here][sandimetz]. All new code should follow these
68
+ rules. If you make changes in a pre-existing file that violates these rules you
69
+ should fix the violations as part of your contribution.
70
+
71
+ ### Setup
72
+
73
+ Clone the repository.
74
+
75
+ ```sh
76
+ git clone https://github.com/riboseinc/enmail
77
+ ```
78
+
79
+ Setup your environment.
80
+
81
+ ```sh
82
+ bin/setup
83
+ ```
84
+
85
+ Run the test suite
86
+
87
+ ```sh
88
+ bin/rspec
89
+ ```
90
+
91
+ ## Contributing
92
+
93
+ First, thank you for contributing! We love pull requests from everyone. By
94
+ participating in this project, you hereby grant [Ribose Inc.][ribose] the
95
+ right to grant or transfer an unlimited number of non exclusive licenses or
96
+ sub-licenses to third parties, under the copyright covering the contribution
97
+ to use the contribution by all means.
98
+
99
+ Here are a few technical guidelines to follow:
100
+
101
+ 1. Open an [issue][issues] to discuss a new feature.
102
+ 1. Write tests to support your new feature.
103
+ 1. Make sure the entire test suite passes locally and on CI.
104
+ 1. Open a Pull Request.
105
+ 1. [Squash your commits][squash] after receiving feedback.
106
+ 1. Party!
107
+
108
+ ## Credits
109
+
110
+ This gem is developed, maintained and funded by [Ribose Inc.][ribose]
111
+
112
+ [ribose]: https://www.ribose.com
113
+ [issues]: https://github.com/abunashir/enmail/issues
114
+ [squash]: https://github.com/thoughtbot/guides/tree/master/protocol/git#write-a-feature
115
+ [sandimetz]: http://robots.thoughtbot.com/post/50655960596/sandi-metz-rules-for-developers
@@ -0,0 +1,214 @@
1
+ # Ruby mail extension for sending/receiving secure mail
2
+
3
+ [//]: # (TODO: JL add interceptor)
4
+
5
+ OpenPGP [RFC 4880] and S/MIME [RFC 5751] are two methods for secure mail
6
+ delivery today.
7
+
8
+ Currently there is no existing mail gem extension (Ruby Gem) that allows
9
+ switching between the methods and are usually not well structured.
10
+
11
+ This work is to complete implementation of the mail-secure gem by
12
+ leveraging existing OpenPGP and S/MIME mail extension code to allow
13
+ secure email sending via either standard (or a combination of both).
14
+
15
+ The mail-secure gem uses the concept of "adapters" to support different
16
+ underlying libraries.
17
+
18
+ * For OpenPGP, there are two existing implementations: GnuPG and NetPGP.
19
+ * For S/MIME, the default Ruby OpenSSL implementation should be used.
20
+
21
+
22
+ ## Implementations to support:
23
+
24
+ * OpenPGP
25
+ * NetPGP
26
+ * GnuPG
27
+ * S/MIME
28
+ * OpenSSL
29
+
30
+ This gem allows you to select different OpenPGP implementations
31
+ including NetPGP and GnuPG as different OpenPGP adapters, and also
32
+ S/MIME.
33
+
34
+ ## References and notes
35
+
36
+ * <https://github.com/jkraemer/mail-gpg>
37
+ * <https://github.com/bluerail/mr_smime>
38
+
39
+ The `mail-gpg` gem hacks the default `mail` gem Deliverer to ensure the
40
+ OpenPGP encryption/signing step is done at the last. This is extremely
41
+ dirty and fragile.
42
+
43
+ The `mr_smime` gem uses an interceptor hook (supplied by the `mail` gem)
44
+ to encrypt/sign the email. The catch is the `mail` gem supports
45
+ multiple interceptors (like Rack middlewares) so there is no guarantee
46
+ that it is the last interceptor.
47
+
48
+ A better approach is to use the interceptor pattern, and hack the
49
+ interceptor methods in `mail` to force a particular interceptor (the one
50
+ to implement) to be at the very end.
51
+
52
+ Technically, this resulting implementation could allow usage of OpenPGP
53
+ to sign/encrypt a message, then use S/MIME to sign (and/or encrypt) the
54
+ OpenPGP-encoded message at the same time.
55
+
56
+
57
+ ## OpenPGP Example code
58
+
59
+ ```ruby
60
+ message = Mail.new
61
+ message.decrypt
62
+
63
+ signed_mail = message.sign(key)
64
+ encrypted_mail = message.encrypt(identity)
65
+
66
+ signed_email.signature_valid? # => true, false
67
+ signed_email.secure? # => true, false
68
+ signed_email.pgp # => :inline, :mime, nil
69
+ signed_email.pgp? # => true, false
70
+ signed_email.pgp_inline? # => true, false
71
+ signed_email.pgp_mime? # => true, false
72
+ encrypted_email.secure # => "OpenPGP RFC 4880", nil
73
+ encrypted_email.secure? # => true, false
74
+ signed_email.smime? # => true, false
75
+
76
+ Mail::Secure::OpenPGP.signature_valid?(signed_email) # => true, false
77
+ ```
78
+
79
+ ## OpenPGP Configuration
80
+
81
+ ```ruby
82
+ Mail::Secure.configuration = {
83
+ method: :openpgp,
84
+ implementation: :netpgp, # :gpgme
85
+
86
+ # Specify PGP key in 3 ways.
87
+ # Only providing the key:
88
+ key: "ASCII-ARMORED-PGP-KEY",
89
+ key: "non-armored-raw-bytes-pgp-key",
90
+ # or:
91
+ key_id: "key-id",
92
+ keyring: "/Users/whoami/keyring-location",
93
+ # or infer "keyring" from GNUPGHOME:
94
+ key_id: "key-id",
95
+ }
96
+
97
+ ```
98
+
99
+ ### Sample mail object
100
+
101
+ ```ruby
102
+ Mail.new do
103
+ to 'jane@doe.net'
104
+ from 'john@doe.net'
105
+ subject 'gpg test'
106
+ body "encrypt me!"
107
+ add_file "some_attachment.zip"
108
+
109
+ # Using default :method configuration:
110
+ secure encrypt: true, encrypt_for: Key.find("mike@kite.com")
111
+
112
+ # #secure's first argument is optional: :openpgp | :smime
113
+ # If missing, then use the default configuration.
114
+ secure :openpgp, encrypt: true, encrypt_for: Key.find("mike@kite.com")
115
+ secure :smime, encrypt: true, encrypt_for: Key.find("mike@kite.com")
116
+
117
+ # #secure as a long-hand:
118
+ secure :openpgp, sign: true
119
+ secure :openpgp, encrypt: true, encrypt_for: PrivateKey.find("myself")
120
+ secure :openpgp, sign: true, sign_as: PrivateKey.find("myself")
121
+ secure :openpgp, encrypt: true
122
+ secure :openpgp, encrypt: true, passphrase: "secret"
123
+ secure :openpgp, encrypt: true, passphrase_callback: ->(...) {}
124
+
125
+ # #openpgp or #smime as short-hand:
126
+ smime sign: true
127
+ smime encrypt: true, encrypt_for: PrivateKey.find("myself")
128
+ smime sign: true, sign_as: PrivateKey.find("myself")
129
+ openpgp encrypt: true
130
+ openpgp encrypt: true, passphrase: "secret"
131
+ openpgp encrypt: true, passphrase_callback: ->(...) {}
132
+
133
+ # encrypt and sign message with sender's private key, using the given
134
+ # passphrase to decrypt the key
135
+ openpgp encrypt: true, sign: true, password: 'secret'
136
+
137
+ # encrypt and sign message using a different key
138
+ openpgp encrypt: true, sign_as: 'joe@otherdomain.com', password: 'secret'
139
+
140
+
141
+ # encrypt and sign message and use a callback function to provide the
142
+ # passphrase.
143
+ openpgp encrypt: true, sign_as: 'joe@otherdomain.com',
144
+ passphrase_callback: ->(obj, uid_hint, passphrase_info, prev_was_bad, fd) {
145
+ puts "Enter passphrase for #{passphrase_info}: "
146
+ (IO.for_fd(fd, 'w') << readline.chomp).flush
147
+ }
148
+ end.deliver
149
+
150
+ ```
151
+
152
+ #### Encrypt mail using OpenPGP public key directly
153
+
154
+ ```ruby
155
+ johns_key = <<-END
156
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
157
+ Version: GnuPG vX.X.XX (GNU/Linux)
158
+
159
+ mQGiBEk39msRBADw1ExmrLD1OUMdfvA7cnVVYTC7CyqfNvHUVuuBDhV7azs
160
+ ....
161
+ END
162
+
163
+ Mail.new do
164
+ to 'john@foo.bar'
165
+ gpg encrypt: true, keys: { 'john@foo.bar' => johns_key }
166
+ end
167
+
168
+ ```
169
+
170
+ ### Decrypting mail using passphrase
171
+
172
+ ```ruby
173
+
174
+ mail = Mail.first
175
+ mail.subject # subject is never encrypted
176
+ if mail.encrypted?
177
+ # decrypt using your private key, protected by the given passphrase
178
+ plaintext_mail = mail.decrypt(password: 'abc')
179
+ # the plaintext_mail, is a full Mail::Message object, just decrypted
180
+ end
181
+
182
+ ```
183
+
184
+ ### Signing mail (simplest case)
185
+
186
+ ```ruby
187
+
188
+
189
+ Mail.new do
190
+ to 'jane@doe.net'
191
+ gpg sign: true
192
+ end.deliver
193
+
194
+ ```
195
+
196
+ ### Verifying signature
197
+
198
+ ```ruby
199
+
200
+ mail = Mail.first
201
+ if !mail.encrypted? && mail.signed?
202
+ verified = mail.verify
203
+ puts "signature(s) valid: #{verified.signature_valid?}"
204
+ puts "message signed by: #{verified.signatures.map{|sig|sig.from}.join("\n")}"
205
+ end
206
+
207
+
208
+ if mail.encrypted?
209
+ decrypted = mail.decrypt(verify: true, password: 's3cr3t')
210
+ puts "signature(s) valid: #{decrypted.signature_valid?}"
211
+ puts "message signed by: #{decrypted.signatures.map{|sig|sig.from}.join("\n")}"
212
+ end
213
+
214
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "enmail"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ require "pry"
10
+ Pry.start
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'rspec' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||=
11
+ File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath)
12
+
13
+ require "rubygems"
14
+ require "bundler/setup"
15
+
16
+ load Gem.bin_path("rspec-core", "rspec")