You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/app/mailers/cohort_mailer.rb

81 lines
2.3 KiB

# frozen_string_literal: true
# CohortMailer
# Handles email delivery for cohort management
# Implements Winston's secure email requirements
class CohortMailer < ApplicationMailer
# CRITICAL: Never include raw token in logs
# CRITICAL: Use HTTPS invitation URL
# CRITICAL: Token only in email, not in URL params
def admin_invitation(invitation)
@invitation = invitation
@institution = invitation.institution
@role = invitation.role
@token = generate_acceptance_token(invitation)
# Security: Verify we have the token before sending
unless @token.present?
Rails.logger.error "No token available for invitation #{invitation.id}"
return
end
# Set email metadata
@subject = "Invitation to manage #{@institution.name} - #{@role.titleize}"
# Track email delivery
mail(
to: invitation.email,
subject: @subject,
track: true
) do |format|
format.html { render 'admin_invitation' }
format.text { render 'admin_invitation' }
end
end
def super_admin_demoted(user, institution)
@user = user
@institution = institution
mail(
to: user.email,
subject: "Role change notification - #{institution.name}"
)
end
private
# Generate secure acceptance token
# Note: This retrieves the raw token from Redis if available
# If not available (already used), returns nil
def generate_acceptance_token(invitation)
# The raw token is only available during the initial creation
# After that, we rely on the invitation flow
# For security, we don't regenerate tokens
# In a real implementation, we might store the raw token temporarily
# in Redis with a short TTL for email delivery
redis = Redis.current
key = "invitation_token_pending:#{invitation.hashed_token}"
# Try to get pending token (set during creation)
raw_token = redis.get(key)
# If not found, the invitation might be old or token already delivered
# In this case, we should not send the email
return nil unless raw_token
# Set TTL for the token in email (24 hours from now)
redis.expire(key, 86400)
raw_token
end
# Override to add security headers
def mail(headers = {}, &block)
headers[:'X-SECURITY'] = 'Cohort-Invitation'
headers[:'X-Role'] = @role if @role
super(headers, &block)
end
end