Skip to content

Commit f721cf2

Browse files
author
Ace Nassri
authored
chore(functions/slack): update Slack library + use url-encoding (GoogleCloudPlatform#3689)
1 parent aab7579 commit f721cf2

File tree

3 files changed

+61
-24
lines changed

3 files changed

+61
-24
lines changed

functions/slack/pom.xml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,15 @@
5757
<scope>provided</scope>
5858
</dependency>
5959

60-
<dependency>
61-
<groupId>com.google.code.gson</groupId>
62-
<artifactId>gson</artifactId>
63-
<version>2.8.6</version>
64-
</dependency>
6560
<dependency>
6661
<groupId>com.google.apis</groupId>
6762
<artifactId>google-api-services-kgsearch</artifactId>
6863
<version>v1-rev20200809-1.30.10</version>
6964
</dependency>
7065
<dependency>
71-
<groupId>com.github.seratch</groupId>
72-
<artifactId>jslack</artifactId>
73-
<version>3.4.2</version>
66+
<groupId>com.slack.api</groupId>
67+
<artifactId>slack-app-backend</artifactId>
68+
<version>1.1.3</version>
7469
</dependency>
7570

7671
<!-- The following dependencies are only required for testing -->

functions/slack/src/main/java/functions/SlackSlashCommand.java

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package functions;
1818

19-
import com.github.seratch.jslack.app_backend.SlackSignature;
2019
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
2120
import com.google.api.client.json.jackson2.JacksonFactory;
2221
import com.google.api.services.kgsearch.v1.Kgsearch;
@@ -26,14 +25,19 @@
2625
import com.google.gson.Gson;
2726
import com.google.gson.JsonArray;
2827
import com.google.gson.JsonObject;
28+
import com.slack.api.app_backend.SlackSignature;
2929
import java.io.BufferedWriter;
3030
import java.io.IOException;
3131
import java.net.HttpURLConnection;
3232
import java.security.GeneralSecurityException;
33+
import java.time.ZonedDateTime;
34+
import java.util.HashMap;
35+
import java.util.Map;
3336
import java.util.Optional;
3437
import java.util.logging.Logger;
3538
import java.util.stream.Collectors;
3639

40+
3741
public class SlackSlashCommand implements HttpFunction {
3842

3943
// [START functions_slack_setup]
@@ -88,7 +92,10 @@ boolean isValidSlackWebhook(HttpRequest request, String requestBody) {
8892
if (!maybeTimestamp.isPresent() || !maybeSignature.isPresent()) {
8993
return false;
9094
}
91-
return verifier.isValid(maybeTimestamp.get(), requestBody, maybeSignature.get(), 1L);
95+
96+
Long nowInMs = ZonedDateTime.now().toInstant().toEpochMilli();
97+
98+
return verifier.isValid(maybeTimestamp.get(), requestBody, maybeSignature.get(), nowInMs);
9299
}
93100
// [END functions_verify_webhook]
94101

@@ -146,7 +153,10 @@ String formatSlackMessage(JsonObject kgResponse, String query) {
146153
addPropertyIfPresent(attachmentJson, "image_url", imageJson, "contentUrl");
147154
}
148155

149-
responseJson.add("attachments", attachmentJson);
156+
JsonArray attachmentList = new JsonArray();
157+
attachmentList.add(attachmentJson);
158+
159+
responseJson.add("attachments", attachmentList);
150160

151161
return gson.toJson(responseJson);
152162
}
@@ -186,9 +196,22 @@ public void service(HttpRequest request, HttpResponse response) throws IOExcepti
186196

187197
// reader can only be read once per request, so we preserve its contents
188198
String bodyString = request.getReader().lines().collect(Collectors.joining());
189-
JsonObject body = gson.fromJson(bodyString, JsonObject.class);
190199

191-
if (body == null || !body.has("text")) {
200+
// Slack sends requests as URL-encoded strings
201+
// Java 11 doesn't have a standard library
202+
// function for this, so do it manually
203+
Map<String, String> body = new HashMap<>();
204+
for (String keyValuePair : bodyString.split("&")) {
205+
String[] keyAndValue = keyValuePair.split("=");
206+
if (keyAndValue.length == 2) {
207+
String key = keyAndValue[0];
208+
String value = keyAndValue[1];
209+
210+
body.put(key, value);
211+
}
212+
}
213+
214+
if (body == null || !body.containsKey("text")) {
192215
response.setStatusCode(HttpURLConnection.HTTP_BAD_REQUEST);
193216
return;
194217
}
@@ -198,15 +221,18 @@ public void service(HttpRequest request, HttpResponse response) throws IOExcepti
198221
return;
199222
}
200223

201-
String query = body.get("text").getAsString();
224+
String query = body.get("text");
202225

203226
// Call knowledge graph API
204227
JsonObject kgResponse = searchKnowledgeGraph(query);
205228

206229
// Format response to Slack
207230
// See https://api.slack.com/docs/message-formatting
208231
BufferedWriter writer = response.getWriter();
232+
209233
writer.write(formatSlackMessage(kgResponse, query));
234+
235+
response.setContentType("application/json");
210236
}
211237
// [END functions_slack_search]
212238
}

functions/slack/src/test/java/functions/SlackSlashCommandTest.java

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
import static org.mockito.Mockito.verify;
2525
import static org.mockito.Mockito.when;
2626

27-
import com.github.seratch.jslack.app_backend.SlackSignature;
2827
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
2928
import com.google.cloud.functions.HttpRequest;
3029
import com.google.cloud.functions.HttpResponse;
3130
import com.google.gson.Gson;
31+
import com.slack.api.app_backend.SlackSignature;
3232
import java.io.BufferedReader;
3333
import java.io.BufferedWriter;
3434
import java.io.IOException;
@@ -91,8 +91,8 @@ public void onlyAcceptsPostRequestsTest() throws IOException, GeneralSecurityExc
9191

9292
@Test
9393
public void requiresSlackAuthHeadersTest() throws IOException, GeneralSecurityException {
94-
String jsonStr = gson.toJson(Map.of("text", "foo"));
95-
StringReader requestReadable = new StringReader(jsonStr);
94+
String urlEncodedStr = "text=foo";
95+
StringReader requestReadable = new StringReader(urlEncodedStr);
9696

9797
when(request.getMethod()).thenReturn("POST");
9898
when(request.getReader()).thenReturn(new BufferedReader(requestReadable));
@@ -105,7 +105,7 @@ public void requiresSlackAuthHeadersTest() throws IOException, GeneralSecurityEx
105105

106106
@Test
107107
public void recognizesValidSlackTokenTest() throws IOException, GeneralSecurityException {
108-
StringReader requestReadable = new StringReader("{}");
108+
StringReader requestReadable = new StringReader("");
109109

110110
when(request.getReader()).thenReturn(new BufferedReader(requestReadable));
111111
when(request.getMethod()).thenReturn("POST");
@@ -117,8 +117,8 @@ public void recognizesValidSlackTokenTest() throws IOException, GeneralSecurityE
117117

118118
@Test
119119
public void handlesSearchErrorTest() throws IOException, GeneralSecurityException {
120-
String jsonStr = gson.toJson(Map.of("text", "foo"));
121-
StringReader requestReadable = new StringReader(jsonStr);
120+
String urlEncodedStr = "text=foo";
121+
StringReader requestReadable = new StringReader(urlEncodedStr);
122122

123123
when(request.getReader()).thenReturn(new BufferedReader(requestReadable));
124124
when(request.getMethod()).thenReturn("POST");
@@ -132,8 +132,8 @@ public void handlesSearchErrorTest() throws IOException, GeneralSecurityExceptio
132132

133133
@Test
134134
public void handlesEmptyKgResultsTest() throws IOException, GeneralSecurityException {
135-
String jsonStr = gson.toJson(Map.of("text", "asdfjkl13579"));
136-
StringReader requestReadable = new StringReader(jsonStr);
135+
String urlEncodedStr = "text=asdfjkl13579";
136+
StringReader requestReadable = new StringReader(urlEncodedStr);
137137

138138
when(request.getReader()).thenReturn(new BufferedReader(requestReadable));
139139
when(request.getMethod()).thenReturn("POST");
@@ -148,8 +148,24 @@ public void handlesEmptyKgResultsTest() throws IOException, GeneralSecurityExcep
148148

149149
@Test
150150
public void handlesPopulatedKgResultsTest() throws IOException, GeneralSecurityException {
151-
String jsonStr = gson.toJson(Map.of("text", "lion"));
152-
StringReader requestReadable = new StringReader(jsonStr);
151+
String urlEncodedStr = "text=lion";
152+
StringReader requestReadable = new StringReader(urlEncodedStr);
153+
154+
when(request.getReader()).thenReturn(new BufferedReader(requestReadable));
155+
when(request.getMethod()).thenReturn("POST");
156+
157+
SlackSlashCommand functionInstance = new SlackSlashCommand(alwaysValidVerifier);
158+
159+
functionInstance.service(request, response);
160+
161+
writerOut.flush();
162+
assertThat(responseOut.toString()).contains("https://en.wikipedia.org/wiki/Lion");
163+
}
164+
165+
@Test
166+
public void handlesMultipleUrlParamsTest() throws IOException, GeneralSecurityException {
167+
String urlEncodedStr = "unused=foo&text=lion";
168+
StringReader requestReadable = new StringReader(urlEncodedStr);
153169

154170
when(request.getReader()).thenReturn(new BufferedReader(requestReadable));
155171
when(request.getMethod()).thenReturn("POST");

0 commit comments

Comments
 (0)