parent
b8fb8a52f1
commit
f5aec1c894
|
@ -41,6 +41,7 @@ import org.whispersystems.textsecuregcm.controllers.FederationControllerV2;
|
|||
import org.whispersystems.textsecuregcm.controllers.KeepAliveController;
|
||||
import org.whispersystems.textsecuregcm.controllers.KeysController;
|
||||
import org.whispersystems.textsecuregcm.controllers.MessageController;
|
||||
import org.whispersystems.textsecuregcm.controllers.ProfileController;
|
||||
import org.whispersystems.textsecuregcm.controllers.ProvisioningController;
|
||||
import org.whispersystems.textsecuregcm.controllers.ReceiptController;
|
||||
import org.whispersystems.textsecuregcm.federation.FederatedClientManager;
|
||||
|
@ -196,6 +197,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
AttachmentController attachmentController = new AttachmentController(rateLimiters, federatedClientManager, urlSigner);
|
||||
KeysController keysController = new KeysController(rateLimiters, keys, accountsManager, federatedClientManager);
|
||||
MessageController messageController = new MessageController(rateLimiters, pushSender, receiptSender, accountsManager, messagesManager, federatedClientManager);
|
||||
ProfileController profileController = new ProfileController(rateLimiters , accountsManager);
|
||||
|
||||
environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<Account>()
|
||||
.setAuthenticator(deviceAuthenticator)
|
||||
|
@ -217,6 +219,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
environment.jersey().register(attachmentController);
|
||||
environment.jersey().register(keysController);
|
||||
environment.jersey().register(messageController);
|
||||
environment.jersey().register(profileController);
|
||||
|
||||
///
|
||||
WebSocketEnvironment webSocketEnvironment = new WebSocketEnvironment(environment, config.getWebSocketConfiguration(), 90000);
|
||||
|
@ -224,6 +227,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
webSocketEnvironment.setConnectListener(new AuthenticatedConnectListener(accountsManager, pushSender, receiptSender, messagesManager, pubSubManager));
|
||||
webSocketEnvironment.jersey().register(new KeepAliveController(pubSubManager));
|
||||
webSocketEnvironment.jersey().register(messageController);
|
||||
webSocketEnvironment.jersey().register(profileController);
|
||||
|
||||
WebSocketEnvironment provisioningEnvironment = new WebSocketEnvironment(environment, webSocketEnvironment.getRequestLog(), 60000);
|
||||
provisioningEnvironment.setConnectListener(new ProvisioningConnectListener(pubSubManager));
|
||||
|
|
|
@ -53,6 +53,9 @@ public class RateLimitsConfiguration {
|
|||
@JsonProperty
|
||||
private RateLimitConfiguration turnAllocations = new RateLimitConfiguration(60, 60);
|
||||
|
||||
@JsonProperty
|
||||
private RateLimitConfiguration profile = new RateLimitConfiguration(4320, 3);
|
||||
|
||||
public RateLimitConfiguration getAllocateDevice() {
|
||||
return allocateDevice;
|
||||
}
|
||||
|
@ -97,6 +100,10 @@ public class RateLimitsConfiguration {
|
|||
return turnAllocations;
|
||||
}
|
||||
|
||||
public RateLimitConfiguration getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public static class RateLimitConfiguration {
|
||||
@JsonProperty
|
||||
private int bucketSize;
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package org.whispersystems.textsecuregcm.controllers;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.google.common.base.Optional;
|
||||
import org.whispersystems.textsecuregcm.entities.Profile;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import io.dropwizard.auth.Auth;
|
||||
|
||||
@Path("/v1/profile")
|
||||
public class ProfileController {
|
||||
|
||||
private final RateLimiters rateLimiters;
|
||||
private final AccountsManager accountsManager;
|
||||
|
||||
public ProfileController(RateLimiters rateLimiters, AccountsManager accountsManager) {
|
||||
this.rateLimiters = rateLimiters;
|
||||
this.accountsManager = accountsManager;
|
||||
}
|
||||
|
||||
@Timed
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/{number}")
|
||||
public Profile getProfile(@Auth Account account, @PathParam("number") String number)
|
||||
throws RateLimitExceededException
|
||||
{
|
||||
rateLimiters.getProfileLimiter().validate(account.getNumber());
|
||||
|
||||
Optional<Account> accountProfile = accountsManager.get(number);
|
||||
|
||||
if (!accountProfile.isPresent()) {
|
||||
throw new WebApplicationException(Response.status(404).build());
|
||||
}
|
||||
|
||||
return new Profile(accountProfile.get().getIdentityKey());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
public class Profile {
|
||||
|
||||
@JsonProperty
|
||||
private String identityKey;
|
||||
|
||||
public Profile() {}
|
||||
|
||||
public Profile(String identityKey) {
|
||||
this.identityKey = identityKey;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public String getIdentityKey() {
|
||||
return identityKey;
|
||||
}
|
||||
}
|
|
@ -38,6 +38,8 @@ public class RateLimiters {
|
|||
|
||||
private final RateLimiter turnLimiter;
|
||||
|
||||
private final RateLimiter profileLimiter;
|
||||
|
||||
public RateLimiters(RateLimitsConfiguration config, JedisPool cacheClient) {
|
||||
this.smsDestinationLimiter = new RateLimiter(cacheClient, "smsDestination",
|
||||
config.getSmsDestination().getBucketSize(),
|
||||
|
@ -82,6 +84,10 @@ public class RateLimiters {
|
|||
this.turnLimiter = new RateLimiter(cacheClient, "turnAllocate",
|
||||
config.getTurnAllocations().getBucketSize(),
|
||||
config.getTurnAllocations().getLeakRatePerMinute());
|
||||
|
||||
this.profileLimiter = new RateLimiter(cacheClient, "profile",
|
||||
config.getProfile().getBucketSize(),
|
||||
config.getProfile().getLeakRatePerMinute());
|
||||
}
|
||||
|
||||
public RateLimiter getAllocateDeviceLimiter() {
|
||||
|
@ -128,4 +134,8 @@ public class RateLimiters {
|
|||
return turnLimiter;
|
||||
}
|
||||
|
||||
public RateLimiter getProfileLimiter() {
|
||||
return profileLimiter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -145,7 +145,11 @@ public class APNSender implements Managed {
|
|||
return;
|
||||
}
|
||||
|
||||
logger.info("APN Unregister APN ID matches! " + number + ", " + deviceId);
|
||||
if (registrationId.equals(device.get().getApnId())) {
|
||||
logger.info("APN Unregister APN ID matches! " + number + ", " + deviceId);
|
||||
} else if (registrationId.equals(device.get().getVoipApnId())) {
|
||||
logger.info("APN Unregister VoIP ID matches! " + number + ", " + deviceId);
|
||||
}
|
||||
|
||||
long tokenTimestamp = device.get().getPushTimestamp();
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import org.junit.Test;
|
||||
import org.whispersystems.textsecuregcm.controllers.ProfileController;
|
||||
import org.whispersystems.textsecuregcm.controllers.RateLimitExceededException;
|
||||
import org.whispersystems.textsecuregcm.entities.Profile;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class ProfileControllerTest {
|
||||
|
||||
@Test
|
||||
public void testProfileGet() throws RateLimitExceededException {
|
||||
Account requestAccount = mock(Account.class );
|
||||
Account profileAccount = mock(Account.class );
|
||||
RateLimiter rateLimiter = mock(RateLimiter.class );
|
||||
RateLimiters rateLimiters = mock(RateLimiters.class );
|
||||
AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
|
||||
when(rateLimiters.getProfileLimiter()).thenReturn(rateLimiter);
|
||||
when(requestAccount.getNumber()).thenReturn("foo");
|
||||
when(profileAccount.getIdentityKey()).thenReturn("bar");
|
||||
when(accountsManager.get(eq("baz"))).thenReturn(Optional.of(profileAccount));
|
||||
|
||||
ProfileController profileController = new ProfileController(rateLimiters, accountsManager);
|
||||
Profile result = profileController.getProfile(requestAccount, "baz");
|
||||
|
||||
assertEquals(result.getIdentityKey(), "bar");
|
||||
|
||||
verify(accountsManager, times(1)).get(eq("baz"));
|
||||
verify(rateLimiters, times(1)).getProfileLimiter();
|
||||
verify(rateLimiter, times(1)).validate("foo");
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue