proxes 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +24 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +12 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +18 -0
  8. data/Gemfile +4 -0
  9. data/Gemfile.ci +15 -0
  10. data/Gemfile.dev +10 -0
  11. data/Gemfile.dev.lock +155 -0
  12. data/LICENSE.txt +8 -0
  13. data/README.md +83 -0
  14. data/Rakefile +9 -0
  15. data/Vagrantfile +46 -0
  16. data/bin/console +15 -0
  17. data/bin/setup +8 -0
  18. data/config.ru +64 -0
  19. data/config/logger.yml +3 -0
  20. data/gulpfile.js +80 -0
  21. data/lib/proxes.rb +3 -0
  22. data/lib/proxes/app.rb +48 -0
  23. data/lib/proxes/controllers/application.rb +53 -0
  24. data/lib/proxes/controllers/audit_logs.rb +34 -0
  25. data/lib/proxes/controllers/auth_identity.rb +21 -0
  26. data/lib/proxes/controllers/component.rb +108 -0
  27. data/lib/proxes/controllers/permissions.rb +10 -0
  28. data/lib/proxes/controllers/roles.rb +10 -0
  29. data/lib/proxes/controllers/users.rb +119 -0
  30. data/lib/proxes/db.rb +17 -0
  31. data/lib/proxes/helpers/authentication.rb +45 -0
  32. data/lib/proxes/helpers/component.rb +40 -0
  33. data/lib/proxes/helpers/indices.rb +16 -0
  34. data/lib/proxes/helpers/pundit.rb +39 -0
  35. data/lib/proxes/helpers/views.rb +41 -0
  36. data/lib/proxes/loggers/elasticsearch.rb +9 -0
  37. data/lib/proxes/models/audit_log.rb +12 -0
  38. data/lib/proxes/models/identity.rb +67 -0
  39. data/lib/proxes/models/permission.rb +17 -0
  40. data/lib/proxes/models/role.rb +14 -0
  41. data/lib/proxes/models/user.rb +57 -0
  42. data/lib/proxes/policies/application_policy.rb +20 -0
  43. data/lib/proxes/policies/audit_log_policy.rb +40 -0
  44. data/lib/proxes/policies/identity_policy.rb +24 -0
  45. data/lib/proxes/policies/permission_policy.rb +40 -0
  46. data/lib/proxes/policies/request/root_policy.rb +12 -0
  47. data/lib/proxes/policies/request/search_policy.rb +15 -0
  48. data/lib/proxes/policies/request/snapshot_policy.rb +12 -0
  49. data/lib/proxes/policies/request/stats_policy.rb +15 -0
  50. data/lib/proxes/policies/request_policy.rb +69 -0
  51. data/lib/proxes/policies/role_policy.rb +40 -0
  52. data/lib/proxes/policies/token_policy.rb +46 -0
  53. data/lib/proxes/policies/user_policy.rb +46 -0
  54. data/lib/proxes/rake_tasks.rb +59 -0
  55. data/lib/proxes/request.rb +51 -0
  56. data/lib/proxes/request/root.rb +10 -0
  57. data/lib/proxes/request/search.rb +37 -0
  58. data/lib/proxes/request/snapshot.rb +16 -0
  59. data/lib/proxes/request/stats.rb +30 -0
  60. data/lib/proxes/security.rb +59 -0
  61. data/lib/proxes/seed.rb +10 -0
  62. data/lib/proxes/services/logger.rb +50 -0
  63. data/lib/proxes/version.rb +4 -0
  64. data/migrate/001_tables.rb +47 -0
  65. data/migrate/002_audit_log.rb +11 -0
  66. data/package.json +34 -0
  67. data/proxes.gemspec +44 -0
  68. data/public/js/bundle.js +28988 -0
  69. data/src/scripts/app.js +10 -0
  70. data/views/404.haml +1 -0
  71. data/views/audit_logs/index.haml +18 -0
  72. data/views/error.haml +4 -0
  73. data/views/getting_started.haml +16 -0
  74. data/views/identity/login.haml +19 -0
  75. data/views/identity/register.haml +17 -0
  76. data/views/index.haml +3 -0
  77. data/views/layout.haml +48 -0
  78. data/views/partials/delete_form.haml +4 -0
  79. data/views/partials/form_control.haml +21 -0
  80. data/views/partials/navbar.haml +25 -0
  81. data/views/partials/notifications.haml +24 -0
  82. data/views/partials/pager.haml +19 -0
  83. data/views/partials/sidebar.haml +32 -0
  84. data/views/permissions/display.haml +24 -0
  85. data/views/permissions/edit.haml +11 -0
  86. data/views/permissions/form.haml +3 -0
  87. data/views/permissions/index.haml +14 -0
  88. data/views/permissions/new.haml +10 -0
  89. data/views/roles/display.haml +33 -0
  90. data/views/roles/edit.haml +11 -0
  91. data/views/roles/form.haml +1 -0
  92. data/views/roles/index.haml +17 -0
  93. data/views/roles/new.haml +10 -0
  94. data/views/users/display.haml +32 -0
  95. data/views/users/edit.haml +11 -0
  96. data/views/users/identity.haml +3 -0
  97. data/views/users/index.haml +20 -0
  98. data/views/users/new.haml +11 -0
  99. data/views/users/profile.haml +37 -0
  100. data/views/users/user.haml +3 -0
  101. metadata +424 -0
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ require 'rake'
3
+ require 'rake/tasklib'
4
+
5
+ module ProxES
6
+ class Tasks < ::Rake::TaskLib
7
+ include ::Rake::DSL if defined?(::Rake::DSL)
8
+
9
+ def install_tasks
10
+ namespace :proxes do
11
+ desc 'Generate the needed tokens'
12
+ task :generate_tokens do
13
+ require 'securerandom'
14
+ File.write('.session_secret', SecureRandom.random_bytes(40))
15
+ File.write('.token_secret', SecureRandom.random_bytes(40))
16
+ end
17
+
18
+ desc 'Seed the database'
19
+ task :seed do
20
+ require 'proxes/seed'
21
+ end
22
+
23
+ desc 'Migrate ProxES database to latest version'
24
+ task :migrate do
25
+ Rake::Task['proxes:migrate:up'].invoke
26
+ end
27
+
28
+ namespace :migrate do
29
+ require_relative './db'
30
+ Sequel.extension :migration
31
+ folder = File.expand_path(File.dirname(__FILE__) + '/../../migrate')
32
+
33
+ desc 'Check if the migration is current'
34
+ task :check do
35
+ Sequel::Migrator.check_current(DB, folder)
36
+ end
37
+
38
+ desc 'Migrate ProxES database to latest version'
39
+ task :up do
40
+ Sequel::Migrator.apply(DB, folder)
41
+ end
42
+
43
+ desc 'Roll back the ProxES database'
44
+ task :down do
45
+ Sequel::Migrator.apply(DB, folder, 0)
46
+ end
47
+
48
+ desc 'Reset the ProxES database'
49
+ task :bounce do
50
+ Sequel::Migrator.apply(DB, folder, 0)
51
+ Sequel::Migrator.apply(DB, folder)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ ProxES::Tasks.new.install_tasks
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ require 'rack'
3
+
4
+ module ProxES
5
+ class Request < Rack::Request
6
+ def self.from_env(env)
7
+ request = Rack::Request.new(env)
8
+ splits = request.path.split('/')
9
+ endpoint = if splits[1] && splits[1][0] == '_'
10
+ splits[1][1..-1].titlecase
11
+ else
12
+ splits.count > 0 ? splits[-1][1..-1].titlecase : 'Root'
13
+ end
14
+ begin
15
+ require 'proxes/request/' + endpoint.downcase
16
+ ProxES::Request.const_get(endpoint).new(env)
17
+ rescue LoadError
18
+ self.new(env)
19
+ end
20
+ end
21
+
22
+ def initialize(env)
23
+ super
24
+ parse
25
+ end
26
+
27
+ def endpoint
28
+ path_parts[0]
29
+ end
30
+
31
+ def parse
32
+ path_parts
33
+ end
34
+
35
+ def indices?
36
+ false
37
+ end
38
+
39
+ private
40
+
41
+ def path_parts
42
+ @path_parts ||= path[1..-1].split('/')
43
+ end
44
+
45
+ def check_part(val)
46
+ return val if val.nil?
47
+ return [] if [endpoint, '_all'].include? val
48
+ val.split(',')
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ require 'rack'
3
+ require 'proxes/request'
4
+
5
+ module ProxES
6
+ class Request
7
+ class Root < ProxES::Request
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ require 'rack'
3
+ require 'proxes/request'
4
+
5
+ module ProxES
6
+ class Request
7
+ class Search < ProxES::Request
8
+ attr_reader :index, :type
9
+ attr_reader :type
10
+
11
+ def index=(idx)
12
+ @index = idx
13
+ self.path_info = '/' + [ index, type, id, endpoint ]
14
+ .map { |v| v.is_a?(Array) ? v.join(',') : v }
15
+ .select { |v| !v.nil? && v != '' }.join('/')
16
+ end
17
+
18
+ def endpoint
19
+ '_search'
20
+ end
21
+
22
+ def parse
23
+ @index ||= check_part(path_parts[0])
24
+ @type ||= check_part(path_parts[1])
25
+ @id ||= check_part(path_parts[2])
26
+ end
27
+
28
+ def id
29
+ @id == [] ? nil : @id
30
+ end
31
+
32
+ def indices?
33
+ true
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ require 'rack'
3
+ require 'proxes/request'
4
+
5
+ module ProxES
6
+ class Request
7
+ class Snapshot < ProxES::Request
8
+ attr_reader :repository
9
+
10
+ def parse
11
+ @repository ||= check_part(path_parts[1])
12
+ @repository = [] if repository.nil?
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ require 'rack'
3
+ require 'proxes/request'
4
+
5
+ module ProxES
6
+ class Request
7
+ class Stats < ProxES::Request
8
+ attr_reader :index
9
+
10
+ def index=(idx)
11
+ @index = idx
12
+ self.path_info = '/' + [ index, endpoint ]
13
+ .map { |v| v.is_a?(Array) ? v.join(',') : v }
14
+ .select { |v| !v.nil? && v != '' }.join('/')
15
+ end
16
+
17
+ def endpoint
18
+ '_stats'
19
+ end
20
+
21
+ def parse
22
+ @index ||= check_part(path_parts[0])
23
+ end
24
+
25
+ def indices?
26
+ true
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ require 'proxes/services/logger'
3
+ require 'rack-proxy'
4
+ require 'proxes/request'
5
+ require 'proxes/policies/request_policy'
6
+ require 'proxes/helpers/pundit'
7
+ require 'proxes/helpers/authentication'
8
+ require 'proxes/services/logger'
9
+
10
+ module ProxES
11
+ class Security
12
+ attr_reader :env, :logger
13
+
14
+ include ProxES::Helpers::Authentication
15
+ include ProxES::Helpers::Pundit
16
+
17
+ def initialize(app, logger = nil)
18
+ @app = app
19
+ @logger = logger || ProxES::Services::Logger.instance
20
+ end
21
+
22
+ def error(message, code = 500)
23
+ [code, { 'Content-Type' => 'application/json' }, ['{"error":"' + message + '}']]
24
+ end
25
+
26
+ def call(env)
27
+ @env = env
28
+
29
+ request = ProxES::Request.from_env(env)
30
+
31
+ logger.debug '==========================BEFORE================================================'
32
+ logger.debug '= ' + "Request: #{request.fullpath}".ljust(76) + ' ='
33
+ logger.debug '= ' + "Endpoint: #{request.endpoint}".ljust(76) + ' ='
34
+ logger.debug '================================================================================'
35
+
36
+ begin
37
+ check_basic
38
+ authorize request
39
+ rescue StandardError => e
40
+ logger.debug "Access denied by security layer: #{e.message}"
41
+ return error 'Forbidden', 403
42
+ end
43
+ request.index = policy_scope(request) if request.indices?
44
+
45
+ logger.debug '==========================AFTER================================================='
46
+ logger.debug '= ' + "Request: #{request.fullpath}".ljust(76) + ' ='
47
+ logger.debug '= ' + "Endpoint: #{request.endpoint}".ljust(76) + ' ='
48
+ logger.debug '================================================================================'
49
+
50
+ begin
51
+ @app.call request.env
52
+ rescue Errno::EHOSTUNREACH
53
+ error 'Could not reach Elasticsearch at ' + ENV['ELASTICSEARCH_URL']
54
+ rescue Errno::ECONNREFUSED
55
+ error 'Elasticsearch not listening at ' + ENV['ELASTICSEARCH_URL']
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,10 @@
1
+ require 'proxes/db'
2
+ require 'proxes/models/role'
3
+ require 'proxes/models/permission'
4
+
5
+ ProxES::Role.find_or_create(name: 'user')
6
+ ProxES::Role.find_or_create(name: 'admin')
7
+ sa = ProxES::Role.find_or_create(name: 'super_admin')
8
+ %w(GET POST PUT DELETE HEAD OPTIONS).each do |verb|
9
+ ProxES::Permission.find_or_create(role: sa, verb: verb, pattern: '.*')
10
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ require 'logger'
3
+ require 'yaml'
4
+ require 'singleton'
5
+ require 'active_support/inflector'
6
+ require 'proxes/loggers/elasticsearch'
7
+
8
+ # ProxES::Services::Logger.instance
9
+
10
+ module ProxES
11
+ module Services
12
+ class Logger
13
+ include Singleton
14
+
15
+ CONFIG = './config/logger.yml'
16
+ attr_reader :loggers
17
+
18
+ def initialize
19
+ @loggers = []
20
+ config.each do |values|
21
+ klass = values['class'].constantize
22
+ opts = values['options'] || nil
23
+ logger = klass.new(opts)
24
+ if values['level']
25
+ logger.level = klass.const_get(values['level'].to_sym)
26
+ end
27
+ @loggers << logger
28
+ end
29
+ end
30
+
31
+ def method_missing(method, *args, &block)
32
+ loggers.each { |logger| logger.send(method, *args, &block) }
33
+ end
34
+
35
+ def respond_to_missing?(method, include_private = false)
36
+ loggers.any? { |logger| logger.respond_to?(method) }
37
+ end
38
+
39
+ private
40
+
41
+ def config
42
+ @config ||= File.exist?(CONFIG) ? YAML.load_file(CONFIG) : default
43
+ end
44
+
45
+ def default
46
+ [{ 'name' => 'default', 'class' => 'Logger' }]
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ module ProxES
3
+ VERSION = '0.1.0'
4
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+ Sequel.migration do
3
+ change do
4
+ create_table :users do
5
+ primary_key :id
6
+ String :name
7
+ String :surname
8
+ String :email
9
+ DateTime :created_at
10
+ DateTime :updated_at
11
+ unique [:email]
12
+ end
13
+
14
+ create_table :identities do
15
+ primary_key :id
16
+ foreign_key :user_id, :users
17
+ String :username
18
+ String :crypted_password
19
+ DateTime :created_at
20
+ DateTime :updated_at
21
+ unique [:username]
22
+ end
23
+
24
+ create_table :roles do
25
+ primary_key :id
26
+ String :name
27
+ DateTime :created_at
28
+ DateTime :updated_at
29
+ unique [:name]
30
+ end
31
+
32
+ create_table :permissions do
33
+ primary_key :id
34
+ String :verb
35
+ String :pattern
36
+ DateTime :created_at
37
+ foreign_key :role_id, :roles
38
+ end
39
+
40
+ create_table :roles_users do
41
+ DateTime :created_at
42
+ foreign_key :user_id, :users
43
+ foreign_key :role_id, :roles
44
+ unique [:user_id, :role_id]
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ Sequel.migration do
3
+ change do
4
+ create_table :audit_logs do
5
+ primary_key :id
6
+ foreign_key :user_id, :users
7
+ String :action
8
+ DateTime :created_at
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "proxes",
3
+ "version": "0.1.0",
4
+ "description": "Elasticsearch Management System",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/EagerELK/proxes.git"
8
+ },
9
+ "author": "Jurgens du Toit",
10
+ "license": "LGPL-3.0",
11
+ "bugs": {
12
+ "url": "https://github.com/EagerELK/proxes/issues"
13
+ },
14
+ "homepage": "https://github.com/EagerELK/proxes#readme",
15
+ "dependencies": {
16
+ "body-parser": "^1.4.3",
17
+ "express": "^4.4.5",
18
+ "gulp-connect": "^5.0.0",
19
+ "jquery": "^3.1.0",
20
+ "numeral": "^1.5.3",
21
+ "react": "^15.2.1",
22
+ "react-dom": "^15.2.1",
23
+ "react-proxes-components": "^0.2.2"
24
+ },
25
+ "devDependencies": {
26
+ "babel-preset-es2015": "^6.9.0",
27
+ "babel-preset-react": "^6.11.1",
28
+ "babelify": "^7.3.0",
29
+ "browserify": "^13.1.0",
30
+ "gulp": "^3.9.1",
31
+ "gulp-util": "^3.0.7",
32
+ "vinyl-source-stream": "^1.1.0"
33
+ }
34
+ }
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'proxes/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'proxes'
9
+ spec.version = ProxES::VERSION
10
+ spec.authors = ['Jurgens du Toit']
11
+ spec.email = ['jrgns@jadeit.co.za']
12
+
13
+ spec.summary = 'Rack wrapper around Elasticsearch to provide security and management features'
14
+ spec.description = 'Rack wrapper around Elasticsearch to provide security and management features'
15
+ spec.homepage = 'https://github.com/eagerelk/proxes'
16
+ spec.license = 'LGPLv3'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.12'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ spec.add_development_dependency 'rspec', '~> 3.0'
26
+ spec.add_development_dependency 'racksh'
27
+ spec.add_development_dependency 'rack-test'
28
+ spec.add_development_dependency 'database_cleaner'
29
+ spec.add_development_dependency 'factory_girl'
30
+
31
+ spec.add_dependency 'rack-proxy'
32
+ spec.add_dependency 'sinatra'
33
+ spec.add_dependency 'sinatra-flash'
34
+ spec.add_dependency 'sinatra-contrib'
35
+ spec.add_dependency 'elasticsearch'
36
+ spec.add_dependency 'logger'
37
+ spec.add_dependency 'pundit'
38
+ spec.add_dependency 'sequel'
39
+ spec.add_dependency 'bcrypt'
40
+ spec.add_dependency 'omniauth'
41
+ spec.add_dependency 'omniauth-identity'
42
+ spec.add_dependency 'haml'
43
+ spec.add_dependency 'tilt', '>= 2'
44
+ end