proxes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +24 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.rubocop.yml +12 -0
- data/.ruby-version +1 -0
- data/.travis.yml +18 -0
- data/Gemfile +4 -0
- data/Gemfile.ci +15 -0
- data/Gemfile.dev +10 -0
- data/Gemfile.dev.lock +155 -0
- data/LICENSE.txt +8 -0
- data/README.md +83 -0
- data/Rakefile +9 -0
- data/Vagrantfile +46 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/config.ru +64 -0
- data/config/logger.yml +3 -0
- data/gulpfile.js +80 -0
- data/lib/proxes.rb +3 -0
- data/lib/proxes/app.rb +48 -0
- data/lib/proxes/controllers/application.rb +53 -0
- data/lib/proxes/controllers/audit_logs.rb +34 -0
- data/lib/proxes/controllers/auth_identity.rb +21 -0
- data/lib/proxes/controllers/component.rb +108 -0
- data/lib/proxes/controllers/permissions.rb +10 -0
- data/lib/proxes/controllers/roles.rb +10 -0
- data/lib/proxes/controllers/users.rb +119 -0
- data/lib/proxes/db.rb +17 -0
- data/lib/proxes/helpers/authentication.rb +45 -0
- data/lib/proxes/helpers/component.rb +40 -0
- data/lib/proxes/helpers/indices.rb +16 -0
- data/lib/proxes/helpers/pundit.rb +39 -0
- data/lib/proxes/helpers/views.rb +41 -0
- data/lib/proxes/loggers/elasticsearch.rb +9 -0
- data/lib/proxes/models/audit_log.rb +12 -0
- data/lib/proxes/models/identity.rb +67 -0
- data/lib/proxes/models/permission.rb +17 -0
- data/lib/proxes/models/role.rb +14 -0
- data/lib/proxes/models/user.rb +57 -0
- data/lib/proxes/policies/application_policy.rb +20 -0
- data/lib/proxes/policies/audit_log_policy.rb +40 -0
- data/lib/proxes/policies/identity_policy.rb +24 -0
- data/lib/proxes/policies/permission_policy.rb +40 -0
- data/lib/proxes/policies/request/root_policy.rb +12 -0
- data/lib/proxes/policies/request/search_policy.rb +15 -0
- data/lib/proxes/policies/request/snapshot_policy.rb +12 -0
- data/lib/proxes/policies/request/stats_policy.rb +15 -0
- data/lib/proxes/policies/request_policy.rb +69 -0
- data/lib/proxes/policies/role_policy.rb +40 -0
- data/lib/proxes/policies/token_policy.rb +46 -0
- data/lib/proxes/policies/user_policy.rb +46 -0
- data/lib/proxes/rake_tasks.rb +59 -0
- data/lib/proxes/request.rb +51 -0
- data/lib/proxes/request/root.rb +10 -0
- data/lib/proxes/request/search.rb +37 -0
- data/lib/proxes/request/snapshot.rb +16 -0
- data/lib/proxes/request/stats.rb +30 -0
- data/lib/proxes/security.rb +59 -0
- data/lib/proxes/seed.rb +10 -0
- data/lib/proxes/services/logger.rb +50 -0
- data/lib/proxes/version.rb +4 -0
- data/migrate/001_tables.rb +47 -0
- data/migrate/002_audit_log.rb +11 -0
- data/package.json +34 -0
- data/proxes.gemspec +44 -0
- data/public/js/bundle.js +28988 -0
- data/src/scripts/app.js +10 -0
- data/views/404.haml +1 -0
- data/views/audit_logs/index.haml +18 -0
- data/views/error.haml +4 -0
- data/views/getting_started.haml +16 -0
- data/views/identity/login.haml +19 -0
- data/views/identity/register.haml +17 -0
- data/views/index.haml +3 -0
- data/views/layout.haml +48 -0
- data/views/partials/delete_form.haml +4 -0
- data/views/partials/form_control.haml +21 -0
- data/views/partials/navbar.haml +25 -0
- data/views/partials/notifications.haml +24 -0
- data/views/partials/pager.haml +19 -0
- data/views/partials/sidebar.haml +32 -0
- data/views/permissions/display.haml +24 -0
- data/views/permissions/edit.haml +11 -0
- data/views/permissions/form.haml +3 -0
- data/views/permissions/index.haml +14 -0
- data/views/permissions/new.haml +10 -0
- data/views/roles/display.haml +33 -0
- data/views/roles/edit.haml +11 -0
- data/views/roles/form.haml +1 -0
- data/views/roles/index.haml +17 -0
- data/views/roles/new.haml +10 -0
- data/views/users/display.haml +32 -0
- data/views/users/edit.haml +11 -0
- data/views/users/identity.haml +3 -0
- data/views/users/index.haml +20 -0
- data/views/users/new.haml +11 -0
- data/views/users/profile.haml +37 -0
- data/views/users/user.haml +3 -0
- 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,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
|
data/lib/proxes/seed.rb
ADDED
@@ -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,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
|
data/package.json
ADDED
@@ -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
|
+
}
|
data/proxes.gemspec
ADDED
@@ -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
|