lotusrb 0.3.2 → 0.4.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 +4 -4
- data/CHANGELOG.md +20 -0
- data/FEATURES.md +17 -0
- data/README.md +16 -355
- data/lib/lotus.rb +0 -1
- data/lib/lotus/action/csrf_protection.rb +167 -0
- data/lib/lotus/application.rb +3 -1
- data/lib/lotus/cli.rb +14 -13
- data/lib/lotus/commands/console.rb +1 -1
- data/lib/lotus/commands/db.rb +102 -0
- data/lib/lotus/commands/db/abstract.rb +15 -0
- data/lib/lotus/commands/db/apply.rb +14 -0
- data/lib/lotus/commands/db/console.rb +1 -5
- data/lib/lotus/commands/db/create.rb +14 -0
- data/lib/lotus/commands/db/drop.rb +14 -0
- data/lib/lotus/commands/db/migrate.rb +19 -0
- data/lib/lotus/commands/db/prepare.rb +14 -0
- data/lib/lotus/commands/db/version.rb +14 -0
- data/lib/lotus/commands/generate.rb +20 -20
- data/lib/lotus/commands/new.rb +1 -0
- data/lib/lotus/commands/routes.rb +1 -2
- data/lib/lotus/configuration.rb +29 -0
- data/lib/lotus/container.rb +19 -3
- data/lib/lotus/environment.rb +62 -9
- data/lib/lotus/frameworks.rb +1 -0
- data/lib/lotus/generators/action.rb +46 -10
- data/lib/lotus/generators/action/action_spec.minitest.tt +1 -1
- data/lib/lotus/generators/action/action_spec.rspec.tt +1 -1
- data/lib/lotus/generators/action/view_spec.minitest.tt +2 -1
- data/lib/lotus/generators/action/view_spec.rspec.tt +2 -1
- data/lib/lotus/generators/app.rb +39 -0
- data/lib/lotus/generators/app/.gitkeep +1 -0
- data/lib/lotus/generators/application/app.rb +184 -0
- data/lib/lotus/generators/application/app/.env.development.tt +3 -0
- data/lib/lotus/generators/application/app/.env.test.tt +3 -0
- data/lib/lotus/generators/application/{container/config → app}/.env.tt +0 -0
- data/lib/lotus/generators/application/app/.gitkeep +1 -0
- data/lib/lotus/generators/application/app/Gemfile.tt +35 -0
- data/lib/lotus/generators/application/app/Rakefile.minitest.tt +10 -0
- data/lib/lotus/generators/application/app/Rakefile.rspec.tt +5 -0
- data/lib/lotus/generators/application/app/apps/.gitkeep.tt +1 -0
- data/lib/lotus/generators/application/app/capybara.rb.rspec.tt +8 -0
- data/lib/lotus/generators/application/app/config.ru.tt +3 -0
- data/lib/lotus/generators/application/app/config/application.rb.tt +227 -0
- data/lib/lotus/generators/application/app/config/environment.rb.tt +5 -0
- data/lib/lotus/generators/application/app/config/routes.rb.tt +2 -0
- data/lib/lotus/generators/application/app/db/.gitkeep +1 -0
- data/lib/lotus/generators/application/app/features_helper.rb.minitest.tt +11 -0
- data/lib/lotus/generators/application/app/features_helper.rb.rspec.tt +12 -0
- data/lib/lotus/generators/application/app/gitignore.tt +2 -0
- data/lib/lotus/generators/application/app/lib/app_name.rb.tt +47 -0
- data/lib/lotus/generators/application/app/lib/chirp/entities/.gitkeep +1 -0
- data/lib/lotus/generators/application/app/lib/chirp/repositories/.gitkeep +1 -0
- data/lib/lotus/generators/application/app/lib/config/mapping.rb.tt +7 -0
- data/lib/lotus/generators/application/app/lotusrc.tt +3 -0
- data/lib/lotus/generators/application/app/rspec.rspec.tt +2 -0
- data/lib/lotus/generators/application/app/schema.sql.tt +0 -0
- data/lib/lotus/generators/application/app/spec_helper.rb.minitest.tt +7 -0
- data/lib/lotus/generators/application/app/spec_helper.rb.rspec.tt +100 -0
- data/lib/lotus/generators/application/app/templates/application.html.erb.tt +9 -0
- data/lib/lotus/generators/application/app/views/application_layout.rb.tt +7 -0
- data/lib/lotus/generators/application/container.rb +37 -13
- data/lib/lotus/generators/application/container/{config/.env.development.tt → .env.development.tt} +0 -0
- data/lib/lotus/generators/application/container/{config/.env.test.tt → .env.test.tt} +0 -0
- data/lib/lotus/generators/application/container/.env.tt +1 -0
- data/lib/lotus/generators/application/container/lib/app_name.rb.tt +9 -0
- data/lib/lotus/generators/application/container/schema.sql.tt +0 -0
- data/lib/lotus/generators/migration.rb +58 -0
- data/lib/lotus/generators/migration/migration.rb.tt +4 -0
- data/lib/lotus/generators/model.rb +10 -7
- data/lib/lotus/generators/slice.rb +4 -12
- data/lib/lotus/generators/slice/application.rb.tt +3 -19
- data/lib/lotus/generators/slice/config/routes.rb.tt +1 -7
- data/lib/lotus/loader.rb +15 -1
- data/lib/lotus/lotusrc.rb +8 -3
- data/lib/lotus/templates/{welcome.html → welcome.html.erb} +4 -3
- data/lib/lotus/version.rb +1 -1
- data/lib/lotus/welcome.rb +20 -1
- data/lotusrb.gemspec +5 -5
- metadata +67 -18
- data/lib/lotus/generators/slice/action.rb.tt +0 -8
- data/lib/lotus/generators/slice/config/mapping.rb.tt +0 -13
- data/lib/lotus/generators/slice/templates/template.html.erb.tt +0 -2
- data/lib/lotus/generators/slice/view.rb.tt +0 -5
- data/lib/lotus/logger.rb +0 -141
data/lib/lotus.rb
CHANGED
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Lotus
|
4
|
+
module Action
|
5
|
+
# Invalid CSRF Token
|
6
|
+
#
|
7
|
+
# @since 0.4.0
|
8
|
+
class InvalidCSRFTokenError < ::StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
# CSRF Protection
|
12
|
+
#
|
13
|
+
# This security mechanism is enabled automatically if sessions are turned on.
|
14
|
+
#
|
15
|
+
# It stores a "challenge" token in session. For each "state changing request"
|
16
|
+
# (eg. <tt>POST</tt>, <tt>PATCH</tt> etc..), we should send a special param:
|
17
|
+
# <tt>_csrf_token</tt>.
|
18
|
+
#
|
19
|
+
# If the param matches with the challenge token, the flow can continue.
|
20
|
+
# Otherwise the application detects an attack attempt, it reset the session
|
21
|
+
# and <tt>Lotus::Action::InvalidCSRFTokenError</tt> is raised.
|
22
|
+
#
|
23
|
+
# We can specify a custom handling strategy, by overriding <tt>#handle_invalid_csrf_token</tt>.
|
24
|
+
#
|
25
|
+
# Form helper (<tt>#form_for</tt>) automatically sets a hidden field with the
|
26
|
+
# correct token. A special view method (<tt>#csrf_token</tt>) is available in
|
27
|
+
# case the form markup is manually crafted.
|
28
|
+
#
|
29
|
+
# We can disable this check on action basis, by overriding <tt>#verify_csrf_token?</tt>.
|
30
|
+
#
|
31
|
+
# @since 0.4.0
|
32
|
+
#
|
33
|
+
# @see https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29
|
34
|
+
# @see https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
|
35
|
+
#
|
36
|
+
# @example Custom Handling
|
37
|
+
# module Web::Controllers::Books
|
38
|
+
# class Create
|
39
|
+
# include Web::Action
|
40
|
+
#
|
41
|
+
# def call(params)
|
42
|
+
# # ...
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# private
|
46
|
+
#
|
47
|
+
# def handle_invalid_csrf_token
|
48
|
+
# Web::Logger.warn "CSRF attack: expected #{ session[:_csrf_token] }, was #{ params[:_csrf_token] }"
|
49
|
+
# # manual handling
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# @example Bypass Security Check
|
55
|
+
# module Web::Controllers::Books
|
56
|
+
# class Create
|
57
|
+
# include Web::Action
|
58
|
+
#
|
59
|
+
# def call(params)
|
60
|
+
# # ...
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# private
|
64
|
+
#
|
65
|
+
# def verify_csrf_token?
|
66
|
+
# false
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
module CSRFProtection
|
71
|
+
# Session and params key for CSRF token.
|
72
|
+
#
|
73
|
+
# This key is shared with <tt>lotus-controller</tt> and <tt>lotus-helpers</tt>
|
74
|
+
#
|
75
|
+
# @since 0.4.0
|
76
|
+
# @api private
|
77
|
+
CSRF_TOKEN = :_csrf_token
|
78
|
+
|
79
|
+
# Idempotent HTTP methods
|
80
|
+
#
|
81
|
+
# By default, the check isn't performed if the request method is included
|
82
|
+
# in this list.
|
83
|
+
#
|
84
|
+
# @since 0.4.0
|
85
|
+
# @api private
|
86
|
+
IDEMPOTENT_HTTP_METHODS = Hash[
|
87
|
+
'GET' => true,
|
88
|
+
'HEAD' => true,
|
89
|
+
'TRACE' => true,
|
90
|
+
'OPTIONS' => true
|
91
|
+
].freeze
|
92
|
+
|
93
|
+
# @since 0.4.0
|
94
|
+
# @api private
|
95
|
+
def self.included(action)
|
96
|
+
action.class_eval do
|
97
|
+
before :set_csrf_token, :verify_csrf_token
|
98
|
+
end unless Lotus.env?(:test)
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
# Set CSRF Token in session
|
103
|
+
#
|
104
|
+
# @since 0.4.0
|
105
|
+
# @api private
|
106
|
+
def set_csrf_token
|
107
|
+
session[CSRF_TOKEN] ||= generate_csrf_token
|
108
|
+
end
|
109
|
+
|
110
|
+
# Verify if CSRF token from params, matches the one stored in session.
|
111
|
+
# If not, it raises an error.
|
112
|
+
#
|
113
|
+
# Don't override this method.
|
114
|
+
#
|
115
|
+
# To bypass the security check, please override <tt>#verify_csrf_token?</tt>.
|
116
|
+
# For custom handling of an attack, please override <tt>#handle_invalid_csrf_token</tt>.
|
117
|
+
#
|
118
|
+
# @since 0.4.0
|
119
|
+
# @api private
|
120
|
+
def verify_csrf_token
|
121
|
+
handle_invalid_csrf_token if invalid_csrf_token?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Verify if CSRF token from params, matches the one stored in session.
|
125
|
+
#
|
126
|
+
# Don't override this method.
|
127
|
+
#
|
128
|
+
# @since 0.4.0
|
129
|
+
# @api private
|
130
|
+
def invalid_csrf_token?
|
131
|
+
verify_csrf_token? &&
|
132
|
+
session[CSRF_TOKEN] != params[CSRF_TOKEN]
|
133
|
+
end
|
134
|
+
|
135
|
+
# Generates a random CSRF Token
|
136
|
+
#
|
137
|
+
# @since 0.4.0
|
138
|
+
# @api private
|
139
|
+
def generate_csrf_token
|
140
|
+
SecureRandom.hex(32)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Decide if perform the check or not.
|
144
|
+
#
|
145
|
+
# Override and return <tt>false</tt> if you want to bypass security check.
|
146
|
+
#
|
147
|
+
# @since 0.4.0
|
148
|
+
def verify_csrf_token?
|
149
|
+
!IDEMPOTENT_HTTP_METHODS[request_method]
|
150
|
+
end
|
151
|
+
|
152
|
+
# Handle CSRF attack.
|
153
|
+
#
|
154
|
+
# The default policy resets the session and raises an exception.
|
155
|
+
#
|
156
|
+
# Override this method, for custom handling.
|
157
|
+
#
|
158
|
+
# @raise [Lotus::Action::InvalidCSRFTokenError]
|
159
|
+
#
|
160
|
+
# @since 0.4.0
|
161
|
+
def handle_invalid_csrf_token
|
162
|
+
session.clear
|
163
|
+
raise InvalidCSRFTokenError.new
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/lib/lotus/application.rb
CHANGED
@@ -2,6 +2,7 @@ require 'lotus/utils/class_attribute'
|
|
2
2
|
require 'lotus/frameworks'
|
3
3
|
require 'lotus/configuration'
|
4
4
|
require 'lotus/loader'
|
5
|
+
require 'lotus/logger'
|
5
6
|
require 'lotus/rendering_policy'
|
6
7
|
require 'lotus/middleware'
|
7
8
|
|
@@ -105,7 +106,8 @@ module Lotus
|
|
105
106
|
# @return [Lotus::Application] a new instance of the application
|
106
107
|
#
|
107
108
|
# @since 0.1.0
|
108
|
-
def initialize
|
109
|
+
def initialize(options = {})
|
110
|
+
self.class.configuration.path_prefix options[:path_prefix]
|
109
111
|
self.class.load!(self)
|
110
112
|
end
|
111
113
|
|
data/lib/lotus/cli.rb
CHANGED
@@ -61,14 +61,14 @@ module Lotus
|
|
61
61
|
end
|
62
62
|
|
63
63
|
desc 'new', 'generates a new application'
|
64
|
-
method_option :database,
|
65
|
-
method_option :architecture,
|
66
|
-
method_option :application,
|
67
|
-
method_option :application_base_url,
|
68
|
-
method_option :path,
|
69
|
-
method_option :test,
|
70
|
-
method_option :lotus_head,
|
71
|
-
method_option :help,
|
64
|
+
method_option :database, aliases: '-d', desc: 'application database', type: :string, default: 'filesystem'
|
65
|
+
method_option :architecture, aliases: ['-a', '--arch'], desc: 'application architecture', type: :string, default: 'container'
|
66
|
+
method_option :application, desc: 'application name', type: :string, default: 'web'
|
67
|
+
method_option :application_base_url, desc: 'application base url', type: :string, default: '/'
|
68
|
+
method_option :path, desc: 'path', type: :string
|
69
|
+
method_option :test, desc: 'application test framework (rspec/minitest)', type: :string, default: 'minitest'
|
70
|
+
method_option :lotus_head, desc: 'use Lotus HEAD', type: :boolean, default: false
|
71
|
+
method_option :help, aliases: '-h', desc: 'displays the usage method'
|
72
72
|
|
73
73
|
def new(name = nil)
|
74
74
|
if options[:help] || name.nil?
|
@@ -79,11 +79,12 @@ module Lotus
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
desc 'generate', 'generates
|
83
|
-
method_option :application_base_url, desc: 'application base url',
|
84
|
-
method_option :path,
|
85
|
-
method_option :
|
86
|
-
method_option :
|
82
|
+
desc 'generate', 'generates action, model or migration'
|
83
|
+
method_option :application_base_url, desc: 'application base url', type: :string
|
84
|
+
method_option :path, desc: 'applications path', type: :string
|
85
|
+
method_option :url, desc: 'relative URL for action', type: :string
|
86
|
+
method_option :skip_view, desc: 'skip the creation of view and templates (only for action)', type: :boolean, default: false
|
87
|
+
method_option :help, aliases: '-h', desc: 'displays the usage method'
|
87
88
|
|
88
89
|
# @since 0.3.0
|
89
90
|
# @api private
|
@@ -24,7 +24,7 @@ module Lotus
|
|
24
24
|
def start
|
25
25
|
# Clear out ARGV so Pry/IRB don't attempt to parse the rest
|
26
26
|
ARGV.shift until ARGV.empty?
|
27
|
-
|
27
|
+
@environment.require_application_environment
|
28
28
|
|
29
29
|
# Add convenience methods to the main:Object binding
|
30
30
|
TOPLEVEL_BINDING.eval('self').send(:include, Methods)
|
data/lib/lotus/commands/db.rb
CHANGED
@@ -17,11 +17,113 @@ module Lotus
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
desc 'db create', 'create database'
|
21
|
+
|
22
|
+
desc 'create', 'create database for current environment'
|
23
|
+
method_option :environment, desc: 'path to environment configuration (config/environment.rb)'
|
24
|
+
|
25
|
+
def create
|
26
|
+
if options[:help]
|
27
|
+
invoke :help, ['create']
|
28
|
+
else
|
29
|
+
assert_allowed_environment!
|
30
|
+
require 'lotus/commands/db/create'
|
31
|
+
Lotus::Commands::DB::Create.new(environment).start
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'db drop', 'drop database'
|
36
|
+
|
37
|
+
desc 'drop', 'drop database for current environment'
|
38
|
+
method_option :environment, desc: 'path to environment configuration (config/environment.rb)'
|
39
|
+
|
40
|
+
def drop
|
41
|
+
if options[:help]
|
42
|
+
invoke :help, ['drop']
|
43
|
+
else
|
44
|
+
assert_allowed_environment!
|
45
|
+
require 'lotus/commands/db/drop'
|
46
|
+
Lotus::Commands::DB::Drop.new(environment).start
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'db migrate', 'migrate database'
|
51
|
+
|
52
|
+
desc 'migrate', 'migrate database for current environment'
|
53
|
+
method_option :environment, desc: 'path to environment configuration (config/environment.rb)'
|
54
|
+
|
55
|
+
def migrate(version = nil)
|
56
|
+
if options[:help]
|
57
|
+
invoke :help, ['migrate']
|
58
|
+
else
|
59
|
+
require 'lotus/commands/db/migrate'
|
60
|
+
Lotus::Commands::DB::Migrate.new(environment, version).start
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc 'db apply', 'apply database changes'
|
65
|
+
|
66
|
+
desc 'apply', 'migrate, dump schema, delete migrations (experimental)'
|
67
|
+
method_option :environment, desc: 'path to environment configuration (config/environment.rb)'
|
68
|
+
|
69
|
+
def apply
|
70
|
+
if options[:help]
|
71
|
+
invoke :help, ['apply']
|
72
|
+
else
|
73
|
+
assert_development_environment!
|
74
|
+
require 'lotus/commands/db/apply'
|
75
|
+
Lotus::Commands::DB::Apply.new(environment).start
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
desc 'db prepare', 'prepare database'
|
80
|
+
|
81
|
+
desc 'prepare', 'create and migrate database'
|
82
|
+
method_option :environment, desc: 'path to environment configuration (config/environment.rb)'
|
83
|
+
|
84
|
+
def prepare
|
85
|
+
if options[:help]
|
86
|
+
invoke :help, ['prepare']
|
87
|
+
else
|
88
|
+
assert_allowed_environment!
|
89
|
+
require 'lotus/commands/db/prepare'
|
90
|
+
Lotus::Commands::DB::Prepare.new(environment).start
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
desc 'db version', 'database version'
|
95
|
+
|
96
|
+
desc 'version', 'current database version'
|
97
|
+
method_option :environment, desc: 'path to environment configuration (config/environment.rb)'
|
98
|
+
|
99
|
+
def version
|
100
|
+
if options[:help]
|
101
|
+
invoke :help, ['version']
|
102
|
+
else
|
103
|
+
require 'lotus/commands/db/version'
|
104
|
+
Lotus::Commands::DB::Version.new(environment).start
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
20
108
|
private
|
21
109
|
|
22
110
|
def environment
|
23
111
|
Lotus::Environment.new(options)
|
24
112
|
end
|
113
|
+
|
114
|
+
def assert_allowed_environment!
|
115
|
+
if environment.environment?(:production)
|
116
|
+
puts "Can't run this command in production mode"
|
117
|
+
exit 1
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def assert_development_environment!
|
122
|
+
unless environment.environment?(:development)
|
123
|
+
puts "This command can be ran only in development mode"
|
124
|
+
exit 1
|
125
|
+
end
|
126
|
+
end
|
25
127
|
end
|
26
128
|
end
|
27
129
|
end
|
@@ -10,7 +10,7 @@ module Lotus
|
|
10
10
|
@name = name
|
11
11
|
@environment = environment
|
12
12
|
@env_options = environment.to_options
|
13
|
-
|
13
|
+
@environment.require_application_environment
|
14
14
|
end
|
15
15
|
|
16
16
|
def start
|
@@ -44,10 +44,6 @@ module Lotus
|
|
44
44
|
def connection_string
|
45
45
|
adapter_class.new(mapper, adapter_config.uri).connection_string
|
46
46
|
end
|
47
|
-
|
48
|
-
def load_config
|
49
|
-
require @env_options[:env_config]
|
50
|
-
end
|
51
47
|
end
|
52
48
|
end
|
53
49
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'lotus/commands/db/abstract'
|
2
|
+
|
3
|
+
module Lotus
|
4
|
+
module Commands
|
5
|
+
class DB
|
6
|
+
class Migrate < Abstract
|
7
|
+
def initialize(environment, version)
|
8
|
+
super(environment)
|
9
|
+
@version = version
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
require 'lotus/model/migrator'
|
14
|
+
Lotus::Model::Migrator.migrate(version: @version)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|