obf 0.6.1 → 0.6.2
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 +4 -4
- data/lib/obf/utils.rb +2 -3
- data/lib/obf/validator.rb +257 -81
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e04159aa51fa8c477f23c58a9dc7eda8f1abca98
|
4
|
+
data.tar.gz: 7281b01429f081deb13970741a95b5ef025bb8fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3527a3ff96333f841b662008533ff81a4a06ea1429551c604a4d232b61de6d9aa79caca2f735efba04adf178a534574ad50fe504ca30c76583bae8ffd7ed893
|
7
|
+
data.tar.gz: 75ab9ed7797c959ddc16589c302e2b75addb2b7460e91be9299464660198b423ce254fd31cf935ae547fb5821c4616674820f73efcda1b680c3bd7eb109fbb4d
|
data/lib/obf/utils.rb
CHANGED
data/lib/obf/validator.rb
CHANGED
@@ -35,13 +35,46 @@ module OBF
|
|
35
35
|
@warnings || 0
|
36
36
|
end
|
37
37
|
|
38
|
-
def self.
|
38
|
+
def self.validate_file(path)
|
39
|
+
type = Utils::identify_file(path)
|
40
|
+
fn = File.basename(path)
|
41
|
+
filesize = File.size(path)
|
42
|
+
if type == :obf
|
43
|
+
validate_obf(path)
|
44
|
+
elsif type == :obz
|
45
|
+
validate_obz(path)
|
46
|
+
else
|
47
|
+
{
|
48
|
+
:filename => fn,
|
49
|
+
:filesize => filesize,
|
50
|
+
:valid => false,
|
51
|
+
:errors => 1,
|
52
|
+
:results => [{
|
53
|
+
'type' => 'valid_file',
|
54
|
+
'description' => 'valid .obf or .obz file',
|
55
|
+
'valid' => false,
|
56
|
+
'error' => 'file must be an .obf JSON file or a .obz zip package'
|
57
|
+
}]
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.validate_obf(path, opts={})
|
39
63
|
v = self.new
|
40
64
|
fn = File.basename(path)
|
41
|
-
|
65
|
+
filesize = 0
|
66
|
+
content = nil
|
67
|
+
if opts['zipper']
|
68
|
+
content = opts['zipper'].read(path)
|
69
|
+
filesize = opts['zipper'].glob(path)[0].size
|
70
|
+
else
|
71
|
+
content = File.read(path)
|
72
|
+
filesize = File.size(path)
|
73
|
+
end
|
74
|
+
results = v.validate_obf(content, fn, opts)
|
42
75
|
{
|
43
76
|
:filename => fn,
|
44
|
-
:filesize =>
|
77
|
+
:filesize => filesize,
|
45
78
|
:valid => v.errors == 0,
|
46
79
|
:errors => v.errors,
|
47
80
|
:warnings => v.warnings,
|
@@ -50,39 +83,176 @@ module OBF
|
|
50
83
|
end
|
51
84
|
|
52
85
|
def self.validate_obz(path)
|
86
|
+
v = self.new
|
87
|
+
fn = File.basename(path)
|
88
|
+
results, sub_results = v.validate_obz(path, fn)
|
89
|
+
errors = ([v.errors] + sub_results.map{|r| r[:errors] }).inject(:+)
|
90
|
+
warnings = ([v.warnings] + sub_results.map{|r| r[:warnings] }).inject(:+)
|
91
|
+
{
|
92
|
+
:filename => fn,
|
93
|
+
:filesize => File.size(path),
|
94
|
+
:valid => errors == 0,
|
95
|
+
:errors => errors,
|
96
|
+
:warnings => warnings,
|
97
|
+
:results => results,
|
98
|
+
:sub_results => sub_results
|
99
|
+
}
|
53
100
|
end
|
54
|
-
|
55
|
-
def
|
101
|
+
|
102
|
+
def setup
|
56
103
|
@blocked = nil
|
57
104
|
@errored = false
|
58
105
|
@warnings = 0
|
59
106
|
@errors = 0
|
60
107
|
@checks = []
|
108
|
+
@sub_checks = []
|
109
|
+
end
|
110
|
+
|
111
|
+
def validate_obz(path, filename)
|
112
|
+
setup
|
113
|
+
|
114
|
+
add_check('filename', "file name") do
|
115
|
+
if !filename.match(/\.obz$/)
|
116
|
+
warn "filename should end with .obz"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
valid_zip = false
|
121
|
+
add_check('zip', 'valid zip') do
|
122
|
+
begin
|
123
|
+
Utils::load_zip(path) do |zipper|
|
124
|
+
end
|
125
|
+
valid_zip = true
|
126
|
+
rescue Zip::Error => e
|
127
|
+
err "file is not a valid zip package"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
if valid_zip
|
131
|
+
Utils::load_zip(path) do |zipper|
|
132
|
+
json = nil
|
133
|
+
add_check('manifest', 'manifest.json') do
|
134
|
+
if zipper.glob('manifest.json').length == 0
|
135
|
+
err "manifest.json is required in the zip package"
|
136
|
+
end
|
137
|
+
json = JSON.parse(zipper.read('manifest.json')) rescue nil
|
138
|
+
if !json
|
139
|
+
err "manifest.json must contain a valid JSON structure"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
if json
|
143
|
+
add_check('manifest_format', 'manifest.json format version') do
|
144
|
+
if !json['format']
|
145
|
+
err "format attribute is required, set to #{OBF::FORMAT}"
|
146
|
+
end
|
147
|
+
version = json['format'].split(/-/, 3)[-1].to_f
|
148
|
+
if version > OBF::FORMAT_CURRENT_VERSION
|
149
|
+
err "format version (#{version}) is invalid, current version is #{OBF::FORMAT_CURRENT_VERSION}"
|
150
|
+
elsif version < OBF::FORMAT_CURRENT_VERSION
|
151
|
+
warn "format version (#{version}) is old, consider updating to #{OBF::FORMAT_CURRENT_VERSION}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
add_check('manifest_root', 'manifest.json root attribute') do
|
156
|
+
if !json['root']
|
157
|
+
err "root attribute is required"
|
158
|
+
end
|
159
|
+
if zipper.glob(json['root']).length == 0
|
160
|
+
err "root attribute must reference a file in the package"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
paths = nil
|
165
|
+
add_check('manifest_paths', 'manifest.json paths attribute') do
|
166
|
+
if !json['paths'] || !json['paths'].is_a?(Hash)
|
167
|
+
err "paths attribute must be a valid hash"
|
168
|
+
end
|
169
|
+
if !json['paths']['boards'] || !json['paths']['boards'].is_a?(Hash)
|
170
|
+
err "paths.boards must be a valid hash"
|
171
|
+
end
|
172
|
+
if json['paths']['images'] && !json['paths']['images'].is_a?(Hash)
|
173
|
+
err "paths.images must be a valid hash if defined"
|
174
|
+
end
|
175
|
+
if json['paths']['sounds'] && !json['paths']['sounds'].is_a?(Hash)
|
176
|
+
err "paths.sounds must be a valid hash if defined"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
add_check('manifest_extras', 'manifest.json extra attributes') do
|
180
|
+
attrs = ['format', 'root', 'paths']
|
181
|
+
json.keys.each do |key|
|
182
|
+
if !attrs.include?(key) && !key.match(/^ext_/)
|
183
|
+
warn "#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
attrs = ['boards', 'images', 'sounds']
|
188
|
+
json['paths'].keys.each do |key|
|
189
|
+
if !attrs.include?(key) && !key.match(/^ext_/)
|
190
|
+
warn "paths.#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
add_check('manifest_boards', 'manifest.json referenced boards') do
|
195
|
+
end
|
196
|
+
|
197
|
+
add_check('manifest_images', 'manifest.json referenced images') do
|
198
|
+
end
|
199
|
+
|
200
|
+
add_check('manifest_sounds', 'manifest.json referenced sounds') do
|
201
|
+
end
|
202
|
+
|
203
|
+
sub_results = []
|
204
|
+
if json['paths']['boards'] && json['paths']['boards'].is_a?(Hash)
|
205
|
+
json['paths']['boards'].each do |key, path|
|
206
|
+
sub = Validator.validate_obf(path, {'zipper' => zipper})
|
207
|
+
sub_results << sub
|
208
|
+
end
|
209
|
+
end
|
210
|
+
@sub_checks = sub_results
|
211
|
+
end
|
212
|
+
if zipper.glob('manifest.json').length > 0
|
213
|
+
json = JSON.parse(zipper.read('manifest.json')) rescue nil
|
214
|
+
if json['root'] && json['format'] && json['format'].match(/^open-board-/)
|
215
|
+
type = :obz
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
return [@checks, @sub_checks]
|
221
|
+
end
|
222
|
+
|
223
|
+
def validate_obf(content, filename, opts={})
|
224
|
+
setup
|
61
225
|
|
62
226
|
# TODO enforce extra attributes being defined with ext_
|
63
227
|
|
228
|
+
add_check('filename', "file name") do
|
229
|
+
if !filename.match(/\.obf$/)
|
230
|
+
warn "filename should end with .obf"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
64
234
|
json = nil
|
65
|
-
add_check('valid_json', "JSON
|
235
|
+
add_check('valid_json', "JSON file") do
|
66
236
|
begin
|
67
|
-
json = JSON.parse(
|
237
|
+
json = JSON.parse(content)
|
68
238
|
rescue => e
|
69
239
|
err "Couldn't parse as JSON", true
|
70
240
|
end
|
71
241
|
end
|
72
242
|
|
73
243
|
ext = nil
|
74
|
-
add_check('to_external', "OBF
|
244
|
+
add_check('to_external', "OBF structure") do
|
75
245
|
begin
|
76
|
-
|
246
|
+
External.from_obf(json, {})
|
247
|
+
ext = JSON.parse(content)
|
77
248
|
rescue External::StructureError => e
|
78
249
|
err "Couldn't parse structure: #{e.message}", true
|
79
250
|
end
|
80
251
|
end
|
81
|
-
|
82
|
-
|
252
|
+
|
83
253
|
add_check('format_version', "format version") do
|
84
254
|
if !ext['format']
|
85
|
-
err "format attribute is required, set to #{FORMAT}"
|
255
|
+
err "format attribute is required, set to #{OBF::FORMAT}"
|
86
256
|
end
|
87
257
|
version = ext['format'].split(/-/, 3)[-1].to_f
|
88
258
|
if version > OBF::FORMAT_CURRENT_VERSION
|
@@ -188,89 +358,95 @@ module OBF
|
|
188
358
|
warn("not all defined buttons were included in the grid order (#{(button_ids - used_button_ids).join(',')})") if (button_ids - used_button_ids).length > 0
|
189
359
|
end
|
190
360
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
add_check('images', "images attribute") do
|
197
|
-
|
198
|
-
if !ext['images']
|
199
|
-
err "images attribute is required"
|
200
|
-
elsif !ext['images'].is_a?(Array)
|
201
|
-
err "images attribute must be an array"
|
202
|
-
end
|
203
|
-
end
|
361
|
+
button_image_ids = []
|
362
|
+
if ext && ext['buttons'] && ext['buttons'].is_a?(Array)
|
363
|
+
ext['buttons'].each{|b| button_image_ids << b['image_id'] if b.is_a?(Hash) && b['image_id'] }
|
364
|
+
end
|
365
|
+
add_check('images', "images attribute") do
|
204
366
|
|
205
|
-
if ext['images']
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
367
|
+
if !ext['images']
|
368
|
+
err "images attribute is required"
|
369
|
+
elsif !ext['images'].is_a?(Array)
|
370
|
+
err "images attribute must be an array"
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
if ext && ext['images'] && ext['images'].is_a?(Array)
|
375
|
+
ext['images'].each_with_index do |image, idx|
|
376
|
+
add_check("image[#{idx}]", "image at images[#{idx}]") do
|
377
|
+
if !image.is_a?(Hash)
|
378
|
+
err "image must be a hash"
|
379
|
+
elsif !image['id']
|
380
|
+
err "image.id is required"
|
381
|
+
elsif !image['width'] || !image['width'].is_a?(Fixnum)
|
382
|
+
err "image.width must be a valid positive number"
|
383
|
+
elsif !image['height'] || !image['height'].is_a?(Fixnum)
|
384
|
+
err "image.height must be a valid positive number"
|
385
|
+
elsif !image['content_type'] || !image['content_type'].match(/^image\/.+$/)
|
386
|
+
err "image.content_type must be a valid image mime type"
|
387
|
+
elsif !image['url'] && !image['data'] && !image['symbol']
|
388
|
+
err "image must have data, url or symbol attribute defined"
|
389
|
+
elsif image['data'] && !image['data'].match(/^data:image\/.+;base64,.+$/)
|
390
|
+
err "image.data must be a valid data URI if defined"
|
391
|
+
elsif image['symbol'] && !image['symbol'].is_a?(Hash)
|
392
|
+
err "image.symbol must be a hash if defined"
|
393
|
+
end
|
394
|
+
if image['path']
|
395
|
+
if opts['zipper']
|
396
|
+
if opts['zipper'].glob(image['path']).length == 0
|
397
|
+
err "image.path \"#{image['path']}\" not found in .obz package"
|
230
398
|
end
|
399
|
+
else
|
400
|
+
err "image.path should not be defined outside of an .obz package"
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
attrs = ['id', 'width', 'height', 'content_type', 'data', 'url', 'symbol', 'path', 'data_url', 'license']
|
405
|
+
image.keys.each do |key|
|
406
|
+
if !attrs.include?(key) && !key.match(/^ext_/)
|
407
|
+
warn "image.#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
|
231
408
|
end
|
232
409
|
end
|
233
410
|
end
|
234
411
|
end
|
412
|
+
end
|
235
413
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
err "sounds attribute must be an array"
|
242
|
-
end
|
414
|
+
add_check('sounds', "sounds attribute") do
|
415
|
+
if !ext['sounds']
|
416
|
+
err "sounds attribute is required"
|
417
|
+
elsif !ext['sounds'].is_a?(Array)
|
418
|
+
err "sounds attribute must be an array"
|
243
419
|
end
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
420
|
+
end
|
421
|
+
|
422
|
+
if ext && ext['sounds'] && ext['sounds'].is_a?(Array)
|
423
|
+
ext['sounds'].each_with_index do |sound, idx|
|
424
|
+
add_check("sounds[#{idx}]", "sound at sounds[#{idx}]") do
|
425
|
+
if !sound.is_a?(Hash)
|
426
|
+
err "sound must be a hash"
|
427
|
+
elsif !sound['id']
|
428
|
+
err "sound.id is required"
|
429
|
+
elsif !sound['duration'] || !sound['duration'].is_a?(Fixnum)
|
430
|
+
err "sound.duration must be a valid positive number"
|
431
|
+
elsif !sound['content_type'] || !sound['content_type'].match(/^audio\/.+$/)
|
432
|
+
err "sound.content_type must be a valid audio mime type"
|
433
|
+
elsif !sound['url'] && !sound['data'] && !sound['symbol']
|
434
|
+
err "sound must have data, url or symbol attribute defined"
|
435
|
+
elsif sound['data'] && !sound['data'].match(/^data:audio\/.+;base64,.+$/)
|
436
|
+
err "sound.data must be a valid data URI if defined"
|
437
|
+
end
|
438
|
+
|
439
|
+
attrs = ['id', 'duration', 'content_type', 'data', 'url', 'path', 'data_url', 'license']
|
440
|
+
sound.keys.each do |key|
|
441
|
+
if !attrs.include?(key) && !key.match(/^ext_/)
|
442
|
+
warn "sound.#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
|
267
443
|
end
|
268
444
|
end
|
269
445
|
end
|
270
446
|
end
|
271
447
|
end
|
272
448
|
|
273
|
-
if ext['buttons'] && ext['buttons'].is_a?(Array)
|
449
|
+
if ext && ext['buttons'] && ext['buttons'].is_a?(Array)
|
274
450
|
ext['buttons'].each_with_index do |button, idx|
|
275
451
|
add_check("buttons[#{idx}]", "button at buttons[#{idx}]") do
|
276
452
|
if !button.is_a?(Hash)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: obf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Whitmer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|