TL; DR : Here is the code. https://github.com/ngoctnq-1957/rasa-chatwork-echo
Opening
If you are a chatbot like me, you probably used Rasa. With superior advantages such as completely local without fear of losing information, a good dialog handler and connectors (even if catching the entity is a bit stupid), Rasa is the number 1 choice of projects that need security / or Need everything in 1 package. Also, if you work at a company that uses Chatwork like you, you will need to find a way for Chatwork to contact Rasa so that it can replace you to reply to the boss’s message. So I will guide your people to do this. Bonus way to make a chatbot to parody what you say.
Note: this post uses Rasa <1.8.0 because it is compatible with TensorFlow 1.x, due to experience that the TF2.0 version is still crumbling.
How to get Rasa to parody you
I have to build a basic bot to demo for you, anyway, so I recommend: the parody action you will define in the actions.py
file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">from</span> typing <span class="token keyword">import</span> Any <span class="token punctuation">,</span> Text <span class="token punctuation">,</span> Dict <span class="token punctuation">,</span> List <span class="token keyword">from</span> rasa_sdk <span class="token keyword">import</span> Action <span class="token punctuation">,</span> Tracker <span class="token keyword">from</span> rasa_sdk <span class="token punctuation">.</span> executor <span class="token keyword">import</span> CollectingDispatcher <span class="token keyword">class</span> <span class="token class-name">ActionHelloWorld</span> <span class="token punctuation">(</span> Action <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">name</span> <span class="token punctuation">(</span> self <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> Text <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token string">"action_echo"</span> <span class="token keyword">def</span> <span class="token function">run</span> <span class="token punctuation">(</span> self <span class="token punctuation">,</span> dispatcher <span class="token punctuation">:</span> CollectingDispatcher <span class="token punctuation">,</span> tracker <span class="token punctuation">:</span> Tracker <span class="token punctuation">,</span> domain <span class="token punctuation">:</span> Dict <span class="token punctuation">[</span> Text <span class="token punctuation">,</span> Any <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> List <span class="token punctuation">[</span> Dict <span class="token punctuation">[</span> Text <span class="token punctuation">,</span> Any <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token punctuation">:</span> dispatcher <span class="token punctuation">.</span> utter_message <span class="token punctuation">(</span> text <span class="token operator">=</span> tracker <span class="token punctuation">.</span> latest_message <span class="token punctuation">[</span> <span class="token string">"text"</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> |
And you leave the default is to run that action in config.yml
:
1 2 3 4 5 6 | <span class="token key atrule">policies</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span> <span class="token punctuation">:</span> <span class="token string">"FallbackPolicy"</span> <span class="token key atrule">nlu_threshold</span> <span class="token punctuation">:</span> <span class="token number">1.0</span> <span class="token key atrule">core_threshold</span> <span class="token punctuation">:</span> <span class="token number">1.0</span> <span class="token key atrule">fallback_action_name</span> <span class="token punctuation">:</span> <span class="token string">'action_echo'</span> |
Over
How to get Rasa connected to Chatwork
The first is that you define the webhook to receive incoming messages for Rasa.
The structure of extend InputChannel
classes requires the following methods: starting with name
, will determine your webhook URL.
1 2 3 4 5 | <span class="token keyword">class</span> <span class="token class-name">ChatworkInput</span> <span class="token punctuation">(</span> InputChannel <span class="token punctuation">)</span> <span class="token punctuation">:</span> @ <span class="token builtin">classmethod</span> <span class="token keyword">def</span> <span class="token function">name</span> <span class="token punctuation">(</span> cls <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> Text <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token string">"chatwork"</span> |
For my example to return chatwork
, the URL would be /webhooks/chatwork/webhook
.
Next is the method to get the token settings in the credentials.yml
file. This section will also be discussed later in this section.
1 2 3 4 5 6 7 8 9 10 | @ <span class="token builtin">classmethod</span> <span class="token keyword">def</span> <span class="token function">from_credentials</span> <span class="token punctuation">(</span> cls <span class="token punctuation">,</span> credentials <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">if</span> <span class="token operator">not</span> credentials <span class="token punctuation">:</span> cls <span class="token punctuation">.</span> raise_missing_credentials_exception <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> cls <span class="token punctuation">(</span> credentials <span class="token punctuation">.</span> get <span class="token punctuation">(</span> <span class="token string">"api_token"</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> credentials <span class="token punctuation">.</span> get <span class="token punctuation">(</span> <span class="token string">"secret_token"</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">__init__</span> <span class="token punctuation">(</span> self <span class="token punctuation">,</span> api_token <span class="token punctuation">:</span> Text <span class="token punctuation">,</span> secret_token <span class="token punctuation">:</span> Text <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token boolean">None</span> <span class="token punctuation">:</span> self <span class="token punctuation">.</span> api_token <span class="token operator">=</span> api_token self <span class="token punctuation">.</span> secret_token <span class="token operator">=</span> secret_token |
Next is an optional method, but I put in to remove the To / Reply types from the input message to clean it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @ <span class="token builtin">staticmethod</span> <span class="token keyword">def</span> <span class="token function">_sanitize_user_message</span> <span class="token punctuation">(</span> text <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token triple-quoted-string string">""" Remove all tags. """</span> <span class="token keyword">for</span> regex <span class="token punctuation">,</span> replacement <span class="token keyword">in</span> <span class="token punctuation">[</span> <span class="token comment"># to messages</span> <span class="token punctuation">(</span> r <span class="token string">"[[Tt][Oo]:d+]"</span> <span class="token punctuation">,</span> <span class="token string">""</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token comment"># reply messages</span> <span class="token punctuation">(</span> r <span class="token string">"[[Rr][Pp] aid=[^]]+]"</span> <span class="token punctuation">,</span> <span class="token string">""</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> r <span class="token string">"[Reply aid=[^]]+]"</span> <span class="token punctuation">,</span> <span class="token string">""</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">:</span> text <span class="token operator">=</span> re <span class="token punctuation">.</span> sub <span class="token punctuation">(</span> regex <span class="token punctuation">,</span> replacement <span class="token punctuation">,</span> text <span class="token punctuation">)</span> <span class="token keyword">return</span> text <span class="token punctuation">.</span> strip <span class="token punctuation">(</span> <span class="token punctuation">)</span> |
The most important piece of code is the blueprint
for Rasa’s sanic
server. In particular, Rasa requires you to implement 2 routes that are /
with the method name health
, and webhook
with the method name receive
.
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">def</span> <span class="token function">blueprint</span> <span class="token punctuation">(</span> self <span class="token punctuation">,</span> on_new_message <span class="token punctuation">:</span> Callable <span class="token punctuation">[</span> <span class="token punctuation">[</span> UserMessage <span class="token punctuation">]</span> <span class="token punctuation">,</span> Awaitable <span class="token punctuation">[</span> <span class="token boolean">None</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> Blueprint <span class="token punctuation">:</span> custom_webhook <span class="token operator">=</span> Blueprint <span class="token punctuation">(</span> <span class="token string">"chatwork_webhook"</span> <span class="token punctuation">,</span> <span class="token string">"chatwork"</span> <span class="token punctuation">)</span> @custom_webhook <span class="token punctuation">.</span> route <span class="token punctuation">(</span> <span class="token string">"/"</span> <span class="token punctuation">,</span> methods <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string">"GET"</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">health</span> <span class="token punctuation">(</span> request <span class="token punctuation">:</span> Request <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> HTTPResponse <span class="token punctuation">:</span> <span class="token keyword">return</span> response <span class="token punctuation">.</span> json <span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token string">"signature_tag"</span> <span class="token punctuation">:</span> <span class="token string">"o' kawaii koto."</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> |
To avoid someone sneaking your request into your webhook (not from Chatwork), you need to check that the message is from Chatwork.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">def</span> <span class="token function">validate_request</span> <span class="token punctuation">(</span> request <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token comment"># Check the X-Hub-Signature header to make sure this is a valid request.</span> chatwork_signature <span class="token operator">=</span> request <span class="token punctuation">.</span> headers <span class="token punctuation">.</span> get <span class="token punctuation">(</span> <span class="token string">'X-ChatWorkWebhookSignature'</span> <span class="token punctuation">,</span> <span class="token string">''</span> <span class="token punctuation">)</span> signature <span class="token operator">=</span> hmac <span class="token punctuation">.</span> new <span class="token punctuation">(</span> base64 <span class="token punctuation">.</span> b64decode <span class="token punctuation">(</span> <span class="token builtin">bytes</span> <span class="token punctuation">(</span> self <span class="token punctuation">.</span> secret_token <span class="token punctuation">,</span> encoding <span class="token operator">=</span> <span class="token string">'utf-8'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> request <span class="token punctuation">.</span> body <span class="token punctuation">,</span> hashlib <span class="token punctuation">.</span> sha256 <span class="token punctuation">)</span> expected_signature <span class="token operator">=</span> base64 <span class="token punctuation">.</span> b64encode <span class="token punctuation">(</span> signature <span class="token punctuation">.</span> digest <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> hmac <span class="token punctuation">.</span> compare_digest <span class="token punctuation">(</span> <span class="token builtin">bytes</span> <span class="token punctuation">(</span> chatwork_signature <span class="token punctuation">,</span> encoding <span class="token operator">=</span> <span class="token string">'utf-8'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> expected_signature <span class="token punctuation">)</span> |
Basically, the request’s header sent to the webhook will include the hash of the message content, signed with your secret token. Compare ok is ok ?
And the focus of this article is webhook. The code has some pretty basic callbacks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | @custom_webhook <span class="token punctuation">.</span> route <span class="token punctuation">(</span> <span class="token string">"/webhook"</span> <span class="token punctuation">,</span> methods <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string">"POST"</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">receive</span> <span class="token punctuation">(</span> request <span class="token punctuation">:</span> Request <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> HTTPResponse <span class="token punctuation">:</span> <span class="token keyword">if</span> <span class="token operator">not</span> validate_request <span class="token punctuation">(</span> request <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> response <span class="token punctuation">.</span> json <span class="token punctuation">(</span> <span class="token string">"you've been a very bad boy!"</span> <span class="token punctuation">,</span> status <span class="token operator">=</span> <span class="token number">400</span> <span class="token punctuation">)</span> content <span class="token operator">=</span> request <span class="token punctuation">.</span> json <span class="token punctuation">[</span> <span class="token string">"webhook_event"</span> <span class="token punctuation">]</span> sender_id <span class="token operator">=</span> content <span class="token punctuation">[</span> <span class="token string">"from_account_id"</span> <span class="token punctuation">]</span> room_id <span class="token operator">=</span> content <span class="token punctuation">[</span> <span class="token string">"room_id"</span> <span class="token punctuation">]</span> message_id <span class="token operator">=</span> content <span class="token punctuation">[</span> <span class="token string">"message_id"</span> <span class="token punctuation">]</span> text <span class="token operator">=</span> content <span class="token punctuation">[</span> <span class="token string">"body"</span> <span class="token punctuation">]</span> metadata <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"sender_id"</span> <span class="token punctuation">:</span> sender_id <span class="token punctuation">,</span> <span class="token string">"room_id"</span> <span class="token punctuation">:</span> room_id <span class="token punctuation">,</span> <span class="token string">"message_id"</span> <span class="token punctuation">:</span> message_id <span class="token punctuation">,</span> <span class="token string">"text"</span> <span class="token punctuation">:</span> self <span class="token punctuation">.</span> _sanitize_user_message <span class="token punctuation">(</span> text <span class="token punctuation">)</span> <span class="token punctuation">}</span> out_channel <span class="token operator">=</span> self <span class="token punctuation">.</span> get_output_channel <span class="token punctuation">(</span> room_id <span class="token punctuation">)</span> <span class="token keyword">try</span> <span class="token punctuation">:</span> <span class="token keyword">await</span> on_new_message <span class="token punctuation">(</span> UserMessage <span class="token punctuation">(</span> text <span class="token punctuation">,</span> out_channel <span class="token punctuation">,</span> sender_id <span class="token punctuation">,</span> input_channel <span class="token operator">=</span> room_id <span class="token punctuation">,</span> metadata <span class="token operator">=</span> metadata <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">except</span> CancelledError <span class="token punctuation">:</span> logger <span class="token punctuation">.</span> error <span class="token punctuation">(</span> <span class="token string">"Message handling timed out for "</span> <span class="token string">"user message '{}'."</span> <span class="token punctuation">.</span> <span class="token builtin">format</span> <span class="token punctuation">(</span> text <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">except</span> Exception <span class="token punctuation">:</span> logger <span class="token punctuation">.</span> exception <span class="token punctuation">(</span> <span class="token string">"An exception occured while handling "</span> <span class="token string">"user message '{}'."</span> <span class="token punctuation">.</span> <span class="token builtin">format</span> <span class="token punctuation">(</span> text <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> response <span class="token punctuation">.</span> json <span class="token punctuation">(</span> <span class="token string">"alles gut ?"</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> custom_webhook |
And finally the optional method, used to create OutputChannel
so you can return messages to the user.
1 2 3 | <span class="token keyword">def</span> <span class="token function">get_output_channel</span> <span class="token punctuation">(</span> self <span class="token punctuation">,</span> room_id <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> OutputChannel <span class="token punctuation">:</span> <span class="token keyword">return</span> ChatworkOutput <span class="token punctuation">(</span> self <span class="token punctuation">.</span> api_token <span class="token punctuation">,</span> room_id <span class="token punctuation">)</span> |
Then you define what the return message will look like.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">class</span> <span class="token class-name">ChatworkOutput</span> <span class="token punctuation">(</span> OutputChannel <span class="token punctuation">)</span> <span class="token punctuation">:</span> @ <span class="token builtin">classmethod</span> <span class="token keyword">def</span> <span class="token function">name</span> <span class="token punctuation">(</span> cls <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token string">"chatwork"</span> <span class="token keyword">def</span> <span class="token function">__init__</span> <span class="token punctuation">(</span> self <span class="token punctuation">,</span> token_api <span class="token punctuation">:</span> Text <span class="token punctuation">,</span> room_id <span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token boolean">None</span> <span class="token punctuation">:</span> self <span class="token punctuation">.</span> room_id <span class="token operator">=</span> room_id self <span class="token punctuation">.</span> header <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"X-ChatWorkToken"</span> <span class="token punctuation">:</span> token_api <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">send_text_message</span> <span class="token punctuation">(</span> self <span class="token punctuation">,</span> recipient_id <span class="token punctuation">:</span> Optional <span class="token punctuation">[</span> Text <span class="token punctuation">]</span> <span class="token punctuation">,</span> text <span class="token punctuation">:</span> Text <span class="token punctuation">,</span> <span class="token operator">**</span> kwargs <span class="token punctuation">:</span> Any <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token boolean">None</span> <span class="token punctuation">:</span> uri <span class="token operator">=</span> <span class="token string">"https://api.chatwork.com/v2/rooms/"</span> <span class="token operator">+</span> <span class="token builtin">str</span> <span class="token punctuation">(</span> self <span class="token punctuation">.</span> room_id <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"/messages"</span> data <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"body"</span> <span class="token punctuation">:</span> text <span class="token punctuation">}</span> requests <span class="token punctuation">.</span> post <span class="token punctuation">(</span> uri <span class="token punctuation">,</span> headers <span class="token operator">=</span> self <span class="token punctuation">.</span> header <span class="token punctuation">,</span> data <span class="token operator">=</span> data <span class="token punctuation">)</span> |
Basically, this class only fires one POST request on the Chatwork server in the right syntax into the right room. If you want to add a cool original sender reply, correct it as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <span class="token keyword">class</span> <span class="token class-name">ChatworkOutput</span> <span class="token punctuation">(</span> OutputChannel <span class="token punctuation">)</span> <span class="token punctuation">:</span> @ <span class="token builtin">classmethod</span> <span class="token keyword">def</span> <span class="token function">name</span> <span class="token punctuation">(</span> cls <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token string">"chatwork"</span> <span class="token keyword">def</span> <span class="token function">__init__</span> <span class="token punctuation">(</span> self <span class="token punctuation">,</span> token_api <span class="token punctuation">:</span> Text <span class="token punctuation">,</span> sender_id <span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token punctuation">,</span> room_id <span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token punctuation">,</span> message_id <span class="token punctuation">:</span> <span class="token builtin">int</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token boolean">None</span> <span class="token punctuation">:</span> self <span class="token punctuation">.</span> room_id <span class="token operator">=</span> room_id self <span class="token punctuation">.</span> sender_id <span class="token operator">=</span> sender_id self <span class="token punctuation">.</span> message_id <span class="token operator">=</span> message_id self <span class="token punctuation">.</span> header <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"X-ChatWorkToken"</span> <span class="token punctuation">:</span> token_api <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">send_text_message</span> <span class="token punctuation">(</span> self <span class="token punctuation">,</span> recipient_id <span class="token punctuation">:</span> Optional <span class="token punctuation">[</span> Text <span class="token punctuation">]</span> <span class="token punctuation">,</span> text <span class="token punctuation">:</span> Text <span class="token punctuation">,</span> <span class="token operator">**</span> kwargs <span class="token punctuation">:</span> Any <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token boolean">None</span> <span class="token punctuation">:</span> uri <span class="token operator">=</span> <span class="token string">"https://api.chatwork.com/v2/rooms/"</span> <span class="token operator">+</span> <span class="token builtin">str</span> <span class="token punctuation">(</span> self <span class="token punctuation">.</span> room_id <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"/messages"</span> name <span class="token operator">=</span> <span class="token string">'Người lạ'</span> <span class="token keyword">for</span> contact <span class="token keyword">in</span> requests <span class="token punctuation">.</span> get <span class="token punctuation">(</span> <span class="token string">"https://api.chatwork.com/v2/contacts"</span> <span class="token punctuation">,</span> headers <span class="token operator">=</span> self <span class="token punctuation">.</span> header <span class="token punctuation">)</span> <span class="token punctuation">.</span> json <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">if</span> contact <span class="token punctuation">[</span> <span class="token string">"account_id"</span> <span class="token punctuation">]</span> <span class="token operator">==</span> self <span class="token punctuation">.</span> sender_id <span class="token punctuation">:</span> name <span class="token operator">=</span> contact <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token keyword">break</span> text <span class="token operator">=</span> f <span class="token string">'[rp aid={self.sender_id} to={self.room_id}-{self.message_id}]{name}n'</span> <span class="token operator">+</span> text data <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"body"</span> <span class="token punctuation">:</span> text <span class="token punctuation">}</span> requests <span class="token punctuation">.</span> post <span class="token punctuation">(</span> uri <span class="token punctuation">,</span> headers <span class="token operator">=</span> self <span class="token punctuation">.</span> header <span class="token punctuation">,</span> data <span class="token operator">=</span> data <span class="token punctuation">)</span> |
Remember to change the code to create the ChatworkOutput
object in the ChatworkInput
class.
Next, you need to install the necessary APIs.
Both can be accessed from the API Setting section of the Chatwork:
With the API key, enter the password in the following field and you will get the flag:
For webhook secret token, click Webhook and create a new entry:
Where the secret token is the Token entry, as I highlighted. In addition, you need to fill in the Webhook URL according to the structure you have put in the image. For example, if you run Rasa and don’t have any proxy port pass (as with nginx
), that link would be
1 2 | https://<server_ip>:5005/webhooks/chatwork/webhook |
Finally, you need to install the API settings.
Go to the credentials.yml
file and add these 3 lines to the bottom
1 2 3 4 | <span class="token key atrule">chatwork_connector.ChatworkInput</span> <span class="token punctuation">:</span> <span class="token key atrule">api_token</span> <span class="token punctuation">:</span> <span class="token string">"put_your_api_token_here"</span> <span class="token key atrule">secret_token</span> <span class="token punctuation">:</span> <span class="token string">"your_secret_token_too"</span> |
with the token values taken from the previous step.
And the problem of Chatwork Webhook
Not to mention the Chatwork changing theme blinded me, the Chatwork webhook sometimes runs extremely bad. Typically, I tried sending a message and it took 5 minutes for Rasa to arrive To prove that this is not a problem for Rasa or the internet, I tried to replay Chatwork’s payload into the webhook, and everything went as normal as never had a breakup:
In the file chatwork_connector.py
as above, in the receive
function of Sanic blueprint, please edit a bit to get the Chatwork payload (5 ‘after you send):
1 2 3 4 | <span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">receive</span> <span class="token punctuation">(</span> request <span class="token punctuation">:</span> Request <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> HTTPResponse <span class="token punctuation">:</span> <span class="token keyword">print</span> <span class="token punctuation">(</span> request <span class="token punctuation">.</span> body <span class="token punctuation">.</span> decode <span class="token punctuation">(</span> <span class="token string">'utf-8'</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">print</span> <span class="token punctuation">(</span> request <span class="token punctuation">.</span> headers <span class="token punctuation">.</span> get <span class="token punctuation">(</span> <span class="token string">'X-ChatWorkWebhookSignature'</span> <span class="token punctuation">,</span> <span class="token string">''</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> |
From there, you already have the payload to replay the attack server Don’t worry, you can’t be hacked like this in real life, because Chatwork requires HTTPS so you won’t have a Man-in-the-Middle (MITM) attack like you are doing right now. Turn on Postman and send it to the webhook URL – remember to include the header to validate your message:
It only takes 1.5 seconds, not 5 minutes, you know. I also fired this request from my computer to the EC2 server used to host this bot, so it was not latency localhost.
Conclude
If you can, get your boss to change to Slack. If you can’t, try to bear with it, and use this code to make your life a little easier. Thank you for reading this, and good luck.