keystok 1.0.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 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