diff options
Diffstat (limited to 'src/main/java/com/juick')
5 files changed, 45 insertions, 51 deletions
diff --git a/src/main/java/com/juick/ActivityPubManager.java b/src/main/java/com/juick/ActivityPubManager.java index 63417626..1dd3b784 100644 --- a/src/main/java/com/juick/ActivityPubManager.java +++ b/src/main/java/com/juick/ActivityPubManager.java @@ -106,7 +106,7 @@ public class ActivityPubManager implements ActivityListener, NotificationListene @Override public void deleteUserEvent(DeleteUserEvent event) { String acct = event.getUserUri(); - logger.info("Deleting {} from followers", acct); + logger.debug("Deleting {} from followers", acct); socialService.removeAccount(acct); } @@ -201,14 +201,18 @@ public class ActivityPubManager implements ActivityListener, NotificationListene Actor me = conversionService.convert(user, Actor.class); socialService.getFollowers(user).forEach(acct -> { try { - Actor follower = (Actor) signatureManager.getContext(URI.create(acct)).orElseThrow(); - Update update = new Update(); - update.setId(userUri + "#update"); - update.setActor(me.getId()); - update.setObject(me); - update.setPublished(Instant.now()); - logger.info("Update to follower {}", follower.getId()); - signatureManager.post(me, follower, update); + var context = signatureManager.getContext(URI.create(acct)); + if (context.isPresent() && context.get() instanceof Actor follower) { + Update update = new Update(); + update.setId(userUri + "#update"); + update.setActor(me.getId()); + update.setObject(me); + update.setPublished(Instant.now()); + logger.info("Update to follower {}", follower.getId()); + signatureManager.post(me, follower, update); + } else { + logger.warn("Unhandled context: {}", acct); + } } catch (Exception e) { logger.warn("activitypub exception", e); } @@ -233,9 +237,8 @@ public class ActivityPubManager implements ActivityListener, NotificationListene subscribers.addAll(note.getCc()); subscribers.forEach(acct -> { if (!acct.equals(profileUriBuilder.followersUri(user))) { - Optional<Context> context = signatureManager.getContext(URI.create(acct)); - if (context.isPresent() && context.get() instanceof Actor) { - Actor follower = (Actor) context.get(); + var context = signatureManager.getContext(URI.create(acct)); + if (context.isPresent() && context.get() instanceof Actor follower) { Create create = new Create(); create.setId(note.getId()); create.setActor(me.getId()); diff --git a/src/main/java/com/juick/SignatureManager.java b/src/main/java/com/juick/SignatureManager.java index 9d6b68f7..92cb7fd9 100644 --- a/src/main/java/com/juick/SignatureManager.java +++ b/src/main/java/com/juick/SignatureManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2020, Juick + * Copyright (C) 2008-2022, Juick * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -23,7 +23,6 @@ import com.juick.model.User; import com.juick.service.UserService; import com.juick.service.activities.DeleteUserEvent; import com.juick.util.DateFormattersHolder; -import com.juick.www.api.activity.model.Activity; import com.juick.www.api.activity.model.Context; import com.juick.www.api.activity.model.objects.Actor; import com.juick.www.api.webfinger.model.Account; @@ -33,19 +32,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import org.tomitribe.auth.signatures.Base64; -import org.tomitribe.auth.signatures.MissingRequiredHeaderException; -import org.tomitribe.auth.signatures.Signature; -import org.tomitribe.auth.signatures.Signer; -import org.tomitribe.auth.signatures.Verifier; +import org.tomitribe.auth.signatures.*; import rocks.xmpp.addr.Jid; import javax.inject.Inject; @@ -56,12 +48,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.time.Instant; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import static com.juick.www.api.activity.model.Context.ACTIVITY_MEDIA_TYPE; @@ -97,18 +84,18 @@ public class SignatureManager { requestHeaders.add("Digest", digestHeader); requestHeaders.add("Signature", signatureString); HttpEntity<String> request = new HttpEntity<>(payload, requestHeaders); - logger.info("Sending context to {}: {}", to.getId(), payload); + logger.debug("Sending context to {}: {}", to.getId(), payload); ResponseEntity<Void> response = apClient.postForEntity(inbox, request, Void.class); - logger.info("Remote response: {}", response.getStatusCodeValue()); + logger.debug("Remote response: {}", response.getStatusCode()); } public String addSignature(Actor from, String host, String method, String path, String dateString, - String digestHeader) throws IOException { + String digestHeader) throws IOException { return addSignature(from, host, method, path, dateString, digestHeader, keystoreManager); } public String addSignature(Actor from, String host, String method, String path, String dateString, - String digestHeader, KeystoreManager keystoreManager) throws IOException { + String digestHeader, KeystoreManager keystoreManager) throws IOException { List<String> requiredHeaders = StringUtils.isEmpty(digestHeader) ? Arrays.asList("(request-target)", "host", "date") : Arrays.asList("(request-target)", "host", "date", "digest"); @@ -128,10 +115,9 @@ public class SignatureManager { public User verifySignature(String method, String path, Map<String, String> headers) { String signatureString = headers.get("signature"); Signature signature = Signature.fromString(signatureString); - Optional<Context> context = getContext( - UriComponentsBuilder.fromUriString(signature.getKeyId()).fragment(null).build().toUri()); - if (context.isPresent() && context.get() instanceof Actor) { - Actor actor = (Actor) context.get(); + var keyId = UriComponentsBuilder.fromUriString(signature.getKeyId()).fragment(null).build().toUri(); + var context = getContext(keyId); + if (context.isPresent() && context.get() instanceof Actor actor) { Key key = KeystoreManager.publicKeyOf(actor); if (key != null) { Verifier verifier = new Verifier(key, signature); @@ -152,14 +138,14 @@ public class SignatureManager { return AnonymousUser.INSTANCE; } } catch (NoSuchAlgorithmException | SignatureException | MissingRequiredHeaderException - | IOException e) { - logger.warn("Invalid signature {}: {}", signatureString, e.getMessage()); + | IOException e) { + logger.warn("Verification error for {}: {}", signature.getKeyId(), e.getMessage()); } } else { - logger.warn("Unknown actor"); + logger.warn("Public key missing for {}", actor.getId()); } } else { - logger.warn("Unknown keyId"); + logger.warn("Public key error for {}", signature.getKeyId()); } return AnonymousUser.INSTANCE; } @@ -177,7 +163,7 @@ public class SignatureManager { } return Optional.of(context); } catch (Exception e) { - logger.warn("REST Exception on {}: {}", contextUri, e.getMessage()); + logger.warn("{}", e.getMessage()); } return Optional.empty(); } diff --git a/src/main/java/com/juick/config/ActivityPubClientErrorHandler.java b/src/main/java/com/juick/config/ActivityPubClientErrorHandler.java index 69958bbd..23576ad5 100644 --- a/src/main/java/com/juick/config/ActivityPubClientErrorHandler.java +++ b/src/main/java/com/juick/config/ActivityPubClientErrorHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2020, Juick + * Copyright (C) 2008-2022, Juick * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -28,6 +28,7 @@ import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.client.DefaultResponseErrorHandler; +import javax.annotation.Nonnull; import javax.inject.Inject; import java.io.IOException; import java.net.URI; @@ -36,16 +37,17 @@ import java.nio.charset.StandardCharsets; @Component public class ActivityPubClientErrorHandler extends DefaultResponseErrorHandler { private static final Logger logger = LoggerFactory.getLogger("ActivityPub"); - @Inject private ApplicationEventPublisher applicationEventPublisher; @Override - public void handleError(URI contextUri, HttpMethod method, ClientHttpResponse response) throws IOException { - logger.warn("HTTP ERROR {} {} : {}", response.getStatusCode().value(), - response.getStatusText(), IOUtils.toString(response.getBody(), StandardCharsets.UTF_8)); + public void handleError(@Nonnull URI contextUri, @Nonnull HttpMethod method, ClientHttpResponse response) + throws IOException { if (response.getStatusCode().equals(HttpStatus.GONE)) { logger.warn("Server report {} is gone, deleting", contextUri.toASCIIString()); applicationEventPublisher.publishEvent(new DeleteUserEvent(this, contextUri.toASCIIString())); + } else { + logger.warn("HTTP ERROR {} {} : {}", response.getStatusCode().value(), + response.getStatusText(), IOUtils.toString(response.getBody(), StandardCharsets.UTF_8)); } } } diff --git a/src/main/java/com/juick/config/ActivityPubConfig.java b/src/main/java/com/juick/config/ActivityPubConfig.java index 3570b97d..9a626d12 100644 --- a/src/main/java/com/juick/config/ActivityPubConfig.java +++ b/src/main/java/com/juick/config/ActivityPubConfig.java @@ -29,6 +29,7 @@ import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; @@ -66,8 +67,8 @@ public class ActivityPubConfig { CloseableHttpClient httpClient; @Bean - HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() { - HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); + ClientHttpRequestFactory clientHttpRequestFactory() { + var clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(); clientHttpRequestFactory.setHttpClient(httpClient); return clientHttpRequestFactory; } diff --git a/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java b/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java index 723cf576..92e26406 100644 --- a/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java +++ b/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java @@ -32,6 +32,8 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; + +import javax.annotation.Nonnull; import java.io.IOException; import java.util.Collections; import java.util.Map; @@ -50,8 +52,8 @@ public class HTTPSignatureAuthenticationFilter extends OncePerRequestFilter { } @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws IOException, ServletException { + protected void doFilterInternal(@Nonnull HttpServletRequest request, @Nonnull HttpServletResponse response, + @Nonnull FilterChain filterChain) throws IOException, ServletException { if (authenticationIsRequired()) { Map<String, String> headers = Collections.list(request.getHeaderNames()) .stream() |