Sinatra doesn't parse Slack interactive content payload

39 views Asked by At

I'm trying to use Slack interactive content to send the response of a button into a Sinatra app but the body doesn't get de-serialized.

Whenever I try to use the Slack message button I receive this error on the Sinatra server:

JSON::ParserError - unexpected token at 'payload=%7B%22type%22%3A%22block_actions%22%2C%22user%22%3A%7B%22id%22%3A%22UG0HVH1GX%22%2C%22username%22%3A%22asd%22%2C%22name%22%3A%22asd%22%2C%22team_id%22%3A%22T024GE59A%22%7D%2C%22api_app_id%22%3A%22A06F3NEL14Z%22%2C%22token%22%3A%22AYZC30arIx4CsV9AMQxU%22%2C%22container%22%3A%7B%22type%22%3A%22message%22%2C%22message_ts%22%3A%221705755611.478699%22%2C%22channel_id%22%3A%22C05GN6W4K5W%22%2C%22is_ephemeral%22%3Afalse%7D%2C%22trigger_id%22%3A%226503856512579.2152481316.74034a39fd2de763bfb820dc5060e6bb%22%2C%22team%22%3A%7B%22id%22%3A%22T024GE59A%22%2C%22domain%22%3A%22asd%22%7D%2C%22enterprise%22%3Anull%2C%22is_enterprise_install%22%3Afalse%2C%22channel%22%3A%7B%22id%22%3A%22C05GN6W4K5W%22%2C%22name%22%3A%22privategroup%22%7D%2C%22message%22%3A%7B%22type%22%3A%22message%22%2C%22subtype%22%3A%22bot_message%22%2C%22text%22%3A%22Click+Me+button%22%2C%22ts%22%3A%221705755611.478699%22%2C%22bot_id%22%3A%22B06EN64BP9B%22%2C%22blocks%22%3A%5B%7B%22type%22%3A%22actions%22%2C%22block_id%22%3A%22TMafK%22%2C%22elements%22%3A%5B%7B%22type%22%3A%22button%22%2C%22action_id%22%3A%22actionId-0%22%2C%22text%22%3A%7B%22type%22%3A%22plain_text%22%2C%22text%22%3A%22Click+Me%22%2C%22emoji%22%3Atrue%7D%2C%22value%22%3A%22click_me_123%22%7D%5D%7D%5D%7D%2C%22state%22%3A%7B%22values%22%3A%7B%7D%7D%2C%22response_url%22%3A%22https%3A%5C%2F%5C%2Fhooks.slack.com%5C%2Factions%5C%2FT024GE59B%5C%2F6516603344528%5C%2FUuYsbmvSAo56tu351G0Zl36w%22%2C%22actions%22%3A%5B%7B%22action_id%22%3A%22actionId-0%22%2C%22block_id%22%3A%22TMafK%22%2C%22text%22%3A%7B%22type%22%3A%22plain_text%22%2C%22text%22%3A%22Click+Me%22%2C%22emoji%22%3Atrue%7D%2C%22value%22%3A%22click_me_123%22%2C%22type%22%3A%22button%22%2C%22action_ts%22%3A%221705758257.494064%22%7D%5D%7D'

I have this de-serializer at the beginning of the server:

before do
  unless request.body.read.empty?
    request.body.rewind
    @params = Sinatra::IndifferentHash.new
    @params.merge!(JSON.parse(request.body.read))
  end
end

If I remove this section and I pp @params I get this:

{"payload"=>
  "{\"type\":\"block_actions\",\"user\":{\"id\":\"UG0HVH1GX\",\"username\":\"asd\",\"name\":\"asd\",\"team_id\":\"T024GE59A\"},\"api_app_id\":\"A06F3NEL14Z\",\"token\":\"AYZC30arIx4CsVQxU\",\"container\":{\"type\":\"message\",\"message_ts\":\"1705755611.478699\",\"channel_id\":\"C05GN6W4K5W\",\"is_ephemeral\":false},\"trigger_id\":\"6503973207090.2152481316.8ad17fadb62def07bf15071b521180d7\",\"team\":{\"id\":\"T024GE59A\",\"domain\":\"asd\"},\"enterprise\":null,\"is_enterprise_install\":false,\"channel\":{\"id\":\"C05GN6W4K5W\",\"name\":\"privategroup\"},\"message\":{\"type\":\"message\",\"subtype\":\"bot_message\",\"text\":\"Click Me button\",\"ts\":\"1705755611.478699\",\"bot_id\":\"B06EN64BP9B\",\"blocks\":[{\"type\":\"actions\",\"block_id\":\"TMafK\",\"elements\":[{\"type\":\"button\",\"action_id\":\"actionId-0\",\"text\":{\"type\":\"plain_text\",\"text\":\"Click Me\",\"emoji\":true},\"value\":\"click_me_123\"}]}]},\"state\":{\"values\":{}},\"response_url\":\"https:\\/\\/hooks.slack.com\\/actions\\/T024GE59A\\/6501045563aa3\\/MlzRCYKujL9ETzxPJySY1v\",\"actions\":[{\"action_id\":\"actionId-0\",\"block_id\":\"TMafK\",\"text\":{\"type\":\"plain_text\",\"text\":\"Click Me\",\"emoji\":true},\"value\":\"click_me_123\",\"type\":\"button\",\"action_ts\":\"1705758480.661885\"}]}"}
2024-01-20 14:48:00 +0100 Rack app ("POST /reply" - (44.204.57.110)): #<Rack::Lint::LintError: Body yielded non-string value ["payload", "{\"type\":\"block_actions\",\"user\":{\"id\":\"UG0HVH1GX\",\"username\":\"asd\",\"name\":\"asd\",\"team_id\":\"T024GE59A\"},\"api_app_id\":\"A06F3NEL14Z\",\"token\":\"A30arIx4CsV9AM\",\"container\":{\"type\":\"message\",\"message_ts\":\"1705755611.478699\",\"channel_id\":\"C05GN6W4K5W\",\"is_ephemeral\":false},\"trigger_id\":\"6503973207090.2152481316.8ad17fadb62def07bf15071b521180d7\",\"team\":{\"id\":\"T024GE59A\",\"domain\":\"asd\"},\"enterprise\":null,\"is_enterprise_install\":false,\"channel\":{\"id\":\"C05GN6W4K5W\",\"name\":\"privategroup\"},\"message\":{\"type\":\"message\",\"subtype\":\"bot_message\",\"text\":\"Click Me button\",\"ts\":\"1705755611.478699\",\"bot_id\":\"B06EN64BP9B\",\"blocks\":[{\"type\":\"actions\",\"block_id\":\"TMafK\",\"elements\":[{\"type\":\"button\",\"action_id\":\"actionId-0\",\"text\":{\"type\":\"plain_text\",\"text\":\"Click Me\",\"emoji\":true},\"value\":\"click_me_123\"}]}]},\"state\":{\"values\":{}},\"response_url\":\"https:\\/\\/hooks.slack.com\\/actions\\/T4GE59A\\/6501045552673\\/MlzRCYKujL2zxPJySY1v\",\"actions\":[{\"action_id\":\"actionId-0\",\"block_id\":\"TMafK\",\"text\":{\"type\":\"plain_text\",\"text\":\"Click Me\",\"emoji\":true},\"value\":\"click_me_123\",\"type\":\"button\",\"action_ts\":\"1705758480.661885\"}]}"]>

Here Rack is giving a lint error but the body is available anyway. What is happening here? Why is the body sent to response_url behaving this way and how can I fix it?

Thanks!

1

There are 1 answers

0
Alvaro On

The payload's content type sent by Slack is application/x-www-form-urlencoded. I've read in this response that Sinatra already parses this type of content.

I've fixed this by excluding the initial parser if the content type is application/x-www-form-urlencoded.

before do
  unless request.body.read.empty? || @env['CONTENT_TYPE'] == 'application/x-www-form-urlencoded'
    request.body.rewind
    @params = Sinatra::IndifferentHash.new
    @params.merge!(JSON.parse(request.body.read))
  end
end