From fc1465c05d028c2fe38742cda894fe4029b45223 Mon Sep 17 00:00:00 2001 From: Ehren Kret Date: Fri, 3 Sep 2021 15:49:27 -0500 Subject: [PATCH] Wire up stored account badges to the profile endpoints --- .../textsecuregcm/WhisperServerService.java | 6 ++- .../badges/ProfileBadgeConverter.java | 22 ++++++++ .../controllers/ProfileController.java | 50 +++++++++++-------- .../textsecuregcm/entities/Profile.java | 8 +-- .../controllers/ProfileControllerTest.java | 4 +- 5 files changed, 64 insertions(+), 26 deletions(-) create mode 100644 service/src/main/java/org/whispersystems/textsecuregcm/badges/ProfileBadgeConverter.java diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index 4549d7d27..0ea791f09 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -43,6 +43,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; @@ -68,6 +69,7 @@ import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccountAuthenticat import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.ExternalServiceCredentialGenerator; import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator; +import org.whispersystems.textsecuregcm.badges.ProfileBadgeConverter; import org.whispersystems.textsecuregcm.configuration.DirectoryServerConfiguration; import org.whispersystems.textsecuregcm.controllers.AccountController; import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV1; @@ -288,6 +290,8 @@ public class WhisperServerService extends Application Set.of(); // TODO: Provide an actual implementation. + JdbiFactory jdbiFactory = new JdbiFactory(DefaultNameStrategy.CHECK_EMPTY); Jdbi accountJdbi = jdbiFactory.build(environment, config.getAccountsDatabaseConfiguration(), "accountdb"); Jdbi abuseJdbi = jdbiFactory.build(environment, config.getAbuseDatabaseConfiguration(), "abusedb" ); @@ -586,7 +590,7 @@ public class WhisperServerService extends Application convert(Request request, Set accountBadges); +} diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java index 385a49833..42ea03d64 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java @@ -10,7 +10,6 @@ import io.dropwizard.auth.Auth; import java.security.SecureRandom; import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.util.List; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -25,7 +24,9 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import org.apache.commons.codec.DecoderException; @@ -44,6 +45,7 @@ import org.whispersystems.textsecuregcm.auth.Anonymous; import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.OptionalAccess; import org.whispersystems.textsecuregcm.auth.UnidentifiedAccessChecksum; +import org.whispersystems.textsecuregcm.badges.ProfileBadgeConverter; import org.whispersystems.textsecuregcm.entities.CreateProfileRequest; import org.whispersystems.textsecuregcm.entities.Profile; import org.whispersystems.textsecuregcm.entities.ProfileAvatarUploadAttributes; @@ -74,6 +76,7 @@ public class ProfileController { private final AccountsManager accountsManager; private final UsernamesManager usernamesManager; private final DynamicConfigurationManager dynamicConfigurationManager; + private final ProfileBadgeConverter profileBadgeConverter; private final PolicySigner policySigner; private final PostPolicyGenerator policyGenerator; @@ -83,23 +86,25 @@ public class ProfileController { private final S3Client s3client; private final String bucket; - public ProfileController(RateLimiters rateLimiters, + public ProfileController( + RateLimiters rateLimiters, AccountsManager accountsManager, ProfilesManager profilesManager, UsernamesManager usernamesManager, DynamicConfigurationManager dynamicConfigurationManager, + ProfileBadgeConverter profileBadgeConverter, S3Client s3client, PostPolicyGenerator policyGenerator, PolicySigner policySigner, String bucket, ServerZkProfileOperations zkProfileOperations, - boolean isZkEnabled) - { + boolean isZkEnabled) { this.rateLimiters = rateLimiters; this.accountsManager = accountsManager; this.profilesManager = profilesManager; this.usernamesManager = usernamesManager; this.dynamicConfigurationManager = dynamicConfigurationManager; + this.profileBadgeConverter = profileBadgeConverter; this.zkProfileOperations = zkProfileOperations; this.bucket = bucket; this.s3client = s3client; @@ -175,23 +180,27 @@ public class ProfileController { @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{uuid}/{version}") - public Optional getProfile(@Auth Optional auth, + public Optional getProfile( + @Auth Optional auth, @HeaderParam(OptionalAccess.UNIDENTIFIED) Optional accessKey, + @Context Request request, @PathParam("uuid") UUID uuid, @PathParam("version") String version) throws RateLimitExceededException { if (!isZkEnabled) { throw new WebApplicationException(Response.Status.NOT_FOUND); } - return getVersionedProfile(auth.map(AuthenticatedAccount::getAccount), accessKey, uuid, version, Optional.empty()); + return getVersionedProfile(auth.map(AuthenticatedAccount::getAccount), accessKey, request, uuid, version, Optional.empty()); } @Timed @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{uuid}/{version}/{credentialRequest}") - public Optional getProfile(@Auth Optional auth, + public Optional getProfile( + @Auth Optional auth, @HeaderParam(OptionalAccess.UNIDENTIFIED) Optional accessKey, + @Context Request request, @PathParam("uuid") UUID uuid, @PathParam("version") String version, @PathParam("credentialRequest") String credentialRequest) @@ -199,17 +208,17 @@ public class ProfileController { if (!isZkEnabled) { throw new WebApplicationException(Response.Status.NOT_FOUND); } - return getVersionedProfile(auth.map(AuthenticatedAccount::getAccount), accessKey, uuid, version, - Optional.of(credentialRequest)); + return getVersionedProfile(auth.map(AuthenticatedAccount::getAccount), accessKey, request, uuid, version, Optional.of(credentialRequest)); } - private Optional getVersionedProfile(Optional requestAccount, - Optional accessKey, - UUID uuid, - String version, - Optional credentialRequest) - throws RateLimitExceededException - { + private Optional getVersionedProfile( + Optional requestAccount, + Optional accessKey, + Request request, + UUID uuid, + String version, + Optional credentialRequest) + throws RateLimitExceededException { if (!isZkEnabled) throw new WebApplicationException(Response.Status.NOT_FOUND); try { @@ -244,7 +253,8 @@ public class ProfileController { Optional credential = getProfileCredential(credentialRequest, profile, uuid); - return Optional.of(new Profile(name, + return Optional.of(new Profile( + name, about, aboutEmoji, avatar, @@ -255,7 +265,7 @@ public class ProfileController { UserCapabilities.createForAccount(accountProfile.get()), username.orElse(null), null, - List.of(), + profileBadgeConverter.convert(request, accountProfile.get().getBadges()), credential.orElse(null))); } catch (InvalidInputException e) { logger.info("Bad profile request", e); @@ -298,7 +308,7 @@ public class ProfileController { UserCapabilities.createForAccount(accountProfile.get()), username, accountProfile.get().getUuid(), - List.of(), + Set.of(), null); } @@ -371,7 +381,7 @@ public class ProfileController { UserCapabilities.createForAccount(accountProfile.get()), username.orElse(null), null, - List.of(), + Set.of(), null); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/Profile.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/Profile.java index edb31eb6a..6e71a0070 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/Profile.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/entities/Profile.java @@ -9,7 +9,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.annotations.VisibleForTesting; -import java.util.List; +import java.util.Set; import java.util.UUID; import org.signal.zkgroup.profiles.ProfileKeyCredentialResponse; @@ -49,7 +49,7 @@ public class Profile { private UUID uuid; @JsonProperty - private List badges; + private Set badges; @JsonProperty @JsonSerialize(using = ProfileKeyCredentialResponseAdapter.Serializing.class) @@ -61,7 +61,7 @@ public class Profile { public Profile( String name, String about, String aboutEmoji, String avatar, String paymentAddress, String identityKey, String unidentifiedAccess, boolean unrestrictedUnidentifiedAccess, UserCapabilities capabilities, String username, - UUID uuid, final List badges, ProfileKeyCredentialResponse credential) + UUID uuid, Set badges, ProfileKeyCredentialResponse credential) { this.name = name; this.about = about; @@ -130,7 +130,7 @@ public class Profile { return uuid; } - public List getBadges() { + public Set getBadges() { return badges; } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java index 466987375..cbcb4720f 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ProfileControllerTest.java @@ -90,11 +90,13 @@ class ProfileControllerTest { ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) .setMapper(SystemMapper.getMapper()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory()) - .addResource(new ProfileController(rateLimiters, + .addResource(new ProfileController( + rateLimiters, accountsManager, profilesManager, usernamesManager, dynamicConfigurationManager, + (request, accountBadges) -> Set.of(), // TODO: Test with some badges. s3client, postPolicyGenerator, policySigner,