form_controller.rb 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
  2. class FormController < ApplicationController
  3. skip_before_action :verify_csrf_token
  4. before_action :cors_preflight_check
  5. after_action :set_access_control_headers_execute
  6. skip_before_action :user_device_check
  7. def configuration
  8. return if !enabled?
  9. return if !fingerprint_exists?
  10. return if limit_reached?
  11. api_path = Rails.configuration.api_path
  12. http_type = Setting.get('http_type')
  13. fqdn = Setting.get('fqdn')
  14. endpoint = "#{http_type}://#{fqdn}#{api_path}/form_submit"
  15. result = {
  16. enabled: Setting.get('form_ticket_create'),
  17. endpoint: endpoint,
  18. token: token_gen(params[:fingerprint])
  19. }
  20. if params[:test] && current_user && current_user.permissions?('admin.channel_formular')
  21. result[:enabled] = true
  22. end
  23. render json: result, status: :ok
  24. end
  25. def submit
  26. return if !enabled?
  27. return if !fingerprint_exists?
  28. return if !token_valid?(params[:token], params[:fingerprint])
  29. return if limit_reached?
  30. # validate input
  31. errors = {}
  32. if params[:name].blank?
  33. errors['name'] = 'required'
  34. end
  35. if params[:title].blank?
  36. errors['title'] = 'required'
  37. end
  38. if params[:body].blank?
  39. errors['body'] = 'required'
  40. end
  41. if params[:email].blank?
  42. errors['email'] = 'required'
  43. else
  44. begin
  45. email_address_validation = EmailAddressValidation.new(params[:email])
  46. if !email_address_validation.valid_format? || !email_address_validation.valid_mx?
  47. errors['email'] = 'invalid'
  48. end
  49. rescue => e
  50. message = e.to_s
  51. Rails.logger.info "Can't verify email #{params[:email]}: #{message}"
  52. # ignore 450, graylistings
  53. errors['email'] = message if !message.match?(/450/)
  54. end
  55. end
  56. if errors.present?
  57. render json: {
  58. errors: errors
  59. }, status: :ok
  60. return
  61. end
  62. name = params[:name].strip
  63. email = params[:email].strip.downcase
  64. customer = User.find_by(email: email)
  65. if !customer
  66. role_ids = Role.signup_role_ids
  67. customer = User.create(
  68. firstname: name,
  69. lastname: '',
  70. email: email,
  71. active: true,
  72. role_ids: role_ids,
  73. updated_by_id: 1,
  74. created_by_id: 1,
  75. )
  76. end
  77. # set current user
  78. UserInfo.current_user_id = customer.id
  79. group = Group.find_by(id: Setting.get('form_ticket_create_group_id'))
  80. if !group
  81. group = Group.where(active: true).first
  82. if !group
  83. group = Group.first
  84. end
  85. end
  86. ticket = Ticket.create!(
  87. group_id: group.id,
  88. customer_id: customer.id,
  89. title: params[:title],
  90. preferences: {
  91. form: {
  92. remote_ip: request.remote_ip,
  93. fingerprint_md5: Digest::MD5.hexdigest(params[:fingerprint]),
  94. }
  95. }
  96. )
  97. article = Ticket::Article.create!(
  98. ticket_id: ticket.id,
  99. type_id: Ticket::Article::Type.find_by(name: 'web').id,
  100. sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
  101. body: params[:body],
  102. subject: params[:title],
  103. internal: false,
  104. )
  105. params[:file]&.each do |file|
  106. Store.add(
  107. object: 'Ticket::Article',
  108. o_id: article.id,
  109. data: file.read,
  110. filename: file.original_filename,
  111. preferences: {
  112. 'Mime-Type' => file.content_type,
  113. }
  114. )
  115. end
  116. UserInfo.current_user_id = 1
  117. result = {
  118. ticket: {
  119. id: ticket.id,
  120. number: ticket.number
  121. }
  122. }
  123. render json: result, status: :ok
  124. end
  125. private
  126. def token_gen(fingerprint)
  127. crypt = ActiveSupport::MessageEncryptor.new(Setting.get('application_secret')[0, 32])
  128. fingerprint = "#{Base64.strict_encode64(Setting.get('fqdn'))}:#{Time.zone.now.to_i}:#{Base64.strict_encode64(fingerprint)}"
  129. Base64.strict_encode64(crypt.encrypt_and_sign(fingerprint))
  130. end
  131. def token_valid?(token, fingerprint)
  132. if token.blank?
  133. Rails.logger.info 'No token for form!'
  134. raise Exceptions::NotAuthorized
  135. end
  136. begin
  137. crypt = ActiveSupport::MessageEncryptor.new(Setting.get('application_secret')[0, 32])
  138. result = crypt.decrypt_and_verify(Base64.decode64(token))
  139. rescue
  140. Rails.logger.info 'Invalid token for form!'
  141. raise Exceptions::NotAuthorized
  142. end
  143. if result.blank?
  144. Rails.logger.info 'Invalid token for form!'
  145. raise Exceptions::NotAuthorized
  146. end
  147. parts = result.split(/:/)
  148. if parts.count != 3
  149. Rails.logger.info "Invalid token for form (need to have 3 parts, only #{parts.count} found)!"
  150. raise Exceptions::NotAuthorized
  151. end
  152. fqdn_local = Base64.decode64(parts[0])
  153. if fqdn_local != Setting.get('fqdn')
  154. Rails.logger.info "Invalid token for form (invalid fqdn found #{fqdn_local} != #{Setting.get('fqdn')})!"
  155. raise Exceptions::NotAuthorized
  156. end
  157. fingerprint_local = Base64.decode64(parts[2])
  158. if fingerprint_local != fingerprint
  159. Rails.logger.info "Invalid token for form (invalid fingerprint found #{fingerprint_local} != #{fingerprint})!"
  160. raise Exceptions::NotAuthorized
  161. end
  162. if parts[1].to_i < (Time.zone.now.to_i - 60 * 60 * 24)
  163. Rails.logger.info 'Invalid token for form (token expired})!'
  164. raise Exceptions::NotAuthorized
  165. end
  166. true
  167. end
  168. def limit_reached?
  169. return false if !SearchIndexBackend.enabled?
  170. # quote ipv6 ip'
  171. remote_ip = request.remote_ip.gsub(':', '\\:')
  172. # in elasticsearch7 "created_at:>now-1h" is not working. Needed to catch -2h
  173. form_limit_by_ip_per_hour = Setting.get('form_ticket_create_by_ip_per_hour') || 20
  174. result = SearchIndexBackend.search("preferences.form.remote_ip:'#{remote_ip}' AND created_at:>now-2h", 'Ticket', limit: form_limit_by_ip_per_hour)
  175. raise Exceptions::NotAuthorized if result.count >= form_limit_by_ip_per_hour.to_i
  176. form_limit_by_ip_per_day = Setting.get('form_ticket_create_by_ip_per_day') || 240
  177. result = SearchIndexBackend.search("preferences.form.remote_ip:'#{remote_ip}' AND created_at:>now-1d", 'Ticket', limit: form_limit_by_ip_per_day)
  178. raise Exceptions::NotAuthorized if result.count >= form_limit_by_ip_per_day.to_i
  179. form_limit_per_day = Setting.get('form_ticket_create_per_day') || 5000
  180. result = SearchIndexBackend.search('preferences.form.remote_ip:* AND created_at:>now-1d', 'Ticket', limit: form_limit_per_day)
  181. raise Exceptions::NotAuthorized if result.count >= form_limit_per_day.to_i
  182. false
  183. end
  184. def fingerprint_exists?
  185. return true if params[:fingerprint].present? && params[:fingerprint].length > 30
  186. Rails.logger.info 'No fingerprint given!'
  187. raise Exceptions::NotAuthorized
  188. end
  189. def enabled?
  190. return true if params[:test] && current_user && current_user.permissions?('admin.channel_formular')
  191. return true if Setting.get('form_ticket_create')
  192. raise Exceptions::NotAuthorized
  193. end
  194. end