chat_sdk-whatsapp 1.0.0 → 1.1.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/lib/chat_sdk/whatsapp/adapter.rb +18 -2
- data/lib/chat_sdk/whatsapp/api_client.rb +46 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 56d2740433f6135cc084664554536e8aada5dadc9784f495e63b744d572bb1b1
|
|
4
|
+
data.tar.gz: 97cae7132efd2af77e10be202134f1430b0142477912745158294c7d297afc22
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58f760deb91563a1cd2cec6a32725fbdecf1249ad6116509ac6646321b36d116b0630220553c2b00c6dde71f8eb9583570cc6a02ffe6d9c386c47827091120a2
|
|
7
|
+
data.tar.gz: 4475cb8cec45232adfe4a1090b08960071a8f041753b2e75d15f977791f35894285e2bd728be042aca550913e89fda9a87d9abadd0af0bc8fe1b700b9797173b
|
|
@@ -6,7 +6,7 @@ module ChatSDK
|
|
|
6
6
|
include ChatSDK::Adapter::MetaVerification
|
|
7
7
|
include ChatSDK::Adapter::MediaTypes
|
|
8
8
|
|
|
9
|
-
capabilities :direct_messages, :file_uploads, :reactions
|
|
9
|
+
capabilities :direct_messages, :file_uploads, :reactions, :replies, :read_receipts
|
|
10
10
|
|
|
11
11
|
attr_reader :client
|
|
12
12
|
|
|
@@ -92,10 +92,26 @@ module ChatSDK
|
|
|
92
92
|
@client.send_template(to: channel_id, template_name: template_name, language_code: language_code, components: components)
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
def mark_as_read(message_id:)
|
|
95
|
+
def mark_as_read(message_id:, channel_id: nil, thread_id: nil, message: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
96
96
|
@client.mark_as_read(message_id: message_id)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
+
def reply_message(channel_id:, message_id:, message:, thread_id: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
100
|
+
payload = prepare_message_payload(message)
|
|
101
|
+
payload[:context] = {message_id: message_id}
|
|
102
|
+
result = @client.send_message(to: channel_id, **payload)
|
|
103
|
+
parse_whatsapp_message(result, channel_id)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def download_media(media_id:)
|
|
107
|
+
meta = @client.get_media_url(media_id: media_id)
|
|
108
|
+
url = meta["url"]
|
|
109
|
+
return nil unless url
|
|
110
|
+
|
|
111
|
+
response = @client.download_media(url: url)
|
|
112
|
+
response.body
|
|
113
|
+
end
|
|
114
|
+
|
|
99
115
|
def upload_file(channel_id:, io:, filename:, thread_id: nil, comment: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
100
116
|
content_type = detect_content_type(filename)
|
|
101
117
|
media_type = media_type_for(content_type)
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
3
5
|
module ChatSDK
|
|
4
6
|
module WhatsApp
|
|
5
7
|
class ApiClient < ChatSDK::ApiClient::Base
|
|
6
8
|
BASE_URL = "https://graph.facebook.com/v25.0"
|
|
9
|
+
MEDIA_HOSTS = %w[fbcdn.net fbsbx.com].freeze
|
|
10
|
+
MEDIA_DOWNLOAD_LIMIT = 25 * 1024 * 1024
|
|
11
|
+
MEDIA_DOWNLOAD_TIMEOUT = 30
|
|
7
12
|
|
|
8
13
|
def initialize(access_token, phone_number_id)
|
|
9
14
|
@access_token = access_token
|
|
@@ -51,6 +56,19 @@ module ChatSDK
|
|
|
51
56
|
})
|
|
52
57
|
end
|
|
53
58
|
|
|
59
|
+
def get_media_url(media_id:)
|
|
60
|
+
request(:get, media_id.to_s)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def download_media(url:)
|
|
64
|
+
validate_media_url!(url)
|
|
65
|
+
Faraday.get(url) do |req|
|
|
66
|
+
req.headers["Authorization"] = "Bearer #{@access_token}"
|
|
67
|
+
req.options.timeout = MEDIA_DOWNLOAD_TIMEOUT
|
|
68
|
+
end
|
|
69
|
+
.tap { |response| validate_media_response!(response) }
|
|
70
|
+
end
|
|
71
|
+
|
|
54
72
|
def upload_media(io:, filename:, content_type:)
|
|
55
73
|
response = upload_connection.post("#{@phone_number_id}/media") do |req|
|
|
56
74
|
req.body = {
|
|
@@ -77,6 +95,34 @@ module ChatSDK
|
|
|
77
95
|
faraday.headers["Authorization"] = "Bearer #{@access_token}"
|
|
78
96
|
end
|
|
79
97
|
|
|
98
|
+
def validate_media_url!(url)
|
|
99
|
+
uri = URI.parse(url)
|
|
100
|
+
host = uri.host&.downcase
|
|
101
|
+
graph_origin = URI.parse(BASE_URL)
|
|
102
|
+
trusted_host = host == graph_origin.host || MEDIA_HOSTS.any? { |allowed| host == allowed || host&.end_with?(".#{allowed}") }
|
|
103
|
+
trusted = uri.is_a?(URI::HTTPS) && uri.port == 443 && trusted_host
|
|
104
|
+
return if trusted
|
|
105
|
+
|
|
106
|
+
raise ChatSDK::PlatformError.new(
|
|
107
|
+
"Refusing to send the WhatsApp access token to an untrusted media URL",
|
|
108
|
+
adapter_name: :whatsapp
|
|
109
|
+
)
|
|
110
|
+
rescue URI::InvalidURIError
|
|
111
|
+
raise ChatSDK::PlatformError.new("Invalid WhatsApp media URL", adapter_name: :whatsapp)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def validate_media_response!(response)
|
|
115
|
+
declared_size = response.headers["content-length"]&.to_i
|
|
116
|
+
actual_size = response.body.respond_to?(:bytesize) ? response.body.bytesize : 0
|
|
117
|
+
return if [declared_size, actual_size].compact.max <= MEDIA_DOWNLOAD_LIMIT
|
|
118
|
+
|
|
119
|
+
raise ChatSDK::PlatformError.new(
|
|
120
|
+
"WhatsApp media exceeds the 25 MB download limit",
|
|
121
|
+
status: response.status,
|
|
122
|
+
adapter_name: :whatsapp
|
|
123
|
+
)
|
|
124
|
+
end
|
|
125
|
+
|
|
80
126
|
def extract_error_message(response)
|
|
81
127
|
body = response.body
|
|
82
128
|
body.is_a?(Hash) ? body.dig("error", "message") : response.status.to_s
|