enmail 0.1.0 → 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 +5 -5
- data/.editorconfig +21 -0
- data/.gitignore +164 -9
- data/.gitmodules +3 -0
- data/.rubocop.yml +26 -627
- data/.travis.yml +86 -3
- data/.yardopts +6 -0
- data/Gemfile +10 -1
- data/LICENSE.txt +21 -0
- data/README.adoc +150 -0
- data/Rakefile +119 -0
- data/bin/rspec +1 -0
- data/bin/setup +18 -1
- data/ci/install_botan.sh +28 -0
- data/ci/install_json_c.sh +32 -0
- data/ci/install_rnp.sh +31 -0
- data/docs/GPGMEAdapter.adoc +68 -0
- data/docs/RNPAdapter.adoc +45 -0
- data/enmail.gemspec +21 -8
- data/lib/enmail.rb +25 -4
- data/lib/enmail/adapters/base.rb +14 -0
- data/lib/enmail/adapters/gpgme.rb +81 -0
- data/lib/enmail/adapters/gpgme_requirements.rb +3 -0
- data/lib/enmail/adapters/rnp.rb +109 -0
- data/lib/enmail/adapters/rnp_requirements.rb +3 -0
- data/lib/enmail/dependency_constraints.rb +9 -0
- data/lib/enmail/extensions/message_transport_encoding_restrictions.rb +20 -0
- data/lib/enmail/helpers/message_manipulation.rb +73 -0
- data/lib/enmail/helpers/rfc1847.rb +103 -0
- data/lib/enmail/helpers/rfc3156.rb +60 -0
- data/lib/enmail/version.rb +4 -1
- metadata +99 -24
- data/README.md +0 -115
- data/lib/enmail/certificate_finder.rb +0 -75
- data/lib/enmail/config.rb +0 -21
- data/lib/enmail/configuration.rb +0 -80
- data/lib/enmail/enmailable.rb +0 -43
- data/lib/enmail/key.rb +0 -53
- data/lib/enmail/mail_ext/message.rb +0 -18
- data/lib/mail/secure/mail_interceptors/pgp.rb +0 -53
- data/lib/mail/secure/models/key.rb +0 -5
- data/lib/mail/secure/pgp_mailable.rb +0 -107
data/README.md
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
# EnMail
|
2
|
-
|
3
|
-
[](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
|
@@ -1,75 +0,0 @@
|
|
1
|
-
require "openssl"
|
2
|
-
|
3
|
-
module EnMail
|
4
|
-
class CertificateFinder
|
5
|
-
def initialize(email:)
|
6
|
-
@email = email
|
7
|
-
end
|
8
|
-
|
9
|
-
# Certificate
|
10
|
-
#
|
11
|
-
# This returns an `OpenSSL::X509::Certificate` instnace which
|
12
|
-
# usages the content for the pem certificate. The certificate
|
13
|
-
# name is the dotify version of the email with `pem` ext.
|
14
|
-
#
|
15
|
-
def certificate
|
16
|
-
certificate_instance
|
17
|
-
end
|
18
|
-
|
19
|
-
# Private Key
|
20
|
-
#
|
21
|
-
# This returns an `OpenSSL::PKey::RSA` instnace which usages
|
22
|
-
# the content for keyfile. The keyfile is the dotify version
|
23
|
-
# of the email with `key` ext.
|
24
|
-
#
|
25
|
-
def private_key
|
26
|
-
private_key_instance
|
27
|
-
end
|
28
|
-
|
29
|
-
# Self.find_by_email
|
30
|
-
#
|
31
|
-
# Initialize a new instnace with more readble interface.
|
32
|
-
#
|
33
|
-
def self.find_by_email(email)
|
34
|
-
new(email: email)
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
attr_reader :email
|
40
|
-
|
41
|
-
def certificate_instance
|
42
|
-
OpenSSL::X509::Certificate.new(
|
43
|
-
certificate_file(extension: :pem),
|
44
|
-
)
|
45
|
-
end
|
46
|
-
|
47
|
-
def private_key_instance
|
48
|
-
OpenSSL::PKey::RSA.new(
|
49
|
-
certificate_file(extension: :key),
|
50
|
-
)
|
51
|
-
end
|
52
|
-
|
53
|
-
def certificate_file(extension:)
|
54
|
-
content_for(
|
55
|
-
[dotify_email, extension.to_s].join("."),
|
56
|
-
)
|
57
|
-
end
|
58
|
-
|
59
|
-
def dotify_email
|
60
|
-
@dotify_email ||= email.sub("@", ".")
|
61
|
-
end
|
62
|
-
|
63
|
-
def content_for(filename)
|
64
|
-
File.read(certificate_file_with_path(filename))
|
65
|
-
end
|
66
|
-
|
67
|
-
def certificate_file_with_path(certificate)
|
68
|
-
File.join(certificates_root, certificate)
|
69
|
-
end
|
70
|
-
|
71
|
-
def certificates_root
|
72
|
-
EnMail.configuration.certificates_path
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
data/lib/enmail/config.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
require "enmail/configuration"
|
2
|
-
|
3
|
-
module EnMail
|
4
|
-
module Config
|
5
|
-
def configure
|
6
|
-
if block_given?
|
7
|
-
yield configuration
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def configuration
|
12
|
-
@configuration ||= EnMail::Configuration.new
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
# Expose config module methods as class level method, so we can
|
17
|
-
# use those method whenever necessary. Specially `configuration`
|
18
|
-
# throughout the gem
|
19
|
-
#
|
20
|
-
extend Config
|
21
|
-
end
|
data/lib/enmail/configuration.rb
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
module EnMail
|
2
|
-
class Configuration
|
3
|
-
attr_reader :smime_adapter
|
4
|
-
attr_accessor :sign_message, :certificates_path
|
5
|
-
attr_accessor :sign_key, :encrypt_key
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@sign_message = true
|
9
|
-
@smime_adapter = :openssl
|
10
|
-
end
|
11
|
-
|
12
|
-
# Signable?
|
13
|
-
#
|
14
|
-
# Returns the message signing status, by defualt it will return `true`.
|
15
|
-
# If the user provided a custom configuration for `sign_message` then
|
16
|
-
# it will use that status, so we can easily skip it when desirable.
|
17
|
-
#
|
18
|
-
def signable?
|
19
|
-
sign_message == true
|
20
|
-
end
|
21
|
-
|
22
|
-
# Set smime adapter
|
23
|
-
#
|
24
|
-
# This allows us to set a valid smime adapter, once this has been
|
25
|
-
# set then the gem will use this on to select the correct adapter
|
26
|
-
# class and then use that one to to `sign` a message.
|
27
|
-
#
|
28
|
-
# @param adapter adapter you want to use to sign the message
|
29
|
-
#
|
30
|
-
def smime_adapter=(adapter)
|
31
|
-
if valid_smime_adapter?(adapter)
|
32
|
-
@smime_adapter = adapter
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Adapter klass name
|
37
|
-
#
|
38
|
-
# This returns the string class name for the configured smime
|
39
|
-
# adapter. We are lazely loading the adapter so this interface
|
40
|
-
# will return the string verion. Please do not forget to use
|
41
|
-
# `Object.const_get` before invokng any method on it.
|
42
|
-
#
|
43
|
-
def smime_adapter_klass
|
44
|
-
smime_adapter_symbol_to_klass
|
45
|
-
end
|
46
|
-
|
47
|
-
# Default key
|
48
|
-
#
|
49
|
-
# This returns a Key instance with the configured keys.
|
50
|
-
# @return [EnMail::Key] the configured default key attributes.
|
51
|
-
#
|
52
|
-
def defualt_key
|
53
|
-
EnMail::Key.new(sign_key: sign_key, encrypt_key: encrypt_key)
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def valid_smime_adapter?(adapter)
|
59
|
-
smime_adapters.include?(adapter.to_sym)
|
60
|
-
end
|
61
|
-
|
62
|
-
def smime_adapter_symbol_to_klass
|
63
|
-
adapter_klasses.fetch(smime_adapter.to_sym)
|
64
|
-
end
|
65
|
-
|
66
|
-
# Supported smime adapters
|
67
|
-
#
|
68
|
-
# The list of the supported smime adapters, if we add support for
|
69
|
-
# a new smime adapter then please update this list and this way we
|
70
|
-
# can ensure user can configure the gem with supported adapter only
|
71
|
-
#
|
72
|
-
def smime_adapters
|
73
|
-
[:openssl].freeze
|
74
|
-
end
|
75
|
-
|
76
|
-
def adapter_klasses
|
77
|
-
{ openssl: "EnMail::Adapters::OpenSSL" }
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
data/lib/enmail/enmailable.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
module EnMail
|
2
|
-
module EnMailable
|
3
|
-
# Sign a message
|
4
|
-
#
|
5
|
-
# This interface allow us to sign a message while using this gem, this
|
6
|
-
# also forecefully sets the `signable` status true, so it ensures that
|
7
|
-
# the specific message will be signed before sending out.
|
8
|
-
#
|
9
|
-
# @param passphrase [String] the passphrase for the sign key
|
10
|
-
# @param key [EnMail::Key] the key model instance
|
11
|
-
#
|
12
|
-
def sign(passphrase: "", key: nil)
|
13
|
-
@key = key
|
14
|
-
|
15
|
-
unless passphrase.empty?
|
16
|
-
signing_key.passphrase = passphrase
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Signing key
|
21
|
-
#
|
22
|
-
# This returns the signing key when applicable, the default signing
|
23
|
-
# key is configured through an initializer, but we are also allowing
|
24
|
-
# user to provide a custom key when they are invoking an interface.
|
25
|
-
#
|
26
|
-
# @return [EnMail::Key] the key model instance
|
27
|
-
#
|
28
|
-
def signing_key
|
29
|
-
@key || EnMail.configuration.defualt_key
|
30
|
-
end
|
31
|
-
|
32
|
-
# Signing status
|
33
|
-
#
|
34
|
-
# This returns the message signing status based on the user specified
|
35
|
-
# configuration and signing key. If the user enabled sign_message and
|
36
|
-
# provided a valid signing key then this will return true otherwise
|
37
|
-
# false, this can be used before trying to sing a message.
|
38
|
-
#
|
39
|
-
def signable?
|
40
|
-
signing_key.sign_key && EnMail.configuration.signable?
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/enmail/key.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
module EnMail
|
2
|
-
class Key
|
3
|
-
# @!attribute [r] sign_key
|
4
|
-
# @return [String] the signing key content
|
5
|
-
#
|
6
|
-
attr_reader :sign_key
|
7
|
-
|
8
|
-
# @!attribute passphrase
|
9
|
-
# @return [String] the signing key passphrase
|
10
|
-
#
|
11
|
-
attr_reader :passphrase
|
12
|
-
|
13
|
-
# @!attribute [r] encrypt_key
|
14
|
-
# @return [String] the encryping key content
|
15
|
-
#
|
16
|
-
attr_reader :encrypt_key
|
17
|
-
|
18
|
-
# @!attribute [r] certificate
|
19
|
-
# @return [String] the certificate content
|
20
|
-
#
|
21
|
-
attr_reader :certificate
|
22
|
-
|
23
|
-
# Initialize a key model with the basic attributes, this expects us
|
24
|
-
# to provided the key/certificate as string and when we actually use
|
25
|
-
# it then the configured adapter will use it as necessary.
|
26
|
-
#
|
27
|
-
# @param :sign_key [String] the signing key content
|
28
|
-
# @param :passphrase [String] the passphrase for encrypted key
|
29
|
-
# @param :encrypt_key [String] the encryping key content
|
30
|
-
# @param :certificate [String] the signing certificate content
|
31
|
-
#
|
32
|
-
# @return [EnMail::Key] - the EnMail::Key model
|
33
|
-
#
|
34
|
-
def initialize(attributes)
|
35
|
-
@sign_key = attributes.fetch(:sign_key, "")
|
36
|
-
@passphrase = attributes.fetch(:passphrase, "")
|
37
|
-
@encrypt_key = attributes.fetch(:encrypt_key, "")
|
38
|
-
@certificate = attributes.fetch(:certificate, "")
|
39
|
-
end
|
40
|
-
|
41
|
-
# Set the passphrase value
|
42
|
-
#
|
43
|
-
# This allow us to set the passphrase after initialization, so if the
|
44
|
-
# user prefere then they can pass the passphrase during the siging /
|
45
|
-
# encrypting steps and we can set that one when necessary
|
46
|
-
#
|
47
|
-
# @param passphrase [String] the passphrase for encrypted key
|
48
|
-
#
|
49
|
-
def passphrase=(passphrase)
|
50
|
-
@passphrase = passphrase
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require "mail"
|
2
|
-
require "enmail/enmailable"
|
3
|
-
|
4
|
-
module Mail
|
5
|
-
class Message
|
6
|
-
# Include enmail interfaces
|
7
|
-
#
|
8
|
-
# We are supporting some custom interfaces for the mail instance,
|
9
|
-
# so the user can use `sign`, `encrypt` and `decrypt` directly to
|
10
|
-
# their mail instance.
|
11
|
-
#
|
12
|
-
# The `EnMail::EnMailable` module defines all of the interfaces
|
13
|
-
# to support the above funcitonality, so let's include that and
|
14
|
-
# please check `EnMail::EnMailable` for more details on those.
|
15
|
-
#
|
16
|
-
include EnMail::EnMailable
|
17
|
-
end
|
18
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module MailInterceptors
|
2
|
-
class PGP
|
3
|
-
|
4
|
-
def self.delivering_email(mail)
|
5
|
-
|
6
|
-
return unless mail.gpg
|
7
|
-
|
8
|
-
options = TrueClass === mail.gpg ? { encrypt: true } : mail.gpg
|
9
|
-
# encrypt and sign are off -> do not encrypt or sign
|
10
|
-
if options.delete(:encrypt)
|
11
|
-
receivers = []
|
12
|
-
receivers += mail.to if mail.to
|
13
|
-
receivers += mail.cc if mail.cc
|
14
|
-
receivers += mail.bcc if mail.bcc
|
15
|
-
|
16
|
-
if options[:sign_as]
|
17
|
-
options[:sign] = true
|
18
|
-
options[:signers] = options.delete(:sign_as)
|
19
|
-
elsif options[:sign]
|
20
|
-
options[:signers] = mail.from
|
21
|
-
end
|
22
|
-
|
23
|
-
# Need to remove any non-SignedPart & non-SignPart
|
24
|
-
mail.body = ''
|
25
|
-
|
26
|
-
mail.add_part Mail::Gpg::VersionPart.new
|
27
|
-
mail.add_part Mail::Gpg::EncryptedPart.new(mail, options.merge({recipients: receivers}))
|
28
|
-
mail.content_type "multipart/encrypted; protocol=\"application/pgp-encrypted\"; boundary=#{mail.boundary}"
|
29
|
-
mail.body.preamble = options[:preamble] || "This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)"
|
30
|
-
|
31
|
-
elsif options[:sign] || options[:sign_as]
|
32
|
-
|
33
|
-
to_be_signed = Mail::Gpg::SignedPart.build(mail)
|
34
|
-
|
35
|
-
# Need to remove any non-SignedPart & non-SignPart
|
36
|
-
mail.body = ''
|
37
|
-
|
38
|
-
mail.add_part to_be_signed
|
39
|
-
mail.add_part to_be_signed.sign(options)
|
40
|
-
|
41
|
-
mail.content_type "multipart/signed; micalg=pgp-sha1; protocol=\"application/pgp-signature\"; boundary=#{mail.boundary}"
|
42
|
-
mail.body.preamble = options[:preamble] || "This is an OpenPGP/MIME signed message (RFC 4880 and 3156)"
|
43
|
-
end
|
44
|
-
|
45
|
-
puts "pee pee mail@"
|
46
|
-
pp mail
|
47
|
-
|
48
|
-
rescue Exception
|
49
|
-
raise $! if mail.raise_encryption_errors
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|