four_eyes 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 164ea5dca880f69d877e8352df5dbaefeb84b016
4
+ data.tar.gz: 5f7d328e524f1c5fcc0957a172a4488cb26dbbea
5
+ SHA512:
6
+ metadata.gz: d099d08b459a46028d9bffeaa3fb94549da48b580bc8ad1671d576a8ff98665cd291fb922bccf57cedca8aabe271867c96602a3d0ee1b37390b15d73711b0def
7
+ data.tar.gz: 28e291b6a365392c8ff58f6940198459685d46445f30472a2b0603004d1b7d8a41176fa63867440a7ab2d6ef094c28581da3b941dd3481307f4bad376008756a
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Dennis Ondeng
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # FourEyes
2
+
3
+ A gem to implement the maker-checker principle. The 4-eyes principle.
4
+
5
+ Maker-checker (or Maker and Checker, or 4-Eyes) is one of the central principles of authorization in the information systems
6
+ of financial organizations.The principle of maker and checker means that for each transaction, there must be at least two
7
+ individuals necessary for its completion. While one individual may create a transaction, the other individual should be involved
8
+ in confirmation/authorization of the same. Here the segregation of duties plays an important role. In this way, strict control
9
+ is kept over system software and data, keeping in mind functional division of labor between all classes of employees.
10
+
11
+ (courtesy Wikipedia)
12
+
13
+ Working with institutions such as financial institutions you may be required to restrict some actions to be done by two pairs of eyes.
14
+ FourEyes makes it easy to do this by adding minimal code to the controller with the actions you would like to have verified.
15
+
16
+ For every action that needs to be authorized, an action containing all the details is stored together with the changes required.
17
+ The new object or changes are stored on JSON format.
18
+ This is done after a validation check to ensure that the object will pass validation during the authorization stage. You are
19
+ responsible for performing the validation check to see if the resource is indeed valid. However, this cannot be guaranteed because
20
+ the system state may change before authorization to a state that renders the action invalid. In such a scenario, the action
21
+ would need to be cancelled and created again.
22
+
23
+ A listing of all pending actions can be availed and depending on any authorization mechanisim that you have implemented, a user can then access a pending
24
+ action and authorize it.
25
+
26
+ ## Installation
27
+
28
+ Add this line to your application's Gemfile:
29
+
30
+ gem 'four_eyes'
31
+
32
+ And then execute:
33
+
34
+ $ bundle
35
+
36
+ Or install it yourself as:
37
+
38
+ $ gem install four_eyes
39
+
40
+ ## Usage
41
+
42
+ To add maker checker functionality, add the following before_filter to the controller in question.
43
+ Sets up a before filter which adds maker checker functionality to the controller
44
+
45
+ class StudentsController < ApplicationController
46
+ add_maker_checker_to_resource
47
+ end
48
+
49
+ To exempt any one of the actions
50
+
51
+ class StudentsController < ApplicationController
52
+ add_maker_checker_to_resource, except: :delete
53
+ end
54
+
55
+ To include only a subset of the actions
56
+
57
+ class StudentsController < ApplicationController
58
+ add_maker_checker_to_resource, only: [:create, :update]
59
+ end
60
+
61
+ Once that is done, in the create, update or delete action you would call the following
62
+
63
+ maker_create([User resource performaing the action],
64
+ [ID of resource performing the action],
65
+ [Class name of the resource being worked on],
66
+ [Parameters of oject/resource in JSON format])
67
+
68
+ For exeample, in a system where the users are called Administrators, and the resource we are trying to create via
69
+ maker checker is a Student, the call to create a student via maker-checker would look like this.
70
+
71
+
72
+ def create
73
+ maker_create('Administrator',
74
+ current_administrator_id,
75
+ 'Student',
76
+ student_params.to_json)
77
+ end
78
+
79
+ def update
80
+ maker_update('Administrator',
81
+ current_administrator_id,
82
+ 'Student',
83
+ student_params.to_json)
84
+ end
85
+
86
+ def destroy
87
+ maker_delete('Administrator',
88
+ 'current_administrator_id,
89
+ 'Student',
90
+ student.to_json)
91
+ end
92
+
93
+ where in the example above, the call has the following format
94
+
95
+ ## TODO - Write spec tests.
96
+
97
+ ## Contributing
98
+
99
+ 1. Fork it ( https://github.com/[my-github-username]/four_eyes/fork )
100
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
101
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
102
+ 4. Push to the branch (`git push origin my-new-feature`)
103
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'FourEyes'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,13 @@
1
+ module FourEyes
2
+ # This controller provides restful route handling for Actions.
3
+ #
4
+ # == Security:
5
+ # Only GET requests are supported. You should ensure that your application
6
+ # controller enforces its own authentication and authorization, which this
7
+ # controller will inherit.
8
+ #
9
+ # @author Dennis Ondeng
10
+ class ActionsController < ApplicationController
11
+ include FourEyes::Concerns::Controllers::Actions
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ module FourEyes
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module FourEyes
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,23 @@
1
+ module FourEyes
2
+ class Action < ActiveRecord::Base
3
+ validates :action_type, :maker_resource_id, :status, presence: true
4
+
5
+
6
+ def self.between_times(start_time, end_time)
7
+ Action.where('created_at >= ? AND created_at < ?', start_time, end_time)
8
+ end
9
+
10
+ def initiated?
11
+ self.status == 'Initiated'
12
+ end
13
+
14
+ def cancelled?
15
+ self.status == 'Cancelled'
16
+ end
17
+
18
+ def authorized?
19
+ self.status == 'Authorized'
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,30 @@
1
+ <div class="four_eyes_container">
2
+ <h1>Actions</h1>
3
+
4
+ <table cellspacing="0">
5
+ <thead>
6
+ <tr>
7
+ <th class="nobg">ID</th>
8
+ <th>Date</th>
9
+ <th>Action</th>
10
+ <th>Maker ID</th>
11
+ <th>Object</th>
12
+ <th>Status</th>
13
+ <th>Data</th>
14
+ </tr>
15
+ </thead>
16
+ <tbody>
17
+ <% @actions.each do |action| %>
18
+ <tr class="<%= cycle("even", "odd") -%>">
19
+ <td><%=link_to(action.id, action_path(action)) %></td>
20
+ <td><%= action.created_at %></td>
21
+ <td><%=h action.action_type %></td>
22
+ <td><%=h action.maker_resource_id %></td>
23
+ <td><%=h action.object_resource_class_name %></td>
24
+ <td><%=h action.status %></td>
25
+ <td><%=h action.data %></td>
26
+ </tr>
27
+ <% end %>
28
+ </tbody>
29
+ </table>
30
+ </div>
@@ -0,0 +1,46 @@
1
+ <div class="four_eyes_container">
2
+ <h1>Action</h1>
3
+
4
+ <table>
5
+ <tr>
6
+ <td>ID</td>
7
+ <td><%= @action.id %></td>
8
+ </tr>
9
+ <tr>
10
+ <td>Date</td>
11
+ <td><%= @action.created_at %></td>
12
+ </tr>
13
+ <tr>
14
+ <td>Action</td>
15
+ <td><%= @action.action_type %></td>
16
+ </tr>
17
+ <tr>
18
+ <td>Maker-Checker Resource</td>
19
+ <td><%= @action.resource_class_name %></td>
20
+ </tr>
21
+ <tr>
22
+ <td>Maker resource ID</td>
23
+ <td><%= @action.maker_resource_id %></td>
24
+ </tr>
25
+ <tr>
26
+ <td>Checker Resource ID</td>
27
+ <td><%= @action.checker_resource_id %></td>
28
+ </tr>
29
+ <tr>
30
+ <td>Object</td>
31
+ <td><%= @action.object_resource_class_name %></td>
32
+ </tr>
33
+ <tr>
34
+ <td>Object ID</td>
35
+ <td><%= @action.object_resource_id %></td>
36
+ </tr>
37
+ <tr>
38
+ <td>Data</td>
39
+ <td><%= @action.data.to_s %></td>
40
+ </tr>
41
+ <tr>
42
+ <td>Status</td>
43
+ <td><%= @action.status %></td>
44
+ </tr>
45
+ </table>
46
+ </div>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ FourEyes::Engine.routes.draw do
2
+ resources :actions, only: [:index, :show]
3
+ end
@@ -0,0 +1,170 @@
1
+ module FourEyes
2
+ module Concerns
3
+ module Controllers
4
+ module Actions
5
+ extend ActiveSupport::Concern
6
+
7
+ #included do
8
+ #end
9
+
10
+ # @example
11
+ # GET /actions
12
+ # GET /actions.xml
13
+ # GET /actions.json
14
+ def index
15
+ @actions = Action.all
16
+
17
+ respond_to do |format|
18
+ format.html # index.html.erb
19
+ format.xml { render :xml => @actions }
20
+ format.json { render :json => @actions }
21
+ end
22
+ end
23
+
24
+ # @example
25
+ # GET /action/1
26
+ # GET /action/1.xml
27
+ # GET /action/1.json
28
+ def show
29
+ @action = Action.find(params[:id])
30
+ respond_to do |format|
31
+ format.html # show.html.erb
32
+ format.xml { render :xml => @action }
33
+ format.json { render :json => @action }
34
+ end
35
+ end
36
+
37
+ # Perform a checker eligibility test.
38
+ # At the most basic level, the actor doing the initiating cannot be the same person
39
+ # doing the checking
40
+ #
41
+ # @params action - The action to be authorized
42
+ # @params resource - The id of the actor requesting the authorization
43
+ #
44
+ def eligible_to_check(action, resource_id)
45
+ action.maker_resource_id != resource_id
46
+ end
47
+
48
+ # Perform the checker action for the maker checker actions
49
+ # Dispatch to function to process the corresponding action (create, upated, delete)
50
+ #
51
+ # @param id - The id of the action being authorized
52
+ # @param checker_resource_id - The id of the actor performing the authorization
53
+ #
54
+ def authorize
55
+ @action = Action.find(params[:id])
56
+ checker_resource_id = params[:checker_resource_id].to_i
57
+ if eligible_to_check(@action, checker_resource_id)
58
+ if @action && @action.initiated? && checker_resource_id
59
+ self.send(@action.action_type.gsub('action_', 'checker_'), @action, checker_resource_id)
60
+ end
61
+ else
62
+ flash[:notice] = 'You are not eligible to authorize this action'
63
+ redirect_to action: :index and return
64
+ end
65
+ end
66
+
67
+ # Retrieve hash of saved parameters and instantiate a new object of type object_resource_class_name
68
+ #
69
+ # @param action - The action to authorize
70
+ # @param resource_id - The id of the actor performing the authorization
71
+ #
72
+ def checker_create(action, resource_id)
73
+ object_resource = action.object_resource_class_name.constantize.new(action.data.deep_symbolize_keys)
74
+ if object_resource.save
75
+ action.status = 'Authorized'
76
+ action.checker_resource_id = resource_id
77
+ if action.save
78
+ flash[:notice] = "#{action.object_resource_class_name.titlecase} authorized and created successfully."
79
+ redirect_to action: :index and return
80
+ else
81
+ flash[:notice] = "#{action.object_resource_class_name.titlecase} created successfully. Action not updated"
82
+ redirect_to action: :index and return
83
+ end
84
+ else
85
+ flash[:error] = object_resource.errors.full_messages
86
+ redirect_to action: :index and return
87
+ end
88
+ end
89
+
90
+ # Retrieve hash of saved parameters and update the object of type object_resource_class_name
91
+ #
92
+ # @param action - The action to authorize
93
+ # @param resource_id - The id of the actor performing the authorization
94
+ #
95
+ def checker_update(action, resource_id)
96
+ begin
97
+ object_resource = action.object_resource_class_name.constantize.find(action.object_resource_id)
98
+ if object_resource.update_attributes(action.data.deep_symbolize_keys)
99
+ action.status = 'Authorized'
100
+ action.checker_resource_id = resource_id
101
+ if action.save
102
+ flash[:notice] = "#{action.object_resource_class_name.titlecase} authorized and updated successfully."
103
+ redirect_to action: :index and return
104
+ else
105
+ flash[:notice] = "#{action.object_resource_class_name.titlecase} updated successfully. Action not updated"
106
+ redirect_to action: :index and return
107
+ end
108
+ else
109
+ flash[:error] = object_resource.errors.full_messages
110
+ redirect_to action: :index and return
111
+ end
112
+ rescue ActiveRecord::RecordNotFound
113
+ flash[:error] = 'Record not found'
114
+ redirect_to action: :index and return
115
+ end
116
+ end
117
+
118
+ # Retrieve a delete action and call destroy on it
119
+ #
120
+ # @param action - The action to authorize
121
+ # @param resource_id - The id of the actor performing the delete authorization
122
+ #
123
+ def checker_delete(action, resource_id)
124
+ begin
125
+ object_resource = action.object_resource_class_name.constantize.find(action.object_resource_id)
126
+ if object_resource.destroy
127
+ action.status = 'Authorized'
128
+ action.checker_resource_id = resource_id
129
+ if action.save
130
+ flash[:notice] = "#{action.object_resource_class_name.titlecase} authorized and deleted successfully."
131
+ redirect_to action: :index and return
132
+ else
133
+ flash[:notice] = "#{action.object_resource_class_name.titlecase} deleted successfully. Action not updated"
134
+ redirect_to action: :index and return
135
+ end
136
+ else
137
+ flash[:error] = object_resource.errors.full_messages
138
+ redirect_to action: :index and return
139
+ end
140
+ rescue ActiveRecord::RecordNotFound
141
+ flash[:error] = 'Record not found'
142
+ redirect_to action: :index and return
143
+ end
144
+ end
145
+
146
+
147
+ # Cancel an action that had been previously initiated
148
+ #
149
+ # @param id - The id of the action action that is to be cancelled
150
+ # @param resource_id - The id of the actor performing the cancellation
151
+ #
152
+ def cancel
153
+ @action = Action.find(params[:id])
154
+ checker_resource_id = params[:checker_resource_id].to_i
155
+ if @action
156
+ @action.status = 'Cancelled'
157
+ @action.checker_resource_id = checker_resource_id
158
+ if @action.save
159
+ flash[:notice] = "Action on #{@action.object_resource_class_name.titlecase} cancelled successfully."
160
+ redirect_to action: :index and return
161
+ else
162
+ flash.now[:error] = @action.errors.full_messages
163
+ redirect_to action: :index and return
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,57 @@
1
+ module FourEyes
2
+
3
+ # This module is automatically included into all controllers that will be implementing the
4
+ # Maker-Checker functionality
5
+ #
6
+ module ControllerAdditions
7
+ module ClassMethods
8
+
9
+ # Sets up a before filter which adds maker checker functionality to the controller
10
+ #
11
+ # @example
12
+ #
13
+ # class StudentsController < ApplicationController
14
+ # add_maker_checker_to_resource
15
+ # end
16
+ #
17
+ # To exempt any one of the actions
18
+ #
19
+ # class StudentsController < ApplicationController
20
+ # add_maker_checker_to_resource, except: :delete
21
+ # end
22
+ #
23
+ # To include only a subset of the actions
24
+ #
25
+ # class StudentsController < ApplicationController
26
+ # add_maker_checker_to_resource, only: [:create, :update]
27
+ # end
28
+ #
29
+ def add_maker_checker_to_resource(*args)
30
+
31
+ # Add maker functions
32
+ four_eyes_resource_class.add_maker_create_function(self, :maker_create, *args)
33
+ four_eyes_resource_class.add_maker_update_function(self, :maker_update, *args)
34
+ four_eyes_resource_class.add_maker_delete_function(self, :maker_delete, *args)
35
+ four_eyes_resource_class.add_maker_generic_function(self, :maker_generic, *args)
36
+ end
37
+
38
+ def four_eyes_resource_class
39
+ if ancestors.map(&:to_s).include? "InheritedResources::Actions"
40
+ InheritedResource
41
+ else
42
+ ControllerResource
43
+ end
44
+ end
45
+ end
46
+
47
+ def self.included(base)
48
+ base.extend ClassMethods
49
+ end
50
+ end
51
+ end
52
+
53
+ if defined? ActionController::Base
54
+ ActionController::Base.class_eval do
55
+ include FourEyes::ControllerAdditions
56
+ end
57
+ end
@@ -0,0 +1,116 @@
1
+ module FourEyes
2
+ class ControllerResource
3
+
4
+ # Define the dynamic maker_create function
5
+ # This handles the storing of the action and it's meta data to the four_eyes_actions
6
+ # table with the status of 'Initiated'
7
+ #
8
+ def self.add_maker_create_function(controller_class, method, *args)
9
+ options = args.extract_options!
10
+ controller_class.send :define_method, method do |*args|
11
+ "#{method} #{args}"
12
+ resource_class_name = args[0]
13
+ resource_id = args[1]
14
+ object_class_name = args[2]
15
+ data = args[3]
16
+
17
+ action = FourEyes::Action.new(resource_class_name: resource_class_name,
18
+ maker_resource_id: resource_id,
19
+ resource_class_name: resource_class_name,
20
+ action_type: 'action_create',
21
+ object_resource_class_name: object_class_name,
22
+ status: 'Initiated',
23
+ data: data)
24
+ if action.save!
25
+ true
26
+ else
27
+ # TODO dondeng - Better to raise an exception here
28
+ false
29
+ end
30
+ end
31
+ end
32
+
33
+ def self.add_maker_update_function(controller_class, method, *args)
34
+ options = args.extract_options!
35
+ controller_class.send :define_method, method do |*args|
36
+ resource_class_name = args[0]
37
+ resource_id = args[1]
38
+ object_class_name = args[2]
39
+ object_resource_id = args[3]
40
+ data = args[4]
41
+
42
+ action = FourEyes::Action.new(resource_class_name: resource_class_name,
43
+ maker_resource_id: resource_id,
44
+ action_type: 'action_update',
45
+ object_resource_class_name: object_class_name,
46
+ object_resource_id: object_resource_id,
47
+ status: 'Initiated',
48
+ data: data)
49
+ if action.save
50
+ true
51
+ else
52
+ # TODO - dondeng - Better to raise an exception here
53
+ false
54
+ end
55
+ end
56
+ end
57
+
58
+ def self.add_maker_delete_function(controller_class, method, *args)
59
+ options = args.extract_options!
60
+ controller_class.send :define_method, method do |*args|
61
+ resource_class_name = args[0]
62
+ resource_id = args[1]
63
+ object_class_name = args[2]
64
+ object_resource_id = args[3]
65
+ data = args[4]
66
+
67
+ action = FourEyes::Action.new(resource_class_name: resource_class_name,
68
+ maker_resource_id: resource_id,
69
+ action_type: 'action_delete',
70
+ object_resource_class_name: object_class_name,
71
+ object_resource_id: object_resource_id,
72
+ status: 'Initiated',
73
+ data: data)
74
+ if action.save
75
+ true
76
+ else
77
+ # TODO - dondeng - Better to raise an exception here
78
+ false
79
+ end
80
+ end
81
+ end
82
+
83
+ def self.add_maker_generic_function(controller_class, method, *args)
84
+ options = args.extract_options!
85
+ controller_class.send :define_method, method do |*args|
86
+ resource_class_name = args[0]
87
+ resource_id = args[1]
88
+ object_class_name = args[2]
89
+ object_resource_id = args[3]
90
+ action = args[4]
91
+ data = args[5]
92
+
93
+ action = FourEyes::Action.new(resource_class_name: resource_class_name,
94
+ maker_resource_id: resource_id,
95
+ action_type: action,
96
+ object_resource_class_name: object_class_name,
97
+ object_resource_id: object_resource_id,
98
+ status: 'Initiated',
99
+ data: data)
100
+ if action.save
101
+ true
102
+ else
103
+ # TODO - dondeng - Better to raise an exception here
104
+ false
105
+ end
106
+ end
107
+ end
108
+
109
+ def initialize(controller, *args)
110
+ @controller = controller
111
+ @params = controller.params
112
+ @options = args.extract_options!
113
+ @name = args.first
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,11 @@
1
+ require 'four_eyes/version'
2
+ require 'four_eyes/controller_resource'
3
+ require 'four_eyes/controller_additions'
4
+ require 'four_eyes/inherited_resource'
5
+ require 'four_eyes/concerns/controllers/actions_controller'
6
+
7
+ module FourEyes
8
+ class Engine < ::Rails::Engine
9
+ isolate_namespace FourEyes
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ module FourEyes
2
+ class InheritedResource < ControllerResource
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module FourEyes
2
+ VERSION = "0.1.0"
3
+ end
data/lib/four_eyes.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "four_eyes/engine"
2
+
3
+ module FourEyes
4
+ end
@@ -0,0 +1,25 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ class FourEyesGenerator < Rails::Generators::Base
5
+ include Rails::Generators::Migration
6
+
7
+ def self.source_root
8
+ @source_root ||= File.join(File.dirname(__FILE__), 'templates')
9
+ end
10
+
11
+ # Implement the required interface for Rails::Generators::Migration.
12
+ # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
13
+ def self.next_migration_number(dirname)
14
+ if ActiveRecord::Base.timestamped_migrations
15
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
16
+ else
17
+ "%.3d" % (current_migration_number(dirname) + 1)
18
+ end
19
+ end
20
+
21
+ def create_migration_file
22
+ migration_template 'migration.rb', 'db/migrate/create_four_eyes_tables.rb'
23
+ end
24
+
25
+ end
@@ -0,0 +1,25 @@
1
+ class CreateFourEyesTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :four_eyes_actions do |t|
4
+ t.string :action_type
5
+ t.string :resource_class_name
6
+ t.integer :maker_resource_id
7
+ t.integer :checker_resource_id
8
+ t.integer :maker_resource_role_id
9
+ t.integer :checker_resource_role_id
10
+ t.string :object_resource_class_name
11
+ t.integer :object_resource_id
12
+ t.json :data
13
+ t.string :status
14
+
15
+ t.timestamps
16
+ end
17
+
18
+ add_index :four_eyes_actions, :maker_resource_id
19
+ add_index :four_eyes_actions, :checker_resource_id
20
+ end
21
+
22
+ def self.down
23
+ drop_table :four_eyes_actions
24
+ end
25
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :four_eyes do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: four_eyes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dennis Ondeng
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: sqlite3
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rspec-rails
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ description: 'courtesy - Wikipedia: Maker-checker (or Maker and Checker, or 4-Eyes)
76
+ is one of the central principles of authorization in the information systems of
77
+ financial organizations.The principle of maker and checker means that for each transaction,
78
+ there must be at least two individuals necessary for its completion. While one individual
79
+ may create a transaction, the other individual should be involved in confirmation/authorization
80
+ of the same. Here the segregation of duties plays an important role. In this way,
81
+ strict control is kept over system software and data, keeping in mind functional
82
+ division of labor between all classes of employees.'
83
+ email:
84
+ - dondeng2@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - MIT-LICENSE
90
+ - README.md
91
+ - Rakefile
92
+ - app/assets/javascripts/four_eyes/application.js
93
+ - app/assets/stylesheets/four_eyes/application.css
94
+ - app/controllers/four_eyes/actions_controller.rb
95
+ - app/controllers/four_eyes/application_controller.rb
96
+ - app/helpers/four_eyes/application_helper.rb
97
+ - app/models/four_eyes/action.rb
98
+ - app/views/four_eyes/actions/index.html.erb
99
+ - app/views/four_eyes/actions/show.html.erb
100
+ - config/routes.rb
101
+ - lib/four_eyes.rb
102
+ - lib/four_eyes/concerns/controllers/actions_controller.rb
103
+ - lib/four_eyes/controller_additions.rb
104
+ - lib/four_eyes/controller_resource.rb
105
+ - lib/four_eyes/engine.rb
106
+ - lib/four_eyes/inherited_resource.rb
107
+ - lib/four_eyes/version.rb
108
+ - lib/generators/four_eyes/four_eyes_generator.rb
109
+ - lib/generators/four_eyes/templates/migration.rb
110
+ - lib/tasks/four_eyes_tasks.rake
111
+ homepage: https://github.com/dondeng/four_eyes
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.4.8
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: A gem to implement the maker-checker principle. The 4-eyes principle
135
+ test_files: []