|
7 | 7 | import com.objectcomputing.checkins.services.fixture.RoleFixture; |
8 | 8 | import com.objectcomputing.checkins.services.memberprofile.MemberProfile; |
9 | 9 | import com.objectcomputing.checkins.util.Util; |
| 10 | +import com.objectcomputing.checkins.configuration.CheckInsConfiguration; |
| 11 | +import com.objectcomputing.checkins.services.SlackSearchReplacement; |
| 12 | + |
| 13 | +import io.micronaut.core.util.StringUtils; |
10 | 14 | import io.micronaut.core.type.Argument; |
| 15 | +import io.micronaut.context.annotation.Property; |
11 | 16 | import io.micronaut.http.HttpRequest; |
12 | 17 | import io.micronaut.http.HttpResponse; |
13 | 18 | import io.micronaut.http.HttpStatus; |
|
27 | 32 | import java.util.UUID; |
28 | 33 | import java.util.stream.Collectors; |
29 | 34 | import java.util.stream.Stream; |
| 35 | +import javax.crypto.Mac; |
| 36 | +import javax.crypto.spec.SecretKeySpec; |
| 37 | +import java.nio.charset.StandardCharsets; |
| 38 | +import java.util.Base64; |
| 39 | +import java.time.Instant; |
30 | 40 |
|
31 | 41 | import static com.objectcomputing.checkins.services.role.RoleType.Constants.ADMIN_ROLE; |
32 | 42 | import static com.objectcomputing.checkins.services.role.RoleType.Constants.MEMBER_ROLE; |
33 | 43 | import static org.junit.jupiter.api.Assertions.assertEquals; |
34 | 44 | import static org.junit.jupiter.api.Assertions.assertThrows; |
35 | 45 | import static org.junit.jupiter.api.Assertions.assertTrue; |
36 | 46 |
|
| 47 | +@Property(name = "replace.slacksearch", value = StringUtils.TRUE) |
37 | 48 | class PulseResponseControllerTest extends TestContainersSuite implements MemberProfileFixture, RoleFixture, PulseResponseFixture { |
38 | 49 |
|
39 | 50 | @Inject |
40 | 51 | @Client("/services/pulse-responses") |
41 | 52 | protected HttpClient client; |
42 | 53 |
|
| 54 | + @Inject |
| 55 | + private CheckInsConfiguration configuration; |
| 56 | + |
| 57 | + @Inject |
| 58 | + private SlackSearchReplacement slackSearch; |
| 59 | + |
43 | 60 | private Map<String, MemberProfile> hierarchy; |
44 | 61 |
|
45 | 62 | @BeforeEach |
@@ -516,6 +533,50 @@ void testUpdateInvalidDatePulseResponse() { |
516 | 533 | assertEquals(request.getPath(), href); |
517 | 534 | } |
518 | 535 |
|
| 536 | + @Test |
| 537 | + void testCreateAPulseResponseFromSlack() { |
| 538 | + MemberProfile memberProfile = createADefaultMemberProfile(); |
| 539 | + slackSearch.users.put("SLACK_ID_HI", memberProfile.getWorkEmail()); |
| 540 | + |
| 541 | + final String rawBody = "payload=%7B%22type%22%3A+%22view_submission%22%2C+%22user%22%3A+%7B%22id%22%3A+%22SLACK_ID_HI%22%7D%2C+%22view%22%3A+%7B%22id%22%3A+%22VNHU13V36%22%2C+%22type%22%3A+%22modal%22%2C+%22state%22%3A+%7B%22values%22%3A+%7B%22internalNumber%22%3A+%7B%22internalScore%22%3A+%7B%22selected_option%22%3A+%7B%22type%22%3A+%22radio_buttons%22%2C+%22value%22%3A+%224%22%7D%7D%7D%2C+%22internalText%22%3A+%7B%22internalFeelings%22%3A+%7B%22type%22%3A+%22plain_text_input%22%2C+%22value%22%3A+%22I+am+a+robot.%22%7D%7D%2C+%22externalNumber%22%3A+%7B%22externalScore%22%3A+%7B%22selected_option%22%3A+%7B%22type%22%3A+%22radio_buttons%22%2C+%22value%22%3A+%225%22%7D%7D%7D%2C+%22externalText%22%3A+%7B%22externalFeelings%22%3A+%7B%22type%22%3A+%22plain_text_input%22%2C+%22value%22%3A+%22You+are+a+robot.%22%7D%7D%7D%7D%7D%7D"; |
| 542 | + |
| 543 | + long currentTime = Instant.now().getEpochSecond(); |
| 544 | + String timestamp = String.valueOf(currentTime); |
| 545 | + |
| 546 | + final HttpRequest request = HttpRequest.POST("/external", rawBody) |
| 547 | + .header("Content-Type", "application/x-www-form-urlencoded") |
| 548 | + .header("X-Slack-Signature", slackSignature(timestamp, rawBody)) |
| 549 | + .header("X-Slack-Request-Timestamp", timestamp); |
| 550 | + |
| 551 | + final HttpResponse response = client.toBlocking().exchange(request); |
| 552 | + |
| 553 | + assertEquals(HttpStatus.OK, response.getStatus()); |
| 554 | + } |
| 555 | + |
| 556 | + private String slackSignature(String timestamp, String rawBody) { |
| 557 | + String baseString = "v0:" + timestamp + ":" + rawBody; |
| 558 | + String secret = configuration.getApplication() |
| 559 | + .getPulseResponse() |
| 560 | + .getSlack().getSigningSecret(); |
| 561 | + |
| 562 | + try { |
| 563 | + // Generate HMAC SHA-256 signature |
| 564 | + Mac mac = Mac.getInstance("HmacSHA256"); |
| 565 | + SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); |
| 566 | + mac.init(secretKeySpec); |
| 567 | + byte[] hash = mac.doFinal(baseString.getBytes(StandardCharsets.UTF_8)); |
| 568 | + |
| 569 | + // Convert hash to hex |
| 570 | + StringBuilder hexString = new StringBuilder(); |
| 571 | + for (byte b : hash) { |
| 572 | + hexString.append(String.format("%02x", b)); |
| 573 | + } |
| 574 | + return "v0=" + hexString.toString(); |
| 575 | + } catch (Exception e) { |
| 576 | + return null; |
| 577 | + } |
| 578 | + } |
| 579 | + |
519 | 580 | private static PulseResponseCreateDTO createPulseResponseCreateDTO() { |
520 | 581 | return createPulseResponseCreateDTO(UUID.randomUUID()); |
521 | 582 | } |
|
0 commit comments