command_tower 0.3.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +59 -0
- data/Rakefile +32 -0
- data/app/controllers/command_tower/admin_controller.rb +104 -0
- data/app/controllers/command_tower/application_controller.rb +81 -0
- data/app/controllers/command_tower/auth/plain_text_controller.rb +132 -0
- data/app/controllers/command_tower/inbox/message_blast_controller.rb +89 -0
- data/app/controllers/command_tower/inbox/message_controller.rb +79 -0
- data/app/controllers/command_tower/user_controller.rb +49 -0
- data/app/controllers/command_tower/username_controller.rb +26 -0
- data/app/helpers/command_tower/application_helper.rb +4 -0
- data/app/helpers/command_tower/schema_helper.rb +29 -0
- data/app/jobs/command_tower/application_job.rb +4 -0
- data/app/mailers/command_tower/application_mailer.rb +8 -0
- data/app/mailers/command_tower/email_verification_mailer.rb +12 -0
- data/app/models/command_tower/application_record.rb +45 -0
- data/app/models/message.rb +30 -0
- data/app/models/message_blast.rb +27 -0
- data/app/models/user.rb +61 -0
- data/app/models/user_secret.rb +72 -0
- data/app/services/command_tower/README.md +49 -0
- data/app/services/command_tower/argument_validation/README.md +192 -0
- data/app/services/command_tower/argument_validation/class_methods.rb +178 -0
- data/app/services/command_tower/argument_validation/instance_methods.rb +148 -0
- data/app/services/command_tower/argument_validation.rb +11 -0
- data/app/services/command_tower/authorize/validate.rb +49 -0
- data/app/services/command_tower/inbox_service/blast/delete.rb +23 -0
- data/app/services/command_tower/inbox_service/blast/metadata.rb +26 -0
- data/app/services/command_tower/inbox_service/blast/new_user_blaster.rb +24 -0
- data/app/services/command_tower/inbox_service/blast/retrieve.rb +30 -0
- data/app/services/command_tower/inbox_service/blast/upsert.rb +67 -0
- data/app/services/command_tower/inbox_service/message/metadata.rb +35 -0
- data/app/services/command_tower/inbox_service/message/modify.rb +44 -0
- data/app/services/command_tower/inbox_service/message/retrieve.rb +36 -0
- data/app/services/command_tower/inbox_service/message/send.rb +33 -0
- data/app/services/command_tower/jwt/authenticate_user.rb +86 -0
- data/app/services/command_tower/jwt/decode.rb +21 -0
- data/app/services/command_tower/jwt/encode.rb +15 -0
- data/app/services/command_tower/jwt/login_create.rb +21 -0
- data/app/services/command_tower/jwt/time_delay_token.rb +17 -0
- data/app/services/command_tower/login_strategy/plain_text/create.rb +43 -0
- data/app/services/command_tower/login_strategy/plain_text/email_verification/generate.rb +29 -0
- data/app/services/command_tower/login_strategy/plain_text/email_verification/required.rb +20 -0
- data/app/services/command_tower/login_strategy/plain_text/email_verification/send.rb +23 -0
- data/app/services/command_tower/login_strategy/plain_text/email_verification/verify.rb +24 -0
- data/app/services/command_tower/login_strategy/plain_text/login.rb +50 -0
- data/app/services/command_tower/secrets/cleanse.rb +14 -0
- data/app/services/command_tower/secrets/generate.rb +62 -0
- data/app/services/command_tower/secrets/verify.rb +27 -0
- data/app/services/command_tower/secrets.rb +15 -0
- data/app/services/command_tower/service_base.rb +89 -0
- data/app/services/command_tower/service_logging.rb +41 -0
- data/app/services/command_tower/user_attributes/modify.rb +68 -0
- data/app/services/command_tower/user_attributes/roles.rb +27 -0
- data/app/services/command_tower/username/available.rb +64 -0
- data/app/views/command_tower/email_verification_mailer/verify_email.html.erb +26 -0
- data/config/routes.rb +55 -0
- data/db/migrate/20241117043720_create_command_tower_users.rb +42 -0
- data/db/migrate/20241204065708_create_command_tower_user_secrets.rb +16 -0
- data/db/migrate/20250223023306_create_command_tower_messages.rb +12 -0
- data/db/migrate/20250223023313_create_command_tower_message_blasts.rb +14 -0
- data/lib/command_tower/authorization/default.yml +42 -0
- data/lib/command_tower/authorization/entity.rb +101 -0
- data/lib/command_tower/authorization/role.rb +101 -0
- data/lib/command_tower/authorization.rb +85 -0
- data/lib/command_tower/configuration/admin/config.rb +18 -0
- data/lib/command_tower/configuration/application/config.rb +40 -0
- data/lib/command_tower/configuration/authorization/config.rb +24 -0
- data/lib/command_tower/configuration/base.rb +11 -0
- data/lib/command_tower/configuration/config.rb +77 -0
- data/lib/command_tower/configuration/email/config.rb +87 -0
- data/lib/command_tower/configuration/jwt/config.rb +22 -0
- data/lib/command_tower/configuration/login/config.rb +18 -0
- data/lib/command_tower/configuration/login/strategy/plain_text/config.rb +57 -0
- data/lib/command_tower/configuration/login/strategy/plain_text/email_verify.rb +50 -0
- data/lib/command_tower/configuration/login/strategy/plain_text/lockable.rb +27 -0
- data/lib/command_tower/configuration/otp/config.rb +54 -0
- data/lib/command_tower/configuration/user/config.rb +56 -0
- data/lib/command_tower/configuration/username/check.rb +31 -0
- data/lib/command_tower/configuration/username/config.rb +41 -0
- data/lib/command_tower/engine.rb +53 -0
- data/lib/command_tower/error.rb +5 -0
- data/lib/command_tower/schema/admin/users.rb +15 -0
- data/lib/command_tower/schema/error/base.rb +15 -0
- data/lib/command_tower/schema/error/invalid_argument.rb +15 -0
- data/lib/command_tower/schema/error/invalid_argument_response.rb +17 -0
- data/lib/command_tower/schema/inbox/blast_request.rb +15 -0
- data/lib/command_tower/schema/inbox/blast_response.rb +16 -0
- data/lib/command_tower/schema/inbox/message_blast_entity.rb +16 -0
- data/lib/command_tower/schema/inbox/message_blast_metadata.rb +16 -0
- data/lib/command_tower/schema/inbox/message_entity.rb +14 -0
- data/lib/command_tower/schema/inbox/metadata.rb +18 -0
- data/lib/command_tower/schema/inbox/modified.rb +13 -0
- data/lib/command_tower/schema/page.rb +14 -0
- data/lib/command_tower/schema/plain_text/create_user_request.rb +18 -0
- data/lib/command_tower/schema/plain_text/create_user_response.rb +17 -0
- data/lib/command_tower/schema/plain_text/email_verify_request.rb +11 -0
- data/lib/command_tower/schema/plain_text/email_verify_response.rb +11 -0
- data/lib/command_tower/schema/plain_text/email_verify_send_request.rb +9 -0
- data/lib/command_tower/schema/plain_text/email_verify_send_response.rb +11 -0
- data/lib/command_tower/schema/plain_text/login_request.rb +15 -0
- data/lib/command_tower/schema/plain_text/login_response.rb +13 -0
- data/lib/command_tower/schema/user.rb +28 -0
- data/lib/command_tower/schema.rb +38 -0
- data/lib/command_tower/spec_helper.rb +19 -0
- data/lib/command_tower/version.rb +5 -0
- data/lib/command_tower.rb +33 -0
- data/lib/generators/api_engine_base/configure/USAGE +8 -0
- data/lib/generators/api_engine_base/configure/configure_generator.rb +12 -0
- data/lib/tasks/auto_annotate_models.rake +60 -0
- metadata +255 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "class_composer"
|
4
|
+
|
5
|
+
module CommandTower
|
6
|
+
module Configuration
|
7
|
+
module Application
|
8
|
+
class Config
|
9
|
+
include ClassComposer::Generator
|
10
|
+
|
11
|
+
add_composer :app_name,
|
12
|
+
allowed: String,
|
13
|
+
dynamic_default: ->(_) { CommandTower.default_app_name },
|
14
|
+
desc: "The default name of the application",
|
15
|
+
default_shown: "# Auto Populates to the name of the application"
|
16
|
+
|
17
|
+
add_composer :communication_name,
|
18
|
+
allowed: String,
|
19
|
+
dynamic_default: :app_name,
|
20
|
+
desc: "The name of the application to use in communications like SMS or Email"
|
21
|
+
|
22
|
+
add_composer :url,
|
23
|
+
allowed: String,
|
24
|
+
default: ENV.fetch("command_tower_URL", "http://localhost"),
|
25
|
+
desc: "When composing SSO's or verification URL's, this is the URL for the application"
|
26
|
+
|
27
|
+
add_composer :port,
|
28
|
+
allowed: [String, NilClass],
|
29
|
+
default: ENV.fetch("command_tower_PORT", nil),
|
30
|
+
desc: "When composing SSO's or verification URL's, this is the PORT for the application"
|
31
|
+
|
32
|
+
add_composer :composed_url,
|
33
|
+
allowed: String,
|
34
|
+
dynamic_default: ->(instance) { "#{instance.url}#{ ":#{instance.port}" if instance.port }" },
|
35
|
+
desc: "The fully composed URL including the port number when needed. This Config variable is not needed as it is composed of the `url` and `port` composed values",
|
36
|
+
default_shown: "# Composed String of the URL and PORT. Override this with caution"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "class_composer"
|
4
|
+
|
5
|
+
module CommandTower
|
6
|
+
module Configuration
|
7
|
+
module Authorization
|
8
|
+
class Config
|
9
|
+
include ClassComposer::Generator
|
10
|
+
|
11
|
+
add_composer :rbac_default_groups,
|
12
|
+
desc: "The default Group Roles defined by this engine.",
|
13
|
+
allowed: [TrueClass, FalseClass],
|
14
|
+
default: true
|
15
|
+
|
16
|
+
add_composer :rbac_group_path,
|
17
|
+
desc: "If defined, this config points to the users YAML file defining RBAC group roles.",
|
18
|
+
allowed: String,
|
19
|
+
dynamic_default: ->(_) { Rails.root.join("config","rbac_groups.yml").to_s },
|
20
|
+
default_shown: "Rails.root.join(\"config\",\"rbac_groups.yml\")"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
require "class_composer"
|
5
|
+
require "command_tower/configuration/base"
|
6
|
+
require "command_tower/configuration/email/config"
|
7
|
+
require "command_tower/configuration/jwt/config"
|
8
|
+
require "command_tower/configuration/login/config"
|
9
|
+
require "command_tower/configuration/otp/config"
|
10
|
+
require "command_tower/configuration/username/config"
|
11
|
+
require "command_tower/configuration/application/config"
|
12
|
+
require "command_tower/configuration/admin/config"
|
13
|
+
require "command_tower/configuration/authorization/config"
|
14
|
+
require "command_tower/configuration/user/config"
|
15
|
+
|
16
|
+
module CommandTower
|
17
|
+
module Configuration
|
18
|
+
class Config < ::CommandTower::Configuration::Base
|
19
|
+
include ClassComposer::Generator
|
20
|
+
|
21
|
+
add_composer :delete_secret_after_invalid,
|
22
|
+
desc: "Remove Secret after it is found as invalid",
|
23
|
+
allowed: [TrueClass, FalseClass],
|
24
|
+
default: true
|
25
|
+
|
26
|
+
add_composer :jwt,
|
27
|
+
desc: "JWT is the basis for Authorization and Authentication for this Engine. HMAC is the only support algorithm",
|
28
|
+
allowed: Configuration::Jwt::Config,
|
29
|
+
default: Configuration::Jwt::Config.new
|
30
|
+
|
31
|
+
add_composer :login,
|
32
|
+
desc: "Definition of Login Strategies.",
|
33
|
+
allowed: Configuration::Login::Config,
|
34
|
+
default: Configuration::Login::Config.new
|
35
|
+
|
36
|
+
add_composer :email,
|
37
|
+
desc: "Email configuration for the app sending Native Rails emails via ActiveMailer. Config changed here will update the Rails Configuration as well",
|
38
|
+
allowed: Configuration::Email::Config,
|
39
|
+
default: Configuration::Email::Config.new
|
40
|
+
|
41
|
+
add_composer :username,
|
42
|
+
desc: "Username configuration for the app",
|
43
|
+
allowed: Configuration::Username::Config,
|
44
|
+
default: Configuration::Username::Config.new
|
45
|
+
|
46
|
+
add_composer :application,
|
47
|
+
desc: "General configurations for the application. Primarily include application specific names, URL's, etc",
|
48
|
+
allowed: Configuration::Application::Config,
|
49
|
+
default: Configuration::Application::Config.new
|
50
|
+
|
51
|
+
# allow shorthand to be used
|
52
|
+
alias_method :app, :application
|
53
|
+
|
54
|
+
add_composer :authorization,
|
55
|
+
desc: "Authorization via rbac configurations",
|
56
|
+
allowed: Configuration::Authorization::Config,
|
57
|
+
default: Configuration::Authorization::Config.new
|
58
|
+
|
59
|
+
add_composer :user,
|
60
|
+
desc: "User configuration for the app. Includes what to display and what attributes can be changed",
|
61
|
+
allowed: Configuration::User::Config,
|
62
|
+
default: Configuration::User::Config.new
|
63
|
+
|
64
|
+
add_composer :admin,
|
65
|
+
desc: "Admin configuration for the app",
|
66
|
+
allowed: Configuration::Admin::Config,
|
67
|
+
default: Configuration::Admin::Config.new
|
68
|
+
|
69
|
+
# To be Deleted
|
70
|
+
add_composer :otp,
|
71
|
+
desc: "One Time Password generation is used for ease in quickly validating a users actions. This is good for short term validation requirements as opposed to UserSecrets",
|
72
|
+
allowed: Configuration::Otp::Config,
|
73
|
+
default: Configuration::Otp::Config.new
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CommandTower
|
4
|
+
module Configuration
|
5
|
+
module Email
|
6
|
+
class Config < ::CommandTower::Configuration::Base
|
7
|
+
include ClassComposer::Generator
|
8
|
+
|
9
|
+
ASSIGNMENT = Proc.new do |key, value|
|
10
|
+
hash = Rails.configuration.action_mailer.smtp_settings ||= {}
|
11
|
+
Rails.configuration.action_mailer.smtp_settings = hash.merge({key => value})
|
12
|
+
end
|
13
|
+
|
14
|
+
ACTION_MAILER = Proc.new do |key, value|
|
15
|
+
Rails.configuration.action_mailer.public_send(:"#{key}=", value)
|
16
|
+
end
|
17
|
+
|
18
|
+
add_composer :user_name,
|
19
|
+
desc: "User Name for email. Defaults to ENV['GMAIL_USER_NAME']",
|
20
|
+
allowed: String,
|
21
|
+
default: ENV.fetch("GMAIL_USER_NAME", ""),
|
22
|
+
default_shown: "ENV[\"GMAIL_USER_NAME\"]",
|
23
|
+
&ASSIGNMENT
|
24
|
+
|
25
|
+
add_composer :password,
|
26
|
+
desc: "Password for email. Defaults to ENV['GMAIL_PASSWORD']. For more info on how to get this for GMAIL...https://support.google.com/accounts/answer/185833",
|
27
|
+
allowed: String,
|
28
|
+
default: ENV.fetch("GMAIL_PASSWORD", ""),
|
29
|
+
default_shown: "ENV[\"GMAIL_PASSWORD\"]",
|
30
|
+
&ASSIGNMENT
|
31
|
+
|
32
|
+
add_composer :port,
|
33
|
+
allowed: Integer,
|
34
|
+
default: 587,
|
35
|
+
&ASSIGNMENT
|
36
|
+
|
37
|
+
add_composer :address,
|
38
|
+
desc: "SMTP address for email. Defaults to smtp.gmail.com",
|
39
|
+
allowed: String,
|
40
|
+
default: "smtp.gmail.com",
|
41
|
+
&ASSIGNMENT
|
42
|
+
|
43
|
+
add_composer :authentication,
|
44
|
+
desc: "Authentication type for email",
|
45
|
+
allowed: String,
|
46
|
+
default: "plain",
|
47
|
+
&ASSIGNMENT
|
48
|
+
|
49
|
+
add_composer :enable_starttls_auto,
|
50
|
+
allowed: [TrueClass, FalseClass],
|
51
|
+
default: true,
|
52
|
+
&ASSIGNMENT
|
53
|
+
|
54
|
+
add_composer :delivery_method,
|
55
|
+
allowed: Symbol,
|
56
|
+
default: Rails.env.test? ? :test : :smtp,
|
57
|
+
&ACTION_MAILER
|
58
|
+
|
59
|
+
add_composer :perform_deliveries,
|
60
|
+
allowed: [TrueClass, FalseClass],
|
61
|
+
default: true,
|
62
|
+
&ACTION_MAILER
|
63
|
+
|
64
|
+
add_composer :raise_delivery_errors,
|
65
|
+
allowed: [TrueClass, FalseClass],
|
66
|
+
default: true,
|
67
|
+
&ACTION_MAILER
|
68
|
+
|
69
|
+
def gmail!(
|
70
|
+
from: ENV["GMAIL_USER_NAME"],
|
71
|
+
password: ENV["GMAIL_PASSWORD"],
|
72
|
+
port: 587,
|
73
|
+
address: "smtp.gmail.com",
|
74
|
+
authentication: "plain",
|
75
|
+
enable_starttls_auto: true
|
76
|
+
)
|
77
|
+
method(:from=).call(from)
|
78
|
+
method(:password=).call(password)
|
79
|
+
method(:port=).call(port)
|
80
|
+
method(:address=).call(address)
|
81
|
+
method(:authentication=).call(authentication)
|
82
|
+
method(:enable_starttls_auto=).call(enable_starttls_auto)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CommandTower
|
4
|
+
module Configuration
|
5
|
+
module Jwt
|
6
|
+
class Config < ::CommandTower::Configuration::Base
|
7
|
+
include ClassComposer::Generator
|
8
|
+
|
9
|
+
add_composer :ttl,
|
10
|
+
desc: "Default TTL on how long the token is valid for",
|
11
|
+
allowed: ActiveSupport::Duration,
|
12
|
+
default: 7.days
|
13
|
+
|
14
|
+
add_composer :hmac_secret,
|
15
|
+
desc: "HMAC is the only algorithm supported. This is the secret key to encrypt he JWT token",
|
16
|
+
allowed: String,
|
17
|
+
default: ENV.fetch("SECRET_KEY_BASE","Thi$IsASeccretIwi::CH&ang3"),
|
18
|
+
default_shown: "ENV.fetch(\"SECRET_KEY_BASE\",\"Thi$IsASeccretIwi::CH&ang3\")"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "command_tower/configuration/login/strategy/plain_text/config"
|
4
|
+
|
5
|
+
module CommandTower
|
6
|
+
module Configuration
|
7
|
+
module Login
|
8
|
+
class Config < ::CommandTower::Configuration::Base
|
9
|
+
include ClassComposer::Generator
|
10
|
+
|
11
|
+
add_composer_blocking :plain_text,
|
12
|
+
desc: "Login strategy for plain text authentication via User/Password combination",
|
13
|
+
composer_class: Strategy::PlainText::Config,
|
14
|
+
enable_attr: :enable
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "command_tower/configuration/login/strategy/plain_text/lockable"
|
4
|
+
require "command_tower/configuration/login/strategy/plain_text/email_verify"
|
5
|
+
|
6
|
+
module CommandTower
|
7
|
+
module Configuration
|
8
|
+
module Login
|
9
|
+
module Strategy
|
10
|
+
module PlainText
|
11
|
+
class Config < ::CommandTower::Configuration::Base
|
12
|
+
include ClassComposer::Generator
|
13
|
+
|
14
|
+
add_composer :enable,
|
15
|
+
desc: "Login Strategy for User/Password. By default, this is enabled",
|
16
|
+
allowed: [FalseClass, TrueClass],
|
17
|
+
default: true
|
18
|
+
|
19
|
+
add_composer_blocking :lockable,
|
20
|
+
desc: "Enable and change Lockable for User/Password Login strategy.",
|
21
|
+
composer_class: Locakable,
|
22
|
+
enable_attr: :enable
|
23
|
+
|
24
|
+
add_composer_blocking :email_verify,
|
25
|
+
desc: "Enable and change Email Verification for User/Password Login strategy.",
|
26
|
+
composer_class: EmailVerify,
|
27
|
+
enable_attr: :enable
|
28
|
+
|
29
|
+
add_composer :password_length_max,
|
30
|
+
desc: "Max Length for Password",
|
31
|
+
allowed: Integer,
|
32
|
+
default: 64
|
33
|
+
|
34
|
+
add_composer :password_length_min,
|
35
|
+
desc: "Min Length for Password",
|
36
|
+
allowed: Integer,
|
37
|
+
default: 8
|
38
|
+
|
39
|
+
add_composer :email_length_max,
|
40
|
+
desc: "Max Length for Email",
|
41
|
+
allowed: Integer,
|
42
|
+
default: 64
|
43
|
+
|
44
|
+
add_composer :email_length_min,
|
45
|
+
desc: "Min Length for Email",
|
46
|
+
allowed: Integer,
|
47
|
+
default: 8
|
48
|
+
|
49
|
+
def enable?
|
50
|
+
enable
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CommandTower
|
4
|
+
module Configuration
|
5
|
+
module Login
|
6
|
+
module Strategy
|
7
|
+
module PlainText
|
8
|
+
class EmailVerify < ::CommandTower::Configuration::Base
|
9
|
+
include ClassComposer::Generator
|
10
|
+
|
11
|
+
add_composer :enable,
|
12
|
+
desc: "Email Verify will help ensure that users emails are valid by requesting a verify code. By default this is enabled",
|
13
|
+
allowed: [FalseClass, TrueClass],
|
14
|
+
default: true
|
15
|
+
|
16
|
+
add_composer :verify_email_required_within,
|
17
|
+
desc: "Strategy allows user to set time before email verification is required. After time has expired, usage of API is no longer valid until email has been verified. Up until this time, the Login Strategy will allow usage of the API. Default time is set to 0 minutes",
|
18
|
+
allowed: ActiveSupport::Duration,
|
19
|
+
default: 0.minutes,
|
20
|
+
validator: -> (val) { val < 10.days },
|
21
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than #{10.days}" }
|
22
|
+
|
23
|
+
|
24
|
+
add_composer :verify_code_link_required_within,
|
25
|
+
desc: "When the email verification is sent, how long will that code be valid for. By default, this is set to 10 minutes",
|
26
|
+
allowed: ActiveSupport::Duration,
|
27
|
+
default: 10.minutes,
|
28
|
+
validator: -> (val) { val < 60.minutes },
|
29
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than #{60.minutes}" }
|
30
|
+
|
31
|
+
|
32
|
+
add_composer :verify_code_link_valid_for,
|
33
|
+
desc: "When the email verification is sent, how long will that code be valid for. By default, this is set to 10 minutes",
|
34
|
+
allowed: ActiveSupport::Duration,
|
35
|
+
default: 10.minutes,
|
36
|
+
validator: -> (val) { val < 60.minutes },
|
37
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than #{60.minutes}" }
|
38
|
+
|
39
|
+
add_composer :verify_code_length,
|
40
|
+
desc: "The length of the verify code sent via email.",
|
41
|
+
allowed: Integer,
|
42
|
+
default: 6,
|
43
|
+
validator: -> (val) { (val <= 10) && (val >= 4) },
|
44
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than or equal to 10 and greater than or equal to 4." }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CommandTower
|
4
|
+
module Configuration
|
5
|
+
module Login
|
6
|
+
module Strategy
|
7
|
+
module PlainText
|
8
|
+
class Locakable < ::CommandTower::Configuration::Base
|
9
|
+
include ClassComposer::Generator
|
10
|
+
|
11
|
+
add_composer :enable,
|
12
|
+
desc: "Disabled by default. When enabled, this adds an additional level of support for brute force attacks on User/Password Logins",
|
13
|
+
allowed: [FalseClass, TrueClass],
|
14
|
+
default: false
|
15
|
+
|
16
|
+
add_composer :password_attempts,
|
17
|
+
desc: "Max failed password attempts before additional verification on account is required.",
|
18
|
+
allowed: Integer,
|
19
|
+
default: 10,
|
20
|
+
validator: -> (val) { val >= 0 && val < 50 },
|
21
|
+
invalid_message: ->(val) { "Max password attempts must be >=0 and less than 50. Received #{val}" }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "class_composer"
|
4
|
+
|
5
|
+
module CommandTower
|
6
|
+
module Configuration
|
7
|
+
module Otp
|
8
|
+
class Config
|
9
|
+
include ClassComposer::Generator
|
10
|
+
|
11
|
+
add_composer :default_code_interval,
|
12
|
+
desc: "The length of time a code is good for",
|
13
|
+
allowed: ActiveSupport::Duration,
|
14
|
+
default: 30.seconds,
|
15
|
+
validator: -> (val) { (val <= 5.minutes) && (val >= 30.seconds) }
|
16
|
+
|
17
|
+
add_composer :default_code_length,
|
18
|
+
desc: "The default length of the OTP. Used when one not provided",
|
19
|
+
allowed: Integer,
|
20
|
+
default: 6,
|
21
|
+
validator: -> (val) { (val <= 10) && (val >= 4) },
|
22
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than or equal to 10 and greater than or equal to 4." }
|
23
|
+
|
24
|
+
add_composer :secret_code_length,
|
25
|
+
desc: "The size of each users base32 Secret value generated",
|
26
|
+
allowed: Integer,
|
27
|
+
default: 32,
|
28
|
+
validator: -> (val) { (val <= 128) && (val >= 32) },
|
29
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than or equal to 128 and greater than or equal to 32." }
|
30
|
+
|
31
|
+
add_composer :backup_code_length,
|
32
|
+
desc: "The length of each backup code for User",
|
33
|
+
allowed: Integer,
|
34
|
+
default: 32,
|
35
|
+
validator: -> (val) { (val <= 64) && (val >= 10) },
|
36
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than or equal to 64 and greater than or equal to 20." }
|
37
|
+
|
38
|
+
add_composer :backup_code_count,
|
39
|
+
desc: "The number of backup codes that get generated",
|
40
|
+
allowed: Integer,
|
41
|
+
default: 10,
|
42
|
+
validator: -> (val) { (val <= 10) && (val >= 2) },
|
43
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than or equal to 10 and greater than or equal to 2." }
|
44
|
+
|
45
|
+
add_composer :allowed_drift_behind,
|
46
|
+
desc: "Sometimes a user is just a tad slow. This allows a small drift behind to allow codes within drift to be accepted",
|
47
|
+
allowed: ActiveSupport::Duration,
|
48
|
+
default: 15.seconds,
|
49
|
+
validator: -> (val) { (val <= 15.seconds) && (val >= 0.seconds) },
|
50
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than or equal to 15.seconds" }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "class_composer"
|
4
|
+
|
5
|
+
module CommandTower
|
6
|
+
module Configuration
|
7
|
+
module User
|
8
|
+
class Config
|
9
|
+
include ClassComposer::Generator
|
10
|
+
|
11
|
+
ATTRIBUTES_TO_CHANGE = [
|
12
|
+
:email,
|
13
|
+
:first_name,
|
14
|
+
:last_name,
|
15
|
+
:last_known_timezone,
|
16
|
+
:username,
|
17
|
+
:verifier_token,
|
18
|
+
]
|
19
|
+
|
20
|
+
ATTRIBUTES_TO_SHOW = [
|
21
|
+
*ATTRIBUTES_TO_CHANGE,
|
22
|
+
:id,
|
23
|
+
:roles,
|
24
|
+
:created_at,
|
25
|
+
]
|
26
|
+
|
27
|
+
ATTRIBUTES_CHANGE_EXECUTE = Proc.new do |key, value|
|
28
|
+
CommandTower::UserAttributes::Modify.assign!
|
29
|
+
end
|
30
|
+
|
31
|
+
ATTRIBUTES_SHOWN_EXECUTE = Proc.new do |key, value|
|
32
|
+
CommandTower::Schema::User.assign!
|
33
|
+
end
|
34
|
+
|
35
|
+
add_composer :additional_attributes_for_change,
|
36
|
+
desc: "On top of the default attributes to change, this adds additional values for the user to change on their account",
|
37
|
+
allowed: Array,
|
38
|
+
default: [],
|
39
|
+
default_shown: "[]"
|
40
|
+
|
41
|
+
add_composer :default_attributes_for_change,
|
42
|
+
desc: "[Not Recommended for change] Default attributes that are allowed to change",
|
43
|
+
allowed: Array,
|
44
|
+
default: ATTRIBUTES_TO_CHANGE,
|
45
|
+
&ATTRIBUTES_CHANGE_EXECUTE
|
46
|
+
|
47
|
+
add_composer :default_attributes,
|
48
|
+
desc: "[Not Recommended for change] Default attributes that are shown to the user",
|
49
|
+
allowed: Array,
|
50
|
+
default_shown: ATTRIBUTES_TO_SHOW,
|
51
|
+
dynamic_default: -> (instance) { (ATTRIBUTES_TO_SHOW + instance.additional_attributes_for_change).uniq },
|
52
|
+
&ATTRIBUTES_SHOWN_EXECUTE
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "class_composer"
|
4
|
+
|
5
|
+
module CommandTower
|
6
|
+
module Configuration
|
7
|
+
module Username
|
8
|
+
class Check
|
9
|
+
include ClassComposer::Generator
|
10
|
+
|
11
|
+
add_composer :enable,
|
12
|
+
desc: "Enable Controller method for checking Real time username availability",
|
13
|
+
allowed: [FalseClass, TrueClass],
|
14
|
+
default: true
|
15
|
+
|
16
|
+
add_composer :local_cache,
|
17
|
+
desc: "Local Cache store. Instantiated before fork",
|
18
|
+
allowed: [ActiveSupport::Cache::MemoryStore, ActiveSupport::Cache::FileStore],
|
19
|
+
default: ActiveSupport::Cache::MemoryStore.new
|
20
|
+
|
21
|
+
add_composer :local_cache_ttl,
|
22
|
+
desc: "TTL on local cache data before data is invalidated and upstream is queried",
|
23
|
+
allowed: ActiveSupport::Duration,
|
24
|
+
default_shown: "1.minutes",
|
25
|
+
default: 1.minute,
|
26
|
+
validator: -> (val) { val < 60.minutes },
|
27
|
+
invalid_message: ->(val) { "Provided #{val}. Value must be less than #{60.minutes}" }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "class_composer"
|
4
|
+
require "command_tower/configuration/username/check"
|
5
|
+
|
6
|
+
module CommandTower::Configuration
|
7
|
+
module Username
|
8
|
+
class Config
|
9
|
+
include ClassComposer::Generator
|
10
|
+
|
11
|
+
DEFAULT_MAX_LENGTH = 32
|
12
|
+
DEFAULT_MIN_LENGTH = 4
|
13
|
+
|
14
|
+
add_composer_blocking :realtime_username_check,
|
15
|
+
desc: "Adds components to check if the username is available in real time",
|
16
|
+
composer_class: Check,
|
17
|
+
enable_attr: :enable
|
18
|
+
|
19
|
+
add_composer :username_length_min,
|
20
|
+
desc: "Min Length for Username",
|
21
|
+
allowed: Integer,
|
22
|
+
default: DEFAULT_MIN_LENGTH
|
23
|
+
|
24
|
+
add_composer :username_length_max,
|
25
|
+
desc: "Max Length for Username",
|
26
|
+
allowed: Integer,
|
27
|
+
default: DEFAULT_MAX_LENGTH
|
28
|
+
|
29
|
+
add_composer :username_regex,
|
30
|
+
desc: "Regex for username.",
|
31
|
+
allowed: Regexp,
|
32
|
+
default: /\A\w{#{DEFAULT_MIN_LENGTH},#{DEFAULT_MAX_LENGTH}}\z/,
|
33
|
+
default_shown: "Regexp.new(\"/\A\w{#{DEFAULT_MIN_LENGTH},#{DEFAULT_MAX_LENGTH}}\z/\")"
|
34
|
+
|
35
|
+
add_composer :username_failure_message,
|
36
|
+
desc: "Max Length for Username",
|
37
|
+
allowed: String,
|
38
|
+
default: "Username length must be between #{DEFAULT_MIN_LENGTH} and #{DEFAULT_MAX_LENGTH}. Must contain only letters and/or numbers"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "command_tower/authorization"
|
4
|
+
require "command_tower/schema"
|
5
|
+
|
6
|
+
module CommandTower
|
7
|
+
class Engine < ::Rails::Engine
|
8
|
+
isolate_namespace CommandTower
|
9
|
+
|
10
|
+
# Run after Rails loads the initializes and environment files
|
11
|
+
# Ensures User has already set their desired config before we lock this down
|
12
|
+
config.after_initialize do
|
13
|
+
db_rake_task = defined?(Rake) && (Rake.application.top_level_tasks.any? { |task| task =~ /db:/ } rescue nil)
|
14
|
+
if db_rake_task
|
15
|
+
# Because we call the Database during configuration setup,
|
16
|
+
# We want to skip calling the DB during a DB migration
|
17
|
+
else
|
18
|
+
# ensure defaults are instantiated and all variables are assigned
|
19
|
+
CommandTower.config.class_composer_assign_defaults!(children: true)
|
20
|
+
|
21
|
+
unless Rails.env.test?
|
22
|
+
# Now that we can confirm all variables are defined, freeze all objects an their children
|
23
|
+
CommandTower.config.class_composer_freeze_objects!(behavior: :raise, children: true)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
####
|
30
|
+
# Bug: @matt-taylor
|
31
|
+
# RBAC code memoizes the controller object into a class variable
|
32
|
+
# In development when code changes, all classes get reloaded
|
33
|
+
# Inherently, this causes the `object_id` of the class to change
|
34
|
+
# This means the memoized class is no longer equal to the newly reloaded class
|
35
|
+
# NOTE: This is only a problem on reload! in development. Not an issue in Production
|
36
|
+
# Once this is fixed, it can go into a regular initializer and does not need to get re-computed on each reload
|
37
|
+
###
|
38
|
+
# Potential solution:
|
39
|
+
# => Don't store the object as the comparison key
|
40
|
+
# => Or...When doing comparisons, convert everything to a string for comparison
|
41
|
+
# Changes to names should be infrequent/should have a full app restart
|
42
|
+
|
43
|
+
# Add all RBAC based role definitions prior to fork/loading
|
44
|
+
# Load once use forever
|
45
|
+
config.to_prepare do
|
46
|
+
CommandTower::Authorization::Role.roles_reset!
|
47
|
+
CommandTower::Authorization::Entity.entities_reset!
|
48
|
+
CommandTower::Authorization.mapped_controllers_reset!
|
49
|
+
|
50
|
+
CommandTower::Authorization.default_defined!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|