skull_island 2.0.1 → 2.2.1

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.
@@ -12,8 +12,8 @@ module SkullIsland
12
12
  end
13
13
 
14
14
  # At this phase, we want to leave this alone...
15
- def lookup(type, value)
16
- "<%= lookup :#{type}, '#{value}' %>"
15
+ def lookup(type, value, raw = false)
16
+ "<%= lookup :#{type}, '#{value}', #{raw} %>"
17
17
  end
18
18
  end
19
19
  end
@@ -44,7 +44,7 @@ module SkullIsland
44
44
  end
45
45
 
46
46
  def project=(project_id)
47
- unless project_id.is_a?(String) && project_id.match?(/^[\w_\-\.~]+$/)
47
+ unless project_id.is_a?(String) && project_id.match?(/^[\w_\-.~]+$/)
48
48
  raise Exceptions::InvalidArguments, 'project'
49
49
  end
50
50
 
@@ -16,6 +16,8 @@ module SkullIsland
16
16
 
17
17
  # rubocop:disable Style/GuardClause
18
18
  # rubocop:disable Security/Eval
19
+ # The delayed_set method allows a second phase of Erb templating immediately
20
+ # before sending data to the API. This allows the `lookup` function to work dynamically
19
21
  def delayed_set(property, data, key = property.to_s)
20
22
  if data[key]
21
23
  value = recursive_erubi(data[key])
@@ -27,11 +29,12 @@ module SkullIsland
27
29
  end
28
30
 
29
31
  def recursive_erubi(data)
30
- if data.is_a?(String)
32
+ case data
33
+ when String
31
34
  eval(Erubi::Engine.new(data).src)
32
- elsif data.is_a?(Array)
35
+ when Array
33
36
  data.map { |item| recursive_erubi(item) }
34
- elsif data.is_a?(Hash)
37
+ when Hash
35
38
  data.map { |k, v| [k, recursive_erubi(v)] }.to_h
36
39
  else
37
40
  data
@@ -72,7 +75,7 @@ module SkullIsland
72
75
  end
73
76
 
74
77
  def host_regex
75
- /^(([\w]|[\w][\w\-]*[\w])\.)*([\w]|[\w][\w\-]*[\w])$/
78
+ /^((\w|\w[\w\-]*\w)\.)*(\w|\w[\w\-]*\w)$/
76
79
  end
77
80
 
78
81
  def id_property
@@ -87,9 +90,8 @@ module SkullIsland
87
90
  self.class.immutable?
88
91
  end
89
92
 
90
- # rubocop:disable Metrics/CyclomaticComplexity
91
93
  # rubocop:disable Metrics/PerceivedComplexity
92
- def import_update_or_skip(verbose: false, test: false, index:)
94
+ def import_update_or_skip(index:, verbose: false, test: false)
93
95
  if find_by_digest
94
96
  puts "[INFO] Skipping #{self.class} index #{index} (#{id})" if verbose
95
97
  elsif test
@@ -102,22 +104,29 @@ module SkullIsland
102
104
  puts "[ERR] Failed to save #{self.class} index #{index}"
103
105
  end
104
106
  end
105
- # rubocop:enable Metrics/CyclomaticComplexity
107
+
106
108
  # rubocop:enable Metrics/PerceivedComplexity
107
109
 
108
- def lookup(type, value)
109
- case type
110
- when :consumer
111
- { 'id' => Resources::Consumer.find(:username, value).id }
112
- when :route
113
- { 'id' => Resources::Route.find(:name, value).id }
114
- when :service
115
- { 'id' => Resources::Service.find(:name, value).id }
116
- when :upstream
117
- { 'id' => Resources::Upstream.find(:name, value).id }
118
- else
119
- raise Exceptions::InvalidArguments, "#{type} is not a valid lookup type"
120
- end
110
+ # Looks up IDs (and usually wraps them in a Hash)
111
+ def lookup(type, value, raw = false)
112
+ id_value = case type
113
+ when :ca_certificate
114
+ Resources::CACertificate.find(:name, value).id
115
+ when :certificate
116
+ Resources::Certificate.find(:name, value).id
117
+ when :consumer
118
+ Resources::Consumer.find(:username, value).id
119
+ when :route
120
+ Resources::Route.find(:name, value).id
121
+ when :service
122
+ Resources::Service.find(:name, value).id
123
+ when :upstream
124
+ Resources::Upstream.find(:name, value).id
125
+ else
126
+ raise Exceptions::InvalidArguments, "#{type} is not a valid lookup type"
127
+ end
128
+
129
+ raw ? id_value : { 'id' => id_value }
121
130
  end
122
131
 
123
132
  # ActiveRecord ActiveModel::Name compatibility method
@@ -57,9 +57,10 @@ module SkullIsland
57
57
  define_method(method_name) do |value|
58
58
  raise Exceptions::ImmutableModification if immutable?
59
59
 
60
- if opts[:validate]
61
- raise Exceptions::InvalidArguments, name unless send("validate_#{name}".to_sym, value)
60
+ if opts[:validate] && !send("validate_#{name}".to_sym, value)
61
+ raise Exceptions::InvalidArguments, name
62
62
  end
63
+
63
64
  @entity[name.to_s] = if opts[:preprocess]
64
65
  send("preprocess_#{name}".to_sym, value)
65
66
  else
@@ -121,7 +122,7 @@ module SkullIsland
121
122
  )
122
123
  end
123
124
 
124
- def self.from_hash(hash)
125
+ def self.from_hash(hash, options = {})
125
126
  # TODO: better options validations
126
127
  raise Exceptions::InvalidOptions unless options.is_a?(Hash)
127
128
 
@@ -179,8 +180,10 @@ module SkullIsland
179
180
  )
180
181
  end
181
182
 
182
- def self.cleanup_except(project, keep_these)
183
- where(:project, project).reject { |res| keep_these.include?(res.id) }.map do |res|
183
+ def self.cleanup_except(project, keep_these, from_these = nil)
184
+ old_resources = from_these || where(:project, project)
185
+
186
+ old_resources.reject { |res| keep_these.include?(res.id) }.map do |res|
184
187
  puts "[WARN] ! Removing #{name} (#{res.id})"
185
188
  res.destroy
186
189
  end
@@ -161,9 +161,10 @@ module SkullIsland
161
161
  # use #merge
162
162
  # @return [ResourceCollection]
163
163
  def +(other)
164
- if other.is_a?(self.class)
164
+ case other
165
+ when self.class
165
166
  self.class.new(@list + other.to_a, type: @type, api_client: @api_client)
166
- elsif other.is_a?(@type)
167
+ when @type
167
168
  self.class.new(@list + [other], type: @type, api_client: @api_client)
168
169
  else
169
170
  raise Exceptions::InvalidArguments
@@ -171,7 +172,7 @@ module SkullIsland
171
172
  end
172
173
 
173
174
  def <<(other)
174
- raise Exceptions::InvalidArguments, 'Resource Type Mismatch' unless other.class == @type
175
+ raise Exceptions::InvalidArguments, 'Resource Type Mismatch' unless other.instance_of?(@type)
175
176
 
176
177
  @list << other
177
178
  end
@@ -12,7 +12,10 @@ module SkullIsland
12
12
  property :cert, required: true, validate: true
13
13
  property :created_at, read_only: true, postprocess: true
14
14
  property :tags, validate: true, preprocess: true, postprocess: true
15
+ # property :name
15
16
 
17
+ # rubocop:disable Metrics/CyclomaticComplexity
18
+ # rubocop:disable Metrics/PerceivedComplexity
16
19
  def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
17
20
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
18
21
 
@@ -22,6 +25,7 @@ module SkullIsland
22
25
  resource = new
23
26
  resource.delayed_set(:cert, resource_data)
24
27
  resource.tags = resource_data['tags'] if resource_data['tags']
28
+ resource.name = resource_data['name'] if resource_data['name']
25
29
  resource.project = project if project
26
30
  resource.import_time = (time || Time.now.utc.to_i) if project
27
31
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
@@ -29,11 +33,16 @@ module SkullIsland
29
33
  end
30
34
 
31
35
  cleanup_except(project, known_ids) if project
36
+
37
+ known_ids
32
38
  end
39
+ # rubocop:enable Metrics/CyclomaticComplexity
40
+ # rubocop:enable Metrics/PerceivedComplexity
33
41
 
34
42
  def export(options = {})
35
43
  hash = { 'cert' => cert }
36
44
  hash['tags'] = tags unless tags.empty?
45
+ hash['name'] = name if name
37
46
  [*options[:exclude]].each do |exclude|
38
47
  hash.delete(exclude.to_s)
39
48
  end
@@ -46,10 +55,19 @@ module SkullIsland
46
55
  def modified_existing?
47
56
  return false unless new?
48
57
 
49
- # Find CA certs of the same cert
50
- same_cert = self.class.where(:cert, cert)
58
+ # Find CA certs of the same "name"
59
+ if name
60
+ same_name = self.class.where(:name, name)
61
+
62
+ existing = same_name.size == 1 ? same_name.first : nil
63
+ end
51
64
 
52
- existing = same_cert.size == 1 ? same_cert.first : nil
65
+ unless existing
66
+ # Find CA certs of the same cert
67
+ same_cert = self.class.where(:cert, cert)
68
+
69
+ existing = same_cert.size == 1 ? same_cert.first : nil
70
+ end
53
71
 
54
72
  if existing
55
73
  @entity['id'] = existing.id
@@ -59,6 +77,16 @@ module SkullIsland
59
77
  end
60
78
  end
61
79
 
80
+ # Simulates retrieving a #name property via a tag
81
+ def name
82
+ metatags['name']
83
+ end
84
+
85
+ # Simulates setting a #name property via a tag
86
+ def name=(value)
87
+ add_meta('name', value.to_s)
88
+ end
89
+
62
90
  private
63
91
 
64
92
  # Used to validate {#cert} on set
@@ -12,11 +12,12 @@ module SkullIsland
12
12
  property :cert, required: true, validate: true
13
13
  property :key, required: true, validate: true
14
14
  property :snis, validate: true
15
+ # property :name
15
16
  property :created_at, read_only: true, postprocess: true
16
17
  property :tags, validate: true, preprocess: true, postprocess: true
17
18
 
18
- # rubocop:disable Metrics/CyclomaticComplexity
19
19
  # rubocop:disable Metrics/PerceivedComplexity
20
+ # rubocop:disable Metrics/CyclomaticComplexity
20
21
  def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
21
22
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
22
23
 
@@ -28,6 +29,7 @@ module SkullIsland
28
29
  resource.delayed_set(:key, resource_data)
29
30
  resource.snis = resource_data['snis'] if resource_data['snis']
30
31
  resource.tags = resource_data['tags'] if resource_data['tags']
32
+ resource.name = resource_data['name'] if resource_data['name']
31
33
  resource.project = project if project
32
34
  resource.import_time = (time || Time.now.utc.to_i) if project
33
35
  resource.import_update_or_skip(index: index, verbose: verbose, test: test)
@@ -35,14 +37,18 @@ module SkullIsland
35
37
  end
36
38
 
37
39
  cleanup_except(project, known_ids) if project
40
+
41
+ known_ids
38
42
  end
39
- # rubocop:enable Metrics/CyclomaticComplexity
40
43
  # rubocop:enable Metrics/PerceivedComplexity
44
+ # rubocop:enable Metrics/CyclomaticComplexity
41
45
 
46
+ # rubocop:disable Metrics/AbcSize
42
47
  def export(options = {})
43
48
  hash = { 'cert' => cert, 'key' => key }
44
49
  hash['snis'] = snis if snis && !snis.empty?
45
50
  hash['tags'] = tags unless tags.empty?
51
+ hash['name'] = name if name
46
52
  [*options[:exclude]].each do |exclude|
47
53
  hash.delete(exclude.to_s)
48
54
  end
@@ -51,14 +57,24 @@ module SkullIsland
51
57
  end
52
58
  hash.reject { |_, value| value.nil? }
53
59
  end
60
+ # rubocop:enable Metrics/AbcSize
54
61
 
55
62
  def modified_existing?
56
63
  return false unless new?
57
64
 
58
- # Find certs of the same cert and key
59
- same_key = self.class.where(:key, key)
65
+ # Find certs of the same "name"
66
+ if name
67
+ same_name = self.class.where(:name, name)
68
+
69
+ existing = same_name.size == 1 ? same_name.first : nil
70
+ end
60
71
 
61
- existing = same_key.size == 1 ? same_key.first : nil
72
+ unless existing
73
+ # Find certs of the same cert and key
74
+ same_key = self.class.where(:key, key)
75
+
76
+ existing = same_key.size == 1 ? same_key.first : nil
77
+ end
62
78
 
63
79
  if existing
64
80
  @entity['id'] = existing.id
@@ -68,6 +84,16 @@ module SkullIsland
68
84
  end
69
85
  end
70
86
 
87
+ # Simulates retrieving a #name property via a tag
88
+ def name
89
+ metatags['name']
90
+ end
91
+
92
+ # Simulates setting a #name property via a tag
93
+ def name=(value)
94
+ add_meta('name', value.to_s)
95
+ end
96
+
71
97
  private
72
98
 
73
99
  # Used to validate {#cert} on set
@@ -60,7 +60,7 @@ module SkullIsland
60
60
 
61
61
  known_acls = AccessControlList.batch_import(
62
62
  (
63
- resource_data.dig('acls') || []
63
+ resource_data['acls'] || []
64
64
  ).map { |t| t.merge('consumer' => { 'id' => resource.id }) },
65
65
  verbose: verbose,
66
66
  test: test
@@ -95,6 +95,8 @@ module SkullIsland
95
95
  # rubocop:enable Metrics/BlockLength
96
96
 
97
97
  cleanup_except(project, known_ids) if project
98
+
99
+ known_ids
98
100
  end
99
101
  # rubocop:enable Metrics/MethodLength
100
102
 
@@ -103,9 +105,10 @@ module SkullIsland
103
105
  end
104
106
 
105
107
  def add_acl!(details)
106
- r = if details.is_a?(AccessControlList)
108
+ r = case details
109
+ when AccessControlList
107
110
  details
108
- elsif details.is_a?(String)
111
+ when String
109
112
  resource = AccessControlList.new(api_client: api_client)
110
113
  resource.group = details
111
114
  resource
@@ -162,6 +165,7 @@ module SkullIsland
162
165
  Plugin.where(:consumer, self, api_client: api_client)
163
166
  end
164
167
 
168
+ # rubocop:disable Metrics/AbcSize
165
169
  def export(options = {})
166
170
  hash = { 'username' => username, 'custom_id' => custom_id }
167
171
  creds = credentials_for_export
@@ -176,6 +180,7 @@ module SkullIsland
176
180
  end
177
181
  hash.reject { |_, value| value.nil? }
178
182
  end
183
+ # rubocop:enable Metrics/AbcSize
179
184
 
180
185
  def modified_existing?
181
186
  return false unless new?
@@ -48,6 +48,7 @@ module SkullIsland
48
48
  consumer ? "#{consumer.relative_uri}/jwt" : nil
49
49
  end
50
50
 
51
+ # rubocop:disable Metrics/AbcSize
51
52
  def export(options = {})
52
53
  hash = { 'algorithm' => algorithm }
53
54
  hash['key'] = key if key
@@ -62,6 +63,7 @@ module SkullIsland
62
63
  end
63
64
  hash.reject { |_, value| value.nil? }
64
65
  end
66
+ # rubocop:enable Metrics/AbcSize
65
67
 
66
68
  # Keys can't be updated, only created or deleted
67
69
  def modified_existing?
@@ -102,9 +104,10 @@ module SkullIsland
102
104
  end
103
105
 
104
106
  # Used to validate {#algorithm} on set
107
+ # @see https://github.com/Kong/kong/blob/master/kong/plugins/jwt/daos.lua#L29
105
108
  def validate_algorithm(value)
106
109
  # allow a String
107
- %w[HS256 HS384 HS512 RS256 ES256].include? value
110
+ %w[HS256 HS384 HS512 RS256 RS512 ES256].include? value
108
111
  end
109
112
 
110
113
  # Used to validate {#key} on set
@@ -21,6 +21,7 @@ module SkullIsland
21
21
 
22
22
  # rubocop:disable Metrics/CyclomaticComplexity
23
23
  # rubocop:disable Metrics/PerceivedComplexity
24
+ # rubocop:disable Metrics/AbcSize
24
25
  def self.batch_import(data, verbose: false, test: false, project: nil, time: nil)
25
26
  raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
26
27
 
@@ -43,9 +44,12 @@ module SkullIsland
43
44
  end
44
45
 
45
46
  cleanup_except(project, known_ids) if project
47
+
48
+ known_ids
46
49
  end
47
50
  # rubocop:enable Metrics/CyclomaticComplexity
48
51
  # rubocop:enable Metrics/PerceivedComplexity
52
+ # rubocop:enable Metrics/AbcSize
49
53
 
50
54
  def self.enabled_names(api_client: APIClient.instance)
51
55
  api_client.get("#{relative_uri}/enabled")['enabled_plugins']
@@ -121,14 +125,15 @@ module SkullIsland
121
125
  end
122
126
 
123
127
  def postprocess_consumer(value)
124
- if value.is_a?(Hash)
128
+ case value
129
+ when Hash
125
130
  Consumer.new(
126
131
  entity: value,
127
132
  lazy: true,
128
133
  tainted: false,
129
134
  api_client: api_client
130
135
  )
131
- elsif value.is_a?(String)
136
+ when String
132
137
  Consumer.new(
133
138
  entity: { 'id' => value },
134
139
  lazy: true,
@@ -141,9 +146,10 @@ module SkullIsland
141
146
  end
142
147
 
143
148
  def preprocess_consumer(input)
144
- if input.is_a?(Hash)
149
+ case input
150
+ when Hash
145
151
  input
146
- elsif input.is_a?(Consumer)
152
+ when Consumer
147
153
  { 'id' => input.id }
148
154
  else
149
155
  input
@@ -151,14 +157,15 @@ module SkullIsland
151
157
  end
152
158
 
153
159
  def postprocess_route(value)
154
- if value.is_a?(Hash)
160
+ case value
161
+ when Hash
155
162
  Route.new(
156
163
  entity: value,
157
164
  lazy: true,
158
165
  tainted: false,
159
166
  api_client: api_client
160
167
  )
161
- elsif value.is_a?(String)
168
+ when String
162
169
  Route.new(
163
170
  entity: { 'id' => value },
164
171
  lazy: true,
@@ -171,9 +178,10 @@ module SkullIsland
171
178
  end
172
179
 
173
180
  def preprocess_route(input)
174
- if input.is_a?(Hash)
181
+ case input
182
+ when Hash
175
183
  input
176
- elsif input.is_a?(Route)
184
+ when Route
177
185
  { 'id' => input.id }
178
186
  else
179
187
  input
@@ -181,14 +189,15 @@ module SkullIsland
181
189
  end
182
190
 
183
191
  def postprocess_service(value)
184
- if value.is_a?(Hash)
192
+ case value
193
+ when Hash
185
194
  Service.new(
186
195
  entity: value,
187
196
  lazy: true,
188
197
  tainted: false,
189
198
  api_client: api_client
190
199
  )
191
- elsif value.is_a?(String)
200
+ when String
192
201
  Service.new(
193
202
  entity: { 'id' => value },
194
203
  lazy: true,
@@ -201,9 +210,10 @@ module SkullIsland
201
210
  end
202
211
 
203
212
  def preprocess_service(input)
204
- if input.is_a?(Hash)
213
+ case input
214
+ when Hash
205
215
  input
206
- elsif input.is_a?(Service)
216
+ when Service
207
217
  { 'id' => input.id }
208
218
  else
209
219
  input