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.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +59 -0
  4. data/Rakefile +32 -0
  5. data/app/controllers/command_tower/admin_controller.rb +104 -0
  6. data/app/controllers/command_tower/application_controller.rb +81 -0
  7. data/app/controllers/command_tower/auth/plain_text_controller.rb +132 -0
  8. data/app/controllers/command_tower/inbox/message_blast_controller.rb +89 -0
  9. data/app/controllers/command_tower/inbox/message_controller.rb +79 -0
  10. data/app/controllers/command_tower/user_controller.rb +49 -0
  11. data/app/controllers/command_tower/username_controller.rb +26 -0
  12. data/app/helpers/command_tower/application_helper.rb +4 -0
  13. data/app/helpers/command_tower/schema_helper.rb +29 -0
  14. data/app/jobs/command_tower/application_job.rb +4 -0
  15. data/app/mailers/command_tower/application_mailer.rb +8 -0
  16. data/app/mailers/command_tower/email_verification_mailer.rb +12 -0
  17. data/app/models/command_tower/application_record.rb +45 -0
  18. data/app/models/message.rb +30 -0
  19. data/app/models/message_blast.rb +27 -0
  20. data/app/models/user.rb +61 -0
  21. data/app/models/user_secret.rb +72 -0
  22. data/app/services/command_tower/README.md +49 -0
  23. data/app/services/command_tower/argument_validation/README.md +192 -0
  24. data/app/services/command_tower/argument_validation/class_methods.rb +178 -0
  25. data/app/services/command_tower/argument_validation/instance_methods.rb +148 -0
  26. data/app/services/command_tower/argument_validation.rb +11 -0
  27. data/app/services/command_tower/authorize/validate.rb +49 -0
  28. data/app/services/command_tower/inbox_service/blast/delete.rb +23 -0
  29. data/app/services/command_tower/inbox_service/blast/metadata.rb +26 -0
  30. data/app/services/command_tower/inbox_service/blast/new_user_blaster.rb +24 -0
  31. data/app/services/command_tower/inbox_service/blast/retrieve.rb +30 -0
  32. data/app/services/command_tower/inbox_service/blast/upsert.rb +67 -0
  33. data/app/services/command_tower/inbox_service/message/metadata.rb +35 -0
  34. data/app/services/command_tower/inbox_service/message/modify.rb +44 -0
  35. data/app/services/command_tower/inbox_service/message/retrieve.rb +36 -0
  36. data/app/services/command_tower/inbox_service/message/send.rb +33 -0
  37. data/app/services/command_tower/jwt/authenticate_user.rb +86 -0
  38. data/app/services/command_tower/jwt/decode.rb +21 -0
  39. data/app/services/command_tower/jwt/encode.rb +15 -0
  40. data/app/services/command_tower/jwt/login_create.rb +21 -0
  41. data/app/services/command_tower/jwt/time_delay_token.rb +17 -0
  42. data/app/services/command_tower/login_strategy/plain_text/create.rb +43 -0
  43. data/app/services/command_tower/login_strategy/plain_text/email_verification/generate.rb +29 -0
  44. data/app/services/command_tower/login_strategy/plain_text/email_verification/required.rb +20 -0
  45. data/app/services/command_tower/login_strategy/plain_text/email_verification/send.rb +23 -0
  46. data/app/services/command_tower/login_strategy/plain_text/email_verification/verify.rb +24 -0
  47. data/app/services/command_tower/login_strategy/plain_text/login.rb +50 -0
  48. data/app/services/command_tower/secrets/cleanse.rb +14 -0
  49. data/app/services/command_tower/secrets/generate.rb +62 -0
  50. data/app/services/command_tower/secrets/verify.rb +27 -0
  51. data/app/services/command_tower/secrets.rb +15 -0
  52. data/app/services/command_tower/service_base.rb +89 -0
  53. data/app/services/command_tower/service_logging.rb +41 -0
  54. data/app/services/command_tower/user_attributes/modify.rb +68 -0
  55. data/app/services/command_tower/user_attributes/roles.rb +27 -0
  56. data/app/services/command_tower/username/available.rb +64 -0
  57. data/app/views/command_tower/email_verification_mailer/verify_email.html.erb +26 -0
  58. data/config/routes.rb +55 -0
  59. data/db/migrate/20241117043720_create_command_tower_users.rb +42 -0
  60. data/db/migrate/20241204065708_create_command_tower_user_secrets.rb +16 -0
  61. data/db/migrate/20250223023306_create_command_tower_messages.rb +12 -0
  62. data/db/migrate/20250223023313_create_command_tower_message_blasts.rb +14 -0
  63. data/lib/command_tower/authorization/default.yml +42 -0
  64. data/lib/command_tower/authorization/entity.rb +101 -0
  65. data/lib/command_tower/authorization/role.rb +101 -0
  66. data/lib/command_tower/authorization.rb +85 -0
  67. data/lib/command_tower/configuration/admin/config.rb +18 -0
  68. data/lib/command_tower/configuration/application/config.rb +40 -0
  69. data/lib/command_tower/configuration/authorization/config.rb +24 -0
  70. data/lib/command_tower/configuration/base.rb +11 -0
  71. data/lib/command_tower/configuration/config.rb +77 -0
  72. data/lib/command_tower/configuration/email/config.rb +87 -0
  73. data/lib/command_tower/configuration/jwt/config.rb +22 -0
  74. data/lib/command_tower/configuration/login/config.rb +18 -0
  75. data/lib/command_tower/configuration/login/strategy/plain_text/config.rb +57 -0
  76. data/lib/command_tower/configuration/login/strategy/plain_text/email_verify.rb +50 -0
  77. data/lib/command_tower/configuration/login/strategy/plain_text/lockable.rb +27 -0
  78. data/lib/command_tower/configuration/otp/config.rb +54 -0
  79. data/lib/command_tower/configuration/user/config.rb +56 -0
  80. data/lib/command_tower/configuration/username/check.rb +31 -0
  81. data/lib/command_tower/configuration/username/config.rb +41 -0
  82. data/lib/command_tower/engine.rb +53 -0
  83. data/lib/command_tower/error.rb +5 -0
  84. data/lib/command_tower/schema/admin/users.rb +15 -0
  85. data/lib/command_tower/schema/error/base.rb +15 -0
  86. data/lib/command_tower/schema/error/invalid_argument.rb +15 -0
  87. data/lib/command_tower/schema/error/invalid_argument_response.rb +17 -0
  88. data/lib/command_tower/schema/inbox/blast_request.rb +15 -0
  89. data/lib/command_tower/schema/inbox/blast_response.rb +16 -0
  90. data/lib/command_tower/schema/inbox/message_blast_entity.rb +16 -0
  91. data/lib/command_tower/schema/inbox/message_blast_metadata.rb +16 -0
  92. data/lib/command_tower/schema/inbox/message_entity.rb +14 -0
  93. data/lib/command_tower/schema/inbox/metadata.rb +18 -0
  94. data/lib/command_tower/schema/inbox/modified.rb +13 -0
  95. data/lib/command_tower/schema/page.rb +14 -0
  96. data/lib/command_tower/schema/plain_text/create_user_request.rb +18 -0
  97. data/lib/command_tower/schema/plain_text/create_user_response.rb +17 -0
  98. data/lib/command_tower/schema/plain_text/email_verify_request.rb +11 -0
  99. data/lib/command_tower/schema/plain_text/email_verify_response.rb +11 -0
  100. data/lib/command_tower/schema/plain_text/email_verify_send_request.rb +9 -0
  101. data/lib/command_tower/schema/plain_text/email_verify_send_response.rb +11 -0
  102. data/lib/command_tower/schema/plain_text/login_request.rb +15 -0
  103. data/lib/command_tower/schema/plain_text/login_response.rb +13 -0
  104. data/lib/command_tower/schema/user.rb +28 -0
  105. data/lib/command_tower/schema.rb +38 -0
  106. data/lib/command_tower/spec_helper.rb +19 -0
  107. data/lib/command_tower/version.rb +5 -0
  108. data/lib/command_tower.rb +33 -0
  109. data/lib/generators/api_engine_base/configure/USAGE +8 -0
  110. data/lib/generators/api_engine_base/configure/configure_generator.rb +12 -0
  111. data/lib/tasks/auto_annotate_models.rake +60 -0
  112. 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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "class_composer"
4
+ require "pry"
5
+
6
+ module CommandTower
7
+ module Configuration
8
+ class Base
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandTower
4
+ class Error < StandardError; end
5
+ end