enmail 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,88 @@
1
- sudo: false
1
+ dist: xenial
2
+ sudo: required
2
3
  language: ruby
4
+
3
5
  rvm:
4
- - 2.4.1
5
- before_install: gem install bundler -v 1.14.6
6
+ - 2.6
7
+ - 2.5
8
+ - 2.4
9
+ - 2.3
10
+ - ruby-head
11
+
12
+ env:
13
+ global:
14
+ - EXPECT_GPG_VERSION="2.2"
15
+ - GPG_VERSION="latest"
16
+ - RNP_VERSION="master"
17
+
18
+ - DEPS_BUILD_DIR="${TRAVIS_BUILD_DIR}/build"
19
+ - DEPS_PREFIX="${TRAVIS_BUILD_DIR}/opt"
20
+ - BOTAN_PREFIX="${DEPS_PREFIX}/botan"
21
+ - JSONC_PREFIX="${DEPS_PREFIX}/json-c"
22
+ - RNP_PREFIX="${DEPS_PREFIX}/rnp"
23
+ - GPG_PREFIX="${DEPS_PREFIX}/gpg"
24
+
25
+ # Be aware of differences between LD_LIBRARY_PATH and LD_RUN_PATH.
26
+ # - http://osr507doc.sco.com/en/tools/ccs_linkedit_dynamic_dirsearch.html
27
+ # - https://www.hpc.dtu.dk/?page_id=1180
28
+ #
29
+ # You should be careful when attempting to replicate following in your
30
+ # setup, because setting LD_LIBRARY_PATH is often a bad idea. Nevertheless,
31
+ # it is okay here in Travis, and actually any attempt to change these led me
32
+ # to linking failures. Side note: I am not a Linux expert, and you may be
33
+ # more lucky.
34
+ #
35
+ # I'd be happy to get rid of LD_LIBRARY_PATH eventually in some future
36
+ # pull request.
37
+ - LD_LIBRARY_PATH="${BOTAN_PREFIX}/lib:${JSONC_PREFIX}/lib:${RNP_PREFIX}/lib"
38
+ - LD_RUN_PATH="${GPG_PREFIX}/lib"
39
+
40
+ - PATH="${RNP_PREFIX}/bin:${GPG_PREFIX}/bin:${PATH}"
41
+
42
+ # Many of these are supported only in few GPG components, hence bunch of
43
+ # harmless warnings typically shows up.
44
+ - >
45
+ GPG_CONFIGURE_OPTS="--disable-doc --enable-pinentry-curses
46
+ --disable-pinentry-emacs --disable-pinentry-gtk2 --disable-pinentry-gnome3
47
+ --disable-pinentry-qt --disable-pinentry-qt4 --disable-pinentry-qt5
48
+ --disable-pinentry-tqt --disable-pinentry-fltk
49
+ --prefix=${GPG_PREFIX}
50
+ --with-libgpg-error-prefix=${GPG_PREFIX}
51
+ --with-libassuan-prefix=${GPG_PREFIX}
52
+ --with-libgpg-error-prefix=${GPG_PREFIX}
53
+ --with-libgcrypt-prefix=${GPG_PREFIX}
54
+ --with-libassuan-prefix=${GPG_PREFIX}
55
+ --with-ksba-prefix=${GPG_PREFIX}
56
+ --with-npth-prefix=${GPG_PREFIX}"
57
+
58
+ before_install:
59
+ - mkdir -p ${DEPS_PREFIX}
60
+ - pushd ci/gpg
61
+ - >
62
+ ./install_gpg_all.sh
63
+ --suite-version "${GPG_VERSION}"
64
+ --build-dir "${DEPS_BUILD_DIR}/gpg"
65
+ --configure-opts "${GPG_CONFIGURE_OPTS}"
66
+ --folding-style travis
67
+ - popd
68
+ - pushd ci
69
+ - ./install_botan.sh
70
+ - ./install_json_c.sh
71
+ - ./install_rnp.sh
72
+ - popd
73
+ - gem install bundler -v "~> 2.0"
74
+
75
+ before_script:
76
+ - bundle exec rake pgp_keys:generate
77
+ - bundle exec rake pgp_keys:list
78
+
79
+ script:
80
+ - bundle exec rspec --format documentation --profile 200
81
+
82
+ matrix:
83
+ include:
84
+ - env: TEST_WITHOUT_RNP="1"
85
+ - env: TEST_WITHOUT_GPGME="1"
86
+
87
+ allow_failures:
88
+ - rvm: ruby-head
@@ -0,0 +1,6 @@
1
+ -
2
+ README.adoc
3
+ CODE_OF_CONDUCT.md
4
+ LICENSE.txt
5
+ docs/GPGMEAdapter.adoc
6
+ docs/RNPAdapter.adoc
data/Gemfile CHANGED
@@ -1,4 +1,13 @@
1
- source 'https://rubygems.org'
1
+ # (c) Copyright 2018 Ribose Inc.
2
+ #
3
+
4
+ source "https://rubygems.org"
2
5
 
3
6
  # Specify your gem's dependencies in enmail.gemspec
4
7
  gemspec
8
+
9
+ gem "codecov", require: false, group: :test
10
+ gem "simplecov", require: false, group: :test
11
+
12
+ gem "gpgme", install_if: -> { !ENV["TEST_WITHOUT_GPGME"] }
13
+ gem "rnp", install_if: -> { !ENV["TEST_WITHOUT_RNP"] }
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Ribose Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,150 @@
1
+ = EnMail
2
+
3
+ ifdef::env-github[]
4
+ image:https://img.shields.io/gem/v/enmail.svg[
5
+ Gem Version, link="https://rubygems.org/gems/enmail"]
6
+ image:https://img.shields.io/travis/riboseinc/enmail/master.svg[
7
+ Build Status, link="https://travis-ci.org/riboseinc/enmail/branches"]
8
+ image:https://img.shields.io/codecov/c/github/riboseinc/enmail.svg[
9
+ Test Coverage, link="https://codecov.io/gh/riboseinc/enmail"]
10
+ image:https://img.shields.io/codeclimate/maintainability/riboseinc/enmail.svg[
11
+ "Code Climate", link="https://codeclimate.com/github/riboseinc/enmail"]
12
+ endif::[]
13
+
14
+ EnMail (encrypted mail) signs or encrypts correspondence sent via the Ruby
15
+ https://rubygems.org/gems/mail[mail] gem.
16
+
17
+ EnMail has open architecture. Multiple adapters are supported, and new ones
18
+ can be implemented with ease. Currently, GPGME and RNP adapters are available
19
+ out of the box. Both implement OpenPGP standard.
20
+
21
+ == Basic usage
22
+
23
+ Given some e-mail:
24
+
25
+ [source,ruby]
26
+ ----
27
+ mail = Mail.new
28
+ mail.from = "Very Myself <me@example.com>"
29
+ mail.to = "Someone Else <someone@example.com>"
30
+ mail.subject = "It is very important"
31
+ mail.body = "Or, whatever"
32
+
33
+ adapter = ::EnMail::Adapters::RNP
34
+
35
+ # sign message
36
+ EnMail.protect :sign, mail, adapter: adapter
37
+
38
+ # encrypt message
39
+ EnMail.protect :encrypt, mail, adapter: adapter
40
+
41
+ # sign and encrypt message
42
+ EnMail.protect :sign_and_encrypt_encapsulated, mail, adapter: adapter
43
+
44
+ # or
45
+ EnMail.protect :sign_and_encrypt_combined, mail, adapter: adapter
46
+ ----
47
+
48
+ == Adapters
49
+
50
+ .Adapter features comparison
51
+ [options="header"]
52
+ |=======
53
+ | | GPGME | RNP
54
+ | Protocol | Open PGP | Open PGP
55
+ | Supporting library | https://gnupg.org/software/gpgme/index.html[GnuPG Made Easy] | https://www.rnpgp.com/[RNP]
56
+ | Native extensions | yes | yes, from https://github.com/ffi/ffi[FFI]
57
+ | Sign | yes | yes
58
+ | Encrypt | yes | yes
59
+ | Sign and encrypt | yes, encapsulated and combined | yes, encapsulated and combined
60
+ | Password-protected keys | yes, password must be a String | yes, password must be a String or Proc
61
+ | Bugs, issues and feature requests | https://github.com/riboseinc/enmail/issues?q=is%3Aissue+is%3Aopen+label%3A%22adapter%3A+gpgme%22[See GitHub] | https://github.com/riboseinc/enmail/issues?q=is%3Aissue+is%3Aopen+label%3A%22adapter%3A+rnp%22[See GitHub]
62
+ |=======
63
+
64
+ See adapter-specific guides for details:
65
+
66
+ ifdef::env-browser,env-github[]
67
+ * <<docs/GPGMEAdapter.adoc#,GPGME>>
68
+ * <<docs/RNPAdapter.adoc#,RNP>>
69
+ endif::[]
70
+ ifndef::env-browser,env-github[]
71
+ * {file:docs/GPGMEAdapter.adoc}
72
+ * {file:docs/RNPAdapter.adoc}
73
+ endif::[]
74
+
75
+ == Development
76
+
77
+ === Setup
78
+
79
+ Clone the repository.
80
+
81
+ [source,sh]
82
+ ----
83
+ git clone https://github.com/riboseinc/enmail
84
+ ----
85
+
86
+ NOTE: GnuPG will create UNIX sockets in the `<project_root>/tmp/pgp_home`
87
+ directory. Be advised that paths to UNIX sockets have limited length (about 100
88
+ characters). Therefore, please ensure that path to directory you are cloning
89
+ repository into is less than 50 characters long, or you may experience weird
90
+ errors.
91
+
92
+ Setup your environment.
93
+
94
+ [source,sh]
95
+ ----
96
+ bin/setup
97
+ ----
98
+
99
+ Above one will take a short while. As the final step, tests will be run
100
+ in order to prove your setup's correctness.
101
+
102
+ === Regenerating OpenPGP keys
103
+
104
+ If you ever need to regenerate your development OpenPGP keys, execute:
105
+
106
+ [source,sh]
107
+ ----
108
+ bundle exec rake pgp_keys:regenerate
109
+ ----
110
+
111
+ NOTE: Always run tests after pulling new changes from the upstream. If they
112
+ fail, it's likely that OpenPGP keys should be regenerated.
113
+
114
+ === Submodules
115
+
116
+ GnuPG is installed in Travis CI via scripts maintained in a sister repository
117
+ https://github.com/riboseinc/gpg-build-scripts[riboseinc/gpg-build-scripts],
118
+ and included here as a Git submodule. Learn more about submodules from
119
+ https://blog.github.com/2016-02-01-working-with-submodules/[The GitHub Blog].
120
+
121
+ === Contributing
122
+
123
+ First, thank you for contributing! We love pull requests from everyone.
124
+ By participating in this project, you hereby grant
125
+ https://www.ribose.com[Ribose Inc.] the right to grant or transfer an
126
+ unlimited number of non exclusive licenses or sub-licenses to third
127
+ parties, under the copyright covering the contribution to use the
128
+ contribution by all means.
129
+
130
+ Here are a few technical guidelines to follow:
131
+
132
+ 1. Open an https://github.com/riboseinc/enmail/issues[issue] to discuss
133
+ a new feature.
134
+ 2. Write tests to support your new feature.
135
+ 3. Make sure the entire test suite passes locally and on CI.
136
+ 4. Open a Pull Request.
137
+ 5. After receiving feedback, perform
138
+ https://help.github.com/articles/about-git-rebase/[an interactive rebase]
139
+ on your branch, in order to create a series of cohesive commits with
140
+ descriptive messages.
141
+ 6. Party!
142
+
143
+ == Credits
144
+
145
+ This gem is developed, maintained and funded by
146
+ https://www.ribose.com[Ribose Inc.]
147
+
148
+ == License
149
+
150
+ This gem is licensed under MIT license.
data/Rakefile CHANGED
@@ -1,6 +1,125 @@
1
+ # (c) Copyright 2018 Ribose Inc.
2
+ #
3
+
1
4
  require "bundler/gem_tasks"
2
5
  require "rspec/core/rake_task"
3
6
 
7
+ require "tempfile"
8
+
4
9
  RSpec::Core::RakeTask.new(:spec)
5
10
 
6
11
  task :default => :spec
12
+
13
+ namespace :pgp_keys do
14
+ def init_homedir_if_missing
15
+ return if Dir.exists?(TMP_PGP_HOME)
16
+
17
+ FileUtils.mkdir_p(TMP_PGP_HOME)
18
+
19
+ File.write(File.join(TMP_PGP_HOME, "gpg.conf"), <<~GPGCONF)
20
+ personal-digest-preferences SHA512
21
+ GPGCONF
22
+
23
+ File.write(File.join(TMP_PGP_HOME, "gpg-agent.conf"), <<~AGENTCONF)
24
+ default-cache-ttl 0
25
+ AGENTCONF
26
+ end
27
+
28
+ def execute_gpg(*options)
29
+ init_homedir_if_missing
30
+ common_options = ["--no-permission-warning", "--homedir", TMP_PGP_HOME]
31
+ cmd = ["gpg", *common_options, *options]
32
+ system(*cmd)
33
+ end
34
+
35
+ # Available parameters for unattended GPG key generation are described here:
36
+ # https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html
37
+ def generate_pgp_keys(key_params)
38
+ Tempfile.create("gnupg-key-params") do |key_params_file|
39
+ key_params_file.write(key_params)
40
+ key_params_file.close
41
+ execute_gpg("--batch", "--gen-key", in: key_params_file.path)
42
+ end
43
+ end
44
+
45
+ desc "Lists keys in tmp/pgp_home"
46
+ task :list => :prepare do
47
+ execute_gpg "--list-keys"
48
+ end
49
+
50
+ desc "Stops all GPG daemons, and deletes tmp/pgp_home"
51
+ task :clear => :prepare do
52
+ if File.exists?(TMP_PGP_HOME)
53
+ system "gpgconf", "--homedir", TMP_PGP_HOME, "--kill", "all"
54
+ FileUtils.remove_entry_secure TMP_PGP_HOME
55
+ end
56
+ end
57
+
58
+ desc "Clears tmp/pgp_home, and generates new set of keys"
59
+ task :regenerate => %i[clear generate]
60
+
61
+ desc "Generates keys in tmp/pgp_home"
62
+ task :generate => :prepare do
63
+ # Key pairs without password
64
+ generate_pgp_keys(<<~KEY_PARAMS)
65
+ %no-protection
66
+ Key-Type: RSA
67
+ Key-Usage: sign, cert
68
+ Key-Length: 2048
69
+ Subkey-Type: RSA
70
+ Subkey-Length: 2048
71
+ Subkey-Usage: encrypt
72
+ Name-Real: Some Arbitrary Key
73
+ Name-Email: whatever@example.test
74
+ Name-Comment: Without passphrase
75
+ Expire-Date: 0
76
+ KEY_PARAMS
77
+
78
+ generate_pgp_keys(<<~KEY_PARAMS)
79
+ %no-protection
80
+ Key-Type: RSA
81
+ Key-Usage: sign, cert
82
+ Key-Length: 2048
83
+ Subkey-Type: RSA
84
+ Subkey-Length: 2048
85
+ Subkey-Usage: encrypt
86
+ Name-Real: Cato Elder
87
+ Name-Email: cato.elder@example.test
88
+ Name-Comment: Without passphrase
89
+ Expire-Date: 0
90
+ KEY_PARAMS
91
+
92
+ generate_pgp_keys(<<~KEY_PARAMS)
93
+ %no-protection
94
+ Key-Type: RSA
95
+ Key-Usage: sign, cert
96
+ Key-Length: 2048
97
+ Subkey-Type: RSA
98
+ Subkey-Length: 2048
99
+ Subkey-Usage: encrypt
100
+ Name-Real: Roman Senate
101
+ Name-Email: senate@example.test
102
+ Name-Comment: Without passphrase
103
+ Expire-Date: 0
104
+ KEY_PARAMS
105
+
106
+ # Password-protected key pairs
107
+ generate_pgp_keys(<<~KEY_PARAMS)
108
+ Key-Type: RSA
109
+ Key-Usage: sign, cert
110
+ Key-Length: 2048
111
+ Subkey-Type: RSA
112
+ Subkey-Length: 2048
113
+ Subkey-Usage: encrypt
114
+ Name-Real: Cato Elder
115
+ Name-Email: cato.elder+pwd@example.test
116
+ Name-Comment: Password-protected
117
+ Expire-Date: 0
118
+ Passphrase: 1234
119
+ KEY_PARAMS
120
+ end
121
+ end
122
+
123
+ task :prepare do
124
+ require_relative "./spec/support/0_tmp_pgp_home"
125
+ end
data/bin/rspec CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
+
3
4
  #
4
5
  # This file was generated by Bundler.
5
6
  #
data/bin/setup CHANGED
@@ -3,6 +3,23 @@ set -euo pipefail
3
3
  IFS=$'\n\t'
4
4
  set -vx
5
5
 
6
+ ########################################
7
+ # Installing required gems... #
8
+ ########################################
9
+
6
10
  bundle install
7
11
 
8
- # Do any other automated setup that you need to do here
12
+ ########################################
13
+ # Generating Open PGP keys #
14
+ # with GnuPG... #
15
+ ########################################
16
+
17
+ bundle exec rake pgp_keys:generate pgp_keys:list
18
+
19
+ ########################################
20
+ # Validating setup... #
21
+ # (tests should pass as long as #
22
+ # they do in CI) #
23
+ ########################################
24
+
25
+ bundle exec rspec
@@ -0,0 +1,28 @@
1
+ #!/bin/bash
2
+
3
+ # (c) Copyright 2018 Ribose Inc.
4
+ #
5
+
6
+ # Based on:
7
+ # https://github.com/riboseinc/ruby-rnp/blob/52d6113458cb095cf7811/ci/install.sh
8
+
9
+ set -eux
10
+
11
+ : "${CORES:=2}"
12
+ : "${MAKE:=make}"
13
+
14
+ botan_build="${DEPS_BUILD_DIR}/botan"
15
+
16
+ if [ ! -e "${BOTAN_PREFIX}/lib/libbotan-2.so" ] && \
17
+ [ ! -e "${BOTAN_PREFIX}/lib/libbotan-2.dylib" ]; then
18
+
19
+ if [ -d "${botan_build}" ]; then
20
+ rm -rf "${botan_build}"
21
+ fi
22
+
23
+ git clone --depth 1 https://github.com/randombit/botan "${botan_build}"
24
+ pushd "${botan_build}"
25
+ ./configure.py --prefix="${BOTAN_PREFIX}" --with-debug-info --cxxflags="-fno-omit-frame-pointer"
26
+ ${MAKE} -j${CORES} install
27
+ popd
28
+ fi