skull_island 2.0.3 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,12 +104,16 @@ 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
110
  # Looks up IDs (and usually wraps them in a Hash)
109
111
  def lookup(type, value, raw = false)
110
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
111
117
  when :consumer
112
118
  Resources::Consumer.find(:username, value).id
113
119
  when :route
@@ -209,6 +215,9 @@ module SkullIsland
209
215
  @api_client.invalidate_cache_for(self.class.relative_uri.to_s) # clear any collection class
210
216
  @tainted = false
211
217
  true
218
+ rescue RestClient::BadRequest => e
219
+ warn "[WARN] Failed to save #{self.class} via #{new? ? save_uri : relative_uri} with " \
220
+ "'#{e.message}':\n#{saveable_data.to_yaml}\n\nReceived: #{e.inspect}"
212
221
  end
213
222
 
214
223
  def save_uri
@@ -11,7 +11,7 @@ module SkullIsland
11
11
  attr_reader :max_size, :keys
12
12
 
13
13
  # @raise [Exceptions::InvalidCacheSize] if the max_size isn't an Integer
14
- def initialize(max_size = 100)
14
+ def initialize(max_size = 10_000)
15
15
  raise Exceptions::InvalidCacheSize unless max_size.is_a?(Integer)
16
16
 
17
17
  @max_size = max_size
@@ -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