Skip to content

Commit

Permalink
Count requests with missing device capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
jon-signal authored Dec 6, 2023
1 parent 072b470 commit 6cdf8eb
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import com.google.common.net.HttpHeaders;
import io.dropwizard.auth.Auth;
import io.lettuce.core.SetArgs;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tags;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.headers.Header;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
Expand Down Expand Up @@ -59,6 +61,8 @@
import org.whispersystems.textsecuregcm.entities.PreKeySignatureValidator;
import org.whispersystems.textsecuregcm.identity.IdentityType;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.metrics.MetricsUtil;
import org.whispersystems.textsecuregcm.metrics.UserAgentTagUtil;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
Expand Down Expand Up @@ -91,6 +95,9 @@ public class DeviceController {
@VisibleForTesting
static final Duration TOKEN_EXPIRATION_DURATION = Duration.ofMinutes(10);

private static final String MISSING_DEVICE_CAPABILITIES_COUNTER_NAME =
MetricsUtil.name(DeviceController.class, "missingDeviceCapabilities");

public DeviceController(byte[] linkDeviceSecret,
AccountsManager accounts,
MessagesManager messages,
Expand Down Expand Up @@ -175,7 +182,7 @@ public VerificationCode createDeviceToken(@Auth AuthenticatedAccount auth)
}

/**
* @deprecated callers should use {@link #linkDevice(BasicAuthorizationHeader, LinkDeviceRequest, ContainerRequest)}
* @deprecated callers should use {@link #linkDevice(BasicAuthorizationHeader, String, LinkDeviceRequest, ContainerRequest)}
* instead
*/
@PUT
Expand All @@ -186,6 +193,7 @@ public VerificationCode createDeviceToken(@Auth AuthenticatedAccount auth)
@Deprecated(forRemoval = true)
public DeviceResponse verifyDeviceToken(@PathParam("verification_code") String verificationCode,
@HeaderParam(HttpHeaders.AUTHORIZATION) BasicAuthorizationHeader authorizationHeader,
@HeaderParam(HttpHeaders.USER_AGENT) final String userAgent,
@NotNull @Valid AccountAttributes accountAttributes,
@Context ContainerRequest containerRequest)
throws RateLimitExceededException, DeviceLimitExceededException {
Expand All @@ -194,7 +202,8 @@ public DeviceResponse verifyDeviceToken(@PathParam("verification_code") String v
verificationCode,
accountAttributes,
containerRequest,
Optional.empty());
Optional.empty(),
userAgent);

final Account account = accountAndDevice.first();
final Device device = accountAndDevice.second();
Expand All @@ -219,6 +228,7 @@ public DeviceResponse verifyDeviceToken(@PathParam("verification_code") String v
name = "Retry-After",
description = "If present, an positive integer indicating the number of seconds before a subsequent attempt could succeed"))
public DeviceResponse linkDevice(@HeaderParam(HttpHeaders.AUTHORIZATION) BasicAuthorizationHeader authorizationHeader,
@HeaderParam(HttpHeaders.USER_AGENT) final String userAgent,
@NotNull @Valid LinkDeviceRequest linkDeviceRequest,
@Context ContainerRequest containerRequest)
throws RateLimitExceededException, DeviceLimitExceededException {
Expand All @@ -227,7 +237,8 @@ public DeviceResponse linkDevice(@HeaderParam(HttpHeaders.AUTHORIZATION) BasicAu
linkDeviceRequest.verificationCode(),
linkDeviceRequest.accountAttributes(),
containerRequest,
Optional.of(linkDeviceRequest.deviceActivationRequest()));
Optional.of(linkDeviceRequest.deviceActivationRequest()),
userAgent);

final Account account = accountAndDevice.first();
final Device device = accountAndDevice.second();
Expand Down Expand Up @@ -341,7 +352,8 @@ private Pair<Account, Device> createDevice(final String password,
final String verificationCode,
final AccountAttributes accountAttributes,
final ContainerRequest containerRequest,
final Optional<DeviceActivationRequest> maybeDeviceActivationRequest)
final Optional<DeviceActivationRequest> maybeDeviceActivationRequest,
final String userAgent)
throws RateLimitExceededException, DeviceLimitExceededException {

final Optional<UUID> maybeAciFromToken = checkVerificationToken(verificationCode);
Expand Down Expand Up @@ -379,6 +391,14 @@ private Pair<Account, Device> createDevice(final String password,
}

final DeviceCapabilities capabilities = accountAttributes.getCapabilities();

if (capabilities == null) {
Metrics.counter(MISSING_DEVICE_CAPABILITIES_COUNTER_NAME,
Tags.of(UserAgentTagUtil.getPlatformTag(userAgent),
io.micrometer.core.instrument.Tag.of("atomic", String.valueOf(maybeDeviceActivationRequest.isPresent()))))
.increment();
}

if (capabilities != null && isCapabilityDowngrade(account, capabilities)) {
throw new WebApplicationException(Response.status(409).build());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ public class RegistrationController {
.register(Metrics.globalRegistry);

private static final String ACCOUNT_CREATED_COUNTER_NAME = name(RegistrationController.class, "accountCreated");
private static final String MISSING_DEVICE_CAPABILITIES_COUNTER_NAME =
name(RegistrationController.class, "missingDeviceCapabilities");

private static final String COUNTRY_CODE_TAG_NAME = "countryCode";
private static final String REGION_CODE_TAG_NAME = "regionCode";
private static final String VERIFICATION_TYPE_TAG_NAME = "verification";
private static final String INVALID_ACCOUNT_ATTRS_COUNTER_NAME = name(RegistrationController.class, "invalidAccountAttrs");

private final AccountsManager accounts;
private final PhoneVerificationTokenManager phoneVerificationTokenManager;
Expand Down Expand Up @@ -106,6 +108,12 @@ public AccountIdentityResponse register(
final String number = authorizationHeader.getUsername();
final String password = authorizationHeader.getPassword();

if (registrationRequest.accountAttributes().getCapabilities() == null) {
Metrics.counter(MISSING_DEVICE_CAPABILITIES_COUNTER_NAME,
Tags.of(UserAgentTagUtil.getPlatformTag(userAgent)))
.increment();
}

RateLimiter.adaptLegacyException(() -> rateLimiters.getRegistrationLimiter().validate(number));

final PhoneVerificationRequest.VerificationType verificationType = phoneVerificationTokenManager.verify(number,
Expand Down

0 comments on commit 6cdf8eb

Please sign in to comment.