trailblazer-endpoint 0.0.3 → 0.0.8

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +16 -0
  3. data/Appraisals +5 -0
  4. data/CHANGES.md +27 -0
  5. data/README.md +40 -5
  6. data/Rakefile +7 -1
  7. data/gemfiles/rails_app.gemfile +12 -0
  8. data/lib/trailblazer/endpoint.rb +50 -14
  9. data/lib/trailblazer/endpoint/adapter.rb +30 -121
  10. data/lib/trailblazer/endpoint/builder.rb +1 -1
  11. data/lib/trailblazer/endpoint/controller.rb +217 -1
  12. data/lib/trailblazer/endpoint/dsl.rb +8 -3
  13. data/lib/trailblazer/endpoint/options.rb +16 -69
  14. data/lib/trailblazer/endpoint/protocol.rb +7 -11
  15. data/lib/trailblazer/endpoint/protocol/cipher.rb +27 -0
  16. data/lib/trailblazer/endpoint/protocol/controller.rb +102 -0
  17. data/lib/trailblazer/endpoint/protocol/find_process_model.rb +15 -0
  18. data/lib/trailblazer/endpoint/version.rb +1 -1
  19. data/test/adapter/api_test.rb +6 -11
  20. data/test/adapter/web_test.rb +2 -5
  21. data/test/config_test.rb +25 -0
  22. data/test/docs/controller_test.rb +220 -73
  23. data/test/endpoint_test.rb +1 -1
  24. data/test/rails-app/.gitignore +8 -2
  25. data/test/rails-app/.ruby-version +1 -0
  26. data/test/rails-app/Gemfile +21 -9
  27. data/test/rails-app/Gemfile.lock +174 -118
  28. data/test/rails-app/app/concepts/app/api/v1/representer/errors.rb +16 -0
  29. data/test/rails-app/app/concepts/auth/jwt.rb +35 -0
  30. data/test/rails-app/app/concepts/auth/operation/authenticate.rb +32 -0
  31. data/test/rails-app/app/concepts/auth/operation/policy.rb +9 -0
  32. data/test/rails-app/app/concepts/song/cell/create.rb +4 -0
  33. data/test/rails-app/app/concepts/song/cell/new.rb +4 -0
  34. data/test/rails-app/app/concepts/song/operation/create.rb +17 -0
  35. data/test/rails-app/app/concepts/song/operation/show.rb +10 -0
  36. data/test/rails-app/app/concepts/song/representer.rb +5 -0
  37. data/test/rails-app/app/concepts/song/view/create.erb +1 -0
  38. data/test/rails-app/app/concepts/song/view/new.erb +1 -0
  39. data/test/rails-app/app/controllers/api/v1/songs_controller.rb +41 -0
  40. data/test/rails-app/app/controllers/application_controller.rb +8 -1
  41. data/test/rails-app/app/controllers/application_controller/api.rb +107 -0
  42. data/test/rails-app/app/controllers/application_controller/web.rb +46 -0
  43. data/test/rails-app/app/controllers/auth_controller.rb +44 -0
  44. data/test/rails-app/app/controllers/home_controller.rb +5 -0
  45. data/test/rails-app/app/controllers/songs_controller.rb +254 -13
  46. data/test/rails-app/app/models/song.rb +6 -0
  47. data/test/rails-app/app/models/user.rb +7 -0
  48. data/test/rails-app/bin/bundle +114 -0
  49. data/test/rails-app/bin/rails +4 -0
  50. data/test/rails-app/bin/rake +4 -0
  51. data/test/rails-app/bin/setup +33 -0
  52. data/test/rails-app/config/application.rb +26 -3
  53. data/test/rails-app/config/credentials.yml.enc +1 -0
  54. data/test/rails-app/config/database.yml +2 -2
  55. data/test/rails-app/config/environments/development.rb +7 -17
  56. data/test/rails-app/config/environments/production.rb +28 -23
  57. data/test/rails-app/config/environments/test.rb +10 -12
  58. data/test/rails-app/config/initializers/application_controller_renderer.rb +6 -4
  59. data/test/rails-app/config/initializers/cors.rb +16 -0
  60. data/test/rails-app/config/initializers/trailblazer.rb +2 -0
  61. data/test/rails-app/config/locales/en.yml +11 -1
  62. data/test/rails-app/config/master.key +1 -0
  63. data/test/rails-app/config/routes.rb +27 -4
  64. data/test/rails-app/db/schema.rb +15 -0
  65. data/test/rails-app/test/controllers/api_songs_controller_test.rb +87 -0
  66. data/test/rails-app/test/controllers/songs_controller_test.rb +152 -145
  67. data/test/rails-app/test/test_helper.rb +7 -1
  68. data/test/test_helper.rb +0 -2
  69. data/trailblazer-endpoint.gemspec +2 -1
  70. metadata +69 -24
  71. data/test/rails-app/config/initializers/cookies_serializer.rb +0 -5
  72. data/test/rails-app/config/initializers/new_framework_defaults.rb +0 -24
  73. data/test/rails-app/config/initializers/session_store.rb +0 -3
  74. data/test/rails-app/config/secrets.yml +0 -22
  75. data/test/rails-app/test/helpers/.keep +0 -0
  76. data/test/rails-app/test/integration/.keep +0 -0
  77. data/test/rails-app/test/mailers/.keep +0 -0
  78. data/test/rails-app/vendor/assets/javascripts/.keep +0 -0
  79. data/test/rails-app/vendor/assets/stylesheets/.keep +0 -0
@@ -35,7 +35,7 @@ module Trailblazer
35
35
  def endpoint_for(id:, builder:, default_options:, **config)
36
36
  options = build_options_for(builder: builder, **config)
37
37
 
38
- return id, Trailblazer::Endpoint.build(default_options.merge(options[:options_for_build]), &options[:protocol_block])
38
+ return id, Trailblazer::Endpoint.build(default_options.merge(options[:options_for_build]).merge(protocol_block: options[:protocol_block]))
39
39
  end
40
40
 
41
41
  # {dsl_options} being something like
@@ -1,7 +1,223 @@
1
1
  module Trailblazer
2
2
  class Endpoint
3
3
  module Controller
4
+ def self.extended(extended)
5
+ extended.extend Trailblazer::Endpoint::Options::DSL # ::directive
6
+ extended.extend Trailblazer::Endpoint::Options::DSL::Inherit
7
+ extended.extend Trailblazer::Endpoint::Options # ::options_for
8
+ extended.extend DSL::Endpoint
4
9
 
5
- end
10
+ extended.include InstanceMethods # {#endpoint_for}
11
+
12
+ # DISCUSS: hmm
13
+ extended.directive :generic_options, ->(*) { Hash.new } # for Controller::endpoint
14
+ extended.directive :options_for_flow_options, ->(*) { Hash.new }
15
+ extended.directive :options_for_endpoint, ->(*) { Hash.new }
16
+ extended.directive :options_for_domain_ctx, ->(*) { Hash.new }
17
+ end
18
+
19
+ # @experimental
20
+ # TODO: test application_controller with and without dsl/api
21
+
22
+ def self.module(framework: :rails, api: false, dsl: false, application_controller: false)
23
+ if application_controller && !api && !dsl # FIXME: not tested! this is useful for an actual AppController with block_options or flow_options settings, "globally"
24
+ Module.new do
25
+ def self.included(includer)
26
+ includer.extend(Controller) # only ::directive and friends.
27
+ end
28
+ end
29
+ elsif api
30
+ Module.new do
31
+ @application_controller = application_controller
32
+ def self.included(includer)
33
+ if @application_controller
34
+ includer.extend Controller
35
+ end
36
+ includer.include(InstanceMethods::API)
37
+ end
38
+ end
39
+ elsif dsl
40
+ Module.new do
41
+ @application_controller = application_controller
42
+ def self.included(includer)
43
+ if @application_controller
44
+ includer.extend Controller
45
+ end
46
+ includer.include Trailblazer::Endpoint::Controller::InstanceMethods::DSL
47
+ includer.include Trailblazer::Endpoint::Controller::Rails
48
+ includer.extend Trailblazer::Endpoint::Controller::Rails::DefaultBlocks
49
+ includer.extend Trailblazer::Endpoint::Controller::Rails::DefaultParams
50
+ includer.include Trailblazer::Endpoint::Controller::Rails::Process
51
+ end
52
+ end # Module
53
+ else
54
+ raise
55
+ end
56
+ end
57
+
58
+ module Rails
59
+ module Process
60
+ def send_action(action_name)
61
+ puts "@@@@@>>>>>>> #{action_name.inspect}"
62
+
63
+ dsl = send(action_name) # call the actual controller action.
64
+
65
+ options, block_options = dsl.to_args(self.class.options_for(:options_for_block_options, controller: self)) # {success_block:, failure_block:, protocol_failure_block:}
66
+ # now we know the authorative blocks
67
+
68
+ Controller.advance_endpoint_for_controller(**options, block_options: block_options, config_source: self.class, controller: self)
69
+ end
70
+
71
+ end # Process
72
+
73
+ # The three default handlers for {Endpoint::with_or_etc}
74
+ # @experimental
75
+ module DefaultBlocks
76
+ def self.extended(extended)
77
+ extended.directive :options_for_block_options, Controller.method(:options_for_block_options)
78
+ end
79
+ end
80
+ # @experimental
81
+ module DefaultParams
82
+ def self.extended(extended)
83
+ extended.directive :options_for_domain_ctx, ->(ctx, controller:, **) { {params: controller.params} }
84
+ end
85
+ end
86
+
87
+ end # Rails
88
+
89
+ module DSL
90
+ module Endpoint
91
+ def self.extended(extended)
92
+ extended.directive(:endpoints, ->(*) { {} })
93
+ end
94
+
95
+ # Builds and registers an endpoint in a controller class.
96
+ def endpoint(name, **options, &block)
97
+ options = options.merge(protocol_block: block) if block_given?
98
+
99
+ return generic_endpoint_config(**name, **options) if name.is_a?(Hash)
100
+ build_endpoint(name, **options)
101
+ end
102
+
103
+ # Configures generic {:adapter}, {:protocol}, etc.
104
+ def generic_endpoint_config(**options)
105
+ self.singleton_class.define_method :generic_options do |ctx,**|
106
+ {
107
+ **options
108
+ }
109
+ end
110
+
111
+ directive :generic_options, method(:generic_options) # FIXME: do we need this?
112
+ end
113
+
114
+ def build_endpoint(name, domain_activity: name, **options)
115
+ build_options = options_for(:generic_options, {}).merge(domain_activity: domain_activity, **options) # DISCUSS: why don't we add this as another directive option/step?
116
+
117
+ endpoint = Trailblazer::Endpoint.build(build_options)
118
+
119
+ directive :endpoints, ->(*) { {name.to_s => endpoint} }
120
+ end
121
+
122
+ end
123
+ end
124
+
125
+ module InstanceMethods
126
+
127
+ def endpoint_for(name, config_source: self.class)
128
+ config_source.options_for(:endpoints, {}).fetch(name.to_s) # TODO: test non-existant endpoint
129
+ end
130
+
131
+ module DSL
132
+ def endpoint(name, **action_options, &block)
133
+ action_options = {controller: self}.merge(action_options) # FIXME: redundant with {API#endpoint}
134
+
135
+ endpoint = endpoint_for(name)
136
+
137
+ invoke_endpoint_with_dsl(endpoint: endpoint, **action_options, &block)
138
+ end
139
+
140
+ def invoke_endpoint_with_dsl(options, &block)
141
+ _dsl = Trailblazer::Endpoint::DSL::Runtime.new(options, block) # provides #Or etc, is returned to {Controller#call}
142
+ end
143
+ end
144
+
145
+ module API
146
+ def endpoint(name, config_source: self.class, **action_options)
147
+ endpoint = endpoint_for(name, config_source: config_source)
148
+
149
+ action_options = {controller: self}.merge(action_options) # FIXME: redundant with {InstanceMethods#endpoint}
150
+
151
+ block_options = config_source.options_for(:options_for_block_options, **action_options)
152
+ block_options = Trailblazer::Endpoint::Options.merge_with(action_options, block_options)
153
+
154
+ signal, (ctx, _) = Trailblazer::Endpoint::Controller.advance_endpoint_for_controller(
155
+ endpoint: endpoint,
156
+ block_options: block_options,
157
+ config_source: config_source,
158
+ **action_options
159
+ )
160
+
161
+ ctx
162
+ end
163
+ end # API
164
+ end
165
+
166
+
167
+ def self.advance_endpoint_for_controller(endpoint:, block_options:, **action_options)
168
+ domain_ctx, endpoint_options, flow_options = compile_options_for_controller(**action_options) # controller-specific, get from directives.
169
+
170
+ endpoint_options = endpoint_options.merge(action_options) # DISCUSS
171
+
172
+ Endpoint::Controller.advance_endpoint(
173
+ endpoint: endpoint,
174
+ block_options: block_options,
175
+
176
+ domain_ctx: domain_ctx,
177
+ endpoint_options: endpoint_options,
178
+ flow_options: flow_options,
179
+ )
180
+ end
181
+
182
+ def self.compile_options_for_controller(options_for_domain_ctx: nil, config_source:, **action_options)
183
+ flow_options = config_source.options_for(:options_for_flow_options, **action_options)
184
+ endpoint_options = config_source.options_for(:options_for_endpoint, **action_options) # "class level"
185
+ domain_ctx = options_for_domain_ctx || config_source.options_for(:options_for_domain_ctx, **action_options)
186
+
187
+ return domain_ctx, endpoint_options, flow_options
188
+ end
189
+
190
+ # Ultimate low-level entry point.
191
+ # Remember that you don't _have_ to use Endpoint.with_or_etc to invoke an endpoint.
192
+ def self.advance_endpoint(endpoint:, block_options:, domain_ctx:, endpoint_options:, flow_options:)
193
+
194
+ # build Context(ctx),
195
+ args, _ = Trailblazer::Endpoint.arguments_for(
196
+ domain_ctx: domain_ctx,
197
+ flow_options: flow_options,
198
+ **endpoint_options,
199
+ )
200
+
201
+ signal, (ctx, _ ) = Trailblazer::Endpoint.with_or_etc(
202
+ endpoint,
203
+ args, # [ctx, flow_options]
204
+
205
+ **block_options,
206
+ # success_block: success_block,
207
+ # failure_block: failure_block,
208
+ # protocol_failure_block: protocol_failure_block,
209
+ )
210
+ end
211
+
212
+ # Default blocks for the {Adapter}.
213
+ def self.options_for_block_options(ctx, controller:, **)
214
+ {
215
+ success_block: ->(ctx, endpoint_ctx:, **) { controller.head 200 },
216
+ failure_block: ->(ctx, **) { controller.head 422 },
217
+ protocol_failure_block: ->(ctx, endpoint_ctx:, **) { controller.head endpoint_ctx[:status] }
218
+ }
219
+ end
220
+
221
+ end # Controller
6
222
  end
7
223
  end
@@ -2,7 +2,7 @@ module Trailblazer
2
2
  class Endpoint
3
3
  module DSL
4
4
  # Run before the endpoint is invoked. This collects the blocks from the controller.
5
- class Runtime < Struct.new(:args, :success_block, :failure_block, :protocol_failure_block)
5
+ class Runtime < Struct.new(:options, :success_block, :failure_block, :protocol_failure_block)
6
6
 
7
7
  def failure(&block)
8
8
  self.failure_block = block
@@ -17,8 +17,13 @@ module Trailblazer
17
17
  end
18
18
 
19
19
  # #call
20
- def to_args
21
- return args, {success_block: success_block, failure_block: failure_block, protocol_failure_block: protocol_failure_block}
20
+ def to_args(default_block_options)
21
+ return options,
22
+ default_block_options.merge( # this adds :invoke.
23
+ success_block: success_block || default_block_options[:success_block],
24
+ failure_block: failure_block || default_block_options[:failure_block],
25
+ protocol_failure_block: protocol_failure_block || default_block_options[:protocol_failure_block]
26
+ )
22
27
  end
23
28
  end
24
29
  end
@@ -1,28 +1,7 @@
1
- # TODO
1
+ # DISCUSS: the generic inheritance/Options logic might be extracted to trailblazer-config or something.
2
+ # it is completely independent and could be helpful for many other configurations.
2
3
  module Trailblazer
3
4
  class Endpoint
4
- def self.Normalizer(target:, options:)
5
- normalizer = Class.new(Trailblazer::Activity::Railway) do
6
- # inject an empty {} for all options.
7
- # options.collect do |(method_name => option)|
8
- # step Normalizer.DefaultToEmptyHash(config_name), id: :"default_#{config_name}"
9
- # end
10
- end
11
-
12
- Normalizer::State.new(normalizer, options)
13
- end
14
-
15
- def self.Normalizer___(options, base_class: Trailblazer::Activity::Path)
16
- normalizer = Class.new(base_class) do
17
- # inject an empty {} for all options.
18
- # options.collect do |(method_name => option)|
19
- # step Normalizer.DefaultToEmptyHash(config_name), id: :"default_#{config_name}"
20
- # end
21
- end
22
-
23
- Normalizer.add(normalizer, nil, options)
24
- end
25
-
26
5
  module Options
27
6
  module DSL
28
7
  def directive(directive_name, *callables, inherit: superclass)
@@ -35,6 +14,7 @@ module Trailblazer
35
14
  @normalizers[directive_name] = Trailblazer::Endpoint::Normalizer.Options(directive_name, *callables, **options) # DISCUSS: allow multiple calls?
36
15
  end
37
16
 
17
+ # Called in {Endpoint::Controller}.
38
18
  def self.extended(extended) # TODO: let's hope this is only called once per hierachy :)
39
19
  extended.instance_variable_set(:@normalizers, {})
40
20
  end
@@ -49,16 +29,25 @@ module Trailblazer
49
29
  end
50
30
 
51
31
  def options_for(directive_name, runtime_options)
52
- normalizer = @normalizers[directive_name]
32
+ normalizer = @normalizers.fetch(directive_name)
53
33
 
54
- ctx = Trailblazer::Context::IndifferentAccess.build(runtime_options, {}, [{}, {}], {}) # FIXME: easier {::build}, please!
34
+ ctx = Trailblazer::Context(runtime_options, {})
55
35
 
56
- signal, (ctx, ) = Trailblazer::Developer.wtf?(normalizer, [ctx])
36
+ # signal, (ctx, ) = Trailblazer::Developer.wtf?(normalizer, [ctx])
37
+ signal, (ctx, ) = Trailblazer::Activity::TaskWrap.invoke(normalizer, [ctx])
57
38
 
58
39
  _, options = ctx.decompose
59
40
  options
60
41
  end
61
- end
42
+
43
+
44
+ # Merge {merged} into {hash}, but only keys that exist in {hash}.
45
+ def self.merge_with(merged, hash)
46
+ keys = hash.keys
47
+ merged = keys.collect { |key| merged.key?(key) ? [key, merged[key]] : nil }.compact.to_h
48
+ hash.merge(merged)
49
+ end
50
+ end # Options
62
51
 
63
52
  module Normalizer
64
53
  def self.Options(directive_name, *callables, base_class: Trailblazer::Activity::Path)
@@ -78,29 +67,6 @@ module Trailblazer
78
67
  target.instance_variable_set(:@config, config)
79
68
  end
80
69
 
81
- class State < Module
82
- def initialize(normalizer, config)
83
- @normalizer = normalizer
84
- @config = config
85
- end
86
-
87
- # called once when extended in {ApplicationController}.
88
- def extended(extended)
89
- super
90
-
91
- extended.extend(Inherited)
92
- Normalizer.add_normalizer!(extended, @normalizer, @config)
93
- end
94
-
95
- end
96
- module Inherited
97
- def inherited(subclass)
98
- super
99
-
100
- Normalizer.add_normalizer!(subclass, @normalizer, @config)
101
- end
102
- end
103
-
104
70
  def self.add(normalizer, directive_name, options)
105
71
  Class.new(normalizer) do
106
72
  options.collect do |callable|
@@ -109,16 +75,6 @@ module Trailblazer
109
75
  end
110
76
  end
111
77
 
112
- def self.CallDirectiveMethod(target, config_name)
113
- ->((ctx, flow_options), *) {
114
- config = target.send(config_name, ctx, **ctx) # e.g. ApplicationController.options_for_endpoint
115
-
116
- ctx[config_name] = ctx[config_name].merge(config)
117
-
118
- return Trailblazer::Activity::Right, [ctx, flow_options]
119
- }
120
- end
121
-
122
78
  def self.CallDirective(callable, option_name)
123
79
  ->((ctx, flow_options), *) {
124
80
  config = callable.(ctx, **ctx) # e.g. ApplicationController.options_for_endpoint
@@ -132,14 +88,5 @@ module Trailblazer
132
88
  }
133
89
  end
134
90
  end # Normalizer
135
-
136
- module Controller
137
- def self.extended(extended)
138
- extended.extend Trailblazer::Endpoint::Options::DSL
139
- extended.extend Trailblazer::Endpoint::Options::DSL::Inherit
140
- extended.extend Trailblazer::Endpoint::Options
141
- end
142
- end # Controller
143
-
144
91
  end
145
92
  end
@@ -1,3 +1,5 @@
1
+ require "trailblazer/activity/dsl/linear"
2
+
1
3
  module Trailblazer
2
4
  class Endpoint
3
5
  # The {Protocol} implements auth*, and calls the domain OP/WF.
@@ -16,18 +18,13 @@ module Trailblazer
16
18
  class Noop < Trailblazer::Activity::Railway
17
19
  end
18
20
 
19
- class Failure < Trailblazer::Activity::End # DISCUSS: move to Act::Railway?
20
- # class Authentication < Failure
21
- # end
22
- end
23
-
24
21
  def self._Path(semantic:, &block) # DISCUSS: the problem with Path currently is https://github.com/trailblazer/trailblazer-activity-dsl-linear/issues/27
25
- Path(track_color: semantic, end_id: "End.#{semantic}", end_task: Failure.new(semantic: semantic), &block)
22
+ Path(track_color: semantic, end_id: "End.#{semantic}", end_task: Activity::End.new(semantic: semantic), &block)
26
23
  end
27
24
 
28
25
  step :authenticate, Output(:failure) => _Path(semantic: :not_authenticated) do
29
26
  # step :handle_not_authenticated
30
- end
27
+ end
31
28
 
32
29
  step :policy, Output(:failure) => _Path(semantic: :not_authorized) do # user from cookie, etc
33
30
  # step :handle_not_authorized
@@ -43,8 +40,8 @@ module Trailblazer
43
40
  # termini for the Adapter this is the only way to get it working right now.
44
41
  # FIXME: is this really the only way to add an {End} to all this?
45
42
  @state.update_sequence do |sequence:, **|
46
- sequence = Activity::Path::DSL.append_end(sequence, task: Failure.new(semantic: :not_found), magnetic_to: :not_found, id: "End.not_found")
47
- sequence = Activity::Path::DSL.append_end(sequence, task: Failure.new(semantic: :invalid_data), magnetic_to: :invalid_data, id: "End.invalid_data")
43
+ sequence = Activity::Path::DSL.append_end(sequence, task: Activity::End.new(semantic: :not_found), magnetic_to: :not_found, id: "End.not_found")
44
+ sequence = Activity::Path::DSL.append_end(sequence, task: Activity::End.new(semantic: :invalid_data), magnetic_to: :invalid_data, id: "End.invalid_data")
48
45
 
49
46
  recompile_activity!(sequence)
50
47
 
@@ -116,7 +113,6 @@ module Trailblazer
116
113
  [[Trailblazer::Activity::TaskWrap::Pipeline.method(:insert_after), "task_wrap.call_task", ["endpoint.end_signal", method(:terminus_handler)]]]
117
114
  end
118
115
  end
119
-
120
- end
116
+ end # Protocol
121
117
  end
122
118
  end
@@ -0,0 +1,27 @@
1
+ require "openssl"
2
+
3
+ module Trailblazer
4
+ class Endpoint::Protocol
5
+ module Controller
6
+ module Cipher # FIXME: copied from Tyrant!
7
+ module_function
8
+
9
+ def encrypt_value(ctx, value:, cipher_key:, **)
10
+ cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
11
+ cipher.key = Digest::SHA1.hexdigest(cipher_key)[0..23] # ArgumentError: key must be 24 bytes
12
+ s = cipher.update(value) + cipher.final
13
+
14
+ ctx[:encrypted_value] = s.unpack('H*')[0].upcase
15
+ end
16
+
17
+ def decrypt_value(ctx, encrypted_value:, cipher_key:, **)
18
+ cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').decrypt
19
+ cipher.key = Digest::SHA1.hexdigest(cipher_key)[0..23]
20
+ s = [encrypted_value].pack("H*").unpack("C*").pack("c*")
21
+
22
+ ctx[:decrypted_value] = cipher.update(s) + cipher.final
23
+ end
24
+ end # Cipher
25
+ end
26
+ end
27
+ end