keystok 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9d3ce263f46ece47e3d9451f0c46b18df5064eb2
4
+ data.tar.gz: 2c9e6f747bc934a6cfbc4c3e24dc89426d512021
5
+ SHA512:
6
+ metadata.gz: b553e40de08d9bc179121066bfd1d99b9952d9293283c1eedbcb9363a2e579a893a02f0926c242f1168db88a4b2d03f04e1fcea923ce489b9c34d76457540737
7
+ data.tar.gz: b7de1606a6be130ded57c50248b0f1f646c17cf69fc4a716cd91594d872d0ffdad7fa8da5321cfaa3ef8ec74d7bff9c44f7942bf4d1c8256950ccd61a7ddc3f7
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .idea
6
+ .yardoc
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ Gemfile.lock
11
+ InstalledFiles
12
+ keystok_cache.data
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
20
+ rspec.xml
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format Fuubar
3
+ --format RspecJunitFormatter
4
+ --out rspec.xml
data/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ MethodLength:
2
+ Max: 30
3
+ ClassLength:
4
+ Max: 250
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1 @@
1
+ Copyright (c) 2014 GitDock Oy
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # Keystok
2
+
3
+ ![Build status](https://www.codeship.io/projects/65218fa0-9e09-0131-3f96-16b8a84518ac/status)
4
+
5
+ ## Installation
6
+
7
+ $ gem install keystok
8
+
9
+ ## Usage
10
+
11
+ require 'keystok'
12
+ require 'yaml' # Config is then easier
13
+ config = YAML.load_file('keystok.yml')
14
+ # or config can be just hash:
15
+ # config = { connection_string: 'das21312312_connection_string',
16
+ # api_host: 'https://api_custom_domain.keystok.com'
17
+ # }
18
+ keystok = Keystok::Client.new(config)
19
+ # get hash with all keys
20
+ keystok.keys
21
+ # get one key
22
+ keystok.get(key_id)
23
+
24
+ ### Rails integration
25
+
26
+ Add keystok to Gemfile:
27
+
28
+ gem 'keystok'
29
+
30
+ Keystok have generator that can create config, initializer and .gitignore entry for you
31
+
32
+ rails g keystok:install connection_string_value
33
+
34
+ In Rails env Keystok will use Rails.logger. Without Rails it will default to logging to STDOUT.
35
+ If you would like to define your own logger you can do it like:
36
+
37
+ Keystok.logger = your_logger
38
+
39
+ ## Config options description
40
+
41
+ ### api_host, auth_host
42
+
43
+ Those values are not needed by default. It can be required if you are using separated Keystok servers
44
+
45
+ ### connection_string
46
+
47
+ This value is visible in app page in Keystok service
48
+
49
+ ### eager_fetching
50
+
51
+ When *true* client will fetch all keys from API even when one was requested. This will save time
52
+ when another key will be requested, because client will not have to fetch it from API.
53
+ However in some cases like huge amount of keys or when *volatile* is set,
54
+ this option should be set to *false*. Default value is *true*
55
+
56
+ ### no_cache
57
+
58
+ If you don't want to use cache functionality, you can disable cache writing by setting *no_cache* to *true* in config
59
+
60
+ ### tmp_dir
61
+
62
+ This dir will be used to store encrypted cache which can be used when API can't be contacted
63
+
64
+ ### volatile
65
+
66
+ Normally when asking about key that is in local store, SDK will not perform API request to provide quicker response.
67
+ Request can be forced on per method call basis by second parameter set to *true* (default is *false*)
68
+
69
+ keystok.get('this_can_change_often', true)
70
+
71
+ However if you want SDK to make request on every request without adding *true* to every *get* or *keys*,
72
+ you can set *volatile* to *true* in config. This will force SDK to ask API on every request.
73
+ Please note that this will may decrese performance of you app since it will require API request
74
+ and cache writing on every *get* and *keys* call
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec'
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc 'Run all specs in spec directory'
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ end
data/keystok.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'keystok/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'keystok'
8
+ spec.version = Keystok::VERSION
9
+ spec.authors = ['Piotr Sokolowski']
10
+ spec.email = ['piotr@keystok.com']
11
+ spec.summary = %q{Keystok API client}
12
+ spec.description = <<-EOS
13
+ Ruby client for Keystok service. https://keystok.com
14
+ EOS
15
+ spec.homepage = 'https://keystok.com'
16
+ spec.license = 'GitDock Oy'
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'faraday'
23
+ spec.add_dependency 'oauth2'
24
+
25
+ spec.add_development_dependency 'bundler'
26
+ spec.add_development_dependency 'fuubar'
27
+ spec.add_development_dependency 'pry'
28
+ spec.add_development_dependency 'rails', '>= 3.0'
29
+ spec.add_development_dependency 'rake'
30
+ spec.add_development_dependency 'rspec'
31
+ spec.add_development_dependency 'rspec_junit_formatter'
32
+ spec.add_development_dependency 'simplecov'
33
+ spec.add_development_dependency 'webmock'
34
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under GitDock Oy license terms.
3
+ # See https://bitbucket.org/keystok/keystok-client-ruby/raw/master/LICENSE.txt
4
+ # for details.
5
+
6
+ module Keystok
7
+ module Generators
8
+ # Generator that creates config file and initializer
9
+ # It also add config file to .gitignore
10
+ class InstallGenerator < Rails::Generators::Base
11
+ argument :connection_string,
12
+ type: :string,
13
+ banner: 'connection_string'
14
+
15
+ source_root File.expand_path('../templates', __FILE__)
16
+
17
+ desc 'Create initializer'
18
+
19
+ def create_initializer_and_config_file
20
+ template 'keystok.yml.erb', 'config/keystok.yml'
21
+ template 'keystok.rb', 'config/initializers/keystok.rb'
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,6 @@
1
+ config_filepath = File.expand_path('../../keystok.yml', __FILE__)
2
+ config_data = YAML.load_file(config_filepath)[Rails.env.to_sym]
3
+ if config_data.nil?
4
+ fail "Config file error in #{Rails.env} (#{config_filepath})"
5
+ end
6
+ KEYSTOK = Keystok::Client.new(config_data)
@@ -0,0 +1,10 @@
1
+ ---
2
+ :production:
3
+ :connection_string: <%= connection_string %>
4
+ :tmp_dir: 'tmp'
5
+ :development:
6
+ :connection_string: <%= connection_string %>
7
+ :tmp_dir: 'tmp'
8
+ :test:
9
+ :connection_string: <%= connection_string %>
10
+ :tmp_dir: 'tmp'
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under GitDock Oy license terms.
3
+ # See https://bitbucket.org/keystok/keystok-client-ruby/raw/master/LICENSE.txt
4
+ # for details.
5
+
6
+ require 'base64'
7
+ require 'json'
8
+ require 'openssl'
9
+
10
+ module Keystok
11
+ # Module handling data encryption and decryption
12
+ # It also handles raw data from API unpacking
13
+ module AESCrypto
14
+ PREFIX = ':aes256:'
15
+
16
+ def cipher(plain_text, key, iv, key_size = 256, block_mode = :CBC)
17
+ cipher = OpenSSL::Cipher::AES.new(key_size, block_mode)
18
+ cipher.encrypt
19
+ cipher.key = key
20
+ cipher.iv = iv
21
+ cipher.update(plain_text) + cipher.final
22
+ end
23
+
24
+ def decipher(encrypted, key, iv, key_size = 256, block_mode = :CBC)
25
+ decipher = OpenSSL::Cipher::AES.new(key_size, block_mode)
26
+ decipher.decrypt
27
+ decipher.key = key
28
+ decipher.iv = iv
29
+ decipher.update(encrypted) + decipher.final
30
+ end
31
+
32
+ def decrypt_key(encrypted_key, config = nil)
33
+ config ||= @config || {}
34
+ fail Error::ConfigError, 'No decryption key in config' unless config[:dk]
35
+ unless encrypted_key.start_with?(PREFIX)
36
+ fail Error::UnsupportedDataFormat, 'Wrong encryption algorithm'
37
+ end
38
+ encrypted_data = Base64.decode64(encrypted_key.sub(/^:[^:]+:/, ''))
39
+ json_data = JSON.parse(encrypted_data)
40
+ key = OpenSSL::PKCS5.pbkdf2_hmac(config[:dk],
41
+ Base64.decode64(json_data['salt']),
42
+ json_data['iter'],
43
+ json_data['ks'] / 8,
44
+ OpenSSL::Digest::SHA1.new)
45
+ decipher(Base64.decode64(json_data['ct']), key,
46
+ Base64.decode64(json_data['iv']), json_data['ks'])
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under GitDock Oy license terms.
3
+ # See https://bitbucket.org/keystok/keystok-client-ruby/raw/master/LICENSE.txt
4
+ # for details.
5
+
6
+ module Keystok
7
+ # Module for handling cache write and read operations
8
+ module Cache
9
+ def cache_file_path(tmp_dir = nil)
10
+ tmp_dir ||= (@config && @config[:tmp_dir]) ? @config[:tmp_dir] : '.'
11
+ @cache_file_path ||= File.join(tmp_dir, 'keystok_cache.data')
12
+ end
13
+
14
+ def cache_file_exists?
15
+ File.exists?(cache_file_path)
16
+ end
17
+
18
+ def cache_stream(method = :read)
19
+ case method
20
+ when :write
21
+ mode = 'wb'
22
+ else
23
+ mode = 'r'
24
+ end
25
+ File.open(cache_file_path, mode)
26
+ end
27
+
28
+ def load_cache(iostream = nil)
29
+ Keystok.logger.warn('Loading data from cache')
30
+ iostream ||= cache_stream
31
+ iostream.read
32
+ end
33
+
34
+ def write_cache(cache_data, iostream = nil)
35
+ iostream ||= cache_stream(:write)
36
+ iostream.write(cache_data)
37
+ iostream.flush
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,198 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under GitDock Oy license terms.
3
+ # See https://bitbucket.org/keystok/keystok-client-ruby/raw/master/LICENSE.txt
4
+ # for details.
5
+
6
+ require 'faraday'
7
+ require 'json'
8
+ require 'oauth2'
9
+
10
+ require 'keystok/aes_crypto'
11
+ require 'keystok/cache'
12
+
13
+ module Keystok
14
+ # Keystok client class
15
+ class Client
16
+ include AESCrypto
17
+ include Cache
18
+
19
+ API_HOST = 'https://api.keystok.com'
20
+ AUTH_HOST = 'https://keystok.com'
21
+ DEFAULT_CONFIG = { eager_fetching: true }
22
+ REQUEST_TRY_COUNT = 3
23
+
24
+ def initialize(config = {})
25
+ @config = DEFAULT_CONFIG.merge(keys_to_symbols(decode_config(config)))
26
+ @keys_store = {}
27
+ end
28
+
29
+ def access_token
30
+ @access_token ||= begin
31
+ fail Error::ConfigError, 'SDK not configured' if @config[:rt].nil?
32
+ refresh_token = OAuth2::AccessToken.new(oauth_client, nil,
33
+ refresh_token:
34
+ @config[:rt])
35
+ access_token = nil
36
+ REQUEST_TRY_COUNT.times do |try_count|
37
+ begin
38
+ access_token = refresh_token.refresh!
39
+ break
40
+ rescue Faraday::Error::ClientError => exception
41
+ Keystok.logger.warn(
42
+ "Exception during token refresh: #{exception.message}")
43
+ raise if try_count == (REQUEST_TRY_COUNT - 1)
44
+ end
45
+ end
46
+ access_token
47
+ end
48
+ end
49
+
50
+ def configured?
51
+ check_config
52
+ true
53
+ rescue Error::ConfigError
54
+ false
55
+ end
56
+
57
+ def get(key_name_or_symbol, force_reload = false)
58
+ key_name = key_name_or_symbol.to_s
59
+ if force_reload || @config[:volatile] || @keys_store[key_name].nil?
60
+ load_keys(key_name_or_symbol)
61
+ end
62
+ @keys_store[key_name]
63
+ end
64
+
65
+ def keys(force_reload = false)
66
+ load_keys if force_reload || @config[:volatile] || @keys_store.empty?
67
+ @keys_store
68
+ end
69
+
70
+ private
71
+
72
+ def check_config
73
+ %w(rt dk id).map(&:to_sym).each do |key|
74
+ if @config[key].nil?
75
+ fail Error::ConfigError, "Config key: #{key} is missing!"
76
+ end
77
+ end
78
+ end
79
+
80
+ def connection
81
+ @connection ||= Faraday.new(url: @config[:api_host] || API_HOST,
82
+ ssl: { verify: true })
83
+ end
84
+
85
+ def decode_config(connection_string)
86
+ config_hash = connection_string
87
+ case
88
+ when connection_string.kind_of?(Hash)
89
+ when connection_string.kind_of?(String)
90
+ config_hash = decode_string_config(connection_string)
91
+ else
92
+ fail Error::ConfigError, 'Unknown config format'
93
+ end
94
+ if config_hash[:connection_string]
95
+ decoded_hash = decode_string_config(config_hash[:connection_string])
96
+ config_hash.delete(:connection_string)
97
+ config_hash = decoded_hash.merge(config_hash)
98
+ end
99
+ config_hash
100
+ end
101
+
102
+ def decode_json_string_config(connection_string)
103
+ parsed_config = nil
104
+ begin
105
+ parsed_config = JSON.parse(connection_string)
106
+ # rubocop:disable HandleExceptions
107
+ rescue JSON::ParserError
108
+ # rubocop:enable HandleExceptions
109
+ # Whatever may fail, we don't want to raise it.
110
+ end
111
+ parsed_config
112
+ end
113
+
114
+ def decode_string_config(connection_string)
115
+ return {} if connection_string == ''
116
+ parsed_config = decode_json_string_config(connection_string)
117
+ unless parsed_config
118
+ decoded_string = Base64.decode64(connection_string)
119
+ parsed_config = decode_json_string_config(decoded_string)
120
+ end
121
+ fail Error::ConfigError, 'Unknown config format' unless parsed_config
122
+ parsed_config
123
+ end
124
+
125
+ def fetch_data(key = nil)
126
+ response = nil
127
+ if key.nil? || @config[:eager_fetching]
128
+ key_path_part = ''
129
+ else
130
+ key_path_part = "/#{key}"
131
+ end
132
+ REQUEST_TRY_COUNT.times do |try_count|
133
+ begin
134
+ response = connection.get do |request|
135
+ request.url ['/apps/', @config[:id],
136
+ '/deploy', key_path_part,
137
+ '?access_token=', access_token.token].join
138
+ request.options[:open_timeout] = 5
139
+ request.options[:timeout] = 5
140
+ end
141
+ if response.status == 200
142
+ break
143
+ else
144
+ Keystok.logger.warn(
145
+ "Keystok API response status: #{response.status}")
146
+ @access_token = nil
147
+ end
148
+ rescue Faraday::Error::ClientError => exception
149
+ Keystok.logger.warn(
150
+ "Exception during Keystok API data fetch: #{exception.message}")
151
+ raise if try_count == (REQUEST_TRY_COUNT - 1)
152
+ end
153
+ end
154
+ response
155
+ end
156
+
157
+ def keys_to_symbols(input_hash)
158
+ Hash[input_hash.map do |key, val|
159
+ [key.kind_of?(String) ? key.to_s.to_sym : key, val]
160
+ end]
161
+ end
162
+
163
+ def load_keys(key = nil)
164
+ begin
165
+ response = fetch_data(key)
166
+ if response.status == 200
167
+ response_data = response.body
168
+ elsif cache_file_exists?
169
+ response_data = load_cache
170
+ else
171
+ fail Keystok::Error::ConnectionError,
172
+ "No cache data and response code:\n" +
173
+ "#{response.status} with body: #{response.body}"
174
+ end
175
+ rescue Faraday::Error::ClientError => exception
176
+ if cache_file_exists?
177
+ response_data = load_cache
178
+ else
179
+ raise Keystok::Error::ConnectionError,
180
+ "No cache data and connection error:\n" +
181
+ "#{exception.class} with message: #{exception.message}"
182
+ end
183
+ end
184
+ @keys_store = {}
185
+ JSON.parse(response_data).each do |key_id, key_info|
186
+ @keys_store[key_id] = decrypt_key(key_info['key'])
187
+ end
188
+ write_cache(response_data) unless @config[:no_cache]
189
+ @keys_store
190
+ end
191
+
192
+ def oauth_client
193
+ @oauth_client ||= begin
194
+ OAuth2::Client.new(nil, nil, site: @config[:auth_host] || AUTH_HOST)
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under GitDock Oy license terms.
3
+ # See https://bitbucket.org/keystok/keystok-client-ruby/raw/master/LICENSE.txt
4
+ # for details.
5
+
6
+ module Keystok
7
+ module Error
8
+ class CacheCorrupted < StandardError
9
+ end
10
+
11
+ class ConfigError < StandardError
12
+ end
13
+
14
+ class ConnectionError < StandardError
15
+ end
16
+
17
+ class UnsupportedDataFormat < StandardError
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under GitDock Oy license terms.
3
+ # See https://bitbucket.org/keystok/keystok-client-ruby/raw/master/LICENSE.txt
4
+ # for details.
5
+
6
+ module Keystok
7
+ # Class used to integrate with Rails
8
+ class Railtie < Rails::Railtie
9
+ initializer 'keystok.configure_rails_initialization' do
10
+ Keystok.logger = Rails.logger
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under GitDock Oy license terms.
3
+ # See https://bitbucket.org/keystok/keystok-client-ruby/raw/master/LICENSE.txt
4
+ # for details.
5
+
6
+ #:nodoc:
7
+ module Keystok
8
+ VERSION = '1.0.0'
9
+ end
data/lib/keystok.rb ADDED
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under GitDock Oy license terms.
3
+ # See https://bitbucket.org/keystok/keystok-client-ruby/raw/master/LICENSE.txt
4
+ # for details.
5
+
6
+ require 'faraday'
7
+ require 'json'
8
+ require 'logger'
9
+ require 'yaml'
10
+
11
+ require 'keystok/version'
12
+ require 'keystok/errors'
13
+ require 'keystok/client'
14
+
15
+ #:nodoc:
16
+ module Keystok
17
+ class << self
18
+ attr_accessor :logger
19
+ end
20
+ end
21
+
22
+ if defined? Rails::Railtie
23
+ require 'keystok/railtie'
24
+ else
25
+ Keystok.logger = Logger.new(STDOUT)
26
+ end
@@ -0,0 +1 @@
1
+ :aes256:eyJpdiI6IkwyRGEzVFg5bnczMWswNVc0RnBpaFE9PSIsInYiOjEsIml0ZXIiOjEwMDAsImtzIjoyNTYsInRzIjo2NCwibW9kZSI6ImNiYyIsImFkYXRhIjoiIiwiY2lwaGVyIjoiYWVzIiwic2FsdCI6ImM0czhpZ3FIOFA0PSIsImN0IjoiZ0FWYVNNaDZINFIzdnl6TnNoelJ1Zz09In0=
@@ -0,0 +1,8 @@
1
+ {
2
+ "key_1": {
3
+ "key": ":aes256:eyJpdiI6IkwyRGEzVFg5bnczMWswNVc0RnBpaFE9PSIsInYiOjEsIml0ZXIiOjEwMDAsImtzIjoyNTYsInRzIjo2NCwibW9kZSI6ImNiYyIsImFkYXRhIjoiIiwiY2lwaGVyIjoiYWVzIiwic2FsdCI6ImM0czhpZ3FIOFA0PSIsImN0IjoiZ0FWYVNNaDZINFIzdnl6TnNoelJ1Zz09In0="
4
+ },
5
+ "key_2": {
6
+ "key": ":aes256:eyJpdiI6Ijd0N1ArNGhEV2cwL2pZeVBqdTBQV3c9PSIsInYiOjEsIml0ZXIiOjEwMDAsImtzIjoyNTYsInRzIjo2NCwibW9kZSI6ImNiYyIsImFkYXRhIjoiIiwiY2lwaGVyIjoiYWVzIiwic2FsdCI6ImM0czhpZ3FIOFA0PSIsImN0IjoiL1h2ZXF4dlIwOU1kSmc4UGd3eHJoZz09In0="
7
+ }
8
+ }
@@ -0,0 +1,90 @@
1
+ # encoding: utf-8
2
+ # This file is distributed under GitDock Oy license terms.
3
+ # See https://bitbucket.org/keystok/keystok-client-ruby/raw/master/LICENSE.txt
4
+ # for details.
5
+
6
+ require 'spec_helper'
7
+
8
+ describe Keystok::AESCrypto do
9
+ let(:dummy_class) { Class.new { include Keystok::AESCrypto } }
10
+ let(:dummy) { dummy_class.new }
11
+
12
+ describe 'cipher' do
13
+ it 'works without any errors' do
14
+ dummy.cipher('plain text', 'key_' * 10, 'vector_' * 10, 256, :CBC)
15
+ end
16
+
17
+ it 'works without passing key_size and block_mode' do
18
+ dummy.cipher('plain text', 'key_' * 10, 'vector_' * 10)
19
+ end
20
+
21
+ it 'is passing OpenSSL exceptions' do
22
+ expect do
23
+ dummy.cipher('plain text', 'a', 'vector_' * 10)
24
+ end.to raise_error(OpenSSL::Cipher::CipherError)
25
+ end
26
+ end
27
+
28
+ describe 'decipher' do
29
+ let(:encrypted) { "A.\xFC\xDDW=\xB7\xCF\x02\x88\xE3:sA\x90S" }
30
+
31
+ it 'works without any errors' do
32
+ dummy.decipher(encrypted, 'key_' * 10, 'vector_' * 10, 256, :CBC)
33
+ end
34
+
35
+ it 'works without passing key_size and block_mode' do
36
+ dummy.decipher(encrypted, 'key_' * 10, 'vector_' * 10)
37
+ end
38
+
39
+ it 'is passing OpenSSL exceptions' do
40
+ expect do
41
+ dummy.decipher('encrypted', 'a', 'vector_' * 10)
42
+ end.to raise_error(OpenSSL::Cipher::CipherError, 'key length too short')
43
+ end
44
+ end
45
+
46
+ describe 'sanity check' do
47
+ it 'decryption of encrypted data returns proper value' do
48
+ plain_text = 'plain text'
49
+ encrypted = dummy.cipher(plain_text, 'key_' * 10, 'vector_' * 10)
50
+ decrypted_text = dummy.decipher(encrypted, 'key_' * 10, 'vector_' * 10)
51
+ expect(decrypted_text).to eq(plain_text)
52
+ end
53
+ end
54
+
55
+ describe 'decrypt_key' do
56
+ let(:encrypted_data) do
57
+ File.open(File.expand_path('../../fixtures/encrypted_data_00.data',
58
+ __FILE__)).read
59
+ end
60
+ let(:config) do
61
+ { dk:
62
+ '965391f2bba37b4586431b8690d7044d5cdc73adf7dda539f8dd3a60cb3e9b12' }
63
+ end
64
+
65
+ it 'properly decrypts data' do
66
+ expect(dummy.decrypt_key(encrypted_data, config)).to eq('Value 1')
67
+ end
68
+
69
+ it "raise UnsupportedDataFormat when data prefix is no ':aes256'" do
70
+ expect do
71
+ dummy.decrypt_key(encrypted_data.sub(':aes256:', ':cesar:'), config)
72
+ end.to raise_error(Keystok::Error::UnsupportedDataFormat,
73
+ 'Wrong encryption algorithm')
74
+ end
75
+
76
+ it 'raise ConfigError when no decryption key is provided' do
77
+ expect do
78
+ dummy.decrypt_key(encrypted_data, {})
79
+ end.to raise_error(Keystok::Error::ConfigError,
80
+ 'No decryption key in config')
81
+ end
82
+
83
+ it 'is passing OpenSSL exceptions' do
84
+ expect do
85
+ dummy.decrypt_key(encrypted_data, dk: 'a')
86
+ end.to raise_error(OpenSSL::Cipher::CipherError,
87
+ 'bad decrypt')
88
+ end
89
+ end
90
+ end