channels_twitter_controller.rb 3.8 KB

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