icfs 0.1.1 → 0.1.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/data/icfs.css +1 -0
- data/{bin/icfs_dev_todo.rb → devel/create.sh} +4 -9
- data/devel/elastic.sh +20 -0
- data/devel/icfs-wrk/Dockerfile +27 -0
- data/devel/minio.sh +22 -0
- data/devel/redis.sh +18 -0
- data/devel/server.sh +18 -0
- data/devel/test/es-s3-fs-init.rb +93 -0
- data/devel/test/es-s3-fs-webrick.rb +79 -0
- data/devel/test/es-s3-restore.rb +56 -0
- data/devel/test/init.rb +93 -0
- data/devel/test/run.rb +96 -0
- data/lib/icfs/api.rb +22 -11
- data/lib/icfs/cache_elastic.rb +9 -1
- data/lib/icfs/demo/auth.rb +7 -1
- data/lib/icfs/store.rb +6 -12
- data/lib/icfs/store_fs.rb +5 -1
- data/lib/icfs/users.rb +0 -3
- data/lib/icfs/users_fs.rb +19 -70
- data/lib/icfs/users_redis.rb +127 -0
- data/lib/icfs/users_s3.rb +68 -0
- data/lib/icfs/utils/backup.rb +212 -7
- data/lib/icfs/utils/check.rb +1 -5
- data/lib/icfs/web/client.rb +101 -8
- data/lib/icfs/web/config.rb +108 -0
- data/lib/icfs/web/config_redis.rb +78 -0
- data/lib/icfs/web/config_s3.rb +66 -0
- data/lib/icfs.rb +0 -2
- metadata +18 -4
- data/lib/icfs/users_elastic.rb +0 -168
data/lib/icfs/web/client.rb
CHANGED
@@ -21,9 +21,6 @@ module Web
|
|
21
21
|
##########################################################################
|
22
22
|
# Web Client
|
23
23
|
#
|
24
|
-
# @todo Improve time handling for web interface
|
25
|
-
# @todo Scrub the javascript
|
26
|
-
#
|
27
24
|
class Client
|
28
25
|
|
29
26
|
###############################################
|
@@ -170,6 +167,7 @@ class Client
|
|
170
167
|
when 'case_edit'; return _call_case_edit(env)
|
171
168
|
when 'entry_edit'; return _call_entry_edit(env)
|
172
169
|
when 'index_edit'; return _call_index_edit(env)
|
170
|
+
when 'config_edit'; return _call_config_edit(env)
|
173
171
|
|
174
172
|
# view
|
175
173
|
when 'home', ''; return _call_home(env)
|
@@ -369,6 +367,8 @@ class Client
|
|
369
367
|
['after'.freeze, :after, :time].freeze,
|
370
368
|
['tags'.freeze, :tags, :string].freeze,
|
371
369
|
['purpose'.freeze, :purpose, :string].freeze,
|
370
|
+
['size'.freeze, :size, :integer].freeze,
|
371
|
+
['page'.freeze, :page, :integer].freeze,
|
372
372
|
['sort'.freeze, :sort, :string].freeze,
|
373
373
|
].freeze
|
374
374
|
|
@@ -430,6 +430,8 @@ class Client
|
|
430
430
|
['content'.freeze, :content, :string].freeze,
|
431
431
|
['tags'.freeze, :tags, :string].freeze,
|
432
432
|
['purpose'.freeze, :purpose, :string].freeze,
|
433
|
+
['size'.freeze, :size, :integer].freeze,
|
434
|
+
['page'.freeze, :page, :integer].freeze,
|
433
435
|
['sort'.freeze, :sort, :string].freeze,
|
434
436
|
].freeze
|
435
437
|
|
@@ -753,6 +755,43 @@ class Client
|
|
753
755
|
end # def _call_index_edit()
|
754
756
|
|
755
757
|
|
758
|
+
###############################################
|
759
|
+
# Edit configuration
|
760
|
+
#
|
761
|
+
def _call_config_edit(env)
|
762
|
+
env['icfs.page'] = 'Config Edit'.freeze
|
763
|
+
api = env['icfs']
|
764
|
+
cfg = env['icfs.config']
|
765
|
+
_verb_getpost(env)
|
766
|
+
|
767
|
+
# get the form
|
768
|
+
if env['REQUEST_METHOD'] == 'GET'.freeze
|
769
|
+
parts = [ _form_config(env) ]
|
770
|
+
body = [
|
771
|
+
_div_nav(env),
|
772
|
+
_div_desc('Edit Configuration'.freeze, ''.freeze),
|
773
|
+
_div_form(env, '/config_edit/'.freeze, nil, parts,
|
774
|
+
'Save Config'.freeze),
|
775
|
+
].join(''.freeze)
|
776
|
+
return _resp_success(env, body)
|
777
|
+
|
778
|
+
# post the form
|
779
|
+
elsif env['REQUEST_METHOD'] == 'POST'.freeze
|
780
|
+
para = _util_post(env)
|
781
|
+
_post_config(env, para).each{|key, val| cfg.set(key,val) }
|
782
|
+
cfg.save
|
783
|
+
|
784
|
+
# display the index
|
785
|
+
body = [
|
786
|
+
_div_nav(env),
|
787
|
+
_div_desc('Edit Configuration'.freeze, 'Settings saved'.freeze),
|
788
|
+
_div_info(env),
|
789
|
+
].join(''.freeze)
|
790
|
+
return _resp_success(env, body)
|
791
|
+
end
|
792
|
+
end # def _call_config_edit()
|
793
|
+
|
794
|
+
|
756
795
|
###############################################
|
757
796
|
# User Home page
|
758
797
|
def _call_home(env)
|
@@ -1020,6 +1059,7 @@ class Client
|
|
1020
1059
|
after: Time.now.to_i - 60*60*24*30,
|
1021
1060
|
purpose: 'User Stats - Last 30 days'.freeze,
|
1022
1061
|
}, 'Stats'.freeze),
|
1062
|
+
_a_config_edit(env, 'Config'),
|
1023
1063
|
_a_info(env, 'Info'.freeze),
|
1024
1064
|
]
|
1025
1065
|
end
|
@@ -1067,7 +1107,7 @@ class Client
|
|
1067
1107
|
#
|
1068
1108
|
def _div_info(env)
|
1069
1109
|
api = env['icfs']
|
1070
|
-
tz = env['icfs.tz'
|
1110
|
+
tz = env['icfs.config'].get('tz')
|
1071
1111
|
|
1072
1112
|
# roles/groups/perms
|
1073
1113
|
roles = api.roles.map{|rol| DivInfoList % Rack::Utils.escape_html(rol)}
|
@@ -2996,7 +3036,7 @@ class Client
|
|
2996
3036
|
FormEntryStatEach % [
|
2997
3037
|
stats_cnt, claim_cnt,
|
2998
3038
|
stats_cnt, esc, esc,
|
2999
|
-
stats_cnt, st['
|
3039
|
+
stats_cnt, st['value'].to_s,
|
3000
3040
|
claims.join(''.freeze)
|
3001
3041
|
]
|
3002
3042
|
end
|
@@ -3032,7 +3072,7 @@ class Client
|
|
3032
3072
|
title, time, content,
|
3033
3073
|
tags_cnt, tags,
|
3034
3074
|
files_cnt, files,
|
3035
|
-
|
3075
|
+
env['SCRIPT_NAME'],
|
3036
3076
|
Rack::Utils.escape(cid),
|
3037
3077
|
index_cnt, index,
|
3038
3078
|
stats_sel, stats_cnt, stats,
|
@@ -3638,6 +3678,36 @@ class Client
|
|
3638
3678
|
</div>'.freeze
|
3639
3679
|
|
3640
3680
|
|
3681
|
+
###############################################
|
3682
|
+
# Config Form
|
3683
|
+
#
|
3684
|
+
def _form_config(env)
|
3685
|
+
cfg = env['icfs.config']
|
3686
|
+
tz = cfg.get('tz')
|
3687
|
+
return FormConfig % [tz]
|
3688
|
+
end # def _form_config()
|
3689
|
+
|
3690
|
+
|
3691
|
+
# Config form
|
3692
|
+
FormConfig = '
|
3693
|
+
<div class="sect">
|
3694
|
+
<div class="sect-main">
|
3695
|
+
<div class="sect-label">Config</div>
|
3696
|
+
<div class="tip"><div class="tip-disp"></div><div class="tip-info">
|
3697
|
+
Configuration settings.
|
3698
|
+
</div></div>
|
3699
|
+
<div class="sect-fill"> </div>
|
3700
|
+
</div>
|
3701
|
+
<div class="form-row">
|
3702
|
+
<div class="list-label">Timezone:</div>
|
3703
|
+
<input class="form-tz" name="cfg-tz" type="text" value="%s">
|
3704
|
+
<div class="tip"><div class="tip-disp"></div><div class="tip-info">
|
3705
|
+
Timezone to display date/times, format as +/-HH:MM.
|
3706
|
+
</div></div>
|
3707
|
+
</div>
|
3708
|
+
</div>'.freeze
|
3709
|
+
|
3710
|
+
|
3641
3711
|
###########################################################
|
3642
3712
|
# Post
|
3643
3713
|
###########################################################
|
@@ -3948,6 +4018,17 @@ class Client
|
|
3948
4018
|
end # def _post_index()
|
3949
4019
|
|
3950
4020
|
|
4021
|
+
###############################################
|
4022
|
+
# Config edit
|
4023
|
+
#
|
4024
|
+
def _post_config(env, para)
|
4025
|
+
cfg = {
|
4026
|
+
'tz' => para['cfg-tz']
|
4027
|
+
}
|
4028
|
+
return cfg
|
4029
|
+
end # def _post_config()
|
4030
|
+
|
4031
|
+
|
3951
4032
|
###########################################################
|
3952
4033
|
# Links
|
3953
4034
|
###########################################################
|
@@ -4129,6 +4210,17 @@ class Client
|
|
4129
4210
|
end
|
4130
4211
|
|
4131
4212
|
|
4213
|
+
###############################################
|
4214
|
+
# Link to Config edit
|
4215
|
+
#
|
4216
|
+
def _a_config_edit(env, txt)
|
4217
|
+
'<a href="%s/config_edit">%s</a>'.freeze % [
|
4218
|
+
env['SCRIPT_NAME'],
|
4219
|
+
Rack::Utils.escape_html(txt)
|
4220
|
+
]
|
4221
|
+
end
|
4222
|
+
|
4223
|
+
|
4132
4224
|
###############################################
|
4133
4225
|
# Link to Home
|
4134
4226
|
#
|
@@ -4287,7 +4379,8 @@ class Client
|
|
4287
4379
|
# Epoch time as local
|
4288
4380
|
#
|
4289
4381
|
def _util_time(env, time)
|
4290
|
-
|
4382
|
+
tz = env['icfs.config'].get('tz')
|
4383
|
+
Time.at(time).getlocal(tz).strftime('%F %T'.freeze)
|
4291
4384
|
end
|
4292
4385
|
|
4293
4386
|
|
@@ -4304,7 +4397,7 @@ class Client
|
|
4304
4397
|
|
4305
4398
|
# default use parse
|
4306
4399
|
ma = /[+-]\d{2}:\d{2}$/.match str
|
4307
|
-
tstr = ma ? str : str + env['icfs.tz'
|
4400
|
+
tstr = ma ? str : str + env['icfs.config'].get('tz')
|
4308
4401
|
time = Time.parse(tstr).to_i
|
4309
4402
|
rescue ArgumentError
|
4310
4403
|
return nil
|
@@ -0,0 +1,108 @@
|
|
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
|
+
#
|
13
|
+
module ICFS
|
14
|
+
module Web
|
15
|
+
|
16
|
+
##########################################################################
|
17
|
+
# Configuration storage interface
|
18
|
+
#
|
19
|
+
# @abstract
|
20
|
+
#
|
21
|
+
class Config
|
22
|
+
|
23
|
+
###############################################
|
24
|
+
# Valid config options
|
25
|
+
ValConfig = {
|
26
|
+
method: :hash,
|
27
|
+
optional: {
|
28
|
+
'tz' => {
|
29
|
+
method: :string,
|
30
|
+
valid: /[+\-](0[0-9]|1[0-2]):[0-5][0-9]/.freeze,
|
31
|
+
whitelist: true,
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
###############################################
|
37
|
+
# New instance
|
38
|
+
#
|
39
|
+
# @param defaults [Hash] The default options
|
40
|
+
#
|
41
|
+
def initialize(defaults={})
|
42
|
+
@data = {}
|
43
|
+
@unam = nil
|
44
|
+
@defaults = defaults
|
45
|
+
end # def initialize()
|
46
|
+
|
47
|
+
|
48
|
+
###############################################
|
49
|
+
# The configuration values hash
|
50
|
+
#
|
51
|
+
attr_accessor :data
|
52
|
+
|
53
|
+
|
54
|
+
###############################################
|
55
|
+
# The configuration defaults
|
56
|
+
#
|
57
|
+
attr_reader :defaults
|
58
|
+
|
59
|
+
|
60
|
+
###############################################
|
61
|
+
# Get a value
|
62
|
+
#
|
63
|
+
# @param key [String] The name of the config setting
|
64
|
+
#
|
65
|
+
def get(key)
|
66
|
+
@data.key?(key) ? @data[key] : @defaults[key]
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
###############################################
|
71
|
+
# Set a value
|
72
|
+
#
|
73
|
+
# @param key [String] The name of the config setting
|
74
|
+
# @param val [Object] The value of the config setting
|
75
|
+
#
|
76
|
+
def set(key, val)
|
77
|
+
@data[key] = val
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
###############################################
|
82
|
+
# Where to store objects
|
83
|
+
#
|
84
|
+
def _key(unam)
|
85
|
+
@pre + unam
|
86
|
+
end # def _key()
|
87
|
+
private :_key
|
88
|
+
|
89
|
+
|
90
|
+
###############################################
|
91
|
+
# Load a user configuration
|
92
|
+
#
|
93
|
+
# @param unam [String] the user name to load
|
94
|
+
# @return [Boolean] if any config data was found for the user
|
95
|
+
#
|
96
|
+
def load(unam); raise NotImplementedError; end
|
97
|
+
|
98
|
+
|
99
|
+
###############################################
|
100
|
+
# Save a user configuration
|
101
|
+
#
|
102
|
+
def save; raise NotImplementedError; end
|
103
|
+
|
104
|
+
|
105
|
+
end # class ICFS::Web::Config
|
106
|
+
|
107
|
+
end # module ICFS::Web
|
108
|
+
end # module ICFS
|
@@ -0,0 +1,78 @@
|
|
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
|
+
require_relative 'config'
|
13
|
+
|
14
|
+
module ICFS
|
15
|
+
module Web
|
16
|
+
|
17
|
+
##########################################################################
|
18
|
+
# Implement Config with a Redis cache
|
19
|
+
#
|
20
|
+
class ConfigRedis < Config
|
21
|
+
|
22
|
+
|
23
|
+
###############################################
|
24
|
+
# New instance
|
25
|
+
#
|
26
|
+
# @param redis [Redis] The redis client
|
27
|
+
# @param base [Config] The base Config store
|
28
|
+
# @param opts [Hash] Options
|
29
|
+
# @option opts [String] :prefix Prefix for Redis key
|
30
|
+
# @option opts [Integer] :expires Expiration time in seconds
|
31
|
+
#
|
32
|
+
def initialize(redis, base, opts={})
|
33
|
+
super(base.defaults)
|
34
|
+
@redis = redis
|
35
|
+
@base = base
|
36
|
+
@pre = opts[:prefix] || ''.freeze
|
37
|
+
@exp = opts[:expires] || 1*60*60 # 1 hour default
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
###############################################
|
42
|
+
# (see Config#load)
|
43
|
+
#
|
44
|
+
def load(unam)
|
45
|
+
Items.validate(unam, 'User/Role/Group name'.freeze, Items::FieldUsergrp)
|
46
|
+
@unam = unam.dup
|
47
|
+
key = _key(unam)
|
48
|
+
|
49
|
+
# try cache
|
50
|
+
json = @redis.get(key)
|
51
|
+
if json
|
52
|
+
@data = Items.parse(json, 'Config values'.freeze, Config::ValConfig)
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
|
56
|
+
# get base object
|
57
|
+
succ = @base.load(unam)
|
58
|
+
@data = @base.data
|
59
|
+
return succ
|
60
|
+
end # def load()
|
61
|
+
|
62
|
+
|
63
|
+
###############################################
|
64
|
+
# (see Config#save)
|
65
|
+
#
|
66
|
+
def save()
|
67
|
+
raise(RuntimeError, 'Save requires a user name'.freeze) if !@unam
|
68
|
+
json = Items.generate(@data, 'Config values'.freeze, Config::ValConfig)
|
69
|
+
@redis.del(_key(@unam))
|
70
|
+
@base.data = @data
|
71
|
+
@base.save
|
72
|
+
end # def save()
|
73
|
+
|
74
|
+
|
75
|
+
end # class ICFS::Web::Config
|
76
|
+
|
77
|
+
end # module ICFS::Web
|
78
|
+
end # module ICFS
|
@@ -0,0 +1,66 @@
|
|
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
|
+
require_relative 'config'
|
13
|
+
|
14
|
+
module ICFS
|
15
|
+
module Web
|
16
|
+
|
17
|
+
##########################################################################
|
18
|
+
# Configuration storage implemented in S3
|
19
|
+
#
|
20
|
+
class ConfigS3 < Config
|
21
|
+
|
22
|
+
|
23
|
+
###############################################
|
24
|
+
# New instance
|
25
|
+
#
|
26
|
+
# @param defaults [Hash] The default options
|
27
|
+
# @param s3 [Aws::S3::Client] the configured S3 client
|
28
|
+
# @param bucket [String] The bucket name
|
29
|
+
# @param prefix [String] Prefix to use for object keys
|
30
|
+
#
|
31
|
+
def initialize(defaults, s3, bucket, prefix=nil)
|
32
|
+
super(defaults)
|
33
|
+
@s3 = s3
|
34
|
+
@bck = bucket
|
35
|
+
@pre = prefix || ''.freeze
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
###############################################
|
40
|
+
# (see Config#load)
|
41
|
+
#
|
42
|
+
def load(unam)
|
43
|
+
Items.validate(unam, 'User/Role/Group name'.freeze, Items::FieldUsergrp)
|
44
|
+
@unam = unam.dup
|
45
|
+
json = @s3.get_object( bucket: @bck, key: _key(unam) ).body.read
|
46
|
+
@data = Items.parse(json, 'Config values'.freeze, Config::ValConfig)
|
47
|
+
return true
|
48
|
+
rescue
|
49
|
+
@data = {}
|
50
|
+
return false
|
51
|
+
end # def load()
|
52
|
+
|
53
|
+
|
54
|
+
###############################################
|
55
|
+
# (see Config#save)
|
56
|
+
#
|
57
|
+
def save()
|
58
|
+
raise(RuntimeError, 'Save requires a user name'.freeze) if !@unam
|
59
|
+
json = Items.generate(@data, 'Config values'.freeze, Config::ValConfig)
|
60
|
+
@s3.put_object( bucket: @bck, key: _key(@unam), body: json )
|
61
|
+
end # def save()
|
62
|
+
|
63
|
+
end # class ICFS::Web::ConfigS3
|
64
|
+
|
65
|
+
end # module ICFS::Web
|
66
|
+
end # module ICFS
|
data/lib/icfs.rb
CHANGED
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.
|
4
|
+
version: 0.1.2
|
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-
|
11
|
+
date: 2019-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2-
|
14
14
|
|
@@ -29,7 +29,6 @@ files:
|
|
29
29
|
- bin/icfs_demo_fcgi.rb
|
30
30
|
- bin/icfs_demo_ssl_gen.rb
|
31
31
|
- bin/icfs_demo_web.rb
|
32
|
-
- bin/icfs_dev_todo.rb
|
33
32
|
- data/demo_config.yml
|
34
33
|
- data/docker/build-web.sh
|
35
34
|
- data/docker/compose-demo.yml
|
@@ -42,6 +41,17 @@ files:
|
|
42
41
|
- data/docker/nginx.conf
|
43
42
|
- data/icfs.css
|
44
43
|
- data/icfs.js
|
44
|
+
- devel/create.sh
|
45
|
+
- devel/elastic.sh
|
46
|
+
- 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
|
45
55
|
- lib/icfs.rb
|
46
56
|
- lib/icfs/api.rb
|
47
57
|
- lib/icfs/cache.rb
|
@@ -55,13 +65,17 @@ files:
|
|
55
65
|
- lib/icfs/store_fs.rb
|
56
66
|
- lib/icfs/store_s3.rb
|
57
67
|
- lib/icfs/users.rb
|
58
|
-
- lib/icfs/users_elastic.rb
|
59
68
|
- lib/icfs/users_fs.rb
|
69
|
+
- lib/icfs/users_redis.rb
|
70
|
+
- lib/icfs/users_s3.rb
|
60
71
|
- lib/icfs/utils/backup.rb
|
61
72
|
- lib/icfs/utils/check.rb
|
62
73
|
- lib/icfs/validate.rb
|
63
74
|
- lib/icfs/web/auth_ssl.rb
|
64
75
|
- lib/icfs/web/client.rb
|
76
|
+
- lib/icfs/web/config.rb
|
77
|
+
- lib/icfs/web/config_redis.rb
|
78
|
+
- lib/icfs/web/config_s3.rb
|
65
79
|
homepage: https://github.com/g4field/icfs
|
66
80
|
licenses:
|
67
81
|
- GPL-3.0
|
data/lib/icfs/users_elastic.rb
DELETED
@@ -1,168 +0,0 @@
|
|
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
|
-
require 'set'
|
13
|
-
require_relative 'elastic'
|
14
|
-
|
15
|
-
module ICFS
|
16
|
-
|
17
|
-
##########################################################################
|
18
|
-
# Implements {ICFS::Users Users} using Elasticsearch to cache
|
19
|
-
# details from another {ICFS::Users Users} instance.
|
20
|
-
#
|
21
|
-
# @todo Add logging
|
22
|
-
#
|
23
|
-
class UsersElastic < Users
|
24
|
-
|
25
|
-
include Elastic
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
###############################################
|
30
|
-
# The ES mappings for the indexes
|
31
|
-
#
|
32
|
-
Maps = {
|
33
|
-
:users => '{
|
34
|
-
"mappings": { "_doc": { "properties": {
|
35
|
-
"name": { "type": "text" },
|
36
|
-
"type": { "type": "keyword" },
|
37
|
-
"roles": { "type": "keyword" },
|
38
|
-
"groups": { "type": "keyword" },
|
39
|
-
"perms": { "type": "keyword" },
|
40
|
-
"first": { "enabled": false },
|
41
|
-
"last": { "type": "date", "format": "epoch_second" },
|
42
|
-
"active": { "type": "boolean" }
|
43
|
-
}}}
|
44
|
-
}'.freeze,
|
45
|
-
}.freeze
|
46
|
-
|
47
|
-
public
|
48
|
-
|
49
|
-
###############################################
|
50
|
-
# New instance
|
51
|
-
#
|
52
|
-
# @param map [Hash] Symbol to String of the indexes.
|
53
|
-
# Must provide :user
|
54
|
-
# @param es [Faraday] Faraday instance to the Elasticsearch cluster
|
55
|
-
# @param src [Users] Source of authoritative information
|
56
|
-
# @param exp [Integer] Maximum time to cache a response
|
57
|
-
#
|
58
|
-
def initialize(map, es, src, exp=3600)
|
59
|
-
@map = map
|
60
|
-
@es = es
|
61
|
-
@src = src
|
62
|
-
@exp = exp
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
###############################################
|
67
|
-
# Validate a user
|
68
|
-
#
|
69
|
-
ValUserCache = {
|
70
|
-
method: :hash,
|
71
|
-
required: {
|
72
|
-
'name' => Items::FieldUsergrp,
|
73
|
-
'type' => {
|
74
|
-
method: :string,
|
75
|
-
allowed: Set[
|
76
|
-
'user'.freeze,
|
77
|
-
'role'.freeze,
|
78
|
-
'group'.freeze,
|
79
|
-
].freeze
|
80
|
-
}.freeze,
|
81
|
-
'first' => Validate::IsIntPos,
|
82
|
-
'last' => Validate::IsIntPos,
|
83
|
-
'active' => Validate::IsBoolean,
|
84
|
-
}.freeze,
|
85
|
-
optional: {
|
86
|
-
'roles' => {
|
87
|
-
method: :array,
|
88
|
-
check: Items::FieldUsergrp,
|
89
|
-
uniq: true
|
90
|
-
}.freeze,
|
91
|
-
'groups' => {
|
92
|
-
method: :array,
|
93
|
-
check: Items::FieldUsergrp,
|
94
|
-
uniq: true
|
95
|
-
}.freeze,
|
96
|
-
'perms' => {
|
97
|
-
method: :array,
|
98
|
-
check: Items::FieldPermGlobal,
|
99
|
-
uniq: true
|
100
|
-
}.freeze
|
101
|
-
}.freeze
|
102
|
-
}.freeze
|
103
|
-
|
104
|
-
|
105
|
-
###############################################
|
106
|
-
# (see Users#read)
|
107
|
-
#
|
108
|
-
def read(urg)
|
109
|
-
json = _read(:users, urg)
|
110
|
-
now = Time.now.to_i
|
111
|
-
|
112
|
-
# not in the cache
|
113
|
-
if !json
|
114
|
-
|
115
|
-
# read from source
|
116
|
-
obj = @src.read(urg)
|
117
|
-
return nil if !obj
|
118
|
-
|
119
|
-
# first time
|
120
|
-
obj['first'] = now
|
121
|
-
obj['last'] = now
|
122
|
-
obj['active'] = true
|
123
|
-
|
124
|
-
# store in cache
|
125
|
-
json = Items.generate(obj, 'User/Role/Group'.freeze, ValUserCache)
|
126
|
-
_write(:users, urg, json)
|
127
|
-
|
128
|
-
# use cached version
|
129
|
-
else
|
130
|
-
obj = Items.parse(json, 'User/Role/Group'.freeze, ValUserCache)
|
131
|
-
end
|
132
|
-
|
133
|
-
# expired
|
134
|
-
if (obj['last'] + @exp) < now
|
135
|
-
|
136
|
-
# read from source
|
137
|
-
obj2 = @src.read(urg)
|
138
|
-
|
139
|
-
# update
|
140
|
-
if obj2
|
141
|
-
obj['active'] = true
|
142
|
-
obj['roles'] = obj2['roles']
|
143
|
-
obj['groups'] = obj2['groups']
|
144
|
-
obj['perms'] = obj2['perms']
|
145
|
-
else
|
146
|
-
obj['active'] = false
|
147
|
-
end
|
148
|
-
obj['last'] = now
|
149
|
-
|
150
|
-
# and store in cache
|
151
|
-
json = Items.generate(obj, 'User/Role/Group'.freeze, ValUserCache)
|
152
|
-
_write(:users, urg, json)
|
153
|
-
end
|
154
|
-
|
155
|
-
# not active
|
156
|
-
return nil unless obj['active']
|
157
|
-
|
158
|
-
# clean out cached info
|
159
|
-
obj.delete('first'.freeze)
|
160
|
-
obj.delete('last'.freeze)
|
161
|
-
obj.delete('active'.freeze)
|
162
|
-
|
163
|
-
return obj
|
164
|
-
end # def read()
|
165
|
-
|
166
|
-
end # class ICFS::Users
|
167
|
-
|
168
|
-
end # module ICFS
|