icfs 0.1.0 → 0.1.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.
data/lib/icfs.rb CHANGED
@@ -11,12 +11,12 @@
11
11
 
12
12
  require 'digest/sha2'
13
13
 
14
+ require_relative 'icfs/validate'
15
+
14
16
  ##########################################################################
15
17
  # Investigative Case File System
16
18
  #
17
19
  # @todo Delete Items and move into this module
18
- # @todo Verification tool written
19
- # @todo Archive/move case tool written
20
20
  #
21
21
  module ICFS
22
22
 
@@ -101,7 +101,6 @@ end # module ICFS::Error
101
101
 
102
102
  end # module ICFS
103
103
 
104
- require_relative 'icfs/validate'
105
104
  require_relative 'icfs/cache'
106
105
  require_relative 'icfs/store'
107
106
  require_relative 'icfs/items'
data/lib/icfs/api.rb CHANGED
@@ -265,12 +265,12 @@ class Api
265
265
  def case_read(cid, lnum=0)
266
266
  if lnum != 0
267
267
  json = @store.case_read(cid, lnum)
268
- return Validate.parse(json, 'case'.freeze, Items::ItemCase)
268
+ return Items.parse(json, 'case'.freeze, Items::ItemCase)
269
269
  end
270
270
 
271
271
  if !@cases.key?(cid)
272
272
  json = @cache.case_read(cid)
273
- cur = Validate.parse(json, 'case'.freeze, Items::ItemCase)
273
+ cur = Items.parse(json, 'case'.freeze, Items::ItemCase)
274
274
  @cases[cid] = cur
275
275
  end
276
276
  return @cases[cid]
@@ -295,7 +295,7 @@ class Api
295
295
 
296
296
  # read
297
297
  json = @cache.log_read(cid, lnum)
298
- return Validate.parse(json, 'log'.freeze, Items::ItemLog)
298
+ return Items.parse(json, 'log'.freeze, Items::ItemLog)
299
299
  end # def log_read()
300
300
 
301
301
 
@@ -313,7 +313,7 @@ class Api
313
313
  # get access list and current entry
314
314
  al = access_list(cid)
315
315
  json = @cache.entry_read(cid, enum)
316
- ec = Validate.parse(json, 'entry'.freeze, Items::ItemEntry)
316
+ ec = Items.parse(json, 'entry'.freeze, Items::ItemEntry)
317
317
 
318
318
  # see if we can read the entry
319
319
  need = Set.new
@@ -330,7 +330,7 @@ class Api
330
330
  return ec
331
331
  else
332
332
  json = @store.entry_read(cid, enum, lnum)
333
- return Validate.parse(json, 'entry'.freeze, Items::ItemEntry)
333
+ return Items.parse(json, 'entry'.freeze, Items::ItemEntry)
334
334
  end
335
335
  end # def entry_read()
336
336
 
@@ -362,7 +362,7 @@ class Api
362
362
  id = '%s.%d'.freeze % [cid, anum]
363
363
  unless @actions.key?(id)
364
364
  json = @cache.action_read(cid, anum)
365
- act = Validate.parse(json, 'action'.freeze, Items::ItemAction)
365
+ act = Items.parse(json, 'action'.freeze, Items::ItemAction)
366
366
  @actions[id] = act
367
367
  end
368
368
  return @actions[id]
@@ -395,7 +395,7 @@ class Api
395
395
  return ac
396
396
  else
397
397
  json = @store.action_read( cid, anum, lnum)
398
- return Validate.parse(json, 'action'.freeze, Items::ItemAction)
398
+ return Items.parse(json, 'action'.freeze, Items::ItemAction)
399
399
  end
400
400
  end # def action_read()
401
401
 
@@ -419,14 +419,14 @@ class Api
419
419
 
420
420
  # read curent index
421
421
  json = @cache.index_read(cid, xnum)
422
- xc = Validate.parse(json, 'index'.freeze, Items::ItemIndex)
422
+ xc = Items.parse(json, 'index'.freeze, Items::ItemIndex)
423
423
 
424
424
  # return the requested version
425
425
  if( lnum == 0 || xc['log'] == lnum )
426
426
  return xc
427
427
  else
428
428
  json = @store.index_read(cid, xnum, lnum)
429
- return Validate.parse(json, 'index'.freeze, Items::ItemIndex)
429
+ return Items.parse(json, 'index'.freeze, Items::ItemIndex)
430
430
  end
431
431
  end # def index_read()
432
432
 
@@ -444,7 +444,7 @@ class Api
444
444
  end
445
445
 
446
446
  json = @cache.current_read(cid)
447
- return Validate.parse(json, 'current'.current, Items::ItemCurrent)
447
+ return Items.parse(json, 'current'.current, Items::ItemCurrent)
448
448
  end # end def current_read()
449
449
 
450
450
 
@@ -476,7 +476,7 @@ class Api
476
476
  # @param query [Hash] a query
477
477
  #
478
478
  def case_search(query)
479
- Validate.validate(query, 'Case Search'.freeze, ValCaseSearch)
479
+ Items.validate(query, 'Case Search'.freeze, ValCaseSearch)
480
480
  @cache.case_search(query)
481
481
  end
482
482
 
@@ -513,7 +513,7 @@ class Api
513
513
  # @param query [Hash] a query
514
514
  #
515
515
  def log_search(query)
516
- Validate.validate(query, 'Log Search'.freeze, ValLogSearch)
516
+ Items.validate(query, 'Log Search'.freeze, ValLogSearch)
517
517
  @cache.log_search(query)
518
518
  end
519
519
 
@@ -552,7 +552,7 @@ class Api
552
552
  # Search for entries
553
553
  #
554
554
  def entry_search(query)
555
- Validate.validate(query, 'Entry Search'.freeze, ValEntrySearch)
555
+ Items.validate(query, 'Entry Search'.freeze, ValEntrySearch)
556
556
 
557
557
  # check permissions
558
558
  # - have global search permissions / read access to the case
@@ -640,7 +640,7 @@ class Api
640
640
  # Search for actions
641
641
  #
642
642
  def action_search(query)
643
- Validate.validate(query, 'Action Search'.freeze, ValActionSearch)
643
+ Items.validate(query, 'Action Search'.freeze, ValActionSearch)
644
644
 
645
645
  # permissions check
646
646
  # - have global search permissions / read access to the case
@@ -686,7 +686,7 @@ class Api
686
686
  # Search for indexes
687
687
  #
688
688
  def index_search(query)
689
- Validate.validate(query, 'Index Search'.freeze, ValIndexSearch)
689
+ Items.validate(query, 'Index Search'.freeze, ValIndexSearch)
690
690
 
691
691
  # permissions check
692
692
  # - have global search permissions / read access to the case
@@ -701,7 +701,7 @@ class Api
701
701
  res[:list].each do |se|
702
702
  idx = se[:object]
703
703
 
704
- unless access_list(idx[:caseid].include?(ICFS::PermRead))
704
+ unless access_list(idx[:caseid]).include?(ICFS::PermRead)
705
705
  idx[:title] = nil
706
706
  idx[:tags] = nil
707
707
  end
@@ -728,7 +728,7 @@ class Api
728
728
  # Analyze stats
729
729
  #
730
730
  def stats(query)
731
- Validate.validate(query, 'Stats Search'.freeze, ValStatsSearch)
731
+ Items.validate(query, 'Stats Search'.freeze, ValStatsSearch)
732
732
 
733
733
  # permissions check
734
734
  # - have global search permissions / read access to the case
@@ -757,7 +757,7 @@ class Api
757
757
  # Get case tags
758
758
  #
759
759
  def case_tags(query)
760
- Validate.validate(query, 'Case Tags Search'.freeze, ValCaseTags)
760
+ Items.validate(query, 'Case Tags Search'.freeze, ValCaseTags)
761
761
  return @cache.case_tags(query)
762
762
  end # def case_tags()
763
763
 
@@ -778,7 +778,7 @@ class Api
778
778
  # Get entry tags
779
779
  #
780
780
  def entry_tags(query)
781
- Validate.validate(query, 'Entry Tags Search'.freeze, ValEntryTags)
781
+ Items.validate(query, 'Entry Tags Search'.freeze, ValEntryTags)
782
782
 
783
783
  # permissions
784
784
  # - read access to case
@@ -819,7 +819,7 @@ class Api
819
819
  # Get action tags
820
820
  #
821
821
  def action_tags(query)
822
- Validate.validate(query, 'Task Tags Search'.freeze, ValActionTags)
822
+ Items.validate(query, 'Task Tags Search'.freeze, ValActionTags)
823
823
 
824
824
  # only allow searches for user/roles you have
825
825
  unless @ur.include?(query[:assigned]) ||
@@ -849,7 +849,7 @@ class Api
849
849
  # Get index tags
850
850
  #
851
851
  def index_tags(query)
852
- Validate.validate(query, 'Index Tags'.freeze, ValIndexTags)
852
+ Items.validate(query, 'Index Tags'.freeze, ValIndexTags)
853
853
  unless access_list(query[:caseid]).include?(ICFS::PermRead)
854
854
  raise(Error::Perms, 'missing perms: %s'.freeze % ICFS::PermRead)
855
855
  end
@@ -875,8 +875,8 @@ class Api
875
875
  # Sanity checks
876
876
 
877
877
  # form & values
878
- Validate.validate(ent, 'entry'.freeze, Items::ItemEntryNew)
879
- Validate.validate(cse, 'case'.freeze, Items::ItemCaseEdit)
878
+ Items.validate(ent, 'entry'.freeze, Items::ItemEntryNew)
879
+ Items.validate(cse, 'case'.freeze, Items::ItemCaseEdit)
880
880
 
881
881
  # access users/roles/groups are valid
882
882
  cse["access"].each do |acc|
@@ -923,7 +923,7 @@ class Api
923
923
  cse['caseid'] = cid
924
924
  cse['log'] = 1
925
925
  cse['tags'] ||= [ ICFS::TagNone ]
926
- citem = Validate.generate(cse, 'case'.freeze, Items::ItemCase)
926
+ citem = Items.generate(cse, 'case'.freeze, Items::ItemCase)
927
927
 
928
928
  # entry
929
929
  ent['icfs'] = 1
@@ -973,12 +973,12 @@ class Api
973
973
  # finish items
974
974
  ent['time'] ||= now
975
975
  ent['files'].each{|fi| fi['log'] ||= 1 } if ent['files']
976
- eitem = Validate.generate(ent, 'entry'.freeze, Items::ItemEntry)
976
+ eitem = Items.generate(ent, 'entry'.freeze, Items::ItemEntry)
977
977
  log['time'] = now
978
978
  log['entry']['hash'] = ICFS.hash(eitem)
979
- litem = Validate.generate(log, 'log'.freeze, Items::ItemLog)
979
+ litem = Items.generate(log, 'log'.freeze, Items::ItemLog)
980
980
  cur['hash'] = ICFS.hash(litem)
981
- nitem = Validate.generate(cur, 'current'.freeze, Items::ItemCurrent)
981
+ nitem = Items.generate(cur, 'current'.freeze, Items::ItemCurrent)
982
982
 
983
983
  # write to cache
984
984
  @cache.entry_write(cid, 1, eitem)
@@ -1017,13 +1017,13 @@ class Api
1017
1017
 
1018
1018
  # form & content
1019
1019
  if idx || cse
1020
- Validate.validate(ent, 'New Entry'.freeze, Items::ItemEntryNew)
1020
+ Items.validate(ent, 'New Entry'.freeze, Items::ItemEntryNew)
1021
1021
  else
1022
- Validate.validate(ent, 'Editable Entry'.freeze, Items::ItemEntryEdit)
1022
+ Items.validate(ent, 'Editable Entry'.freeze, Items::ItemEntryEdit)
1023
1023
  end
1024
- Validate.validate(act, 'action'.freeze, Items::ItemActionEdit) if act
1025
- Validate.validate(idx, 'index'.freeze, Items::ItemIndexEdit) if idx
1026
- Validate.validate(cse, 'case'.freeze, Items::ItemCaseEdit) if cse
1024
+ Items.validate(act, 'action'.freeze, Items::ItemActionEdit) if act
1025
+ Items.validate(idx, 'index'.freeze, Items::ItemIndexEdit) if idx
1026
+ Items.validate(cse, 'case'.freeze, Items::ItemCaseEdit) if cse
1027
1027
 
1028
1028
  # edit index OR case, not both
1029
1029
  if idx && cse
@@ -1133,13 +1133,13 @@ class Api
1133
1133
 
1134
1134
  # current
1135
1135
  json = @cache.current_read(cid)
1136
- cur = Validate.parse(json, 'current'.freeze, Items::ItemCurrent)
1136
+ cur = Items.parse(json, 'current'.freeze, Items::ItemCurrent)
1137
1137
 
1138
1138
  # entry
1139
1139
  if ent['entry']
1140
1140
  enum = ent['entry']
1141
1141
  json = @cache.entry_read(cid, enum)
1142
- ent_pri = Validate.parse(json, 'entry'.freeze, Items::ItemEntry)
1142
+ ent_pri = Items.parse(json, 'entry'.freeze, Items::ItemEntry)
1143
1143
  nxt['entry'] = cur['entry']
1144
1144
  else
1145
1145
  enum = cur['entry'] + 1
@@ -1156,7 +1156,7 @@ class Api
1156
1156
  end
1157
1157
  if anum
1158
1158
  json = @cache.action_read(cid, anum)
1159
- act_pri = Validate.parse(json, 'action'.freeze, Items::ItemAction)
1159
+ act_pri = Items.parse(json, 'action'.freeze, Items::ItemAction)
1160
1160
  nxt['action'] = cur['action']
1161
1161
  elsif act
1162
1162
  anum = cur['action'] + 1
@@ -1318,7 +1318,7 @@ class Api
1318
1318
  end
1319
1319
  end
1320
1320
  ent['files'].each{|fi| fi['log'] ||= lnum } if ent['files']
1321
- eitem = Validate.generate(ent, 'entry'.freeze, Items::ItemEntry)
1321
+ eitem = Items.generate(ent, 'entry'.freeze, Items::ItemEntry)
1322
1322
  log['entry'] = {
1323
1323
  'num' => enum,
1324
1324
  'hash' => ICFS.hash(eitem)
@@ -1328,7 +1328,7 @@ class Api
1328
1328
  if act
1329
1329
  act['action'] = anum
1330
1330
  act['log'] = lnum
1331
- aitem = Validate.generate(act, 'action'.freeze, Items::ItemAction)
1331
+ aitem = Items.generate(act, 'action'.freeze, Items::ItemAction)
1332
1332
  log['action'] = {
1333
1333
  'num' => anum,
1334
1334
  'hash' => ICFS.hash(aitem)
@@ -1339,7 +1339,7 @@ class Api
1339
1339
  if idx
1340
1340
  idx['index'] = xnum
1341
1341
  idx['log'] = lnum
1342
- xitem = Validate.generate(idx, 'index'.freeze, Items::ItemIndex)
1342
+ xitem = Items.generate(idx, 'index'.freeze, Items::ItemIndex)
1343
1343
  log['index'] = {
1344
1344
  'num' => xnum,
1345
1345
  'hash' => ICFS.hash(xitem)
@@ -1349,7 +1349,7 @@ class Api
1349
1349
  # case
1350
1350
  if cse
1351
1351
  cse['log'] = lnum
1352
- citem = Validate.generate(cse, 'case'.freeze, Items::ItemCase)
1352
+ citem = Items.generate(cse, 'case'.freeze, Items::ItemCase)
1353
1353
  log['case_hash'] = ICFS.hash(citem)
1354
1354
  end
1355
1355
 
@@ -1357,11 +1357,11 @@ class Api
1357
1357
  log['log'] = lnum
1358
1358
  log['prev'] = cur['hash']
1359
1359
  log['time'] = now
1360
- litem = Validate.generate(log, 'log'.freeze, Items::ItemLog)
1360
+ litem = Items.generate(log, 'log'.freeze, Items::ItemLog)
1361
1361
  nxt['hash'] = ICFS.hash(litem)
1362
1362
 
1363
1363
  # next
1364
- nitem = Validate.generate(nxt, 'current'.freeze, Items::ItemCurrent)
1364
+ nitem = Items.generate(nxt, 'current'.freeze, Items::ItemCurrent)
1365
1365
 
1366
1366
 
1367
1367
  ####################
@@ -9,6 +9,8 @@
9
9
  # This program is distributed WITHOUT ANY WARRANTY; without even the
10
10
  # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
11
 
12
+ require 'json'
13
+ require 'socket'
12
14
  require_relative 'elastic'
13
15
 
14
16
 
@@ -153,6 +155,8 @@ class CacheElastic < Cache
153
155
  def initialize(map, es)
154
156
  @map = map
155
157
  @es = es
158
+ @name = '%s:%d' % [Socket.gethostname, Process.pid]
159
+ @name.freeze
156
160
  end
157
161
 
158
162
 
@@ -165,11 +169,9 @@ class CacheElastic < Cache
165
169
  ###############################################
166
170
  # (see Cache#lock_take)
167
171
  #
168
- # @todo Include client info to help with debugging
169
- #
170
172
  def lock_take(cid)
171
173
 
172
- json = '{"client":"TODO"}'.freeze
174
+ json = '{"client":"%s"}'.freeze % @name
173
175
  url = '%s/_doc/%s/_create'.freeze % [@map[:lock], CGI.escape(cid)]
174
176
  head = {'Content-Type'.freeze => 'application/json'.freeze}.freeze
175
177
 
@@ -656,7 +658,7 @@ class CacheElastic < Cache
656
658
  filter = [
657
659
  _query_term('caseid'.freeze, query[:caseid]),
658
660
  _query_term('tags'.freeze, query[:tags]),
659
- _query_prefix('title'.freeze, query[:prefix]),
661
+ _query_prefix('title.raw'.freeze, query[:prefix]),
660
662
  ].compact
661
663
  req = { 'query' => _query_bool(must, filter, nil, nil) }
662
664
 
data/lib/icfs/items.rb CHANGED
@@ -9,7 +9,9 @@
9
9
  # This program is distributed WITHOUT ANY WARRANTY; without even the
10
10
  # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
11
 
12
- #
12
+ require 'json'
13
+
14
+
13
15
  module ICFS
14
16
 
15
17
 
@@ -18,6 +20,65 @@ module ICFS
18
20
  #
19
21
  module Items
20
22
 
23
+
24
+ ###############################################
25
+ # Parse JSON string and validate
26
+ #
27
+ # @param json [String] the JSON to parse
28
+ # @param name [String] description of the item
29
+ # @param val [Hash] the check to use
30
+ # @return [Object] the item
31
+ #
32
+ # @raise [Error::NotFound] if json is nil
33
+ # @raise [Error::Value] if parsing or validation fails
34
+ #
35
+ def self.parse(json, name, val)
36
+ if json.nil?
37
+ raise(Error::NotFound, '%s not found'.freeze % name)
38
+ end
39
+ begin
40
+ itm = JSON.parse(json)
41
+ rescue
42
+ raise(Error::Value, 'JSON parsing failed'.freeze)
43
+ end
44
+ Items.validate(itm, name, val)
45
+ return itm
46
+ end # def self.parse()
47
+
48
+
49
+ ###############################################
50
+ # Validate and generate JSON
51
+ #
52
+ # @param itm [Object] item to validate
53
+ # @param name [String] description of the item
54
+ # @param val [Hash] the check to use
55
+ # @return [String] JSON encoded item
56
+ #
57
+ # @raise [Error::Value] if validation fails
58
+ #
59
+ def self.generate(itm, name, val)
60
+ Items.validate(itm, name, val)
61
+ return JSON.pretty_generate(itm)
62
+ end # def self.generate()
63
+
64
+
65
+ ###############################################
66
+ # Validate an object
67
+ #
68
+ # @param obj [Object] object to validate
69
+ # @param name [String] description of the object
70
+ # @param val [Hash] the check to use
71
+ #
72
+ # @raise [Error::Value] if validation fails
73
+ #
74
+ def self.validate(obj, name, val)
75
+ err = Validate.check(obj, val)
76
+ if err
77
+ raise(Error::Value, '%s has bad values: %s'.freeze %
78
+ [name, err.inspect])
79
+ end
80
+ end
81
+
21
82
  ##############################################################
22
83
  # Base fields
23
84
  ##############################################################
data/lib/icfs/store.rb CHANGED
@@ -115,6 +115,18 @@ class Store
115
115
  def file_write(cid, enum, lnum, fnum, tmpf); raise NotImplementedError; end
116
116
 
117
117
 
118
+ ###############################################
119
+ # Get a file size
120
+ #
121
+ # @param cid [String] caseid
122
+ # @param enum [Integer] Entry number
123
+ # @param lnum [Integer] Log number
124
+ # @param fnum [Integer] File number
125
+ # @return [Integer] The size of the file
126
+ #
127
+ def file_size(cid, enum, lnum, fnum); raise NotImplementedError; end
128
+
129
+
118
130
  ###############################################
119
131
  # Read an action
120
132
  #
@@ -176,6 +188,19 @@ class Store
176
188
  def tempfile; raise NotImplementedError; end
177
189
 
178
190
 
191
+ ###############################################
192
+ # Close the file returned by file_read()
193
+ #
194
+ # @param fi [File] The file to close
195
+ #
196
+ def close(fi)
197
+ if fi.respond_to?( :close! )
198
+ fi.close!
199
+ else
200
+ fi.close
201
+ end
202
+ end
203
+
179
204
  private
180
205
 
181
206