channels_twitter_controller.rb 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class ChannelsTwitterController < ApplicationController
  3. prepend_before_action :authenticate_and_authorize!, except: %i[webhook_incoming webhook_verify]
  4. skip_before_action :verify_csrf_token, only: %i[webhook_incoming webhook_verify]
  5. before_action :validate_webhook_signature!, only: :webhook_incoming
  6. def webhook_incoming
  7. @channel.process(params.permit!.to_h)
  8. render json: {}
  9. end
  10. def validate_webhook_signature!
  11. header_name = 'x-twitter-webhooks-signature'
  12. given_signature = request.headers[header_name]
  13. raise Exceptions::UnprocessableEntity, "Missing '#{header_name}' header" if given_signature.blank?
  14. calculated_signature = hmac_signature_by_app(request.raw_post)
  15. raise Exceptions::NotAuthorized if calculated_signature != given_signature
  16. raise Exceptions::UnprocessableEntity, __("The required parameter 'for_user_id' is missing.") if params[:for_user_id].blank?
  17. @channel = nil
  18. Channel.where(area: 'Twitter::Account', active: true).each do |channel|
  19. next if channel.options[:user].blank?
  20. next if channel.options[:user][:id].to_s != params[:for_user_id].to_s
  21. @channel = channel
  22. end
  23. raise Exceptions::UnprocessableEntity, "Could not find channel for user id '#{params[:for_user_id]}'!" if !@channel
  24. true
  25. end
  26. def hmac_signature_by_app(content)
  27. external_credential = ExternalCredential.find_by(name: 'twitter')
  28. raise Exceptions::UnprocessableEntity, __("The required 'ExternalCredential' 'twitter' could not be found.") if !external_credential
  29. hmac_signature_gen(external_credential.credentials[:consumer_secret], content)
  30. end
  31. def hmac_signature_gen(consumer_secret, content)
  32. hashed = OpenSSL::HMAC.digest('sha256', consumer_secret, content)
  33. hashed = Base64.strict_encode64(hashed)
  34. "sha256=#{hashed}"
  35. end
  36. def webhook_verify
  37. external_credential = Rails.cache.read('external_credential_twitter')
  38. if !external_credential && ExternalCredential.exists?(name: 'twitter')
  39. external_credential = ExternalCredential.find_by(name: 'twitter').credentials
  40. end
  41. raise Exceptions::UnprocessableEntity, __('The required value external_credential could not be found in the cache.') if external_credential.blank?
  42. raise Exceptions::UnprocessableEntity, __("The required value 'external_credential[:consumer_secret]' could not be found in the cache.") if external_credential[:consumer_secret].blank?
  43. raise Exceptions::UnprocessableEntity, __("The required parameter 'crc_token' is missing from the Twitter verify payload!") if params['crc_token'].blank?
  44. render json: {
  45. response_token: hmac_signature_gen(external_credential[:consumer_secret], params['crc_token'])
  46. }
  47. end
  48. def index
  49. assets = {}
  50. external_credential_ids = []
  51. ExternalCredential.where(name: 'twitter').each do |external_credential|
  52. assets = external_credential.assets(assets)
  53. external_credential_ids.push external_credential.id
  54. end
  55. channel_ids = []
  56. Channel.where(area: 'Twitter::Account').reorder(:id).each do |channel|
  57. assets = channel.assets(assets)
  58. channel_ids.push channel.id
  59. end
  60. render json: {
  61. assets: assets,
  62. channel_ids: channel_ids,
  63. external_credential_ids: external_credential_ids,
  64. callback_url: ExternalCredential.callback_url('twitter'),
  65. }
  66. end
  67. def update
  68. model_update_render(Channel, params)
  69. end
  70. def enable
  71. channel = Channel.find_by(id: params[:id], area: 'Twitter::Account')
  72. channel.active = true
  73. channel.save!
  74. render json: {}
  75. end
  76. def disable
  77. channel = Channel.find_by(id: params[:id], area: 'Twitter::Account')
  78. channel.active = false
  79. channel.save!
  80. render json: {}
  81. end
  82. def destroy
  83. channel = Channel.find_by(id: params[:id], area: 'Twitter::Account')
  84. channel.destroy
  85. render json: {}
  86. end
  87. end