pg_export 0.5.1 → 0.6.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +2 -8
  4. data/bin/pg_export +39 -19
  5. data/lib/pg_export/aes/base.rb +47 -0
  6. data/lib/pg_export/aes/decryptor.rb +13 -0
  7. data/lib/pg_export/aes/encryptor.rb +13 -0
  8. data/lib/pg_export/aes.rb +3 -0
  9. data/lib/pg_export/bash/adapter.rb +31 -0
  10. data/lib/pg_export/bash/factory.rb +23 -0
  11. data/lib/pg_export/bash/repository.rb +18 -0
  12. data/lib/pg_export/boot_container.rb +69 -0
  13. data/lib/pg_export/build_logger.rb +19 -0
  14. data/lib/pg_export/configuration.rb +11 -53
  15. data/lib/pg_export/{entities/dump.rb → dump.rb} +18 -4
  16. data/lib/pg_export/errors.rb +3 -3
  17. data/lib/pg_export/ftp/adapter.rb +41 -0
  18. data/lib/pg_export/ftp/connection.rb +40 -0
  19. data/lib/pg_export/ftp/repository.rb +40 -0
  20. data/lib/pg_export/roles/colourable_string.rb +19 -0
  21. data/lib/pg_export/roles/human_readable.rb +17 -0
  22. data/lib/pg_export/roles/interactive.rb +98 -0
  23. data/lib/pg_export/roles/validatable.rb +24 -0
  24. data/lib/pg_export/services/create_and_export_dump.rb +20 -0
  25. data/lib/pg_export/version.rb +1 -1
  26. data/lib/pg_export.rb +18 -56
  27. data/pg_export.gemspec +2 -1
  28. metadata +49 -31
  29. data/lib/pg_export/includable_modules/colourable_string.rb +0 -17
  30. data/lib/pg_export/includable_modules/dump/size_human.rb +0 -15
  31. data/lib/pg_export/includable_modules/interactive.rb +0 -97
  32. data/lib/pg_export/includable_modules/logging.rb +0 -31
  33. data/lib/pg_export/includable_modules/services_container.rb +0 -41
  34. data/lib/pg_export/services/aes/base.rb +0 -26
  35. data/lib/pg_export/services/aes/decryptor.rb +0 -12
  36. data/lib/pg_export/services/aes/encryptor.rb +0 -12
  37. data/lib/pg_export/services/aes.rb +0 -28
  38. data/lib/pg_export/services/bash_utils.rb +0 -32
  39. data/lib/pg_export/services/dump_storage.rb +0 -48
  40. data/lib/pg_export/services/ftp_adapter.rb +0 -38
  41. data/lib/pg_export/services/ftp_connection.rb +0 -28
@@ -0,0 +1,98 @@
1
+ require 'cli_spinnable'
2
+ require_relative 'colourable_string'
3
+
4
+ class PgExport
5
+ module Roles
6
+ module Interactive
7
+ include CliSpinnable
8
+ using ColourableString
9
+
10
+ def self.extended(_)
11
+ puts 'Interactive mode, for restoring dump into database.'.green
12
+ end
13
+
14
+ def call(database, _keep_dumps = nil)
15
+ initialize_connection
16
+ dumps = print_all_dumps
17
+ dump = download_dump(select_dump(dumps))
18
+ t = Thread.new { container[:ftp_connection].close }
19
+ restore_downloaded_dump(dump, database)
20
+ t.join
21
+ puts 'Success'.green
22
+ self
23
+ end
24
+
25
+ private
26
+
27
+ def initialize_connection
28
+ with_spinner do |cli|
29
+ cli.print 'Connecting to FTP'
30
+ container[:ftp_connection].ftp
31
+ cli.tick
32
+ end
33
+ end
34
+
35
+ def print_all_dumps
36
+ dumps = container[:ftp_repository].all
37
+ dumps.each.with_index(1) do |name, i|
38
+ print "(#{i}) "
39
+ puts name.to_s.gray
40
+ end
41
+
42
+ dumps
43
+ end
44
+
45
+ def select_dump(dumps)
46
+ puts 'Which dump would you like to import?'
47
+ number = loop do
48
+ print "Type from 1 to #{dumps.count} (1): "
49
+ number = gets.chomp.to_i
50
+ break number if (1..dumps.count).cover?(number)
51
+ puts 'Invalid number. Please try again.'.red
52
+ end
53
+
54
+ dumps.fetch(number - 1)
55
+ end
56
+
57
+ def download_dump(name)
58
+ dump = nil
59
+
60
+ with_spinner do |cli|
61
+ cli.print "Downloading dump #{name}"
62
+ encrypted_dump = container[:ftp_repository].get(name)
63
+ cli.print " (#{encrypted_dump.size_human})"
64
+ cli.tick
65
+ cli.print "Decrypting dump #{name}"
66
+ dump = container[:decryptor].call(encrypted_dump)
67
+ cli.print " (#{dump.size_human})"
68
+ cli.tick
69
+ end
70
+
71
+ dump
72
+ rescue OpenSSL::Cipher::CipherError => e
73
+ puts "Problem decrypting dump file: #{e}. Try again.".red
74
+ retry
75
+ end
76
+
77
+ def restore_downloaded_dump(dump, database)
78
+ puts 'To which database you would like to restore the downloaded dump?'
79
+ if database == 'undefined'
80
+ print 'Enter a local database name: '
81
+ else
82
+ print "Enter a local database name (#{database}): "
83
+ end
84
+ db_name = gets.chomp
85
+ db_name = db_name.empty? ? database : db_name
86
+ with_spinner do |cli|
87
+ cli.print "Restoring dump to #{db_name} database"
88
+ container[:bash_repository].persist(dump, db_name)
89
+ cli.tick
90
+ end
91
+ self
92
+ rescue PgRestoreError => e
93
+ puts e.to_s.red
94
+ retry
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,24 @@
1
+ require 'dry-types'
2
+
3
+ class PgExport
4
+ module Roles
5
+ module Validatable
6
+ include Dry::Types.module
7
+
8
+ VALID_NON_EMPTY_STRING = Strict::String.constrained(min_size: 1)
9
+ VALID_POSITIVE_INTEGER = Strict::Int.constrained(gteq: 0)
10
+
11
+ def validate_database_name(database)
12
+ VALID_NON_EMPTY_STRING[database]
13
+ rescue Dry::Types::ConstraintError
14
+ raise ArgumentError, 'The "database" parameter has to be a valid, non-empty string'
15
+ end
16
+
17
+ def validate_keep_dumps(keep_dumps)
18
+ VALID_POSITIVE_INTEGER[keep_dumps]
19
+ rescue Dry::Types::ConstraintError
20
+ raise ArgumentError, 'The "keep_dumps" parameter has to be a valid, non-negative integer'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ class PgExport
2
+ module Services
3
+ class CreateAndExportDump
4
+ def initialize(bash_factory:, encryptor:, ftp_repository:)
5
+ @bash_factory, @encryptor, @ftp_repository = bash_factory, encryptor, ftp_repository
6
+ end
7
+
8
+ def call(database_name, keep_dumps)
9
+ dump = bash_factory.build_dump(database_name)
10
+ encrypted_dump = encryptor.call(dump)
11
+ ftp_repository.persist(encrypted_dump)
12
+ ftp_repository.remove_old(database_name, keep_dumps)
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :bash_factory, :encryptor, :ftp_repository
18
+ end
19
+ end
20
+ end
@@ -1,3 +1,3 @@
1
1
  class PgExport
2
- VERSION = '0.5.1'.freeze
2
+ VERSION = '0.6.0'.freeze
3
3
  end
data/lib/pg_export.rb CHANGED
@@ -1,67 +1,29 @@
1
- require 'logger'
2
- require 'tempfile'
3
- require 'zlib'
4
- require 'net/ftp'
5
- require 'openssl'
6
- require 'forwardable'
7
- require 'open3'
8
-
9
1
  require 'pg_export/version'
10
- require 'pg_export/includable_modules/logging'
11
- require 'pg_export/includable_modules/dump/size_human'
12
- require 'pg_export/includable_modules/services_container'
13
- require 'pg_export/errors'
14
2
  require 'pg_export/configuration'
15
- require 'pg_export/entities/dump'
16
- require 'pg_export/services/ftp_adapter'
17
- require 'pg_export/services/ftp_connection'
18
- require 'pg_export/services/bash_utils'
19
- require 'pg_export/services/dump_storage'
20
- require 'pg_export/services/aes'
21
- require 'pg_export/services/aes/base'
22
- require 'pg_export/services/aes/encryptor'
23
- require 'pg_export/services/aes/decryptor'
3
+ require 'pg_export/boot_container'
4
+ require 'pg_export/roles/interactive'
5
+ require 'pg_export/errors'
6
+ require 'pg_export/roles/validatable'
24
7
 
25
8
  class PgExport
26
- extend Forwardable
27
- include ServicesContainer
28
-
29
- def_delegators :services_container, :config, :bash_utils, :dump_storage, :ftp_connection, :encryptor, :decryptor
30
-
31
- def initialize
32
- yield config if block_given?
9
+ include Roles::Validatable
10
+
11
+ def initialize(**args)
12
+ config = Configuration.new(**args)
13
+ extend Roles::Interactive if config.interactive
14
+ @container = BootContainer.call(config.to_h)
15
+ rescue Dry::Struct::Error => e
16
+ raise ArgumentError, e
33
17
  end
34
18
 
35
- def call
36
- config.validate
37
- concurrently do |threads|
38
- threads << create_dump
39
- threads << open_ftp_connection
40
- end
41
- dump_storage.upload(dump)
42
- dump_storage.remove_old
43
- self
19
+ def call(database_name, keep_dumps)
20
+ container[:create_and_export_dump].call(
21
+ validate_database_name(database_name),
22
+ validate_keep_dumps(keep_dumps)
23
+ )
44
24
  end
45
25
 
46
26
  private
47
27
 
48
- def concurrently
49
- [].tap do |threads|
50
- yield threads
51
- end.each(&:join)
52
- end
53
-
54
- def dump
55
- create_dump[:dump]
56
- end
57
-
58
- def create_dump
59
- @create_dump ||= Thread.new do
60
- Thread.current[:dump] = encryptor.call(bash_utils.create_dump)
61
- end
62
- end
63
-
64
- def open_ftp_connection
65
- Thread.new { ftp_connection.open }
66
- end
28
+ attr_reader :container
67
29
  end
data/pg_export.gemspec CHANGED
@@ -21,12 +21,13 @@ Gem::Specification.new do |spec|
21
21
  spec.required_ruby_version = '>= 2.1.0'
22
22
 
23
23
  spec.add_dependency 'cli_spinnable', '~> 0.2'
24
+ spec.add_dependency 'dry-types', '~> 0.11.1'
25
+ spec.add_dependency 'dry-struct', '~> 0.3.1'
24
26
 
25
27
  spec.add_development_dependency 'bundler', '~> 1.10'
26
28
  spec.add_development_dependency 'rubocop', '~> 0.44'
27
29
  spec.add_development_dependency 'rake', '~> 10.0'
28
30
  spec.add_development_dependency 'rspec', '~> 3.4'
29
31
  spec.add_development_dependency 'pg', '~> 0.19'
30
- spec.add_development_dependency 'simplecov', '~> 0.12'
31
32
  spec.add_development_dependency 'pry'
32
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_export
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Krzysztof Maicher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-31 00:00:00.000000000 Z
11
+ date: 2017-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cli_spinnable
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-types
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.11.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.11.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-struct
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.3.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.3.1
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: bundler
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,20 +122,6 @@ dependencies:
94
122
  - - "~>"
95
123
  - !ruby/object:Gem::Version
96
124
  version: '0.19'
97
- - !ruby/object:Gem::Dependency
98
- name: simplecov
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '0.12'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '0.12'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: pry
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -147,22 +161,26 @@ files:
147
161
  - bin/pg_export
148
162
  - bin/setup
149
163
  - lib/pg_export.rb
164
+ - lib/pg_export/aes.rb
165
+ - lib/pg_export/aes/base.rb
166
+ - lib/pg_export/aes/decryptor.rb
167
+ - lib/pg_export/aes/encryptor.rb
168
+ - lib/pg_export/bash/adapter.rb
169
+ - lib/pg_export/bash/factory.rb
170
+ - lib/pg_export/bash/repository.rb
171
+ - lib/pg_export/boot_container.rb
172
+ - lib/pg_export/build_logger.rb
150
173
  - lib/pg_export/configuration.rb
151
- - lib/pg_export/entities/dump.rb
174
+ - lib/pg_export/dump.rb
152
175
  - lib/pg_export/errors.rb
153
- - lib/pg_export/includable_modules/colourable_string.rb
154
- - lib/pg_export/includable_modules/dump/size_human.rb
155
- - lib/pg_export/includable_modules/interactive.rb
156
- - lib/pg_export/includable_modules/logging.rb
157
- - lib/pg_export/includable_modules/services_container.rb
158
- - lib/pg_export/services/aes.rb
159
- - lib/pg_export/services/aes/base.rb
160
- - lib/pg_export/services/aes/decryptor.rb
161
- - lib/pg_export/services/aes/encryptor.rb
162
- - lib/pg_export/services/bash_utils.rb
163
- - lib/pg_export/services/dump_storage.rb
164
- - lib/pg_export/services/ftp_adapter.rb
165
- - lib/pg_export/services/ftp_connection.rb
176
+ - lib/pg_export/ftp/adapter.rb
177
+ - lib/pg_export/ftp/connection.rb
178
+ - lib/pg_export/ftp/repository.rb
179
+ - lib/pg_export/roles/colourable_string.rb
180
+ - lib/pg_export/roles/human_readable.rb
181
+ - lib/pg_export/roles/interactive.rb
182
+ - lib/pg_export/roles/validatable.rb
183
+ - lib/pg_export/services/create_and_export_dump.rb
166
184
  - lib/pg_export/version.rb
167
185
  - pg_export.gemspec
168
186
  homepage: https://github.com/maicher/pg_export
@@ -185,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
203
  version: '0'
186
204
  requirements: []
187
205
  rubyforge_project:
188
- rubygems_version: 2.6.8
206
+ rubygems_version: 2.5.1
189
207
  signing_key:
190
208
  specification_version: 4
191
209
  summary: CLI for creating and exporting PostgreSQL dumps to FTP.
@@ -1,17 +0,0 @@
1
- class PgExport
2
- module ColourableString
3
- refine String do
4
- def red
5
- "\e[31m#{self}\e[0m"
6
- end
7
-
8
- def green
9
- "\e[0;32;49m#{self}\e[0m"
10
- end
11
-
12
- def gray
13
- "\e[37m#{self}\e[0m"
14
- end
15
- end
16
- end
17
- end
@@ -1,15 +0,0 @@
1
- class PgExport
2
- class Dump
3
- module SizeHuman
4
- def size_human
5
- {
6
- 'B' => 1024,
7
- 'kB' => 1024 * 1024,
8
- 'MB' => 1024 * 1024 * 1024,
9
- 'GB' => 1024 * 1024 * 1024 * 1024,
10
- 'TB' => 1024 * 1024 * 1024 * 1024 * 1024
11
- }.each_pair { |e, s| return "#{(size.to_f / (s / 1024)).round(2)}#{e}" if size < s }
12
- end
13
- end
14
- end
15
- end
@@ -1,97 +0,0 @@
1
- class PgExport
2
- module Interactive
3
- include CliSpinnable
4
- using ColourableString
5
-
6
- def self.extended(_)
7
- puts 'Interactive mode, for restoring dump into database.'.green
8
- end
9
-
10
- def call
11
- initialize_connection
12
- print_all_dumps
13
- selected_dump = select_dump
14
- dump = download_dump(selected_dump)
15
- concurrently do |threads|
16
- threads << Thread.new(dump) { restore_downloaded_dump(dump) }
17
- threads << Thread.new { ftp_connection.close }
18
- end
19
- puts 'Success'.green
20
- self
21
- end
22
-
23
- private
24
-
25
- def initialize_connection
26
- with_spinner do |cli|
27
- cli.print 'Connecting to FTP'
28
- ftp_connection.open
29
- cli.tick
30
- end
31
- end
32
-
33
- def print_all_dumps
34
- dumps.each.with_index(1) do |name, i|
35
- print "(#{i}) "
36
- puts name.to_s.gray
37
- end
38
- self
39
- end
40
-
41
- def select_dump
42
- puts 'Which dump would you like to import?'
43
- number = loop do
44
- print "Type from 1 to #{dumps.count} (1): "
45
- number = gets.chomp.to_i
46
- break number if (1..dumps.count).cover?(number)
47
- puts 'Invalid number. Please try again.'.red
48
- end
49
-
50
- dumps.fetch(number - 1)
51
- end
52
-
53
- def download_dump(name)
54
- dump = nil
55
-
56
- with_spinner do |cli|
57
- cli.print "Downloading dump #{name}"
58
- encrypted_dump = dump_storage.download(name)
59
- cli.print " (#{encrypted_dump.size_human})"
60
- cli.tick
61
- cli.print "Decrypting dump #{name}"
62
- dump = decryptor.call(encrypted_dump)
63
- cli.print " (#{dump.size_human})"
64
- cli.tick
65
- end
66
-
67
- dump
68
- rescue OpenSSL::Cipher::CipherError => e
69
- puts "Problem decrypting dump file: #{e}. Try again.".red
70
- retry
71
- end
72
-
73
- def restore_downloaded_dump(dump)
74
- puts 'To which database you would like to restore the downloaded dump?'
75
- if config.database == 'undefined'
76
- print 'Enter a local database name: '
77
- else
78
- print "Enter a local database name (#{config.database}): "
79
- end
80
- database = gets.chomp
81
- database = database.empty? ? config.database : database
82
- with_spinner do |cli|
83
- cli.print "Restoring dump to #{database} database"
84
- bash_utils.restore_dump(dump, database)
85
- cli.tick
86
- end
87
- self
88
- rescue PgRestoreError => e
89
- puts e.to_s.red
90
- retry
91
- end
92
-
93
- def dumps
94
- @dumps ||= dump_storage.all
95
- end
96
- end
97
- end
@@ -1,31 +0,0 @@
1
- class PgExport
2
- module Logging
3
- FORMAT_PLAIN = ->(_, _, _, message) { "#{message}\n" }
4
- FORMAT_TIMESTAMPED = ->(severity, datetime, progname, message) { "#{datetime} #{Process.pid} TID-#{Thread.current.object_id.to_s(36)}#{progname} #{severity}: #{message}\n" }
5
- FORMAT_MUTED = ->(_, _, _, _) {}
6
-
7
- class << self
8
- def logger
9
- @logger ||= Logger.new(STDOUT).tap do |logger|
10
- logger.formatter = FORMAT_PLAIN
11
- end
12
- end
13
-
14
- def format_default
15
- logger.formatter = FORMAT_PLAIN
16
- end
17
-
18
- def format_timestamped
19
- logger.formatter = FORMAT_TIMESTAMPED
20
- end
21
-
22
- def mute
23
- logger.formatter = FORMAT_MUTED
24
- end
25
- end
26
-
27
- def logger
28
- Logging.logger
29
- end
30
- end
31
- end
@@ -1,41 +0,0 @@
1
- class PgExport
2
- module ServicesContainer
3
- class << self
4
- def config
5
- @config ||= Configuration.new
6
- end
7
-
8
- def aes
9
- @aes ||= Aes.new(config.dump_encryption_key)
10
- end
11
-
12
- def encryptor
13
- @encryptor ||= aes.build_encryptor
14
- end
15
-
16
- def decryptor
17
- @decryptor ||= aes.build_decryptor
18
- end
19
-
20
- def bash_utils
21
- @bash_utils ||= BashUtils.new(config.database)
22
- end
23
-
24
- def ftp_connection
25
- @ftp_connection ||= FtpConnection.new(config.ftp_params)
26
- end
27
-
28
- def ftp_adapter
29
- @ftp_adapter ||= FtpAdapter.new(ftp_connection)
30
- end
31
-
32
- def dump_storage
33
- @dump_storage ||= DumpStorage.new(ftp_adapter, config.database, config.keep_dumps)
34
- end
35
- end
36
-
37
- def services_container
38
- @services_container ||= ServicesContainer
39
- end
40
- end
41
- end
@@ -1,26 +0,0 @@
1
- class PgExport
2
- class Aes
3
- class Base
4
- include Logging
5
-
6
- def initialize(cipher)
7
- @cipher = cipher
8
- end
9
-
10
- private
11
-
12
- def copy_using(cipher, from:, to:)
13
- cipher.reset
14
- to.open(:write) do |f|
15
- from.each_chunk do |chunk|
16
- f << cipher.update(chunk)
17
- end
18
- f << cipher.final
19
- end
20
- self
21
- end
22
-
23
- attr_reader :cipher
24
- end
25
- end
26
- end
@@ -1,12 +0,0 @@
1
- class PgExport
2
- class Aes
3
- class Decryptor < Base
4
- def call(enc_dump)
5
- dump = Dump.new('Dump')
6
- copy_using(cipher, from: enc_dump, to: dump)
7
- logger.info "Create #{dump}"
8
- dump
9
- end
10
- end
11
- end
12
- end
@@ -1,12 +0,0 @@
1
- class PgExport
2
- class Aes
3
- class Encryptor < Base
4
- def call(dump)
5
- enc_dump = Dump.new('Encrypted Dump')
6
- copy_using(cipher, from: dump, to: enc_dump)
7
- logger.info "Create #{enc_dump}"
8
- enc_dump
9
- end
10
- end
11
- end
12
- end
@@ -1,28 +0,0 @@
1
- class PgExport
2
- class Aes
3
- ALGORITHM = 'AES-128-CBC'.freeze
4
-
5
- def initialize(key)
6
- @key = key
7
- end
8
-
9
- def build_encryptor
10
- Aes::Encryptor.new(cipher(:encrypt))
11
- end
12
-
13
- def build_decryptor
14
- Aes::Decryptor.new(cipher(:decrypt))
15
- end
16
-
17
- private
18
-
19
- attr_reader :key
20
-
21
- def cipher(mode)
22
- OpenSSL::Cipher.new(ALGORITHM).tap do |cipher|
23
- cipher.public_send(mode.to_sym)
24
- cipher.key = key
25
- end
26
- end
27
- end
28
- end