icfs 0.1.2 → 0.1.3

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.
@@ -0,0 +1,49 @@
1
+ #
2
+ # Investigative Case File System
3
+ #
4
+ # Copyright 2019 by Graham A. Field
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License version 3.
8
+ #
9
+ # This program is distributed WITHOUT ANY WARRANTY; without even the
10
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
+
12
+ version: '3'
13
+
14
+ services:
15
+
16
+ # Elasticsearch instance
17
+ elastic:
18
+ image: docker.elastic.co/elasticsearch/elasticsearch:6.7.2
19
+ environment:
20
+ discovery-type: single-node
21
+ volume:
22
+ - elastic:/usr/share/elasticsearch/data
23
+ ports:
24
+ - "127.0.0.1:9200:9200"
25
+
26
+ # Minio S3-compatible object store
27
+ minio:
28
+ image: minio/minio
29
+ environment:
30
+ MINIO_ACCESS_KEY: minio_key
31
+ MINIO_SECRET_KEY: minio_secret
32
+ volume:
33
+ - minio:/data
34
+ command: ["server", "/data"]
35
+
36
+ # Redis cache
37
+ redis:
38
+ image: redis:alpine
39
+
40
+ # the app
41
+ app:
42
+ image: icfs-wrk
43
+ ports:
44
+ - "127.0.0.1:80:8080"
45
+
46
+
47
+ volumes:
48
+ - elastic
49
+ - minio
@@ -0,0 +1,63 @@
1
+ #
2
+ # Investigative Case File System
3
+ #
4
+ # Copyright 2019 by Graham A. Field
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License version 3.
8
+ #
9
+ # This program is distributed WITHOUT ANY WARRANTY; without even the
10
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
+
12
+ version: '3'
13
+
14
+ services:
15
+
16
+ # Elasticsearch
17
+ elastic:
18
+ image: docker.elastic.co/elasticsearch/elasticsearch:6.7.2
19
+ environment:
20
+ discovery.type: single-node
21
+ volumes:
22
+ - elastic:/usr/share/elasticsearch/data
23
+ ports:
24
+ - "127.0.0.1:9200:9200"
25
+ - "127.0.0.1:9300:9300"
26
+
27
+
28
+ # Minio - S3 compatible object store
29
+ minio:
30
+ image: minio/minio
31
+ volumes:
32
+ - objects:/data
33
+ environment:
34
+ MINIO_ACCESS_KEY: minio_key
35
+ MINIO_SECRET_KEY: minio_secret
36
+ ports:
37
+ - "127.0.0.1:9000:9000"
38
+ command: ["server", "/data"]
39
+
40
+
41
+ # Redis - cache
42
+ # to run the CLI: docker exec -it icfs-redis redis-cli
43
+ redis:
44
+ image: redis:alpine
45
+ ports:
46
+ - "127.0.0.1:6379:6379"
47
+
48
+
49
+ # App development
50
+ # just run a sleep for a week, then connect interactively using:
51
+ # docker-compose exec icfs /bin/sh
52
+ icfs:
53
+ image: icfs-wrk
54
+ build: ./icfs-wrk
55
+ volumes:
56
+ - ./icfs:/icfs
57
+ ports:
58
+ - "127.0.0.1:8080:8080"
59
+ command: ["/bin/sleep", "7d"]
60
+
61
+ volumes:
62
+ elastic:
63
+ objects:
data/devel/icfs ADDED
@@ -0,0 +1 @@
1
+ devel/../
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Investigative Case File System
4
+ #
5
+ # Copyright 2019 by Graham A. Field
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License version 3.
9
+ #
10
+ # This program is distributed WITHOUT ANY WARRANTY; without even the
11
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
+
13
+ require 'aws-sdk-s3'
14
+ require 'find'
15
+
16
+ require_relative '../../lib/icfs'
17
+
18
+ # Minio config
19
+ Aws.config.update(
20
+ endpoint: 'http://minio:9000',
21
+ access_key_id: 'minio_key',
22
+ secret_access_key: 'minio_secret',
23
+ force_path_style: true,
24
+ region: 'us-east-1'
25
+ )
26
+
27
+ s3 = Aws::S3::Client.new
28
+
29
+ dir = ARGV[0]
30
+ prefix = ARGV[1]
31
+ size = (dir[-1] == '/') ? dir.size : dir.size + 1
32
+
33
+ # copy in all the files in the dir
34
+ Find.find(dir) do |fn|
35
+ next unless File.file?(fn)
36
+
37
+ rel = fn[size..-1]
38
+ key = prefix + rel
39
+
40
+ cont = File.binread(fn)
41
+ s3.put_object( bucket: 'icfs', key: key, body: cont )
42
+ puts key
43
+ end
@@ -10,30 +10,22 @@
10
10
  # This program is distributed WITHOUT ANY WARRANTY; without even the
11
11
  # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
12
 
13
- # Elasticsearch cache
14
- # S3 item store
15
- # S3 & Redis Users
16
-
17
13
  require 'json'
18
14
  require 'faraday'
19
- require 'fileutils'
20
15
  require 'aws-sdk-s3'
21
- require 'redis'
22
16
 
23
17
  require_relative '../../lib/icfs'
24
18
  require_relative '../../lib/icfs/cache_elastic'
25
19
  require_relative '../../lib/icfs/store_s3'
26
- require_relative '../../lib/icfs/users_fs'
27
- require_relative '../../lib/icfs/users_redis'
28
20
 
29
21
 
30
22
  # Minio config
31
23
  Aws.config.update(
32
- endpoint: 'http://icfs-minio:9000',
24
+ endpoint: 'http://minio:9000',
33
25
  access_key_id: 'minio_key',
34
26
  secret_access_key: 'minio_secret',
35
27
  force_path_style: true,
36
- region: 'use-east-1'
28
+ region: 'us-east-1'
37
29
  )
38
30
 
39
31
  # default mapping
@@ -49,15 +41,9 @@ map = {
49
41
 
50
42
  # base items
51
43
  s3 = Aws::S3::Client.new
52
- redis = Redis.new(host: 'icfs-redis')
53
- es = Faraday.new('http://icfs-elastic:9200')
44
+ es = Faraday.new('http://elastic:9200')
54
45
  cache = ICFS::CacheElastic.new(map, es)
55
46
  store = ICFS::StoreS3.new(s3, 'icfs', 'case/')
56
- users_base = ICFS::UsersFs.new(ARGV[0])
57
- users = ICFS::UsersRedis.new(redis, users_base, {
58
- prefix: 'users/'.freeze,
59
- expires: 60, # one minute cache for testing
60
- })
61
47
 
62
48
  # create the indexes
63
49
  cache.create(ICFS::CacheElastic::Maps)
@@ -67,8 +53,7 @@ puts "Indexes created"
67
53
  s3.create_bucket(bucket: 'icfs')
68
54
  puts "S3 bucket created"
69
55
 
70
- api = ICFS::Api.new([], users, cache, store)
71
- api.user = 'user1'
56
+ api = ICFS::Api.new([], nil, cache, store)
72
57
 
73
58
  # add a template
74
59
  tmpl = {
@@ -89,5 +74,5 @@ ent = {
89
74
  'title' => 'Create template',
90
75
  'content' => 'To test'
91
76
  }
92
- api.case_create(ent, tmpl)
77
+ api.case_create(ent, tmpl, nil, 'user1')
93
78
  puts "Create template"
@@ -10,16 +10,14 @@
10
10
  # This program is distributed WITHOUT ANY WARRANTY; without even the
11
11
  # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
12
 
13
- require 'json'
14
13
  require 'faraday'
15
- require 'fileutils'
16
14
  require 'aws-sdk-s3'
17
15
  require 'redis'
18
16
 
19
17
  require_relative '../../lib/icfs'
20
18
  require_relative '../../lib/icfs/cache_elastic'
21
19
  require_relative '../../lib/icfs/store_s3'
22
- require_relative '../../lib/icfs/users_fs'
20
+ require_relative '../../lib/icfs/users_s3'
23
21
  require_relative '../../lib/icfs/users_redis'
24
22
  require_relative '../../lib/icfs/web/client'
25
23
  require_relative '../../lib/icfs/web/config_s3'
@@ -29,11 +27,11 @@ require_relative '../../lib/icfs/demo/static'
29
27
 
30
28
  # Minio config
31
29
  Aws.config.update(
32
- endpoint: 'http://icfs-minio:9000',
30
+ endpoint: 'http://minio:9000',
33
31
  access_key_id: 'minio_key',
34
32
  secret_access_key: 'minio_secret',
35
33
  force_path_style: true,
36
- region: 'use-east-1'
34
+ region: 'us-east-1'
37
35
  )
38
36
 
39
37
  # default mapping
@@ -52,16 +50,21 @@ defaults = {
52
50
  'tz' => '-04:00'
53
51
  }
54
52
 
53
+ # the log
54
+ log = Logger.new(STDERR)
55
+ log.level = Logger::INFO
56
+
55
57
  # base items
56
58
  s3 = Aws::S3::Client.new
57
- redis = Redis.new(host: 'icfs-redis')
58
- es = Faraday.new('http://icfs-elastic:9200')
59
+ redis = Redis.new(host: 'redis')
60
+ es = Faraday.new('http://elastic:9200')
59
61
  cache = ICFS::CacheElastic.new(map, es)
60
- store = ICFS::StoreS3.new(s3, 'icfs', 'case/')
61
- users_base = ICFS::UsersFs.new(ARGV[0])
62
+ store = ICFS::StoreS3.new(s3, 'icfs'.freeze, 'case/'.freeze)
63
+ users_base = ICFS::UsersS3.new(s3, 'icfs'.freeze, 'users/'.freeze)
62
64
  users = ICFS::UsersRedis.new(redis, users_base, {
63
65
  prefix: 'users/'.freeze,
64
66
  expires: 60, # one minute cache for testing
67
+ log: log,
65
68
  })
66
69
  api = ICFS::Api.new([], users, cache, store)
67
70
  config_base = ICFS::Web::ConfigS3.new(defaults, s3, 'icfs', 'config/')
@@ -74,11 +77,11 @@ web = ICFS::Web::Client.new('/static/icfs.css', '/static/icfs.js')
74
77
  # static files
75
78
  static = {
76
79
  '/static/icfs.css' => {
77
- 'path' => 'data/icfs.css',
80
+ 'path' => '/icfs/data/icfs.css',
78
81
  'mime' => 'text/css; charset=utf-8'
79
82
  },
80
83
  '/static/icfs.js' => {
81
- 'path' => 'data/icfs.js',
84
+ 'path' => '/icfs/data/icfs.js',
82
85
  'mime' => 'application/javascript; charset=utf-8'
83
86
  }
84
87
  }
data/lib/icfs/api.rb CHANGED
@@ -100,6 +100,14 @@ class Api
100
100
  end # def user=()
101
101
 
102
102
 
103
+ ###############################################
104
+ # Flush any user caching
105
+ def user_flush()
106
+ @users.flush(@user)
107
+ self.user = @user
108
+ end # def user_flush
109
+
110
+
103
111
  ###############################################
104
112
  # User
105
113
  #
@@ -878,8 +886,9 @@ class Api
878
886
  # @param ent [Hash] the first entry
879
887
  # @param cse [Hash] the case
880
888
  # @param tid [String] the template name
889
+ # @param unam [String] the user name if not using the Users API
881
890
  #
882
- def case_create(ent, cse, tid=nil)
891
+ def case_create(ent, cse, tid=nil, unam=nil)
883
892
 
884
893
  ####################
885
894
  # Sanity checks
@@ -888,12 +897,14 @@ class Api
888
897
  Items.validate(ent, 'entry'.freeze, Items::ItemEntryNew)
889
898
  Items.validate(cse, 'case'.freeze, Items::ItemCaseEdit)
890
899
 
891
- # access users/roles/groups are valid
892
- cse["access"].each do |acc|
893
- acc["grant"].each do |gnt|
894
- urg = @users.read(gnt)
895
- if !urg
896
- raise(Error::NotFound, 'User/role/group %s not found'.freeze % urg)
900
+ # access users/roles/groups are valid, unless manually specifying user
901
+ unless unam
902
+ cse["access"].each do |acc|
903
+ acc["grant"].each do |gnt|
904
+ urg = @users.read(gnt)
905
+ if !urg
906
+ raise(Error::NotFound, 'User/role/group %s not found'.freeze % urg)
907
+ end
897
908
  end
898
909
  end
899
910
  end
@@ -923,6 +934,9 @@ class Api
923
934
  raise(Error::Value, 'No Index for a new case entry'.freeze)
924
935
  end
925
936
 
937
+ # Allow case creation without a Users system in place
938
+ user = @user ? @user : unam
939
+ raise(ArgumentError, 'No user specified'.freeze) if user.nil?
926
940
 
927
941
  ####################
928
942
  # Prep
@@ -941,7 +955,7 @@ class Api
941
955
  ent['log'] = 1
942
956
  ent['tags'] ||= [ ]
943
957
  ent['tags'] << ICFS::TagCase
944
- ent['user'] = @user
958
+ ent['user'] = user
945
959
  files, fhash = _pre_files(ent)
946
960
 
947
961
  # log
@@ -950,7 +964,7 @@ class Api
950
964
  'caseid' => cid,
951
965
  'log' => 1,
952
966
  'prev' => '0'*64,
953
- 'user' => @user,
967
+ 'user' => user,
954
968
  'entry' => {
955
969
  'num' => 1,
956
970
  },
data/lib/icfs/users.rb CHANGED
@@ -56,6 +56,15 @@ class Users
56
56
  }.freeze
57
57
 
58
58
 
59
+ ###############################################
60
+ # Flush a user/role/group from a cache, if any
61
+ #
62
+ # @param urg [String] User/Role/Group name
63
+ # @return [Boolean] if cached
64
+ #
65
+ def flush(urg); raise NotImplementedError; end
66
+
67
+
59
68
  ###############################################
60
69
  # Read a user/role/group
61
70
  #
data/lib/icfs/users_fs.rb CHANGED
@@ -42,6 +42,12 @@ class UsersFs < Users
42
42
  private :_path
43
43
 
44
44
 
45
+ ###############################################
46
+ # (see Users#flush)
47
+ #
48
+ def flush(urg); false; end
49
+
50
+
45
51
  ###############################################
46
52
  # (see Users#read)
47
53
  #
@@ -26,12 +26,14 @@ class UsersRedis < Users
26
26
  # @param opts [Hash] Options
27
27
  # @option opts [String] :prefix Prefix for Redis key
28
28
  # @option opts [Integer] :expires Expiration time in seconds
29
+ # @option opts [Logger] :log Logger which records info about user
29
30
  #
30
31
  def initialize(redis, base, opts={})
31
32
  @redis = redis
32
33
  @base = base
33
34
  @pre = opts[:prefix] || ''.freeze
34
35
  @exp = opts[:expires] || 1*60*60 # 1 hour default
36
+ @log = opts[:log]
35
37
  end
36
38
 
37
39
 
@@ -44,20 +46,38 @@ class UsersRedis < Users
44
46
  private :_key
45
47
 
46
48
 
49
+ ###############################################
50
+ # (see Users#flush)
51
+ #
52
+ def flush(urg)
53
+ Items.validate(urg, 'User/role/group name'.freeze, Items::FieldUsergrp)
54
+ @log.info('User/role/group cache flush: %s'.freeze % urg) if @log
55
+ @redis.del(_key(urg))
56
+ return true
57
+ end # def flush()
58
+
59
+
47
60
  ###############################################
48
61
  # (see Users#read)
49
62
  #
50
63
  def read(urg)
51
- Validate.check(urg, Items::FieldUsergrp) # FIXME
64
+ Items.validate(urg, 'User/role/group name'.freeze, Items::FieldUsergrp)
52
65
  key = _key(urg)
66
+ @log.debug('User/role/group read: %s'.freeze % urg) if @log
53
67
 
54
68
  # try cache
55
69
  json = @redis.get(key)
56
- return JSON.parse(json) if json
70
+ if json
71
+ @log.debug('User/role/group cache hit: %s'.freeze % urg) if @log
72
+ return JSON.parse(json)
73
+ end
57
74
 
58
75
  # get base object from base store
59
76
  bse = @base.read(urg)
60
- return nil if !bse
77
+ if !bse
78
+ @log.warn('User/role/group not found: %s'.freeze % urg) if @log
79
+ return nil
80
+ end
61
81
 
62
82
  # assemble
63
83
  seen = Set.new.add(urg)
@@ -103,11 +123,12 @@ class UsersRedis < Users
103
123
  bse['roles'] = roles.to_a unless roles.empty?
104
124
  bse['groups'] = grps.to_a unless grps.empty?
105
125
  bse['perms'] = perms.to_a unless perms.empty?
106
- json = JSON.pretty_generate(bse)
126
+ json = JSON.generate(bse)
107
127
 
108
128
  # save to cache
109
129
  @redis.set(key, json)
110
130
  @redis.expire(key, @exp)
131
+ @log.info('User/role/group cached: %s %s'.freeze % [urg, json]) if @log
111
132
  return bse
112
133
  end # def read()
113
134
 
@@ -118,6 +139,7 @@ class UsersRedis < Users
118
139
  def write(obj)
119
140
  json = Items.generate(obj, 'User/Role/Group'.freeze, Users::ValUser)
120
141
  key = _key(obj['name'])
142
+ @log.info('User/role/group write: %s'.freeze % urg) if @log
121
143
  @redis.del(key)
122
144
  @base.write(obj)
123
145
  end # def write()
data/lib/icfs/users_s3.rb CHANGED
@@ -33,14 +33,20 @@ class UsersS3 < Users
33
33
 
34
34
 
35
35
  ###############################################
36
- # Where to store onfig
36
+ # Where to store user
37
37
  #
38
38
  def _path(user)
39
- @pre + user
39
+ @pre + user + '.json'.freeze
40
40
  end # def _path()
41
41
  private :_path
42
42
 
43
43
 
44
+ ###############################################
45
+ # (see Users#flush)
46
+ #
47
+ def flush(urg); false; end
48
+
49
+
44
50
  ###############################################
45
51
  # (see Users#read)
46
52
  #
@@ -24,11 +24,13 @@ class AuthSsl
24
24
  # @param app [Object] The rack app
25
25
  # @param map [Object] Maps DN to user name
26
26
  # @param api [ICFS::Api] the Api
27
+ # @param cfg [ICFS::Web::Config] the config settings
27
28
  #
28
- def initialize(app, map, api)
29
+ def initialize(app, map, api, cfg)
29
30
  @app = app
30
31
  @map = map
31
32
  @api = api
33
+ @cfg = cfg
32
34
  end
33
35
 
34
36
 
@@ -70,6 +72,8 @@ class AuthSsl
70
72
  ]
71
73
  end
72
74
  env['icfs'] = @api
75
+ @cfg.load(user)
76
+ env['icfs.config'] = @cfg
73
77
  return @app.call(env)
74
78
  end # def call()
75
79
 
@@ -780,6 +780,7 @@ class Client
780
780
  para = _util_post(env)
781
781
  _post_config(env, para).each{|key, val| cfg.set(key,val) }
782
782
  cfg.save
783
+ api.user_flush()
783
784
 
784
785
  # display the index
785
786
  body = [
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icfs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Graham A. Field
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-07 00:00:00.000000000 Z
11
+ date: 2019-06-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2-
14
14
 
@@ -24,41 +24,23 @@ extensions: []
24
24
  extra_rdoc_files: []
25
25
  files:
26
26
  - LICENSE.txt
27
- - bin/icfs_demo_check.rb
28
- - bin/icfs_demo_create.rb
29
27
  - bin/icfs_demo_fcgi.rb
30
28
  - bin/icfs_demo_ssl_gen.rb
31
- - bin/icfs_demo_web.rb
32
- - data/demo_config.yml
33
- - data/docker/build-web.sh
34
- - data/docker/compose-demo.yml
35
- - data/docker/compose-init.yml
36
- - data/docker/icfs-app.rb
37
- - data/docker/icfs-cfg.yml
38
- - data/docker/icfs-init.rb
39
- - data/docker/icfs-ruby/Dockerfile
40
- - data/docker/icfs-ruby/build.sh
41
- - data/docker/nginx.conf
42
29
  - data/icfs.css
43
30
  - data/icfs.js
44
- - devel/create.sh
45
- - devel/elastic.sh
31
+ - devel/devel-webrick.yml
32
+ - devel/docker-compose.yml
33
+ - devel/icfs
46
34
  - devel/icfs-wrk/Dockerfile
47
- - devel/minio.sh
48
- - devel/redis.sh
49
- - devel/server.sh
50
- - devel/test/es-s3-fs-init.rb
51
- - devel/test/es-s3-fs-webrick.rb
52
- - devel/test/es-s3-restore.rb
53
- - devel/test/init.rb
54
- - devel/test/run.rb
35
+ - devel/run/copy-s3.rb
36
+ - devel/run/init-icfs.rb
37
+ - devel/run/webrick.rb
55
38
  - lib/icfs.rb
56
39
  - lib/icfs/api.rb
57
40
  - lib/icfs/cache.rb
58
41
  - lib/icfs/cache_elastic.rb
59
42
  - lib/icfs/demo/auth.rb
60
43
  - lib/icfs/demo/static.rb
61
- - lib/icfs/demo/timezone.rb
62
44
  - lib/icfs/elastic.rb
63
45
  - lib/icfs/items.rb
64
46
  - lib/icfs/store.rb
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # Investigative Case File System
4
- #
5
- # Copyright 2019 by Graham A. Field
6
- #
7
- # This program is free software: you can redistribute it and/or modify
8
- # it under the terms of the GNU General Public License version 3.
9
- #
10
- # This program is distributed WITHOUT ANY WARRANTY; without even the
11
- # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
-
13
- require 'yaml'
14
- require 'logger'
15
-
16
- require_relative '../lib/icfs'
17
- require_relative '../lib/icfs/utils/check'
18
- require_relative '../lib/icfs/store_fs'
19
-
20
- # load the config file
21
- cfg = YAML.load_file(ARGV[0])
22
-
23
- # objects
24
- store = ICFS::StoreFs.new(cfg['store']['dir'])
25
- log = Logger.new(STDOUT, level: Logger::INFO)
26
- check = ICFS::Utils::Check.new(store, log)
27
-
28
- # check
29
- check.check(ARGV[1], ARGV[2].to_i, nil, {hash_all: true})