diff --git a/BUILD b/BUILD index 20454c9891..6f024f4997 100644 --- a/BUILD +++ b/BUILD @@ -136,9 +136,12 @@ java_library( java_library( name = "springboot_security", exports = [ + "@maven//:org_springframework_boot_spring_boot_starter_oauth2_client", "@maven//:org_springframework_boot_spring_boot_starter_security", + "@maven//:org_springframework_security_oauth_spring_security_oauth2", "@maven//:org_springframework_security_spring_security_config", "@maven//:org_springframework_security_spring_security_core", + "@maven//:org_springframework_security_spring_security_oauth2_core", "@maven//:org_springframework_security_spring_security_web", ], ) diff --git a/VERSION b/VERSION index 1cf0537c34..5a03fb737b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.19.0 +0.20.0 diff --git a/WORKSPACE b/WORKSPACE index 3fce84f6b3..271e190dc1 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -33,6 +33,7 @@ maven_install( "com.github.everit-org.json-schema:org.everit.json.schema:1.12.2", "com.google.auth:google-auth-library-oauth2-http:0.20.0", "com.jayway.jsonpath:json-path:2.4.0", + "com.dinstone:beanstalkc:2.3.0", "com.twilio.sdk:twilio:7.51.0", "io.confluent:kafka-avro-serializer:5.5.1", "io.confluent:kafka-schema-registry-client:5.5.1", @@ -41,7 +42,6 @@ maven_install( "io.jsonwebtoken:jjwt-api:0.10.5", "io.jsonwebtoken:jjwt-impl:0.10.5", "io.jsonwebtoken:jjwt-jackson:0.10.5", - "io.lettuce:lettuce-core:5.3.3.RELEASE", "io.micrometer:micrometer-registry-prometheus:1.6.5", "javax.activation:javax.activation-api:1.2.0", "javax.validation:validation-api:2.0.1.Final", @@ -77,13 +77,14 @@ maven_install( "org.springframework.boot:spring-boot-starter-web:2.4.5", "org.springframework.boot:spring-boot-starter-websocket:2.4.5", "org.springframework.boot:spring-boot-starter-security:2.4.5", + "org.springframework.boot:spring-boot-starter-oauth2-client:2.4.5", + "org.springframework.security.oauth:spring-security-oauth2:2.4.1.RELEASE", "org.springframework.retry:spring-retry:1.2.5.RELEASE", "org.springframework:spring-aop:4.1.4.RELEASE", "org.springframework:spring-context-support:5.3.6", "org.springframework:spring-context:5.3.6", "org.springframework:spring-messaging:5.3.6", "org.springframework:spring-websocket:5.3.6", - "org.springframework.data:spring-data-redis:2.3.3.RELEASE", "org.springframework.security:spring-security-core:5.4.6", "org.rocksdb:rocksdbjni:5.18.3", ], diff --git a/backend/BUILD b/backend/BUILD index 004eb75715..29bd98d74f 100644 --- a/backend/BUILD +++ b/backend/BUILD @@ -32,14 +32,6 @@ java_library( ], ) -java_library( - name = "tag", - exports = [ - "//backend/avro:tag", - "//lib/java/kafka/schema:application-communication-tags", - ], -) - java_library( name = "webhook", exports = [ diff --git a/backend/api/admin/BUILD b/backend/api/admin/BUILD index 9f5867e4f4..a51240b54f 100644 --- a/backend/api/admin/BUILD +++ b/backend/api/admin/BUILD @@ -7,7 +7,7 @@ app_deps = [ "//backend:base_app", "//:springboot_actuator", "//backend/model/channel", - "//backend:tag", + "//backend/model/tag", "//backend:webhook", "//backend/model/metadata", "//backend/model/template", diff --git a/backend/api/admin/src/main/java/co/airy/core/api/admin/TagsController.java b/backend/api/admin/src/main/java/co/airy/core/api/admin/TagsController.java index 61b10b17e8..27aa2f120e 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/admin/TagsController.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/admin/TagsController.java @@ -5,7 +5,7 @@ import co.airy.core.api.admin.payload.CreateTagRequestPayload; import co.airy.core.api.admin.payload.DeleteTagRequestPayload; import co.airy.core.api.admin.payload.ListTagsResponsePayload; -import co.airy.core.api.admin.payload.TagResponsePayload; +import co.airy.core.api.admin.payload.TagPayload; import co.airy.core.api.admin.payload.UpdateTagRequestPayload; import co.airy.spring.web.payload.RequestErrorResponsePayload; import org.apache.kafka.streams.state.KeyValueIterator; @@ -62,11 +62,7 @@ ResponseEntity createTag(@RequestBody @Valid CreateTagRequestPayload payload) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); } - return ResponseEntity.status(201).body(TagResponsePayload.builder() - .id(tag.getId()) - .name(tag.getName()) - .color(tag.getColor().toString()) - .build()); + return ResponseEntity.status(201).body(TagPayload.fromTag(tag)); } @PostMapping("/tags.list") @@ -77,13 +73,7 @@ ResponseEntity listTags() { List tags = new ArrayList<>(); iterator.forEachRemaining(kv -> tags.add(kv.value)); - final List data = tags.stream() - .map(tag -> TagResponsePayload.builder() - .id(tag.getId()) - .name(tag.getName()) - .color(tag.getColor().toString()) - .build() - ).collect(toList()); + final List data = tags.stream().map(TagPayload::fromTag).collect(toList()); return ResponseEntity.ok().body(ListTagsResponsePayload.builder().data(data).build()); } diff --git a/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/ListTagsResponsePayload.java b/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/ListTagsResponsePayload.java index bd9c628e8a..c04add3def 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/ListTagsResponsePayload.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/ListTagsResponsePayload.java @@ -12,5 +12,5 @@ @AllArgsConstructor @Builder public class ListTagsResponsePayload { - private List data; + private List data; } diff --git a/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/TagResponsePayload.java b/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/TagResponsePayload.java deleted file mode 100644 index 5968bc618e..0000000000 --- a/backend/api/admin/src/main/java/co/airy/core/api/admin/payload/TagResponsePayload.java +++ /dev/null @@ -1,16 +0,0 @@ -package co.airy.core.api.admin.payload; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class TagResponsePayload { - private String id; - private String name; - private String color; -} diff --git a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java index 5c4d35c666..c74a7c1af6 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigController.java @@ -1,6 +1,8 @@ package co.airy.core.api.config; +import co.airy.spring.auth.PrincipalAccess; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @@ -13,9 +15,10 @@ public ClientConfigController(ServiceDiscovery serviceDiscovery) { } @PostMapping("/client.config") - public ResponseEntity getConfig() { + public ResponseEntity getConfig(Authentication auth) { return ResponseEntity.ok(ClientConfigResponsePayload.builder() .components(serviceDiscovery.getComponents()) + .userProfile(PrincipalAccess.getUserProfile(auth)) .build()); } } diff --git a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigResponsePayload.java b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigResponsePayload.java index 56f96a52b6..5ec8e9fd7f 100644 --- a/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigResponsePayload.java +++ b/backend/api/admin/src/main/java/co/airy/core/api/config/ClientConfigResponsePayload.java @@ -1,5 +1,6 @@ package co.airy.core.api.config; +import co.airy.spring.auth.session.UserProfile; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -13,4 +14,5 @@ @AllArgsConstructor public class ClientConfigResponsePayload { private Map> components; + private UserProfile userProfile; } diff --git a/backend/api/admin/src/test/java/co/airy/core/api/admin/TagsControllerTest.java b/backend/api/admin/src/test/java/co/airy/core/api/admin/TagsControllerTest.java index 068c50e123..2ddbf3acc0 100644 --- a/backend/api/admin/src/test/java/co/airy/core/api/admin/TagsControllerTest.java +++ b/backend/api/admin/src/test/java/co/airy/core/api/admin/TagsControllerTest.java @@ -23,8 +23,7 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; -import java.util.concurrent.TimeUnit; - +import static co.airy.test.Timing.retryOnException; import static org.hamcrest.CoreMatchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -74,7 +73,7 @@ void beforeEach() throws Exception { @Test void canManageTags() throws Exception { - final String name = "awesome-tag"; + final String name = "flag"; final String color = "tag-red"; final String payload = "{\"name\":\"" + name + "\",\"color\": \"" + color + "\"}"; @@ -87,34 +86,33 @@ void canManageTags() throws Exception { final JsonNode jsonNode = objectMapper.readTree(createTagResponse); final String tagId = jsonNode.get("id").textValue(); - //TODO wait for tag to be there - TimeUnit.SECONDS.sleep(5); - webTestHelper.post("/tags.list", "{}") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.data.length()", is(1))) - .andExpect(jsonPath("$.data[0].id").value(is(tagId))) - .andExpect(jsonPath("$.data[0].name").value(is(name))) - .andExpect(jsonPath("$.data[0].color").value(is("RED"))); + retryOnException(() -> + webTestHelper.post("/tags.list", "{}") + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.length()", is(1))) + .andExpect(jsonPath("$.data[0].id").value(is(tagId))) + .andExpect(jsonPath("$.data[0].name").value(is(name))) + .andExpect(jsonPath("$.data[0].color").value(is("tag-red"))), + "could not create tag"); webTestHelper.post("/tags.update", - "{\"id\": \"" + tagId + "\", \"name\": \"new-name\", \"color\": \"" + color + "\"}") + "{\"id\": \"" + tagId + "\", \"name\": \"new-flag\", \"color\": \"" + color + "\"}") .andExpect(status().isNoContent()); - webTestHelper.post("/tags.list", "{}") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.data.length()", is(1))) - .andExpect(jsonPath("$.data[0].id").value(is(tagId))) - .andExpect(jsonPath("$.data[0].name").value(is("new-name"))) - .andExpect(jsonPath("$.data[0].color").value(is("RED"))); + retryOnException(() -> webTestHelper.post("/tags.list", "{}") + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.length()", is(1))) + .andExpect(jsonPath("$.data[0].id").value(is(tagId))) + .andExpect(jsonPath("$.data[0].name").value(is("new-flag"))) + .andExpect(jsonPath("$.data[0].color").value(is("tag-red"))), + "could not update tag"); webTestHelper.post("/tags.delete", "{\"id\": \"" + tagId + "\"}").andExpect(status().isNoContent()); - //TODO wait for tag deletion - TimeUnit.SECONDS.sleep(5); - - webTestHelper.post("/tags.list", "{}") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.data.length()", is(0))); + retryOnException(() -> webTestHelper.post("/tags.list", "{}") + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.length()", is(0))), + "could not delete tag"); } } diff --git a/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java b/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java index 566b4347ad..d7c5fa06fc 100644 --- a/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java +++ b/backend/api/communication/src/main/java/co/airy/core/api/communication/SendMessageController.java @@ -28,6 +28,8 @@ import java.util.UUID; import java.util.concurrent.ExecutionException; +import static co.airy.spring.auth.PrincipalAccess.getUserId; + @RestController public class SendMessageController { private final Stores stores; @@ -43,7 +45,7 @@ public class SendMessageController { } @PostMapping("/messages.send") - public ResponseEntity sendMessage(@RequestBody @Valid SendMessageRequestPayload payload) throws ExecutionException, InterruptedException, JsonProcessingException { + public ResponseEntity sendMessage(@RequestBody @Valid SendMessageRequestPayload payload, Authentication auth) throws ExecutionException, InterruptedException, JsonProcessingException { final ReadOnlyKeyValueStore conversationsStore = stores.getConversationsStore(); final Conversation conversation = conversationsStore.get(payload.getConversationId().toString()); @@ -56,6 +58,8 @@ public ResponseEntity sendMessage(@RequestBody @Valid SendMessageRequestPaylo return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } + final String userId = getUserId(auth); + final Message message = Message.newBuilder() .setId(UUID.randomUUID().toString()) .setChannelId(channel.getId()) @@ -64,8 +68,7 @@ public ResponseEntity sendMessage(@RequestBody @Valid SendMessageRequestPaylo .setHeaders(Map.of()) .setDeliveryState(DeliveryState.PENDING) .setSource(channel.getSource()) - // TODO add the oidc id here in https://github.com/airyhq/airy/issues/1518 - .setSenderId("airy-core-anonymous") + .setSenderId(userId) .setSentAt(Instant.now().toEpochMilli()) .setIsFromContact(false) .build(); diff --git a/backend/api/websocket/BUILD b/backend/api/websocket/BUILD index b92e0ba082..b51ddf2590 100644 --- a/backend/api/websocket/BUILD +++ b/backend/api/websocket/BUILD @@ -11,6 +11,7 @@ app_deps = [ "//backend/model/event", "//backend/model/message", "//backend/model/metadata", + "//backend/model/tag", "//lib/java/date", "//lib/java/spring/auth:spring-auth", "//lib/java/spring/web:spring-web", diff --git a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/Stores.java b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/Stores.java index 65a973f692..bd2b36c0b8 100644 --- a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/Stores.java +++ b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/Stores.java @@ -3,9 +3,11 @@ import co.airy.avro.communication.Channel; import co.airy.avro.communication.Message; import co.airy.avro.communication.Metadata; +import co.airy.avro.communication.Tag; import co.airy.kafka.schema.application.ApplicationCommunicationChannels; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; +import co.airy.kafka.schema.application.ApplicationCommunicationTags; import co.airy.kafka.streams.KafkaStreamsWrapper; import co.airy.model.metadata.dto.MetadataMap; import org.apache.kafka.streams.KeyValue; @@ -22,13 +24,11 @@ @Component public class Stores implements HealthIndicator, ApplicationListener, DisposableBean { - private static final String appId = "api.WebsocketStores"; + private static final String appId = "api.WebSocketStores"; private final KafkaStreamsWrapper streams; private final WebSocketController webSocketController; - Stores(KafkaStreamsWrapper streams, - WebSocketController webSocketController - ) { + Stores(KafkaStreamsWrapper streams, WebSocketController webSocketController) { this.streams = streams; this.webSocketController = webSocketController; } @@ -43,6 +43,10 @@ public void onApplicationEvent(ApplicationStartedEvent event) { builder.stream(new ApplicationCommunicationChannels().name()) .peek((channelId, channel) -> webSocketController.onChannel(channel)); + builder.stream(new ApplicationCommunicationTags().name()) + .filter((id, tag) -> tag != null) + .peek((id, tag) -> webSocketController.onTag(tag)); + builder.table(new ApplicationCommunicationMetadata().name()) .groupBy((metadataId, metadata) -> KeyValue.pair(getSubject(metadata).getIdentifier(), metadata)) .aggregate(MetadataMap::new, MetadataMap::adder, MetadataMap::subtractor) diff --git a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketConfig.java b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketConfig.java index a16dc58c56..11010016d7 100644 --- a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketConfig.java +++ b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketConfig.java @@ -1,42 +1,17 @@ package co.airy.core.api.websocket; -import co.airy.log.AiryLoggerFactory; -import org.slf4j.Logger; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.messaging.simp.stomp.StompCommand; -import org.springframework.messaging.simp.stomp.StompHeaderAccessor; -import org.springframework.messaging.support.ChannelInterceptor; -import org.springframework.messaging.support.MessageHeaderAccessor; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.web.server.ResponseStatusException; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; -import java.util.List; - @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - private static final Logger log = AiryLoggerFactory.getLogger(WebSocketConfig.class); - private final String systemToken; - private final String systemTokenPrincipal; - - public WebSocketConfig(@Value("${systemToken:#{null}}") String systemToken) { - this.systemToken = systemToken; - this.systemTokenPrincipal = systemToken == null ? null : String.format("system-token-%s", systemToken.substring(0, Math.min(systemToken.length(), 4))); - } - @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker() @@ -58,39 +33,4 @@ TaskScheduler heartbeatScheduler() { return heartbeatScheduler; } - - @Override - public void configureClientInboundChannel(ChannelRegistration registration) { - registration.interceptors(new ChannelInterceptor() { - @Override - public Message preSend(Message message, MessageChannel channel) { - if (systemToken == null) { - return message; - } - - final StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); - - if (accessor != null && StompCommand.CONNECT.equals(accessor.getCommand())) { - String authToken = accessor.getFirstNativeHeader(HttpHeaders.AUTHORIZATION); - if (authToken != null && authToken.startsWith("Bearer")) { - authToken = authToken.substring(7); - } - - try { - if (systemToken.equals(authToken)) { - accessor.setUser(new UsernamePasswordAuthenticationToken(systemTokenPrincipal, null, List.of())); - } - } catch (Exception e) { - log.error(String.format("STOMP Command: %s, token: %s \n Failed to authenticate", accessor.getCommand(), authToken)); - } - } - - if (accessor == null || accessor.getUser() == null) { - throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); - } - - return message; - } - }); - } } diff --git a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketController.java b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketController.java index 0f189c4826..feb4cc1b2a 100644 --- a/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketController.java +++ b/backend/api/websocket/src/main/java/co/airy/core/api/websocket/WebSocketController.java @@ -2,10 +2,12 @@ import co.airy.avro.communication.Channel; import co.airy.avro.communication.Message; +import co.airy.avro.communication.Tag; import co.airy.model.channel.ChannelPayload; import co.airy.model.event.payload.ChannelEvent; import co.airy.model.event.payload.MessageEvent; import co.airy.model.event.payload.MetadataEvent; +import co.airy.model.event.payload.TagEvent; import co.airy.model.metadata.dto.MetadataMap; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; @@ -38,4 +40,8 @@ public void onMetadata(MetadataMap metadataMap) { messagingTemplate.convertAndSend(QUEUE_EVENTS, MetadataEvent.fromMetadataMap(metadataMap)); } + + public void onTag(Tag tag) { + messagingTemplate.convertAndSend(QUEUE_EVENTS, TagEvent.fromTag(tag)); + } } diff --git a/backend/api/websocket/src/test/java/co/airy/core/api/websocket/WebSocketControllerTest.java b/backend/api/websocket/src/test/java/co/airy/core/api/websocket/WebSocketControllerTest.java index 90a9e03560..213acc37b1 100644 --- a/backend/api/websocket/src/test/java/co/airy/core/api/websocket/WebSocketControllerTest.java +++ b/backend/api/websocket/src/test/java/co/airy/core/api/websocket/WebSocketControllerTest.java @@ -5,14 +5,18 @@ import co.airy.avro.communication.DeliveryState; import co.airy.avro.communication.Message; import co.airy.avro.communication.Metadata; +import co.airy.avro.communication.Tag; +import co.airy.avro.communication.TagColor; import co.airy.kafka.schema.application.ApplicationCommunicationChannels; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; +import co.airy.kafka.schema.application.ApplicationCommunicationTags; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; import co.airy.model.event.payload.ChannelEvent; import co.airy.model.event.payload.MessageEvent; import co.airy.model.event.payload.MetadataEvent; +import co.airy.model.event.payload.TagEvent; import co.airy.spring.core.AirySpringBootApplication; import co.airy.spring.test.WebTestHelper; import com.fasterxml.jackson.databind.ObjectMapper; @@ -51,7 +55,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.springframework.http.HttpHeaders.AUTHORIZATION; @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {AirySpringBootApplication.class}) @@ -65,11 +68,11 @@ public class WebSocketControllerTest { private static final ApplicationCommunicationMessages applicationCommunicationMessages = new ApplicationCommunicationMessages(); private static final ApplicationCommunicationChannels applicationCommunicationChannels = new ApplicationCommunicationChannels(); private static final ApplicationCommunicationMetadata applicationCommunicationMetadata = new ApplicationCommunicationMetadata(); + private static final ApplicationCommunicationTags applicationCommunicationTags = new ApplicationCommunicationTags(); @Value("${local.server.port}") private int port; - @Autowired private WebTestHelper webTestHelper; @@ -78,7 +81,8 @@ static void beforeAll() throws Exception { kafkaTestHelper = new KafkaTestHelper(sharedKafkaTestResource, applicationCommunicationMessages, applicationCommunicationChannels, - applicationCommunicationMetadata + applicationCommunicationMetadata, + applicationCommunicationTags ); kafkaTestHelper.beforeAll(); } @@ -94,7 +98,7 @@ void beforeEach() throws Exception { } @Test - void canReceiveMessageEvents() throws Exception { + void canSendMessageEvents() throws Exception { final CompletableFuture future = subscribe(port, MessageEvent.class, QUEUE_EVENTS); final Message message = Message.newBuilder() .setId("messageId") @@ -120,7 +124,7 @@ void canReceiveMessageEvents() throws Exception { } @Test - void canReceiveChannelEvents() throws Exception { + void canSendChannelEvents() throws Exception { final CompletableFuture future = subscribe(port, ChannelEvent.class, QUEUE_EVENTS); final Channel channel = Channel.newBuilder() @@ -138,7 +142,7 @@ void canReceiveChannelEvents() throws Exception { } @Test - void canReceiveMetadataEvents() throws Exception { + void canSendMetadataEvents() throws Exception { final CompletableFuture future = subscribe(port, MetadataEvent.class, QUEUE_EVENTS); final Metadata metadata = Metadata.newBuilder() @@ -157,6 +161,26 @@ void canReceiveMetadataEvents() throws Exception { assertThat(recMetadata.getPayload().getMetadata().get("contact").get("displayName").textValue(), equalTo(metadata.getValue())); } + @Test + void canSendTagEvents() throws Exception { + final CompletableFuture future = subscribe(port, TagEvent.class, QUEUE_EVENTS); + + String tagId=UUID.randomUUID().toString(); + final Tag tag = Tag.newBuilder() + .setId(tagId) + .setName("flag") + .setColor(TagColor.RED) + .build(); + + kafkaTestHelper.produceRecord(new ProducerRecord<>(applicationCommunicationTags.name(), tagId, tag)); + + TagEvent tagEvent = future.get(30, TimeUnit.SECONDS); + assertNotNull(tagEvent); + assertThat(tagEvent.getPayload().getId(), equalTo(tagId)); + assertThat(tagEvent.getPayload().getName(), equalTo("flag")); + assertThat(tagEvent.getPayload().getColor(), equalTo("tag-red")); + } + private static StompSession connectToWs(int port) throws ExecutionException, InterruptedException { final WebSocketStompClient stompClient = new WebSocketStompClient(new StandardWebSocketClient()); MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter(); diff --git a/backend/avro/BUILD b/backend/avro/BUILD index 77f06c43aa..d79dfd54d2 100644 --- a/backend/avro/BUILD +++ b/backend/avro/BUILD @@ -27,7 +27,8 @@ avro_java_library( ) avro_java_library( - name = "tag", + name = "tag-avro", + srcs = ["tag.avsc"], ) avro_java_library( diff --git a/backend/model/event/BUILD b/backend/model/event/BUILD index 8faff392a8..5158888b6b 100644 --- a/backend/model/event/BUILD +++ b/backend/model/event/BUILD @@ -11,6 +11,7 @@ custom_java_library( "//backend/model/channel", "//backend/model/message", "//backend/model/metadata", + "//backend/model/tag", ], ) diff --git a/backend/model/event/src/main/java/co/airy/model/event/payload/Event.java b/backend/model/event/src/main/java/co/airy/model/event/payload/Event.java index aae28c1c68..f374ee61bd 100644 --- a/backend/model/event/src/main/java/co/airy/model/event/payload/Event.java +++ b/backend/model/event/src/main/java/co/airy/model/event/payload/Event.java @@ -3,11 +3,12 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = MessageEvent.class, name = "message"), @JsonSubTypes.Type(value = MetadataEvent.class, name = "metadata"), - @JsonSubTypes.Type(value = ChannelEvent.class, name = "channel") + @JsonSubTypes.Type(value = ChannelEvent.class, name = "channel"), + @JsonSubTypes.Type(value = TagEvent.class, name = "tag") }) public abstract class Event { } diff --git a/backend/model/event/src/main/java/co/airy/model/event/payload/TagEvent.java b/backend/model/event/src/main/java/co/airy/model/event/payload/TagEvent.java new file mode 100644 index 0000000000..d0624611e8 --- /dev/null +++ b/backend/model/event/src/main/java/co/airy/model/event/payload/TagEvent.java @@ -0,0 +1,24 @@ +package co.airy.model.event.payload; + +import co.airy.avro.communication.Tag; +import co.airy.core.api.admin.payload.TagPayload; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +public class TagEvent extends Event implements Serializable { + private TagPayload payload; + + public static TagEvent fromTag(Tag tag) { + return builder().payload(TagPayload.fromTag(tag)).build(); + } +} diff --git a/backend/model/tag/BUILD b/backend/model/tag/BUILD new file mode 100644 index 0000000000..9487eeab53 --- /dev/null +++ b/backend/model/tag/BUILD @@ -0,0 +1,19 @@ +load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") +load("//tools/build:java_library.bzl", "custom_java_library") + +custom_java_library( + name = "tag", + srcs = glob(["src/main/java/co/airy/model/tag/**/*.java"]), + visibility = ["//visibility:public"], + exports = [ + "//backend/avro:tag-avro", + "//lib/java/kafka/schema:application-communication-tags", + ], + deps = [ + "//:jackson", + "//:lombok", + "//backend/avro:tag-avro", + ], +) + +check_pkg(name = "buildifier") diff --git a/backend/model/tag/src/main/java/co/airy/model/tag/TagPayload.java b/backend/model/tag/src/main/java/co/airy/model/tag/TagPayload.java new file mode 100644 index 0000000000..4a692c84ac --- /dev/null +++ b/backend/model/tag/src/main/java/co/airy/model/tag/TagPayload.java @@ -0,0 +1,25 @@ +package co.airy.core.api.admin.payload; + +import co.airy.avro.communication.Tag; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class TagPayload { + private String id; + private String name; + private String color; + + public static TagPayload fromTag(Tag tag) { + return TagPayload.builder() + .id(tag.getId()) + .color("tag-"+tag.getColor().toString().toLowerCase()) + .name(tag.getName()) + .build(); + } +} diff --git a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/config/AuthConfig.java b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/config/AuthConfig.java index bf29f44e88..e1e3c865b6 100644 --- a/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/config/AuthConfig.java +++ b/backend/sources/chat-plugin/src/main/java/co/airy/core/chat_plugin/config/AuthConfig.java @@ -49,7 +49,7 @@ CorsConfigurationSource corsConfigurationSource(final Environment environment) { final String allowed = environment.getProperty("allowedOrigins", ""); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); - config.addAllowedOrigin(allowed); + config.addAllowedOriginPattern(allowed); config.addAllowedHeader("*"); config.setAllowedMethods(List.of("GET", "POST")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); diff --git a/backend/webhook/redis-worker/BUILD b/backend/webhook/consumer/BUILD similarity index 68% rename from backend/webhook/redis-worker/BUILD rename to backend/webhook/consumer/BUILD index 21bab2e1a9..dc7ef58c4a 100644 --- a/backend/webhook/redis-worker/BUILD +++ b/backend/webhook/consumer/BUILD @@ -1,4 +1,4 @@ -# gazelle:prefix redis-worker +# gazelle:prefix consumer load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") @@ -6,14 +6,14 @@ load("@io_bazel_rules_docker//go:image.bzl", "go_image") load("//tools/build:container_release.bzl", "container_release") go_binary( - name = "redis-worker_binary", - embed = [":redis-worker_lib"], + name = "consumer_binary", + embed = [":consumer_lib"], visibility = ["//visibility:public"], ) go_image( name = "image", - embed = [":redis-worker_lib"], + embed = [":consumer_lib"], ) container_release( @@ -21,12 +21,12 @@ container_release( repository = "consumer", ) +check_pkg(name = "buildifier") + go_library( - name = "redis-worker_lib", + name = "consumer_lib", srcs = ["main.go"], - importpath = "redis-worker", + importpath = "consumer", visibility = ["//visibility:private"], - deps = ["//backend/webhook/redis-worker/pkg/scheduler"], + deps = ["//backend/webhook/consumer/pkg/worker"], ) - -check_pkg(name = "buildifier") diff --git a/backend/webhook/consumer/go.mod b/backend/webhook/consumer/go.mod new file mode 100644 index 0000000000..2fe45fe9ff --- /dev/null +++ b/backend/webhook/consumer/go.mod @@ -0,0 +1,10 @@ +module consumer + +go 1.16 + +require ( + github.com/Shopify/sarama v1.28.0 + github.com/beanstalkd/go-beanstalk v0.1.0 + github.com/jpillora/backoff v1.0.0 + github.com/riferrei/srclient v0.2.1 +) diff --git a/backend/webhook/consumer/go.sum b/backend/webhook/consumer/go.sum new file mode 100644 index 0000000000..c0b5db1153 --- /dev/null +++ b/backend/webhook/consumer/go.sum @@ -0,0 +1,98 @@ +github.com/Shopify/sarama v1.28.0 h1:lOi3SfE6OcFlW9Trgtked2aHNZ2BIG/d6Do+PEUAqqM= +github.com/Shopify/sarama v1.28.0/go.mod h1:j/2xTrU39dlzBmsxF1eQ2/DdWrxyBCl6pzz7a81o/ZY= +github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/beanstalkd/go-beanstalk v0.1.0 h1:IiNwYbAoVBDs5xEOmleGoX+DRD3Moz99EpATbl8672w= +github.com/beanstalkd/go-beanstalk v0.1.0/go.mod h1:/G8YTyChOtpOArwLTQPY1CHB+i212+av35bkPXXj56Y= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/linkedin/goavro/v2 v2.9.7 h1:Vd++Rb/RKcmNJjM0HP/JJFMEWa21eUBVKPYlKehOGrM= +github.com/linkedin/goavro/v2 v2.9.7/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= +github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A= +github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/riferrei/srclient v0.2.1 h1:uIJhzPXW+suDsEDOZKf4oTZZXTyxtw98cFC70rFzvgU= +github.com/riferrei/srclient v0.2.1/go.mod h1:SmCz0lrYQ1pLqXlYq0yPnRccHLGh+llDA0i6hecPeW8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/webhook/consumer/main.go b/backend/webhook/consumer/main.go new file mode 100644 index 0000000000..d0c65203a5 --- /dev/null +++ b/backend/webhook/consumer/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "consumer/pkg/worker" + "context" + "log" + "os" + "os/signal" + "strconv" + "sync" + "syscall" + "time" +) + +func main() { + maxBackOffSeconds, err := strconv.Atoi(os.Getenv("MAX_BACKOFF_SECONDS")) + if err != nil { + log.Fatal("MAX_BACKOFF_SECONDS not set") + } + + ctx, cancel := context.WithCancel(context.Background()) + var wg sync.WaitGroup + + webhookConfigStream := make(chan string) + + kafkaConsumerConfig := worker.KafkaConsumerConfig{ + Brokers: os.Getenv("KAFKA_BROKERS"), + SchemaRegistryURL: os.Getenv("KAFKA_SCHEMA_REGISTRY_URL"), + Group: "WebhookConsumer", + Topics: "application.communication.webhooks", + } + + wg.Add(1) + go worker.StartKafkaConsumer(ctx, &wg, webhookConfigStream, kafkaConsumerConfig) + + w, err := worker.Start( + ctx, + &wg, + webhookConfigStream, + os.Getenv("BEANSTALK_HOSTNAME"), + os.Getenv("BEANSTALK_PORT"), + time.Duration(maxBackOffSeconds)*time.Second, + ) + if err != nil { + cancel() + } + + wg.Add(1) + go w.StartServer(ctx, &wg) + + sigterm := make(chan os.Signal, 1) + signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM) + + <-sigterm + log.Println("terminating: via signal") + cancel() + wg.Wait() +} diff --git a/backend/webhook/consumer/pkg/worker/BUILD b/backend/webhook/consumer/pkg/worker/BUILD new file mode 100644 index 0000000000..aa42f1db79 --- /dev/null +++ b/backend/webhook/consumer/pkg/worker/BUILD @@ -0,0 +1,21 @@ +load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +check_pkg(name = "buildifier") + +go_library( + name = "worker", + srcs = [ + "consumer.go", + "server.go", + "worker.go", + ], + importpath = "consumer/pkg/worker", + visibility = ["//visibility:public"], + deps = [ + "@com_github_beanstalkd_go_beanstalk//:go-beanstalk", + "@com_github_jpillora_backoff//:backoff", + "@com_github_riferrei_srclient//:srclient", + "@com_github_shopify_sarama//:sarama", + ], +) diff --git a/backend/webhook/consumer/pkg/worker/consumer.go b/backend/webhook/consumer/pkg/worker/consumer.go new file mode 100644 index 0000000000..bc4e4be13f --- /dev/null +++ b/backend/webhook/consumer/pkg/worker/consumer.go @@ -0,0 +1,97 @@ +package worker + +import ( + "context" + "encoding/binary" + "fmt" + "log" + "strings" + "sync" + + "github.com/Shopify/sarama" + "github.com/riferrei/srclient" +) + +type Consumer struct { + ready chan bool + webhookConfigStream chan string + schemaRegistryClient *srclient.SchemaRegistryClient +} + +type KafkaConsumerConfig struct { + Brokers, SchemaRegistryURL, Topics, Group string +} + +func StartKafkaConsumer( + ctx context.Context, + wg *sync.WaitGroup, + webhookConfigStream chan string, + kafkaConsumerConfig KafkaConsumerConfig, +) { + defer wg.Done() + config := sarama.NewConfig() + config.Consumer.Offsets.Initial = sarama.OffsetOldest + + schemaRegistryClient := srclient.CreateSchemaRegistryClient(kafkaConsumerConfig.SchemaRegistryURL) + + consumer := Consumer{ + ready: make(chan bool), + webhookConfigStream: webhookConfigStream, + schemaRegistryClient: schemaRegistryClient, + } + + client, err := sarama.NewConsumerGroup(strings.Split(kafkaConsumerConfig.Brokers, ","), kafkaConsumerConfig.Group, config) + if err != nil { + log.Panicf("Error creating consumer group client: %v", err) + } + + go func() { + for { + if err := client.Consume(ctx, strings.Split(kafkaConsumerConfig.Topics, ","), &consumer); err != nil { + log.Panicf("Error from consumer: %v", err) + } + if ctx.Err() != nil { + return + } + consumer.ready = make(chan bool) + } + }() + + <-consumer.ready + log.Println("Sarama consumer up and running!...") + + <-ctx.Done() + log.Println("terminating consumer: context cancelled") + if err = client.Close(); err != nil { + log.Panicf("Error closing client: %v", err) + } +} + +func (consumer *Consumer) Setup(sarama.ConsumerGroupSession) error { + close(consumer.ready) + return nil +} + +func (consumer *Consumer) Cleanup(sarama.ConsumerGroupSession) error { + return nil +} + +func (consumer *Consumer) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { + for config := range claim.Messages() { + consumer.publishWebhookConfig(config) + session.MarkMessage(config, "") + } + return nil +} + +func (consumer *Consumer) publishWebhookConfig(config *sarama.ConsumerMessage) { + schemaID := binary.BigEndian.Uint32(config.Value[1:5]) + schema, err := consumer.schemaRegistryClient.GetSchema(int(schemaID)) + if err != nil { + panic(fmt.Sprintf("Error getting the schema with id '%d' %s", schemaID, err)) + } + native, _, _ := schema.Codec().NativeFromBinary(config.Value[5:]) + value, _ := schema.Codec().TextualFromNative(nil, native) + + consumer.webhookConfigStream <- string(value) +} diff --git a/backend/webhook/redis-worker/main.go b/backend/webhook/consumer/pkg/worker/server.go similarity index 52% rename from backend/webhook/redis-worker/main.go rename to backend/webhook/consumer/pkg/worker/server.go index 6249504580..00197292b3 100644 --- a/backend/webhook/redis-worker/main.go +++ b/backend/webhook/consumer/pkg/worker/server.go @@ -1,18 +1,17 @@ -package main +package worker import ( + "context" "encoding/json" "log" "net/http" - "os" - "redis-worker/pkg/scheduler" + "sync" ) -func main() { - schedulerTask := scheduler.Start(os.Getenv("REDIS_HOSTNAME"), os.Getenv("REDIS_PORT")) - +func (worker *Worker) StartServer(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) { - errors, err := json.Marshal(schedulerTask.GetStatuses()) + errors, err := json.Marshal(worker.GetErrors()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -29,5 +28,13 @@ func main() { w.WriteHeader(200) }) - log.Fatal(http.ListenAndServe(":8080", nil)) + go func() { + log.Println("serving on 8080") + err := http.ListenAndServe(":8080", nil) + if err != nil { + panic("ListenAndServe: " + err.Error()) + } + }() + <-ctx.Done() + log.Println("terminating server: context cancelled") } diff --git a/backend/webhook/consumer/pkg/worker/worker.go b/backend/webhook/consumer/pkg/worker/worker.go new file mode 100644 index 0000000000..2cea9585db --- /dev/null +++ b/backend/webhook/consumer/pkg/worker/worker.go @@ -0,0 +1,158 @@ +package worker + +import ( + "context" + "encoding/json" + "errors" + "sync" + + "github.com/beanstalkd/go-beanstalk" + "github.com/jpillora/backoff" + + "bytes" + "fmt" + + "log" + "net/http" + "time" +) + +type Worker struct { + endpoint string + customHeader map[string]string + beanstalk *beanstalk.Conn + backoff *backoff.Backoff + errors []consumerError +} +type consumerError struct { + Err error + T time.Time +} + +type webhookConfig struct { + Id string + Endpoint string + Headers map[string]map[string]string + Status string +} + +func Start( + ctx context.Context, + wg *sync.WaitGroup, + webhookConfigStream chan string, + hostname, port string, + maxBackoff time.Duration, +) (*Worker, error) { + + conn, err := beanstalk.Dial("tcp", fmt.Sprintf("%s:%s", hostname, port)) + + if err != nil { + return nil, err + } + + w := Worker{ + endpoint: "", + customHeader: make(map[string]string), + beanstalk: conn, + backoff: &backoff.Backoff{Max: maxBackoff}, + errors: make([]consumerError, 0), + } + + wg.Add(2) + go w.Run(ctx, wg) + go w.updateWebhookConfig(ctx, wg, webhookConfigStream) + return &w, nil +} + +func (w *Worker) Run(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + for { + select { + case <-ctx.Done(): + log.Println("terminating worker: context canceled ") + return + default: + id, event, err := w.beanstalk.Reserve(1 * time.Minute) + if err != nil { + if !errors.Is(err, beanstalk.ErrTimeout) { + log.Println(err) + } + continue + } + + for { + select { + case <-ctx.Done(): + log.Println("terminating worker: context cancelled") + return + default: + err = w.HandleEvent(event) + if err != nil { + w.logError(err) + time.Sleep(w.backoff.Duration()) + continue + } + err = w.beanstalk.Delete(id) + if err != nil { + w.logError(err) + } + w.backoff.Reset() + break + } + } + } + } +} + +func (w *Worker) updateWebhookConfig(ctx context.Context, wg *sync.WaitGroup, webhookConfigStream chan string) { + defer wg.Done() + log.Println("Started updateWebhookConfig routine") + select { + case <-ctx.Done(): + log.Println("terminating updateWebhookConfig: context cancelled") + case config := <-webhookConfigStream: + var webhookConfig = webhookConfig{} + if err := json.Unmarshal([]byte(config), &webhookConfig); err != nil { + log.Fatal(err) + } + w.endpoint = webhookConfig.Endpoint + w.customHeader = webhookConfig.Headers["map"] + } +} + +func (w *Worker) HandleEvent(data []byte) error { + req, _ := http.NewRequest("POST", w.endpoint, bytes.NewBuffer(data)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("User-Agent", "Airy/1.0") + + for k, v := range w.customHeader { + req.Header.Set(k, v) + } + + client := &http.Client{ + Timeout: 10 * time.Second, + } + endpointResp, err := client.Do(req) + + if err != nil { + return err + } + + if endpointResp.StatusCode > 299 { + return fmt.Errorf("%v returned status code %v", w.endpoint, endpointResp.StatusCode) + } + + return nil +} + +func (t *Worker) logError(err error) { + log.Println(err) + t.errors = append(t.errors, consumerError{ + Err: err, + T: time.Now(), + }) +} + +func (t *Worker) GetErrors() []consumerError { + return t.errors +} diff --git a/backend/webhook/publisher/BUILD b/backend/webhook/publisher/BUILD index 4141c9c2cf..991ac516b5 100644 --- a/backend/webhook/publisher/BUILD +++ b/backend/webhook/publisher/BUILD @@ -13,8 +13,7 @@ app_deps = [ "//lib/java/date", "//lib/java/spring/kafka/core:spring-kafka-core", "//lib/java/spring/kafka/streams:spring-kafka-streams", - "@maven//:io_lettuce_lettuce_core", - "@maven//:org_springframework_data_spring_data_redis", + "@maven//:com_dinstone_beanstalkc", ] springboot( diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/RedisQueue.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/BeanstalkPublisher.java similarity index 52% rename from backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/RedisQueue.java rename to backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/BeanstalkPublisher.java index d248a664c5..3c19d635e1 100644 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/RedisQueue.java +++ b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/BeanstalkPublisher.java @@ -1,34 +1,35 @@ package co.airy.core.webhook.publisher; -import co.airy.core.webhook.publisher.payload.QueueMessage; import co.airy.log.AiryLoggerFactory; +import co.airy.model.event.payload.Event; +import com.dinstone.beanstalkc.JobProducer; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import org.slf4j.Logger; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service -public class RedisQueue { - private static final Logger log = AiryLoggerFactory.getLogger(RedisQueue.class); +public class BeanstalkPublisher { + private static final Logger log = AiryLoggerFactory.getLogger(BeanstalkPublisher.class); - final ObjectMapper objectMapper = new ObjectMapper() + private ObjectMapper objectMapper = new ObjectMapper() .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) .setSerializationInclusion(JsonInclude.Include.NON_NULL); - private final RedisTemplate redisTemplate; + private final JobProducer beanstalkdJobProducer; - RedisQueue(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; + BeanstalkPublisher(JobProducer beanstalkdJobProducer) { + this.beanstalkdJobProducer = beanstalkdJobProducer; } - void publishMessage(String webhookId, QueueMessage message) { + + void publishMessage(Event event) { try { - redisTemplate.opsForList().leftPush(webhookId, objectMapper.writeValueAsString(message)); + beanstalkdJobProducer.putJob(1, 1, 5000, objectMapper.writeValueAsBytes(event)); } catch (JsonProcessingException e) { - log.error("failed to publish message to redis", e); + log.error("Failed to publish event to Beanstalkd", e); } } } diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Publisher.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Publisher.java index ea55085a5d..b7abba7e77 100644 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Publisher.java +++ b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/Publisher.java @@ -4,7 +4,6 @@ import co.airy.avro.communication.Metadata; import co.airy.avro.communication.Status; import co.airy.avro.communication.Webhook; -import co.airy.core.webhook.publisher.payload.QueueMessage; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; import co.airy.kafka.schema.application.ApplicationCommunicationWebhooks; @@ -37,11 +36,11 @@ public class Publisher implements ApplicationListener, private final String webhooksStore = "webhook-store"; private final String allWebhooksKey = "339ab777-92aa-43a5-b452-82e73c50fc59"; private final KafkaStreamsWrapper streams; - private final RedisQueue redisQueuePublisher; + private final BeanstalkPublisher beanstalkdPublisher; - public Publisher(KafkaStreamsWrapper streams, RedisQueue redisQueuePublisher) { + public Publisher(KafkaStreamsWrapper streams, BeanstalkPublisher beanstalkdPublisher) { this.streams = streams; - this.redisQueuePublisher = redisQueuePublisher; + this.beanstalkdPublisher = beanstalkdPublisher; } private void startStream() { @@ -70,12 +69,7 @@ private void publishRecord(Serializable record) { final Webhook webhook = webhookStore.get(allWebhooksKey); if (webhook != null && webhook.getStatus().equals(Status.Subscribed)) { - redisQueuePublisher.publishMessage(webhook.getId(), QueueMessage.builder() - .body(fromRecord(record)) - .endpoint(webhook.getEndpoint()) - .headers(webhook.getHeaders()) - .build() - ); + beanstalkdPublisher.publishMessage(fromRecord(record)); } } catch (Exception e) { log.error("failed to publish record", e); diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/BeanstalkProducerConfig.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/BeanstalkProducerConfig.java new file mode 100644 index 0000000000..da3af61d69 --- /dev/null +++ b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/BeanstalkProducerConfig.java @@ -0,0 +1,22 @@ +package co.airy.core.webhook.publisher.config; + +import com.dinstone.beanstalkc.BeanstalkClientFactory; +import com.dinstone.beanstalkc.JobProducer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class BeanstalkProducerConfig { + + @Bean + public JobProducer beanstalkJobProducer(@Value("${beanstalk.hostname}") String hostName, @Value("${beanstalk.port}") int port) { + com.dinstone.beanstalkc.Configuration config = new com.dinstone.beanstalkc.Configuration(); + config.setServiceHost(hostName); + config.setServicePort(port); + config.setConnectTimeout(2000); + config.setReadTimeout(3000); + BeanstalkClientFactory beanstalkClientFactory = new BeanstalkClientFactory(config); + return beanstalkClientFactory.createJobProducer("default"); + } +} diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/LettuceConfig.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/LettuceConfig.java deleted file mode 100644 index e64637802f..0000000000 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/LettuceConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package co.airy.core.webhook.publisher.config; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisStandaloneConfiguration; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; - -@Configuration -public class LettuceConfig { - - @Bean - public LettuceConnectionFactory redisConnectionFactory(@Value("${redis.url}") final String hostName, @Value("${redis.port}") final int port) { - return new LettuceConnectionFactory(new RedisStandaloneConfiguration(hostName, port)); - } -} diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/RedisConfig.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/RedisConfig.java deleted file mode 100644 index fe1a1014cc..0000000000 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/config/RedisConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package co.airy.core.webhook.publisher.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration -public class RedisConfig { - private final LettuceConnectionFactory redisConnectionFactory; - - RedisConfig(LettuceConnectionFactory redisConnectionFactory) { - this.redisConnectionFactory = redisConnectionFactory; - } - - @Bean - public RedisTemplate redisTemplate() { - RedisTemplate stringTemplate = new RedisTemplate<>(); - stringTemplate.setConnectionFactory(redisConnectionFactory); - stringTemplate.setDefaultSerializer(new StringRedisSerializer()); - stringTemplate.afterPropertiesSet(); - - return stringTemplate; - } -} diff --git a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/payload/QueueMessage.java b/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/payload/QueueMessage.java deleted file mode 100644 index 613495fb3d..0000000000 --- a/backend/webhook/publisher/src/main/java/co/airy/core/webhook/publisher/payload/QueueMessage.java +++ /dev/null @@ -1,20 +0,0 @@ -package co.airy.core.webhook.publisher.payload; - -import co.airy.model.event.payload.Event; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.io.Serializable; -import java.util.Map; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class QueueMessage implements Serializable { - private String endpoint; - private Map headers; - private Event body; -} diff --git a/backend/webhook/publisher/src/main/resources/application.properties b/backend/webhook/publisher/src/main/resources/application.properties index dc8be7692e..efac0b55d3 100644 --- a/backend/webhook/publisher/src/main/resources/application.properties +++ b/backend/webhook/publisher/src/main/resources/application.properties @@ -3,5 +3,5 @@ kafka.schema-registry-url=${KAFKA_SCHEMA_REGISTRY_URL} kafka.cleanup=${KAFKA_CLEANUP:false} kafka.commit-interval-ms=${KAFKA_COMMIT_INTERVAL_MS} -redis.url=${REDIS_HOSTNAME} -redis.port=${REDIS_PORT} +beanstalk.hostname=${BEANSTALK_HOSTNAME} +beanstalk.port=${BEANSTALK_PORT} diff --git a/backend/webhook/publisher/src/test/java/co/airy/core/webhook/publisher/PublisherTest.java b/backend/webhook/publisher/src/test/java/co/airy/core/webhook/publisher/PublisherTest.java index b0fa3ef8bd..4119ddbb68 100644 --- a/backend/webhook/publisher/src/test/java/co/airy/core/webhook/publisher/PublisherTest.java +++ b/backend/webhook/publisher/src/test/java/co/airy/core/webhook/publisher/PublisherTest.java @@ -4,12 +4,12 @@ import co.airy.avro.communication.Message; import co.airy.avro.communication.Status; import co.airy.avro.communication.Webhook; -import co.airy.core.webhook.publisher.payload.QueueMessage; import co.airy.kafka.schema.application.ApplicationCommunicationMessages; import co.airy.kafka.schema.application.ApplicationCommunicationMetadata; import co.airy.kafka.schema.application.ApplicationCommunicationWebhooks; import co.airy.kafka.test.KafkaTestHelper; import co.airy.kafka.test.junit.SharedKafkaTestResource; +import co.airy.model.event.payload.Event; import co.airy.spring.core.AirySpringBootApplication; import org.apache.kafka.clients.producer.ProducerRecord; import org.junit.jupiter.api.AfterAll; @@ -20,7 +20,6 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -72,7 +71,7 @@ static void afterAll() throws Exception { Publisher publisher; @MockBean - private RedisQueue redisQueue; + private BeanstalkPublisher beanstalkPublisher; @BeforeEach void beforeEach() throws InterruptedException { @@ -94,8 +93,8 @@ void canPublishMessageToQueue() throws Exception { TimeUnit.SECONDS.sleep(2); - ArgumentCaptor batchCaptor = ArgumentCaptor.forClass(QueueMessage.class); - doNothing().when(redisQueue).publishMessage(Mockito.anyString(), batchCaptor.capture()); + ArgumentCaptor batchCaptor = ArgumentCaptor.forClass(Event.class); + doNothing().when(beanstalkPublisher).publishMessage(batchCaptor.capture()); List> messages = new ArrayList<>(); diff --git a/backend/webhook/publisher/src/test/resources/test.properties b/backend/webhook/publisher/src/test/resources/test.properties index 160ec0212b..0cb65c22c5 100644 --- a/backend/webhook/publisher/src/test/resources/test.properties +++ b/backend/webhook/publisher/src/test/resources/test.properties @@ -1,5 +1,5 @@ kafka.cleanup=true kafka.cache.max.bytes=0 kafka.commit-interval-ms=100 -redis.url=no -redis.port=10 \ No newline at end of file +beanstalk.hostname=no +beanstalk.port=10 diff --git a/backend/webhook/redis-worker/go.mod b/backend/webhook/redis-worker/go.mod deleted file mode 100644 index eb01405e93..0000000000 --- a/backend/webhook/redis-worker/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module redis-worker - -go 1.16 - -require ( - github.com/alicebob/miniredis/v2 v2.13.3 - github.com/go-redis/redis/v8 v8.2.2 -) diff --git a/backend/webhook/redis-worker/go.sum b/backend/webhook/redis-worker/go.sum deleted file mode 100644 index 7e5bc4c44b..0000000000 --- a/backend/webhook/redis-worker/go.sum +++ /dev/null @@ -1,88 +0,0 @@ -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.13.3 h1:kohgdtN58KW/r9ZDVmMJE3MrfbumwsDQStd0LPAGmmw= -github.com/alicebob/miniredis/v2 v2.13.3/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/go-redis/redis/v8 v8.2.2 h1:A1tQgdeVF23Ojc1TIRpVuVfOadUdIM0vFVURigoPEMM= -github.com/go-redis/redis/v8 v8.2.2/go.mod h1:ysgGY09J/QeDYbu3HikWEIPCwaeOkuNoTgKayTEaEOw= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= -github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= -github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= -go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E= -go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/webhook/redis-worker/pkg/scheduler/BUILD b/backend/webhook/redis-worker/pkg/scheduler/BUILD deleted file mode 100644 index 6386a30d1a..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/BUILD +++ /dev/null @@ -1,25 +0,0 @@ -load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -go_library( - name = "scheduler", - srcs = ["scheduler.go"], - importpath = "redis-worker/pkg/scheduler", - visibility = ["//visibility:public"], - deps = [ - "//backend/webhook/redis-worker/pkg/scheduler/consumer", - "//backend/webhook/redis-worker/pkg/scheduler/queue", - ], -) - -go_test( - name = "scheduler_test", - srcs = ["scheduler_test.go"], - embed = [":scheduler"], - deps = [ - "//backend/webhook/redis-worker/pkg/scheduler/queue", - "@com_github_alicebob_miniredis_v2//:miniredis", - ], -) - -check_pkg(name = "buildifier") diff --git a/backend/webhook/redis-worker/pkg/scheduler/consumer/BUILD b/backend/webhook/redis-worker/pkg/scheduler/consumer/BUILD deleted file mode 100644 index 0674e1702b..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/consumer/BUILD +++ /dev/null @@ -1,15 +0,0 @@ -load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "consumer", - srcs = ["consumer.go"], - importpath = "redis-worker/pkg/scheduler/consumer", - visibility = ["//visibility:public"], - deps = [ - "//backend/webhook/redis-worker/pkg/scheduler/queue", - "@com_github_go_redis_redis_v8//:redis", - ], -) - -check_pkg(name = "buildifier") diff --git a/backend/webhook/redis-worker/pkg/scheduler/consumer/consumer.go b/backend/webhook/redis-worker/pkg/scheduler/consumer/consumer.go deleted file mode 100644 index 4c7a0b09ae..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/consumer/consumer.go +++ /dev/null @@ -1,153 +0,0 @@ -package consumer - -import ( - "bytes" - "encoding/json" - "fmt" - "redis-worker/pkg/scheduler/queue" - - "log" - "net/http" - "time" - - "github.com/go-redis/redis/v8" -) - -type ConsumerError struct { - Err error - T time.Time -} - -type Task struct { - done chan bool - queue string - waitInS int32 - rdb *redis.Client - errors []ConsumerError -} - -type AiryMessage struct { - Endpoint string - Headers map[string]string - Body map[string]interface{} -} - -func StartConsumer(rdb *redis.Client, queue string) Task { - t := &Task{ - queue: queue, - waitInS: 2, - rdb: rdb, - done: make(chan bool), - errors: make([]ConsumerError, 0), - } - - go func() { - for { - t.Run() - } - }() - - log.Printf("consumer spawned [%s]", queue) - return *t -} - -func (t *Task) GetErrors() []ConsumerError { - return t.errors -} - -const endpointRequestTimeout = 60 - -func (t *Task) HandleMessage(message string) error { - data := &AiryMessage{} - - if err := json.Unmarshal([]byte(message), &data); err != nil { - return err - } - - jsonString, err := json.Marshal(data.Body) - - if err != nil { - return err - } - - req, _ := http.NewRequest("POST", data.Endpoint, bytes.NewBuffer(jsonString)) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("User-Agent", "Airy/1.0") - - for k, v := range data.Headers { - req.Header.Set(k, v) - } - - client := &http.Client{ - Timeout: endpointRequestTimeout * time.Second, - } - endpointResp, err := client.Do(req) - - if err != nil { - return err - } - - if endpointResp.StatusCode > 299 { - return fmt.Errorf("%v returned status code %v", data.Endpoint, endpointResp.StatusCode) - } - - return nil -} - -func (t *Task) logError(err error) { - log.Println(err) - t.errors = append(t.errors, ConsumerError{ - Err: err, - T: time.Now(), - }) -} - -func (t *Task) Run() { - retry := 0 - maxRetries := 10 - processingQueue := t.queue + "_processing" - - q := queue.NewQueue(t.rdb) - - result, err := q.Dequeue(processingQueue) - if err != nil { - t.logError(fmt.Errorf("Failed to dequeue \n%w", err)) - return - } - - if len(result) > 0 { - message := result[0] - if err = t.HandleMessage(message); err != nil { - t.logError(fmt.Errorf("error when processing message for queue %v\n%w", processingQueue, err)) - time.Sleep(time.Duration(t.waitInS) * time.Second) - t.waitInS = 2 * t.waitInS - return - - } - t.waitInS = 2 - q.DeleteFromQueue(processingQueue, message) - } - fmt.Println("nothing in processing") - - message, err := q.DequeueEnqueue(t.queue, processingQueue) - - if err != nil { - t.logError(fmt.Errorf("failed to receive messages %s", err)) - return - } - - for retry < maxRetries { - if err = t.HandleMessage(message); err != nil { - t.logError(fmt.Errorf("error when processing message for queue %v\n%w", t.queue, err)) - time.Sleep(time.Duration(t.waitInS) * time.Second) - t.waitInS = 2 * t.waitInS - retry = retry + 1 - fmt.Println("retry %i", retry) - - } else { - q.DeleteFromQueue(processingQueue, message) - t.waitInS = 2 - break - } - } -} diff --git a/backend/webhook/redis-worker/pkg/scheduler/queue/BUILD b/backend/webhook/redis-worker/pkg/scheduler/queue/BUILD deleted file mode 100644 index 0b4154f244..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/queue/BUILD +++ /dev/null @@ -1,12 +0,0 @@ -load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg") -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "queue", - srcs = ["queue.go"], - importpath = "redis-worker/pkg/scheduler/queue", - visibility = ["//visibility:public"], - deps = ["@com_github_go_redis_redis_v8//:redis"], -) - -check_pkg(name = "buildifier") diff --git a/backend/webhook/redis-worker/pkg/scheduler/queue/queue.go b/backend/webhook/redis-worker/pkg/scheduler/queue/queue.go deleted file mode 100644 index 1185e6c4f6..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/queue/queue.go +++ /dev/null @@ -1,63 +0,0 @@ -package queue - -import ( - "context" - "fmt" - "time" - - "github.com/go-redis/redis/v8" -) - -type Queue struct { - ctx context.Context - Rdb *redis.Client -} - -func NewQueue(Rdb *redis.Client) Queue { - q := &Queue{ - ctx: context.Background(), - Rdb: Rdb, - } - return *q -} - -func GetClient(hostname, port string) *redis.Client { - return redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("%s:%s", hostname, port), - Password: "", // no password set - DB: 0, // use default DB - }) -} - -func (q *Queue) GetAllQueues() ([]string, error) { - var cursor uint64 - var keys []string - for { - var err error - keys, cursor, err = q.Rdb.Scan(q.ctx, cursor, "*", 10).Result() - if err != nil { - return nil, err - } - if cursor == 0 { - break - } - } - - return keys, nil -} - -func (q *Queue) DequeueEnqueue(queue, processingQueue string) (string, error) { - return q.Rdb.BRPopLPush(q.ctx, queue, processingQueue, 130*time.Second).Result() -} - -func (q *Queue) Dequeue(queue string) ([]string, error) { - return q.Rdb.LRange(q.ctx, queue, 0, 0).Result() -} - -func (q *Queue) DeleteFromQueue(queue, message string) { - q.Rdb.LRem(q.ctx, queue, 1, message) -} - -func (q *Queue) Enqueue(queue, message string) *redis.IntCmd { - return q.Rdb.RPush(q.ctx, queue, message) -} diff --git a/backend/webhook/redis-worker/pkg/scheduler/scheduler.go b/backend/webhook/redis-worker/pkg/scheduler/scheduler.go deleted file mode 100644 index d0e36254fd..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/scheduler.go +++ /dev/null @@ -1,80 +0,0 @@ -package scheduler - -import ( - "fmt" - "redis-worker/pkg/scheduler/queue" - "regexp" - - "log" - "redis-worker/pkg/scheduler/consumer" - "time" -) - -type Task struct { - ticker *time.Ticker - queue queue.Queue - consumers map[string]consumer.Task -} - -func Start(hostname, port string) *Task { - t := &Task{ - ticker: time.NewTicker(time.Minute), - queue: queue.NewQueue(queue.GetClient(hostname, port)), - consumers: make(map[string]consumer.Task), - } - - go func() { - t.updateConsumers(t.queue) - for range t.ticker.C { - t.updateConsumers(t.queue) - } - }() - - log.Println("queue consumer scheduler started") - return t -} - -type ConsumerStatus struct { - Errors []consumer.ConsumerError - Queue string -} - -func (t *Task) GetStatuses() []ConsumerStatus { - errors := make([]ConsumerStatus, len(t.consumers)) - - for k, v := range t.consumers { - if err := v.GetErrors(); err != nil { - errors = append(errors, ConsumerStatus{ - Errors: err, - Queue: k, - }) - } - } - - return errors -} - -func (t *Task) updateConsumers(q queue.Queue) { - queues, err := q.GetAllQueues() - - if err != nil { - log.Println("failed to fetch queues", err) - } - - for _, it := range queues { - fmt.Println(it) - if _, ok := t.consumers[it]; !ok && !isProcessingQueue(it) { - t.consumers[it] = consumer.StartConsumer(t.queue.Rdb, it) - } - } -} - -func isProcessingQueue(queue string) bool { - matched, err := regexp.MatchString(`.*_processing`, queue) - - if err != nil { - panic(err) - } - - return matched -} diff --git a/backend/webhook/redis-worker/pkg/scheduler/scheduler_test.go b/backend/webhook/redis-worker/pkg/scheduler/scheduler_test.go deleted file mode 100644 index 7b25b49cf2..0000000000 --- a/backend/webhook/redis-worker/pkg/scheduler/scheduler_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package scheduler - -import ( - "redis-worker/pkg/scheduler/queue" - "strings" - - "github.com/alicebob/miniredis/v2" - - "testing" -) - -func mockRedis() *miniredis.Miniredis { - s, err := miniredis.Run() - - if err != nil { - panic(err) - } - - return s -} - -func TestScheduler(t *testing.T) { - redisServer := setup() - defer teardown(redisServer) - - addr := strings.Split(redisServer.Addr(), ":") - schedulerTask := Start(addr[0], addr[1]) - - queues, _ := schedulerTask.queue.GetAllQueues() - q := queue.NewQueue(schedulerTask.queue.Rdb) - - if len(queues) != 0 { - t.Error("expected empty queue") - } - - testMessage := "{\"endpoint\":\"https://airy-platform-status.herokuapp.com/receive-message\",\"headers\":{\"X-Custom-Header\":\"custom-code-for-header\"},\"body\":{\"conversation_id\":\"2477cf76-633f-4343-bb22-49983b735131\",\"id\":\"bc685c4e-211f-4ef5-adf7-636ffe78279d\",\"text\":\"All work and no play makes Jack a dull boy\",\"sender\":{\"id\":\"433e835e-76d3-4351-82e7-1c8363766639\"},\"sent_at\":\"2020-09-21T18:50:23.155Z\",\"source\":\"FACEBOOK\",\"postback\":{}}}" - - q.Enqueue("test_queue", testMessage) - q.Enqueue("test_queue_processing", testMessage) - - schedulerTask.updateConsumers(q) - - queues, _ = q.GetAllQueues() - - if len(queues) != 2 { - t.Error("expected there to be two queues") - } - - if len(schedulerTask.consumers) != 1 { - t.Error("expected scheduler to spawn one consumer task") - } -} - -func setup() *miniredis.Miniredis { - return mockRedis() -} - -func teardown(redisServer *miniredis.Miniredis) { - redisServer.Close() -} diff --git a/cli/pkg/cmd/config/config.go b/cli/pkg/cmd/config/config.go index 2b18eb71f4..6b45bb65c5 100644 --- a/cli/pkg/cmd/config/config.go +++ b/cli/pkg/cmd/config/config.go @@ -37,9 +37,11 @@ func applyConfig(cmd *cobra.Command, args []string) { console.Exit("could not find an installation of Airy Core. Get started here https://airy.co/docs/core/getting-started/installation/introduction") } - if len(conf.Security) != 0 { - applyErr := kube.ApplyConfigMap("security", conf.Kubernetes.Namespace, conf.Security, map[string]string{}, clientset) + secData := conf.Security.getData() + if len(secData) != 0 { + applyErr := kube.ApplyConfigMap("security", conf.Kubernetes.Namespace, secData, map[string]string{}, clientset) if applyErr != nil { + // TODO should we error here? fmt.Printf("unable to apply configuration for \"security\"\n Error:\n %v\n", applyErr) } else { fmt.Printf("applied configuration for \"security\"\n") diff --git a/cli/pkg/cmd/config/parser.go b/cli/pkg/cmd/config/parser.go index bc58b70b34..bd80f92450 100644 --- a/cli/pkg/cmd/config/parser.go +++ b/cli/pkg/cmd/config/parser.go @@ -17,10 +17,39 @@ type componentsConf map[string]map[string]string type airyConf struct { Kubernetes kubernetesConf - Security map[string]string + Security securityConf Components map[string]componentsConf } +type securityConf struct { + SystemToken string `yaml:"systemToken"` + AllowedOrigins string `yaml:"allowedOrigins"` + JwtSecret string `yaml:"jwtSecret"` + Oidc map[string]string `yaml:"oidc"` +} + +func (s securityConf) getData() map[string]string { + m := make(map[string]string, len(s.Oidc)) + + if s.SystemToken != "" { + m["systemToken"] = s.SystemToken + } + if s.AllowedOrigins != "" { + m["allowedOrigins"] = s.AllowedOrigins + } + if s.JwtSecret != "" { + m["jwtSecret"] = s.JwtSecret + } + + for key, value := range s.Oidc { + if value != "" { + m["oidc." + key] = value + } + } + + return m +} + func parseConf(configFile string) (airyConf, error) { data, err := ioutil.ReadFile(configFile) if err != nil { diff --git a/cli/pkg/cmd/create/helm.go b/cli/pkg/cmd/create/helm.go index 1196e5a0b3..f3b8ff911f 100644 --- a/cli/pkg/cmd/create/helm.go +++ b/cli/pkg/cmd/create/helm.go @@ -151,16 +151,13 @@ func (h *Helm) runHelm(args []string) error { for event := range ch { switch event.Type { case watch.Error: - h.cleanupJob() return fmt.Errorf("helm run failed with error %v", event.Object) case watch.Added: case watch.Modified: job, _ := event.Object.(*batchv1.Job) if job.Status.Succeeded == 1 { - h.cleanupJob() return nil } else if job.Status.Failed == 1 { - h.cleanupJob() return fmt.Errorf("helm run failed with error %v", event.Object) } } diff --git a/cli/pkg/workspace/template/airy.yaml b/cli/pkg/workspace/template/airy.yaml index f2cbaf3fcf..67a9a0c061 100644 --- a/cli/pkg/workspace/template/airy.yaml +++ b/cli/pkg/workspace/template/airy.yaml @@ -2,3 +2,5 @@ kubernetes: containerRegistry: ghcr.io/airyhq namespace: default ngrokEnabled: false +security: + allowedOrigins: "*" diff --git a/docs/docs/api/authentication.md b/docs/docs/api/authentication.md index 77c017af20..4e3ef13245 100644 --- a/docs/docs/api/authentication.md +++ b/docs/docs/api/authentication.md @@ -3,7 +3,67 @@ title: Authentication sidebar_label: Authentication --- -By default, authentication is disabled. To protect your API endpoints you need to set the `security.systemToken` -[cluster configuration](getting-started/installation/configuration.md) value in your `airy.yaml` and apply it. +By default, authentication is disabled. There are two ways of protecting resources from unauthorized access. +You can set `security.systemToken` in the [cluster configuration](getting-started/installation/configuration.md) to a secure secret value in your `airy.yaml` and apply it. Once that is done you authenticate by setting the token as a value on the [Bearer Authorization header](https://tools.ietf.org/html/rfc6750#section-2.1) when making requests. -Once that is done you authenticate by setting the token as a value on the [Bearer Authorization header](https://tools.ietf.org/html/rfc6750#section-2.1) when making requests. +This is fine for API only access, but it means that UI clients will no longer work since api keys are not meant for web authentication. Therefore Airy Core also supports [Open Id Connect (OIDC)](https://openid.net/connect/) to allow your agents to authenticate via an external provider. If you configure this in addition to the system token then both types of authentication will work when requesting APIs. If you only configure OIDC authentication then regular + +## Configuring OIDC + +OIDC is an authentication layer on top of the popular OAuth 2.0 authorization framework. With the added information of +"who" made a request (authentication) Airy Core is able to offer audit and workflow features. + +### GitHub + +The easiest way to configure our OIDC is by using our GitHub preset. We will explain how to configure any OIDC provider further below. To get started you first need a GitHub OAuth app. You can follow [this guide](https://docs.github.com/en/developers/apps/creating-an-oauth-app) and as an Authorization Callback URL you need to put your Airy host with the +path `/login/oauth2/code/github`. So if your Airy Core instance is hosted at `https://airy.example.org` the Callback URL +would be `https://airy.example.org/login/oauth2/code/github` + +:::note + +You can always get your Airy host by running the CLI command `airy api endpoint` + +::: + +Now you can add your GitHub app configuration to the security section in your `airy.yaml`: + +```yaml +security: + oidc: + allowedEmailPatterns: "*@airy.co,grace@example.org" + provider: "github" + clientId: "github oauth client id" + clientSecret: "github oauth client secret" +``` + +Since you don't want just any GitHub user to be able to access your Airy Core instance you are also required to add +a list of emails or email wildcard patterns to define which users are authorized for use. + +Once this configuration is applied all new requests to the Airy Core API will be redirected to the Github +provider for login. If that login is successful the Airy Core platform will set a http only authentication cookie +that will authenticate the current user session. + +### Any open id provider + +To configure any open id connect provider for authentication we expose the following configuration values: + +```yaml +security: + oidc: + allowedEmailPatterns: "grace@example.org" + provider: "my-provider" + clientId: "client-id" + clientSecret: "client-secret" + scope: "openid,email" # comma separated list of scopes. Must include "openid" + clientAuthenticationMethod: "basic" # One of [basic,post,none] + authorizationGrantType: "authorization_code" # One of [authorization_code,implicit,refresh_token,client_credentials,password] + authorizationUri: "https://my-provider.org/oauth2/v1/authorize" + tokenUri: "https://my-provider.org/oauth2/v1/token" + userInfoUri: "https://my-provider.org/oauth2/v1/userinfo" + userInfoAuthenticationMethod: "form" # One of [header,form,query] + userNameAttributeName: "id" # Field name within the OIDC identity token that uniquely identifies the user + issuerUri: "https://my-provider.org/jwt-issuer" + jwkSetUri: "https://my-provider.org/oauth2/v1/certs" +``` + +The redirect Uri to configure with your provider will always be of the form `{airy core host}/login/oauth2/code/{provider name}`. diff --git a/docs/docs/api/endpoints/chatplugin.md b/docs/docs/api/endpoints/chatplugin.md index ecefde4b54..5277812e22 100644 --- a/docs/docs/api/endpoints/chatplugin.md +++ b/docs/docs/api/endpoints/chatplugin.md @@ -3,7 +3,7 @@ title: Chat Plugin sidebar_label: Chat Plugin --- -Refer to our [Chat Plugin introduction](sources/chatplugin/overview.md) for +Refer to our [Chat Plugin overview](sources/chatplugin/overview.md) document for more information. The HTTP api adheres to standards laid out in the [core @@ -16,8 +16,9 @@ API](/api/introduction#authentication). The request returns an authentication token that needs to be included in the WebSocket connection handshake. -You can either pass the `channel_id` for a new conversation or a `resume_token` that was obtained in a -previous conversation using the [resume endpoint](#get-a-resume-token). +You can either pass the `channel_id` for a new conversation or a `resume_token` +that was obtained in a previous conversation using the [resume +endpoint](#get-a-resume-token). **Sample request** @@ -75,8 +76,9 @@ endpoint](#authenticating-web-users) as an `Authorization` header. } ``` -You can also obtain a resume token on behalf of the user. To do so you need to call this endpoint with the -system API token set on the `Authorization` header and with the channel and conversation id. +You can also obtain a resume token on behalf of the user. To do so you need to +call this endpoint with the system API token set on the `Authorization` header +and with the channel and conversation id. **Sample request** @@ -89,8 +91,8 @@ system API token set on the `Authorization` header and with the channel and conv #### Send message -You must set the `token` obtained on the [authorization endpoint](#authenticating-web-users) as an `Authorization` -header. +You must set the `token` obtained on the [authorization +endpoint](#authenticating-web-users) as an `Authorization` header. `POST /chatplugin.send` diff --git a/docs/docs/api/endpoints/google-messages-send.mdx b/docs/docs/api/endpoints/google-messages-send.mdx index cd306095dd..1ddfa30ca7 100644 --- a/docs/docs/api/endpoints/google-messages-send.mdx +++ b/docs/docs/api/endpoints/google-messages-send.mdx @@ -11,13 +11,11 @@ Whatever is put on the `message` field will be forwarded "as-is" to the source's ```json5 { - "conversation_id": "a688d36c-a85e-44af-bc02-4248c2c97622", - "message": { - "text": "Hello World Agent!", - "representative": { - "displayName": "Hello World from Agent", - "avatarImage": "REPRESENTATIVE_AVATAR_URL", - "representativeType": "HUMAN", + conversation_id: 'a688d36c-a85e-44af-bc02-4248c2c97622', + message: { + text: 'Hello!', + representative: { + representativeType: 'HUMAN', }, }, } @@ -27,17 +25,21 @@ Whatever is put on the `message` field will be forwarded "as-is" to the source's ```json5 { - "id": "{UUID}", - "content": "{\"text\":\"Hello\"}", - "state": "pending|failed|delivered", - "from_contact": true, + "id": '{UUID}', + "content": { + "text": 'Hello!', + "representative": { + "representativeType": 'HUMAN', + }, + }, + "delivery_state": 'pending|failed|delivered', + "from_contact": 'true|false', // See glossary - "sent_at": "{string}", + "sent_at": '{string}', //'yyyy-MM-dd'T'HH:mm:ss.SSSZ' date in UTC form, to be localized by clients - "source": "{String}", - // one of the possible sources + "source": 'google', "metadata": { - "sentFrom": "iPhone", + "sentFrom": 'iPhone', }, // metadata object of the message } diff --git a/docs/docs/api/endpoints/messages.md b/docs/docs/api/endpoints/messages.md index 340adc2eca..4396634c55 100644 --- a/docs/docs/api/endpoints/messages.md +++ b/docs/docs/api/endpoints/messages.md @@ -3,15 +3,15 @@ title: Messages sidebar_label: Messages --- -Refer to our [messages](getting-started/glossary.md#message) definition -for more information. +Refer to our [message](getting-started/glossary.md#message) definition for more +information. ## List `POST /messages.list` -This is a [paginated](#pagination) endpoint. Messages are sorted from oldest to -latest. +This is a [paginated](api/endpoints/introduction.md#pagination) endpoint. Messages +are sorted from oldest to latest. **Sample request** diff --git a/docs/docs/api/endpoints/metadata.md b/docs/docs/api/endpoints/metadata.md index 6a7e78d53a..3c9fe62a91 100644 --- a/docs/docs/api/endpoints/metadata.md +++ b/docs/docs/api/endpoints/metadata.md @@ -3,12 +3,14 @@ title: Metadata sidebar_label: Metadata --- -Have a look at our [metadata design](concepts/metadata.md) for more information. +Refer to our [metadata design](concepts/metadata.md) document for more +information. ## Upsert -This endpoint takes a `data` object and upserts the metadata for the `id`. The data may only contain -values of type string or object values (i.e. no lists or numbers). +This endpoint takes a `data` object and upserts the metadata for the `id`. The +data may only contain values of type string or object values (i.e. no lists or +numbers). `POST /metadata.upsert` diff --git a/docs/docs/api/endpoints/tags.md b/docs/docs/api/endpoints/tags.md index 82251e761e..7d2244b5fb 100644 --- a/docs/docs/api/endpoints/tags.md +++ b/docs/docs/api/endpoints/tags.md @@ -3,7 +3,7 @@ title: Tags sidebar_label: Tags --- -Please refer to our [tag](getting-started/glossary.md#tag) definition for more +Refer to our [tag](getting-started/glossary.md#tag) definition for more information. ## Create @@ -19,7 +19,8 @@ information. } ``` -If the tag is successfully created, the request returns status code `201` (created) with the tag ID in the response body. +If the tag is successfully created, the request returns status code `201` +(created) with the tag ID in the response body. **Sample response** @@ -45,8 +46,6 @@ If the tag is successfully created, the request returns status code `201` (creat } ``` -If action is successful, the request returns status code `200`. - **Empty response (204)** ## Delete @@ -61,8 +60,6 @@ If action is successful, the request returns status code `200`. } ``` -If action is successful, returns HTTP status `200`. - **Empty response (204)** ## List @@ -77,7 +74,7 @@ If action is successful, returns HTTP status `200`. { "id": "TAG-ID", "name": "name of the tag", - "color": "RED" + "color": "tag-red" } ] } diff --git a/docs/docs/api/websocket.md b/docs/docs/api/websocket.md index 9aa3fc9afb..ffe2080688 100644 --- a/docs/docs/api/websocket.md +++ b/docs/docs/api/websocket.md @@ -18,8 +18,9 @@ protocol endpoint at `/ws.communication`. ## Event Payloads -All event updates are sent to the `/events` queue as JSON encoded payloads. The `type` -field informs the client of the kind of update that is encoded in the payload. +All event updates are sent to the `/events` queue as JSON encoded payloads. The +`type` field informs the client of the kind of update that is encoded in the +payload. ### Message @@ -81,3 +82,17 @@ field informs the client of the kind of update that is encoded in the payload. } } ``` + +### Tag + +```json5 +{ + "type": "tag", + + "payload": { + "id": "{UUID}", + "name": "flag", + "color": "tag-red" + } +} +``` diff --git a/docs/docs/changelog.md b/docs/docs/changelog.md index 901908b451..8a81ffaff0 100644 --- a/docs/docs/changelog.md +++ b/docs/docs/changelog.md @@ -3,6 +3,57 @@ title: Changelog sidebar_label: 📝 Changelog --- +## 0.20.0 + +#### Changes + +- Bump @types/react from 16.9.34 to 17.0.4 [[#1658](https://github.com/airyhq/airy/pull/1658)] + +#### 🚀 Features + +- [[#1518](https://github.com/airyhq/airy/issues/1518)] Add OIDC authentication backend [[#1623](https://github.com/airyhq/airy/pull/1623)] +- [[#1505](https://github.com/airyhq/airy/issues/1505)] Rewrite Webhook queue with Beanstalkd [[#1536](https://github.com/airyhq/airy/pull/1536)] +- [[#1687](https://github.com/airyhq/airy/issues/1687)] Kafka Prometheus exporter error on… [[#1688](https://github.com/airyhq/airy/pull/1688)] +- [[#1615](https://github.com/airyhq/airy/issues/1615)] Expose tag events via websocket [[#1624](https://github.com/airyhq/airy/pull/1624)] +- [[#1495](https://github.com/airyhq/airy/issues/1495)] Add kafka Prometheus exporter [[#1668](https://github.com/airyhq/airy/pull/1668)] +- [[#1525](https://github.com/airyhq/airy/issues/1525)] Update quick filter [[#1660](https://github.com/airyhq/airy/pull/1660)] + +#### 🐛 Bug Fixes + +- [[#1698](https://github.com/airyhq/airy/issues/1698)] Webhook config error [[#1699](https://github.com/airyhq/airy/pull/1699)] +- [[#1689](https://github.com/airyhq/airy/issues/1689)] Bug: Conversation Counter: Optimize Filter Use [[#1697](https://github.com/airyhq/airy/pull/1697)] +- [[#1665](https://github.com/airyhq/airy/issues/1665)] Fix chatplugin reconnection problem [[#1682](https://github.com/airyhq/airy/pull/1682)] +- [[#1646](https://github.com/airyhq/airy/issues/1646)] fix avatar images styling [[#1680](https://github.com/airyhq/airy/pull/1680)] +- [[#1652](https://github.com/airyhq/airy/issues/1652)] Fix rendering messages with render library [[#1675](https://github.com/airyhq/airy/pull/1675)] +- [[#1674](https://github.com/airyhq/airy/issues/1674)] Chatplugin customize problems [[#1678](https://github.com/airyhq/airy/pull/1678)] +- [[#1666](https://github.com/airyhq/airy/issues/1666)] Fix chatplugin cors config [[#1667](https://github.com/airyhq/airy/pull/1667)] + +#### 📚 Documentation + +- [[#1676](https://github.com/airyhq/airy/issues/1676)] fix sending messages to google source [[#1677](https://github.com/airyhq/airy/pull/1677)] +- [[#1661](https://github.com/airyhq/airy/issues/1661)] Fix token name in docs [[#1664](https://github.com/airyhq/airy/pull/1664)] + +#### 🧰 Maintenance + +- Bump @babel/preset-env from 7.14.0 to 7.14.1 [[#1705](https://github.com/airyhq/airy/pull/1705)] +- Bump webpack from 5.36.1 to 5.36.2 [[#1692](https://github.com/airyhq/airy/pull/1692)] +- Bump @babel/core from 7.13.16 to 7.14.0 [[#1685](https://github.com/airyhq/airy/pull/1685)] +- Bump @babel/preset-env from 7.13.15 to 7.14.0 [[#1684](https://github.com/airyhq/airy/pull/1684)] +- Bump webpack from 5.36.0 to 5.36.1 [[#1670](https://github.com/airyhq/airy/pull/1670)] +- Bump @bazel/typescript from 3.4.1 to 3.4.2 [[#1671](https://github.com/airyhq/airy/pull/1671)] +- Bump core-js from 3.11.0 to 3.11.1 [[#1672](https://github.com/airyhq/airy/pull/1672)] +- Bump sass from 1.32.11 to 1.32.12 [[#1673](https://github.com/airyhq/airy/pull/1673)] +- Bump webpack from 5.35.1 to 5.36.0 [[#1663](https://github.com/airyhq/airy/pull/1663)] +- Bump @types/node from 15.0.0 to 15.0.1 [[#1662](https://github.com/airyhq/airy/pull/1662)] + +#### Airy CLI + +You can download the Airy CLI for your operating system from the following links: + +[MacOS](https://airy-core-binaries.s3.amazonaws.com/0.19.1/darwin/amd64/airy) +[Linux](https://airy-core-binaries.s3.amazonaws.com/0.19.1/linux/amd64/airy) +[Windows](https://airy-core-binaries.s3.amazonaws.com/0.19.1/windows/amd64/airy.exe) + ## 0.19.0 #### Changes diff --git a/docs/docs/getting-started/installation/configuration.md b/docs/docs/getting-started/installation/configuration.md index 3525c2edfc..5de7bf1972 100644 --- a/docs/docs/getting-started/installation/configuration.md +++ b/docs/docs/getting-started/installation/configuration.md @@ -57,8 +57,10 @@ cluster and Redis. ### Security -- `token` set to a long secure secret to use for machine [API authentication](api/authentication.md) (default: random generated) -- `allowedOrigins` your sites origin to prevent CORS-based attacks (default: "\*") +- `systemToken` set to a long secure secret to use for machine [API authentication](api/authentication.md) +- `allowedOrigins` your site's origin to prevent CORS-based attacks (default: `"*"`) +- `oidc` a map of values that when set enable and define [OIDC authentication](api/authentication.md#configuring-oidc) +- `jwtSecret` used to create jwt http sessions derived from oidc authentication (default: randomized on installation) ### Components @@ -74,6 +76,8 @@ cluster and Redis. - `integration` - `webhook` - `name` set this to the name of your webhook integration + - `maxBackoff` set this to the maximum number of seconds the webhook should + wait between retries with exponential backoff - `media` - `resolver` - `s3Key` set this to your AWS S3 access key id diff --git a/docs/docs/guides/operations.md b/docs/docs/guides/operations.md index b3ef55fb38..25a1781f99 100644 --- a/docs/docs/guides/operations.md +++ b/docs/docs/guides/operations.md @@ -70,7 +70,10 @@ Access Grafana under `/grafana` and login with the If the `defaultDashboardsEnabled` is set to true you can find the default Kubernetes dashboards under `/grafana/dashboards` -For the spring apps we recommend to import this (dashboard)[https://grafana.com/grafana/dashboards/12464]. +For the spring apps we recommend to import this +(dashboard)[https://grafana.com/grafana/dashboards/12464]. + +And for Kafka this (dashboard)[https://grafana.com/grafana/dashboards/7589]. ### Monitoring with alerts diff --git a/docs/docs/sources/google.md b/docs/docs/sources/google.md index c432f85826..8c8750db71 100644 --- a/docs/docs/sources/google.md +++ b/docs/docs/sources/google.md @@ -92,6 +92,6 @@ import ConnectGoogle from '../api/endpoints/connect-google.mdx' After connecting the source to your instance, you will be able to send messages through the [Messages endpoint](/api/endpoints/messages#send). -import InboxMessages from './inbox-messages.mdx' +import GoogleMessagesSend from '../api/endpoints/google-messages-send.mdx' - + diff --git a/frontend/chat-plugin/src/App.tsx b/frontend/chat-plugin/src/App.tsx index b88ea86e79..c125e3a9a7 100644 --- a/frontend/chat-plugin/src/App.tsx +++ b/frontend/chat-plugin/src/App.tsx @@ -17,22 +17,10 @@ export default class App extends Component { const queryParams = new URLSearchParams(window.location.search); const channelId = queryParams.get('channel_id'); - const customStyle = { - background: 'transparent', - ...(config?.primaryColor && { - '--color-airy-blue': config?.primaryColor, - }), - ...(config?.accentColor && { - '--color-airy-accent': config?.accentColor, - '--color-airy-blue-hover': config?.accentColor, - '--color-airy-blue-pressed': config?.accentColor, - }), - }; - const apiHost: string = window.airy ? window.airy.host : process.env.API_HOST; return ( -
+
{channelId ? ( { return ( diff --git a/frontend/chat-plugin/src/components/chat/index.module.scss b/frontend/chat-plugin/src/components/chat/index.module.scss index f3dbbe8873..f45ce762eb 100644 --- a/frontend/chat-plugin/src/components/chat/index.module.scss +++ b/frontend/chat-plugin/src/components/chat/index.module.scss @@ -1,3 +1,5 @@ +@import 'assets/scss/fonts.scss'; + .main { height: 100%; padding: 0; @@ -84,7 +86,7 @@ position: relative; } -.disconnectedOverlay { +.modalOverlay { position: absolute; top: 0; left: 0; @@ -97,6 +99,21 @@ color: white; } +.modalCloseChat { + @include font-m; + width: 100%; + margin: 16px; + padding: 32px 0 38px 0; + background: white; + border-radius: 8px; + p { + text-align: center; + font-size: 18px; + margin: 0 0 8px 0; + color: gray; + } +} + .buttonWrapper { height: 30px; display: flex; @@ -114,7 +131,7 @@ height: 40px; background-color: white; color: var(--color-airy-blue); - border-radius: 4px; + border-radius: 8px; border: 1px solid var(--color-airy-blue); cursor: pointer; padding: 8px 10px; @@ -130,7 +147,7 @@ height: 40px; background-color: var(--color-airy-blue); color: white; - border-radius: 4px; + border-radius: 8px; border: none; cursor: pointer; padding: 8px 10px; diff --git a/frontend/chat-plugin/src/components/chat/index.tsx b/frontend/chat-plugin/src/components/chat/index.tsx index 5ab67c02d0..8e91cbc561 100644 --- a/frontend/chat-plugin/src/components/chat/index.tsx +++ b/frontend/chat-plugin/src/components/chat/index.tsx @@ -24,7 +24,6 @@ import {MessageInfoWrapper} from 'render/components/MessageInfoWrapper'; const camelcaseKeys = require('camelcase-keys'); import {cyBubble, cyChatPluginMessageList, cyChatPluginEndChatModalButton} from 'chat-plugin-handles'; import {getResumeTokenFromStorage, resetStorage} from '../../storage'; -import {ModalDialogue} from '../../components/modal'; import NewConversation from '../../components/newConversation'; import {setApiHost, start} from '../../api'; @@ -49,6 +48,18 @@ const Chat = (props: Props) => { defaultWelcomeMessage.content = config.welcomeMessage; } + const customStyle = { + background: 'transparent', + ...(config?.primaryColor && { + '--color-airy-blue': config?.primaryColor, + }), + ...(config?.accentColor && { + '--color-airy-accent': config?.accentColor, + '--color-airy-blue-hover': config?.accentColor, + '--color-airy-blue-pressed': config?.accentColor, + }), + }; + const chatHiddenInitialState = (): boolean => { if (config.showMode === true) return false; if (getResumeTokenFromStorage(props.channelId)) return true; @@ -205,7 +216,7 @@ const Chat = (props: Props) => { }; return ( -
+
{!isChatHidden && (
{
{connectionState === ConnectionState.Disconnected && ( -
Reconnecting...
+
Reconnecting...
+ )} + {showModal && ( +
+
+

Are you sure you want to end this chat?

+
+ + +
+
+
)}
)} - {showModal && ( - - <> -
- - -
- -
- )}
); }; diff --git a/frontend/chat-plugin/src/websocket/index.ts b/frontend/chat-plugin/src/websocket/index.ts index 09d3e97ed9..ef23337d07 100644 --- a/frontend/chat-plugin/src/websocket/index.ts +++ b/frontend/chat-plugin/src/websocket/index.ts @@ -100,7 +100,6 @@ class WebSocket { reconnect = () => { if (!this.isConnected) { - this.reconnectTimeout = window.setTimeout(this.reconnect, 5000); this.start(); } }; diff --git a/frontend/ui/src/actions/conversations/index.ts b/frontend/ui/src/actions/conversations/index.ts index 6ef760da13..11cd89de3e 100644 --- a/frontend/ui/src/actions/conversations/index.ts +++ b/frontend/ui/src/actions/conversations/index.ts @@ -4,7 +4,7 @@ import {Conversation, Pagination} from 'model'; import {PaginatedResponse} from 'httpclient'; import {HttpClientInstance} from '../../InitializeAiryApi'; import {StateModel} from '../../reducers'; -import {mergeMetadataAction, setMetadataAction} from '../metadata'; +import {setMetadataAction} from '../metadata'; const CONVERSATION_LOADING = '@@conversation/LOADING'; const CONVERSATIONS_LOADING = '@@conversations/LOADING'; @@ -114,7 +114,7 @@ export const conversationState = (conversationId: string, state: string) => (dis export const addTagToConversation = (conversationId: string, tagId: string) => (dispatch: Dispatch) => { HttpClientInstance.tagConversation({conversationId, tagId}).then(() => dispatch( - mergeMetadataAction({ + setMetadataAction({ subject: 'conversation', identifier: conversationId, metadata: { diff --git a/frontend/ui/src/actions/conversationsFilter/index.ts b/frontend/ui/src/actions/conversationsFilter/index.ts index caca7492de..c244b7cd1e 100644 --- a/frontend/ui/src/actions/conversationsFilter/index.ts +++ b/frontend/ui/src/actions/conversationsFilter/index.ts @@ -110,5 +110,10 @@ const filterToLuceneSyntax = (filter: ConversationFilter): string | null => { if (filter.bySources && filter.bySources.length > 0) { filterQuery.push('source:(' + filter.bySources.join(' OR ') + ')'); } + if (filter.isStateOpen === true) { + filterQuery.push('id:* AND NOT metadata.state:CLOSED'); + } else if (filter.isStateOpen !== undefined) { + filterQuery.push('metadata.state:CLOSED'); + } return !filterQuery.length ? null : filterQuery.join(' AND '); }; diff --git a/frontend/ui/src/actions/metadata/index.ts b/frontend/ui/src/actions/metadata/index.ts index f221db886e..d8ad43177d 100644 --- a/frontend/ui/src/actions/metadata/index.ts +++ b/frontend/ui/src/actions/metadata/index.ts @@ -1,15 +1,9 @@ import _typesafe, {createAction} from 'typesafe-actions'; import {MetadataEvent} from 'model'; -const MERGE_METADATA = '@@metadata/MERGE_METADATA'; const SET_METADATA = '@@metadata/SET_METADATA'; export const setMetadataAction = createAction( SET_METADATA, (metadataEvent: MetadataEvent) => metadataEvent )(); - -export const mergeMetadataAction = createAction( - MERGE_METADATA, - (metadataEvent: MetadataEvent) => metadataEvent -)(); diff --git a/frontend/ui/src/actions/tags/index.tsx b/frontend/ui/src/actions/tags/index.tsx index 23c0ce2948..5eef58fcff 100644 --- a/frontend/ui/src/actions/tags/index.tsx +++ b/frontend/ui/src/actions/tags/index.tsx @@ -7,23 +7,18 @@ import {HttpClientInstance} from '../../InitializeAiryApi'; const UPSERT_TAG = 'UPSERT_TAG'; const DELETE_TAG = 'DELETE_TAG'; -const EDIT_TAG = 'EDIT_TAG'; const ERROR_TAG = 'ERROR_TAG'; const ADD_TAGS_TO_STORE = 'ADD_TAGS_TO_STORE'; -const SET_TAG_FILTER = 'SET_TAG_FILTER'; export const fetchTagAction = createAction(ADD_TAGS_TO_STORE, (tags: Tag[]) => tags)(); -export const addTagAction = createAction(UPSERT_TAG, (tag: Tag) => tag)(); -export const editTagAction = createAction(EDIT_TAG, (tag: Tag) => tag)(); +export const upsertTagAction = createAction(UPSERT_TAG, (tag: Tag) => tag)(); export const deleteTagAction = createAction(DELETE_TAG, (id: string) => id)(); -export const filterTagAction = createAction(SET_TAG_FILTER, (filter: string) => filter)(); export const errorTagAction = createAction(ERROR_TAG, (status: string) => status)(); export function listTags() { - return function (dispatch: Dispatch) { - return HttpClientInstance.listTags().then((response: Tag[]) => { - dispatch(fetchTagAction(response)); - }); + return async function (dispatch: Dispatch) { + const response = await HttpClientInstance.listTags(); + dispatch(fetchTagAction(response)); }; } @@ -31,7 +26,7 @@ export function createTag(requestPayload: CreateTagRequestPayload) { return async (dispatch: Dispatch) => { return HttpClientInstance.createTag(requestPayload) .then((response: Tag) => { - dispatch(addTagAction(response)); + dispatch(upsertTagAction(response)); return Promise.resolve(response); }) .catch((error: string) => { @@ -43,7 +38,7 @@ export function createTag(requestPayload: CreateTagRequestPayload) { export function updateTag(tag: Tag) { return function (dispatch: Dispatch) { - HttpClientInstance.updateTag(tag).then(() => dispatch(editTagAction(tag))); + HttpClientInstance.updateTag(tag).then(() => dispatch(upsertTagAction(tag))); }; } @@ -55,12 +50,6 @@ export function deleteTag(id: string) { }; } -export function filterTags(filter: string) { - return function (dispatch: Dispatch) { - dispatch(filterTagAction(filter)); - }; -} - export function errorTag(status: string) { return function (dispatch: Dispatch) { dispatch(errorTagAction(status)); diff --git a/frontend/ui/src/components/AiryWebsocket/index.tsx b/frontend/ui/src/components/AiryWebsocket/index.tsx index 5dd73ea2db..d4f890d767 100644 --- a/frontend/ui/src/components/AiryWebsocket/index.tsx +++ b/frontend/ui/src/components/AiryWebsocket/index.tsx @@ -1,7 +1,7 @@ import React, {useState, useEffect} from 'react'; import _, {connect, ConnectedProps} from 'react-redux'; import {WebSocketClient} from 'websocketclient'; -import {Message, Channel, MetadataEvent} from 'model'; +import {Message, Channel, MetadataEvent, Tag} from 'model'; import camelcaseKeys from 'camelcase-keys'; import {env} from '../../env'; @@ -11,12 +11,11 @@ import {getConversationInfo} from '../../actions/conversations'; import {setChannelAction} from '../../actions/channel'; import {setMetadataAction} from '../../actions/metadata'; import {allConversations} from '../../selectors/conversations'; +import {upsertTagAction} from '../../actions'; type AiryWebSocketProps = {} & ConnectedProps; -export const AiryWebSocketContext = React.createContext({ - refreshSocket: null, -}); +export const AiryWebSocketContext = React.createContext({refreshSocket: null}); const mapStateToProps = (state: StateModel) => ({ conversations: allConversations(state), @@ -33,12 +32,15 @@ const mapDispatchToProps = dispatch => ({ stopPaths: ['payload.metadata.user_data', 'payload.metadata.tags'], }) ), + onTag: (tag: Tag) => { + dispatch(upsertTagAction(tag)); + }, }); const connector = connect(mapStateToProps, mapDispatchToProps); const AiryWebSocket: React.FC = props => { - const {children, conversations, getConversationInfo, addMessages, onChannel, onMetadata} = props; + const {children, conversations, getConversationInfo, addMessages, onChannel, onMetadata, onTag} = props; const [webSocketClient, setWebSocketClient] = useState(null); const onMessage = (conversationId: string, message: Message) => { @@ -62,6 +64,7 @@ const AiryWebSocket: React.FC = props => { }, onChannel, onMetadata, + onTag, }) ); }; diff --git a/frontend/ui/src/components/ChannelAvatar/index.tsx b/frontend/ui/src/components/ChannelAvatar/index.tsx index 0c78d3d7de..72331a2758 100644 --- a/frontend/ui/src/components/ChannelAvatar/index.tsx +++ b/frontend/ui/src/components/ChannelAvatar/index.tsx @@ -39,7 +39,7 @@ const ChannelAvatar = (props: ChannelAvatarProps) => { return ; case Source.twilioSMS: return ; - case Source.twilioWhatsapp: + case Source.twilioWhatsApp: return ; default: return ; diff --git a/frontend/ui/src/components/Tag/index.module.scss b/frontend/ui/src/components/Tag/index.module.scss index 94c42ce3dc..375fa4ee9a 100644 --- a/frontend/ui/src/components/Tag/index.module.scss +++ b/frontend/ui/src/components/Tag/index.module.scss @@ -15,6 +15,7 @@ line-height: 24px; max-width: 100%; white-space: nowrap; + border: 1px solid transparent; &:hover { word-break: break-all; diff --git a/frontend/ui/src/pages/Channels/ConnectedChannelsBySourceCard/index.tsx b/frontend/ui/src/pages/Channels/ConnectedChannelsBySourceCard/index.tsx index ce4f62087d..76b7cb646e 100644 --- a/frontend/ui/src/pages/Channels/ConnectedChannelsBySourceCard/index.tsx +++ b/frontend/ui/src/pages/Channels/ConnectedChannelsBySourceCard/index.tsx @@ -12,7 +12,6 @@ import styles from './index.module.scss'; type ConnectedChannelsBySourceCardProps = { sourceInfo: SourceInfo; channels: Channel[]; - connected: string; }; const ConnectedChannelsBySourceCard = (props: ConnectedChannelsBySourceCardProps & RouteComponentProps) => { @@ -26,9 +25,7 @@ const ConnectedChannelsBySourceCard = (props: ConnectedChannelsBySourceCardProps <>
-

- {channels.length} {props.connected} -

+

{channels.length} Connected

{ setName('Twilio SMS'); setPath(CHANNELS_TWILIO_SMS_ROUTE + '/new_account'); break; - case Source.twilioWhatsapp: + case Source.twilioWhatsApp: setName('Twilio Whatsapp'); setPath(CHANNELS_TWILIO_WHATSAPP_ROUTE + '/new_account'); break; diff --git a/frontend/ui/src/pages/Channels/MainPage/index.tsx b/frontend/ui/src/pages/Channels/MainPage/index.tsx index baf4f46899..347463bdcb 100644 --- a/frontend/ui/src/pages/Channels/MainPage/index.tsx +++ b/frontend/ui/src/pages/Channels/MainPage/index.tsx @@ -11,7 +11,7 @@ import ConnectedChannelsBySourceCard from '../ConnectedChannelsBySourceCard'; import {ReactComponent as AiryAvatarIcon} from 'assets/images/icons/airy_avatar.svg'; import {ReactComponent as MessengerAvatarIcon} from 'assets/images/icons/messenger_avatar.svg'; import {ReactComponent as SMSAvatarIcon} from 'assets/images/icons/sms_avatar.svg'; -import {ReactComponent as WhatsappLogo} from 'assets/images/icons/whatsapp_avatar.svg'; +import {ReactComponent as WhatsAppAvatarIcon} from 'assets/images/icons/whatsapp_avatar.svg'; import {ReactComponent as GoogleAvatarIcon} from 'assets/images/icons/google_avatar.svg'; import styles from './index.module.scss'; @@ -95,10 +95,10 @@ const SourcesInfo: SourceInfo[] = [ dataCyChannelList: cyChannelsTwilioSmsList, }, { - type: Source.twilioWhatsapp, - title: 'Whatsapp', + type: Source.twilioWhatsApp, + title: 'WhatsApp', description: 'World #1 chat app', - image: , + image: , newChannelRoute: CHANNELS_TWILIO_WHATSAPP_ROUTE + '/new_account', channelsListRoute: CHANNELS_CONNECTED_ROUTE + '/twilio.whatsapp/#', configKey: 'sources-twilio', @@ -133,7 +133,7 @@ const MainPage = (props: MainPageProps & RouteComponentProps) => { case Source.google: return setDisplayDialogFromSource('')} />; case Source.twilioSMS: - case Source.twilioWhatsapp: + case Source.twilioWhatsApp: return setDisplayDialogFromSource('')} />; } @@ -169,11 +169,7 @@ const MainPage = (props: MainPageProps & RouteComponentProps) => { } }} /> - +
))}
diff --git a/frontend/ui/src/pages/Channels/Providers/Airy/ChatPlugin/sections/CustomiseSection.tsx b/frontend/ui/src/pages/Channels/Providers/Airy/ChatPlugin/sections/CustomiseSection.tsx index 87eb23a7fd..f578c87ff8 100644 --- a/frontend/ui/src/pages/Channels/Providers/Airy/ChatPlugin/sections/CustomiseSection.tsx +++ b/frontend/ui/src/pages/Channels/Providers/Airy/ChatPlugin/sections/CustomiseSection.tsx @@ -54,13 +54,13 @@ export const CustomiseSection = ({channelId, host}: CustomiseSectionProps) => { return ''; } let config = ''; - if (headerText !== '') config += `\n headerText: '${headerText}'`; - if (bubbleIconUrl !== '') config += `\n bubbleIcon: '${bubbleIconUrl}'`; - if (sendMessageIconUrl !== '') config += `\n sendMessageIcon: '${sendMessageIconUrl}'`; - if (headerTextColor !== '') config += `\n headerTextColor: '${headerTextColor}'`; - if (primaryColor !== '') config += `\n primaryColor: '${primaryColor}'`; - if (accentColor !== '') config += `\n accentColor: '${accentColor}'`; - if (backgroundColor !== '') config += `\n backgroundColor: '${backgroundColor}'`; + if (headerText !== '') config += `\n headerText: '${headerText}',`; + if (bubbleIconUrl !== '') config += `\n bubbleIcon: '${bubbleIconUrl}',`; + if (sendMessageIconUrl !== '') config += `\n sendMessageIcon: '${sendMessageIconUrl}',`; + if (headerTextColor !== '') config += `\n headerTextColor: '${headerTextColor}',`; + if (primaryColor !== '') config += `\n primaryColor: '${primaryColor}',`; + if (accentColor !== '') config += `\n accentColor: '${accentColor}',`; + if (backgroundColor !== '') config += `\n backgroundColor: '${backgroundColor}',`; return ` w[n].config = {${config} @@ -94,9 +94,9 @@ export const CustomiseSection = ({channelId, host}: CustomiseSectionProps) => { w[n].channelId = "${channelId}"; w[n].host = "${host}";${getTemplateConfig()} var f = d.getElementsByTagName(s)[0], - j = d.createElement(s); + j = d.createElement(s); j.async = true; - j.src = w[n].host + "/s.js"; + j.src = w[n].host + '/chatplugin/ui/s.js'; f.parentNode.insertBefore(j, f); })(window, document, "script", "airy"); `; diff --git a/frontend/ui/src/pages/Channels/Providers/Twilio/TwilioConnect.tsx b/frontend/ui/src/pages/Channels/Providers/Twilio/TwilioConnect.tsx index 605a5fc7ee..36ecaa5116 100644 --- a/frontend/ui/src/pages/Channels/Providers/Twilio/TwilioConnect.tsx +++ b/frontend/ui/src/pages/Channels/Providers/Twilio/TwilioConnect.tsx @@ -52,7 +52,7 @@ const TwilioConnect = (props: TwilioConnectProps) => { imageUrl: imageUrlInput, }; - if (source === Source.twilioWhatsapp) { + if (source === Source.twilioWhatsApp) { connectTwilioWhatsapp(connectPayload).then(() => { history.replace({ pathname: CHANNELS_CONNECTED_ROUTE + `/twilio.whatsapp/#`, diff --git a/frontend/ui/src/pages/Channels/Providers/Twilio/WhatsApp/TwilioWhatsappConnect.tsx b/frontend/ui/src/pages/Channels/Providers/Twilio/WhatsApp/TwilioWhatsappConnect.tsx index a2e66db9e1..517f46233a 100644 --- a/frontend/ui/src/pages/Channels/Providers/Twilio/WhatsApp/TwilioWhatsappConnect.tsx +++ b/frontend/ui/src/pages/Channels/Providers/Twilio/WhatsApp/TwilioWhatsappConnect.tsx @@ -43,7 +43,7 @@ const TwilioWhatsappConnect = (props: TwilioWhatsappProps) => { }, [channels, channelId]); return ( - + ); }; diff --git a/frontend/ui/src/pages/Inbox/ConversationList/index.tsx b/frontend/ui/src/pages/Inbox/ConversationList/index.tsx index 6d38517e01..883d793c1b 100644 --- a/frontend/ui/src/pages/Inbox/ConversationList/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationList/index.tsx @@ -117,8 +117,8 @@ const ConversationList = (props: ConversationListProps) => {
- - resizeList()} /> + resizeList()} /> +
{renderConversationList()}
diff --git a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.module.scss b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.module.scss index e81dd14cfa..dff4a0cf1f 100644 --- a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.module.scss +++ b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.module.scss @@ -10,8 +10,9 @@ .containerSearchHeadline { display: flex; justify-content: space-between; - height: 40px; + height: 42px; width: 100%; + align-items: center; } .containerSearchField { @@ -65,6 +66,7 @@ border: none; background-color: white; cursor: pointer; + outline: none; } .headline { @@ -76,12 +78,27 @@ .searchIcon { width: 22px; height: 22px; - padding-top: 2px; + padding-top: 1px; margin-right: 4px; position: relative; - top: 8px; path { fill: var(--color-text-gray); } } + +.filterButton { + cursor: pointer; + background: none; + border: none; + outline: none; +} + +.activeFilters { + @extend .filterButton; + svg { + path { + fill: var(--color-airy-blue); + } + } +} diff --git a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx index 90d61f2b4f..fa7899678d 100644 --- a/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationListHeader/index.tsx @@ -1,5 +1,6 @@ import React, {useEffect, useState} from 'react'; -import {connect, ConnectedProps} from 'react-redux'; +import _, {connect, ConnectedProps} from 'react-redux'; +import {RouteComponentProps} from 'react-router-dom'; import {SearchField} from 'components'; import {StateModel} from '../../../reducers'; @@ -8,31 +9,38 @@ import {setSearch, resetFilteredConversationAction} from '../../../actions/conve import {ReactComponent as IconSearch} from 'assets/images/icons/search.svg'; import {ReactComponent as BackIcon} from 'assets/images/icons/arrow-left-2.svg'; +import {ReactComponent as FilterIcon} from 'assets/images/icons/filter-alt.svg'; import styles from './index.module.scss'; import {cySearchButton, cySearchField, cySearchFieldBackButton} from 'handles'; - -const mapStateToProps = (state: StateModel) => { - return { - user: state.data.user, - currentFilter: state.data.conversations.filtered.currentFilter || {}, - totalConversations: state.data.conversations.all.paginationData.total, - }; -}; +import Popup from '../ConversationsFilter/Popup'; const mapDispatchToProps = { setSearch, resetFilteredConversationAction, }; +const mapStateToProps = (state: StateModel) => ({ + user: state.data.user, + currentFilter: state.data.conversations.filtered.currentFilter || {}, + totalConversations: state.data.conversations.all.paginationData.total, + filteredPaginationData: state.data.conversations.filtered.paginationData, +}); + const connector = connect(mapStateToProps, mapDispatchToProps); -const ConversationListHeader = (props: ConnectedProps) => { - const {setSearch, resetFilteredConversationAction, currentFilter} = props; +type ConversationListHeaderProps = { + onFilterVisibilityChanged: () => void; +} & ConnectedProps & + RouteComponentProps; + +const ConversationListHeader = (props: ConversationListHeaderProps) => { + const {setSearch, resetFilteredConversationAction, currentFilter, onFilterVisibilityChanged} = props; const [isShowingSearchInput, setIsShowingSearchInput] = useState(false); const [searchText, setSearchText] = useState(''); + const [isFilterOpen, setIsFilterOpen] = useState(false); useEffect(() => { resetFilteredConversationAction(); @@ -61,9 +69,27 @@ const ConversationListHeader = (props: ConnectedProps) => { }; const InboxConversationCount = () => { - const {totalConversations} = props; + const {totalConversations, filteredPaginationData} = props; + + return ( +
{`Inbox (${filteredPaginationData.filteredTotal ?? totalConversations})`}
+ ); + }; - return
{`Inbox (${totalConversations})`}
; + const toggleFilter = () => { + setIsFilterOpen(!isFilterOpen); + onFilterVisibilityChanged(); + }; + + const activeFilter = () => { + const currentFilterLength = Object.keys(currentFilter).length; + + if (currentFilter.isStateOpen === undefined && currentFilter.displayName === (null || undefined)) { + return currentFilterLength - 2; + } + if (currentFilter.isStateOpen === undefined || currentFilter.displayName === (null || undefined)) { + return currentFilterLength - 1; + } }; const renderSearchInput = isShowingSearchInput ? ( @@ -89,6 +115,18 @@ const ConversationListHeader = (props: ConnectedProps) => { + + {isFilterOpen && ( +
+ +
+ )} ); diff --git a/frontend/ui/src/pages/Inbox/ConversationListItem/index.tsx b/frontend/ui/src/pages/Inbox/ConversationListItem/index.tsx index 5a76b16cc6..a7225d1f47 100644 --- a/frontend/ui/src/pages/Inbox/ConversationListItem/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationListItem/index.tsx @@ -8,12 +8,13 @@ import {Avatar} from 'render'; import {formatTimeOfMessage} from '../../../services/format/date'; import {Message} from 'model'; -import {MergedConversation} from '../../../reducers'; +import {MergedConversation, StateModel} from '../../../reducers'; import {INBOX_CONVERSATIONS_ROUTE} from '../../../routes/routes'; import {readConversations, conversationState} from '../../../actions/conversations'; import styles from './index.module.scss'; import {ReactComponent as Checkmark} from 'assets/images/icons/checkmark-circle.svg'; +import {newestFilteredConversationFirst} from '../../../selectors/conversations'; interface FormattedMessageProps { message: Message; @@ -30,7 +31,13 @@ const mapDispatchToProps = { conversationState, }; -const connector = connect(null, mapDispatchToProps); +const mapStateToProps = (state: StateModel) => { + return { + filteredConversations: newestFilteredConversationFirst(state), + }; +}; + +const connector = connect(mapStateToProps, mapDispatchToProps); const FormattedMessage = ({message}: FormattedMessageProps) => { if (message?.content) { @@ -75,7 +82,7 @@ const ConversationListItem = (props: ConversationListItemProps) => { if (active && unread) { return readConversations(conversation.id); } - }, [active, conversation]); + }, [active, conversation, currentConversationState]); return (
readConversations(conversation.id)}> diff --git a/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.module.scss b/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.module.scss index bebcf247ee..45bec7968d 100644 --- a/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.module.scss +++ b/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.module.scss @@ -72,6 +72,8 @@ display: flex; align-items: center; cursor: pointer; + outline: none; + max-height: 29px; svg { display: inline-block; @@ -83,16 +85,15 @@ fill: var(--color-soft-green); } } +} - .openIcon { - display: inline-block; - width: 15px; - height: 15px; - background: none; - border: 2px solid #bf1a2f; - border-radius: 50%; - margin-right: 6px; - } +.openIconButton { + width: 19px; + height: 19px; + background: none; + border: 2px solid #bf1a2f; + border-radius: 50%; + margin-right: 2px; } .filterButtonSelected { @@ -100,6 +101,7 @@ border: 1px solid var(--color-airy-blue); background-color: var(--color-airy-blue); color: white; + outline: none; path { stroke: white; @@ -194,10 +196,12 @@ } svg { - width: 8px; - height: 6px; - margin-left: 8px; + width: 24px; + height: 24px; margin-bottom: 2px; + border-radius: 50%; + padding-top: 2px; + padding-left: 2px; } } diff --git a/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.tsx b/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.tsx index 4d1d93bc06..77f2ad412b 100644 --- a/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationsFilter/Popup.tsx @@ -9,6 +9,7 @@ import {StateModel} from '../../../reducers'; import DialogCustomizable from '../../../components/DialogCustomizable'; import Tag from '../../../components/Tag'; import {ReactComponent as CheckmarkIcon} from 'assets/images/icons/checkmark.svg'; +import {ReactComponent as CheckmarkCircleIcon} from 'assets/images/icons/checkmark-circle.svg'; import styles from './Popup.module.scss'; import {allChannels} from '../../../selectors/channels'; import ChannelAvatar from '../../../components/ChannelAvatar'; @@ -70,6 +71,13 @@ const PopUpFilter = (props: PopUpFilterProps) => { setFilter(newFilter); }; + const toggleState = (event: React.MouseEvent, isOpen: boolean) => { + event.stopPropagation(); + const newFilter: ConversationFilter = {...filter}; + newFilter.isStateOpen === isOpen ? (newFilter.isStateOpen = !isOpen) : (newFilter.isStateOpen = isOpen); + setFilter(newFilter); + }; + const isChannelSelected = (channelsList: Array, channel: Channel) => { return (channelsList || []).includes(channel.id); }; @@ -97,6 +105,10 @@ const PopUpFilter = (props: PopUpFilterProps) => { }); }; + const OpenIcon = () => { + return
; + }; + return ( applyPressed()} @@ -104,19 +116,48 @@ const PopUpFilter = (props: PopUpFilterProps) => { coverStyle={{backgroundColor: 'rgba(247,247,247,0.7)'}}>
-
-

Read/Unread

-
- - +
+
+

Read/Unread

+
+ + +
+
+
+
+
+

State

+
+ + +
@@ -170,7 +211,6 @@ const PopUpFilter = (props: PopUpFilterProps) => { ) : ( )} -
{channel.metadata?.name || channel.sourceChannelId}
))} diff --git a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.module.scss b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.module.scss index 6f134b7206..66125b9a33 100644 --- a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.module.scss +++ b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.module.scss @@ -1,14 +1,38 @@ @import 'assets/scss/colors.scss'; @import 'assets/scss/fonts.scss'; -.actionRow { +.quickFilterContainer { display: flex; - flex-direction: row; - justify-content: space-between; - flex-grow: 1; - z-index: 3; - position: relative; - min-height: 36px; + align-items: center; +} + +.quickFilterButtons { + display: flex; + width: 100%; + justify-content: center; +} + +.quickFilterButtonsBackground { + border-radius: 8px; + background-color: var(--color-background-gray); +} + +.quickFilterButton { + @include font-base; + background: var(--color-background-gray); + border: none; + outline: none; + border-radius: 8px; + padding: 2px; + width: 80px; + border: 1px solid transparent; + cursor: pointer; +} + +.quickFilterButtonActive { + @extend .quickFilterButton; + background-color: var(--color-background-blue); + border: 1px solid var(--color-airy-blue); } .shortcutButton { diff --git a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx index 65a41d23ac..7d2eb79871 100644 --- a/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx +++ b/frontend/ui/src/pages/Inbox/ConversationsFilter/index.tsx @@ -1,156 +1,78 @@ -import React, {useEffect, useState} from 'react'; +import React, {useEffect, useRef} from 'react'; import _, {connect, ConnectedProps} from 'react-redux'; -import {filter} from 'lodash-es'; import {ConversationFilter} from 'model'; import {StateModel} from '../../../reducers'; -import {setFilter, resetFilter} from '../../../actions/conversationsFilter'; +import {setFilter} from '../../../actions/conversationsFilter'; import {allConversations, isFilterActive} from '../../../selectors/conversations'; -import {ReactComponent as ChevronLeft} from 'assets/images/icons/chevron_left.svg'; -import Popup from './Popup'; - import styles from './index.module.scss'; const mapStateToProps = (state: StateModel) => { return { conversationsFilter: state.data.conversations.filtered.currentFilter, isFilterActive: isFilterActive(state), - filteredPaginationData: state.data.conversations.filtered.paginationData, conversations: allConversations(state), }; }; const mapDispatchToProps = { setFilter, - resetFilter, }; const connector = connect(mapStateToProps, mapDispatchToProps); -type ConversationsFilterProps = { - onFilterVisibilityChanged: () => void; -} & ConnectedProps; +type ConversationsFilterProps = {} & ConnectedProps; const ConversationsFilter = (props: ConversationsFilterProps) => { - const {conversationsFilter, setFilter, onFilterVisibilityChanged} = props; - - const [isFilterOpen, setIsFilterOpen] = useState(false); + const {conversationsFilter, setFilter} = props; + const allButton = useRef(null); + const openButton = useRef(null); + const closedButton = useRef(null); useEffect(() => { - resetFilter(); - itemsCount(); + currentStateFilter(); }), [props.conversations]; - const toggleFilter = () => { - setIsFilterOpen(!isFilterOpen); - onFilterVisibilityChanged(); - }; - - const getActiveFilterCount = () => { - return filter(Object.keys(conversationsFilter), (element: string) => { - return element !== 'displayName'; - }).length; - }; - - const isOnlyOneFilterActive = () => { - return getActiveFilterCount() === 1; - }; - - const isFilterUnreadActive = () => { - return conversationsFilter.unreadOnly && isOnlyOneFilterActive(); - }; - - const isFilterButtonActive = () => { - return ( - getActiveFilterCount() > 1 || - conversationsFilter.unreadOnly || - (conversationsFilter.byTags && conversationsFilter.byTags.length > 0) || - (conversationsFilter.byChannels && conversationsFilter.byChannels.length > 0) - ); - }; - - const activateUnreadFilter = () => { - resetFilter(); - const filter: ConversationFilter = {unreadOnly: true}; - setFilter(filter); - }; - - const renderFilterStatus = () => { - const activeFilters = []; - if (conversationsFilter.readOnly) { - activeFilters.push('Read'); - } - if (conversationsFilter.unreadOnly) { - activeFilters.push('Unread'); + const currentStateFilter = () => { + allButton.current.className = styles.quickFilterButton; + openButton.current.className = styles.quickFilterButton; + closedButton.current.className = styles.quickFilterButton; + + if (conversationsFilter.isStateOpen === undefined) { + allButton.current.className = styles.quickFilterButtonActive; + } else if (conversationsFilter.isStateOpen === true) { + openButton.current.className = styles.quickFilterButtonActive; + } else if (conversationsFilter.isStateOpen === false) { + closedButton.current.className = styles.quickFilterButtonActive; } - if (conversationsFilter.byTags && conversationsFilter.byTags.length > 0) { - activeFilters.push(`${conversationsFilter.byTags.length} Tags`); - } - if (conversationsFilter.byChannels && conversationsFilter.byChannels.length > 0) { - activeFilters.push(`${conversationsFilter.byChannels.length} Channels`); - } - - return ( -
- {activeFilters.map((filter, key) => { - return ( -
- {filter} -
- ); - })} -
- ); }; - const itemsCount = () => { - const {filteredPaginationData} = props; - - if ( - filteredPaginationData.filteredTotal !== undefined && - filteredPaginationData.filteredTotal !== filteredPaginationData.total - ) { - return ( -
- {`Filtered: ${filteredPaginationData.filteredTotal} Total: ${props.conversations.length}`} -
- ); - } - - return
 
; + const setStateOpen = (setOpen: boolean) => { + const newFilter: ConversationFilter = {...conversationsFilter}; + newFilter.isStateOpen = setOpen; + setFilter(newFilter); }; return (
- {itemsCount()} -
- {isFilterButtonActive() ? ( - renderFilterStatus() - ) : ( -
- - +
- )} -
-
- {isFilterOpen && }
); }; diff --git a/frontend/ui/src/pages/Inbox/Messenger/ConversationMetadata/index.tsx b/frontend/ui/src/pages/Inbox/Messenger/ConversationMetadata/index.tsx index 52255884a3..c7795d48d2 100644 --- a/frontend/ui/src/pages/Inbox/Messenger/ConversationMetadata/index.tsx +++ b/frontend/ui/src/pages/Inbox/Messenger/ConversationMetadata/index.tsx @@ -1,7 +1,7 @@ import React, {FormEvent, useEffect, useState} from 'react'; import _, {connect, ConnectedProps} from 'react-redux'; import {withRouter} from 'react-router-dom'; -import {Tag as TagModel, TagColor, getTags} from 'model'; +import {Tag as TagModel, TagColor} from 'model'; import {createTag, listTags} from '../../../../actions/tags'; import {addTagToConversation, removeTagFromConversation} from '../../../../actions/conversations'; @@ -17,6 +17,7 @@ import {getCurrentConversation} from '../../../../selectors/conversations'; import {ConversationRouteProps} from '../../index'; import {cyShowTagsDialog, cyTagsDialogInput, cyTagsDialogButton} from 'handles'; +import difference from 'lodash/difference'; const mapStateToProps = (state: StateModel, ownProps: ConversationRouteProps) => { return { @@ -58,31 +59,21 @@ const ConversationMetadata = (props: ConnectedProps) => { removeTagFromConversation(conversation.id, tag.id); }; - const filterForUnusedTags = (tags: TagModel[]): TagModel[] => { - return tags.filter(tag => !(tag.id in (conversation.metadata.tags || {}))); - }; - - const filterForUsedTags = (tags: TagModel[]): TagModel[] => { - return tags.filter(tag => tag.id in (conversation.metadata.tags || {})); - }; + const tagSorter = (a: TagModel, b: TagModel) => a.name.localeCompare(b.name); - const tagSorter = (tagA: TagModel, tagB: TagModel) => { - if (tagA.name < tagB.name) { - return -1; - } - if (tagA.name > tagB.name) { - return 1; - } + const conversationTags = () => + Object.keys(conversation.metadata.tags || {}) + .map(tagId => tags[tagId]) + .filter(tag => tag !== undefined) + .sort(tagSorter); - return 0; - }; - - const checkIfExists = (value: string) => { - const usedTags = filterForUsedTags(tags); - if (value.length == 0) { + const checkIfExists = (tagName: string) => { + const usedTags = conversationTags(); + if (tagName.length === 0) { return true; } - if (usedTags.find(tag => tag.name === value)) { + + if (usedTags.find(tag => tag.name === tagName)) { return 'Tag already added'; } @@ -90,15 +81,17 @@ const ConversationMetadata = (props: ConnectedProps) => { }; const getFilteredTags = (): TagModel[] => - filterForUnusedTags(tags) + difference(Object.keys(tags), Object.keys(conversation.metadata.tags || {})) + .map(id => tags[id]) + .filter(tag => tag !== undefined) .sort(tagSorter) - .filter(tag => tag.name.startsWith(tagName)); + .filter((tag: TagModel) => tag.name.startsWith(tagName)); const submitForm = (event: FormEvent) => { event.preventDefault(); const filteredTags = getFilteredTags(); - if (filteredTags.length == 1) { + if (filteredTags.length === 1) { addTag(filteredTags[0]); } else if (filteredTags.length == 0 && tagName.trim().length > 0) { createTag({name: tagName.trim(), color}).then((tag: TagModel) => { @@ -166,10 +159,6 @@ const ConversationMetadata = (props: ConnectedProps) => { ); }; - const findTag = (tagId: string): TagModel => { - return tags.find(tag => tag.id === tagId); - }; - const contact = conversation.metadata.contact; return (
@@ -179,7 +168,6 @@ const ConversationMetadata = (props: ConnectedProps) => {
-
{contact?.displayName}
@@ -193,11 +181,9 @@ const ConversationMetadata = (props: ConnectedProps) => { {showTagsDialog && renderTagsDialog()}
- {tags && - getTags(conversation) - .map(tagId => findTag(tagId)) - .sort(tagSorter) - .map(tag => tag && removeTag(tag)} />)} + {conversationTags().map(tag => ( + removeTag(tag)} /> + ))}
diff --git a/frontend/ui/src/pages/Inbox/Messenger/MessageList/index.tsx b/frontend/ui/src/pages/Inbox/Messenger/MessageList/index.tsx index f274a14183..77a5bbec7a 100644 --- a/frontend/ui/src/pages/Inbox/Messenger/MessageList/index.tsx +++ b/frontend/ui/src/pages/Inbox/Messenger/MessageList/index.tsx @@ -5,7 +5,7 @@ import {debounce, isEmpty} from 'lodash-es'; import {withRouter} from 'react-router-dom'; import {cyMessageList} from 'handles'; -import {Message, Suggestions, getSource} from 'model'; +import {Message, Suggestions} from 'model'; import {SourceMessage} from 'render'; import {ReactComponent as LightBulbIcon} from 'assets/images/icons/lightbulb.svg'; @@ -179,7 +179,7 @@ const MessageList = (props: MessageListProps) => { lastInGroup={lastInGroup} isChatPlugin={false} decoration={messageDecoration}> - +
); diff --git a/frontend/ui/src/pages/Tags/SimpleTagForm.tsx b/frontend/ui/src/pages/Tags/SimpleTagForm.tsx index 9a70ab9494..c063d496e2 100644 --- a/frontend/ui/src/pages/Tags/SimpleTagForm.tsx +++ b/frontend/ui/src/pages/Tags/SimpleTagForm.tsx @@ -1,8 +1,7 @@ import React, {useState, Fragment} from 'react'; import {connect} from 'react-redux'; -import {createTag, listTags, errorTag, filterTags} from '../../actions/tags'; -import {filteredTags} from '../../selectors/tags'; +import {createTag, listTags, errorTag} from '../../actions/tags'; import {Button, Input} from 'components'; import DialogCustomizable from '../../components/DialogCustomizable'; @@ -98,7 +97,7 @@ const SimpleTagForm = ({errorMessage, createTag, errorTag, onClose, tags}: Simpl const mapStateToProps = (state: StateModel) => { return { - tags: filteredTags(state), + tags: Object.values(state.data.tags.all), errorMessage: state.data.tags.error, }; }; @@ -107,7 +106,6 @@ const mapDispatchToProps = { createTag, errorTag, listTags, - filterTags, }; const connector = connect(mapStateToProps, mapDispatchToProps); diff --git a/frontend/ui/src/pages/Tags/index.tsx b/frontend/ui/src/pages/Tags/index.tsx index 1383a358be..3fbd3da260 100644 --- a/frontend/ui/src/pages/Tags/index.tsx +++ b/frontend/ui/src/pages/Tags/index.tsx @@ -6,10 +6,8 @@ import {cyTagsSearchField, cyTagsTable} from 'handles'; import {ReactComponent as Plus} from 'assets/images/icons/plus.svg'; -import {listTags, deleteTag, filterTags, errorTag} from '../../actions/tags'; -import {filteredTags} from '../../selectors/tags'; +import {listTags, deleteTag, errorTag} from '../../actions/tags'; -import {Tag} from 'model'; import {ModalType} from '../../types'; import {TableRow} from './TableRow'; @@ -30,7 +28,8 @@ const initialState = { delete: '', error: '', }, - tagQuery: '', + query: '', + filteredTags: [], createDrawer: false, emptyState: true, }; @@ -41,14 +40,10 @@ class Tags extends Component, typeof initialSta componentDidMount() { setPageTitle('Tags'); this.props.listTags(); - this.props.filterTags(''); } - handleSearch = (value: string) => { - this.setState({ - tagQuery: value, - }); - this.props.filterTags(value); + handleSearch = (query: string) => { + this.setState({query, filteredTags: this.props.tags.filter(t => t.name.match(query))}); }; handleDelete = (e: React.ChangeEvent) => { @@ -57,7 +52,7 @@ class Tags extends Component, typeof initialSta return { modal: { ...state.modal, - delete: e.target && e.target.value, + delete: e.target?.value, }, }; }); @@ -71,9 +66,7 @@ class Tags extends Component, typeof initialSta }; removeEmptyStateAndCreateTag = () => { - this.setState({ - emptyState: false, - }); + this.setState({emptyState: false}); this.handleTagDrawer(); }; @@ -173,7 +166,7 @@ class Tags extends Component, typeof initialSta }; renderTagList() { - const {tags} = this.props; + const tags = this.state.query !== '' ? this.state.filteredTags : this.props.tags; return (
@@ -184,7 +177,7 @@ class Tags extends Component, typeof initialSta
@@ -202,10 +195,9 @@ class Tags extends Component, typeof initialSta Color - {tags && - tags.map((tag: Tag, idx: number) => { - return ; - })} + {tags.map(tag => ( + + ))} ) : ( @@ -235,18 +227,15 @@ class Tags extends Component, typeof initialSta } const mapStateToProps = (state: StateModel) => ({ - tags: filteredTags(state), - allTagsCount: state.data.tags.all.length, - tagQuery: state.data.tags.query, + tags: Object.values(state.data.tags.all), + allTagsCount: Object.keys(state.data.tags.all).length, errorMessage: state.data.tags.error, - userData: state.data.user, }); const mapDispatchToProps = { listTags, deleteTag, errorTag, - filterTags, }; const connector = connect(mapStateToProps, mapDispatchToProps); diff --git a/frontend/ui/src/reducers/data/conversations/index.ts b/frontend/ui/src/reducers/data/conversations/index.ts index 0fa9d583ab..3b80a85b96 100644 --- a/frontend/ui/src/reducers/data/conversations/index.ts +++ b/frontend/ui/src/reducers/data/conversations/index.ts @@ -8,7 +8,6 @@ import * as metadataActions from '../../../actions/metadata'; import * as actions from '../../../actions/conversations'; import * as filterActions from '../../../actions/conversationsFilter'; import * as messageActions from '../../../actions/messages'; -import {MetadataEvent, ConversationMetadata} from 'model'; type Action = ActionType | ActionType; type FilterAction = ActionType; @@ -58,7 +57,7 @@ export type ConversationsState = { }; function mergeConversations( - oldConversation: {[conversation_id: string]: MergedConversation}, + oldConversation: {[conversationId: string]: MergedConversation}, newConversations: MergedConversation[] ): ConversationMap { newConversations.forEach((conversation: MergedConversation) => { @@ -90,7 +89,7 @@ function mergeConversations( } function mergeFilteredConversations( - oldConversation: {[conversation_id: string]: MergedConversation}, + oldConversation: {[conversationId: string]: MergedConversation}, newConversations: MergedConversation[] ): ConversationMap { newConversations.forEach((conversation: MergedConversation) => { @@ -160,7 +159,7 @@ const removeTagFromConversation = (state: AllConversationsState, conversationId, ...conversation, metadata: { ...conversation.metadata, - tags: pickBy(conversation.metadata?.tags, (value, key) => key !== tagId), + tags: pickBy(conversation.metadata?.tags, (_, key) => key !== tagId), }, }, }, @@ -214,31 +213,6 @@ function allReducer( return state; } - return { - ...state, - items: { - ...state.items, - [action.payload.identifier]: { - id: action.payload.identifier, - ...state.items[action.payload.identifier], - metadata: { - // Ensure that there is always a display name present - ...(action.payload as MetadataEvent).metadata, - state: action.payload.metadata.state || state.items[action.payload.identifier]?.metadata.state || 'OPEN', - contact: { - ...state.items[action.payload.identifier]?.metadata.contact, - ...(action.payload as MetadataEvent).metadata.contact, - }, - }, - }, - }, - }; - - case getType(metadataActions.mergeMetadataAction): - if (action.payload.subject !== 'conversation') { - return state; - } - return { ...state, items: { diff --git a/frontend/ui/src/reducers/data/messages/index.ts b/frontend/ui/src/reducers/data/messages/index.ts index 67a38d05b0..e058bac131 100644 --- a/frontend/ui/src/reducers/data/messages/index.ts +++ b/frontend/ui/src/reducers/data/messages/index.ts @@ -2,7 +2,7 @@ import {ActionType, getType} from 'typesafe-actions'; import * as actions from '../../../actions/messages'; import * as metadataActions from '../../../actions/metadata'; import {Message, MessageMetadata} from 'model'; -import {cloneDeep, merge, sortBy} from 'lodash-es'; +import {cloneDeep, sortBy} from 'lodash-es'; type Action = ActionType | ActionType; @@ -59,29 +59,6 @@ const setMetadata = (state: Messages, action: ActionType }, }; }; -const mergeMetadata = (state: Messages, action: ActionType) => { - const conversationId = findConversationId(state, action.payload.identifier); - - if (conversationId == undefined) { - return state; - } - - return { - ...state, - all: { - ...state.all, - [conversationId]: state.all[conversationId].map((message: Message) => { - if (message.id !== action.payload.identifier) { - return message; - } - return { - ...message, - metadata: merge({}, message.metadata, action.payload.metadata as MessageMetadata), - }; - }), - }, - }; -}; export default function messagesReducer(state = initialState, action: Action): Messages { switch (action.type) { @@ -102,13 +79,6 @@ export default function messagesReducer(state = initialState, action: Action): M return state; } return setMetadata(state, action); - - case getType(metadataActions.mergeMetadataAction): - if (action.payload.subject !== 'conversation') { - return state; - } - return mergeMetadata(state, action); - default: return state; } diff --git a/frontend/ui/src/reducers/data/tags/index.ts b/frontend/ui/src/reducers/data/tags/index.ts index 1c782edb95..8bcc7b198d 100644 --- a/frontend/ui/src/reducers/data/tags/index.ts +++ b/frontend/ui/src/reducers/data/tags/index.ts @@ -1,23 +1,19 @@ import {ActionType, getType} from 'typesafe-actions'; import * as actions from '../../../actions/tags'; import {Tag} from 'model'; -import {DataState} from '../../data'; +import {omit, keyBy} from 'lodash'; type Action = ActionType; -export type TagState = { - data: DataState; -}; - export type Tags = { - all: Tag[]; - query: string; + all: { + [tagId: string]: Tag; + }; error: string; }; const defaultState = { - all: [], - query: '', + all: {}, error: '', }; @@ -40,46 +36,27 @@ export default function tagsReducer(state = defaultState, action: Action): any { case getType(actions.fetchTagAction): return { ...state, - all: action.payload, + all: keyBy(action.payload, 'id'), }; case getType(actions.deleteTagAction): return { ...state, - all: state.all.filter((tag: Tag) => tag.id !== action.payload), + all: omit(state.all, action.payload), }; - case getType(actions.addTagAction): { - let updatedTag = false; - const mappedTags = state.all.map((tag: Tag) => { - if (tag.id === action.payload.id) { - updatedTag = true; - return { - ...tag, - ...action.payload, - }; - } - return tag; - }); - + case getType(actions.upsertTagAction): { return { ...state, - all: updatedTag ? mappedTags : state.all.concat([action.payload]), + all: { + ...state.all, + [action.payload.id]: action.payload, + }, }; } - case getType(actions.editTagAction): - return { - ...state, - all: state.all.map((tag: Tag) => (tag.id === action.payload.id ? action.payload : tag)), - }; case getType(actions.errorTagAction): return { ...state, error: errorMessage(action.payload), }; - case getType(actions.filterTagAction): - return { - ...state, - query: action.payload, - }; default: return state; } diff --git a/frontend/ui/src/selectors/conversations.ts b/frontend/ui/src/selectors/conversations.ts index ea73408af4..c6805a23df 100644 --- a/frontend/ui/src/selectors/conversations.ts +++ b/frontend/ui/src/selectors/conversations.ts @@ -1,6 +1,6 @@ import _, {createSelector} from 'reselect'; import {filter, pickBy, reverse, sortBy, values} from 'lodash-es'; -import {Conversation} from 'model'; +import {Conversation, ConversationFilter} from 'model'; import {MergedConversation, StateModel} from '../reducers'; import {ConversationMap} from '../reducers/data/conversations'; import {ConversationRouteProps} from '../pages/Inbox'; @@ -35,10 +35,88 @@ export const newestConversationFirst = createSelector(allConversations, conversa }); export const newestFilteredConversationFirst = createSelector( - filteredConversationSelector, - (conversations: Conversation[]) => { + (state: StateModel) => state.data.conversations.all.items, + (state: StateModel) => state.data.conversations.filtered.items, + (state: StateModel) => state.data.conversations.filtered.currentFilter, + (conversationsMap: ConversationMap, filteredConversationsMap: ConversationMap, currentFilter: ConversationFilter) => { + const conversations = Object.keys(conversationsMap).map((cId: string) => ({...conversationsMap[cId]})); + const filteredConversations = Object.keys(filteredConversationsMap).map((cId: string) => ({ + ...filteredConversationsMap[cId], + })); + + const updatedConversations: ConversationMap = {}; + + filteredConversations.forEach((filteredConversation: Conversation) => { + if (conversationsMap[filteredConversation.id]) { + updatedConversations[filteredConversation.id] = conversationsMap[filteredConversation.id]; + } else { + updatedConversations[filteredConversation.id] = filteredConversationsMap[filteredConversation.id]; + } + }); + + conversations.forEach((conversation: Conversation) => { + if (!updatedConversations[conversation.id]) { + updatedConversations[conversation.id] = conversation; + } + }); + + const updatedFiltered = filter(updatedConversations, (conversation: Conversation) => { + let isFulfilled = true; + + if (currentFilter.isStateOpen !== undefined) { + if (currentFilter.isStateOpen) { + isFulfilled = conversation.metadata.state === 'OPEN' || conversation.metadata.state === undefined; + } else { + isFulfilled = conversation.metadata.state === 'CLOSED'; + } + if (!isFulfilled) return isFulfilled; + } + + if (currentFilter.readOnly) { + isFulfilled = conversation.metadata.unreadCount === 0; + } else if (currentFilter.unreadOnly) { + isFulfilled = conversation.metadata.unreadCount > 0; + } + + if (currentFilter.byTags) { + const conversationTags = Object.keys(conversation.metadata.tags || {}).map((id: string) => id); + const filterTags = Object.keys(currentFilter.byTags).map((id: string) => currentFilter.byTags[id]); + + isFulfilled = filterTags.every(function (tag) { + return conversationTags.indexOf(tag) >= 0; + }); + } + + if (currentFilter.byChannels?.length > 0) { + const channelId = conversation.channel.id; + const filterChannel = Object.keys(currentFilter.byChannels).map((id: string) => currentFilter.byChannels[id]); + + isFulfilled = filterChannel.includes(channelId); + } + + if (currentFilter.bySources?.length > 0) { + const conversationSource = conversation.channel.source; + const filterSource = Object.keys(currentFilter.bySources).map((id: string) => currentFilter.bySources[id]); + + isFulfilled = filterSource.includes(conversationSource); + } + + if (currentFilter.displayName) { + const searchValue = currentFilter.displayName.toLowerCase(); + const displayName = conversation.metadata.contact.displayName.toLowerCase(); + + isFulfilled = displayName.includes(searchValue); + } + if (!isFulfilled) return isFulfilled; + + return isFulfilled; + }); + return reverse( - sortBy(conversations, (conversation: Conversation) => conversation.lastMessage && conversation.lastMessage.sentAt) + sortBy( + updatedFiltered, + (conversation: Conversation) => conversation.lastMessage && conversation.lastMessage.sentAt + ) ); } ); diff --git a/frontend/ui/src/selectors/tags.ts b/frontend/ui/src/selectors/tags.ts deleted file mode 100644 index 8e492ed972..0000000000 --- a/frontend/ui/src/selectors/tags.ts +++ /dev/null @@ -1,21 +0,0 @@ -import _redux from 'redux'; -import _, {createSelector} from 'reselect'; -import {Tag} from 'model'; -import {StateModel} from '../reducers'; - -const tags = (state: StateModel) => state.data.tags.all; -const queries = (state: StateModel) => state.data.tags.query; -const filter = (tags: Tag[], filter: string) => { - if (filter === '') { - return tags; - } - return ( - filter && - filter.length && - tags.filter((tag: Tag) => { - return tag.name.toLowerCase().includes(filter.toLowerCase()); - }) - ); -}; - -export const filteredTags = createSelector(tags, queries, filter); diff --git a/go.mod b/go.mod index a546c3b251..f2be033ef2 100644 --- a/go.mod +++ b/go.mod @@ -6,30 +6,32 @@ go 1.16 // Automatically generated by running //tools/update-deps require ( - github.com/alicebob/miniredis/v2 v2.13.3 - github.com/go-redis/redis/v8 v8.2.2 + github.com/Shopify/sarama v1.28.0 github.com/TwinProduction/go-color v1.0.0 github.com/aws/aws-sdk-go v1.37.29 github.com/aws/aws-sdk-go-v2/config v1.1.1 github.com/aws/aws-sdk-go-v2/service/ec2 v1.1.1 github.com/aws/aws-sdk-go-v2/service/eks v1.1.1 github.com/aws/aws-sdk-go-v2/service/iam v1.1.1 + github.com/beanstalkd/go-beanstalk v0.1.0 github.com/imdario/mergo v0.3.11 // indirect + github.com/jpillora/backoff v1.0.0 github.com/kr/pretty v0.2.1 github.com/mitchellh/go-homedir v1.1.0 + github.com/riferrei/srclient v0.2.1 github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.1.1 github.com/spf13/viper v1.7.1 + github.com/stretchr/testify v1.7.0 github.com/thanhpk/randstr v1.0.4 github.com/txn2/txeh v1.3.0 goji.io v2.0.2+incompatible + golang.org/x/mod v0.4.1 + golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.19.0 k8s.io/apimachinery v0.19.0 k8s.io/client-go v0.19.0 k8s.io/klog v1.0.0 - golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect - github.com/stretchr/testify v1.6.1 - golang.org/x/mod v0.4.1 ) diff --git a/go.sum b/go.sum index 1747e4d00a..737bbe1c2b 100644 --- a/go.sum +++ b/go.sum @@ -48,16 +48,16 @@ github.com/PuerkitoBio/purell v1.0.0 h1:0GoNN3taZV6QI81IXgCbxMyEaJDXMSIjArYBCYzV github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.28.0 h1:lOi3SfE6OcFlW9Trgtked2aHNZ2BIG/d6Do+PEUAqqM= +github.com/Shopify/sarama v1.28.0/go.mod h1:j/2xTrU39dlzBmsxF1eQ2/DdWrxyBCl6pzz7a81o/ZY= +github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/TwinProduction/go-color v1.0.0 h1:8n59tqmLmt8jyRsY44RPy2ixPDDw0FcVoAhlYeyz3Jw= github.com/TwinProduction/go-color v1.0.0/go.mod h1:5hWpSyT+mmKPjCwPNEruBW5Dkbs/2PwOuU468ntEXNQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.13.3 h1:kohgdtN58KW/r9ZDVmMJE3MrfbumwsDQStd0LPAGmmw= -github.com/alicebob/miniredis/v2 v2.13.3/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wXxSpQUE9EaJ/Blg= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= @@ -90,6 +90,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 h1:TJoIfnIFubCX0ACVeJ0w46HEH5Mwj github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0 h1:D6CSsM3gdxaGaqXnPgOBCeL6Mophqzu7KJOu7zW78sU= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/beanstalkd/go-beanstalk v0.1.0 h1:IiNwYbAoVBDs5xEOmleGoX+DRD3Moz99EpATbl8672w= +github.com/beanstalkd/go-beanstalk v0.1.0/go.mod h1:/G8YTyChOtpOArwLTQPY1CHB+i212+av35bkPXXj56Y= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -101,8 +103,6 @@ github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= @@ -129,19 +129,25 @@ github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= @@ -154,6 +160,10 @@ github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQo github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -180,8 +190,6 @@ github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501 h1:C1JKChikHGpXwT5 github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87 h1:zP3nY8Tk2E6RTkqGYrarZXuzh+ffyLDljLxCy1iJw80= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-redis/redis/v8 v8.2.2 h1:A1tQgdeVF23Ojc1TIRpVuVfOadUdIM0vFVURigoPEMM= -github.com/go-redis/redis/v8 v8.2.2/go.mod h1:ysgGY09J/QeDYbu3HikWEIPCwaeOkuNoTgKayTEaEOw= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -210,6 +218,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -218,7 +229,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -241,6 +251,10 @@ github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyyc github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= @@ -272,8 +286,9 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -298,12 +313,26 @@ github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -319,6 +348,8 @@ github.com/kisielk/errcheck v1.2.0 h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= @@ -329,8 +360,11 @@ github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/linkedin/goavro/v2 v2.9.7 h1:Vd++Rb/RKcmNJjM0HP/JJFMEWa21eUBVKPYlKehOGrM= +github.com/linkedin/goavro/v2 v2.9.7/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -370,28 +404,23 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= -github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= -github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A= +github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -415,6 +444,10 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzr github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/riferrei/srclient v0.2.1 h1:uIJhzPXW+suDsEDOZKf4oTZZXTyxtw98cFC70rFzvgU= +github.com/riferrei/srclient v0.2.1/go.mod h1:SmCz0lrYQ1pLqXlYq0yPnRccHLGh+llDA0i6hecPeW8= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af h1:gu+uRPtBe88sKxUCEXRoeCvVG90TJmwhiqRpvdhQFng= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= @@ -464,8 +497,9 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo= @@ -476,20 +510,20 @@ github.com/txn2/txeh v1.3.0 h1:vnbv63htVMZCaQgLqVBxKvj2+HHHFUzNW7I183zjg3E= github.com/txn2/txeh v1.3.0/go.mod h1:O7M6gUTPeMF+vsa4c4Ipx3JDkOYrruB1Wry8QRsMcw8= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0= -github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E= -go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= @@ -506,8 +540,10 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -551,11 +587,12 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -566,8 +603,9 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -576,7 +614,6 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -584,21 +621,24 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -630,8 +670,9 @@ golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 h1:Toz2IK7k8rbltAXwNAxKcn9 golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -678,8 +719,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -700,8 +742,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/go_repositories.bzl b/go_repositories.bzl index d779aa6f38..e7bf2ec90d 100644 --- a/go_repositories.bzl +++ b/go_repositories.bzl @@ -21,19 +21,6 @@ def go_repositories(): version = "v0.0.0-20151022065526-2efee857e7cf", ) - go_repository( - name = "com_github_alicebob_gopher_json", - importpath = "github.com/alicebob/gopher-json", - sum = "h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=", - version = "v0.0.0-20200520072559-a9ecdc9d1d3a", - ) - go_repository( - name = "com_github_alicebob_miniredis_v2", - importpath = "github.com/alicebob/miniredis/v2", - sum = "h1:kohgdtN58KW/r9ZDVmMJE3MrfbumwsDQStd0LPAGmmw=", - version = "v2.13.3", - ) - go_repository( name = "com_github_armon_circbuf", importpath = "github.com/armon/circbuf", @@ -170,6 +157,13 @@ def go_repositories(): sum = "h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=", version = "v0.5.0", ) + go_repository( + name = "com_github_beanstalkd_go_beanstalk", + importpath = "github.com/beanstalkd/go-beanstalk", + sum = "h1:IiNwYbAoVBDs5xEOmleGoX+DRD3Moz99EpATbl8672w=", + version = "v0.1.0", + ) + go_repository( name = "com_github_beorn7_perks", importpath = "github.com/beorn7/perks", @@ -215,12 +209,6 @@ def go_repositories(): version = "v1.1.0", ) - go_repository( - name = "com_github_cespare_xxhash_v2", - importpath = "github.com/cespare/xxhash/v2", - sum = "h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=", - version = "v2.1.1", - ) go_repository( name = "com_github_chzyer_logex", importpath = "github.com/chzyer/logex", @@ -297,6 +285,12 @@ def go_repositories(): sum = "h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=", version = "v2.0.0", ) + go_repository( + name = "com_github_creack_pty", + importpath = "github.com/creack/pty", + sum = "h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=", + version = "v1.1.9", + ) go_repository( name = "com_github_davecgh_go_spew", @@ -311,12 +305,6 @@ def go_repositories(): version = "v3.2.0+incompatible", ) - go_repository( - name = "com_github_dgryski_go_rendezvous", - importpath = "github.com/dgryski/go-rendezvous", - sum = "h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=", - version = "v0.0.0-20200823014737-9f7001d12a5f", - ) go_repository( name = "com_github_dgryski_go_sip13", importpath = "github.com/dgryski/go-sip13", @@ -336,6 +324,24 @@ def go_repositories(): sum = "h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=", version = "v0.0.0-20180111231733-ee0de3bc6815", ) + go_repository( + name = "com_github_eapache_go_resiliency", + importpath = "github.com/eapache/go-resiliency", + sum = "h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q=", + version = "v1.2.0", + ) + go_repository( + name = "com_github_eapache_go_xerial_snappy", + importpath = "github.com/eapache/go-xerial-snappy", + sum = "h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=", + version = "v0.0.0-20180814174437-776d5712da21", + ) + go_repository( + name = "com_github_eapache_queue", + importpath = "github.com/eapache/queue", + sum = "h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=", + version = "v1.1.0", + ) go_repository( name = "com_github_elazarl_goproxy", @@ -373,6 +379,18 @@ def go_repositories(): sum = "h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=", version = "v1.7.0", ) + go_repository( + name = "com_github_fortytw2_leaktest", + importpath = "github.com/fortytw2/leaktest", + sum = "h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=", + version = "v1.3.0", + ) + go_repository( + name = "com_github_frankban_quicktest", + importpath = "github.com/frankban/quicktest", + sum = "h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=", + version = "v1.11.3", + ) go_repository( name = "com_github_fsnotify_fsnotify", @@ -442,13 +460,6 @@ def go_repositories(): version = "v0.0.0-20160704191624-1d0bd113de87", ) - go_repository( - name = "com_github_go_redis_redis_v8", - importpath = "github.com/go-redis/redis/v8", - sum = "h1:A1tQgdeVF23Ojc1TIRpVuVfOadUdIM0vFVURigoPEMM=", - version = "v8.2.2", - ) - go_repository( name = "com_github_go_stack_stack", importpath = "github.com/go-stack/stack", @@ -488,6 +499,12 @@ def go_repositories(): sum = "h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=", version = "v1.4.2", ) + go_repository( + name = "com_github_golang_snappy", + importpath = "github.com/golang/snappy", + sum = "h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=", + version = "v0.0.2", + ) go_repository( name = "com_github_google_btree", @@ -552,6 +569,18 @@ def go_repositories(): sum = "h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=", version = "v0.0.0-20181017120253-0766667cb4d1", ) + go_repository( + name = "com_github_gorilla_securecookie", + importpath = "github.com/gorilla/securecookie", + sum = "h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=", + version = "v1.1.1", + ) + go_repository( + name = "com_github_gorilla_sessions", + importpath = "github.com/gorilla/sessions", + sum = "h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=", + version = "v1.2.1", + ) go_repository( name = "com_github_gorilla_websocket", @@ -652,8 +681,8 @@ def go_repositories(): go_repository( name = "com_github_hashicorp_go_uuid", importpath = "github.com/hashicorp/go-uuid", - sum = "h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=", - version = "v1.0.1", + sum = "h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=", + version = "v1.0.2", ) go_repository( @@ -719,6 +748,43 @@ def go_repositories(): sum = "h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=", version = "v1.0.0", ) + go_repository( + name = "com_github_jcmturner_aescts_v2", + importpath = "github.com/jcmturner/aescts/v2", + sum = "h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=", + version = "v2.0.0", + ) + go_repository( + name = "com_github_jcmturner_dnsutils_v2", + importpath = "github.com/jcmturner/dnsutils/v2", + sum = "h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=", + version = "v2.0.0", + ) + go_repository( + name = "com_github_jcmturner_gofork", + importpath = "github.com/jcmturner/gofork", + sum = "h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=", + version = "v1.0.0", + ) + go_repository( + name = "com_github_jcmturner_goidentity_v6", + importpath = "github.com/jcmturner/goidentity/v6", + sum = "h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=", + version = "v6.0.1", + ) + go_repository( + name = "com_github_jcmturner_gokrb5_v8", + importpath = "github.com/jcmturner/gokrb5/v8", + sum = "h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA=", + version = "v8.4.2", + ) + go_repository( + name = "com_github_jcmturner_rpc_v2", + importpath = "github.com/jcmturner/rpc/v2", + sum = "h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=", + version = "v2.0.3", + ) + go_repository( name = "com_github_jmespath_go_jmespath", importpath = "github.com/jmespath/go-jmespath", @@ -738,6 +804,12 @@ def go_repositories(): sum = "h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=", version = "v0.1.0", ) + go_repository( + name = "com_github_jpillora_backoff", + importpath = "github.com/jpillora/backoff", + sum = "h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=", + version = "v1.0.0", + ) go_repository( name = "com_github_json_iterator_go", @@ -776,6 +848,12 @@ def go_repositories(): sum = "h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=", version = "v1.0.0", ) + go_repository( + name = "com_github_klauspost_compress", + importpath = "github.com/klauspost/compress", + sum = "h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=", + version = "v1.11.7", + ) go_repository( name = "com_github_konsorten_go_windows_terminal_sequences", @@ -805,8 +883,14 @@ def go_repositories(): go_repository( name = "com_github_kr_text", importpath = "github.com/kr/text", - sum = "h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=", - version = "v0.1.0", + sum = "h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=", + version = "v0.2.0", + ) + go_repository( + name = "com_github_linkedin_goavro_v2", + importpath = "github.com/linkedin/goavro/v2", + sum = "h1:Vd++Rb/RKcmNJjM0HP/JJFMEWa21eUBVKPYlKehOGrM=", + version = "v2.9.7", ) go_repository( @@ -821,6 +905,7 @@ def go_repositories(): sum = "h1:TpvdAwDAt1K4ANVOfcihouRdvP+MgAfDWwBuct4l6ZY=", version = "v0.0.0-20160728113105-d5b7844b561a", ) + go_repository( name = "com_github_mattn_go_colorable", importpath = "github.com/mattn/go-colorable", @@ -915,12 +1000,6 @@ def go_repositories(): version = "v0.0.0-20140419014527-cca7078d478f", ) - go_repository( - name = "com_github_nxadm_tail", - importpath = "github.com/nxadm/tail", - sum = "h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=", - version = "v1.4.4", - ) go_repository( name = "com_github_nytimes_gziphandler", importpath = "github.com/NYTimes/gziphandler", @@ -943,14 +1022,14 @@ def go_repositories(): go_repository( name = "com_github_onsi_ginkgo", importpath = "github.com/onsi/ginkgo", - sum = "h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=", - version = "v1.14.1", + sum = "h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=", + version = "v1.11.0", ) go_repository( name = "com_github_onsi_gomega", importpath = "github.com/onsi/gomega", - sum = "h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=", - version = "v1.10.2", + sum = "h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=", + version = "v1.7.0", ) go_repository( @@ -973,6 +1052,12 @@ def go_repositories(): sum = "h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=", version = "v2.0.1+incompatible", ) + go_repository( + name = "com_github_pierrec_lz4", + importpath = "github.com/pierrec/lz4", + sum = "h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A=", + version = "v2.6.0+incompatible", + ) go_repository( name = "com_github_pkg_errors", @@ -1037,6 +1122,18 @@ def go_repositories(): sum = "h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE=", version = "v0.0.0-20160726150825-5bd2802263f2", ) + go_repository( + name = "com_github_rcrowley_go_metrics", + importpath = "github.com/rcrowley/go-metrics", + sum = "h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=", + version = "v0.0.0-20201227073835-cf1acfcdf475", + ) + go_repository( + name = "com_github_riferrei_srclient", + importpath = "github.com/riferrei/srclient", + sum = "h1:uIJhzPXW+suDsEDOZKf4oTZZXTyxtw98cFC70rFzvgU=", + version = "v0.2.1", + ) go_repository( name = "com_github_rogpeppe_fastuuid", @@ -1076,6 +1173,18 @@ def go_repositories(): sum = "h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=", version = "v0.0.0-20170313163322-e2103e2c3529", ) + go_repository( + name = "com_github_shopify_sarama", + importpath = "github.com/Shopify/sarama", + sum = "h1:lOi3SfE6OcFlW9Trgtked2aHNZ2BIG/d6Do+PEUAqqM=", + version = "v1.28.0", + ) + go_repository( + name = "com_github_shopify_toxiproxy", + importpath = "github.com/Shopify/toxiproxy", + sum = "h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=", + version = "v2.1.4+incompatible", + ) go_repository( name = "com_github_shurcool_sanitized_anchor_name", @@ -1161,8 +1270,8 @@ def go_repositories(): go_repository( name = "com_github_stretchr_testify", importpath = "github.com/stretchr/testify", - sum = "h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=", - version = "v1.6.1", + sum = "h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=", + version = "v1.7.0", ) go_repository( name = "com_github_subosito_gotenv", @@ -1202,6 +1311,18 @@ def go_repositories(): sum = "h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648=", version = "v0.0.0-20181204163529-d75b2dcb6bc8", ) + go_repository( + name = "com_github_xdg_scram", + importpath = "github.com/xdg/scram", + sum = "h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=", + version = "v0.0.0-20180814205039-7eeb5667e42c", + ) + go_repository( + name = "com_github_xdg_stringprep", + importpath = "github.com/xdg/stringprep", + sum = "h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=", + version = "v1.0.0", + ) go_repository( name = "com_github_xiang90_probing", @@ -1216,12 +1337,6 @@ def go_repositories(): version = "v0.0.3-0.20170626215501-b2862e3d0a77", ) - go_repository( - name = "com_github_yuin_gopher_lua", - importpath = "github.com/yuin/gopher-lua", - sum = "h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=", - version = "v0.0.0-20191220021717-ab39c6098bdb", - ) go_repository( name = "com_google_cloud_go", importpath = "cloud.google.com/go", @@ -1276,8 +1391,8 @@ def go_repositories(): go_repository( name = "in_gopkg_check_v1", importpath = "gopkg.in/check.v1", - sum = "h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=", - version = "v1.0.0-20190902080502-41f04d3bba15", + sum = "h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=", + version = "v1.0.0-20201130134442-10cb98267c6c", ) go_repository( @@ -1330,8 +1445,8 @@ def go_repositories(): go_repository( name = "in_gopkg_yaml_v3", importpath = "gopkg.in/yaml.v3", - sum = "h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=", - version = "v3.0.0-20200313102051-9f266ea9e77c", + sum = "h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=", + version = "v3.0.0-20210107192922-496545a6307b", ) go_repository( name = "io_etcd_go_bbolt", @@ -1420,13 +1535,6 @@ def go_repositories(): version = "v0.22.2", ) - go_repository( - name = "io_opentelemetry_go_otel", - build_file_proto_mode = "disable", - importpath = "go.opentelemetry.io/otel", - sum = "h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E=", - version = "v0.11.0", - ) go_repository( name = "io_rsc_binaryregexp", importpath = "rsc.io/binaryregexp", @@ -1469,8 +1577,8 @@ def go_repositories(): go_repository( name = "org_golang_x_crypto", importpath = "golang.org/x/crypto", - sum = "h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=", - version = "v0.0.0-20200622213623-75b288015ac9", + sum = "h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=", + version = "v0.0.0-20201221181555-eec23a3978ad", ) go_repository( name = "org_golang_x_exp", @@ -1508,8 +1616,8 @@ def go_repositories(): go_repository( name = "org_golang_x_net", importpath = "golang.org/x/net", - sum = "h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=", - version = "v0.0.0-20201110031124-69a78807bb2b", + sum = "h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=", + version = "v0.0.0-20210119194325-5f4716e94777", ) go_repository( name = "org_golang_x_oauth2", @@ -1521,20 +1629,27 @@ def go_repositories(): go_repository( name = "org_golang_x_sync", importpath = "golang.org/x/sync", - sum = "h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=", - version = "v0.0.0-20190911185100-cd5d95a43a6e", + sum = "h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=", + version = "v0.0.0-20201020160332-67f06af15bc9", ) go_repository( name = "org_golang_x_sys", importpath = "golang.org/x/sys", - sum = "h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=", - version = "v0.0.0-20200930185726-fdedc70b468f", + sum = "h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=", + version = "v0.0.0-20201119102817-f84b799fce68", ) + go_repository( + name = "org_golang_x_term", + importpath = "golang.org/x/term", + sum = "h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=", + version = "v0.0.0-20201126162022-7de9c90e9dd1", + ) + go_repository( name = "org_golang_x_text", importpath = "golang.org/x/text", - sum = "h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=", - version = "v0.3.3", + sum = "h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=", + version = "v0.3.5", ) go_repository( name = "org_golang_x_time", @@ -1552,8 +1667,8 @@ def go_repositories(): go_repository( name = "org_golang_x_xerrors", importpath = "golang.org/x/xerrors", - sum = "h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=", - version = "v0.0.0-20191204190536-9bdfabe68543", + sum = "h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=", + version = "v0.0.0-20200804184101-5ec99f83aff1", ) go_repository( diff --git a/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml b/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml index 919d2d7a2b..7e62ba1eee 100644 --- a/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml +++ b/infrastructure/helm-chart/charts/apps/charts/api/charts/api-admin/templates/deployment.yaml @@ -53,6 +53,16 @@ spec: key: KAFKA_COMMIT_INTERVAL_MS - name: SERVICE_NAME value: api-admin + - name: BEANSTALK_HOSTNAME + valueFrom: + configMapKeyRef: + name: beanstalk-config + key: BEANSTALK_HOSTNAME + - name: BEANSTALK_PORT + valueFrom: + configMapKeyRef: + name: beanstalk-config + key: BEANSTALK_PORT livenessProbe: httpGet: path: /actuator/health diff --git a/infrastructure/helm-chart/charts/apps/charts/api/templates/security.yaml b/infrastructure/helm-chart/charts/apps/charts/api/templates/security.yaml index b8e87081e0..59a13b746f 100644 --- a/infrastructure/helm-chart/charts/apps/charts/api/templates/security.yaml +++ b/infrastructure/helm-chart/charts/apps/charts/api/templates/security.yaml @@ -7,4 +7,5 @@ data: {{- if .Values.systemToken }} systemToken: {{ .Values.systemToken | quote }} {{- end }} + jwtSecret: {{ .Values.jwtSecret | default (randAlphaNum 128) | quote }} allowedOrigins: {{ .Values.allowedOrigins | quote }} diff --git a/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml b/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml index 5d9bec820d..3ca65588d0 100644 --- a/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml +++ b/infrastructure/helm-chart/charts/apps/charts/integration/charts/webhook/templates/deployments.yaml @@ -31,21 +31,36 @@ spec: env: - name: SERVICE_NAME value: webhook-consumer - - name: REDIS_HOSTNAME + - name: BEANSTALK_HOSTNAME valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_HOSTNAME - - name: REDIS_PORT + name: beanstalk-config + key: BEANSTALK_HOSTNAME + - name: BEANSTALK_PORT valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_PORT + name: beanstalk-config + key: BEANSTALK_PORT + - name: KAFKA_BROKERS + valueFrom: + configMapKeyRef: + name: kafka-config + key: KAFKA_BROKERS + - name: KAFKA_SCHEMA_REGISTRY_URL + valueFrom: + configMapKeyRef: + name: kafka-config + key: KAFKA_SCHEMA_REGISTRY_URL - name: WEBHOOK_NAME valueFrom: configMapKeyRef: name: "{{ .Values.component }}" key: name + - name: MAX_BACKOFF_SECONDS + valueFrom: + configMapKeyRef: + name: integration-webhook + key: maxBackoff livenessProbe: httpGet: path: /health @@ -64,13 +79,13 @@ spec: - name: SERVICE_NAME valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_HOSTNAME + name: beanstalkd-config + key: BEANSTALK_HOSTNAME - name: SERVICE_PORT valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_PORT + name: beanstalkd-config + key: BEANSTALK_PORT volumeMounts: - name: provisioning-scripts mountPath: /opt/provisioning @@ -127,16 +142,16 @@ spec: key: KAFKA_COMMIT_INTERVAL_MS - name: SERVICE_NAME value: webhook-publisher - - name: REDIS_HOSTNAME + - name: BEANSTALK_HOSTNAME valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_HOSTNAME - - name: REDIS_PORT + name: beanstalk-config + key: BEANSTALK_HOSTNAME + - name: BEANSTALK_PORT valueFrom: configMapKeyRef: - name: redis-config - key: REDIS_PORT + name: beanstalk-config + key: BEANSTALK_PORT - name: WEBHOOK_NAME valueFrom: configMapKeyRef: diff --git a/infrastructure/helm-chart/charts/beanstalkd/Chart.yaml b/infrastructure/helm-chart/charts/beanstalkd/Chart.yaml new file mode 100644 index 0000000000..5ce8faea3f --- /dev/null +++ b/infrastructure/helm-chart/charts/beanstalkd/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Beanstalkd +name: beanstalkd +version: 1.0 diff --git a/infrastructure/helm-chart/charts/beanstalkd/templates/service.yaml b/infrastructure/helm-chart/charts/beanstalkd/templates/service.yaml new file mode 100644 index 0000000000..5e98901988 --- /dev/null +++ b/infrastructure/helm-chart/charts/beanstalkd/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: beanstalk + namespace: {{ .Values.global.namespace }} +spec: + type: ClusterIP + ports: + - name: client + port: {{ .Values.port }} + targetPort: {{ .Values.port }} + - name: exporter + port: {{ .Values.prometheusExporterPort }} + targetPort: {{ .Values.prometheusExporterPort }} + selector: + app: beanstalkd diff --git a/infrastructure/helm-chart/charts/beanstalkd/templates/statefulset.yaml b/infrastructure/helm-chart/charts/beanstalkd/templates/statefulset.yaml new file mode 100644 index 0000000000..c7563570af --- /dev/null +++ b/infrastructure/helm-chart/charts/beanstalkd/templates/statefulset.yaml @@ -0,0 +1,39 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: beanstalkd + namespace: {{ .Values.global.namespace}} +spec: + serviceName: beanstalkd + replicas: 1 + selector: + matchLabels: + app: beanstalkd + template: + metadata: + labels: + app: beanstalkd + spec: + containers: + - name: beanstalk + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + ports: + - containerPort: {{ .Values.port }} + name: client + - name: beanstalk-exporter + image: "{{ .Values.prometheusExporterImage }}:{{ .Values.prometheusExporterImageTag }}" + resources: + requests: + cpu: 100m + memory: 100Mi + ports: + - containerPort: {{ .Values.prometheusExporterPort }} + name: exporter + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 1Gi diff --git a/infrastructure/helm-chart/charts/beanstalkd/values.yaml b/infrastructure/helm-chart/charts/beanstalkd/values.yaml new file mode 100644 index 0000000000..3d5468c435 --- /dev/null +++ b/infrastructure/helm-chart/charts/beanstalkd/values.yaml @@ -0,0 +1,8 @@ +enabled: true +image: schickling/beanstalkd +imageTag: latest +resources: {} +port: 11300 +prometheusExporterImage: messagebird/beanstalkd_exporter +prometheusExporterImageTag: latest +prometheusExporterPort: 8080 diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl index 1d89a598b5..fe026c0740 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/_helpers.tpl @@ -2,7 +2,7 @@ {{/* Expand the name of the chart. */}} -{{- define "cp-kafka.name" -}} +{{- define "kafka.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -11,7 +11,7 @@ Create a default fully qualified app name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). If release name contains chart name it will be used as a full name. */}} -{{- define "cp-kafka.fullname" -}} +{{- define "kafka.fullname" -}} {{- if .Values.fullnameOverride -}} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} {{- else -}} @@ -27,7 +27,7 @@ If release name contains chart name it will be used as a full name. {{/* Create chart name and version as used by the chart label. */}} -{{- define "cp-kafka.chart" -}} +{{- define "kafka.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -35,8 +35,8 @@ Create chart name and version as used by the chart label. Create a default fully qualified zookeeper name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). */}} -{{- define "cp-kafka.cp-zookeeper.fullname" -}} -{{- $name := default "zookeeper" (index .Values "cp-zookeeper" "nameOverride") -}} +{{- define "kafka.zookeeper.fullname" -}} +{{- $name := default "zookeeper" (index .Values "zookeeper" "nameOverride") -}} {{- printf "%s-headless" $name | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -44,12 +44,12 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this Form the Zookeeper URL. If zookeeper is installed as part of this chart, use k8s service discovery, else use user-provided URL */}} -{{- define "cp-kafka.cp-zookeeper.service-name" }} -{{- if (index .Values "cp-zookeeper" "enabled") -}} -{{- $clientPort := default 2181 (index .Values "cp-zookeeper" "clientPort") | int -}} -{{- printf "%s:%d" (include "cp-kafka.cp-zookeeper.fullname" .) $clientPort }} +{{- define "kafka.zookeeper.service-name" }} +{{- if (index .Values "zookeeper" "enabled") -}} +{{- $clientPort := default 2181 (index .Values "zookeeper" "clientPort") | int -}} +{{- printf "%s:%d" (include "kafka.zookeeper.fullname" .) $clientPort }} {{- else -}} -{{- $zookeeperConnect := printf "%s" (index .Values "cp-zookeeper" "url") }} +{{- $zookeeperConnect := printf "%s" (index .Values "zookeeper" "url") }} {{- $zookeeperConnectOverride := (index .Values "configurationOverrides" "zookeeper.connect") }} {{- default $zookeeperConnect $zookeeperConnectOverride }} {{- end -}} @@ -59,7 +59,7 @@ else use user-provided URL Form the Advertised Listeners. We will use the value of nodeport.firstListenerPort to create the external advertised listeners if configurationOverrides.advertised.listeners is not set. */}} -{{- define "cp-kafka.configuration.advertised.listeners" }} +{{- define "kafka.configuration.advertised.listeners" }} {{- if (index .Values "configurationOverrides" "advertised.listeners") -}} {{- printf ",%s" (first (pluck "advertised.listeners" .Values.configurationOverrides)) }} {{- else -}} @@ -71,8 +71,8 @@ external advertised listeners if configurationOverrides.advertised.listeners is Create a default fully qualified kafka headless name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). */}} -{{- define "cp-kafka.cp-kafka-headless.fullname" -}} -{{- $name := "cp-kafka-headless" -}} +{{- define "kafka.kafka-headless.fullname" -}} +{{- $name := "kafka-headless" -}} {{- printf "%s" $name | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -80,9 +80,14 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this Create a variable containing all the datadirs created. */}} -{{- define "cp-kafka.log.dirs" -}} +{{- define "kafka.log.dirs" -}} {{- range $k, $e := until (.Values.persistence.disksPerBroker|int) -}} {{- if $k}}{{- printf ","}}{{end}} {{- printf "/opt/kafka/data-%d/logs" $k -}} {{- end -}} {{- end -}} + +{{- define "kafka.prometheus.name" -}} +{{- $name := "prometheus-prometheus-kafka-exporter" -}} +{{- printf "%s" $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml index afc113e0fe..c0ed8c0a8f 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/headless-service.yaml @@ -1,18 +1,18 @@ apiVersion: v1 kind: Service metadata: - name: {{ template "cp-kafka.fullname" . }}-headless + name: {{ template "kafka.fullname" . }}-headless namespace: {{ .Values.global.namespace }} labels: - app: {{ template "cp-kafka.name" . }} - chart: {{ template "cp-kafka.chart" . }} + app: {{ template "kafka.name" . }} + chart: {{ template "kafka.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} spec: ports: - - port: 9092 + - port: {{ .Values.port }} name: broker clusterIP: None selector: - app: {{ template "cp-kafka.name" . }} + app: {{ template "kafka.name" . }} release: {{ .Release.Name }} \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/nodeport-service.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/nodeport-service.yaml index 6c439b8270..1395e58323 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/nodeport-service.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/nodeport-service.yaml @@ -1,5 +1,5 @@ {{- if .Values.nodeport.enabled }} - {{- $fullName := include "cp-kafka.fullname" . }} + {{- $fullName := include "kafka.fullname" . }} {{- $brokers := .Values.brokers | int }} {{- $servicePort := .Values.nodeport.servicePort }} {{- $root := . }} @@ -10,11 +10,11 @@ apiVersion: v1 kind: Service metadata: - name: "{{ template "cp-kafka.fullname" $root }}-{{ $i }}-nodeport" + name: "{{ template "kafka.fullname" $root }}-{{ $i }}-nodeport" namespace: {{ $root.Values.global.namespace }} labels: - app: {{ include "cp-kafka.name" $root }} - chart: {{ template "cp-kafka.chart" $root }} + app: {{ include "kafka.name" $root }} + chart: {{ template "kafka.chart" $root }} release: {{ $root.Release.Name }} heritage: {{ $root.Release.Service }} pod: {{ $responsiblePod }} @@ -27,7 +27,7 @@ spec: nodePort: {{ $externalListenerPort }} protocol: TCP selector: - app: {{ include "cp-kafka.name" $root }} + app: {{ include "kafka.name" $root }} release: {{ $root.Release.Name }} statefulset.kubernetes.io/pod-name: {{ $responsiblePod | quote }} {{- end }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/prometheus.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/prometheus.yaml new file mode 100644 index 0000000000..28d5623ea1 --- /dev/null +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/prometheus.yaml @@ -0,0 +1,46 @@ +{{- if .Values.prometheus.enabled }} +{{- if .Capabilities.APIVersions.Has "apps/v1" }} +apiVersion: apps/v1 +{{- else }} +apiVersion: apps/v1beta2 +{{- end }} +kind: Deployment +metadata: + name: {{ template "kafka.prometheus.name" . }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ template "kafka.prometheus.name" . }} + chart: {{ template "kafka.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ template "kafka.prometheus.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "kafka.prometheus.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: prometheus + image: "{{ .Values.prometheus.exporterImage }}:{{ .Values.prometheus.exporterImageTag }}" + command: ["/bin/kafka_exporter"] + args: + - "--kafka.server={{ template "kafka.name" . }}:{{ .Values.port }}" + resources: + requests: + cpu: 100m + memory: 100Mi + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + ports: + - containerPort: {{ .Values.prometheus.exporterPort }} + name: prometheus + volumes: + - name: provisioning-scripts + configMap: + name: provisioning-scripts +{{ end }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml index addfb0bee8..ebd6edba7e 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/service.yaml @@ -1,17 +1,38 @@ apiVersion: v1 kind: Service metadata: - name: {{ template "cp-kafka.fullname" . }} + name: {{ template "kafka.fullname" . }} namespace: {{ .Values.global.namespace }} labels: - app: {{ template "cp-kafka.name" . }} - chart: {{ template "cp-kafka.chart" . }} + app: {{ template "kafka.name" . }} + chart: {{ template "kafka.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} spec: ports: - - port: 9092 + - port: {{ .Values.port }} name: broker selector: - app: {{ template "cp-kafka.name" . }} + app: {{ template "kafka.name" . }} release: {{ .Release.Name }} +--- +{{- if .Values.prometheus.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kafka.prometheus.name" . }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ template "kafka.prometheus.name" . }} + chart: {{ template "kafka.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + core.airy.co/prometheus: {{ template "kafka.name" . }} +spec: + ports: + - port: {{ .Values.prometheus.exporterPort }} + name: prometheus + selector: + app: {{ template "kafka.prometheus.name" . }} + release: {{ .Release.Name }} +{{ end }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml index 0bcd67ca55..11ad7b06be 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/templates/statefulset.yaml @@ -5,21 +5,21 @@ apiVersion: apps/v1beta1 {{- end }} kind: StatefulSet metadata: - name: {{ template "cp-kafka.fullname" . }} + name: {{ template "kafka.fullname" . }} namespace: {{ .Values.global.namespace }} labels: - app: {{ template "cp-kafka.name" . }} - chart: {{ template "cp-kafka.chart" . }} + app: {{ template "kafka.name" . }} + chart: {{ template "kafka.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} spec: {{- if .Capabilities.APIVersions.Has "apps/v1" }} selector: matchLabels: - app: {{ template "cp-kafka.name" . }} + app: {{ template "kafka.name" . }} release: {{ .Release.Name }} {{- end }} - serviceName: {{ template "cp-kafka.fullname" . }}-headless + serviceName: {{ template "kafka.fullname" . }}-headless podManagementPolicy: {{ .Values.podManagementPolicy }} replicas: {{ default 3 .Values.brokers }} updateStrategy: @@ -27,7 +27,7 @@ spec: template: metadata: labels: - app: {{ template "cp-kafka.name" . }} + app: {{ template "kafka.name" . }} release: {{ .Release.Name }} spec: affinity: @@ -40,18 +40,18 @@ spec: - key: "app" operator: In values: - - {{ template "cp-kafka.name" . }} + - {{ template "kafka.name" . }} - key: "release" operator: In values: - {{ .Release.Name }} topologyKey: "kubernetes.io/hostname" containers: - - name: {{ template "cp-kafka.name" . }}-broker + - name: {{ template "kafka.name" . }}-broker image: "{{ .Values.image }}:{{ .Values.imageTag }}" imagePullPolicy: "{{ .Values.imagePullPolicy }}" ports: - - containerPort: 9092 + - containerPort: {{ .Values.port }} name: kafka {{- if .Values.nodeport.enabled }} {{- $brokers := .Values.brokers | int }} @@ -83,13 +83,13 @@ spec: - name: AIRY_LISTENERS value: PLAINTEXT://0.0.0.0:9092,EXTERNAL://0.0.0.0:AIRY_BROKER_PORT - name: AIRY_ADVERTISED_LISTENERS - value: PLAINTEXT://AIRY_POD_NAME.{{ template "cp-kafka.fullname" . }}-headless.AIRY_NAMESPACE:9092,EXTERNAL://AIRY_HOST_IP:AIRY_BROKER_PORT + value: PLAINTEXT://AIRY_POD_NAME.{{ template "kafka.fullname" . }}-headless.AIRY_NAMESPACE:9092,EXTERNAL://AIRY_HOST_IP:AIRY_BROKER_PORT - name: AIRY_FIRST_LISTENER_PORT value: "{{ .Values.firstListenerPort }}" - name: KAFKA_HEAP_OPTS value: {{ .Values.heapOptions }} - name: KAFKA_ZOOKEEPER_CONNECT - value: {{ include "cp-kafka.cp-zookeeper.service-name" . | quote }} + value: {{ include "kafka.zookeeper.service-name" . | quote }} {{- range $key, $value := .Values.configurationOverrides }} - name: {{ printf "KAFKA_%s" $key | replace "." "_" | upper | quote }} value: {{ $value | quote }} diff --git a/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml b/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml index 5a0fc937ab..86ac2ef849 100644 --- a/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml +++ b/infrastructure/helm-chart/charts/kafka/charts/kafka/values.yaml @@ -10,6 +10,7 @@ configurationOverrides: "log.retention.hours": "-1" "listener.security.protocol.map": |- PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT +port: 9092 firstListenerPort: 31090 persistence: enabled: true @@ -24,7 +25,7 @@ nodeport: enabled: true servicePort: 19092 firstListenerPort: 31090 -cp-zookeeper: +zookeeper: enabled: true servers: 1 persistence: @@ -32,3 +33,8 @@ cp-zookeeper: dataDirSize: 5Gi dataLogDirSize: 5Gi url: "" +prometheus: + enabled: false + exporterImage: danielqsj/kafka-exporter + exporterImageTag: v1.3.0 + exporterPort: 9308 diff --git a/infrastructure/helm-chart/charts/prerequisites/templates/beanstalk.yaml b/infrastructure/helm-chart/charts/prerequisites/templates/beanstalk.yaml new file mode 100644 index 0000000000..e16f2f2879 --- /dev/null +++ b/infrastructure/helm-chart/charts/prerequisites/templates/beanstalk.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: beanstalk-config + namespace: {{ .Values.global.namespace }} +data: + BEANSTALK_HOSTNAME: {{ .Values.beanstalk.hostname }} + BEANSTALK_PORT: "{{ .Values.beanstalk.port }}" diff --git a/infrastructure/helm-chart/charts/prerequisites/templates/redis.yaml b/infrastructure/helm-chart/charts/prerequisites/templates/redis.yaml deleted file mode 100644 index 91182856ab..0000000000 --- a/infrastructure/helm-chart/charts/prerequisites/templates/redis.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: redis-config - namespace: {{ .Values.global.namespace }} -data: - REDIS_HOSTNAME: {{ .Values.redis.hostname }} - REDIS_PORT: "{{ .Values.redis.port }}" diff --git a/infrastructure/helm-chart/charts/prerequisites/values.yaml b/infrastructure/helm-chart/charts/prerequisites/values.yaml index 42fa8da1e8..90f41358c7 100644 --- a/infrastructure/helm-chart/charts/prerequisites/values.yaml +++ b/infrastructure/helm-chart/charts/prerequisites/values.yaml @@ -3,6 +3,6 @@ kafka: zookeeper: "zookeeper:2181" schemaRegistryUrl: "http://schema-registry:8081" commitInterval: 1000 -redis: - hostname: "redis-cluster" - port: 6379 +beanstalk: + hostname: "beanstalk" + port: 11300 \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/Chart.yaml b/infrastructure/helm-chart/charts/redis/Chart.yaml deleted file mode 100644 index 5e07ff4c78..0000000000 --- a/infrastructure/helm-chart/charts/redis/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0" -description: A Helm chart for Redis -name: redis -version: 1.0 \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/templates/configmap.yaml b/infrastructure/helm-chart/charts/redis/templates/configmap.yaml deleted file mode 100644 index 01abc80ee8..0000000000 --- a/infrastructure/helm-chart/charts/redis/templates/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: redis-cluster - namespace: {{ .Values.global.namespace }} -data: - update-node.sh: | - #!/bin/sh - REDIS_NODES="/data/nodes.conf" - sed -i -e "/myself/ s/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/${POD_IP}/" ${REDIS_NODES} - exec "$@" - redis.conf: |+ - cluster-enabled no - cluster-require-full-coverage no - cluster-node-timeout 15000 - cluster-config-file /data/nodes.conf - cluster-migration-barrier 1 - appendonly yes - protected-mode no \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/templates/service.yaml b/infrastructure/helm-chart/charts/redis/templates/service.yaml deleted file mode 100644 index 0df88d88c2..0000000000 --- a/infrastructure/helm-chart/charts/redis/templates/service.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: redis-cluster - namespace: {{ .Values.global.namespace }} -spec: - type: ClusterIP - ports: - - port: 6379 - targetPort: 6379 - name: client - - port: 16379 - targetPort: 16379 - name: gossip - selector: - app: redis-cluster \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/templates/statefulset.yaml b/infrastructure/helm-chart/charts/redis/templates/statefulset.yaml deleted file mode 100644 index 843ca11ca2..0000000000 --- a/infrastructure/helm-chart/charts/redis/templates/statefulset.yaml +++ /dev/null @@ -1,50 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: redis-cluster - namespace: {{ .Values.global.namespace }} -spec: - serviceName: redis-cluster - replicas: 1 - selector: - matchLabels: - app: redis-cluster - template: - metadata: - labels: - app: redis-cluster - spec: - containers: - - name: redis - image: "{{ .Values.image }}:{{ .Values.imageTag }}" - ports: - - containerPort: 6379 - name: client - - containerPort: 16379 - name: gossip - command: ["/conf/update-node.sh", "redis-server", "/conf/redis.conf"] - env: - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - volumeMounts: - - name: conf - mountPath: /conf - readOnly: false - - name: data - mountPath: /data - readOnly: false - volumes: - - name: conf - configMap: - name: redis-cluster - defaultMode: 0755 - volumeClaimTemplates: - - metadata: - name: data - spec: - accessModes: [ "ReadWriteOnce" ] - resources: - requests: - storage: 1Gi \ No newline at end of file diff --git a/infrastructure/helm-chart/charts/redis/values.yaml b/infrastructure/helm-chart/charts/redis/values.yaml deleted file mode 100644 index a1b8ae4caf..0000000000 --- a/infrastructure/helm-chart/charts/redis/values.yaml +++ /dev/null @@ -1,4 +0,0 @@ -enabled: true -image: redis -imageTag: 5.0.1-alpine -resources: {} diff --git a/infrastructure/helm-chart/templates/ingress.yaml b/infrastructure/helm-chart/templates/ingress.yaml index 2624940c1f..6a14186ee3 100644 --- a/infrastructure/helm-chart/templates/ingress.yaml +++ b/infrastructure/helm-chart/templates/ingress.yaml @@ -92,6 +92,20 @@ spec: name: api-communication port: number: 80 + - path: /login + pathType: Prefix + backend: + service: + name: api-admin + port: + number: 80 + - path: /oauth + pathType: Prefix + backend: + service: + name: api-admin + port: + number: 80 - path: /client.config pathType: Prefix backend: @@ -99,6 +113,13 @@ spec: name: api-admin port: number: 80 + - path: /users.getProfile + pathType: Prefix + backend: + service: + name: api-admin + port: + number: 80 - path: /channels.list pathType: Prefix backend: diff --git a/infrastructure/tools/prometheus/values.yaml b/infrastructure/tools/prometheus/values.yaml index 622f7ff6ed..0003857c98 100644 --- a/infrastructure/tools/prometheus/values.yaml +++ b/infrastructure/tools/prometheus/values.yaml @@ -21,6 +21,10 @@ prometheus: paths: ['/prometheus'] prometheusSpec: routePrefix: /prometheus + additionalScrapeConfigs: + - job_name: beanstalkd_exporter + static_configs: + - targets: ['beanstalk:8080'] additionalServiceMonitors: - name: "spring-apps" selector: @@ -32,3 +36,12 @@ prometheus: - port: web interval: 30s path: actuator/prometheus + - name: "kafka" + selector: + matchLabels: + core.airy.co/prometheus: kafka + namespaceSelector: + matchNames: ["default"] + endpoints: + - port: prometheus + interval: 30s diff --git a/lib/java/spring/auth/BUILD b/lib/java/spring/auth/BUILD index 6e8a788b93..64351172e6 100644 --- a/lib/java/spring/auth/BUILD +++ b/lib/java/spring/auth/BUILD @@ -11,6 +11,10 @@ lib_deps = [ "//lib/java/log", "//lib/java/spring/core:spring-core", "@maven//:javax_servlet_javax_servlet_api", + "@maven//:org_springframework_security_spring_security_core", + "@maven//:org_springframework_boot_spring_boot", + "@maven//:org_springframework_security_spring_security_oauth2_client", + "@maven//:org_springframework_boot_spring_boot_autoconfigure", "@maven//:javax_xml_bind_jaxb_api", ] @@ -20,13 +24,14 @@ custom_java_library( visibility = ["//visibility:public"], exports = [ "@maven//:org_springframework_security_spring_security_core", + "@maven//:org_springframework_security_spring_security_oauth2_core", ], deps = lib_deps, ) custom_java_library( name = "test-app", - srcs = ["src/test/java/co/airy/spring/auth/TestApp.java"], + srcs = glob(["src/test/java/co/airy/spring/auth/test_app/*.java"]), deps = lib_deps, ) diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthConfig.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthConfig.java index 5616c07c1b..88704c2213 100644 --- a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthConfig.java +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthConfig.java @@ -1,5 +1,14 @@ package co.airy.spring.auth; +import co.airy.log.AiryLoggerFactory; +import co.airy.spring.auth.oidc.ConfigProvider; +import co.airy.spring.auth.oidc.EmailFilter; +import co.airy.spring.auth.oidc.UserService; +import co.airy.spring.auth.session.AuthCookie; +import co.airy.spring.auth.session.CookieSecurityContextRepository; +import co.airy.spring.auth.session.Jwt; +import co.airy.spring.auth.token.AuthenticationFilter; +import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -9,6 +18,8 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @@ -23,30 +34,59 @@ jsr250Enabled = true ) public class AuthConfig extends WebSecurityConfigurerAdapter { + private static final Logger log = AiryLoggerFactory.getLogger(AuthConfig.class); private final String[] ignoreAuthPatterns; private final String systemToken; + private final String jwtSecret; + private final UserService userService; + private final ConfigProvider configProvider; - public AuthConfig(@Value("${systemToken:#{null}}") String systemToken, List ignorePatternBeans) { + public AuthConfig(@Value("${systemToken:#{null}}") String systemToken, + @Value("${jwtSecret:#{null}}") String jwtSecret, + List ignorePatternBeans, + ConfigProvider configProvider, + UserService userService + ) { this.systemToken = systemToken; + this.jwtSecret = jwtSecret; this.ignoreAuthPatterns = ignorePatternBeans.stream() .flatMap((ignoreAuthPatternBean -> ignoreAuthPatternBean.getIgnorePattern().stream())) .toArray(String[]::new); + this.configProvider = configProvider; + this.userService = userService; } @Override protected void configure(final HttpSecurity http) throws Exception { http.cors().and() .csrf().disable() - // Don't let Spring create its own session - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS); - if (this.systemToken != null) { - http.addFilter(new AuthenticationFilter(authenticationManager(), this.systemToken)) - .authorizeRequests(authorize -> authorize - .antMatchers("/actuator/**", "/ws*").permitAll() - .antMatchers(ignoreAuthPatterns).permitAll() - .anyRequest().authenticated() - ); + if (systemToken != null || configProvider.isPresent()) { + http.authorizeRequests(authorize -> authorize + .antMatchers("/actuator/**").permitAll() + .antMatchers(ignoreAuthPatterns).permitAll() + .anyRequest().authenticated() + ); + + if (systemToken != null) { + log.info("System token auth enabled"); + http.addFilterBefore(new AuthenticationFilter(systemToken), AnonymousAuthenticationFilter.class); + } + + if (configProvider.isPresent()) { + log.info("Oidc auth enabled with provider: {}", configProvider.getRegistration().getRegistrationId()); + http + .securityContext().securityContextRepository(new CookieSecurityContextRepository(new Jwt(jwtSecret))) + .and().logout().permitAll().deleteCookies(AuthCookie.NAME) + .and() + .oauth2Login(oauth2 -> oauth2 + .userInfoEndpoint(userInfo -> userInfo + .userService(this.userService) + )) + .addFilterAfter(new EmailFilter(configProvider), OAuth2LoginAuthenticationFilter.class); + } } } diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/PrincipalAccess.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/PrincipalAccess.java new file mode 100644 index 0000000000..f9219fc1ca --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/PrincipalAccess.java @@ -0,0 +1,38 @@ +package co.airy.spring.auth; + +import co.airy.spring.auth.session.AiryAuth; +import co.airy.spring.auth.session.UserProfile; +import co.airy.spring.auth.token.TokenAuth; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; + +public class PrincipalAccess { + public static final String ANON_PRINCIPAL = "airy-core-anonymous"; + + public static String getUserId(Authentication authentication) { + if (authentication == null) { + return ANON_PRINCIPAL; + } + + if (authentication instanceof TokenAuth) { + return ((TokenAuth) authentication).getPrincipal(); + } + + final UserProfile userProfile = getUserProfile(authentication); + if (userProfile == null) { + throw new IllegalStateException("Unknown authentication type"); + } + + return userProfile.getId(); + } + + public static UserProfile getUserProfile(Authentication authentication) { + if (authentication instanceof OAuth2AuthenticationToken) { + return UserProfile.from((OAuth2AuthenticationToken) authentication); + } else if (authentication instanceof AiryAuth) { + return ((AiryAuth) authentication).getPrincipal(); + } + + return null; + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ClientConfig.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ClientConfig.java new file mode 100644 index 0000000000..a46c2b4ec8 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ClientConfig.java @@ -0,0 +1,41 @@ +package co.airy.spring.auth.oidc; + +import co.airy.spring.auth.oidc.github.GithubApi; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; +import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository; +import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; + +@Configuration +public class ClientConfig { + @Bean + @ConditionalOnProperty({"oidc.provider", "oidc.allowedEmailPatterns"}) + public ClientRegistrationRepository clientRegistrationRepository(ConfigProvider config) { + return new InMemoryClientRegistrationRepository(config.getRegistration()); + } + + @Bean + @ConditionalOnBean(ClientRegistrationRepository.class) + public OAuth2AuthorizedClientService authorizedClientService( + ClientRegistrationRepository clientRegistrationRepository) { + return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository); + } + + @Bean + @ConditionalOnBean(OAuth2AuthorizedClientService.class) + public OAuth2AuthorizedClientRepository authorizedClientRepository( + OAuth2AuthorizedClientService authorizedClientService) { + return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService); + } + + @Bean + public UserService userService(GithubApi githubApi) { + return new UserService(githubApi); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/CommonProviders.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/CommonProviders.java new file mode 100644 index 0000000000..f7f1a77fff --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/CommonProviders.java @@ -0,0 +1,90 @@ +package co.airy.spring.auth.oidc; + +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; +import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; + +/** + * Customized presets adapted from + * org.springframework.security.config.oauth2.client.CommonOAuth2Provider + */ +public enum CommonProviders { + + GOOGLE { + @Override + public ClientRegistration.Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.BASIC, + DEFAULT_REDIRECT_URL); + builder.scope("openid", "profile", "email"); + builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth"); + builder.tokenUri("https://www.googleapis.com/oauth2/v4/token"); + builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs"); + builder.issuerUri("https://accounts.google.com"); + builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo"); + builder.userNameAttributeName(IdTokenClaimNames.SUB); + builder.clientName("Google"); + return builder; + } + + }, + + GITHUB { + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.BASIC, + DEFAULT_REDIRECT_URL); + builder.scope("read:user", "user:email"); + builder.authorizationUri("https://github.com/login/oauth/authorize"); + builder.tokenUri("https://github.com/login/oauth/access_token"); + builder.userInfoUri("https://api.github.com/user"); + builder.userNameAttributeName("id"); + builder.clientName("GitHub"); + return builder; + } + + }, + + FACEBOOK { + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.POST, + DEFAULT_REDIRECT_URL); + builder.scope("public_profile", "email"); + builder.authorizationUri("https://www.facebook.com/v2.8/dialog/oauth"); + builder.tokenUri("https://graph.facebook.com/v2.8/oauth/access_token"); + builder.userInfoUri("https://graph.facebook.com/me?fields=id,name,email"); + builder.userNameAttributeName("id"); + builder.clientName("Facebook"); + return builder; + } + + }, + + OKTA { + @Override + public Builder getBuilder(String registrationId) { + ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.BASIC, + DEFAULT_REDIRECT_URL); + builder.scope("openid", "profile", "email"); + builder.userNameAttributeName(IdTokenClaimNames.SUB); + builder.clientName("Okta"); + return builder; + } + + }; + + private static final String DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}"; + + protected final ClientRegistration.Builder getBuilder(String registrationId, ClientAuthenticationMethod method, + String redirectUri) { + ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(registrationId); + builder.clientAuthenticationMethod(method); + builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE); + builder.redirectUri(redirectUri); + return builder; + } + + public abstract ClientRegistration.Builder getBuilder(String registrationId); +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ConfigProvider.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ConfigProvider.java new file mode 100644 index 0000000000..19e242572c --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/ConfigProvider.java @@ -0,0 +1,83 @@ +package co.airy.spring.auth.oidc; + +import lombok.Getter; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Component +public class ConfigProvider { + @Getter + private ClientRegistration registration; + private List> emailMatchers; + + public ConfigProvider(UserProperties props) { + if (props.getProvider() == null || props.getAllowedEmailPatterns() == null) { + return; + } + + ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(props.getProvider()); + try { + final CommonProviders commonProvider = CommonProviders.valueOf(props.getProvider().toUpperCase()); + builder = commonProvider.getBuilder(props.getProvider()); + } catch (Exception expected) { + // not a common oauth provider + } + + builder.clientId(props.getClientId()).clientSecret(props.getClientSecret()); + + if (props.getClientAuthenticationMethod() != null) { + builder.clientAuthenticationMethod(props.getClientAuthenticationMethod()); + } + if (props.getAuthorizationGrantType() != null) { + builder.authorizationGrantType(props.getAuthorizationGrantType()); + } + if (props.getAuthorizationUri() != null) { + builder.authorizationUri(props.getAuthorizationUri()); + } + if (props.getTokenUri() != null) { + builder.tokenUri(props.getTokenUri()); + } + if (props.getUserInfoUri() != null) { + builder.userInfoUri(props.getUserInfoUri()); + } + if (props.getUserInfoAuthenticationMethod() != null) { + builder.userInfoAuthenticationMethod(props.getUserInfoAuthenticationMethod()); + } + if (props.getUserNameAttributeName() != null) { + builder.userNameAttributeName(props.getUserNameAttributeName()); + } + if (props.getIssuerUri() != null) { + builder.issuerUri(props.getIssuerUri()); + } + if (props.getJwkSetUri() != null) { + builder.jwkSetUri(props.getJwkSetUri()); + } + if (props.getScope() != null) { + builder.scope(props.getScope()); + } + + registration = builder.build(); + + emailMatchers = Arrays.stream(props.getAllowedEmailPatterns().split(",")) + .map(this::regexFromWildcard).map(Pattern::asMatchPredicate).collect(Collectors.toList()); + } + + private Pattern regexFromWildcard(String pattern) { + final String s = pattern.replaceAll("\\*", ".*"); + return Pattern.compile(s); + } + + public boolean isPresent() { + return emailMatchers != null && registration != null; + } + + public boolean emailMatches(String email) { + return emailMatchers.stream().anyMatch((matches) -> matches.test(email)); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/EmailFilter.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/EmailFilter.java new file mode 100644 index 0000000000..8fbd609670 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/EmailFilter.java @@ -0,0 +1,58 @@ +package co.airy.spring.auth.oidc; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class EmailFilter extends OncePerRequestFilter { + private final ConfigProvider configProvider; + + public EmailFilter(ConfigProvider config) { + this.configProvider = config; + } + + @Override + protected void doFilterInternal(HttpServletRequest req, + HttpServletResponse res, + FilterChain chain) throws IOException, ServletException { + final Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth instanceof OAuth2AuthenticationToken) { + final OAuth2User user = ((OAuth2AuthenticationToken) auth).getPrincipal(); + final List emails = getEmails(user); + + + if (emails.stream().noneMatch(configProvider::emailMatches)) { + res.sendError(403, "Email not allowed"); + return; + } + } + + chain.doFilter(req, res); + } + + private List getEmails(OAuth2User user) { + final ArrayList emails = new ArrayList<>(); + + final Map attrs = user.getAttributes(); + Optional.ofNullable(attrs.get("email")) + .ifPresent((email) -> emails.add((String) email)); + + Optional.ofNullable(attrs.get("emails")) + .ifPresent((allEmails) -> emails.addAll((Collection) allEmails)); + + return emails; + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserProperties.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserProperties.java new file mode 100644 index 0000000000..9bf231728a --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserProperties.java @@ -0,0 +1,58 @@ +package co.airy.spring.auth.oidc; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.security.oauth2.core.AuthenticationMethod; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.core.ClientAuthenticationMethod; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +@Data +@Component +@ConfigurationProperties(prefix = "oidc") +public class UserProperties { + private String allowedEmailPatterns; + private String provider; + private String clientId; + private String clientSecret; + + // Config values for manual provider configuration + private String clientAuthenticationMethod; + public ClientAuthenticationMethod getClientAuthenticationMethod() { + return Optional.ofNullable(clientAuthenticationMethod).map(ClientAuthenticationMethod::new).orElse(null); + } + + private String authorizationGrantType; + public AuthorizationGrantType getAuthorizationGrantType() { + return Optional.ofNullable(authorizationGrantType).map(AuthorizationGrantType::new).orElse(null); + } + + private String authorizationUri; + private String tokenUri; + private String userInfoUri; + + private String userInfoAuthenticationMethod; + public AuthenticationMethod getUserInfoAuthenticationMethod() { + return Optional.ofNullable(userInfoAuthenticationMethod).map(AuthenticationMethod::new).orElse(null); + } + + private String userNameAttributeName; + private String issuerUri; + private String jwkSetUri; + + private String scope; + + public Collection getScope() { + if (scope == null) { + return null; + } + + return Arrays.asList(scope.split(",")); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserService.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserService.java new file mode 100644 index 0000000000..102dac84fa --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/UserService.java @@ -0,0 +1,52 @@ +package co.airy.spring.auth.oidc; + +import co.airy.spring.auth.oidc.github.EmailsResponse; +import co.airy.spring.auth.oidc.github.GithubApi; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.user.DefaultOAuth2User; +import org.springframework.security.oauth2.core.user.OAuth2User; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.util.stream.Collectors.toList; + +public class UserService implements OAuth2UserService { + private final GithubApi githubApi; + private final DefaultOAuth2UserService userService = new DefaultOAuth2UserService(); + + public UserService(GithubApi githubApi) { + this.githubApi = githubApi; + } + + public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { + OAuth2User user = userService.loadUser(userRequest); + + // Github does not return a user's email by default + if ("github".equals(userRequest.getClientRegistration().getRegistrationId())) { + user = addGithubEmails(user, userRequest); + } + + return user; + } + + private OAuth2User addGithubEmails(OAuth2User user, OAuth2UserRequest userRequest) { + try { + final List userEmails = this.githubApi.getUserEmails(userRequest.getAccessToken().getTokenValue()); + + final Map attributes = new HashMap<>(user.getAttributes()); + attributes.put("emails", userEmails.stream().map(EmailsResponse::getEmail).collect(toList())); + + return new DefaultOAuth2User(user.getAuthorities(), attributes, userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint() + .getUserNameAttributeName()); + } catch (Exception e) { + throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INSUFFICIENT_SCOPE), e.getMessage()); + } + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/EmailsResponse.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/EmailsResponse.java new file mode 100644 index 0000000000..be96b4ce50 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/EmailsResponse.java @@ -0,0 +1,10 @@ +package co.airy.spring.auth.oidc.github; + +import lombok.Data; + +@Data +public class EmailsResponse { + private String email; + private Boolean primary; + private Boolean verified; +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/GithubApi.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/GithubApi.java new file mode 100644 index 0000000000..4dc2d036d6 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/oidc/github/GithubApi.java @@ -0,0 +1,49 @@ +package co.airy.spring.auth.oidc.github; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.ApplicationListener; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; +import java.util.Collections; +import java.util.List; + +@Component +public class GithubApi implements ApplicationListener { + private RestTemplate restTemplate; + private final RestTemplateBuilder restTemplateBuilder; + private final ObjectMapper objectMapper = new ObjectMapper(); + private final URI githubEmailUri = URI.create("https://api.github.com/user/emails"); + + public GithubApi(RestTemplateBuilder restTemplateBuilder) { + this.restTemplateBuilder = restTemplateBuilder; + } + + public List getUserEmails(String accessToken) { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.setBearerAuth(accessToken); + + RequestEntity> request = new RequestEntity<>(headers, HttpMethod.GET, githubEmailUri); + ResponseEntity> response = restTemplate.exchange(request, new ParameterizedTypeReference>() { + }); + return response.getBody(); + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + restTemplate = restTemplateBuilder + .additionalMessageConverters(new MappingJackson2HttpMessageConverter(objectMapper)) + .build(); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AiryAuth.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AiryAuth.java new file mode 100644 index 0000000000..39d0138b24 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AiryAuth.java @@ -0,0 +1,53 @@ +package co.airy.spring.auth.session; + +import lombok.NoArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; + +import java.io.Serializable; +import java.util.Collection; + +@NoArgsConstructor +public class AiryAuth implements Authentication, Serializable { + private UserProfile userProfile; + private boolean isAuthenticated = true; + + public AiryAuth(UserProfile userProfile) { + this.userProfile = userProfile; + } + + @Override + public Collection getAuthorities() { + return null; + } + + @Override + public Object getCredentials() { + return null; + } + + @Override + public Object getDetails() { + return null; + } + + @Override + public UserProfile getPrincipal() { + return userProfile; + } + + @Override + public boolean isAuthenticated() { + return this.isAuthenticated; + } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + this.isAuthenticated = true; + } + + @Override + public String getName() { + return userProfile.getId(); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AuthCookie.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AuthCookie.java new file mode 100644 index 0000000000..197cfc59cf --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/AuthCookie.java @@ -0,0 +1,14 @@ +package co.airy.spring.auth.session; + +import javax.servlet.http.Cookie; + +public class AuthCookie extends Cookie { + public static String NAME = "airy_auth_token"; + private static final String PATH = "/"; + + public AuthCookie(String value) { + super(NAME, value); + this.setPath(PATH); + this.setHttpOnly(true); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/CookieSecurityContextRepository.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/CookieSecurityContextRepository.java new file mode 100644 index 0000000000..3a49068457 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/CookieSecurityContextRepository.java @@ -0,0 +1,117 @@ +package co.airy.spring.auth.session; + +import co.airy.log.AiryLoggerFactory; +import com.fasterxml.jackson.core.JsonProcessingException; +import org.slf4j.Logger; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.web.context.HttpRequestResponseHolder; +import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper; +import org.springframework.security.web.context.SecurityContextRepository; +import org.springframework.web.util.WebUtils; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Optional; +import java.util.stream.Stream; + +import static co.airy.spring.auth.PrincipalAccess.getUserProfile; + +/** + * Spring's default session store attaches a session id and stores the security context in memory. + *

+ * We prefer to store the authentication state on the client, which allows us to authenticate users + * against any Spring app without the need for them to maintain another datastore. + */ +public class CookieSecurityContextRepository implements SecurityContextRepository { + private static final Logger log = AiryLoggerFactory.getLogger(CookieSecurityContextRepository.class); + private final Jwt jwt; + + public CookieSecurityContextRepository(Jwt jwt) { + this.jwt = jwt; + } + + @Override + public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) { + HttpServletRequest request = requestResponseHolder.getRequest(); + HttpServletResponse response = requestResponseHolder.getResponse(); + requestResponseHolder.setResponse(new SaveToCookieResponseWrapper(request, response)); + + SecurityContext context = SecurityContextHolder.createEmptyContext(); + getStoredAuth(request) + .ifPresent(context::setAuthentication); + + return context; + } + + @Override + public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) { + SaveToCookieResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, + SaveToCookieResponseWrapper.class); + if (responseWrapper != null && !responseWrapper.isContextSaved()) { + responseWrapper.saveContext(context); + } + } + + @Override + public boolean containsContext(HttpServletRequest request) { + return getStoredAuth(request).isPresent(); + } + + private Optional getStoredAuth(HttpServletRequest request) { + return getCookie(request) + .map((authCookie) -> { + try { + return jwt.loadFromToken(authCookie.getValue()); + } catch (Exception e) { + log.warn("Clearing user session because token could not be decoded", e); + return null; + } + }); + } + + private Optional getCookie(HttpServletRequest request) { + if (request.getCookies() == null) { + return Optional.empty(); + } + + return Stream.of(request.getCookies()) + .filter(c -> AuthCookie.NAME.equals(c.getName()) && !c.getValue().equals("")) + .findFirst(); + } + + private class SaveToCookieResponseWrapper extends SaveContextOnUpdateOrErrorResponseWrapper { + private final HttpServletRequest request; + + SaveToCookieResponseWrapper(HttpServletRequest request, HttpServletResponse response) { + super(response, true); + this.request = request; + } + + @Override + protected void saveContext(SecurityContext securityContext) { + HttpServletResponse response = (HttpServletResponse) getResponse(); + Authentication authentication = securityContext.getAuthentication(); + + if (authentication instanceof OAuth2AuthenticationToken) { + try { + // Exchange the oauth2 session for an Airy JWT cookie session + final UserProfile profile = getUserProfile(authentication); + final AiryAuth airyAuth = new AiryAuth(profile); + + AuthCookie cookie = new AuthCookie(jwt.getAuthToken(airyAuth)); + cookie.setSecure(request.isSecure()); + response.addCookie(cookie); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } else if (authentication == null || !authentication.isAuthenticated()) { + // Remove the cookie if there is no auth present + response.addCookie(new AuthCookie("")); + } + } + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/Jwt.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/Jwt.java new file mode 100644 index 0000000000..039851d40b --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/Jwt.java @@ -0,0 +1,65 @@ +package co.airy.spring.auth.session; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +import javax.crypto.spec.SecretKeySpec; +import javax.xml.bind.DatatypeConverter; +import java.security.Key; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class Jwt { + public static final String PRINCIPAL_CLAIM = "principal"; + private final ObjectMapper objectMapper; + private final Key signingKey; + + public Jwt(String tokenKey) { + this.signingKey = parseSigningKey(tokenKey); + this.objectMapper = new ObjectMapper(); + } + + public String getAuthToken(AiryAuth auth) throws JsonProcessingException { + Date now = Date.from(Instant.now()); + + Map claims = new HashMap<>(); + claims.put(PRINCIPAL_CLAIM, objectMapper.writeValueAsString(auth.getPrincipal())); + + JwtBuilder builder = Jwts.builder() + .setId(UUID.randomUUID().toString()) + .setSubject(auth.getPrincipal().getName()) + .setIssuedAt(now) + .addClaims(claims) + .signWith(signingKey, SignatureAlgorithm.HS256); + + Date exp = Date.from(Instant.now().plus(Duration.ofDays(30))); + builder.setExpiration(exp); + + return builder.compact(); + } + + public AiryAuth loadFromToken(final String authHeader) throws Exception { + Claims claims = extractClaims(authHeader); + final String principalClaim = (String) claims.get(PRINCIPAL_CLAIM); + final UserProfile profile = objectMapper.readValue(principalClaim, UserProfile.class); + return new AiryAuth(profile); + } + + + private Key parseSigningKey(String tokenKey) { + byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(tokenKey); + return new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName()); + } + + private Claims extractClaims(String token) { + return Jwts.parser().setSigningKey(signingKey).parseClaimsJws(token).getBody(); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/UserProfile.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/UserProfile.java new file mode 100644 index 0000000000..f7643ce50a --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/session/UserProfile.java @@ -0,0 +1,34 @@ +package co.airy.spring.auth.session; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.security.core.AuthenticatedPrincipal; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.core.oidc.OidcUserInfo; +import org.springframework.security.oauth2.core.oidc.user.OidcUser; +import org.springframework.security.oauth2.core.user.OAuth2User; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserProfile implements AuthenticatedPrincipal { + private String id; + private String name; + private String avatarUrl; + + public static UserProfile from(OAuth2AuthenticationToken auth) { + final OAuth2User user = auth.getPrincipal(); + + // e.g. github:4403838 + if (user instanceof OidcUser) { + final String id = String.format("%s:%s", auth.getAuthorizedClientRegistrationId(), + user.getName()); + return new UserProfile(id, ((OidcUser) user).getFullName(), ((OidcUser) user).getPicture()); + } + + final String id = String.format("%s:%s", auth.getAuthorizedClientRegistrationId(), + user.getAttribute("id")); + return new UserProfile(id, user.getAttribute("name"), user.getAttribute("avatar_url")); + } +} diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthenticationFilter.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/AuthenticationFilter.java similarity index 54% rename from lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthenticationFilter.java rename to lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/AuthenticationFilter.java index 4c024c6652..9608de905e 100644 --- a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/AuthenticationFilter.java +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/AuthenticationFilter.java @@ -1,26 +1,20 @@ -package co.airy.spring.auth; +package co.airy.spring.auth.token; import org.springframework.http.HttpHeaders; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.List; -public class AuthenticationFilter extends BasicAuthenticationFilter { +public class AuthenticationFilter extends OncePerRequestFilter { private final String systemToken; - private final String systemTokenPrincipal; - public AuthenticationFilter(AuthenticationManager authManager, String systemToken) { - super(authManager); + public AuthenticationFilter(String systemToken) { this.systemToken = systemToken; - this.systemTokenPrincipal = systemToken == null ? null : String.format("system-token-%s", systemToken.substring(0, Math.min(systemToken.length(), 4))); } @Override @@ -37,19 +31,20 @@ protected void doFilterInternal(HttpServletRequest req, return; } - UsernamePasswordAuthenticationToken authentication = getAuthentication(authToken); + TokenAuth authentication = getAuthentication(authToken); if (authentication == null) { - res.sendError(HttpServletResponse.SC_FORBIDDEN); + res.sendError(403, "system token does not match"); return; } + authentication.setAuthenticated(true); SecurityContextHolder.getContext().setAuthentication(authentication); chain.doFilter(req, res); } - private UsernamePasswordAuthenticationToken getAuthentication(String token) { + private TokenAuth getAuthentication(String token) { if (systemToken != null && systemToken.equals(token)) { - return new UsernamePasswordAuthenticationToken(systemTokenPrincipal, null, List.of()); + return new TokenAuth(token); } return null; diff --git a/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/TokenAuth.java b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/TokenAuth.java new file mode 100644 index 0000000000..3c4a8b3181 --- /dev/null +++ b/lib/java/spring/auth/src/main/java/co/airy/spring/auth/token/TokenAuth.java @@ -0,0 +1,50 @@ +package co.airy.spring.auth.token; + +import lombok.Data; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; + +import java.util.Collection; +import java.util.List; + +@Data +public class TokenAuth implements Authentication { + private String token; + private String principal; + private boolean isAuthenticated = false; + + public TokenAuth(String token) { + this.principal = String.format("system-token-%s", token.substring(0, Math.min(token.length(), 4))); + } + + @Override + public Collection getAuthorities() { + return List.of(); + } + + @Override + public Object getCredentials() { + return null; + } + + @Override + public Object getDetails() { + return null; + } + + @Override + public boolean isAuthenticated() { + return this.isAuthenticated; + } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + this.isAuthenticated = true; + } + + + @Override + public String getName() { + return principal; + } +} diff --git a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/JwtAuthenticationFilterTest.java b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/AuthenticationTest.java similarity index 87% rename from lib/java/spring/auth/src/test/java/co/airy/spring/auth/JwtAuthenticationFilterTest.java rename to lib/java/spring/auth/src/test/java/co/airy/spring/auth/AuthenticationTest.java index 2809e4f62c..50400616c0 100644 --- a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/JwtAuthenticationFilterTest.java +++ b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/AuthenticationTest.java @@ -20,11 +20,10 @@ @SpringBootTest(properties = { "allowedOrigins=*", "systemToken=user-generated-api-token", - "allowedOrigins=*" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = AirySpringBootApplication.class) @AutoConfigureMockMvc @ExtendWith(SpringExtension.class) -public class JwtAuthenticationFilterTest { +public class AuthenticationTest { @Autowired private MockMvc mvc; @@ -47,15 +46,6 @@ void setsCorsHeaders() throws Exception { .andExpect(header().string("Access-Control-Allow-Origin", origin)); } - @Test - void rejectsInvalidJwt() throws Exception { - mvc.perform(post("/principal.get") - .header(HttpHeaders.AUTHORIZATION, "not a jwt") - ) - .andExpect(status().isForbidden()) - .andExpect(jsonPath("$").doesNotExist()); - } - @Test void authenticatesSystemToken() throws Exception { mvc.perform(post("/principal.get") diff --git a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/NoAuthTest.java b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/NoAuthTest.java new file mode 100644 index 0000000000..e7d24d4bf2 --- /dev/null +++ b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/NoAuthTest.java @@ -0,0 +1,30 @@ +package co.airy.spring.auth; + +import co.airy.spring.core.AirySpringBootApplication; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(properties = { + "allowedOrigins=*", +}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = AirySpringBootApplication.class) +@AutoConfigureMockMvc +@ExtendWith(SpringExtension.class) +public class NoAuthTest { + + @Autowired + private MockMvc mvc; + + @Test + void shouldNotAuthorize() throws Exception { + mvc.perform(post("/data.get")) + .andExpect(status().isOk()); + } +} diff --git a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/OidcTest.java b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/OidcTest.java new file mode 100644 index 0000000000..6da7caea98 --- /dev/null +++ b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/OidcTest.java @@ -0,0 +1,49 @@ +package co.airy.spring.auth; + +import co.airy.spring.core.AirySpringBootApplication; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(properties = { + "systemToken=user-generated-api-token", + "jwtSecret=long-randomly-generated-secret-used-as-jwt-secret-key", + "oidc.provider=github", + "oidc.allowedEmailPatterns=grace@example.com", + "oidc.clientId=oauth-registration-id", + "oidc.clientSecret=oauth-secret" +}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = AirySpringBootApplication.class) +@AutoConfigureMockMvc +@ExtendWith(SpringExtension.class) +public class OidcTest { + + @Autowired + private MockMvc mvc; + + @Test + void redirectsToAuth() throws Exception { + mvc.perform(post("/principal.get")) + .andExpect(status().is3xxRedirection()) + .andExpect(header().exists("Location")) + .andExpect(jsonPath("$").doesNotExist()); + } + + @Test + void systemTokenAuthStillWorks() throws Exception { + mvc.perform(post("/principal.get") + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .header(HttpHeaders.AUTHORIZATION, "user-generated-api-token")) + .andExpect(status().isOk()); + } +} diff --git a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/TestApp.java b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/test_app/Controller.java similarity index 79% rename from lib/java/spring/auth/src/test/java/co/airy/spring/auth/TestApp.java rename to lib/java/spring/auth/src/test/java/co/airy/spring/auth/test_app/Controller.java index 4f439aca03..39770072a1 100644 --- a/lib/java/spring/auth/src/test/java/co/airy/spring/auth/TestApp.java +++ b/lib/java/spring/auth/src/test/java/co/airy/spring/auth/test_app/Controller.java @@ -1,4 +1,4 @@ -package co.airy.spring.auth; +package co.airy.spring.auth.test_app; import lombok.AllArgsConstructor; import lombok.Data; @@ -9,13 +9,19 @@ import org.springframework.web.bind.annotation.RestController; @RestController -public class TestApp { +public class Controller { @PostMapping("/principal.get") ResponseEntity echoPrincipal(Authentication authentication) { final String userId = (String) authentication.getPrincipal(); return ResponseEntity.ok(new PrincipalDetails(userId)); } + + + @PostMapping("/data.get") + ResponseEntity getData() { + return ResponseEntity.ok().build(); + } } @Data diff --git a/lib/typescript/httpclient/README.md b/lib/typescript/httpclient/README.md index 9049c8020c..74fc538242 100644 --- a/lib/typescript/httpclient/README.md +++ b/lib/typescript/httpclient/README.md @@ -2,7 +2,8 @@ The HttpClient Library includes a HTTP client for making requests to Airy's API. -The library exports a HttpClient class with public methods that make requests to Airy's API. +The library exports a HttpClient class with public methods that make requests to +Airy's API. To use the library, you need to instantiate the class with an Airy Core API URL. @@ -14,34 +15,3 @@ import {HttpClient} from "httpclient"; const client = new HttpClient("http://airy.core"); client.listChannels().then(channels => console.debug("channels", channels)); ``` - -Here is a list of the public methods the library's class includes: - -CHANNELS - -- listChannels -- exploreChannels -- connectChannel -- disconnectChannel -- connectFacebookChannel -- exploreFacebookChannels - -CONVERSATIONS - -- listConversations -- getConversationInfo -- readConversations -- tagConversation -- untagConversation - -MESSAGES - -- listMessages -- sendMessages - -TAGS - -- listTags -- createTag -- updateTag -- deleteTag diff --git a/lib/typescript/httpclient/src/endpoints/createTag.ts b/lib/typescript/httpclient/src/endpoints/createTag.ts index 6306f1e181..b0d4595698 100644 --- a/lib/typescript/httpclient/src/endpoints/createTag.ts +++ b/lib/typescript/httpclient/src/endpoints/createTag.ts @@ -1,17 +1,3 @@ -import {Tag} from 'model'; - -const tagMapper = { - BLUE: 'tag-blue', - RED: 'tag-red', - GREEN: 'tag-green', - PURPLE: 'tag-purple', -}; - export const createTagDef = { endpoint: 'tags.create', - mapResponse: (response: Tag) => ({ - id: response.id, - name: response.name, - color: tagMapper[response.color] || 'tag-blue', - }), }; diff --git a/lib/typescript/httpclient/src/endpoints/deleteTag.ts b/lib/typescript/httpclient/src/endpoints/deleteTag.ts index 219638ff75..afcb26f045 100644 --- a/lib/typescript/httpclient/src/endpoints/deleteTag.ts +++ b/lib/typescript/httpclient/src/endpoints/deleteTag.ts @@ -1,5 +1,4 @@ export const deleteTagDef = { endpoint: 'tags.delete', mapRequest: id => ({id}), - mapResponse: response => response, }; diff --git a/lib/typescript/httpclient/src/endpoints/listTags.ts b/lib/typescript/httpclient/src/endpoints/listTags.ts index a839a5e76b..095bba761e 100644 --- a/lib/typescript/httpclient/src/endpoints/listTags.ts +++ b/lib/typescript/httpclient/src/endpoints/listTags.ts @@ -1,14 +1,4 @@ -import {Tag} from 'model'; - -const tagMapper = { - BLUE: 'tag-blue', - RED: 'tag-red', - GREEN: 'tag-green', - PURPLE: 'tag-purple', -}; - export const listTagsDef = { endpoint: 'tags.list', - mapResponse: response => - response.data.map((t: Tag) => ({id: t.id, name: t.name, color: tagMapper[t.color] || 'tag-blue'})), + mapResponse: response => response.data, }; diff --git a/lib/typescript/model/Conversation.ts b/lib/typescript/model/Conversation.ts index 8f7d1f52bf..93a9b8f918 100644 --- a/lib/typescript/model/Conversation.ts +++ b/lib/typescript/model/Conversation.ts @@ -19,11 +19,3 @@ export interface Conversation { createdAt: Date; lastMessage: Message; } - -export function getTags(conversation: Conversation) { - return Object.keys(conversation.metadata.tags || {}); -} - -export function getSource(conversation: Conversation) { - return conversation?.channel?.source; -} diff --git a/lib/typescript/model/ConversationFilter.ts b/lib/typescript/model/ConversationFilter.ts index 2382f83c00..6cd3eefde5 100644 --- a/lib/typescript/model/ConversationFilter.ts +++ b/lib/typescript/model/ConversationFilter.ts @@ -6,4 +6,5 @@ export interface ConversationFilter { byTags?: string[]; byChannels?: string[]; bySources?: string[]; + isStateOpen?: boolean; } diff --git a/lib/typescript/model/Source.ts b/lib/typescript/model/Source.ts index 34bb6d5203..33bb5573b1 100644 --- a/lib/typescript/model/Source.ts +++ b/lib/typescript/model/Source.ts @@ -3,5 +3,5 @@ export enum Source { google = 'google', chatPlugin = 'chatplugin', twilioSMS = 'twilio.sms', - twilioWhatsapp = 'twilio.whatsapp', + twilioWhatsApp = 'twilio.whatsapp', } diff --git a/lib/typescript/render/components/Avatar/index.module.scss b/lib/typescript/render/components/Avatar/index.module.scss index 0645713cd9..5dc1dba968 100644 --- a/lib/typescript/render/components/Avatar/index.module.scss +++ b/lib/typescript/render/components/Avatar/index.module.scss @@ -1,13 +1,9 @@ @import 'assets/scss/fonts.scss'; @import 'assets/scss/colors.scss'; -.avatar { - display: flex; - flex-shrink: 0; -} - .avatarImage { border-radius: 50%; width: 100%; height: 100%; + object-fit: cover; } diff --git a/lib/typescript/render/components/Avatar/index.tsx b/lib/typescript/render/components/Avatar/index.tsx index c51441e03f..33f18f7b28 100644 --- a/lib/typescript/render/components/Avatar/index.tsx +++ b/lib/typescript/render/components/Avatar/index.tsx @@ -14,12 +14,10 @@ const fallbackAvatarImage = (event: SyntheticEvent) => }; export const Avatar = ({contact}: AvatarProps) => ( -

- {contact?.displayName) => fallbackAvatarImage(event)} - /> -
+ {contact?.displayName) => fallbackAvatarImage(event)} + /> ); diff --git a/lib/typescript/render/providers/google/GoogleRender.tsx b/lib/typescript/render/providers/google/GoogleRender.tsx index 87e7ff91cc..599371c331 100644 --- a/lib/typescript/render/providers/google/GoogleRender.tsx +++ b/lib/typescript/render/providers/google/GoogleRender.tsx @@ -51,7 +51,7 @@ function render(content: ContentUnion, props: RenderPropsUnion) { } function googleInbound(message: Message): ContentUnion { - const messageJson = message.content.message; + const messageJson = message.content.message ?? message.content; if (messageJson.richCard?.standaloneCard) { const { diff --git a/lib/typescript/websocketclient/index.ts b/lib/typescript/websocketclient/index.ts index 3de16c780c..b40da9ff51 100644 --- a/lib/typescript/websocketclient/index.ts +++ b/lib/typescript/websocketclient/index.ts @@ -1,6 +1,6 @@ import {StompWrapper} from './stompWrapper'; -import {Message, Channel, MetadataEvent} from 'model'; -import {EventPayloadUnion} from './payload'; +import {Message, Channel, MetadataEvent, Tag} from 'model'; +import {EventPayload} from './payload'; /* eslint-disable @typescript-eslint/no-var-requires */ const camelcaseKeys = require('camelcase-keys'); @@ -8,6 +8,7 @@ type CallbackMap = { onMessage?: (conversationId: string, channelId: string, message: Message) => void; onMetadata?: (metadataEvent: MetadataEvent) => void; onChannel?: (channel: Channel) => void; + onTag?: (tag: Tag) => void; onError?: () => void; }; @@ -41,7 +42,7 @@ export class WebSocketClient { }; onEvent = (body: string) => { - const json: EventPayloadUnion = JSON.parse(body) as any; + const json = JSON.parse(body) as EventPayload; switch (json.type) { case 'channel': this.callbackMap.onChannel?.(camelcaseKeys(json.payload, {deep: true, stopPaths: ['metadata.user_data']})); @@ -55,6 +56,9 @@ export class WebSocketClient { case 'metadata': this.callbackMap.onMetadata?.(json.payload); break; + case 'tag': + this.callbackMap.onTag?.(json.payload); + break; default: console.error('Unknown /events payload', json); } diff --git a/lib/typescript/websocketclient/payload.ts b/lib/typescript/websocketclient/payload.ts index 18c989b329..e02c44e46c 100644 --- a/lib/typescript/websocketclient/payload.ts +++ b/lib/typescript/websocketclient/payload.ts @@ -1,27 +1,7 @@ -import {DeliveryState, Metadata, MetadataEvent} from 'model'; +import {DeliveryState, Metadata, MetadataEvent, Tag} from 'model'; interface Event { - type: 'message' | 'channel' | 'metadata'; -} - -interface MessagePayload { - id: string; - content: string; - delivery_state: DeliveryState; - from_contact: boolean; - sent_at: Date; - metadata: any; -} - -interface ChannelPayload { - id: string; - metadata?: Metadata & { - name: string; - image_url?: string; - }; - source: string; - source_channel_id: string; - connected: boolean; + type: 'message' | 'channel' | 'metadata' | 'tag'; } export interface MessageEventPayload extends Event { @@ -29,13 +9,28 @@ export interface MessageEventPayload extends Event { payload: { conversation_id: string; channel_id: string; - message: MessagePayload; + message: { + id: string; + content: string; + delivery_state: DeliveryState; + from_contact: boolean; + sent_at: Date; + }; }; } export interface ChannelEventPayload extends Event { type: 'channel'; - payload: ChannelPayload; + payload: { + id: string; + metadata?: Metadata & { + name: string; + image_url?: string; + }; + source: string; + source_channel_id: string; + connected: boolean; + }; } export interface MetadataEventPayload extends Event { @@ -43,4 +38,9 @@ export interface MetadataEventPayload extends Event { payload: MetadataEvent; } -export type EventPayloadUnion = MessageEventPayload | ChannelEventPayload | MetadataEventPayload; +export interface TagEventPayload extends Event { + type: 'tag'; + payload: Tag; +} + +export type EventPayload = MessageEventPayload | ChannelEventPayload | MetadataEventPayload | TagEventPayload; diff --git a/maven_install.json b/maven_install.json index 47277aeaa7..5b465d261c 100644 --- a/maven_install.json +++ b/maven_install.json @@ -1,6 +1,6 @@ { "dependency_tree": { - "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": 669563076, + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": -1641397329, "conflict_resolution": { "com.fasterxml.jackson.core:jackson-annotations:2.10.0": "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "com.fasterxml.jackson.core:jackson-core:2.10.0": "com.fasterxml.jackson.core:jackson-core:2.11.4", @@ -70,7 +70,7 @@ "com.fasterxml.jackson.core:jackson-core:2.11.4", "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "software.amazon.ion:ion-java:1.0.2", - "commons-codec:commons-codec:1.11", + "commons-codec:commons-codec:1.14", "org.apache.httpcomponents:httpcore:4.4.13", "com.fasterxml.jackson.core:jackson-databind:jar:2.11.4", "joda-time:joda-time:2.10.2", @@ -109,7 +109,7 @@ "com.fasterxml.jackson.core:jackson-core:2.11.4", "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "software.amazon.ion:ion-java:1.0.2", - "commons-codec:commons-codec:1.11", + "commons-codec:commons-codec:1.14", "com.fasterxml.jackson.core:jackson-databind:2.11.4", "org.apache.httpcomponents:httpcore:4.4.13", "com.fasterxml.jackson.core:jackson-databind:jar:2.11.4", @@ -146,7 +146,7 @@ "com.fasterxml.jackson.core:jackson-core:2.11.4", "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "software.amazon.ion:ion-java:1.0.2", - "commons-codec:commons-codec:1.11", + "commons-codec:commons-codec:1.14", "com.fasterxml.jackson.core:jackson-databind:2.11.4", "org.apache.httpcomponents:httpcore:4.4.13", "com.fasterxml.jackson.core:jackson-databind:jar:2.11.4", @@ -222,6 +222,32 @@ "sha256": "6b83846f2ff61d0aaa66997b64b883ec7b65cf13b50a4d7f58250996d429be2e", "url": "https://repo1.maven.org/maven2/com/damnhandy/handy-uri-templates/2.1.8/handy-uri-templates-2.1.8.jar" }, + { + "coord": "com.dinstone:beanstalkc:2.3.0", + "dependencies": [ + "org.slf4j:slf4j-api:1.7.30", + "org.slf4j:slf4j-api:jar:1.7.30", + "org.apache.mina:mina-core:2.1.3" + ], + "directDependencies": [ + "org.apache.mina:mina-core:2.1.3", + "org.slf4j:slf4j-api:jar:1.7.30" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar", + "https://repo1.maven.org/maven2/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar", + "https://jitpack.io/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar" + ], + "sha256": "1e4ff30499ae4229b0aca779ad90e184fa9fbcbbb3ad0bad4fb8beff2ca86b1b", + "url": "https://repo1.maven.org/maven2/com/dinstone/beanstalkc/2.3.0/beanstalkc-2.3.0.jar" + }, { "coord": "com.fasterxml.jackson.core:jackson-annotations:2.11.4", "dependencies": [], @@ -766,6 +792,25 @@ "sha256": "973431c14b4d09a86e23b7184116fcac2d85501eb4a7430f7d185cce1af46050", "url": "https://repo1.maven.org/maven2/com/github/luben/zstd-jni/1.4.5-2/zstd-jni-1.4.5-2.jar" }, + { + "coord": "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "dependencies": [], + "directDependencies": [], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar", + "https://repo1.maven.org/maven2/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar", + "https://jitpack.io/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar" + ], + "sha256": "4fccff8382aafc589962c4edb262f6aa595e34f1e11e61057d1c6a96e8fc7323", + "url": "https://repo1.maven.org/maven2/com/github/stephenc/jcip/jcip-annotations/1.0-1/jcip-annotations-1.0-1.jar" + }, { "coord": "com.google.auth:google-auth-library-credentials:0.20.0", "dependencies": [], @@ -796,9 +841,9 @@ "com.google.code.findbugs:jsr305:3.0.2", "com.google.auto.value:auto-value-annotations:1.7", "com.google.auth:google-auth-library-credentials:0.20.0", - "commons-codec:commons-codec:1.11", "io.opencensus:opencensus-api:0.24.0", "io.grpc:grpc-context:1.22.1", + "commons-codec:commons-codec:1.14", "org.apache.httpcomponents:httpcore:4.4.13", "com.google.http-client:google-http-client-jackson2:1.34.0", "com.google.errorprone:error_prone_annotations:2.3.4", @@ -987,9 +1032,9 @@ "io.opencensus:opencensus-contrib-http-util:0.24.0", "com.fasterxml.jackson.core:jackson-core:2.11.4", "com.google.code.findbugs:jsr305:3.0.2", - "commons-codec:commons-codec:1.11", "io.opencensus:opencensus-api:0.24.0", "io.grpc:grpc-context:1.22.1", + "commons-codec:commons-codec:1.14", "org.apache.httpcomponents:httpcore:4.4.13", "com.google.errorprone:error_prone_annotations:2.3.4", "com.google.http-client:google-http-client:1.34.0", @@ -1025,9 +1070,9 @@ "commons-logging:commons-logging:1.2", "io.opencensus:opencensus-contrib-http-util:0.24.0", "com.google.code.findbugs:jsr305:3.0.2", - "commons-codec:commons-codec:1.11", "io.opencensus:opencensus-api:0.24.0", "io.grpc:grpc-context:1.22.1", + "commons-codec:commons-codec:1.14", "org.apache.httpcomponents:httpcore:4.4.13", "com.google.errorprone:error_prone_annotations:2.3.4", "com.google.guava:failureaccess:1.0.1", @@ -1221,6 +1266,107 @@ "sha256": "2f8dca7b5487d6adda3b47e5584e074eae37a7d85e8aaeb5516ed8d390101d36", "url": "https://repo1.maven.org/maven2/com/kjetland/mbknor-jackson-jsonschema_2.12/1.0.39/mbknor-jackson-jsonschema_2.12-1.0.39.jar" }, + { + "coord": "com.nimbusds:content-type:2.1", + "dependencies": [], + "directDependencies": [], + "exclusions": [ + "org.slf4j:slf4j-log4j12", + "com.sun.mail:javax.mail", + "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/com/nimbusds/content-type/2.1/content-type-2.1.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/nimbusds/content-type/2.1/content-type-2.1.jar", + "https://repo1.maven.org/maven2/com/nimbusds/content-type/2.1/content-type-2.1.jar", + "https://jitpack.io/com/nimbusds/content-type/2.1/content-type-2.1.jar" + ], + "sha256": "f37ae072a89350d42d9508def6a40255f2671e6303da1bb0905d35b83ca48555", + "url": "https://repo1.maven.org/maven2/com/nimbusds/content-type/2.1/content-type-2.1.jar" + }, + { + "coord": "com.nimbusds:lang-tag:1.4.4", + "dependencies": [], + "directDependencies": [], + "exclusions": [ + "org.slf4j:slf4j-log4j12", + "com.sun.mail:javax.mail", + "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar", + "https://repo1.maven.org/maven2/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar", + "https://jitpack.io/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar" + ], + "sha256": "e49d2c694bb80c7036c177f2aabf53b7156061a68bd19dfd60e2bd370709e0c5", + "url": "https://repo1.maven.org/maven2/com/nimbusds/lang-tag/1.4.4/lang-tag-1.4.4.jar" + }, + { + "coord": "com.nimbusds:nimbus-jose-jwt:8.21", + "dependencies": [ + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "net.minidev:json-smart:2.3", + "org.ow2.asm:asm:9.0", + "net.minidev:accessors-smart:1.2" + ], + "directDependencies": [ + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "net.minidev:json-smart:2.3" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar", + "https://repo1.maven.org/maven2/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar", + "https://jitpack.io/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar" + ], + "sha256": "c6225341ea4b2659fb3862dff88c6b1f2fbb7f599ddfe48590bd31d142558dc2", + "url": "https://repo1.maven.org/maven2/com/nimbusds/nimbus-jose-jwt/8.21/nimbus-jose-jwt-8.21.jar" + }, + { + "coord": "com.nimbusds:oauth2-oidc-sdk:8.36.1", + "dependencies": [ + "net.minidev:accessors-smart:1.2", + "org.ow2.asm:asm:9.0", + "com.nimbusds:lang-tag:1.4.4", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", + "com.nimbusds:content-type:2.1", + "net.minidev:json-smart:2.3" + ], + "directDependencies": [ + "com.nimbusds:lang-tag:1.4.4", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", + "com.nimbusds:content-type:2.1", + "net.minidev:json-smart:2.3" + ], + "exclusions": [ + "org.slf4j:slf4j-log4j12", + "com.sun.mail:javax.mail", + "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar", + "https://repo1.maven.org/maven2/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar", + "https://jitpack.io/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar" + ], + "sha256": "e89aaae9300fde54bc36eecb5f78a9a2878552d9ed2cc8781e61b7506588d50a", + "url": "https://repo1.maven.org/maven2/com/nimbusds/oauth2-oidc-sdk/8.36.1/oauth2-oidc-sdk-8.36.1.jar" + }, { "coord": "com.puppycrawl.tools:checkstyle:8.37", "dependencies": [ @@ -1378,6 +1524,29 @@ "sha256": "d84d4ba8b55cdb7fdcbb885e6939386367433f56f5ab8cfdc302a7c3587fa92b", "url": "https://repo1.maven.org/maven2/com/sun/activation/jakarta.activation/1.2.1/jakarta.activation-1.2.1.jar" }, + { + "coord": "com.sun.mail:jakarta.mail:1.6.7", + "dependencies": [ + "com.sun.activation:jakarta.activation:1.2.1" + ], + "directDependencies": [ + "com.sun.activation:jakarta.activation:1.2.1" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar", + "https://repo1.maven.org/maven2/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar", + "https://jitpack.io/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar" + ], + "sha256": "1b258ef45fae93059b65d0a0dd109e59ab93e8cd8a735ff66b2ba85f870d5150", + "url": "https://repo1.maven.org/maven2/com/sun/mail/jakarta.mail/1.6.7/jakarta.mail-1.6.7.jar" + }, { "coord": "com.thoughtworks.paranamer:paranamer:2.8", "dependencies": [], @@ -1580,7 +1749,7 @@ "url": "https://repo1.maven.org/maven2/commons-cli/commons-cli/1.4/commons-cli-1.4.jar" }, { - "coord": "commons-codec:commons-codec:1.11", + "coord": "commons-codec:commons-codec:1.14", "dependencies": [], "directDependencies": [], "exclusions": [ @@ -1589,14 +1758,14 @@ "org.springframework.boot:spring-boot-starter-logging", "org.slf4j:slf4j-log4j12" ], - "file": "v1/https/repo1.maven.org/maven2/commons-codec/commons-codec/1.11/commons-codec-1.11.jar", + "file": "v1/https/repo1.maven.org/maven2/commons-codec/commons-codec/1.14/commons-codec-1.14.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/commons-codec/commons-codec/1.11/commons-codec-1.11.jar", - "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.11/commons-codec-1.11.jar", - "https://jitpack.io/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" + "https://packages.confluent.io/maven/commons-codec/commons-codec/1.14/commons-codec-1.14.jar", + "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.14/commons-codec-1.14.jar", + "https://jitpack.io/commons-codec/commons-codec/1.14/commons-codec-1.14.jar" ], - "sha256": "e599d5318e97aa48f42136a2927e6dfa4e8881dff0e6c8e3109ddbbff51d7b7d", - "url": "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" + "sha256": "a128e4f93fabe5381ded64cf2873019e06030b718eb43ceeae0b0e5d17ad33e9", + "url": "https://repo1.maven.org/maven2/commons-codec/commons-codec/1.14/commons-codec-1.14.jar" }, { "coord": "commons-collections:commons-collections:3.2.2", @@ -2036,6 +2205,7 @@ "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.4", "com.kjetland:mbknor-jackson-jsonschema_2.12:1.0.39", "org.jetbrains.kotlin:kotlin-script-runtime:1.3.50", + "io.netty:netty-transport:4.1.48.Final", "org.ow2.asm:asm-analysis:9.0", "commons-validator:commons-validator:1.6", "javax.xml.bind:jaxb-api:2.3.1", @@ -2083,11 +2253,11 @@ "com.google.re2j:re2j:1.3", "javax.websocket:javax.websocket-client-api:1.0", "org.eclipse.jetty:jetty-xml:9.4.39.v20210325", - "io.netty:netty-buffer:4.1.51.Final", "io.netty:netty-transport-native-epoll:4.1.48.Final", "com.google.code.gson:gson:2.8.6", "com.fasterxml.jackson.core:jackson-databind:2.11.4", "com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.4", + "io.netty:netty-buffer:4.1.48.Final", "io.confluent:common-metrics:5.5.1", "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.71", "io.confluent:kafka-protobuf-provider:5.5.1", @@ -2095,7 +2265,6 @@ "org.eclipse.jetty.websocket:websocket-client:9.4.39.v20210325", "org.glassfish.jersey.core:jersey-server:2.30", "org.eclipse.jetty.websocket:websocket-servlet:9.4.39.v20210325", - "io.netty:netty-codec:4.1.51.Final", "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.71", "org.glassfish.hk2:hk2-utils:2.6.1", "org.apache.avro:avro:1.10.0", @@ -2106,18 +2275,17 @@ "com.google.errorprone:error_prone_annotations:2.3.4", "org.eclipse.jetty:jetty-server:9.4.39.v20210325", "jakarta.annotation:jakarta.annotation-api:1.3.5", - "io.netty:netty-resolver:4.1.51.Final", "org.scala-lang.modules:scala-java8-compat_2.12:0.9.0", - "io.netty:netty-handler:4.1.51.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", "org.eclipse.jetty.websocket:javax-websocket-client-impl:9.4.39.v20210325", + "io.netty:netty-resolver:4.1.48.Final", "org.jetbrains.kotlin:kotlin-stdlib-common:1.3.71", "org.jetbrains.kotlin:kotlin-scripting-jvm:1.3.50", "org.apache.yetus:audience-annotations:0.5.0", + "io.netty:netty-common:4.1.48.Final", "org.json:json:20201115", "org.scala-lang:scala-reflect:2.12.10", "com.damnhandy:handy-uri-templates:2.1.8", - "io.netty:netty-transport:4.1.51.Final", "com.yammer.metrics:metrics-core:2.2.0", "org.glassfish.jersey.ext:jersey-bean-validation:2.30", "org.jetbrains.kotlin:kotlin-stdlib:1.3.71", @@ -2132,6 +2300,7 @@ "org.eclipse.jetty:jetty-jaas:9.4.24.v20191120", "org.hibernate.validator:hibernate-validator:6.0.17.Final", "org.eclipse.jetty:jetty-client:9.4.39.v20210325", + "io.netty:netty-handler:4.1.48.Final", "io.confluent:common-utils:5.5.1", "javax.annotation:javax.annotation-api:1.3.2", "io.confluent:common-config:5.5.1", @@ -2145,10 +2314,10 @@ "com.google.guava:guava:29.0-jre", "org.glassfish.jersey.containers:jersey-container-servlet:2.30", "org.eclipse.jetty.websocket:websocket-common:9.4.39.v20210325", + "io.netty:netty-codec:4.1.48.Final", "com.fasterxml:classmate:1.3.4", "org.eclipse.jetty:jetty-servlet:9.4.39.v20210325", "org.eclipse.jetty:jetty-jndi:9.4.39.v20210325", - "io.netty:netty-common:4.1.51.Final", "org.glassfish:jakarta.el:3.0.3", "io.confluent:kafka-schema-registry-client:5.5.1", "jakarta.activation:jakarta.activation-api:1.2.2", @@ -2531,39 +2700,6 @@ "sha256": "5b5f84f4397c54ab4f6267f95b3c2186d32a5562e6704a0a581401b3ee3a2d0d", "url": "https://repo1.maven.org/maven2/io/jsonwebtoken/jjwt-jackson/0.10.7/jjwt-jackson-0.10.7.jar" }, - { - "coord": "io.lettuce:lettuce-core:5.3.3.RELEASE", - "dependencies": [ - "org.reactivestreams:reactive-streams:1.0.3", - "io.projectreactor:reactor-core:3.3.9.RELEASE", - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-handler:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final" - ], - "directDependencies": [ - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-handler:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.projectreactor:reactor-core:3.3.9.RELEASE" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar", - "https://repo1.maven.org/maven2/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar", - "https://jitpack.io/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar" - ], - "sha256": "0cd01a1cbe881dc7f7b72118e274eaff8cac3865f2258d3389dbe436fb498841", - "url": "https://repo1.maven.org/maven2/io/lettuce/lettuce-core/5.3.3.RELEASE/lettuce-core-5.3.3.RELEASE.jar" - }, { "coord": "io.micrometer:micrometer-core:1.6.6", "dependencies": [ @@ -2618,40 +2754,12 @@ "url": "https://repo1.maven.org/maven2/io/micrometer/micrometer-registry-prometheus/1.6.5/micrometer-registry-prometheus-1.6.5.jar" }, { - "coord": "io.netty:netty-buffer:4.1.51.Final", - "dependencies": [ - "io.netty:netty-common:4.1.51.Final" - ], - "directDependencies": [ - "io.netty:netty-common:4.1.51.Final" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar" - ], - "sha256": "c3c3b710e1b5a8df3d60cd4602e0a743481d5e609e4aa852fa2629e4e412d245", - "url": "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.51.Final/netty-buffer-4.1.51.Final.jar" - }, - { - "coord": "io.netty:netty-codec:4.1.51.Final", + "coord": "io.netty:netty-buffer:4.1.48.Final", "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final" + "io.netty:netty-common:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final" + "io.netty:netty-common:4.1.48.Final" ], "exclusions": [ "*:jline", @@ -2667,50 +2775,51 @@ "ch.qos.logback:logback-classic", "org.springframework.boot:spring-boot-starter-logging" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar" ], - "sha256": "ff741aaa35f7048a6be7c700aa4851bf643917648ea5b7c0cbada2f3848c2bee", - "url": "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.51.Final/netty-codec-4.1.51.Final.jar" + "sha256": "7efc8f98224c703ef09a409e5ddffbe14f5b4b6f527d3836c1647b4d9eff8cec", + "url": "https://repo1.maven.org/maven2/io/netty/netty-buffer/4.1.48.Final/netty-buffer-4.1.48.Final.jar" }, { - "coord": "io.netty:netty-common:4.1.51.Final", - "dependencies": [], - "directDependencies": [], + "coord": "io.netty:netty-codec:4.1.48.Final", + "dependencies": [ + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final" + ], + "directDependencies": [ + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final" + ], "exclusions": [ - "ch.qos.logback:logback-classic", + "javax.jms:jms", + "org.slf4j:slf4j-log4j12", + "junit:junit", "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" + "com.sun.jmx:jmxri", + "com.sun.jdmk:jmxtools", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar" ], - "sha256": "110e06515f43913a2bbac23e1aa78b7f59ae09d466b00af5fcf399a4f9af1b6b", - "url": "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.51.Final/netty-common-4.1.51.Final.jar" + "sha256": "81b4c316163a591b4f74fd2dc23a3ea45359cb817d0a9c4fc7f37dc9edfdbea8", + "url": "https://repo1.maven.org/maven2/io/netty/netty-codec/4.1.48.Final/netty-codec-4.1.48.Final.jar" }, { - "coord": "io.netty:netty-handler:4.1.51.Final", - "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final" - ], - "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final" - ], + "coord": "io.netty:netty-common:4.1.48.Final", + "dependencies": [], + "directDependencies": [], "exclusions": [ "*:jline", "*:netty", @@ -2725,51 +2834,87 @@ "ch.qos.logback:logback-classic", "org.springframework.boot:spring-boot-starter-logging" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar" ], - "sha256": "4461970f04f4d5eb9112ad94255ce1987394ce64de6c3c87690bf0865c936258", - "url": "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.51.Final/netty-handler-4.1.51.Final.jar" + "sha256": "e44a2369566fd1fa8a0f30b12e2801de8fb405b9d1fa3894a58b6262065a9916", + "url": "https://repo1.maven.org/maven2/io/netty/netty-common/4.1.48.Final/netty-common-4.1.48.Final.jar" }, { - "coord": "io.netty:netty-resolver:4.1.51.Final", + "coord": "io.netty:netty-handler:4.1.48.Final", "dependencies": [ - "io.netty:netty-common:4.1.51.Final" + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-codec:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-common:4.1.51.Final" + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-codec:4.1.48.Final" ], "exclusions": [ + "javax.jms:jms", + "org.slf4j:slf4j-log4j12", + "junit:junit", + "org.springframework.boot:spring-boot-starter-tomcat", + "com.sun.jmx:jmxri", + "com.sun.jdmk:jmxtools", "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar" + ], + "sha256": "757f83c7891ad2ebad209f02d8dbca0121e03f7062c2d4ec9d00eba1a0d403d5", + "url": "https://repo1.maven.org/maven2/io/netty/netty-handler/4.1.48.Final/netty-handler-4.1.48.Final.jar" + }, + { + "coord": "io.netty:netty-resolver:4.1.48.Final", + "dependencies": [ + "io.netty:netty-common:4.1.48.Final" + ], + "directDependencies": [ + "io.netty:netty-common:4.1.48.Final" + ], + "exclusions": [ + "org.slf4j:slf4j-log4j12", "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" + "log4j:log4j" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar" ], - "sha256": "c8a77765e481fbf5906c596eb441de49096b354bcae0356b7404ac5e96399350", - "url": "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.51.Final/netty-resolver-4.1.51.Final.jar" + "sha256": "fb125914398ebef821def3dbb1642f9f360f39d182f00149ef3db845ebf06ad2", + "url": "https://repo1.maven.org/maven2/io/netty/netty-resolver/4.1.48.Final/netty-resolver-4.1.48.Final.jar" }, { "coord": "io.netty:netty-transport-native-epoll:4.1.48.Final", "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", "io.netty:netty-transport-native-unix-common:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final", + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final", "io.netty:netty-transport-native-unix-common:4.1.48.Final" ], "exclusions": [ @@ -2798,15 +2943,15 @@ { "coord": "io.netty:netty-transport-native-unix-common:4.1.48.Final", "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final" + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-transport:4.1.51.Final" + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-transport:4.1.48.Final" ], "exclusions": [ "javax.jms:jms", @@ -2828,31 +2973,32 @@ "url": "https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common/4.1.48.Final/netty-transport-native-unix-common-4.1.48.Final.jar" }, { - "coord": "io.netty:netty-transport:4.1.51.Final", + "coord": "io.netty:netty-transport:4.1.48.Final", "dependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final" + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final", + "io.netty:netty-buffer:4.1.48.Final" ], "directDependencies": [ - "io.netty:netty-buffer:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final" + "io.netty:netty-buffer:4.1.48.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-resolver:4.1.48.Final" ], "exclusions": [ - "ch.qos.logback:logback-classic", + "org.slf4j:slf4j-log4j12", "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" + "log4j:log4j" ], - "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar", + "file": "v1/https/repo1.maven.org/maven2/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar", - "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar", - "https://jitpack.io/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar" + "https://packages.confluent.io/maven/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar", + "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar", + "https://jitpack.io/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar" ], - "sha256": "e5be259f35a246bf504ad93ea8f5df31872b5abebfb751380eab95d5dc840d44", - "url": "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.51.Final/netty-transport-4.1.51.Final.jar" + "sha256": "6b4ba9e09a8e060bad2540845491b5fa1ca73614d157860e657f4027c91e72fd", + "url": "https://repo1.maven.org/maven2/io/netty/netty-transport/4.1.48.Final/netty-transport-4.1.48.Final.jar" }, { "coord": "io.opencensus:opencensus-api:0.24.0", @@ -2909,29 +3055,6 @@ "sha256": "7155273bbb1ed3d477ea33cf19d7bbc0b285ff395f43b29ae576722cf247000f", "url": "https://repo1.maven.org/maven2/io/opencensus/opencensus-contrib-http-util/0.24.0/opencensus-contrib-http-util-0.24.0.jar" }, - { - "coord": "io.projectreactor:reactor-core:3.3.9.RELEASE", - "dependencies": [ - "org.reactivestreams:reactive-streams:1.0.3" - ], - "directDependencies": [ - "org.reactivestreams:reactive-streams:1.0.3" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar", - "https://repo1.maven.org/maven2/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar", - "https://jitpack.io/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar" - ], - "sha256": "2e72796bf56a03e767a5fa1e0e1027b5c9b3737489922ce28138349796b2ed19", - "url": "https://repo1.maven.org/maven2/io/projectreactor/reactor-core/3.3.9.RELEASE/reactor-core-3.3.9.RELEASE.jar" - }, { "coord": "io.prometheus:simpleclient:0.9.0", "dependencies": [], @@ -4043,23 +4166,23 @@ "coord": "org.apache.curator:curator-test:4.2.0", "dependencies": [ "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava", + "io.netty:netty-transport:4.1.48.Final", "com.google.j2objc:j2objc-annotations:1.3", "com.google.code.findbugs:jsr305:3.0.2", "org.slf4j:slf4j-api:1.7.30", "org.apache.zookeeper:zookeeper:3.5.8", "log4j:log4j:1.2.17", - "io.netty:netty-buffer:4.1.51.Final", "io.netty:netty-transport-native-epoll:4.1.48.Final", - "io.netty:netty-codec:4.1.51.Final", + "io.netty:netty-buffer:4.1.48.Final", "com.google.errorprone:error_prone_annotations:2.3.4", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-handler:4.1.51.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", + "io.netty:netty-resolver:4.1.48.Final", "org.apache.yetus:audience-annotations:0.5.0", - "io.netty:netty-transport:4.1.51.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-handler:4.1.48.Final", "com.google.guava:failureaccess:1.0.1", "com.google.guava:guava:29.0-jre", - "io.netty:netty-common:4.1.51.Final", + "io.netty:netty-codec:4.1.48.Final", "io.netty:netty-transport-native-unix-common:4.1.48.Final", "org.checkerframework:checker-qual:2.11.1" ], @@ -4086,11 +4209,11 @@ "coord": "org.apache.httpcomponents:httpclient:4.5.13", "dependencies": [ "org.apache.httpcomponents:httpcore:4.4.13", - "commons-logging:commons-logging:1.2", - "commons-codec:commons-codec:1.11" + "commons-codec:commons-codec:1.14", + "commons-logging:commons-logging:1.2" ], "directDependencies": [ - "commons-codec:commons-codec:1.11", + "commons-codec:commons-codec:1.14", "commons-logging:commons-logging:1.2", "org.apache.httpcomponents:httpcore:4.4.13" ], @@ -4328,6 +4451,7 @@ { "coord": "org.apache.kafka:kafka_2.12:5.5.1-ccs", "dependencies": [ + "io.netty:netty-transport:4.1.48.Final", "org.apache.kafka:kafka-clients:5.5.1-ccs", "com.thoughtworks.paranamer:paranamer:2.8", "com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.10.2", @@ -4340,20 +4464,19 @@ "org.apache.zookeeper:zookeeper:3.5.8", "org.lz4:lz4-java:1.7.1", "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.4", - "io.netty:netty-buffer:4.1.51.Final", "io.netty:netty-transport-native-epoll:4.1.48.Final", "com.fasterxml.jackson.core:jackson-databind:2.11.4", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", + "io.netty:netty-buffer:4.1.48.Final", "org.scala-lang.modules:scala-java8-compat_2.12:0.9.0", - "io.netty:netty-handler:4.1.51.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", + "io.netty:netty-resolver:4.1.48.Final", "org.apache.yetus:audience-annotations:0.5.0", + "io.netty:netty-common:4.1.48.Final", "org.scala-lang:scala-reflect:2.12.10", - "io.netty:netty-transport:4.1.51.Final", "com.yammer.metrics:metrics-core:2.2.0", + "io.netty:netty-handler:4.1.48.Final", "org.scala-lang:scala-library:2.12.10", - "io.netty:netty-common:4.1.51.Final", + "io.netty:netty-codec:4.1.48.Final", "com.github.luben:zstd-jni:1.4.5-2", "commons-cli:commons-cli:1.4", "org.scala-lang.modules:scala-collection-compat_2.12:2.1.3", @@ -4571,6 +4694,29 @@ "sha256": "073381087a3014cc66859779141a4627e239b2d019676d9800411172b2c0bee6", "url": "https://repo1.maven.org/maven2/org/apache/lucene/lucene-sandbox/8.7.0/lucene-sandbox-8.7.0.jar" }, + { + "coord": "org.apache.mina:mina-core:2.1.3", + "dependencies": [ + "org.slf4j:slf4j-api:1.7.30" + ], + "directDependencies": [ + "org.slf4j:slf4j-api:1.7.30" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar", + "https://repo1.maven.org/maven2/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar", + "https://jitpack.io/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar" + ], + "sha256": "28bfef56fb8fedeee0ddc1cb6d7297a6c7dd04b3299b50968a77216c25593941", + "url": "https://repo1.maven.org/maven2/org/apache/mina/mina-core/2.1.3/mina-core-2.1.3.jar" + }, { "coord": "org.apache.velocity:velocity-engine-core:2.2", "dependencies": [ @@ -4650,26 +4796,26 @@ { "coord": "org.apache.zookeeper:zookeeper:3.5.8", "dependencies": [ + "io.netty:netty-transport:4.1.48.Final", "org.slf4j:slf4j-api:1.7.30", "log4j:log4j:1.2.17", - "io.netty:netty-buffer:4.1.51.Final", "io.netty:netty-transport-native-epoll:4.1.48.Final", - "io.netty:netty-codec:4.1.51.Final", - "io.netty:netty-resolver:4.1.51.Final", - "io.netty:netty-handler:4.1.51.Final", + "io.netty:netty-buffer:4.1.48.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", + "io.netty:netty-resolver:4.1.48.Final", "org.apache.yetus:audience-annotations:0.5.0", - "io.netty:netty-transport:4.1.51.Final", - "io.netty:netty-common:4.1.51.Final", + "io.netty:netty-common:4.1.48.Final", + "io.netty:netty-handler:4.1.48.Final", + "io.netty:netty-codec:4.1.48.Final", "io.netty:netty-transport-native-unix-common:4.1.48.Final" ], "directDependencies": [ "org.slf4j:slf4j-api:1.7.30", "log4j:log4j:1.2.17", "io.netty:netty-transport-native-epoll:4.1.48.Final", - "io.netty:netty-handler:4.1.51.Final", "org.apache.zookeeper:zookeeper-jute:3.5.8", - "org.apache.yetus:audience-annotations:0.5.0" + "org.apache.yetus:audience-annotations:0.5.0", + "io.netty:netty-handler:4.1.48.Final" ], "exclusions": [ "javax.jms:jms", @@ -6867,25 +7013,6 @@ "sha256": "2836e954823bfcbad45e78c18896e3d01058e6f643749810c608b7005ee7b2fa", "url": "https://repo1.maven.org/maven2/org/projectlombok/lombok/1.18.10/lombok-1.18.10.jar" }, - { - "coord": "org.reactivestreams:reactive-streams:1.0.3", - "dependencies": [], - "directDependencies": [], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar", - "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar", - "https://jitpack.io/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar" - ], - "sha256": "1dee0481072d19c929b623e155e14d2f6085dc011529a0a0dbefc84cf571d865", - "url": "https://repo1.maven.org/maven2/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar" - }, { "coord": "org.reflections:reflections:0.9.12", "dependencies": [ @@ -7337,6 +7464,61 @@ "sha256": "19d3249ade85335c80b32570a26c2367046d488b6d84b4e1172a3ed5d6d52279", "url": "https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-json/2.4.5/spring-boot-starter-json-2.4.5.jar" }, + { + "coord": "org.springframework.boot:spring-boot-starter-oauth2-client:2.4.5", + "dependencies": [ + "net.minidev:accessors-smart:1.2", + "org.springframework.security:spring-security-oauth2-jose:5.4.6", + "org.springframework.boot:spring-boot-autoconfigure:2.4.5", + "org.ow2.asm:asm:9.0", + "org.springframework.security:spring-security-web:5.4.6", + "com.nimbusds:lang-tag:1.4.4", + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-jcl:5.3.6", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", + "org.springframework:spring-context:5.3.6", + "com.sun.mail:jakarta.mail:1.6.7", + "org.springframework.security:spring-security-config:5.4.6", + "org.springframework.security:spring-security-oauth2-client:5.4.6", + "org.springframework:spring-expression:5.3.6", + "jakarta.annotation:jakarta.annotation-api:1.3.5", + "org.springframework:spring-web:5.3.6", + "com.nimbusds:content-type:2.1", + "com.sun.activation:jakarta.activation:1.2.1", + "org.springframework:spring-core:5.3.6", + "com.nimbusds:oauth2-oidc-sdk:8.36.1", + "org.springframework.security:spring-security-oauth2-core:5.4.6", + "org.springframework:spring-aop:5.3.6", + "org.springframework.security:spring-security-core:5.4.6", + "org.springframework.boot:spring-boot:2.4.5", + "org.yaml:snakeyaml:1.27", + "net.minidev:json-smart:2.3", + "org.springframework.boot:spring-boot-starter:2.4.5" + ], + "directDependencies": [ + "org.springframework.security:spring-security-oauth2-jose:5.4.6", + "com.sun.mail:jakarta.mail:1.6.7", + "org.springframework.security:spring-security-config:5.4.6", + "org.springframework.security:spring-security-oauth2-client:5.4.6", + "org.springframework.security:spring-security-core:5.4.6", + "org.springframework.boot:spring-boot-starter:2.4.5" + ], + "exclusions": [ + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-tomcat", + "org.springframework.boot:spring-boot-starter-logging", + "org.slf4j:slf4j-log4j12" + ], + "file": "v1/https/repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar", + "https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar", + "https://jitpack.io/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar" + ], + "sha256": "79298ed9006a065879f15e9a69dba147e6d6a0e0ab452e63bd38920a3de05bc1", + "url": "https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-oauth2-client/2.4.5/spring-boot-starter-oauth2-client-2.4.5.jar" + }, { "coord": "org.springframework.boot:spring-boot-starter-security:2.4.5", "dependencies": [ @@ -7671,16 +7853,12 @@ "url": "https://repo1.maven.org/maven2/org/springframework/boot/spring-boot/2.4.5/spring-boot-2.4.5.jar" }, { - "coord": "org.springframework.data:spring-data-commons:2.3.3.RELEASE", + "coord": "org.springframework.retry:spring-retry:1.2.5.RELEASE", "dependencies": [ - "org.slf4j:slf4j-api:1.7.30", - "org.springframework:spring-beans:5.3.6", "org.springframework:spring-core:5.3.6", "org.springframework:spring-jcl:5.3.6" ], "directDependencies": [ - "org.slf4j:slf4j-api:1.7.30", - "org.springframework:spring-beans:5.3.6", "org.springframework:spring-core:5.3.6" ], "exclusions": [ @@ -7689,33 +7867,40 @@ "org.springframework.boot:spring-boot-starter-logging", "org.slf4j:slf4j-log4j12" ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar", + "file": "v1/https/repo1.maven.org/maven2/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar", - "https://jitpack.io/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar" + "https://packages.confluent.io/maven/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar", + "https://repo1.maven.org/maven2/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar", + "https://jitpack.io/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar" ], - "sha256": "f53742d93faf5dfb63318c173be4f5443dbba804753ce811cdb6be3260b399bc", - "url": "https://repo1.maven.org/maven2/org/springframework/data/spring-data-commons/2.3.3.RELEASE/spring-data-commons-2.3.3.RELEASE.jar" + "sha256": "71e7cb0d33e3f595011d3e98b14f41ca165a435760ecd4d68cb935e8afa8a3d2", + "url": "https://repo1.maven.org/maven2/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar" }, { - "coord": "org.springframework.data:spring-data-keyvalue:2.3.3.RELEASE", + "coord": "org.springframework.security.oauth:spring-security-oauth2:2.4.1.RELEASE", "dependencies": [ + "org.springframework.security:spring-security-web:5.4.6", "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-tx:5.2.8.RELEASE", - "org.slf4j:slf4j-api:1.7.30", + "org.springframework:spring-webmvc:5.3.6", "org.springframework:spring-jcl:5.3.6", "org.springframework:spring-context:5.3.6", + "org.springframework.security:spring-security-config:5.4.6", + "commons-codec:commons-codec:1.14", "org.springframework:spring-expression:5.3.6", + "org.springframework:spring-web:5.3.6", "org.springframework:spring-core:5.3.6", - "org.springframework.data:spring-data-commons:2.3.3.RELEASE", - "org.springframework:spring-aop:5.3.6" + "org.springframework:spring-aop:5.3.6", + "org.springframework.security:spring-security-core:5.4.6" ], "directDependencies": [ - "org.slf4j:slf4j-api:1.7.30", + "org.springframework.security:spring-security-web:5.4.6", + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-webmvc:5.3.6", "org.springframework:spring-context:5.3.6", - "org.springframework:spring-tx:5.2.8.RELEASE", - "org.springframework.data:spring-data-commons:2.3.3.RELEASE" + "org.springframework.security:spring-security-config:5.4.6", + "commons-codec:commons-codec:1.14", + "org.springframework:spring-core:5.3.6", + "org.springframework.security:spring-security-core:5.4.6" ], "exclusions": [ "ch.qos.logback:logback-classic", @@ -7723,38 +7908,32 @@ "org.springframework.boot:spring-boot-starter-logging", "org.slf4j:slf4j-log4j12" ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar", + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar", - "https://jitpack.io/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar" + "https://packages.confluent.io/maven/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar", + "https://repo1.maven.org/maven2/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar", + "https://jitpack.io/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar" ], - "sha256": "e5e301d378cfacf3941c1e063c03134a802d5604da987d52391461db1b72d37c", - "url": "https://repo1.maven.org/maven2/org/springframework/data/spring-data-keyvalue/2.3.3.RELEASE/spring-data-keyvalue-2.3.3.RELEASE.jar" + "sha256": "333d00f579f244a047a0f997850a23488632037bc7d30fb760a73ed6a6f8f588", + "url": "https://repo1.maven.org/maven2/org/springframework/security/oauth/spring-security-oauth2/2.4.1.RELEASE/spring-security-oauth2-2.4.1.RELEASE.jar" }, { - "coord": "org.springframework.data:spring-data-redis:2.3.3.RELEASE", + "coord": "org.springframework.security:spring-security-config:5.4.6", "dependencies": [ "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-tx:5.2.8.RELEASE", - "org.slf4j:slf4j-api:1.7.30", "org.springframework:spring-jcl:5.3.6", "org.springframework:spring-context:5.3.6", - "org.springframework:spring-context-support:5.3.6", "org.springframework:spring-expression:5.3.6", - "org.springframework:spring-oxm:5.2.8.RELEASE", "org.springframework:spring-core:5.3.6", - "org.springframework.data:spring-data-commons:2.3.3.RELEASE", "org.springframework:spring-aop:5.3.6", - "org.springframework.data:spring-data-keyvalue:2.3.3.RELEASE" + "org.springframework.security:spring-security-core:5.4.6" ], "directDependencies": [ - "org.springframework:spring-tx:5.2.8.RELEASE", - "org.slf4j:slf4j-api:1.7.30", - "org.springframework:spring-context-support:5.3.6", - "org.springframework:spring-oxm:5.2.8.RELEASE", + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-context:5.3.6", + "org.springframework:spring-core:5.3.6", "org.springframework:spring-aop:5.3.6", - "org.springframework.data:spring-data-keyvalue:2.3.3.RELEASE" + "org.springframework.security:spring-security-core:5.4.6" ], "exclusions": [ "ch.qos.logback:logback-classic", @@ -7762,23 +7941,31 @@ "org.springframework.boot:spring-boot-starter-logging", "org.slf4j:slf4j-log4j12" ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar", + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar", - "https://jitpack.io/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar" + "https://packages.confluent.io/maven/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar", + "https://repo1.maven.org/maven2/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar", + "https://jitpack.io/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar" ], - "sha256": "d28e3914d8345a6d30d7292b710bc5b74d127fa2ce89588e9ff0e7a28905f11a", - "url": "https://repo1.maven.org/maven2/org/springframework/data/spring-data-redis/2.3.3.RELEASE/spring-data-redis-2.3.3.RELEASE.jar" + "sha256": "940be8bd1980e18c1258788591f952537bcf29dd2adca35cd2a9a61ba3ac8741", + "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar" }, { - "coord": "org.springframework.retry:spring-retry:1.2.5.RELEASE", + "coord": "org.springframework.security:spring-security-core:5.4.6", "dependencies": [ + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-jcl:5.3.6", + "org.springframework:spring-context:5.3.6", + "org.springframework:spring-expression:5.3.6", "org.springframework:spring-core:5.3.6", - "org.springframework:spring-jcl:5.3.6" + "org.springframework:spring-aop:5.3.6" ], "directDependencies": [ - "org.springframework:spring-core:5.3.6" + "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-context:5.3.6", + "org.springframework:spring-expression:5.3.6", + "org.springframework:spring-core:5.3.6", + "org.springframework:spring-aop:5.3.6" ], "exclusions": [ "ch.qos.logback:logback-classic", @@ -7786,64 +7973,115 @@ "org.springframework.boot:spring-boot-starter-logging", "org.slf4j:slf4j-log4j12" ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar", + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar", - "https://jitpack.io/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar" + "https://packages.confluent.io/maven/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar", + "https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar", + "https://jitpack.io/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar" ], - "sha256": "71e7cb0d33e3f595011d3e98b14f41ca165a435760ecd4d68cb935e8afa8a3d2", - "url": "https://repo1.maven.org/maven2/org/springframework/retry/spring-retry/1.2.5.RELEASE/spring-retry-1.2.5.RELEASE.jar" + "sha256": "dc75ecb94dad7625a0e1af31e8bc22ee9c119433c901aaf9b0d9454d6f6df783", + "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar" }, { - "coord": "org.springframework.security:spring-security-config:5.4.6", + "coord": "org.springframework.security:spring-security-oauth2-client:5.4.6", "dependencies": [ + "net.minidev:accessors-smart:1.2", + "org.ow2.asm:asm:9.0", + "org.springframework.security:spring-security-web:5.4.6", + "com.nimbusds:lang-tag:1.4.4", "org.springframework:spring-beans:5.3.6", "org.springframework:spring-jcl:5.3.6", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", "org.springframework:spring-context:5.3.6", "org.springframework:spring-expression:5.3.6", + "org.springframework:spring-web:5.3.6", + "com.nimbusds:content-type:2.1", "org.springframework:spring-core:5.3.6", + "com.nimbusds:oauth2-oidc-sdk:8.36.1", + "org.springframework.security:spring-security-oauth2-core:5.4.6", "org.springframework:spring-aop:5.3.6", - "org.springframework.security:spring-security-core:5.4.6" + "org.springframework.security:spring-security-core:5.4.6", + "net.minidev:json-smart:2.3" ], "directDependencies": [ + "org.springframework.security:spring-security-web:5.4.6", + "org.springframework:spring-core:5.3.6", + "com.nimbusds:oauth2-oidc-sdk:8.36.1", + "org.springframework.security:spring-security-oauth2-core:5.4.6", + "org.springframework.security:spring-security-core:5.4.6" + ], + "exclusions": [ + "org.slf4j:slf4j-log4j12", + "com.sun.mail:javax.mail", + "org.springframework.boot:spring-boot-starter-tomcat", + "ch.qos.logback:logback-classic", + "org.springframework.boot:spring-boot-starter-logging" + ], + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar", + "mirror_urls": [ + "https://packages.confluent.io/maven/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar", + "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar", + "https://jitpack.io/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar" + ], + "sha256": "db27a98c2c1b602d5d9e63387ba2b4b7a45e13cdd13120803256c5abde77e358", + "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-client/5.4.6/spring-security-oauth2-client-5.4.6.jar" + }, + { + "coord": "org.springframework.security:spring-security-oauth2-core:5.4.6", + "dependencies": [ "org.springframework:spring-beans:5.3.6", + "org.springframework:spring-jcl:5.3.6", "org.springframework:spring-context:5.3.6", + "org.springframework:spring-expression:5.3.6", + "org.springframework:spring-web:5.3.6", "org.springframework:spring-core:5.3.6", "org.springframework:spring-aop:5.3.6", "org.springframework.security:spring-security-core:5.4.6" ], + "directDependencies": [ + "org.springframework:spring-core:5.3.6", + "org.springframework:spring-web:5.3.6", + "org.springframework.security:spring-security-core:5.4.6" + ], "exclusions": [ "ch.qos.logback:logback-classic", "org.springframework.boot:spring-boot-starter-tomcat", "org.springframework.boot:spring-boot-starter-logging", "org.slf4j:slf4j-log4j12" ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar", + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar", - "https://repo1.maven.org/maven2/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar", - "https://jitpack.io/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar" + "https://packages.confluent.io/maven/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar", + "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar", + "https://jitpack.io/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar" ], - "sha256": "940be8bd1980e18c1258788591f952537bcf29dd2adca35cd2a9a61ba3ac8741", - "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-config/5.4.6/spring-security-config-5.4.6.jar" + "sha256": "e13af768309b30b357bb78ae40a2bcbc40565916357e6156c3e94669ed7b7f48", + "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-core/5.4.6/spring-security-oauth2-core-5.4.6.jar" }, { - "coord": "org.springframework.security:spring-security-core:5.4.6", + "coord": "org.springframework.security:spring-security-oauth2-jose:5.4.6", "dependencies": [ + "net.minidev:accessors-smart:1.2", + "org.ow2.asm:asm:9.0", "org.springframework:spring-beans:5.3.6", "org.springframework:spring-jcl:5.3.6", + "com.github.stephenc.jcip:jcip-annotations:1.0-1", + "com.nimbusds:nimbus-jose-jwt:8.21", "org.springframework:spring-context:5.3.6", "org.springframework:spring-expression:5.3.6", + "org.springframework:spring-web:5.3.6", "org.springframework:spring-core:5.3.6", - "org.springframework:spring-aop:5.3.6" + "org.springframework.security:spring-security-oauth2-core:5.4.6", + "org.springframework:spring-aop:5.3.6", + "org.springframework.security:spring-security-core:5.4.6", + "net.minidev:json-smart:2.3" ], "directDependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-context:5.3.6", - "org.springframework:spring-expression:5.3.6", + "com.nimbusds:nimbus-jose-jwt:8.21", "org.springframework:spring-core:5.3.6", - "org.springframework:spring-aop:5.3.6" + "org.springframework.security:spring-security-core:5.4.6", + "org.springframework.security:spring-security-oauth2-core:5.4.6" ], "exclusions": [ "ch.qos.logback:logback-classic", @@ -7851,14 +8089,14 @@ "org.springframework.boot:spring-boot-starter-logging", "org.slf4j:slf4j-log4j12" ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar", + "file": "v1/https/repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar", "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar", - "https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar", - "https://jitpack.io/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar" + "https://packages.confluent.io/maven/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar", + "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar", + "https://jitpack.io/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar" ], - "sha256": "dc75ecb94dad7625a0e1af31e8bc22ee9c119433c901aaf9b0d9454d6f6df783", - "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/5.4.6/spring-security-core-5.4.6.jar" + "sha256": "8f5d14a402d67b0590982051f9d221c1ecfa289bd2a60c0d516b97d0a2986665", + "url": "https://repo1.maven.org/maven2/org/springframework/security/spring-security-oauth2-jose/5.4.6/spring-security-oauth2-jose-5.4.6.jar" }, { "coord": "org.springframework.security:spring-security-web:5.4.6", @@ -8098,32 +8336,6 @@ "sha256": "7f3491e73a48781ae39d93cb7b01b88c7d6fa802a8184d4a5d82ee36804289c1", "url": "https://repo1.maven.org/maven2/org/springframework/spring-messaging/5.3.6/spring-messaging-5.3.6.jar" }, - { - "coord": "org.springframework:spring-oxm:5.2.8.RELEASE", - "dependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6", - "org.springframework:spring-jcl:5.3.6" - ], - "directDependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar", - "https://jitpack.io/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar" - ], - "sha256": "0fdb104a00ace520d0f75adf698867d05997b647a28f079811cba8fa2742200d", - "url": "https://repo1.maven.org/maven2/org/springframework/spring-oxm/5.2.8.RELEASE/spring-oxm-5.2.8.RELEASE.jar" - }, { "coord": "org.springframework:spring-test:5.3.6", "dependencies": [ @@ -8148,32 +8360,6 @@ "sha256": "b85bc653b7eda0488f68a18257b5a3ccb61b5ef24b32af48cded0953d6ec76b8", "url": "https://repo1.maven.org/maven2/org/springframework/spring-test/5.3.6/spring-test-5.3.6.jar" }, - { - "coord": "org.springframework:spring-tx:5.2.8.RELEASE", - "dependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6", - "org.springframework:spring-jcl:5.3.6" - ], - "directDependencies": [ - "org.springframework:spring-beans:5.3.6", - "org.springframework:spring-core:5.3.6" - ], - "exclusions": [ - "ch.qos.logback:logback-classic", - "org.springframework.boot:spring-boot-starter-tomcat", - "org.springframework.boot:spring-boot-starter-logging", - "org.slf4j:slf4j-log4j12" - ], - "file": "v1/https/repo1.maven.org/maven2/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar", - "mirror_urls": [ - "https://packages.confluent.io/maven/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar", - "https://repo1.maven.org/maven2/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar", - "https://jitpack.io/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar" - ], - "sha256": "df2aeb728d5c95938c5b301175b1d48b3281ef56bd17b13bd010555cc954a31f", - "url": "https://repo1.maven.org/maven2/org/springframework/spring-tx/5.2.8.RELEASE/spring-tx-5.2.8.RELEASE.jar" - }, { "coord": "org.springframework:spring-web:5.3.6", "dependencies": [ diff --git a/package.json b/package.json index d8c713ab35..0ac3785603 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "@crello/react-lottie": "^0.0.11", "@reduxjs/toolkit": "^1.5.1", "@stomp/stompjs": "^6.1.0", - "@types/node": "15.0.0", - "@types/react": "16.9.34", + "@types/node": "15.0.1", + "@types/react": "17.0.4", "@types/react-dom": "16.9.2", "@types/react-redux": "7.1.16", "@types/react-router-dom": "^5.1.7", @@ -33,15 +33,15 @@ "typesafe-actions": "^5.1.0" }, "devDependencies": { - "@babel/core": "7.13.16", + "@babel/core": "7.14.0", "@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/plugin-proposal-object-rest-spread": "^7.13.8", "@babel/plugin-transform-spread": "^7.13.0", - "@babel/preset-env": "^7.13.15", + "@babel/preset-env": "^7.14.1", "@babel/preset-react": "^7.13.13", "@babel/preset-typescript": "^7.13.0", "@bazel/bazelisk": "^1.8.0", - "@bazel/typescript": "^3.4.1", + "@bazel/typescript": "^3.4.2", "@svgr/webpack": "^5.5.0", "@types/lodash-es": "^4.17.4", "@types/react-window-infinite-loader": "^1.0.3", @@ -59,13 +59,13 @@ "minimist": "^1.2.5", "prettier": "^2.2.1", "react-hot-loader": "^4.13.0", - "sass": "^1.32.11", + "sass": "^1.32.12", "sass-loader": "^11", "style-loader": "^2.0.0", "terser-webpack-plugin": "^5.1.1", "typescript": "3.7.4", "url-loader": "^4.1.1", - "webpack": "^5.35.1", + "webpack": "^5.36.2", "webpack-bundle-analyzer": "^4.4.1", "webpack-cli": "^4.6.0", "webpack-dev-server": "^3.11.2" diff --git a/yarn.lock b/yarn.lock index a1a2347323..ffba82e2ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,25 +16,25 @@ dependencies: "@babel/highlight" "^7.12.13" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.13.8": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4" - integrity sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.13.8", "@babel/compat-data@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" + integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== -"@babel/core@7.13.16", "@babel/core@^7.12.3": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.16.tgz#7756ab24396cc9675f1c3fcd5b79fcce192ea96a" - integrity sha512-sXHpixBiWWFti0AV2Zq7avpTasr6sIAu7Y396c608541qAU2ui4a193m0KSQmfPSKFZLnQ3cvlKDOm3XkuXm3Q== +"@babel/core@7.14.0", "@babel/core@^7.12.3": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.0.tgz#47299ff3ec8d111b493f1a9d04bf88c04e728d88" + integrity sha512-8YqpRig5NmIHlMLw09zMlPTvUVMILjqCOtVgu+TVNWEBvy9b5I3RRyhqnrV4hjgEK7n8P9OqvkWJAFmEL6Wwfw== dependencies: "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.16" + "@babel/generator" "^7.14.0" "@babel/helper-compilation-targets" "^7.13.16" - "@babel/helper-module-transforms" "^7.13.14" - "@babel/helpers" "^7.13.16" - "@babel/parser" "^7.13.16" + "@babel/helper-module-transforms" "^7.14.0" + "@babel/helpers" "^7.14.0" + "@babel/parser" "^7.14.0" "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.15" - "@babel/types" "^7.13.16" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -42,12 +42,12 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.13.16", "@babel/generator@^7.13.9": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.16.tgz#0befc287031a201d84cdfc173b46b320ae472d14" - integrity sha512-grBBR75UnKOcUWMp8WoDxNsWCFl//XCK6HWTrBQKTr5SV9f5g0pNOjdyzi/DTBv12S9GnYPInIXQBTky7OXEMg== +"@babel/generator@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.0.tgz#0f35d663506c43e4f10898fbda0d752ec75494be" + integrity sha512-C6u00HbmsrNPug6A+CiNl8rEys7TsdcXwg12BHi2ca5rUfAs3+UwZsuDQSXnc+wCElCXMB8gMaJ3YXDdh8fAlg== dependencies: - "@babel/types" "^7.13.16" + "@babel/types" "^7.14.0" jsesc "^2.5.1" source-map "^0.5.0" @@ -66,7 +66,7 @@ "@babel/helper-explode-assignable-expression" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.16", "@babel/helper-compilation-targets@^7.13.8": +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.16", "@babel/helper-compilation-targets@^7.13.8": version "7.13.16" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA== @@ -87,6 +87,18 @@ "@babel/helper-replace-supers" "^7.13.0" "@babel/helper-split-export-declaration" "^7.12.13" +"@babel/helper-create-class-features-plugin@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.0.tgz#38367d3dab125b12f94273de418f4df23a11a15e" + integrity sha512-6pXDPguA5zC40Y8oI5mqr+jEUpjMJonKvknvA+vD8CYDz5uuXEwWBK8sRAsE/t3gfb1k15AQb9RhwpscC4nUJQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-function-name" "^7.12.13" + "@babel/helper-member-expression-to-functions" "^7.13.12" + "@babel/helper-optimise-call-expression" "^7.12.13" + "@babel/helper-replace-supers" "^7.13.12" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/helper-create-regexp-features-plugin@^7.12.13": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz#a2ac87e9e319269ac655b8d4415e94d38d663cb7" @@ -168,19 +180,19 @@ dependencies: "@babel/types" "^7.13.12" -"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.13.14": - version "7.13.14" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz#e600652ba48ccb1641775413cb32cfa4e8b495ef" - integrity sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g== +"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.0.tgz#8fcf78be220156f22633ee204ea81f73f826a8ad" + integrity sha512-L40t9bxIuGOfpIGA3HNkJhU9qYrf4y5A5LUSw7rGMSn+pcG8dfJ0g6Zval6YJGd2nEjI7oP00fRdnhLKndx6bw== dependencies: "@babel/helper-module-imports" "^7.13.12" "@babel/helper-replace-supers" "^7.13.12" "@babel/helper-simple-access" "^7.13.12" "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-validator-identifier" "^7.12.11" + "@babel/helper-validator-identifier" "^7.14.0" "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.13" - "@babel/types" "^7.13.14" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" "@babel/helper-optimise-call-expression@^7.12.13": version "7.12.13" @@ -223,13 +235,6 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.12" -"@babel/helper-simple-access@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz#8478bcc5cacf6aa1672b251c1d2dde5ccd61a6c4" - integrity sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA== - dependencies: - "@babel/types" "^7.12.13" - "@babel/helper-simple-access@^7.13.12": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" @@ -256,6 +261,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== +"@babel/helper-validator-identifier@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" + integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== + "@babel/helper-validator-option@^7.12.17": version "7.12.17" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" @@ -271,14 +281,14 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.0" -"@babel/helpers@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.16.tgz#08af075f786fd06a56e41bcac3e8cc87ddc4d0b3" - integrity sha512-x5otxUaLpdWHl02P4L94wBU+2BJXBkvO+6d6uzQ+xD9/h2hTSAwA5O8QV8GqKx/l8i+VYmKKQg9e2QGTa2Wu3Q== +"@babel/helpers@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" + integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== dependencies: "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.15" - "@babel/types" "^7.13.16" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": version "7.13.10" @@ -289,10 +299,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.12.13", "@babel/parser@^7.13.15", "@babel/parser@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.16.tgz#0f18179b0448e6939b1f3f5c4c355a3a9bcdfd37" - integrity sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw== +"@babel/parser@^7.12.13", "@babel/parser@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.0.tgz#2f0ebfed92bcddcc8395b91f1895191ce2760380" + integrity sha512-AHbfoxesfBALg33idaTBVUkLnfXtsgvJREf93p4p0Lwsz4ppfE7g1tpEXVm4vrxUcH4DVhAa9Z1m1zqf9WUC7Q== "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12": version "7.13.12" @@ -320,6 +330,14 @@ "@babel/helper-create-class-features-plugin" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-proposal-class-static-block@^7.13.11": + version "7.13.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.13.11.tgz#6fcbba4a962702c17e5371a0c7b39afde186d703" + integrity sha512-fJTdFI4bfnMjvxJyNuaf8i9mVcZ0UhetaGEUHaHV9KEnibLugJkZAtXikR8KcYj+NYmI4DZMS8yQAyg+hvfSqg== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-class-static-block" "^7.12.13" + "@babel/plugin-proposal-dynamic-import@^7.13.8": version "7.13.8" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz#876a1f6966e1dec332e8c9451afda3bebcdf2e1d" @@ -404,6 +422,16 @@ "@babel/helper-create-class-features-plugin" "^7.13.0" "@babel/helper-plugin-utils" "^7.13.0" +"@babel/plugin-proposal-private-property-in-object@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.0.tgz#b1a1f2030586b9d3489cc26179d2eb5883277636" + integrity sha512-59ANdmEwwRUkLjB7CRtwJxxwtjESw+X2IePItA+RGQh+oy5RmpCh/EvVVvh5XQc3yxsm5gtv0+i9oBZhaDNVTg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-create-class-features-plugin" "^7.14.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-private-property-in-object" "^7.14.0" + "@babel/plugin-proposal-unicode-property-regex@^7.12.13", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba" @@ -426,6 +454,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-class-static-block@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.12.13.tgz#8e3d674b0613e67975ceac2776c97b60cafc5c9c" + integrity sha512-ZmKQ0ZXR0nYpHZIIuj9zE7oIqCx2hw9TKi+lIo73NNrMPAZGHfS92/VRV0ZmPj6H2ffBgyFHXvJ5NYsNeEaP2A== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" @@ -496,6 +531,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-private-property-in-object@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.0.tgz#762a4babec61176fec6c88480dec40372b140c0b" + integrity sha512-bda3xF8wGl5/5btF794utNOL0Jw+9jE5C1sLZcoK7c4uonE/y3iQiyG+KbkF3WBV/paX58VCpjhxLPkdj5Fe4w== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-top-level-await@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178" @@ -533,12 +575,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-block-scoping@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz#f36e55076d06f41dfd78557ea039c1b581642e61" - integrity sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ== +"@babel/plugin-transform-block-scoping@^7.14.1": + version "7.14.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.1.tgz#ac1b3a8e3d8cbb31efc6b9be2f74eb9823b74ab2" + integrity sha512-2mQXd0zBrwfp0O1moWIhPpEeTKDvxyHcnma3JATVP1l+CctWBuot6OJG8LQ4DnBj4ZZPSmlb/fm4mu47EOAnVA== dependencies: - "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-transform-classes@^7.13.0": version "7.13.0" @@ -560,10 +602,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-destructuring@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz#c5dce270014d4e1ebb1d806116694c12b7028963" - integrity sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA== +"@babel/plugin-transform-destructuring@^7.13.17": + version "7.13.17" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz#678d96576638c19d5b36b332504d3fd6e06dea27" + integrity sha512-UAUqiLv+uRLO+xuBKKMEpC+t7YRNVRqBsWWq1yKXbBZBje/t3IXCiSinZhjn/DC3qzBfICeYd2EFGEbHsh5RLA== dependencies: "@babel/helper-plugin-utils" "^7.13.0" @@ -619,23 +661,23 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-modules-amd@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz#19f511d60e3d8753cc5a6d4e775d3a5184866cc3" - integrity sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ== +"@babel/plugin-transform-modules-amd@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.0.tgz#589494b5b290ff76cf7f59c798011f6d77026553" + integrity sha512-CF4c5LX4LQ03LebQxJ5JZes2OYjzBuk1TdiF7cG7d5dK4lAdw9NZmaxq5K/mouUdNeqwz3TNjnW6v01UqUNgpQ== dependencies: - "@babel/helper-module-transforms" "^7.13.0" + "@babel/helper-module-transforms" "^7.14.0" "@babel/helper-plugin-utils" "^7.13.0" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.13.8": - version "7.13.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz#7b01ad7c2dcf2275b06fa1781e00d13d420b3e1b" - integrity sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw== +"@babel/plugin-transform-modules-commonjs@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz#52bc199cb581e0992edba0f0f80356467587f161" + integrity sha512-EX4QePlsTaRZQmw9BsoPeyh5OCtRGIhwfLquhxGp5e32w+dyL8htOcDwamlitmNFK6xBZYlygjdye9dbd9rUlQ== dependencies: - "@babel/helper-module-transforms" "^7.13.0" + "@babel/helper-module-transforms" "^7.14.0" "@babel/helper-plugin-utils" "^7.13.0" - "@babel/helper-simple-access" "^7.12.13" + "@babel/helper-simple-access" "^7.13.12" babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.13.8": @@ -649,12 +691,12 @@ "@babel/helper-validator-identifier" "^7.12.11" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz#8a3d96a97d199705b9fd021580082af81c06e70b" - integrity sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw== +"@babel/plugin-transform-modules-umd@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.0.tgz#2f8179d1bbc9263665ce4a65f305526b2ea8ac34" + integrity sha512-nPZdnWtXXeY7I87UZr9VlsWme3Y0cfFFE41Wbxz4bbaexAjNMInXPFUpRRUJ8NoMm0Cw+zxbqjdPmLhcjfazMw== dependencies: - "@babel/helper-module-transforms" "^7.13.0" + "@babel/helper-module-transforms" "^7.14.0" "@babel/helper-plugin-utils" "^7.13.0" "@babel/plugin-transform-named-capturing-groups-regex@^7.12.13": @@ -818,18 +860,19 @@ "@babel/helper-create-regexp-features-plugin" "^7.12.13" "@babel/helper-plugin-utils" "^7.12.13" -"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.13.15": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.15.tgz#c8a6eb584f96ecba183d3d414a83553a599f478f" - integrity sha512-D4JAPMXcxk69PKe81jRJ21/fP/uYdcTZ3hJDF5QX2HSI9bBxxYw/dumdR6dGumhjxlprHPE4XWoPaqzZUVy2MA== +"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.14.1": + version "7.14.1" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.1.tgz#b55914e2e68885ea03f69600b2d3537e54574a93" + integrity sha512-0M4yL1l7V4l+j/UHvxcdvNfLB9pPtIooHTbEhgD/6UGyh8Hy3Bm1Mj0buzjDXATCSz3JFibVdnoJZCrlUCanrQ== dependencies: - "@babel/compat-data" "^7.13.15" - "@babel/helper-compilation-targets" "^7.13.13" + "@babel/compat-data" "^7.14.0" + "@babel/helper-compilation-targets" "^7.13.16" "@babel/helper-plugin-utils" "^7.13.0" "@babel/helper-validator-option" "^7.12.17" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.13.12" "@babel/plugin-proposal-async-generator-functions" "^7.13.15" "@babel/plugin-proposal-class-properties" "^7.13.0" + "@babel/plugin-proposal-class-static-block" "^7.13.11" "@babel/plugin-proposal-dynamic-import" "^7.13.8" "@babel/plugin-proposal-export-namespace-from" "^7.12.13" "@babel/plugin-proposal-json-strings" "^7.13.8" @@ -840,9 +883,11 @@ "@babel/plugin-proposal-optional-catch-binding" "^7.13.8" "@babel/plugin-proposal-optional-chaining" "^7.13.12" "@babel/plugin-proposal-private-methods" "^7.13.0" + "@babel/plugin-proposal-private-property-in-object" "^7.14.0" "@babel/plugin-proposal-unicode-property-regex" "^7.12.13" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.12.13" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" @@ -852,14 +897,15 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.0" "@babel/plugin-syntax-top-level-await" "^7.12.13" "@babel/plugin-transform-arrow-functions" "^7.13.0" "@babel/plugin-transform-async-to-generator" "^7.13.0" "@babel/plugin-transform-block-scoped-functions" "^7.12.13" - "@babel/plugin-transform-block-scoping" "^7.12.13" + "@babel/plugin-transform-block-scoping" "^7.14.1" "@babel/plugin-transform-classes" "^7.13.0" "@babel/plugin-transform-computed-properties" "^7.13.0" - "@babel/plugin-transform-destructuring" "^7.13.0" + "@babel/plugin-transform-destructuring" "^7.13.17" "@babel/plugin-transform-dotall-regex" "^7.12.13" "@babel/plugin-transform-duplicate-keys" "^7.12.13" "@babel/plugin-transform-exponentiation-operator" "^7.12.13" @@ -867,10 +913,10 @@ "@babel/plugin-transform-function-name" "^7.12.13" "@babel/plugin-transform-literals" "^7.12.13" "@babel/plugin-transform-member-expression-literals" "^7.12.13" - "@babel/plugin-transform-modules-amd" "^7.13.0" - "@babel/plugin-transform-modules-commonjs" "^7.13.8" + "@babel/plugin-transform-modules-amd" "^7.14.0" + "@babel/plugin-transform-modules-commonjs" "^7.14.0" "@babel/plugin-transform-modules-systemjs" "^7.13.8" - "@babel/plugin-transform-modules-umd" "^7.13.0" + "@babel/plugin-transform-modules-umd" "^7.14.0" "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.13" "@babel/plugin-transform-new-target" "^7.12.13" "@babel/plugin-transform-object-super" "^7.12.13" @@ -886,7 +932,7 @@ "@babel/plugin-transform-unicode-escapes" "^7.12.13" "@babel/plugin-transform-unicode-regex" "^7.12.13" "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.13.14" + "@babel/types" "^7.14.1" babel-plugin-polyfill-corejs2 "^0.2.0" babel-plugin-polyfill-corejs3 "^0.2.0" babel-plugin-polyfill-regenerator "^0.2.0" @@ -952,26 +998,26 @@ "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.13.15": - version "7.13.15" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.15.tgz#c38bf7679334ddd4028e8e1f7b3aa5019f0dada7" - integrity sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ== +"@babel/traverse@^7.13.0", "@babel/traverse@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.0.tgz#cea0dc8ae7e2b1dec65f512f39f3483e8cc95aef" + integrity sha512-dZ/a371EE5XNhTHomvtuLTUyx6UEoJmYX+DT5zBCQN3McHemsuIaKKYqsc/fs26BEkHs/lBZy0J571LP5z9kQA== dependencies: "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.9" + "@babel/generator" "^7.14.0" "@babel/helper-function-name" "^7.12.13" "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.13.15" - "@babel/types" "^7.13.14" + "@babel/parser" "^7.14.0" + "@babel/types" "^7.14.0" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.17", "@babel/types@^7.12.6", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.13.16", "@babel/types@^7.4.4": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.16.tgz#916120b858aa5655cfba84bd0f6021ff5bdb4e65" - integrity sha512-7enM8Wxhrl1hB1+k6+xO6RmxpNkaveRWkdpyii8DkrLWRgr0l3x29/SEuhTIkP+ynHsU/Hpjn8Evd/axv/ll6Q== +"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.12.17", "@babel/types@^7.12.6", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.14.0", "@babel/types@^7.14.1", "@babel/types@^7.4.4": + version "7.14.1" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.1.tgz#095bd12f1c08ab63eff6e8f7745fa7c9cc15a9db" + integrity sha512-S13Qe85fzLs3gYRUnrpyeIrBJIMYv33qSTg1qoBwiG6nPKwUWAD9odSzWhEedpwOIzSEI6gbdQIWEMiCI42iBA== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" + "@babel/helper-validator-identifier" "^7.14.0" to-fast-properties "^2.0.0" "@bazel/bazelisk@^1.8.0": @@ -979,10 +1025,10 @@ resolved "https://registry.yarnpkg.com/@bazel/bazelisk/-/bazelisk-1.8.0.tgz#7bdb7c7068d4779ba8ddbf8cd72afb9b2099bb6e" integrity sha512-RcovBpVPlLptW/+j1+Xbnr4+Ooy1HO8bG2ECAC0pegLvKFWhO6X3twLKKAJ2KQ4jkoeE0xzUUWIL9zyaIsNxLA== -"@bazel/typescript@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.4.1.tgz#ec52292b240157cd2d874ff7ea7857da8416c00c" - integrity sha512-OKpfjFRhudsaUBL3xH1oAbat+bwdRyfAOTn2qgMQSO3vR4ZBBVYk7GVMJzWamLkbDS0aY5ws5wLfDScJSKD2ww== +"@bazel/typescript@^3.4.2": + version "3.4.2" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.4.2.tgz#183cb14d1f4149cc67ed2723c4b8a7366da5ec36" + integrity sha512-JtLdPOC7rytALJBxawxTCnxVopGstk2eXFs56zHBy+JWSeqrnwujeWZyK5qZHzpag02/JtIQ/ZKkM/DQtrXC8Q== dependencies: protobufjs "6.8.8" semver "5.6.0" @@ -1357,10 +1403,10 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== -"@types/node@*", "@types/node@15.0.0": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.0.tgz#557dd0da4a6dca1407481df3bbacae0cd6f68042" - integrity sha512-YN1d+ae2MCb4U0mMa+Zlb5lWTdpFShbAj5nmte6lel27waMMBfivrm0prC16p/Di3DyTrmerrYUT8/145HXxVw== +"@types/node@*", "@types/node@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" + integrity sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA== "@types/node@^10.1.0": version "10.17.55" @@ -1436,23 +1482,15 @@ dependencies: "@types/react" "*" -"@types/react@*": - version "17.0.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.3.tgz#ba6e215368501ac3826951eef2904574c262cc79" - integrity sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg== +"@types/react@*", "@types/react@17.0.4": + version "17.0.4" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.4.tgz#a67c6f7a460d2660e950d9ccc1c2f18525c28220" + integrity sha512-onz2BqScSFMoTRdJUZUDD/7xrusM8hBA2Fktk2qgaTYPCgPvWnDEgkrOs8hhPUf2jfcIXkJ5yK6VfYormJS3Jw== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@16.9.34": - version "16.9.34" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.34.tgz#f7d5e331c468f53affed17a8a4d488cd44ea9349" - integrity sha512-8AJlYMOfPe1KGLKyHpflCg5z46n0b5DbRfqDksxBLBTUpB75ypDBAO9eCUcjNwE6LCUslwTz00yyG/X9gaVtow== - dependencies: - "@types/prop-types" "*" - csstype "^2.2.0" - "@types/resize-observer-browser@^0.1.5": version "0.1.5" resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.5.tgz#36d897708172ac2380cd486da7a3daf1161c1e23" @@ -1719,10 +1757,10 @@ acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4: - version "8.1.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.1.0.tgz#52311fd7037ae119cbb134309e901aa46295b3fe" - integrity sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA== +acorn@^8.0.4, acorn@^8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.2.1.tgz#0d36af126fb6755095879c1dc6fd7edf7d60a5fb" + integrity sha512-z716cpm5TX4uzOzILx8PavOE6C6DKshHDw1aQN52M/yNSqE9s5O8SMfyhCCfCJ3HmTL0NkVOi+8a/55T7YB3bg== ajv-errors@^1.0.0: version "1.0.1" @@ -2636,9 +2674,9 @@ core-js-compat@^3.9.0, core-js-compat@^3.9.1: semver "7.0.0" core-js@3: - version "3.11.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.0.tgz#05dac6aa70c0a4ad842261f8957b961d36eb8926" - integrity sha512-bd79DPpx+1Ilh9+30aT5O1sgpQd4Ttg8oqkqi51ZzhedMM1omD2e6IOF48Z/DzDCZ2svp49tN/3vneTK6ZBkXw== + version "3.11.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.1.tgz#f920392bf8ed63a0ec8e4e729857bfa3d121c525" + integrity sha512-k93Isqg7e4txZWMGNYwevZL9MiogLk8pd1PtwrmFmi8IBq4GXqUaVW/a33Llt6amSI36uSjd0GWwc9pTT9ALlQ== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -2741,11 +2779,6 @@ csso@^4.0.2: dependencies: css-tree "^1.1.2" -csstype@^2.2.0: - version "2.6.16" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.16.tgz#544d69f547013b85a40d15bff75db38f34fe9c39" - integrity sha512-61FBWoDHp/gRtsoDkq/B1nWrCUG/ok1E3tUrcNbZjsE9Cxd9yzUirjS3+nAATB8U4cTtaQmAHbNndoFz5L6C9Q== - csstype@^3.0.2: version "3.0.7" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" @@ -6475,10 +6508,10 @@ sass-loader@^11: klona "^2.0.4" neo-async "^2.6.2" -sass@^1.32.11: - version "1.32.11" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.11.tgz#b236b3ea55c76602c2ef2bd0445f0db581baa218" - integrity sha512-O9tRcob/fegUVSIV1ihLLZcftIOh0AF1VpKgusUfLqnb2jQ0GLDwI5ivv1FYWivGv8eZ/AwntTyTzjcHu0c/qw== +sass@^1.32.12: + version "1.32.12" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.12.tgz#a2a47ad0f1c168222db5206444a30c12457abb9f" + integrity sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA== dependencies: chokidar ">=3.0.0 <4.0.0" @@ -7687,17 +7720,17 @@ webpack-sources@^2.1.1: source-list-map "^2.0.1" source-map "^0.6.1" -webpack@^5.35.1: - version "5.35.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.35.1.tgz#857670799465c8a5cbb94c4c175d60ac42d18ba3" - integrity sha512-uWKYStqJ23+N6/EnMEwUjPSSKUG1tFmcuKhALEh/QXoUxwN8eb3ATNIZB38A+fO6QZ0xfc7Cu7KNV9LXNhDCsw== +webpack@^5.36.2: + version "5.36.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.36.2.tgz#6ef1fb2453ad52faa61e78d486d353d07cca8a0f" + integrity sha512-XJumVnnGoH2dV+Pk1VwgY4YT6AiMKpVoudUFCNOXMIVrEKPUgEwdIfWPjIuGLESAiS8EdIHX5+TiJz/5JccmRg== dependencies: "@types/eslint-scope" "^3.7.0" "@types/estree" "^0.0.47" "@webassemblyjs/ast" "1.11.0" "@webassemblyjs/wasm-edit" "1.11.0" "@webassemblyjs/wasm-parser" "1.11.0" - acorn "^8.0.4" + acorn "^8.2.1" browserslist "^4.14.5" chrome-trace-event "^1.0.2" enhanced-resolve "^5.8.0"