icfs 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/bin/icfs_demo_fcgi.rb +2 -0
  3. data/{bin/icfs_demo_ssl_gen.rb → devel/demo/ssl_gen.rb} +25 -13
  4. data/devel/demo/ssl_gen.yml +14 -0
  5. data/devel/icfs-wrk/Dockerfile +1 -1
  6. data/devel/run/base.rb +92 -0
  7. data/devel/run/copy-s3.rb +2 -0
  8. data/devel/run/email.rb +36 -0
  9. data/devel/run/email_imap.rb +43 -0
  10. data/devel/run/email_smime.rb +47 -0
  11. data/devel/run/init-icfs.rb +2 -0
  12. data/devel/run/webrick.rb +5 -57
  13. data/lib/icfs/api.rb +101 -90
  14. data/lib/icfs/cache.rb +2 -0
  15. data/lib/icfs/cache_elastic.rb +127 -125
  16. data/lib/icfs/{web/config.rb → config.rb} +3 -3
  17. data/lib/icfs/{web/config_redis.rb → config_redis.rb} +8 -8
  18. data/lib/icfs/{web/config_s3.rb → config_s3.rb} +8 -8
  19. data/lib/icfs/demo/auth.rb +5 -7
  20. data/lib/icfs/demo/static.rb +2 -0
  21. data/lib/icfs/elastic.rb +10 -8
  22. data/lib/icfs/email/basic.rb +242 -0
  23. data/lib/icfs/email/core.rb +293 -0
  24. data/lib/icfs/email/from.rb +52 -0
  25. data/lib/icfs/email/imap.rb +148 -0
  26. data/lib/icfs/email/smime.rb +139 -0
  27. data/lib/icfs/items.rb +5 -3
  28. data/lib/icfs/store.rb +20 -18
  29. data/lib/icfs/store_fs.rb +7 -5
  30. data/lib/icfs/store_s3.rb +4 -2
  31. data/lib/icfs/users.rb +5 -3
  32. data/lib/icfs/users_fs.rb +8 -6
  33. data/lib/icfs/users_redis.rb +12 -10
  34. data/lib/icfs/users_s3.rb +6 -4
  35. data/lib/icfs/utils/backup.rb +30 -29
  36. data/lib/icfs/utils/check.rb +36 -34
  37. data/lib/icfs/validate.rb +24 -15
  38. data/lib/icfs/web/auth_ssl.rb +7 -9
  39. data/lib/icfs/web/client.rb +671 -679
  40. data/lib/icfs.rb +174 -10
  41. metadata +16 -7
  42. data/devel/devel-webrick.yml +0 -49
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c6508e2169aa8ab7a2567c545e793c5f3af51a6b7d3426d7763ba148f1c2b71
4
- data.tar.gz: fc121b8053444a4757d7c9a1d1247a691baa8217aecf7963ba0ba1ffcc4ca358
3
+ metadata.gz: 28031e9c5c67e30c2cf4778fbf56a7840117d256e4384e6e044e7cc888958d09
4
+ data.tar.gz: 3abea632e084b00bd09ac570710eab52e99a152d073c6f96779a04c23dbc1c21
5
5
  SHA512:
6
- metadata.gz: bf90379adfeeb08e1cc1f8371eeb813d4259e187094b331f12d6232b6a10855044f0be14db531722b037b4a18c5c63be9830a13d24b443db4c98f1e62b8aaf25
7
- data.tar.gz: d307474f2ae62e6b5f1da6d9128bccc122088e8e0bee1ee3f50f6ad3895906ce9c9136c5f9df39d812c9ea0a85309ed5ac897398097523bf1edfb51f04f633d0
6
+ metadata.gz: cd28dc30f59e5bec1b272508d5b64ecb950a3e2b6d26d4318156069d19c338093177302ac09207a4b76b7decfa8272f84a8839f3165eeee28fdb9f15ae5c6ef3
7
+ data.tar.gz: '08f19a62a3d3c21cdf46c8120bd0b5846107a57409aba71939587affed4e7daf32c4d0bd805919d884baa4d24b520521527f62e8edf66ed6f886cf2237122b27'
@@ -10,6 +10,8 @@
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
+ # frozen_string_literal: true
14
+
13
15
  require 'yaml'
14
16
  require 'faraday'
15
17
 
@@ -10,15 +10,23 @@
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
+ # frozen_string_literal: true
14
+
13
15
  require 'openssl'
16
+ require 'yaml'
17
+
18
+ # read the configuration
19
+ cfg = YAML.load(File.read(ARGV[0]))
20
+
14
21
 
22
+ serial = Time.now.to_i
15
23
 
16
- # make a CA key
24
+ # make a CA cert
17
25
  ca_key = OpenSSL::PKey::RSA.new 2048
18
26
  ca_cert = OpenSSL::X509::Certificate.new
19
27
  ca_cert.version = 2
20
- ca_cert.serial = 1
21
- ca_cert.subject = OpenSSL::X509::Name.parse('/OU=org/OU=example/CN=Test Root CA')
28
+ ca_cert.serial = serial
29
+ ca_cert.subject = OpenSSL::X509::Name.parse(cfg['ca']['cn'])
22
30
  ca_cert.issuer = ca_cert.subject
23
31
  ca_cert.public_key = ca_key.public_key
24
32
  ca_cert.not_before = Time.now
@@ -36,11 +44,11 @@ ca_cert.sign(ca_key, OpenSSL::Digest::SHA256.new)
36
44
  File.open("ca_cert.pem", "wb"){|fi| fi.write ca_cert.to_pem }
37
45
 
38
46
 
39
- # make a server key
47
+ # make a server cert & key
40
48
  srv_key = OpenSSL::PKey::RSA.new 2048
41
49
  srv_cert = OpenSSL::X509::Certificate.new
42
50
  srv_cert.version = 2
43
- srv_cert.serial = 2
51
+ srv_cert.serial = serial + 1
44
52
  srv_cert.subject = OpenSSL::X509::Name.parse('/OU=org/OU=example/OU=Test Server/CN=localhost')
45
53
  srv_cert.issuer = ca_cert.subject
46
54
  srv_cert.public_key = srv_key.public_key
@@ -52,19 +60,22 @@ ef.issuer_certificate = ca_cert
52
60
  srv_cert.add_extension(ef.create_extension("basicConstraints", "CA:FALSE"))
53
61
  srv_cert.add_extension(ef.create_extension("keyUsage", "keyEncipherment,dataEncipherment,digitalSignature"))
54
62
  srv_cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
63
+ srv_cert.add_extension(ef.create_extension("subjectAltName", "email:%s" % cfg['server']['email'], false))
55
64
  srv_cert.sign(ca_key, OpenSSL::Digest::SHA256.new)
56
65
 
57
- # save server key
66
+ # save server cert & key
58
67
  File.open("srv_cert.pem", "wb"){|fi| fi.write srv_cert.to_pem }
59
68
  File.open("srv_key.pem", "wb"){|fi| fi.write srv_key.to_pem }
60
69
 
61
- # make client certs
62
- 5.times do |ix|
70
+ # make client certs with key included
71
+ cnt = 0
72
+ cfg['clients'].each do |cc|
73
+ cnt += 1
63
74
  clt_key = OpenSSL::PKey::RSA.new 2048
64
75
  clt_cert = OpenSSL::X509::Certificate.new
65
76
  clt_cert.version = 2
66
- clt_cert.serial = ix+3
67
- clt_cert.subject = OpenSSL::X509::Name.parse('/OU=org/OU=example/OU=Test Client/CN=client %d' % ix)
77
+ clt_cert.serial = serial + 2 + cnt
78
+ clt_cert.subject = OpenSSL::X509::Name.parse(cc['cn'])
68
79
  clt_cert.issuer = ca_cert.subject
69
80
  clt_cert.public_key = clt_key.public_key
70
81
  clt_cert.not_before = Time.now
@@ -74,11 +85,12 @@ File.open("srv_key.pem", "wb"){|fi| fi.write srv_key.to_pem }
74
85
  ef.issuer_certificate = ca_cert
75
86
  clt_cert.add_extension(ef.create_extension("basicConstraints", "CA:FALSE"))
76
87
  clt_cert.add_extension(ef.create_extension("keyUsage", "keyEncipherment,dataEncipherment,digitalSignature"))
88
+ clt_cert.add_extension(ef.create_extension("subjectAltName", "email:%s" % cc['email'], false))
77
89
  clt_cert.sign(ca_key, OpenSSL::Digest::SHA256.new)
78
90
 
79
91
  # pkcs12
80
- clt_pkcs12 = OpenSSL::PKCS12.create('demo', 'client-%d' % ix, clt_key, clt_cert)
92
+ clt_pkcs12 = OpenSSL::PKCS12.create('demo', 'client-%d' % cnt, clt_key, clt_cert)
81
93
 
82
- # save cert
83
- File.open('clt_%d.pfx' % ix, 'wb'){|fi| fi.write clt_pkcs12.to_der }
94
+ # save cert w/key
95
+ File.open('clt_%d.pfx' % cnt, 'wb'){|fi| fi.write clt_pkcs12.to_der }
84
96
  end
@@ -0,0 +1,14 @@
1
+
2
+ ca:
3
+ cn: "/OU=org/OU=example/CN=Test Root CA"
4
+
5
+ server:
6
+ cn: "/OU=org/OU=example/OU=Test Server/CN=localhost"
7
+ email: "server@example.org"
8
+
9
+ clients:
10
+ - cn: "/OU=org/OU=example/OU=Test Client/CN=client 1"
11
+ email: "client1@example.org"
12
+
13
+ - cn: "/OU=org/OU=example/OU=Test Client/CN=client 2"
14
+ email: "client2example.org"
@@ -16,7 +16,7 @@ RUN apk update && \
16
16
  apk upgrade && \
17
17
  apk --update add ruby fcgi ruby-json tzdata vim curl git bash && \
18
18
  apk --update add --virtual build-deps ruby-dev build-base fcgi-dev && \
19
- gem install -N rack webrick etc faraday yard aws-sdk-s3 redis && \
19
+ gem install -N rack webrick etc faraday yard aws-sdk-s3 redis mail && \
20
20
  apk del build-deps && \
21
21
  rm -rf /var/cache/apk/*
22
22
 
data/devel/run/base.rb ADDED
@@ -0,0 +1,92 @@
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
+ # frozen_string_literal: true
14
+
15
+ require 'faraday'
16
+ require 'aws-sdk-s3'
17
+ require 'redis'
18
+
19
+ require_relative '../../lib/icfs'
20
+ require_relative '../../lib/icfs/cache_elastic'
21
+ require_relative '../../lib/icfs/store_s3'
22
+ require_relative '../../lib/icfs/users_s3'
23
+ require_relative '../../lib/icfs/users_redis'
24
+ require_relative '../../lib/icfs/config_s3'
25
+ require_relative '../../lib/icfs/config_redis'
26
+
27
+ #################################################
28
+ # Get the API
29
+ #
30
+ def get_base
31
+
32
+ # the log
33
+ log = Logger.new(STDERR)
34
+ log.level = Logger::INFO
35
+
36
+ # S3
37
+ s3 = Aws::S3::Client.new(
38
+ endpoint: 'http://minio:9000',
39
+ access_key_id: 'minio_key',
40
+ secret_access_key: 'minio_secret',
41
+ force_path_style: true,
42
+ region: 'us-east-1'
43
+ )
44
+
45
+ # redis
46
+ redis = Redis.new(host: 'redis')
47
+
48
+ # elasic
49
+ es = Faraday.new('http://elastic:9200')
50
+
51
+ # default mapping
52
+ map = {
53
+ entry: 'entry',
54
+ case: 'case',
55
+ action: 'action',
56
+ index: 'index',
57
+ log: 'log',
58
+ lock: 'lock',
59
+ current: 'current',
60
+ }.freeze
61
+
62
+ # default config
63
+ defaults = {
64
+ 'tz' => '-04:00'
65
+ }
66
+
67
+ # base objects
68
+ cache = ICFS::CacheElastic.new(map, es)
69
+ store = ICFS::StoreS3.new(s3, 'icfs', 'case/')
70
+ users_base = ICFS::UsersS3.new(s3, 'icfs', 'users/')
71
+ users = ICFS::UsersRedis.new(redis, users_base, {
72
+ prefix: 'users/',
73
+ expires: 60, # one minute cache for testing
74
+ log: log,
75
+ })
76
+ config_base = ICFS::ConfigS3.new(defaults, s3, 'icfs', 'config/')
77
+ config = ICFS::ConfigRedis.new(redis, config_base, {
78
+ prefix: 'config/',
79
+ expires: 60, # debug, only cache for one minute
80
+ })
81
+ api = ICFS::Api.new([], users, cache, store, config)
82
+
83
+ return {
84
+ cache: cache,
85
+ store: store,
86
+ users: users,
87
+ config: config,
88
+ api: api,
89
+ log: log,
90
+ }
91
+
92
+ end # def base
data/devel/run/copy-s3.rb CHANGED
@@ -10,6 +10,8 @@
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
+ # frozen_string_literal: true
14
+
13
15
  require 'aws-sdk-s3'
14
16
  require 'find'
15
17
 
@@ -0,0 +1,36 @@
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
+ # frozen_string_literal: true
14
+
15
+ require_relative 'base'
16
+ require_relative '../../lib/icfs/email/from'
17
+ require_relative '../../lib/icfs/email/basic'
18
+
19
+ # api
20
+ base = get_base
21
+ api = base[:api]
22
+ log = base[:log]
23
+ log.level = Logger::DEBUG
24
+
25
+ # load the email map
26
+ map_email = JSON.parse(File.read(ARGV[0]))
27
+
28
+ # email gateway
29
+ email_basic = ICFS::Email::Basic.new
30
+ email_from = ICFS::Email::From.new(map_email)
31
+ email = ICFS::Email::Core.new(api, log, [email_from, email_basic])
32
+
33
+ txt = STDIN.read
34
+ res = email.receive(txt)
35
+
36
+ p res
@@ -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
+ # frozen_string_literal: true
14
+
15
+ # <app> <email_map.json> <config.json>
16
+
17
+ require_relative 'base'
18
+ require_relative '../../lib/icfs/email/from'
19
+ require_relative '../../lib/icfs/email/basic'
20
+ require_relative '../../lib/icfs/email/imap'
21
+
22
+ # api
23
+ base = get_base
24
+ api = base[:api]
25
+ log = base[:log]
26
+ log.level = Logger::DEBUG
27
+
28
+ # load the email map
29
+ map_email = JSON.parse(File.read(ARGV[0]))
30
+
31
+ # load the IMAP config
32
+ cfg_raw = JSON.parse(File.read(ARGV[1]))
33
+ cfg = {}
34
+ cfg_raw.each{|key, val| cfg[key.to_sym] = val}
35
+
36
+ # email gateway
37
+ email_basic = ICFS::Email::Basic.new
38
+ email_from = ICFS::Email::From.new(map_email)
39
+ email = ICFS::Email::Core.new(api, log, [email_from, email_basic])
40
+ imap = ICFS::Email::Imap.new(email, log, cfg)
41
+
42
+ # and fetch
43
+ imap.reconnect
@@ -0,0 +1,47 @@
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
+ # <app> <srv_cert.pem> <srv_key.pem> <ca.pem> < <email.eml>
14
+
15
+ # frozen_string_literal: true
16
+
17
+ require_relative 'base'
18
+ require_relative '../../lib/icfs/email/smime'
19
+ require_relative '../../lib/icfs/email/basic'
20
+
21
+ # api
22
+ base = get_base
23
+ api = base[:api]
24
+ log = base[:log]
25
+ log.level = Logger::DEBUG
26
+
27
+ # load the email map
28
+ cert = ::OpenSSL::X509::Certificate.new(File.read(ARGV[0]))
29
+ key = ::OpenSSL::PKey.read(File.read(ARGV[1]))
30
+ ca = ::OpenSSL::X509::Store.new
31
+ ca.add_file(ARGV[2])
32
+
33
+ map_cn = {
34
+ 'CN=client 1,OU=Test Client,OU=example,OU=org' => 'user1',
35
+ 'CN=client 2,OU=Test Client,OU=example,OU=org' => 'user2',
36
+ 'CN=client 3,OU=Test Client,OU=example,OU=org' => 'user3',
37
+ }
38
+
39
+ # email gateway
40
+ email_basic = ICFS::Email::Basic.new
41
+ email_smime = ICFS::Email::Smime.new(key, cert, ca, map_cn)
42
+ email = ICFS::Email::Core.new(api, log, [email_smime, email_basic])
43
+
44
+ txt = STDIN.read
45
+ res = email.receive(txt)
46
+
47
+ p res
@@ -10,6 +10,8 @@
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
+ # frozen_string_literal: true
14
+
13
15
  require 'json'
14
16
  require 'faraday'
15
17
  require 'aws-sdk-s3'
data/devel/run/webrick.rb CHANGED
@@ -10,68 +10,16 @@
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 'faraday'
14
- require 'aws-sdk-s3'
15
- require 'redis'
13
+ # frozen_string_literal: true
16
14
 
17
- require_relative '../../lib/icfs'
18
- require_relative '../../lib/icfs/cache_elastic'
19
- require_relative '../../lib/icfs/store_s3'
20
- require_relative '../../lib/icfs/users_s3'
21
- require_relative '../../lib/icfs/users_redis'
15
+ require_relative 'base'
22
16
  require_relative '../../lib/icfs/web/client'
23
- require_relative '../../lib/icfs/web/config_s3'
24
- require_relative '../../lib/icfs/web/config_redis'
25
17
  require_relative '../../lib/icfs/demo/auth'
26
18
  require_relative '../../lib/icfs/demo/static'
27
19
 
28
- # Minio config
29
- Aws.config.update(
30
- endpoint: 'http://minio:9000',
31
- access_key_id: 'minio_key',
32
- secret_access_key: 'minio_secret',
33
- force_path_style: true,
34
- region: 'us-east-1'
35
- )
20
+ base = get_base()
21
+ api = base[:api]
36
22
 
37
- # default mapping
38
- map = {
39
- entry: 'entry',
40
- case: 'case',
41
- action: 'action',
42
- index: 'index',
43
- log: 'log',
44
- lock: 'lock',
45
- current: 'current',
46
- }.freeze
47
-
48
- # default config
49
- defaults = {
50
- 'tz' => '-04:00'
51
- }
52
-
53
- # the log
54
- log = Logger.new(STDERR)
55
- log.level = Logger::INFO
56
-
57
- # base items
58
- s3 = Aws::S3::Client.new
59
- redis = Redis.new(host: 'redis')
60
- es = Faraday.new('http://elastic:9200')
61
- cache = ICFS::CacheElastic.new(map, es)
62
- store = ICFS::StoreS3.new(s3, 'icfs'.freeze, 'case/'.freeze)
63
- users_base = ICFS::UsersS3.new(s3, 'icfs'.freeze, 'users/'.freeze)
64
- users = ICFS::UsersRedis.new(redis, users_base, {
65
- prefix: 'users/'.freeze,
66
- expires: 60, # one minute cache for testing
67
- log: log,
68
- })
69
- api = ICFS::Api.new([], users, cache, store)
70
- config_base = ICFS::Web::ConfigS3.new(defaults, s3, 'icfs', 'config/')
71
- config = ICFS::Web::ConfigRedis.new(redis, config_base, {
72
- prefix: 'config/',
73
- expires: 60, # debug, only cache for one minute
74
- })
75
23
  web = ICFS::Web::Client.new('/static/icfs.css', '/static/icfs.js')
76
24
 
77
25
  # static files
@@ -87,7 +35,7 @@ static = {
87
35
  }
88
36
 
89
37
  app = Rack::Builder.new do
90
- use(ICFS::Demo::Auth, api, config)
38
+ use(ICFS::Demo::Auth, api)
91
39
  use(ICFS::Demo::Static, static)
92
40
  run web
93
41
  end