vault-rails 0.0.11 → 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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +362 -0
  3. data/README.md +106 -0
  4. data/Rakefile +18 -2
  5. data/lib/vault/encrypted_model.rb +112 -0
  6. data/lib/vault/rails.rb +30 -0
  7. data/lib/vault/rails/version.rb +1 -1
  8. data/spec/dummy/Rakefile +6 -0
  9. data/spec/dummy/app/models/person.rb +8 -0
  10. data/spec/dummy/bin/bundle +3 -0
  11. data/spec/dummy/bin/rails +4 -0
  12. data/spec/dummy/bin/rake +4 -0
  13. data/spec/dummy/config.ru +4 -0
  14. data/spec/dummy/config/application.rb +29 -0
  15. data/spec/dummy/config/boot.rb +5 -0
  16. data/spec/dummy/config/database.yml +12 -0
  17. data/spec/dummy/config/environment.rb +5 -0
  18. data/spec/dummy/config/environments/development.rb +37 -0
  19. data/spec/dummy/config/environments/test.rb +39 -0
  20. data/spec/dummy/config/initializers/assets.rb +8 -0
  21. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  22. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  23. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  24. data/spec/dummy/config/initializers/inflections.rb +16 -0
  25. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  26. data/spec/dummy/config/initializers/session_store.rb +3 -0
  27. data/spec/dummy/config/initializers/vault.rb +9 -0
  28. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  29. data/spec/dummy/config/locales/en.yml +23 -0
  30. data/spec/dummy/config/routes.rb +3 -0
  31. data/spec/dummy/config/secrets.yml +22 -0
  32. data/spec/dummy/db/development.sqlite3 +0 -0
  33. data/spec/dummy/db/migrate/20150428220101_create_people.rb +11 -0
  34. data/spec/dummy/db/schema.rb +24 -0
  35. data/spec/dummy/log/development.log +124 -0
  36. data/spec/dummy/public/404.html +67 -0
  37. data/spec/dummy/public/422.html +67 -0
  38. data/spec/dummy/public/500.html +66 -0
  39. data/spec/dummy/public/favicon.ico +0 -0
  40. data/spec/integration/rails_spec.rb +27 -0
  41. data/spec/spec_helper.rb +24 -0
  42. data/spec/support/vault_server.rb +68 -0
  43. data/spec/unit/rails_spec.rb +28 -0
  44. metadata +178 -23
  45. data/lib/vault-rails.rb +0 -5
  46. data/lib/vault/rails/engine.rb +0 -8
  47. data/vendor/assets/javascripts/vault.js.coffee +0 -629
  48. data/vendor/assets/javascripts/vault/vault.js.coffee +0 -629
data/Rakefile CHANGED
@@ -1,2 +1,18 @@
1
- require "bundler"
2
- Bundler::GemHelper.install_tasks
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ Bundler::GemHelper.install_tasks
8
+
9
+ require 'rake/testtask'
10
+
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.libs << 'test'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = false
16
+ end
17
+
18
+ task default: :test
@@ -0,0 +1,112 @@
1
+ module Vault
2
+ module EncryptedModel
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ # Creates an attribute that is read and written using Vault.
7
+ #
8
+ # @example
9
+ #
10
+ # class Person < ActiveRecord::Base
11
+ # include Vault::EncryptedModel
12
+ # vault_attribute :ssn
13
+ # end
14
+ #
15
+ # person = Person.new
16
+ # person.ssn = "123-45-6789"
17
+ # person.save
18
+ # person.encrypted_ssn #=> "vault:v0:6hdPkhvyL6..."
19
+ #
20
+ # @param [Symbol] column
21
+ # the column that is encrypted
22
+ # @param [Hash] options
23
+ #
24
+ # @option options [Symbol] :encrypted_column
25
+ # the name of the encrypted column (default: +#{column}_encrypted+)
26
+ # @option options [String] :path
27
+ # the path to the transit backend (default: +transit+)
28
+ # @option options [String] :key
29
+ # the name of the encryption key (default: +#{app}_#{table}_#{column}+)
30
+ def vault_attribute(column, options = {})
31
+ encrypted_column = options[:encrypted_column] || "#{column}_encrypted"
32
+ path = options[:path] || "transit"
33
+ key = options[:key] || "#{Vault.application}_#{table_name}_#{column}"
34
+
35
+ class_eval <<-EOH, __FILE__, __LINE__ + 1
36
+ def #{column}
37
+ value = instance_variable_get(:@#{column})
38
+ return value if !value.nil?
39
+
40
+ encrypted = read_attribute(:#{encrypted_column})
41
+ return nil if encrypted.nil?
42
+
43
+ path = File.join("v1", "#{path}", "decrypt", "#{key}")
44
+ response = Vault.put(path, JSON.fast_generate(
45
+ ciphertext: encrypted,
46
+ ))
47
+ secret = Vault::Secret.decode(response)
48
+ plaintext = Base64.decode64(secret.data[:plaintext])
49
+
50
+ instance_variable_set(:@#{column}, plaintext)
51
+ end
52
+
53
+ def #{column}=(value)
54
+ path = File.join("v1", "#{path}", "encrypt", "#{key}")
55
+ response = Vault.put(path, JSON.fast_generate(
56
+ plaintext: Base64.encode64(value),
57
+ ))
58
+ secret = Vault::Secret.decode(response)
59
+ ciphertext = secret.data[:ciphertext]
60
+
61
+ write_attribute(:#{encrypted_column}, ciphertext)
62
+ instance_variable_set(:@#{column}, value)
63
+ end
64
+
65
+ def #{column}?
66
+ read_attribute(:#{encrypted_column}).present?
67
+ end
68
+ EOH
69
+
70
+ _vault_ensure_mounted!(path)
71
+ _vault_ensure_key!(path, key)
72
+ _vault_attributes.store(column.to_sym, true)
73
+
74
+ self
75
+ end
76
+
77
+ # The list of Vault attributes.
78
+ #
79
+ # @return [Hash]
80
+ def _vault_attributes
81
+ @vault_attributes ||= {}
82
+ end
83
+
84
+ # Ensure the proper transit backend is mounted at the given path.
85
+ #
86
+ # @return [true]
87
+ def _vault_ensure_mounted!(path)
88
+ mounts = Vault.sys.mounts
89
+ return true if mounts[path.to_s.chomp("/").to_sym]
90
+
91
+ Vault.sys.mount(path, :transit)
92
+ return true
93
+ end
94
+
95
+ # Ensure a key exists for the transit backend at the given path.
96
+ #
97
+ # @return [true]
98
+ def _vault_ensure_key!(path, key)
99
+ key_path = File.join("v1", path, "keys", key)
100
+
101
+ begin
102
+ Vault.get(key_path)
103
+ rescue => e
104
+ raise if e.code != 404
105
+ Vault.post(key_path, nil)
106
+ end
107
+
108
+ return true
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,30 @@
1
+ require "vault"
2
+
3
+ require "base64"
4
+ require "json"
5
+
6
+ module Vault
7
+ class << self
8
+ # The name of this application.
9
+ #
10
+ # @return [String]
11
+ attr_writer :application
12
+
13
+ # The name of the application. This must be set or an error will be
14
+ # returned.
15
+ #
16
+ # @return [String]
17
+ def application
18
+ if !defined?(@application) || @application.nil?
19
+ raise RuntimeError, "Must set `Vault.application'!"
20
+ end
21
+
22
+ return @application
23
+ end
24
+ end
25
+
26
+ autoload :EncryptedModel, "vault/encrypted_model"
27
+
28
+ module Rails
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  module Vault
2
2
  module Rails
3
- VERSION = "0.0.11"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,8 @@
1
+ class Person < ActiveRecord::Base
2
+ include Vault::EncryptedModel
3
+ vault_attribute :ssn
4
+ vault_attribute :credit_card,
5
+ encrypted_column: :cc_encrypted,
6
+ path: "credit-secrets",
7
+ key: "people_credit_cards"
8
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Rails.application
@@ -0,0 +1,29 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ # Pick the frameworks you want:
4
+ require "active_record/railtie"
5
+ require "action_controller/railtie"
6
+ require "action_mailer/railtie"
7
+ # require "action_view/railtie"
8
+ # require "sprockets/railtie"
9
+ require "rails/test_unit/railtie"
10
+
11
+ Bundler.require(*Rails.groups)
12
+ require "vault"
13
+
14
+ module Dummy
15
+ class Application < Rails::Application
16
+ # Settings in config/environments/* take precedence over those specified here.
17
+ # Application configuration should go into files in config/initializers
18
+ # -- all .rb files in that directory are automatically loaded.
19
+
20
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
21
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
22
+ # config.time_zone = 'Central Time (US & Canada)'
23
+
24
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
25
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
26
+ # config.i18n.default_locale = :de
27
+ end
28
+ end
29
+
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
@@ -0,0 +1,12 @@
1
+ default: &default
2
+ adapter: sqlite3
3
+ pool: 5
4
+ timeout: 5000
5
+
6
+ development:
7
+ <<: *default
8
+ database: db/development.sqlite3
9
+
10
+ test:
11
+ <<: *default
12
+ database: db/test.sqlite3
@@ -0,0 +1,5 @@
1
+ # Load the Rails application.
2
+ require File.expand_path('../application', __FILE__)
3
+
4
+ # Initialize the Rails application.
5
+ Rails.application.initialize!
@@ -0,0 +1,37 @@
1
+ Rails.application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
+
4
+ # In the development environment your application's code is reloaded on
5
+ # every request. This slows down response time but is perfect for development
6
+ # since you don't have to restart the web server when you make code changes.
7
+ config.cache_classes = false
8
+
9
+ # Do not eager load code on boot.
10
+ config.eager_load = false
11
+
12
+ # Show full error reports and disable caching.
13
+ config.consider_all_requests_local = true
14
+ config.action_controller.perform_caching = false
15
+
16
+ # Don't care if the mailer can't send.
17
+ config.action_mailer.raise_delivery_errors = false
18
+
19
+ # Print deprecation notices to the Rails logger.
20
+ config.active_support.deprecation = :log
21
+
22
+ # Raise an error on page load if there are pending migrations.
23
+ config.active_record.migration_error = :page_load
24
+
25
+ # Debug mode disables concatenation and preprocessing of assets.
26
+ # This option may cause significant delays in view rendering with a large
27
+ # number of complex assets.
28
+ config.assets.debug = true
29
+
30
+ # Adds additional error checking when serving assets at runtime.
31
+ # Checks for improperly declared sprockets dependencies.
32
+ # Raises helpful error messages.
33
+ config.assets.raise_runtime_errors = true
34
+
35
+ # Raises error for missing translations
36
+ # config.action_view.raise_on_missing_translations = true
37
+ end
@@ -0,0 +1,39 @@
1
+ Rails.application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
+
4
+ # The test environment is used exclusively to run your application's
5
+ # test suite. You never need to work with it otherwise. Remember that
6
+ # your test database is "scratch space" for the test suite and is wiped
7
+ # and recreated between test runs. Don't rely on the data there!
8
+ config.cache_classes = true
9
+
10
+ # Do not eager load code on boot. This avoids loading your whole application
11
+ # just for the purpose of running a single test. If you are using a tool that
12
+ # preloads Rails for running tests, you may have to set it to true.
13
+ config.eager_load = false
14
+
15
+ # Configure static asset server for tests with Cache-Control for performance.
16
+ config.serve_static_assets = true
17
+ config.static_cache_control = 'public, max-age=3600'
18
+
19
+ # Show full error reports and disable caching.
20
+ config.consider_all_requests_local = true
21
+ config.action_controller.perform_caching = false
22
+
23
+ # Raise exceptions instead of rendering exception templates.
24
+ config.action_dispatch.show_exceptions = false
25
+
26
+ # Disable request forgery protection in test environment.
27
+ config.action_controller.allow_forgery_protection = false
28
+
29
+ # Tell Action Mailer not to deliver emails to the real world.
30
+ # The :test delivery method accumulates sent emails in the
31
+ # ActionMailer::Base.deliveries array.
32
+ config.action_mailer.delivery_method = :test
33
+
34
+ # Print deprecation notices to the stderr.
35
+ config.active_support.deprecation = :stderr
36
+
37
+ # Raises error for missing translations
38
+ # config.action_view.raise_on_missing_translations = true
39
+ end
@@ -0,0 +1,8 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Version of your assets, change this if you want to expire all your assets.
4
+ Rails.application.config.assets.version = '1.0'
5
+
6
+ # Precompile additional assets.
7
+ # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
8
+ # Rails.application.config.assets.precompile += %w( search.js )
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4
+ # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5
+
6
+ # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7
+ # Rails.backtrace_cleaner.remove_silencers!
@@ -0,0 +1,3 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ Rails.application.config.action_dispatch.cookies_serializer = :json
@@ -0,0 +1,4 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Configure sensitive parameters which will be filtered from the log file.
4
+ Rails.application.config.filter_parameters += [:password]
@@ -0,0 +1,16 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new inflection rules using the following format. Inflections
4
+ # are locale specific, and you may define rules for as many different
5
+ # locales as you wish. All of these examples are active by default:
6
+ # ActiveSupport::Inflector.inflections(:en) do |inflect|
7
+ # inflect.plural /^(ox)$/i, '\1en'
8
+ # inflect.singular /^(ox)en/i, '\1'
9
+ # inflect.irregular 'person', 'people'
10
+ # inflect.uncountable %w( fish sheep )
11
+ # end
12
+
13
+ # These inflection rules are supported but not enabled by default:
14
+ # ActiveSupport::Inflector.inflections(:en) do |inflect|
15
+ # inflect.acronym 'RESTful'
16
+ # end
@@ -0,0 +1,4 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new mime types for use in respond_to blocks:
4
+ # Mime::Type.register "text/richtext", :rtf
@@ -0,0 +1,3 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ Rails.application.config.session_store :cookie_store, key: '_dummy_session'
@@ -0,0 +1,9 @@
1
+ require "vault/rails"
2
+
3
+ require_relative "../../../support/vault_server"
4
+
5
+ Vault.configure do |vault|
6
+ vault.application = "dummy"
7
+ vault.address = RSpec::VaultServer.address
8
+ vault.token = RSpec::VaultServer.token
9
+ end
@@ -0,0 +1,14 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # This file contains settings for ActionController::ParamsWrapper which
4
+ # is enabled by default.
5
+
6
+ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7
+ ActiveSupport.on_load(:action_controller) do
8
+ wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9
+ end
10
+
11
+ # To enable root element in JSON for ActiveRecord objects.
12
+ # ActiveSupport.on_load(:active_record) do
13
+ # self.include_root_in_json = true
14
+ # end
@@ -0,0 +1,23 @@
1
+ # Files in the config/locales directory are used for internationalization
2
+ # and are automatically loaded by Rails. If you want to use locales other
3
+ # than English, add the necessary files in this directory.
4
+ #
5
+ # To use the locales, use `I18n.t`:
6
+ #
7
+ # I18n.t 'hello'
8
+ #
9
+ # In views, this is aliased to just `t`:
10
+ #
11
+ # <%= t('hello') %>
12
+ #
13
+ # To use a different locale, set it with `I18n.locale`:
14
+ #
15
+ # I18n.locale = :es
16
+ #
17
+ # This would use the information in config/locales/es.yml.
18
+ #
19
+ # To learn more, please read the Rails Internationalization guide
20
+ # available at http://guides.rubyonrails.org/i18n.html.
21
+
22
+ en:
23
+ hello: "Hello world"