command_tower 0.4.0 → 0.10.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/README.md +102 -29
- data/app/auth/command_tower/auth/auth_context.rb +36 -0
- data/app/auth/command_tower/auth/password_recovery_session_context.rb +11 -0
- data/app/auth/command_tower/auth/signup_session_context.rb +11 -0
- data/app/controllers/command_tower/admin/messaging/announcements_controller.rb +34 -0
- data/app/controllers/command_tower/application_controller.rb +80 -14
- data/app/controllers/command_tower/auth/email/availability_controller.rb +35 -0
- data/app/controllers/command_tower/auth/email_verification/send_controller.rb +24 -0
- data/app/controllers/command_tower/auth/email_verification/verify_controller.rb +41 -0
- data/app/controllers/command_tower/auth/identity_policy_controller.rb +14 -0
- data/app/controllers/command_tower/auth/logout_controller.rb +14 -0
- data/app/controllers/command_tower/auth/password_recovery_session/create_controller.rb +17 -0
- data/app/controllers/command_tower/auth/password_reset/reset_controller.rb +35 -0
- data/app/controllers/command_tower/auth/password_reset/send_controller.rb +40 -0
- data/app/controllers/command_tower/auth/password_reset/validate_controller.rb +35 -0
- data/app/controllers/command_tower/auth/plain_text/login_controller.rb +22 -0
- data/app/controllers/command_tower/auth/register_controller.rb +33 -0
- data/app/controllers/command_tower/auth/session_controller.rb +21 -0
- data/app/controllers/command_tower/auth/signup_session/create_controller.rb +17 -0
- data/app/controllers/command_tower/auth/username/availability_controller.rb +35 -0
- data/app/controllers/command_tower/me/inbox_controller.rb +85 -0
- data/app/controllers/command_tower/me/name_controller.rb +37 -0
- data/app/controllers/command_tower/me/password_controller.rb +37 -0
- data/app/controllers/command_tower/me/phone_controller.rb +44 -0
- data/app/controllers/command_tower/me/phone_verification/verifications_controller.rb +23 -0
- data/app/controllers/command_tower/me/phone_verification/verify_controller.rb +34 -0
- data/app/controllers/command_tower/me/preferences_controller.rb +46 -0
- data/app/controllers/command_tower/me/pushover/verifications_controller.rb +23 -0
- data/app/controllers/command_tower/me/pushover_controller.rb +66 -0
- data/app/controllers/command_tower/me_controller.rb +19 -0
- data/app/controllers/command_tower/profile_controller.rb +19 -0
- data/app/controllers/concerns/command_tower/api/application_response_renderer.rb +82 -0
- data/app/controllers/concerns/command_tower/api/deserializer_failure_details.rb +22 -0
- data/app/controllers/concerns/command_tower/auth/authentication_boundary.rb +34 -0
- data/app/controllers/concerns/command_tower/auth/authorization_boundary.rb +26 -0
- data/app/controllers/concerns/command_tower/auth/invalid_credentials_deserializer_renderer.rb +23 -0
- data/app/controllers/concerns/command_tower/auth/password_recovery_session_boundary.rb +29 -0
- data/app/controllers/concerns/command_tower/auth/signup_session_boundary.rb +29 -0
- data/app/deserializers/command_tower/deserializers/admin/messaging/create_announcement_deserializer.rb +106 -0
- data/app/deserializers/command_tower/deserializers/application_deserializer.rb +148 -0
- data/app/deserializers/command_tower/deserializers/auth/email_availability_deserializer.rb +19 -0
- data/app/deserializers/command_tower/deserializers/auth/email_verification/verify_deserializer.rb +21 -0
- data/app/deserializers/command_tower/deserializers/auth/password_reset/reset_deserializer.rb +31 -0
- data/app/deserializers/command_tower/deserializers/auth/password_reset/send_deserializer.rb +21 -0
- data/app/deserializers/command_tower/deserializers/auth/password_reset/validate_deserializer.rb +23 -0
- data/app/deserializers/command_tower/deserializers/auth/plain_text/login_deserializer.rb +24 -0
- data/app/deserializers/command_tower/deserializers/auth/register_deserializer.rb +42 -0
- data/app/deserializers/command_tower/deserializers/auth/username_availability_deserializer.rb +19 -0
- data/app/deserializers/command_tower/deserializers/clients/errors.rb +45 -0
- data/app/deserializers/command_tower/deserializers/clients/missing.rb +10 -0
- data/app/deserializers/command_tower/deserializers/clients/payload.rb +21 -0
- data/app/deserializers/command_tower/deserializers/clients/result.rb +122 -0
- data/app/deserializers/command_tower/deserializers/clients/types.rb +192 -0
- data/app/deserializers/command_tower/deserializers/coercion_result.rb +35 -0
- data/app/deserializers/command_tower/deserializers/failure.rb +14 -0
- data/app/deserializers/command_tower/deserializers/me/change_password_deserializer.rb +41 -0
- data/app/deserializers/command_tower/deserializers/me/phone_verification/verify_deserializer.rb +29 -0
- data/app/deserializers/command_tower/deserializers/me/pushover/credentials_deserializer.rb +31 -0
- data/app/deserializers/command_tower/deserializers/me/update_name_deserializer.rb +22 -0
- data/app/deserializers/command_tower/deserializers/me/update_phone_deserializer.rb +22 -0
- data/app/deserializers/command_tower/deserializers/messaging/inbox.rb +77 -0
- data/app/deserializers/command_tower/deserializers/messaging/preferences/show_deserializer.rb +17 -0
- data/app/deserializers/command_tower/deserializers/messaging/preferences/update_deserializer.rb +97 -0
- data/app/errors/command_tower/errors/account/phone_already_verified_error.rb +17 -0
- data/app/errors/command_tower/errors/account/phone_missing_error.rb +17 -0
- data/app/errors/command_tower/errors/account/phone_verification_code_invalid_error.rb +17 -0
- data/app/errors/command_tower/errors/account/phone_verification_expired_error.rb +17 -0
- data/app/errors/command_tower/errors/account/phone_verification_send_failed_error.rb +25 -0
- data/app/errors/command_tower/errors/account/phone_verification_stale_error.rb +17 -0
- data/app/errors/command_tower/errors/account/phone_verification_throttled_error.rb +24 -0
- data/app/errors/command_tower/errors/account/pushover_already_configured_error.rb +21 -0
- data/app/errors/command_tower/errors/account/pushover_capability_unavailable_error.rb +21 -0
- data/app/errors/command_tower/errors/account/pushover_not_configured_error.rb +21 -0
- data/app/errors/command_tower/errors/account/pushover_provider_unavailable_error.rb +21 -0
- data/app/errors/command_tower/errors/account/pushover_verification_failed_error.rb +27 -0
- data/app/errors/command_tower/errors/account/sms_capability_unavailable_error.rb +21 -0
- data/app/errors/command_tower/errors/application_error.rb +27 -0
- data/app/errors/command_tower/errors/auth/csrf_mismatch_error.rb +17 -0
- data/app/errors/command_tower/errors/auth/csrf_missing_error.rb +17 -0
- data/app/errors/command_tower/errors/auth/email_already_registered_error.rb +17 -0
- data/app/errors/command_tower/errors/auth/email_verification_required_error.rb +21 -0
- data/app/errors/command_tower/errors/auth/invalid_credentials_error.rb +21 -0
- data/app/errors/command_tower/errors/auth/password_recovery_ip_rate_limit_error.rb +25 -0
- data/app/errors/command_tower/errors/auth/password_recovery_session_expired_error.rb +21 -0
- data/app/errors/command_tower/errors/auth/password_recovery_session_invalid_error.rb +21 -0
- data/app/errors/command_tower/errors/auth/password_recovery_session_missing_error.rb +21 -0
- data/app/errors/command_tower/errors/auth/password_recovery_session_rate_limit_error.rb +25 -0
- data/app/errors/command_tower/errors/auth/password_reset_invalid_token_error.rb +21 -0
- data/app/errors/command_tower/errors/auth/password_reset_unavailable_error.rb +21 -0
- data/app/errors/command_tower/errors/auth/signup_ip_rate_limit_error.rb +25 -0
- data/app/errors/command_tower/errors/auth/signup_session_expired_error.rb +17 -0
- data/app/errors/command_tower/errors/auth/signup_session_invalid_error.rb +17 -0
- data/app/errors/command_tower/errors/auth/signup_session_missing_error.rb +17 -0
- data/app/errors/command_tower/errors/auth/signup_session_rate_limit_error.rb +25 -0
- data/app/errors/command_tower/errors/auth/verification_code_invalid_error.rb +17 -0
- data/app/errors/command_tower/errors/auth/verification_send_failed_error.rb +25 -0
- data/app/errors/command_tower/errors/forbidden_error.rb +19 -0
- data/app/errors/command_tower/errors/internal_error.rb +19 -0
- data/app/errors/command_tower/errors/messaging/accept_rejected_error.rb +21 -0
- data/app/errors/command_tower/errors/messaging/idempotency_conflict_error.rb +21 -0
- data/app/errors/command_tower/errors/messaging/recipient_unresolved_error.rb +21 -0
- data/app/errors/command_tower/errors/not_found_error.rb +19 -0
- data/app/errors/command_tower/errors/unauthorized_error.rb +19 -0
- data/app/errors/command_tower/errors/validation_error.rb +15 -0
- data/app/jobs/command_tower/messaging/channel_delivery_execution_job.rb +18 -0
- data/app/jobs/command_tower/messaging/communications/produce_recipient_job.rb +24 -0
- data/app/jobs/command_tower/messaging/execution_recovery_job.rb +13 -0
- data/app/jobs/command_tower/messaging/handoff_job.rb +15 -0
- data/app/jobs/command_tower/messaging/handoff_recovery_job.rb +13 -0
- data/app/mailers/command_tower/email_verification_mailer.rb +5 -3
- data/app/mailers/command_tower/messaging/channel_mailer.rb +25 -0
- data/app/mailers/command_tower/password_reset_mailer.rb +18 -0
- data/app/models/command_tower/messaging/channel_delivery.rb +45 -0
- data/app/models/command_tower/messaging/communication.rb +60 -0
- data/app/models/command_tower/messaging/delivery_attempt.rb +28 -0
- data/app/models/command_tower/messaging/destination_plan.rb +17 -0
- data/app/models/command_tower/messaging/endpoint.rb +98 -0
- data/app/models/command_tower/messaging/endpoint_pushover_credential.rb +18 -0
- data/app/models/command_tower/messaging/inbox_item.rb +52 -0
- data/app/models/command_tower/messaging/notification_preference.rb +21 -0
- data/app/models/user.rb +4 -1
- data/app/serializers/command_tower/serializers/admin/messaging/announcement_response_serializer.rb +41 -0
- data/app/serializers/command_tower/serializers/application/envelope_serializer.rb +25 -0
- data/app/serializers/command_tower/serializers/application/error_entry_serializer.rb +18 -0
- data/app/serializers/command_tower/serializers/application_serializer.rb +26 -0
- data/app/serializers/command_tower/serializers/auth/email_availability_serializer.rb +17 -0
- data/app/serializers/command_tower/serializers/auth/email_verification/message_response_serializer.rb +15 -0
- data/app/serializers/command_tower/serializers/auth/identity_policy_serializer.rb +36 -0
- data/app/serializers/command_tower/serializers/auth/login_response_serializer.rb +17 -0
- data/app/serializers/command_tower/serializers/auth/logout_response_serializer.rb +13 -0
- data/app/serializers/command_tower/serializers/auth/password_recovery_session_response_serializer.rb +16 -0
- data/app/serializers/command_tower/serializers/auth/password_reset/message_response_serializer.rb +15 -0
- data/app/serializers/command_tower/serializers/auth/password_reset/validate_response_serializer.rb +22 -0
- data/app/serializers/command_tower/serializers/auth/register_response_serializer.rb +16 -0
- data/app/serializers/command_tower/serializers/auth/session_response_serializer.rb +16 -0
- data/app/serializers/command_tower/serializers/auth/signup_session_response_serializer.rb +16 -0
- data/app/serializers/command_tower/serializers/auth/user_serializer.rb +21 -0
- data/app/serializers/command_tower/serializers/auth/username_availability_serializer.rb +17 -0
- data/app/serializers/command_tower/serializers/me/account_serializer.rb +45 -0
- data/app/serializers/command_tower/serializers/me/change_password_response_serializer.rb +13 -0
- data/app/serializers/command_tower/serializers/me/pushover_serializer.rb +59 -0
- data/app/serializers/command_tower/serializers/messaging/inbox.rb +45 -0
- data/app/serializers/command_tower/serializers/messaging/preferences/catalog_serializer.rb +17 -0
- data/app/serializers/command_tower/serializers/messaging/preferences/category_serializer.rb +23 -0
- data/app/serializers/command_tower/serializers/messaging/preferences/notification_serializer.rb +30 -0
- data/app/serializers/command_tower/serializers/profile/profile_serializer.rb +13 -0
- data/app/services/command_tower/README.md +22 -6
- data/app/services/command_tower/auth/request_context.rb +21 -0
- data/app/services/command_tower/authorize/validate.rb +54 -18
- data/app/services/command_tower/clients/client_base.rb +183 -0
- data/app/services/command_tower/clients/client_result.rb +45 -0
- data/app/services/command_tower/clients/const_resolution.rb +32 -0
- data/app/services/command_tower/clients/decoded_response.rb +16 -0
- data/app/services/command_tower/clients/endpoint_base.rb +242 -0
- data/app/services/command_tower/clients/endpoint_input.rb +18 -0
- data/app/services/command_tower/clients/errors/authentication_error.rb +26 -0
- data/app/services/command_tower/clients/errors/configuration_error.rb +10 -0
- data/app/services/command_tower/clients/errors/deserialization_error.rb +26 -0
- data/app/services/command_tower/clients/errors/discovery_error.rb +10 -0
- data/app/services/command_tower/clients/errors/upstream_error.rb +26 -0
- data/app/services/command_tower/clients/invocation.rb +61 -0
- data/app/services/command_tower/clients/namespace_proxy.rb +75 -0
- data/app/services/command_tower/clients/scoped_client.rb +88 -0
- data/app/services/command_tower/clients/serialized_request.rb +17 -0
- data/app/services/command_tower/clients/transport/error.rb +18 -0
- data/app/services/command_tower/clients/transport/faraday_adapter.rb +129 -0
- data/app/services/command_tower/clients/transport/faraday_config.rb +45 -0
- data/app/services/command_tower/clients/transport/request.rb +50 -0
- data/app/services/command_tower/clients/transport/response.rb +22 -0
- data/app/services/command_tower/clients/url.rb +56 -0
- data/app/services/command_tower/identity/phone/normalizer.rb +41 -0
- data/app/services/command_tower/identity/phone_verification/sms_configuration.rb +58 -0
- data/app/services/command_tower/identity/phone_verification/sms_transport/adapters/fake_adapter.rb +35 -0
- data/app/services/command_tower/identity/phone_verification/sms_transport/adapters/log_adapter.rb +34 -0
- data/app/services/command_tower/identity/phone_verification/sms_transport/adapters/twilio_adapter.rb +60 -0
- data/app/services/command_tower/identity/phone_verification/sms_transport.rb +42 -0
- data/app/services/command_tower/jwt/authenticate_user.rb +61 -34
- data/app/services/command_tower/jwt/authentication_outcome.rb +36 -0
- data/app/services/command_tower/jwt/decode.rb +27 -8
- data/app/services/command_tower/jwt/encode.rb +4 -6
- data/app/services/command_tower/jwt/login_create.rb +6 -7
- data/app/services/command_tower/login_strategy/plain_text/email_verification/required.rb +11 -9
- data/app/services/command_tower/messaging/accept/channel_delivery_result.rb +13 -0
- data/app/services/command_tower/messaging/accept/coordinator.rb +166 -0
- data/app/services/command_tower/messaging/accept/error.rb +9 -0
- data/app/services/command_tower/messaging/accept/excluded_destination.rb +24 -0
- data/app/services/command_tower/messaging/accept/handoff_scheduler.rb +40 -0
- data/app/services/command_tower/messaging/accept/idempotency_conflict_error.rb +9 -0
- data/app/services/command_tower/messaging/accept/illegal_override_error.rb +9 -0
- data/app/services/command_tower/messaging/accept/impossible_mandatory_plan_error.rb +9 -0
- data/app/services/command_tower/messaging/accept/invalid_preference_error.rb +9 -0
- data/app/services/command_tower/messaging/accept/invariant_error.rb +9 -0
- data/app/services/command_tower/messaging/accept/operation_logger.rb +97 -0
- data/app/services/command_tower/messaging/accept/persistence_error.rb +9 -0
- data/app/services/command_tower/messaging/accept/persister.rb +90 -0
- data/app/services/command_tower/messaging/accept/request_normalizer.rb +100 -0
- data/app/services/command_tower/messaging/accept/result.rb +99 -0
- data/app/services/command_tower/messaging/accept/unknown_type_error.rb +9 -0
- data/app/services/command_tower/messaging/accept/validation_error.rb +9 -0
- data/app/services/command_tower/messaging/channel_detectors.rb +52 -0
- data/app/services/command_tower/messaging/channels/definition.rb +24 -0
- data/app/services/command_tower/messaging/channels/error.rb +9 -0
- data/app/services/command_tower/messaging/channels/unknown_channel_error.rb +9 -0
- data/app/services/command_tower/messaging/channels.rb +85 -0
- data/app/services/command_tower/messaging/contract/communications.rb +29 -0
- data/app/services/command_tower/messaging/contract/error.rb +9 -0
- data/app/services/command_tower/messaging/contract/internal/finder.rb +43 -0
- data/app/services/command_tower/messaging/contract/invariant_error.rb +9 -0
- data/app/services/command_tower/messaging/contract/mappers/channel_delivery_mapper.rb +53 -0
- data/app/services/command_tower/messaging/contract/mappers/communication_mapper.rb +61 -0
- data/app/services/command_tower/messaging/contract/mappers/delivery_attempt_mapper.rb +27 -0
- data/app/services/command_tower/messaging/contract/mappers/destination_plan_mapper.rb +17 -0
- data/app/services/command_tower/messaging/contract/mappers/inbox_item_mapper.rb +17 -0
- data/app/services/command_tower/messaging/contract/not_found_error.rb +9 -0
- data/app/services/command_tower/messaging/contract/observability/correlation.rb +17 -0
- data/app/services/command_tower/messaging/contract/observability/operation_logger.rb +101 -0
- data/app/services/command_tower/messaging/contract/observability/structured_logger.rb +56 -0
- data/app/services/command_tower/messaging/contract/requests/find_communication.rb +21 -0
- data/app/services/command_tower/messaging/contract/results/channel_delivery_result.rb +25 -0
- data/app/services/command_tower/messaging/contract/results/communication_result.rb +22 -0
- data/app/services/command_tower/messaging/contract/results/delivery_attempt_result.rb +21 -0
- data/app/services/command_tower/messaging/contract/results/destination_plan_result.rb +11 -0
- data/app/services/command_tower/messaging/contract/results/inbox_item_result.rb +11 -0
- data/app/services/command_tower/messaging/contract/validation_error.rb +9 -0
- data/app/services/command_tower/messaging/delivery_retry_policy.rb +30 -0
- data/app/services/command_tower/messaging/endpoints/begin_verification.rb +13 -0
- data/app/services/command_tower/messaging/endpoints/channel_gate.rb +39 -0
- data/app/services/command_tower/messaging/endpoints/conflict_error.rb +9 -0
- data/app/services/command_tower/messaging/endpoints/create.rb +181 -0
- data/app/services/command_tower/messaging/endpoints/error.rb +9 -0
- data/app/services/command_tower/messaging/endpoints/fingerprinter.rb +50 -0
- data/app/services/command_tower/messaging/endpoints/invalid_transition_error.rb +9 -0
- data/app/services/command_tower/messaging/endpoints/lifecycle.rb +37 -0
- data/app/services/command_tower/messaging/endpoints/mark_invalid.rb +32 -0
- data/app/services/command_tower/messaging/endpoints/mark_verification_failed.rb +13 -0
- data/app/services/command_tower/messaging/endpoints/mark_verified.rb +13 -0
- data/app/services/command_tower/messaging/endpoints/not_found_error.rb +9 -0
- data/app/services/command_tower/messaging/endpoints/persistence.rb +91 -0
- data/app/services/command_tower/messaging/endpoints/pushover/verify.rb +101 -0
- data/app/services/command_tower/messaging/endpoints/query.rb +28 -0
- data/app/services/command_tower/messaging/endpoints/replace.rb +181 -0
- data/app/services/command_tower/messaging/endpoints/reset_verification.rb +13 -0
- data/app/services/command_tower/messaging/endpoints/revoke.rb +40 -0
- data/app/services/command_tower/messaging/endpoints/safe_view.rb +50 -0
- data/app/services/command_tower/messaging/endpoints/secret_box.rb +86 -0
- data/app/services/command_tower/messaging/endpoints/secret_reader.rb +72 -0
- data/app/services/command_tower/messaging/endpoints/validation_error.rb +9 -0
- data/app/services/command_tower/messaging/endpoints/validators/push.rb +24 -0
- data/app/services/command_tower/messaging/endpoints/validators/pushover.rb +68 -0
- data/app/services/command_tower/messaging/endpoints/validators.rb +36 -0
- data/app/services/command_tower/messaging/endpoints/verification.rb +39 -0
- data/app/services/command_tower/messaging/endpoints/verification_failed_error.rb +18 -0
- data/app/services/command_tower/messaging/endpoints/verification_transition.rb +20 -0
- data/app/services/command_tower/messaging/endpoints.rb +55 -0
- data/app/services/command_tower/messaging/execution/adapter_request.rb +45 -0
- data/app/services/command_tower/messaging/execution/adapter_result.rb +81 -0
- data/app/services/command_tower/messaging/execution/adapters/email/adapter.rb +78 -0
- data/app/services/command_tower/messaging/execution/adapters/email/configuration.rb +55 -0
- data/app/services/command_tower/messaging/execution/adapters/fake_adapter.rb +34 -0
- data/app/services/command_tower/messaging/execution/adapters/pushover/adapter.rb +107 -0
- data/app/services/command_tower/messaging/execution/adapters/pushover/configuration.rb +30 -0
- data/app/services/command_tower/messaging/execution/adapters/sms/adapter.rb +90 -0
- data/app/services/command_tower/messaging/execution/adapters/sms/configuration.rb +58 -0
- data/app/services/command_tower/messaging/execution/adapters/sms/log_adapter.rb +34 -0
- data/app/services/command_tower/messaging/execution/adapters/sms/twilio_http_client.rb +70 -0
- data/app/services/command_tower/messaging/execution/adapters/unconfigured_adapter.rb +20 -0
- data/app/services/command_tower/messaging/execution/attempt_ledger.rb +146 -0
- data/app/services/command_tower/messaging/execution/claim.rb +35 -0
- data/app/services/command_tower/messaging/execution/invalid_adapter_contract_error.rb +9 -0
- data/app/services/command_tower/messaging/execution/operation_logger.rb +237 -0
- data/app/services/command_tower/messaging/execution/readiness_terminal_mapping.rb +37 -0
- data/app/services/command_tower/messaging/execution/recovery.rb +78 -0
- data/app/services/command_tower/messaging/execution/resolve_recipient_address.rb +58 -0
- data/app/services/command_tower/messaging/execution/revalidate_readiness.rb +73 -0
- data/app/services/command_tower/messaging/execution/scheduler.rb +38 -0
- data/app/services/command_tower/messaging/execution/select_adapter.rb +63 -0
- data/app/services/command_tower/messaging/handoff/advance_communication.rb +39 -0
- data/app/services/command_tower/messaging/handoff/operation_logger.rb +78 -0
- data/app/services/command_tower/messaging/handoff/recovery.rb +26 -0
- data/app/services/command_tower/messaging/inbox/bulk_result.rb +19 -0
- data/app/services/command_tower/messaging/inbox/error.rb +9 -0
- data/app/services/command_tower/messaging/inbox/invalid_bulk_items_error.rb +19 -0
- data/app/services/command_tower/messaging/inbox/invariant_error.rb +9 -0
- data/app/services/command_tower/messaging/inbox/item_result.rb +64 -0
- data/app/services/command_tower/messaging/inbox/list_result.rb +18 -0
- data/app/services/command_tower/messaging/inbox/mutator.rb +252 -0
- data/app/services/command_tower/messaging/inbox/not_found_error.rb +9 -0
- data/app/services/command_tower/messaging/inbox/operation_logger.rb +37 -0
- data/app/services/command_tower/messaging/inbox/reader.rb +117 -0
- data/app/services/command_tower/messaging/inbox/scope.rb +24 -0
- data/app/services/command_tower/messaging/inbox/unread_count_result.rb +16 -0
- data/app/services/command_tower/messaging/inbox/validation_error.rb +9 -0
- data/app/services/command_tower/messaging/inbox.rb +61 -0
- data/app/services/command_tower/messaging/notification_types/catalog_category.rb +19 -0
- data/app/services/command_tower/messaging/notification_types/declaration.rb +96 -0
- data/app/services/command_tower/messaging/notification_types/declaration_validator.rb +152 -0
- data/app/services/command_tower/messaging/notification_types/duplicate_type_error.rb +9 -0
- data/app/services/command_tower/messaging/notification_types/error.rb +9 -0
- data/app/services/command_tower/messaging/notification_types/invalid_declaration_error.rb +9 -0
- data/app/services/command_tower/messaging/notification_types/not_found_error.rb +9 -0
- data/app/services/command_tower/messaging/notification_types/registry.rb +103 -0
- data/app/services/command_tower/messaging/notification_types/sealed_registry_error.rb +9 -0
- data/app/services/command_tower/messaging/notification_types.rb +37 -0
- data/app/services/command_tower/messaging/planner/destination_plan.rb +41 -0
- data/app/services/command_tower/messaging/planner/error.rb +9 -0
- data/app/services/command_tower/messaging/planner/excluded_destination.rb +28 -0
- data/app/services/command_tower/messaging/planner/illegal_override_error.rb +9 -0
- data/app/services/command_tower/messaging/planner/impossible_mandatory_plan_error.rb +9 -0
- data/app/services/command_tower/messaging/planner/invalid_evaluation_error.rb +9 -0
- data/app/services/command_tower/messaging/planner/message_overrides.rb +33 -0
- data/app/services/command_tower/messaging/planner/operation_logger.rb +28 -0
- data/app/services/command_tower/messaging/planner/planner.rb +261 -0
- data/app/services/command_tower/messaging/planner/unknown_type_error.rb +9 -0
- data/app/services/command_tower/messaging/planner.rb +25 -0
- data/app/services/command_tower/messaging/preferences/catalog.rb +96 -0
- data/app/services/command_tower/messaging/preferences/catalog_category_result.rb +19 -0
- data/app/services/command_tower/messaging/preferences/catalog_notification_result.rb +55 -0
- data/app/services/command_tower/messaging/preferences/catalog_result.rb +13 -0
- data/app/services/command_tower/messaging/preferences/error.rb +9 -0
- data/app/services/command_tower/messaging/preferences/evaluation_result.rb +61 -0
- data/app/services/command_tower/messaging/preferences/evaluator.rb +194 -0
- data/app/services/command_tower/messaging/preferences/invalid_preference_state_error.rb +9 -0
- data/app/services/command_tower/messaging/preferences/invalid_preference_write_error.rb +10 -0
- data/app/services/command_tower/messaging/preferences/not_settings_visible_error.rb +10 -0
- data/app/services/command_tower/messaging/preferences/preference_state.rb +61 -0
- data/app/services/command_tower/messaging/preferences/reason_classes.rb +17 -0
- data/app/services/command_tower/messaging/preferences/resolve.rb +50 -0
- data/app/services/command_tower/messaging/preferences/store.rb +126 -0
- data/app/services/command_tower/messaging/preferences/store_error.rb +10 -0
- data/app/services/command_tower/messaging/preferences/suppressed_destination.rb +24 -0
- data/app/services/command_tower/messaging/preferences/unknown_type_error.rb +9 -0
- data/app/services/command_tower/messaging/preferences/update.rb +248 -0
- data/app/services/command_tower/messaging/preferences.rb +68 -0
- data/app/services/command_tower/messaging/pushover/adapters/disabled_adapter.rb +33 -0
- data/app/services/command_tower/messaging/pushover/adapters/fake_adapter.rb +90 -0
- data/app/services/command_tower/messaging/pushover/adapters/http_adapter.rb +145 -0
- data/app/services/command_tower/messaging/pushover/adapters/log_adapter.rb +52 -0
- data/app/services/command_tower/messaging/pushover/result.rb +34 -0
- data/app/services/command_tower/messaging/pushover/transport.rb +64 -0
- data/app/services/command_tower/messaging/recipient_readiness/channel_result.rb +55 -0
- data/app/services/command_tower/messaging/recipient_readiness/error.rb +9 -0
- data/app/services/command_tower/messaging/recipient_readiness/evaluate.rb +319 -0
- data/app/services/command_tower/messaging/recipient_readiness/identity_facts.rb +54 -0
- data/app/services/command_tower/messaging/recipient_readiness/reason_codes.rb +33 -0
- data/app/services/command_tower/messaging/recipient_readiness/recipient_not_found_error.rb +9 -0
- data/app/services/command_tower/messaging/recipient_readiness/recipient_result.rb +38 -0
- data/app/services/command_tower/messaging/recipient_readiness/unknown_channel_error.rb +9 -0
- data/app/services/command_tower/messaging/recipient_readiness.rb +26 -0
- data/app/services/command_tower/messaging/rendering/channel_renderer.rb +127 -0
- data/app/services/command_tower/messaging/rendering/render_error.rb +24 -0
- data/app/services/command_tower/messaging/rendering/rendered_payload.rb +44 -0
- data/app/services/command_tower/messaging/rendering/rendered_pushover_payload.rb +43 -0
- data/app/services/command_tower/messaging/rendering/rendered_sms_payload.rb +40 -0
- data/app/services/command_tower/messaging.rb +35 -0
- data/app/services/command_tower/secrets/cleanse.rb +19 -5
- data/app/services/command_tower/secrets/generate.rb +62 -27
- data/app/services/command_tower/secrets/verify.rb +46 -12
- data/app/services/command_tower/secrets.rb +2 -0
- data/app/services/command_tower/services/account/clear_phone.rb +25 -0
- data/app/services/command_tower/services/account/phone_verification/send.rb +114 -0
- data/app/services/command_tower/services/account/phone_verification/verify.rb +88 -0
- data/app/services/command_tower/services/account/pushover/create.rb +28 -0
- data/app/services/command_tower/services/account/pushover/ct_support.rb +70 -0
- data/app/services/command_tower/services/account/pushover/destroy.rb +30 -0
- data/app/services/command_tower/services/account/pushover/replace.rb +28 -0
- data/app/services/command_tower/services/account/pushover/show.rb +19 -0
- data/app/services/command_tower/services/account/pushover/verify.rb +30 -0
- data/app/services/command_tower/services/account/update_phone.rb +50 -0
- data/app/services/command_tower/services/application_service.rb +21 -0
- data/app/services/command_tower/services/auth/authenticate_session.rb +105 -0
- data/app/services/command_tower/services/auth/authorize_request.rb +34 -0
- data/app/services/command_tower/services/auth/client_ip_resolver.rb +13 -0
- data/app/services/command_tower/services/auth/email_availability.rb +42 -0
- data/app/services/command_tower/services/auth/email_verification/send.rb +65 -0
- data/app/services/command_tower/services/auth/email_verification/verify.rb +51 -0
- data/app/services/command_tower/services/auth/identity_policy.rb +60 -0
- data/app/services/command_tower/services/auth/password_recovery/rate_limits/check_send.rb +48 -0
- data/app/services/command_tower/services/auth/password_recovery/rate_limits/check_token_issue.rb +35 -0
- data/app/services/command_tower/services/auth/password_recovery/rate_limits/enforcement.rb +53 -0
- data/app/services/command_tower/services/auth/password_recovery_session/create.rb +26 -0
- data/app/services/command_tower/services/auth/password_recovery_session/decode.rb +29 -0
- data/app/services/command_tower/services/auth/password_recovery_session/encode.rb +31 -0
- data/app/services/command_tower/services/auth/password_recovery_session/validate.rb +58 -0
- data/app/services/command_tower/services/auth/password_reset/reset.rb +65 -0
- data/app/services/command_tower/services/auth/password_reset/send.rb +77 -0
- data/app/services/command_tower/services/auth/password_reset/token_verification.rb +68 -0
- data/app/services/command_tower/services/auth/password_reset/validate.rb +29 -0
- data/app/services/command_tower/services/auth/plain_text/login.rb +44 -0
- data/app/services/command_tower/services/auth/register.rb +77 -0
- data/app/services/command_tower/services/auth/signup_rate_limits/check_availability.rb +52 -0
- data/app/services/command_tower/services/auth/signup_rate_limits/check_register.rb +24 -0
- data/app/services/command_tower/services/auth/signup_rate_limits/check_token_issue.rb +33 -0
- data/app/services/command_tower/services/auth/signup_rate_limits/enforcement.rb +50 -0
- data/app/services/command_tower/services/auth/signup_session/create.rb +26 -0
- data/app/services/command_tower/services/auth/signup_session/decode.rb +29 -0
- data/app/services/command_tower/services/auth/signup_session/encode.rb +31 -0
- data/app/services/command_tower/services/auth/signup_session/validate.rb +58 -0
- data/app/services/command_tower/services/auth/username_availability.rb +28 -0
- data/app/services/command_tower/services/me/capabilities.rb +43 -0
- data/app/services/command_tower/services/me/change_password.rb +84 -0
- data/app/services/command_tower/services/me/pushover_product_gate.rb +18 -0
- data/app/services/command_tower/services/me/sms_product_gate.rb +19 -0
- data/app/services/command_tower/services/me/update_name.rb +58 -0
- data/app/services/command_tower/services/messaging/communications/produce.rb +68 -0
- data/app/services/command_tower/services/messaging/communications/produce_many.rb +154 -0
- data/app/services/command_tower/services/messaging/inbox.rb +129 -0
- data/app/services/command_tower/services/messaging/preferences/platform_enabled_channels.rb +20 -0
- data/app/services/command_tower/services/messaging/preferences/show.rb +36 -0
- data/app/services/command_tower/services/messaging/preferences/update.rb +43 -0
- data/app/services/command_tower/services/messaging/recipients.rb +20 -0
- data/app/services/command_tower/services/rate_limits/check.rb +31 -0
- data/app/services/command_tower/services/service_result.rb +73 -0
- data/app/services/command_tower/user_attributes/mutate.rb +154 -0
- data/app/services/command_tower/username/available.rb +24 -11
- data/app/views/command_tower/email_verification_mailer/verify_email.html.erb +70 -22
- data/app/views/command_tower/messaging/rendering/email.html.erb +28 -0
- data/app/views/command_tower/messaging/rendering/email.text.erb +7 -0
- data/app/views/command_tower/messaging/rendering/pushover.text.erb +1 -0
- data/app/views/command_tower/messaging/rendering/sms.text.erb +1 -0
- data/app/views/command_tower/password_reset_mailer/reset_password.html.erb +107 -0
- data/app/views/layouts/mailer.html.erb +13 -0
- data/app/views/layouts/mailer.text.erb +1 -0
- data/app/workflows/command_tower/workflows/admin/messaging/create_announcement_workflow.rb +62 -0
- data/app/workflows/command_tower/workflows/application_workflow.rb +68 -0
- data/app/workflows/command_tower/workflows/auth/authenticate_request_workflow.rb +40 -0
- data/app/workflows/command_tower/workflows/auth/authentication_response_effects.rb +21 -0
- data/app/workflows/command_tower/workflows/auth/authorize_request_workflow.rb +28 -0
- data/app/workflows/command_tower/workflows/auth/email_availability_workflow.rb +39 -0
- data/app/workflows/command_tower/workflows/auth/email_verification/send_workflow.rb +32 -0
- data/app/workflows/command_tower/workflows/auth/email_verification/verify_workflow.rb +35 -0
- data/app/workflows/command_tower/workflows/auth/identity_error_status.rb +36 -0
- data/app/workflows/command_tower/workflows/auth/identity_policy_workflow.rb +26 -0
- data/app/workflows/command_tower/workflows/auth/logout_workflow.rb +19 -0
- data/app/workflows/command_tower/workflows/auth/password_recovery_session/authenticate_workflow.rb +49 -0
- data/app/workflows/command_tower/workflows/auth/password_recovery_session/create_workflow.rb +39 -0
- data/app/workflows/command_tower/workflows/auth/password_reset/reset_workflow.rb +40 -0
- data/app/workflows/command_tower/workflows/auth/password_reset/send_workflow.rb +45 -0
- data/app/workflows/command_tower/workflows/auth/password_reset/validate_workflow.rb +40 -0
- data/app/workflows/command_tower/workflows/auth/plain_text/login_workflow.rb +46 -0
- data/app/workflows/command_tower/workflows/auth/register_workflow.rb +83 -0
- data/app/workflows/command_tower/workflows/auth/session/show_workflow.rb +44 -0
- data/app/workflows/command_tower/workflows/auth/session_error_status.rb +30 -0
- data/app/workflows/command_tower/workflows/auth/signup_error_status.rb +31 -0
- data/app/workflows/command_tower/workflows/auth/signup_session/authenticate_workflow.rb +49 -0
- data/app/workflows/command_tower/workflows/auth/signup_session/create_workflow.rb +37 -0
- data/app/workflows/command_tower/workflows/auth/username_availability_workflow.rb +39 -0
- data/app/workflows/command_tower/workflows/me/change_password_workflow.rb +34 -0
- data/app/workflows/command_tower/workflows/me/clear_phone_workflow.rb +52 -0
- data/app/workflows/command_tower/workflows/me/error_mapping.rb +46 -0
- data/app/workflows/command_tower/workflows/me/error_status.rb +28 -0
- data/app/workflows/command_tower/workflows/me/phone_verification/send_workflow.rb +65 -0
- data/app/workflows/command_tower/workflows/me/phone_verification/verify_workflow.rb +57 -0
- data/app/workflows/command_tower/workflows/me/pushover/create_workflow.rb +38 -0
- data/app/workflows/command_tower/workflows/me/pushover/destroy_workflow.rb +34 -0
- data/app/workflows/command_tower/workflows/me/pushover/replace_workflow.rb +38 -0
- data/app/workflows/command_tower/workflows/me/pushover/show_workflow.rb +34 -0
- data/app/workflows/command_tower/workflows/me/pushover/verify_workflow.rb +34 -0
- data/app/workflows/command_tower/workflows/me/pushover/workflow_support.rb +31 -0
- data/app/workflows/command_tower/workflows/me/show_workflow.rb +33 -0
- data/app/workflows/command_tower/workflows/me/update_name_workflow.rb +48 -0
- data/app/workflows/command_tower/workflows/me/update_phone_workflow.rb +55 -0
- data/app/workflows/command_tower/workflows/messaging/communications/produce_recipient_workflow.rb +60 -0
- data/app/workflows/command_tower/workflows/messaging/error_mapping.rb +26 -0
- data/app/workflows/command_tower/workflows/messaging/execution/deliver_workflow.rb +234 -0
- data/app/workflows/command_tower/workflows/messaging/handoff/process_workflow.rb +90 -0
- data/app/workflows/command_tower/workflows/messaging/inbox.rb +97 -0
- data/app/workflows/command_tower/workflows/messaging/preferences/show_workflow.rb +31 -0
- data/app/workflows/command_tower/workflows/messaging/preferences/update_workflow.rb +37 -0
- data/app/workflows/command_tower/workflows/profile/show_workflow.rb +27 -0
- data/app/workflows/command_tower/workflows/workflow_result.rb +34 -0
- data/config/routes.rb +85 -37
- data/db/migrate/{20241117043720_create_command_tower_users.rb → 20260805000001_create_command_tower_users.rb} +7 -9
- data/db/migrate/{20241204065708_create_command_tower_user_secrets.rb → 20260805000002_create_command_tower_user_secrets.rb} +3 -0
- data/db/migrate/20260805000003_create_command_tower_messaging_core.rb +90 -0
- data/db/migrate/20260805000004_create_messaging_notification_preferences.rb +17 -0
- data/db/migrate/20260805000005_create_messaging_endpoints_and_pushover_credentials.rb +72 -0
- data/docs/api_reference.md +438 -0
- data/docs/architecture.md +30 -0
- data/docs/authentication.md +37 -0
- data/docs/authentication_authorization_guide.md +150 -0
- data/docs/authorization.md +34 -0
- data/docs/change_password_workflow.md +67 -0
- data/docs/controllers.md +35 -0
- data/docs/cookie_authentication_guide.md +167 -0
- data/docs/email_verification_workflow.md +58 -0
- data/docs/extending.md +105 -0
- data/docs/host_integration_guide.md +158 -0
- data/docs/initializing.md +169 -0
- data/docs/messaging_integration_guide.md +87 -0
- data/docs/models.md +51 -0
- data/docs/pagination.md +47 -0
- data/docs/password_reset_workflow.md +82 -0
- data/docs/sensitive_routes.md +47 -0
- data/docs/testing.md +74 -0
- data/docs/upgrades/0.10.0.md +58 -0
- data/docs/upgrades/README.md +9 -0
- data/lib/command_tower/authorization/default.yml +5 -33
- data/lib/command_tower/configuration/application/config.rb +2 -2
- data/lib/command_tower/configuration/base.rb +0 -1
- data/lib/command_tower/configuration/config.rb +31 -1
- data/lib/command_tower/configuration/credentials/config.rb +33 -0
- data/lib/command_tower/configuration/credentials/smtp.rb +33 -0
- data/lib/command_tower/configuration/credentials/twilio.rb +33 -0
- data/lib/command_tower/configuration/email/config.rb +1 -18
- data/lib/command_tower/configuration/identity/config.rb +19 -0
- data/lib/command_tower/configuration/identity/phone_verification.rb +54 -0
- data/lib/command_tower/configuration/jwt/config.rb +7 -0
- data/lib/command_tower/configuration/jwt/cookie/config.rb +64 -0
- data/lib/command_tower/configuration/jwt/cookie/csrf/config.rb +72 -0
- data/lib/command_tower/configuration/login/strategy/plain_text/config.rb +6 -0
- data/lib/command_tower/configuration/login/strategy/plain_text/email_verify.rb +5 -0
- data/lib/command_tower/configuration/login/strategy/plain_text/password_reset.rb +49 -0
- data/lib/command_tower/configuration/messaging/config.rb +60 -0
- data/lib/command_tower/configuration/messaging/pushover.rb +42 -0
- data/lib/command_tower/configuration/messaging/sms.rb +32 -0
- data/lib/command_tower/configuration/password_recovery_session/config.rb +61 -0
- data/lib/command_tower/configuration/password_recovery_session/rate_limits.rb +33 -0
- data/lib/command_tower/configuration/signup_session/config.rb +67 -0
- data/lib/command_tower/configuration/signup_session/email_availability.rb +18 -0
- data/lib/command_tower/configuration/signup_session/rate_limits.rb +48 -0
- data/lib/command_tower/configuration/user/config.rb +6 -5
- data/lib/command_tower/credential_resolution/env_backend.rb +25 -0
- data/lib/command_tower/credential_resolution/smtp_action_mailer_bridge.rb +24 -0
- data/lib/command_tower/credential_resolution/smtp_credentials.rb +26 -0
- data/lib/command_tower/credential_resolution/twilio_credentials.rb +26 -0
- data/lib/command_tower/credential_resolution.rb +78 -0
- data/lib/command_tower/current.rb +7 -0
- data/lib/command_tower/engine.rb +4 -1
- data/lib/command_tower/install/baseline.rb +31 -0
- data/lib/command_tower/install/doctor.rb +227 -0
- data/lib/command_tower/jwt/authorization_helper.rb +136 -0
- data/lib/command_tower/jwt/csrf_helper.rb +138 -0
- data/lib/command_tower/password_recovery/authorization_helper.rb +25 -0
- data/lib/command_tower/redis_connection.rb +21 -0
- data/lib/command_tower/schema/error/email_validation_required.rb +15 -0
- data/lib/command_tower/schema/shared/user.rb +32 -0
- data/lib/command_tower/schema.rb +2 -25
- data/lib/command_tower/signup/authorization_helper.rb +25 -0
- data/lib/command_tower/spec_helper.rb +58 -1
- data/lib/command_tower/testing.rb +62 -0
- data/lib/command_tower/version.rb +1 -1
- data/lib/command_tower.rb +20 -0
- data/lib/generators/command_tower/configure/USAGE +14 -2
- data/lib/generators/command_tower/configure/configure_generator.rb +29 -2
- data/lib/tasks/auto_annotate_models.rake +23 -55
- data/lib/tasks/install.rake +81 -0
- data/lib/tasks/users.rake +119 -0
- data/spec/factories/entity.rb +37 -0
- data/spec/factories/messaging.rb +156 -0
- data/spec/factories/role.rb +29 -0
- data/spec/factories/user.rb +53 -0
- data/spec/factories/user_secret.rb +12 -0
- metadata +576 -55
- data/app/controllers/command_tower/admin_controller.rb +0 -110
- data/app/controllers/command_tower/auth/plain_text_controller.rb +0 -133
- data/app/controllers/command_tower/inbox/message_blast_controller.rb +0 -89
- data/app/controllers/command_tower/inbox/message_controller.rb +0 -81
- data/app/controllers/command_tower/user_controller.rb +0 -49
- data/app/controllers/command_tower/username_controller.rb +0 -26
- data/app/helpers/command_tower/pagination_helper.rb +0 -40
- data/app/helpers/command_tower/schema_helper.rb +0 -29
- data/app/models/message.rb +0 -30
- data/app/models/message_blast.rb +0 -27
- data/app/services/command_tower/admin_service/users.rb +0 -27
- data/app/services/command_tower/inbox_service/blast/delete.rb +0 -23
- data/app/services/command_tower/inbox_service/blast/metadata.rb +0 -26
- data/app/services/command_tower/inbox_service/blast/new_user_blaster.rb +0 -24
- data/app/services/command_tower/inbox_service/blast/retrieve.rb +0 -30
- data/app/services/command_tower/inbox_service/blast/upsert.rb +0 -67
- data/app/services/command_tower/inbox_service/message/metadata.rb +0 -41
- data/app/services/command_tower/inbox_service/message/modify.rb +0 -44
- data/app/services/command_tower/inbox_service/message/retrieve.rb +0 -36
- data/app/services/command_tower/inbox_service/message/send.rb +0 -33
- data/app/services/command_tower/jwt/time_delay_token.rb +0 -17
- data/app/services/command_tower/login_strategy/plain_text/create.rb +0 -43
- data/app/services/command_tower/login_strategy/plain_text/email_verification/generate.rb +0 -29
- data/app/services/command_tower/login_strategy/plain_text/email_verification/send.rb +0 -23
- data/app/services/command_tower/login_strategy/plain_text/email_verification/verify.rb +0 -24
- data/app/services/command_tower/login_strategy/plain_text/login.rb +0 -50
- data/app/services/command_tower/pagination_service_helper.rb +0 -88
- data/app/services/command_tower/user_attributes/modify.rb +0 -68
- data/app/services/command_tower/user_attributes/roles.rb +0 -27
- data/db/migrate/20250223023306_create_command_tower_messages.rb +0 -12
- data/db/migrate/20250223023313_create_command_tower_message_blasts.rb +0 -14
- data/lib/command_tower/schema/admin/users.rb +0 -16
- data/lib/command_tower/schema/inbox/blast_request.rb +0 -15
- data/lib/command_tower/schema/inbox/blast_response.rb +0 -16
- data/lib/command_tower/schema/inbox/message_blast_entity.rb +0 -16
- data/lib/command_tower/schema/inbox/message_blast_metadata.rb +0 -16
- data/lib/command_tower/schema/inbox/message_entity.rb +0 -14
- data/lib/command_tower/schema/inbox/metadata.rb +0 -18
- data/lib/command_tower/schema/inbox/modified.rb +0 -13
- data/lib/command_tower/schema/page.rb +0 -11
- data/lib/command_tower/schema/pagination.rb +0 -16
- data/lib/command_tower/schema/plain_text/create_user_request.rb +0 -18
- data/lib/command_tower/schema/plain_text/create_user_response.rb +0 -17
- data/lib/command_tower/schema/plain_text/email_verify_request.rb +0 -11
- data/lib/command_tower/schema/plain_text/email_verify_response.rb +0 -11
- data/lib/command_tower/schema/plain_text/email_verify_send_request.rb +0 -9
- data/lib/command_tower/schema/plain_text/email_verify_send_response.rb +0 -11
- data/lib/command_tower/schema/plain_text/login_request.rb +0 -15
- data/lib/command_tower/schema/plain_text/login_response.rb +0 -16
- data/lib/command_tower/schema/user.rb +0 -28
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 726d34845596392ec87fbeacf508323aa72fbfa73d87094e40f0747595450ae9
|
|
4
|
+
data.tar.gz: 7f1ff986df01e27008e33867e80039a406534e57801111334e3e3c3798705e13
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 065535eb260884b0982e56e94c071d2d0707133a62e033d74db8c0d3eaed6c5629b924c8a4a27c007cbb9636aee5198070ef7b3a395cde9a77b1c0bb9661a4e0
|
|
7
|
+
data.tar.gz: dfd1337b02b1a6350a8ab5ba16316b77b219a47a383f294f42404dbb78f522f13cc0996e045a2dc9e758f4db0fd05f67bc80cfa2ebd6d9fc970e7db48508a211
|
data/README.md
CHANGED
|
@@ -1,62 +1,135 @@
|
|
|
1
1
|
# CommandTower
|
|
2
|
-
This is an API only base engine to build on top of. This Engine takes care of all Authentication, Token Refresh, and RBAC Roles so that you do not have to! For all applications, you can get right to work on implementing the code directly related to your project rather than dealing with the administrative overhead.
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
CommandTower is a mountable **Rails engine** that provides shared platform capabilities for host applications: JWT authentication, RBAC authorization, account/Me surfaces, messaging HTTP (inbox, preferences, endpoints), admin announcements, and shared test factories.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Hosts mount the engine, configure secrets and product policy, and build product features on top—without re-implementing platform foundations.
|
|
6
|
+
|
|
7
|
+
The engine is opinionated and configurable. Architecture follows a stable layer map (workflows orchestrate; services implement capabilities). See [Architecture](docs/architecture.md).
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
8
10
|
|
|
9
11
|
```ruby
|
|
12
|
+
# Gemfile
|
|
10
13
|
gem "command_tower"
|
|
11
14
|
```
|
|
12
15
|
|
|
13
|
-
And then execute:
|
|
14
16
|
```bash
|
|
15
|
-
|
|
17
|
+
bundle install
|
|
18
|
+
bin/rails command_tower:install
|
|
19
|
+
bin/rails db:migrate
|
|
20
|
+
bin/rails command_tower:doctor
|
|
16
21
|
```
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
Full install, upgrade, configuration, and troubleshooting: [Initializing CommandTower](docs/initializing.md).
|
|
24
|
+
|
|
25
|
+
After install, complete RBAC, feature gates, and a Me smoke check: [Host integration guide](docs/host_integration_guide.md) (**start here for a new Rails host**).
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
Controller / Job → Workflow → Shared Sequences / Services → Models & Clients
|
|
21
31
|
```
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
33
|
+
- Controllers are transport adapters (one workflow per action).
|
|
34
|
+
- Workflows orchestrate a business action.
|
|
35
|
+
- Services (including `CommandTower::ServiceBase`) implement one capability.
|
|
36
|
+
|
|
37
|
+
See [Architecture](docs/architecture.md) and [ServiceBase](app/services/command_tower/README.md).
|
|
38
|
+
|
|
39
|
+
## Documentation
|
|
40
|
+
|
|
41
|
+
| Guide | Purpose |
|
|
42
|
+
|-------|---------|
|
|
43
|
+
| [Host integration](docs/host_integration_guide.md) | **Start here** — step-by-step new Rails host path |
|
|
44
|
+
| [Upgrades](docs/upgrades/README.md) | Release upgrade summaries (see [0.10.0](docs/upgrades/0.10.0.md)) |
|
|
45
|
+
| [Initializing](docs/initializing.md) | Install, configure, migrate, doctor, upgrades |
|
|
46
|
+
| [Testing](docs/testing.md) | Shared FactoryBot / `CommandTower::Testing` |
|
|
47
|
+
| [Architecture](docs/architecture.md) | Layer map for hosts and contributors |
|
|
48
|
+
| [Controllers / routes](docs/controllers.md) | Engine route areas (index) |
|
|
49
|
+
| [API reference](docs/api_reference.md) | Endpoint catalog (detailed contracts) |
|
|
50
|
+
| [Extending](docs/extending.md) | Stable extension points / do-not-extend |
|
|
51
|
+
| [Models](docs/models.md) | `User`, `UserSecret`, reopening classes |
|
|
52
|
+
| [Authentication](docs/authentication.md) | JWT auth quick start |
|
|
53
|
+
| [Authorization](docs/authorization.md) | RBAC quick start |
|
|
54
|
+
| [Authentication & authorization guide](docs/authentication_authorization_guide.md) | Deep authn + RBAC |
|
|
55
|
+
| [Cookie authentication](docs/cookie_authentication_guide.md) | HttpOnly cookies, CORS, CSRF |
|
|
56
|
+
| [Sensitive changes](docs/sensitive_routes.md) | Verifier token / session invalidation |
|
|
57
|
+
| [Messaging](docs/messaging_integration_guide.md) | Current messaging surfaces |
|
|
58
|
+
| [Pagination](docs/pagination.md) | Pagination helpers |
|
|
59
|
+
| [ServiceBase](app/services/command_tower/README.md) | Service capability base |
|
|
60
|
+
| [Password reset workflow](docs/password_reset_workflow.md) | Forgot-password flow |
|
|
61
|
+
| [Change password workflow](docs/change_password_workflow.md) | Authenticated password change |
|
|
62
|
+
| [Email verification workflow](docs/email_verification_workflow.md) | Email verification flow |
|
|
63
|
+
|
|
64
|
+
## Installation and configuration
|
|
65
|
+
|
|
66
|
+
See [Initializing CommandTower](docs/initializing.md) for:
|
|
67
|
+
|
|
68
|
+
- `command_tower:install` / `install:migrations`
|
|
69
|
+
- Configure generator flags (`SKIP_CONFIGURE`, `SKIP_MOUNT`, `FORCE`)
|
|
70
|
+
- Schema ownership (**AD-SCH-01**)
|
|
71
|
+
- Secrets and doctor checks
|
|
72
|
+
- Existing customized hosts
|
|
73
|
+
|
|
74
|
+
## Testing
|
|
75
|
+
|
|
76
|
+
Shared factories for hosts:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
require "command_tower/testing"
|
|
80
|
+
CommandTower::Testing.install!
|
|
81
|
+
```
|
|
25
82
|
|
|
83
|
+
Details: [Testing with CommandTower](docs/testing.md).
|
|
26
84
|
|
|
27
|
-
|
|
85
|
+
Engine HTTP coverage lives primarily under `spec/requests/`. Residual journey coverage may remain under `spec/integration_test/`.
|
|
28
86
|
|
|
29
|
-
|
|
87
|
+
## Routes
|
|
30
88
|
|
|
31
|
-
|
|
89
|
+
Engine routes cover Auth, Me (profile, inbox, preferences, phone, Pushover), and Admin messaging announcements. Index: [Controllers](docs/controllers.md). Contracts: [API reference](docs/api_reference.md).
|
|
32
90
|
|
|
33
|
-
##
|
|
91
|
+
## Models
|
|
34
92
|
|
|
35
|
-
|
|
93
|
+
Core models such as `User` and `UserSecret` are available for hosts to use and reopen carefully. See [Models](docs/models.md).
|
|
36
94
|
|
|
37
|
-
|
|
95
|
+
## Authentication (JWT)
|
|
38
96
|
|
|
39
|
-
|
|
40
|
-
Authentication ensures that we know which user is requesting the action. When the Engine is unable to authenticate, a `401` status code is returned.
|
|
97
|
+
Authentication establishes identity (`401` when it fails).
|
|
41
98
|
|
|
42
|
-
|
|
99
|
+
- **Engine controllers** use `authenticate_request!` / `authorize_request!` (Authentication/Authorization boundaries) and return the application envelope.
|
|
100
|
+
- **Host controllers** may use provisional `before_action :authenticate_user!` (failure shapes can differ — see the deep guide).
|
|
101
|
+
|
|
102
|
+
- Quick start: [Authentication](docs/authentication.md)
|
|
103
|
+
- Deep guide: [Authentication & authorization](docs/authentication_authorization_guide.md)
|
|
104
|
+
- Web / SPA cookies: [Cookie authentication](docs/cookie_authentication_guide.md)
|
|
105
|
+
|
|
106
|
+
Cookie mode supports HttpOnly JWT cookies, SameSite, optional double-submit CSRF, and secure cookies in production.
|
|
43
107
|
|
|
44
108
|
## Authorization (RBAC)
|
|
45
|
-
Authorization is only done after authentication. This is the act of ensuring that the user can perform the action it is requesting. Put differently, I know who you are, but I need to validate you have permissions to complete the action. When the engine is unable to authorize the user, a `403` status code is returned.
|
|
46
109
|
|
|
47
|
-
|
|
110
|
+
Authorization establishes permission after authentication (`403` when it fails).
|
|
111
|
+
|
|
112
|
+
Engine defaults ship `owner` and `admin` (announcements). Hosts **must** supply `rbac_groups.yml` entities for Me/Auth surfaces (fail-closed). Host controllers may use provisional `authorize_user!` after `authenticate_user!`.
|
|
113
|
+
|
|
114
|
+
- Quick start: [Authorization](docs/authorization.md)
|
|
115
|
+
- Deep guide: [Authentication & authorization](docs/authentication_authorization_guide.md)
|
|
48
116
|
|
|
49
|
-
## Sensitive
|
|
117
|
+
## Sensitive changes
|
|
50
118
|
|
|
51
|
-
|
|
119
|
+
JWT tokens embed a `verifier_token` bound to the user. Rotating the verifier invalidates outstanding sessions. See [Sensitive changes](docs/sensitive_routes.md).
|
|
52
120
|
|
|
53
|
-
##
|
|
54
|
-
ServiceBase is built on top of Interactor. The ServiceBase is the heart of all logic for CommandTower. It includes Logging and enhanced ArgumentValidation that can directly return back to the API request.
|
|
121
|
+
## Messaging
|
|
55
122
|
|
|
56
|
-
|
|
123
|
+
Modern messaging surfaces: Me Inbox consume, Produce / ProduceMany emit, admin announcements. See [Messaging](docs/messaging_integration_guide.md).
|
|
57
124
|
|
|
58
125
|
## Pagination
|
|
59
|
-
|
|
126
|
+
|
|
127
|
+
Pagination helpers are available for controllers and services. See [Pagination](docs/pagination.md).
|
|
128
|
+
|
|
129
|
+
## Services
|
|
130
|
+
|
|
131
|
+
`CommandTower::ServiceBase` adds logging and argument validation for **service** classes under workflows. See [ServiceBase](app/services/command_tower/README.md).
|
|
60
132
|
|
|
61
133
|
## License
|
|
62
|
-
|
|
134
|
+
|
|
135
|
+
MIT — see [MIT-LICENSE](MIT-LICENSE).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
AuthContext = Data.define(
|
|
6
|
+
:user,
|
|
7
|
+
:token_expires_at,
|
|
8
|
+
:token_source,
|
|
9
|
+
:roles,
|
|
10
|
+
:principal_type,
|
|
11
|
+
:generated_token
|
|
12
|
+
) do
|
|
13
|
+
def initialize(user:, token_expires_at:, token_source:, roles:, principal_type:, generated_token: nil)
|
|
14
|
+
super(
|
|
15
|
+
user:,
|
|
16
|
+
token_expires_at:,
|
|
17
|
+
token_source:,
|
|
18
|
+
roles:,
|
|
19
|
+
principal_type:,
|
|
20
|
+
generated_token:
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.from_authenticate_session_result(data:, metadata:)
|
|
25
|
+
new(
|
|
26
|
+
user: data[:user],
|
|
27
|
+
token_expires_at: data[:token_expires_at],
|
|
28
|
+
token_source: metadata[:token_source],
|
|
29
|
+
roles: data[:user].roles,
|
|
30
|
+
principal_type: :user,
|
|
31
|
+
generated_token: data[:generated_token]
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Admin
|
|
5
|
+
module Messaging
|
|
6
|
+
class AnnouncementsController < CommandTower::ApplicationController
|
|
7
|
+
include CommandTower::Auth::AuthenticationBoundary
|
|
8
|
+
include CommandTower::Auth::AuthorizationBoundary
|
|
9
|
+
include CommandTower::Api::ApplicationResponseRenderer
|
|
10
|
+
|
|
11
|
+
before_action :authenticate_request!
|
|
12
|
+
before_action :authorize_request!
|
|
13
|
+
|
|
14
|
+
def create
|
|
15
|
+
deserialized = CommandTower::Deserializers::Admin::Messaging::CreateAnnouncementDeserializer.call(params)
|
|
16
|
+
unless deserialized.success?
|
|
17
|
+
return render_application_result(
|
|
18
|
+
CommandTower::Workflows::WorkflowResult.failure(
|
|
19
|
+
errors: [CommandTower::Errors::ValidationError.new(details: { base: "Invalid request parameters" })],
|
|
20
|
+
http_status: :unprocessable_entity
|
|
21
|
+
)
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
render_application_result(
|
|
26
|
+
CommandTower::Workflows::Admin::Messaging::CreateAnnouncementWorkflow.call(
|
|
27
|
+
input: deserialized.input
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module CommandTower
|
|
4
4
|
class ApplicationController < ActionController::API
|
|
5
|
-
AUTHENTICATION_HEADER =
|
|
6
|
-
AUTHENTICATION_EXPIRE_HEADER =
|
|
7
|
-
AUTHENTICATION_WITH_RESET =
|
|
5
|
+
AUTHENTICATION_HEADER = CommandTower::Jwt::AuthorizationHelper::AUTHENTICATION_HEADER
|
|
6
|
+
AUTHENTICATION_EXPIRE_HEADER = CommandTower::Jwt::AuthorizationHelper::AUTHENTICATION_EXPIRE_HEADER
|
|
7
|
+
AUTHENTICATION_WITH_RESET = CommandTower::Jwt::AuthorizationHelper::AUTHENTICATION_WITH_RESET
|
|
8
8
|
|
|
9
9
|
def safe_boolean(value:)
|
|
10
10
|
return nil unless [true, false, "true", "false", "0", "1", 0, 1].include?(value)
|
|
@@ -13,30 +13,84 @@ module CommandTower
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
###
|
|
16
|
-
# Authenticate user via the passed in header
|
|
17
|
-
# AUTHENTICATION_HEADER="Bearer
|
|
16
|
+
# Authenticate user via the passed in header or cookie
|
|
17
|
+
# AUTHENTICATION_HEADER="Bearer {token value}" or cookie (if enabled)
|
|
18
18
|
def authenticate_user!(bypass_email_validation: false)
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
# Extract and validate token (from header or cookie fallback)
|
|
20
|
+
token_data = CommandTower::Jwt::AuthorizationHelper.extract_token(request)
|
|
21
|
+
if token_data[:error]
|
|
21
22
|
status = 401
|
|
22
|
-
schema = CommandTower::Schema::Error::Base.new(status:, message:
|
|
23
|
+
schema = CommandTower::Schema::Error::Base.new(status:, message: token_data[:message])
|
|
23
24
|
render(json: schema.to_h, status:)
|
|
24
25
|
return false
|
|
25
26
|
end
|
|
26
27
|
|
|
27
|
-
token =
|
|
28
|
-
|
|
28
|
+
token = token_data[:token]
|
|
29
|
+
token_source = token_data[:source]
|
|
30
|
+
|
|
31
|
+
# CSRF validation for cookie-authenticated unsafe requests
|
|
32
|
+
# Enforcement is centralized here because token_source is only reliably known in this shared filter
|
|
33
|
+
if csrf_required?(request, token_source)
|
|
34
|
+
csrf_validation = CommandTower::Jwt::CsrfHelper.validate(request)
|
|
35
|
+
unless csrf_validation[:valid]
|
|
36
|
+
status = 403
|
|
37
|
+
schema = CommandTower::Schema::Error::Base.new(
|
|
38
|
+
status: status.to_s,
|
|
39
|
+
message: csrf_validation[:message] # Stable error code: "csrf_missing" or "csrf_mismatch"
|
|
40
|
+
)
|
|
41
|
+
render(json: schema.to_h, status: status)
|
|
42
|
+
return false
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
with_reset = CommandTower::Jwt::AuthorizationHelper.get_with_reset_flag(request)
|
|
29
47
|
result = CommandTower::Jwt::AuthenticateUser.(token:, bypass_email_validation:, with_reset:)
|
|
30
48
|
if result.success?
|
|
31
49
|
@current_user = result.user
|
|
32
|
-
response.set_header(AUTHENTICATION_EXPIRE_HEADER, result.expires_at)
|
|
33
50
|
if with_reset
|
|
34
|
-
|
|
51
|
+
# Use helper to set both headers and cookie (if enabled)
|
|
52
|
+
CommandTower::Jwt::AuthorizationHelper.set_token(
|
|
53
|
+
response,
|
|
54
|
+
result.generated_token,
|
|
55
|
+
expires_at: result.expires_at
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Handle CSRF cookie issuance/rotation for token reset path
|
|
59
|
+
# CSRF cookie issuance rules:
|
|
60
|
+
# - rotate_on_reset = true → force rotate (generate new token)
|
|
61
|
+
# - rotate_on_reset = false → ensure exists only (create if missing, keep if exists)
|
|
62
|
+
if CommandTower::Jwt::CsrfHelper.csrf_enabled?
|
|
63
|
+
if CommandTower.config.jwt.cookie.csrf.rotate_on_reset
|
|
64
|
+
CommandTower::Jwt::CsrfHelper.ensure_cookie(request, response, should_rotate: true)
|
|
65
|
+
else
|
|
66
|
+
# Ensure cookie exists (rotate-or-ensure model)
|
|
67
|
+
CommandTower::Jwt::CsrfHelper.ensure_cookie(request, response, should_rotate: false)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
else
|
|
71
|
+
# Only set expire header when not resetting
|
|
72
|
+
response.set_header(AUTHENTICATION_EXPIRE_HEADER, result.expires_at)
|
|
35
73
|
end
|
|
36
74
|
true
|
|
37
75
|
else
|
|
38
|
-
status
|
|
39
|
-
|
|
76
|
+
# Check if this is an email validation failure (status 412)
|
|
77
|
+
if result.status == 412
|
|
78
|
+
status = 412
|
|
79
|
+
schema = CommandTower::Schema::Error::EmailValidationRequired.new(
|
|
80
|
+
status:,
|
|
81
|
+
message: result.msg,
|
|
82
|
+
meta: { email_validated: false }
|
|
83
|
+
)
|
|
84
|
+
# Do NOT clear cookie for 412 status - user needs to keep cookie to verify email
|
|
85
|
+
else
|
|
86
|
+
# If authentication failed and token came from cookie, clear the invalid cookie
|
|
87
|
+
# Exception: Do not clear cookie for 412 status (email validation required)
|
|
88
|
+
if token_source == :cookie
|
|
89
|
+
CommandTower::Jwt::AuthorizationHelper.clear_cookie(response)
|
|
90
|
+
end
|
|
91
|
+
status = result.status || 401
|
|
92
|
+
schema = CommandTower::Schema::Error::Base.new(status:, message: result.msg)
|
|
93
|
+
end
|
|
40
94
|
render(json: schema.to_h, status:)
|
|
41
95
|
# Must return false so callbacks know to halt propagation
|
|
42
96
|
false
|
|
@@ -77,5 +131,17 @@ module CommandTower
|
|
|
77
131
|
def current_user
|
|
78
132
|
@current_user ||= nil
|
|
79
133
|
end
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
def csrf_required?(request, token_source)
|
|
138
|
+
return false unless CommandTower::Jwt::CsrfHelper.csrf_enabled?
|
|
139
|
+
# CRITICAL: Check token_source, not cookie presence
|
|
140
|
+
return false unless token_source == :cookie
|
|
141
|
+
return false if request.get? || request.head? || request.options?
|
|
142
|
+
|
|
143
|
+
# Unsafe methods: POST, PUT, PATCH, DELETE
|
|
144
|
+
%w[POST PUT PATCH DELETE].include?(request.method)
|
|
145
|
+
end
|
|
80
146
|
end
|
|
81
147
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
module Email
|
|
6
|
+
class AvailabilityController < CommandTower::ApplicationController
|
|
7
|
+
include CommandTower::Auth::SignupSessionBoundary
|
|
8
|
+
|
|
9
|
+
before_action :authenticate_signup_session!
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
deserialized = CommandTower::Deserializers::Auth::EmailAvailabilityDeserializer.call(params)
|
|
13
|
+
return render_email_deserializer_errors unless deserialized.success?
|
|
14
|
+
|
|
15
|
+
result = CommandTower::Workflows::Auth::EmailAvailabilityWorkflow.call(
|
|
16
|
+
input: deserialized.input,
|
|
17
|
+
signup_session: current_signup_session
|
|
18
|
+
)
|
|
19
|
+
render_application_result(result)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def render_email_deserializer_errors
|
|
25
|
+
render_application_result(
|
|
26
|
+
CommandTower::Workflows::WorkflowResult.failure(
|
|
27
|
+
errors: [CommandTower::Errors::ValidationError.new(details: { email: "Email is required" })],
|
|
28
|
+
http_status: :unprocessable_entity
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
module EmailVerification
|
|
6
|
+
class SendController < CommandTower::ApplicationController
|
|
7
|
+
include CommandTower::Auth::AuthenticationBoundary
|
|
8
|
+
include CommandTower::Auth::AuthorizationBoundary
|
|
9
|
+
|
|
10
|
+
# Requesting a verification code is exactly the action an unverified user
|
|
11
|
+
# needs, so the email verification precondition is bypassed here.
|
|
12
|
+
before_action -> { authenticate_request!(bypass_email_validation: true) }
|
|
13
|
+
before_action :authorize_request!
|
|
14
|
+
|
|
15
|
+
def create
|
|
16
|
+
result = CommandTower::Workflows::Auth::EmailVerification::SendWorkflow.call(
|
|
17
|
+
current_user: current_user
|
|
18
|
+
)
|
|
19
|
+
render_application_result(result)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
module EmailVerification
|
|
6
|
+
class VerifyController < CommandTower::ApplicationController
|
|
7
|
+
include CommandTower::Auth::AuthenticationBoundary
|
|
8
|
+
include CommandTower::Auth::AuthorizationBoundary
|
|
9
|
+
|
|
10
|
+
before_action -> { authenticate_request!(bypass_email_validation: true) }
|
|
11
|
+
before_action :authorize_request!
|
|
12
|
+
|
|
13
|
+
def create
|
|
14
|
+
deserialized = CommandTower::Deserializers::Auth::EmailVerification::VerifyDeserializer.call(params)
|
|
15
|
+
return render_verify_deserializer_errors unless deserialized.success?
|
|
16
|
+
|
|
17
|
+
result = CommandTower::Workflows::Auth::EmailVerification::VerifyWorkflow.call(
|
|
18
|
+
current_user: current_user,
|
|
19
|
+
input: deserialized.input
|
|
20
|
+
)
|
|
21
|
+
render_application_result(result)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def render_verify_deserializer_errors
|
|
27
|
+
render_application_result(
|
|
28
|
+
CommandTower::Workflows::WorkflowResult.failure(
|
|
29
|
+
errors: [
|
|
30
|
+
CommandTower::Errors::Auth::VerificationCodeInvalidError.new(
|
|
31
|
+
details: { code: "Verification code is required" }
|
|
32
|
+
)
|
|
33
|
+
],
|
|
34
|
+
http_status: :unprocessable_entity
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
class IdentityPolicyController < CommandTower::ApplicationController
|
|
6
|
+
include CommandTower::Api::ApplicationResponseRenderer
|
|
7
|
+
|
|
8
|
+
def show
|
|
9
|
+
result = CommandTower::Workflows::Auth::IdentityPolicyWorkflow.call
|
|
10
|
+
render_application_result(result)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
class LogoutController < CommandTower::ApplicationController
|
|
6
|
+
include CommandTower::Api::ApplicationResponseRenderer
|
|
7
|
+
|
|
8
|
+
def create
|
|
9
|
+
result = CommandTower::Workflows::Auth::LogoutWorkflow.call
|
|
10
|
+
render_application_result(result)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
module PasswordRecoverySession
|
|
6
|
+
class CreateController < CommandTower::ApplicationController
|
|
7
|
+
include CommandTower::Api::ApplicationResponseRenderer
|
|
8
|
+
|
|
9
|
+
def create
|
|
10
|
+
client_ip = CommandTower::Services::Auth::ClientIpResolver.call(request: request)
|
|
11
|
+
result = CommandTower::Workflows::Auth::PasswordRecoverySession::CreateWorkflow.call(client_ip: client_ip)
|
|
12
|
+
render_application_result(result)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
module PasswordReset
|
|
6
|
+
class ResetController < CommandTower::ApplicationController
|
|
7
|
+
include CommandTower::Api::ApplicationResponseRenderer
|
|
8
|
+
include CommandTower::Api::DeserializerFailureDetails
|
|
9
|
+
|
|
10
|
+
def create
|
|
11
|
+
deserialized = CommandTower::Deserializers::Auth::PasswordReset::ResetDeserializer.call(params)
|
|
12
|
+
return render_reset_deserializer_errors(deserialized) unless deserialized.success?
|
|
13
|
+
|
|
14
|
+
result = CommandTower::Workflows::Auth::PasswordReset::ResetWorkflow.call(input: deserialized.input)
|
|
15
|
+
render_application_result(result)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def render_reset_deserializer_errors(deserialized)
|
|
21
|
+
render_application_result(
|
|
22
|
+
CommandTower::Workflows::WorkflowResult.failure(
|
|
23
|
+
errors: [
|
|
24
|
+
CommandTower::Errors::ValidationError.new(
|
|
25
|
+
details: deserializer_failure_details(deserialized)
|
|
26
|
+
)
|
|
27
|
+
],
|
|
28
|
+
http_status: :unprocessable_entity
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
module PasswordReset
|
|
6
|
+
class SendController < CommandTower::ApplicationController
|
|
7
|
+
include CommandTower::Auth::PasswordRecoverySessionBoundary
|
|
8
|
+
include CommandTower::Api::DeserializerFailureDetails
|
|
9
|
+
|
|
10
|
+
before_action :authenticate_password_recovery_session!
|
|
11
|
+
|
|
12
|
+
def create
|
|
13
|
+
deserialized = CommandTower::Deserializers::Auth::PasswordReset::SendDeserializer.call(params)
|
|
14
|
+
return render_send_deserializer_errors(deserialized) unless deserialized.success?
|
|
15
|
+
|
|
16
|
+
result = CommandTower::Workflows::Auth::PasswordReset::SendWorkflow.call(
|
|
17
|
+
input: deserialized.input,
|
|
18
|
+
password_recovery_session: current_password_recovery_session
|
|
19
|
+
)
|
|
20
|
+
render_application_result(result)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def render_send_deserializer_errors(deserialized)
|
|
26
|
+
render_application_result(
|
|
27
|
+
CommandTower::Workflows::WorkflowResult.failure(
|
|
28
|
+
errors: [
|
|
29
|
+
CommandTower::Errors::ValidationError.new(
|
|
30
|
+
details: deserializer_failure_details(deserialized)
|
|
31
|
+
)
|
|
32
|
+
],
|
|
33
|
+
http_status: :unprocessable_entity
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CommandTower
|
|
4
|
+
module Auth
|
|
5
|
+
module PasswordReset
|
|
6
|
+
class ValidateController < CommandTower::ApplicationController
|
|
7
|
+
include CommandTower::Api::ApplicationResponseRenderer
|
|
8
|
+
include CommandTower::Api::DeserializerFailureDetails
|
|
9
|
+
|
|
10
|
+
def create
|
|
11
|
+
deserialized = CommandTower::Deserializers::Auth::PasswordReset::ValidateDeserializer.call(params)
|
|
12
|
+
return render_validate_deserializer_errors(deserialized) unless deserialized.success?
|
|
13
|
+
|
|
14
|
+
result = CommandTower::Workflows::Auth::PasswordReset::ValidateWorkflow.call(input: deserialized.input)
|
|
15
|
+
render_application_result(result)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def render_validate_deserializer_errors(deserialized)
|
|
21
|
+
render_application_result(
|
|
22
|
+
CommandTower::Workflows::WorkflowResult.failure(
|
|
23
|
+
errors: [
|
|
24
|
+
CommandTower::Errors::ValidationError.new(
|
|
25
|
+
details: deserializer_failure_details(deserialized)
|
|
26
|
+
)
|
|
27
|
+
],
|
|
28
|
+
http_status: :unprocessable_entity
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|