diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAndAuthenticatedDeviceHolder.java b/service/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAndAuthenticatedDeviceHolder.java deleted file mode 100644 index 293cb62df..000000000 --- a/service/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAndAuthenticatedDeviceHolder.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2021 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.whispersystems.textsecuregcm.auth; - -import org.whispersystems.textsecuregcm.storage.Account; -import org.whispersystems.textsecuregcm.storage.Device; -import java.time.Instant; -import java.util.UUID; - -public interface AccountAndAuthenticatedDeviceHolder { - - UUID getAccountIdentifier(); - - byte getDeviceId(); - - Instant getPrimaryDeviceLastSeen(); - - @Deprecated(forRemoval = true) - Account getAccount(); - - @Deprecated(forRemoval = true) - Device getAuthenticatedDevice(); -} diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticator.java b/service/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticator.java index f416997ee..2b3d83314 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticator.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticator.java @@ -15,10 +15,12 @@ import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Tags; import java.time.Clock; import java.time.Duration; +import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Optional; import java.util.UUID; import org.apache.commons.lang3.StringUtils; +import org.whispersystems.textsecuregcm.identity.IdentityType; import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.Device; @@ -112,7 +114,9 @@ public class AccountAuthenticator implements Authenticator authenticatedDevice.getDeviceId() != Device.PRIMARY_ID) + .filter(authenticatedDevice -> authenticatedDevice.deviceId() != Device.PRIMARY_ID) .ifPresent(authenticatedDevice -> { - final Instant primaryDeviceLastSeen = authenticatedDevice.getPrimaryDeviceLastSeen(); - - if (primaryDeviceLastSeen.isBefore(clock.instant().minus(minIdleDuration))) { + if (authenticatedDevice.primaryDeviceLastSeen().isBefore(clock.instant().minus(minIdleDuration))) { response.addHeader(ALERT_HEADER, IDLE_PRIMARY_DEVICE_ALERT); IDLE_PRIMARY_WARNING_COUNTER.increment(); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java index 621073e16..f0882ced4 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java @@ -98,10 +98,10 @@ public class AccountController { public void setGcmRegistrationId(@Auth AuthenticatedDevice auth, @NotNull @Valid GcmRegistrationId registrationId) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); - final Device device = account.getDevice(auth.getDeviceId()) + final Device device = account.getDevice(auth.deviceId()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); if (Objects.equals(device.getGcmId(), registrationId.gcmRegistrationId())) { @@ -118,10 +118,10 @@ public class AccountController { @DELETE @Path("/gcm/") public void deleteGcmRegistrationId(@Auth AuthenticatedDevice auth) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); - final Device device = account.getDevice(auth.getDeviceId()) + final Device device = account.getDevice(auth.deviceId()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); accounts.updateDevice(account, device.getId(), d -> { @@ -138,10 +138,10 @@ public class AccountController { public void setApnRegistrationId(@Auth AuthenticatedDevice auth, @NotNull @Valid ApnRegistrationId registrationId) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); - final Device device = account.getDevice(auth.getDeviceId()) + final Device device = account.getDevice(auth.deviceId()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); // Unlike FCM tokens, we need current "last updated" timestamps for APNs tokens and so update device records @@ -156,10 +156,10 @@ public class AccountController { @DELETE @Path("/apn/") public void deleteApnRegistrationId(@Auth AuthenticatedDevice auth) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); - final Device device = account.getDevice(auth.getDeviceId()) + final Device device = account.getDevice(auth.deviceId()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); accounts.updateDevice(account, device.getId(), d -> { @@ -179,7 +179,7 @@ public class AccountController { public void setRegistrationLock(@Auth AuthenticatedDevice auth, @NotNull @Valid RegistrationLock accountLock) { final SaltedTokenHash credentials = SaltedTokenHash.generateFor(accountLock.getRegistrationLock()); - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); accounts.update(account, @@ -189,7 +189,7 @@ public class AccountController { @DELETE @Path("/registration_lock") public void removeRegistrationLock(@Auth AuthenticatedDevice auth) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); accounts.update(account, a -> a.setRegistrationLock(null, null)); @@ -215,16 +215,16 @@ public class AccountController { requiredMode = Schema.RequiredMode.NOT_REQUIRED) final Byte deviceId) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); - final byte targetDeviceId = deviceId == null ? auth.getDeviceId() : deviceId; + final byte targetDeviceId = deviceId == null ? auth.deviceId() : deviceId; if (account.getDevice(targetDeviceId).isEmpty()) { throw new NotFoundException(); } - final boolean mayChangeName = auth.getDeviceId() == Device.PRIMARY_ID || auth.getDeviceId() == targetDeviceId; + final boolean mayChangeName = auth.deviceId() == Device.PRIMARY_ID || auth.deviceId() == targetDeviceId; if (!mayChangeName) { throw new ForbiddenException(); @@ -241,11 +241,11 @@ public class AccountController { @Auth AuthenticatedDevice auth, @HeaderParam(HeaderUtils.X_SIGNAL_AGENT) String userAgent, @NotNull @Valid AccountAttributes attributes) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); final Account updatedAccount = accounts.update(account, a -> { - a.getDevice(auth.getDeviceId()).ifPresent(d -> { + a.getDevice(auth.deviceId()).ifPresent(d -> { d.setFetchesMessages(attributes.getFetchesMessages()); d.setName(attributes.getName()); d.setLastSeen(Util.todayInMillis()); @@ -270,7 +270,7 @@ public class AccountController { @Path("/whoami") @Produces(MediaType.APPLICATION_JSON) public AccountIdentityResponse whoAmI(@Auth final AuthenticatedDevice auth) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); return AccountIdentityResponseBuilder.fromAccount(account); @@ -288,7 +288,7 @@ public class AccountController { @ApiResponse(responseCode = "204", description = "Username successfully deleted.", useReturnTypeSchema = true) @ApiResponse(responseCode = "401", description = "Account authentication check failed.") public CompletableFuture deleteUsernameHash(@Auth final AuthenticatedDevice auth) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); return accounts.clearUsernameHash(account) @@ -315,10 +315,10 @@ public class AccountController { @Auth final AuthenticatedDevice auth, @NotNull @Valid final ReserveUsernameHashRequest usernameRequest) throws RateLimitExceededException { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); - rateLimiters.getUsernameReserveLimiter().validate(auth.getAccountIdentifier()); + rateLimiters.getUsernameReserveLimiter().validate(auth.accountIdentifier()); for (final byte[] hash : usernameRequest.usernameHashes()) { if (hash.length != USERNAME_HASH_LENGTH) { @@ -358,7 +358,7 @@ public class AccountController { @Auth final AuthenticatedDevice auth, @NotNull @Valid final ConfirmUsernameHashRequest confirmRequest) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); try { @@ -446,9 +446,9 @@ public class AccountController { @NotNull @Valid final EncryptedUsername encryptedUsername) throws RateLimitExceededException { // check ratelimiter for username link operations - rateLimiters.forDescriptor(RateLimiters.For.USERNAME_LINK_OPERATION).validate(auth.getAccountIdentifier()); + rateLimiters.forDescriptor(RateLimiters.For.USERNAME_LINK_OPERATION).validate(auth.accountIdentifier()); - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); // check if username hash is set for the account @@ -480,9 +480,9 @@ public class AccountController { @ApiResponse(responseCode = "429", description = "Ratelimited.") public void deleteUsernameLink(@Auth final AuthenticatedDevice auth) throws RateLimitExceededException { // check ratelimiter for username link operations - rateLimiters.forDescriptor(RateLimiters.For.USERNAME_LINK_OPERATION).validate(auth.getAccountIdentifier()); + rateLimiters.forDescriptor(RateLimiters.For.USERNAME_LINK_OPERATION).validate(auth.accountIdentifier()); - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); clearUsernameLink(account); @@ -547,7 +547,7 @@ public class AccountController { @DELETE @Path("/me") public CompletableFuture deleteAccount(@Auth AuthenticatedDevice auth) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); return accounts.delete(account, AccountsManager.DeletionReason.USER_REQUEST).thenApply(Util.ASYNC_EMPTY_RESPONSE); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountControllerV2.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountControllerV2.java index c069aa103..94ffcb5d0 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountControllerV2.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountControllerV2.java @@ -105,7 +105,7 @@ public class AccountControllerV2 { @HeaderParam(HttpHeaders.USER_AGENT) final String userAgentString, @Context final ContainerRequestContext requestContext) throws RateLimitExceededException, InterruptedException { - if (authenticatedDevice.getDeviceId() != Device.PRIMARY_ID) { + if (authenticatedDevice.deviceId() != Device.PRIMARY_ID) { throw new ForbiddenException(); } @@ -115,7 +115,7 @@ public class AccountControllerV2 { final String number = request.number(); - final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); // Only verify and check reglock if there's a data change to be made... @@ -191,7 +191,7 @@ public class AccountControllerV2 { @HeaderParam(HttpHeaders.USER_AGENT) @Nullable final String userAgentString, @NotNull @Valid final PhoneNumberIdentityKeyDistributionRequest request) { - if (authenticatedDevice.getDeviceId() != Device.PRIMARY_ID) { + if (authenticatedDevice.deviceId() != Device.PRIMARY_ID) { throw new ForbiddenException(); } @@ -199,7 +199,7 @@ public class AccountControllerV2 { throw new WebApplicationException("Invalid signature", 422); } - final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); try { @@ -243,7 +243,7 @@ public class AccountControllerV2 { @Auth AuthenticatedDevice auth, @NotNull @Valid PhoneNumberDiscoverabilityRequest phoneNumberDiscoverability) { - final Account account = accountsManager.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); accountsManager.update(account, a -> a.setDiscoverableByPhoneNumber( @@ -259,7 +259,7 @@ public class AccountControllerV2 { useReturnTypeSchema = true) public AccountDataReportResponse getAccountDataReport(@Auth final AuthenticatedDevice auth) { - final Account account = accountsManager.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); return new AccountDataReportResponse(UUID.randomUUID(), Instant.now(), diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ArchiveController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ArchiveController.java index 28a34ca3b..16ce7e450 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ArchiveController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ArchiveController.java @@ -147,12 +147,12 @@ public class ArchiveController { @Auth final AuthenticatedDevice authenticatedDevice, @Valid @NotNull final SetBackupIdRequest setBackupIdRequest) throws RateLimitExceededException { - return accountsManager.getByAccountIdentifierAsync(authenticatedDevice.getAccountIdentifier()) + return accountsManager.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier()) .thenCompose(maybeAccount -> { final Account account = maybeAccount .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); - final Device device = account.getDevice(authenticatedDevice.getDeviceId()) + final Device device = account.getDevice(authenticatedDevice.deviceId()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); return backupAuthManager @@ -206,7 +206,7 @@ public class ArchiveController { @Auth final AuthenticatedDevice authenticatedDevice, @Valid @NotNull final RedeemBackupReceiptRequest redeemBackupReceiptRequest) { - return accountsManager.getByAccountIdentifierAsync(authenticatedDevice.getAccountIdentifier()) + return accountsManager.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier()) .thenCompose(maybeAccount -> { final Account account = maybeAccount .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); @@ -280,7 +280,7 @@ public class ArchiveController { final Map> credentialsByType = new ConcurrentHashMap<>(); - return accountsManager.getByAccountIdentifierAsync(authenticatedDevice.getAccountIdentifier()) + return accountsManager.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier()) .thenCompose(maybeAccount -> { final Account account = maybeAccount .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AttachmentControllerV4.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AttachmentControllerV4.java index 5ea8baf5d..7d34f37d1 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AttachmentControllerV4.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AttachmentControllerV4.java @@ -79,9 +79,9 @@ public class AttachmentControllerV4 { description = "If present, an positive integer indicating the number of seconds before a subsequent attempt could succeed")) public AttachmentDescriptorV3 getAttachmentUploadForm(@Auth AuthenticatedDevice auth) throws RateLimitExceededException { - rateLimiter.validate(auth.getAccountIdentifier()); + rateLimiter.validate(auth.accountIdentifier()); final String key = generateAttachmentKey(); - final boolean useCdn3 = this.experimentEnrollmentManager.isEnrolled(auth.getAccountIdentifier(), CDN3_EXPERIMENT_NAME); + final boolean useCdn3 = this.experimentEnrollmentManager.isEnrolled(auth.accountIdentifier(), CDN3_EXPERIMENT_NAME); int cdn = useCdn3 ? 3 : 2; final AttachmentGenerator.Descriptor descriptor = this.attachmentGenerators.get(cdn).generateAttachment(key); return new AttachmentDescriptorV3(cdn, key, descriptor.headers(), descriptor.signedUploadLocation()); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallLinkController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallLinkController.java index edc884286..706732276 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallLinkController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallLinkController.java @@ -55,7 +55,7 @@ public class CallLinkController { final @NotNull @Valid GetCreateCallLinkCredentialsRequest request ) throws RateLimitExceededException { - rateLimiters.getCreateCallLinkLimiter().validate(auth.getAccountIdentifier()); + rateLimiters.getCreateCallLinkLimiter().validate(auth.accountIdentifier()); final Instant truncatedDayTimestamp = Instant.now().truncatedTo(ChronoUnit.DAYS); @@ -67,7 +67,7 @@ public class CallLinkController { } return new CreateCallLinkCredential( - createCallLinkCredentialRequest.issueCredential(new ServiceId.Aci(auth.getAccountIdentifier()), truncatedDayTimestamp, genericServerSecretParams).serialize(), + createCallLinkCredentialRequest.issueCredential(new ServiceId.Aci(auth.accountIdentifier()), truncatedDayTimestamp, genericServerSecretParams).serialize(), truncatedDayTimestamp.getEpochSecond() ); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallRoutingControllerV2.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallRoutingControllerV2.java index d3762e42a..f4c8d7cfd 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallRoutingControllerV2.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallRoutingControllerV2.java @@ -57,7 +57,7 @@ public class CallRoutingControllerV2 { public GetCallingRelaysResponse getCallingRelays(final @Auth AuthenticatedDevice auth) throws RateLimitExceededException, IOException { - rateLimiters.getCallEndpointLimiter().validate(auth.getAccountIdentifier()); + rateLimiters.getCallEndpointLimiter().validate(auth.accountIdentifier()); try { return new GetCallingRelaysResponse(List.of(cloudflareTurnCredentialsManager.retrieveFromCloudflare())); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CertificateController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CertificateController.java index fa71cc5b5..6e44b0222 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CertificateController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CertificateController.java @@ -82,11 +82,11 @@ public class CertificateController { Metrics.counter(GENERATE_DELIVERY_CERTIFICATE_COUNTER_NAME, INCLUDE_E164_TAG_NAME, String.valueOf(includeE164)) .increment(); - final Account account = accountsManager.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); return new DeliveryCertificate( - certificateGenerator.createFor(account, auth.getDeviceId(), includeE164)); + certificateGenerator.createFor(account, auth.deviceId(), includeE164)); } @GET @@ -110,7 +110,7 @@ public class CertificateController { throw new BadRequestException(); } - final Account account = accountsManager.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); final List credentials = new ArrayList<>(); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ChallengeController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ChallengeController.java index 12a2b772f..7f3d4c930 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ChallengeController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ChallengeController.java @@ -87,7 +87,7 @@ public class ChallengeController { @Context ContainerRequestContext requestContext, @HeaderParam(HttpHeaders.USER_AGENT) final String userAgent) throws RateLimitExceededException, IOException { - final Account account = accountsManager.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); Tags tags = Tags.of(UserAgentTagUtil.getPlatformTag(userAgent)); @@ -174,7 +174,7 @@ public class ChallengeController { public Response requestPushChallenge(@Auth final AuthenticatedDevice auth, @Context ContainerRequestContext requestContext) { - final Account account = accountsManager.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); final ChallengeConstraints constraints = challengeConstraintChecker.challengeConstraints(requestContext, account); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceCheckController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceCheckController.java index 9eaec898f..765580d91 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceCheckController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceCheckController.java @@ -100,9 +100,9 @@ public class DeviceCheckController { public ChallengeResponse attestChallenge(@Auth AuthenticatedDevice authenticatedDevice) throws RateLimitExceededException { rateLimiters.forDescriptor(RateLimiters.For.DEVICE_CHECK_CHALLENGE) - .validate(authenticatedDevice.getAccountIdentifier()); + .validate(authenticatedDevice.accountIdentifier()); - final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); return new ChallengeResponse(deviceCheckManager.createChallenge( @@ -141,7 +141,7 @@ public class DeviceCheckController { @RequestBody(description = "The attestation data, created by [attestKey](https://developer.apple.com/documentation/devicecheck/dcappattestservice/attestkey(_:clientdatahash:completionhandler:))") @NotNull final byte[] attestation) { - final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); try { @@ -182,9 +182,9 @@ public class DeviceCheckController { implementation = String.class)) @QueryParam("action") Action action) throws RateLimitExceededException { rateLimiters.forDescriptor(RateLimiters.For.DEVICE_CHECK_CHALLENGE) - .validate(authenticatedDevice.getAccountIdentifier()); + .validate(authenticatedDevice.accountIdentifier()); - final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); return new ChallengeResponse(deviceCheckManager.createChallenge(toChallengeType(action), account)); @@ -229,7 +229,7 @@ public class DeviceCheckController { @RequestBody(description = "The assertion created by [generateAssertion](https://developer.apple.com/documentation/devicecheck/dcappattestservice/generateassertion(_:clientdatahash:completionhandler:))") @NotNull final byte[] assertion) { - final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); try { diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java index 0a050ce6c..ad52a22d0 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DeviceController.java @@ -151,7 +151,7 @@ public class DeviceController { public DeviceInfoList getDevices(@Auth AuthenticatedDevice auth) { // Devices may change their own names (and primary devices may change the names of linked devices) and so the device // state associated with the authenticated account may be stale. Fetch a fresh copy to compensate. - return accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + return accounts.getByAccountIdentifier(auth.accountIdentifier()) .map(account -> new DeviceInfoList(account.getDevices().stream() .map(DeviceInfo::forDevice) .toList())) @@ -163,7 +163,7 @@ public class DeviceController { @Path("/{device_id}") @ChangesLinkedDevices public void removeDevice(@Auth AuthenticatedDevice auth, @PathParam("device_id") byte deviceId) { - if (auth.getDeviceId() != Device.PRIMARY_ID && auth.getDeviceId() != deviceId) { + if (auth.deviceId() != Device.PRIMARY_ID && auth.deviceId() != deviceId) { throw new WebApplicationException(Response.Status.UNAUTHORIZED); } @@ -171,7 +171,7 @@ public class DeviceController { throw new ForbiddenException(); } - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); accounts.removeDevice(account, deviceId).join(); @@ -208,7 +208,7 @@ public class DeviceController { public LinkDeviceToken createDeviceToken(@Auth AuthenticatedDevice auth) throws RateLimitExceededException, DeviceLimitExceededException { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); rateLimiters.getAllocateDeviceLimiter().validate(account.getUuid()); @@ -223,7 +223,7 @@ public class DeviceController { throw new DeviceLimitExceededException(account.getDevices().size(), maxDeviceLimit); } - if (auth.getDeviceId() != Device.PRIMARY_ID) { + if (auth.deviceId() != Device.PRIMARY_ID) { throw new WebApplicationException(Response.Status.UNAUTHORIZED); } @@ -367,8 +367,8 @@ public class DeviceController { final AtomicInteger linkedDeviceListenerCounter = getCounterForLinkedDeviceListeners(userAgent); linkedDeviceListenerCounter.incrementAndGet(); - return rateLimiters.getWaitForLinkedDeviceLimiter().validateAsync(authenticatedDevice.getAccountIdentifier()) - .thenCompose(ignored -> accounts.getByAccountIdentifierAsync(authenticatedDevice.getAccountIdentifier())) + return rateLimiters.getWaitForLinkedDeviceLimiter().validateAsync(authenticatedDevice.accountIdentifier()) + .thenCompose(ignored -> accounts.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier())) .thenCompose(maybeAccount -> { final Account account = maybeAccount.orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); @@ -376,8 +376,8 @@ public class DeviceController { .thenApply(sample -> new Pair<>(account, sample)); }) .thenCompose(accountAndSample -> accounts.waitForNewLinkedDevice( - authenticatedDevice.getAccountIdentifier(), - accountAndSample.first().getDevice(authenticatedDevice.getDeviceId()) + authenticatedDevice.accountIdentifier(), + accountAndSample.first().getDevice(authenticatedDevice.deviceId()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)), tokenIdentifier, Duration.ofSeconds(timeoutSeconds)) @@ -414,10 +414,10 @@ public class DeviceController { @NotNull final Map capabilities) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); - accounts.updateDevice(account, auth.getDeviceId(), + accounts.updateDevice(account, auth.deviceId(), d -> d.setCapabilities(DeviceCapabilityAdapter.mapToSet(capabilities))); } @@ -438,10 +438,10 @@ public class DeviceController { public CompletableFuture setPublicKey(@Auth final AuthenticatedDevice auth, final SetPublicKeyRequest setPublicKeyRequest) { - final Account account = accounts.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accounts.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); - return clientPublicKeysManager.setPublicKey(account, auth.getDeviceId(), setPublicKeyRequest.publicKey()); + return clientPublicKeysManager.setPublicKey(account, auth.deviceId(), setPublicKeyRequest.publicKey()); } private static boolean isCapabilityDowngrade(final Account account, final Set capabilities) { @@ -536,8 +536,8 @@ public class DeviceController { @NotNull @Valid final TransferArchiveUploadedRequest transferArchiveUploadedRequest) { return rateLimiters.getUploadTransferArchiveLimiter() - .validateAsync(authenticatedDevice.getAccountIdentifier()) - .thenCompose(ignored -> accounts.getByAccountIdentifierAsync(authenticatedDevice.getAccountIdentifier())) + .validateAsync(authenticatedDevice.accountIdentifier()) + .thenCompose(ignored -> accounts.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier())) .thenCompose(maybeAccount -> { final Account account = maybeAccount.orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); @@ -582,10 +582,10 @@ public class DeviceController { @HeaderParam(HttpHeaders.USER_AGENT) @Nullable String userAgent) { - final String rateLimiterKey = authenticatedDevice.getAccountIdentifier() + ":" + authenticatedDevice.getDeviceId(); + final String rateLimiterKey = authenticatedDevice.accountIdentifier() + ":" + authenticatedDevice.deviceId(); return rateLimiters.getWaitForTransferArchiveLimiter().validateAsync(rateLimiterKey) - .thenCompose(ignored -> accounts.getByAccountIdentifierAsync(authenticatedDevice.getAccountIdentifier())) + .thenCompose(ignored -> accounts.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier())) .thenCompose(maybeAccount -> { final Account account = maybeAccount.orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); @@ -593,7 +593,7 @@ public class DeviceController { .thenApply(sample -> new Pair<>(account, sample)); }) .thenCompose(accountAndSample -> accounts.waitForTransferArchive(accountAndSample.first(), - accountAndSample.first().getDevice(authenticatedDevice.getDeviceId()) + accountAndSample.first().getDevice(authenticatedDevice.deviceId()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)), Duration.ofSeconds(timeoutSeconds)) .thenApply(maybeTransferArchive -> maybeTransferArchive diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DirectoryV2Controller.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DirectoryV2Controller.java index 150006c26..a90658c0e 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DirectoryV2Controller.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DirectoryV2Controller.java @@ -56,6 +56,6 @@ public class DirectoryV2Controller { ) @ApiResponse(responseCode = "200", description = "`JSON` with generated credentials.", useReturnTypeSchema = true) public ExternalServiceCredentials getAuthToken(final @Auth AuthenticatedDevice auth) { - return directoryServiceTokenGenerator.generateForUuid(auth.getAccountIdentifier()); + return directoryServiceTokenGenerator.generateForUuid(auth.accountIdentifier()); } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DonationController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DonationController.java index 369463675..709b69542 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DonationController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DonationController.java @@ -120,12 +120,12 @@ public class DonationController { .build()); } - return accountsManager.getByAccountIdentifierAsync(auth.getAccountIdentifier()) + return accountsManager.getByAccountIdentifierAsync(auth.accountIdentifier()) .thenCompose(maybeAccount -> { final Account account = maybeAccount.orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); return redeemedReceiptsManager.put( - receiptSerial, receiptExpiration.getEpochSecond(), receiptLevel, auth.getAccountIdentifier()) + receiptSerial, receiptExpiration.getEpochSecond(), receiptLevel, auth.accountIdentifier()) .thenCompose(receiptMatched -> { if (!receiptMatched) { return CompletableFuture.completedFuture(Response.status(Status.BAD_REQUEST) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeepAliveController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeepAliveController.java index b19397fb1..fdb8fa017 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeepAliveController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeepAliveController.java @@ -48,12 +48,12 @@ public class KeepAliveController { @WebSocketSession WebSocketSessionContext context) { maybeAuth.ifPresent(auth -> { - if (!webSocketConnectionEventManager.isLocallyPresent(auth.getAccountIdentifier(), auth.getDeviceId())) { + if (!webSocketConnectionEventManager.isLocallyPresent(auth.accountIdentifier(), auth.deviceId())) { final Duration age = Duration.between(context.getClient().getCreated(), Instant.now()); logger.debug("***** No local subscription found for {}::{}; age = {}ms, User-Agent = {}", - auth.getAccountIdentifier(), auth.getDeviceId(), age.toMillis(), + auth.accountIdentifier(), auth.deviceId(), age.toMillis(), context.getClient().getUserAgent()); context.getClient().close(1000, "OK"); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java index 85d661fa6..efbf6d0b4 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/KeysController.java @@ -113,15 +113,15 @@ public class KeysController { public CompletableFuture getStatus(@Auth final AuthenticatedDevice auth, @QueryParam("identity") @DefaultValue("aci") final IdentityType identityType) { - return accounts.getByAccountIdentifierAsync(auth.getAccountIdentifier()) + return accounts.getByAccountIdentifierAsync(auth.accountIdentifier()) .thenCompose(maybeAccount -> { final Account account = maybeAccount.orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); final CompletableFuture ecCountFuture = - keysManager.getEcCount(account.getIdentifier(identityType), auth.getDeviceId()); + keysManager.getEcCount(account.getIdentifier(identityType), auth.deviceId()); final CompletableFuture pqCountFuture = - keysManager.getPqCount(account.getIdentifier(identityType), auth.getDeviceId()); + keysManager.getPqCount(account.getIdentifier(identityType), auth.deviceId()); return ecCountFuture.thenCombine(pqCountFuture, PreKeyCount::new); }); @@ -147,12 +147,12 @@ public class KeysController { @QueryParam("identity") @DefaultValue("aci") final IdentityType identityType, @HeaderParam(HttpHeaders.USER_AGENT) final String userAgent) { - return accounts.getByAccountIdentifierAsync(auth.getAccountIdentifier()) + return accounts.getByAccountIdentifierAsync(auth.accountIdentifier()) .thenCompose(maybeAccount -> { final Account account = maybeAccount .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); - final Device device = account.getDevice(auth.getDeviceId()) + final Device device = account.getDevice(auth.deviceId()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); final UUID identifier = account.getIdentifier(identityType); @@ -160,7 +160,7 @@ public class KeysController { checkSignedPreKeySignatures(setKeysRequest, account.getIdentityKey(identityType), userAgent); final Tag platformTag = UserAgentTagUtil.getPlatformTag(userAgent); - final Tag primaryDeviceTag = Tag.of(PRIMARY_DEVICE_TAG_NAME, String.valueOf(auth.getDeviceId() == Device.PRIMARY_ID)); + final Tag primaryDeviceTag = Tag.of(PRIMARY_DEVICE_TAG_NAME, String.valueOf(auth.deviceId() == Device.PRIMARY_ID)); final Tag identityTypeTag = Tag.of(IDENTITY_TYPE_TAG_NAME, identityType.name()); final List> storeFutures = new ArrayList<>(4); @@ -267,12 +267,12 @@ public class KeysController { @Auth final AuthenticatedDevice auth, @RequestBody @NotNull @Valid final CheckKeysRequest checkKeysRequest) { - return accounts.getByAccountIdentifierAsync(auth.getAccountIdentifier()) + return accounts.getByAccountIdentifierAsync(auth.accountIdentifier()) .thenCompose(maybeAccount -> { final Account account = maybeAccount.orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); final UUID identifier = account.getIdentifier(checkKeysRequest.identityType()); - final byte deviceId = auth.getDeviceId(); + final byte deviceId = auth.deviceId(); final CompletableFuture> ecSignedPreKeyFuture = keysManager.getEcSignedPreKey(identifier, deviceId); @@ -361,7 +361,7 @@ public class KeysController { } final Optional account = maybeAuthenticatedDevice - .map(authenticatedDevice -> accounts.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + .map(authenticatedDevice -> accounts.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED))); final Optional maybeTarget = accounts.getByServiceIdentifier(targetIdentifier); @@ -383,7 +383,7 @@ public class KeysController { if (account.isPresent()) { rateLimiters.getPreKeysLimiter().validate( - account.get().getUuid() + "." + maybeAuthenticatedDevice.get().getDeviceId() + "__" + targetIdentifier.uuid() + account.get().getUuid() + "." + maybeAuthenticatedDevice.get().deviceId() + "__" + targetIdentifier.uuid() + "." + deviceId); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java index ee3cb2641..3d4a399a8 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java @@ -274,7 +274,7 @@ public class MessageController { sendStoryMessage(destinationIdentifier, messages, context); } else if (source.isPresent()) { final AuthenticatedDevice authenticatedDevice = source.get(); - final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); if (account.isIdentifiedBy(destinationIdentifier)) { @@ -304,7 +304,7 @@ public class MessageController { final Account destination = accountsManager.getByServiceIdentifier(destinationIdentifier).orElseThrow(NotFoundException::new); - rateLimiters.getMessagesLimiter().validate(source.getAccountIdentifier(), destination.getUuid()); + rateLimiters.getMessagesLimiter().validate(source.accountIdentifier(), destination.getUuid()); sendIndividualMessage(destination, destinationIdentifier, @@ -423,8 +423,8 @@ public class MessageController { try { return message.toEnvelope( destinationIdentifier, - sender != null ? new AciServiceIdentifier(sender.getAccountIdentifier()) : null, - sender != null ? sender.getDeviceId() : null, + sender != null ? new AciServiceIdentifier(sender.accountIdentifier()) : null, + sender != null ? sender.deviceId() : null, messages.timestamp() == 0 ? System.currentTimeMillis() : messages.timestamp(), isStory, messages.online(), @@ -440,7 +440,7 @@ public class MessageController { .collect(Collectors.toMap(IncomingMessage::destinationDeviceId, IncomingMessage::destinationRegistrationId)); final Optional syncMessageSenderDeviceId = messageType == MessageType.SYNC - ? Optional.ofNullable(sender).map(AuthenticatedDevice::getDeviceId) + ? Optional.ofNullable(sender).map(AuthenticatedDevice::deviceId) : Optional.empty(); try { @@ -762,10 +762,10 @@ public class MessageController { @HeaderParam(WebsocketHeaders.X_SIGNAL_RECEIVE_STORIES) String receiveStoriesHeader, @HeaderParam(HttpHeaders.USER_AGENT) String userAgent) { - return accountsManager.getByAccountIdentifierAsync(auth.getAccountIdentifier()) + return accountsManager.getByAccountIdentifierAsync(auth.accountIdentifier()) .thenCompose(maybeAccount -> { final Account account = maybeAccount.orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); - final Device device = account.getDevice(auth.getDeviceId()) + final Device device = account.getDevice(auth.deviceId()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); final boolean shouldReceiveStories = WebsocketHeaders.parseReceiveStoriesHeader(receiveStoriesHeader); @@ -773,7 +773,7 @@ public class MessageController { pushNotificationManager.handleMessagesRetrieved(account, device, userAgent); return messagesManager.getMessagesForDevice( - auth.getAccountIdentifier(), + auth.accountIdentifier(), device, false) .map(messagesAndHasMore -> { @@ -788,7 +788,7 @@ public class MessageController { messageMetrics.measureAccountOutgoingMessageUuidMismatches(account, outgoingMessageEntity); messageMetrics.measureOutgoingMessageLatency(outgoingMessageEntity.serverTimestamp(), "rest", - auth.getDeviceId() == Device.PRIMARY_ID, + auth.deviceId() == Device.PRIMARY_ID, outgoingMessageEntity.urgent(), // Messages fetched via this endpoint (as opposed to WebSocketConnection) are never ephemeral // because, by definition, the client doesn't have a "live" connection via which to receive @@ -804,8 +804,8 @@ public class MessageController { .record(estimateMessageListSizeBytes(messages)); if (!messages.messages().isEmpty()) { - messageDeliveryLoopMonitor.recordDeliveryAttempt(auth.getAccountIdentifier(), - auth.getDeviceId(), + messageDeliveryLoopMonitor.recordDeliveryAttempt(auth.accountIdentifier(), + auth.deviceId(), messages.messages().getFirst().guid(), userAgent, "rest"); @@ -838,14 +838,14 @@ public class MessageController { @DELETE @Path("/uuid/{uuid}") public CompletableFuture removePendingMessage(@Auth AuthenticatedDevice auth, @PathParam("uuid") UUID uuid) { - final Account account = accountsManager.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); - final Device device = account.getDevice(auth.getDeviceId()) + final Device device = account.getDevice(auth.deviceId()) .orElseThrow(() -> new WebApplicationException(Status.UNAUTHORIZED)); return messagesManager.delete( - auth.getAccountIdentifier(), + auth.accountIdentifier(), device, uuid, null) @@ -857,7 +857,7 @@ public class MessageController { && removedMessage.envelopeType() != Type.SERVER_DELIVERY_RECEIPT) { if (removedMessage.sourceServiceId().get() instanceof AciServiceIdentifier aciServiceIdentifier) { try { - receiptSender.sendReceipt(removedMessage.destinationServiceId(), auth.getDeviceId(), + receiptSender.sendReceipt(removedMessage.destinationServiceId(), auth.deviceId(), aciServiceIdentifier, removedMessage.clientTimestamp()); } catch (Exception e) { logger.warn("Failed to send delivery receipt", e); @@ -914,7 +914,7 @@ public class MessageController { } } - UUID spamReporterUuid = auth.getAccountIdentifier(); + UUID spamReporterUuid = auth.accountIdentifier(); // spam report token is optional, but if provided ensure it is non-empty. final Optional maybeSpamReportToken = diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/PaymentsController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/PaymentsController.java index 15d0b8fcf..e66397dfc 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/PaymentsController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/PaymentsController.java @@ -43,7 +43,7 @@ public class PaymentsController { @Path("/auth") @Produces(MediaType.APPLICATION_JSON) public ExternalServiceCredentials getAuth(final @Auth AuthenticatedDevice auth) { - return paymentsServiceCredentialsGenerator.generateForUuid(auth.getAccountIdentifier()); + return paymentsServiceCredentialsGenerator.generateForUuid(auth.accountIdentifier()); } @GET 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 469a93504..a6f7bbe4e 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java @@ -153,11 +153,11 @@ public class ProfileController { @Consumes(MediaType.APPLICATION_JSON) public Response setProfile(@Auth AuthenticatedDevice auth, @NotNull @Valid CreateProfileRequest request) { - final Account account = accountsManager.getByAccountIdentifier(auth.getAccountIdentifier()) + final Account account = accountsManager.getByAccountIdentifier(auth.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED)); final Optional currentProfile = - profilesManager.get(auth.getAccountIdentifier(), request.version()); + profilesManager.get(auth.accountIdentifier(), request.version()); if (request.paymentAddress() != null && request.paymentAddress().length != 0) { final boolean hasDisallowedPrefix = @@ -181,7 +181,7 @@ public class ProfileController { case UPDATE -> ProfileHelper.generateAvatarObjectName(); }; - profilesManager.set(auth.getAccountIdentifier(), + profilesManager.set(auth.accountIdentifier(), new VersionedProfile( request.version(), request.name(), @@ -228,7 +228,7 @@ public class ProfileController { final Optional maybeRequester = maybeAuthenticatedDevice.map( - authenticatedDevice -> accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + authenticatedDevice -> accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED))); final Account targetAccount = verifyPermissionToReceiveProfile(maybeRequester, accessKey, accountIdentifier, "getVersionedProfile", userAgent); @@ -260,7 +260,7 @@ public class ProfileController { final Optional maybeRequester = maybeAuthenticatedDevice.map( - authenticatedDevice -> accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + authenticatedDevice -> accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED))); final Account targetAccount = verifyPermissionToReceiveProfile(maybeRequester, accessKey, accountIdentifier, "credentialRequest", userAgent); @@ -290,7 +290,7 @@ public class ProfileController { final Optional maybeRequester = maybeAuthenticatedDevice.map( - authenticatedDevice -> accountsManager.getByAccountIdentifier(authenticatedDevice.getAccountIdentifier()) + authenticatedDevice -> accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier()) .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED))); final Account targetAccount; diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProvisioningController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProvisioningController.java index 00c2af142..146ab1cf4 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProvisioningController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProvisioningController.java @@ -92,7 +92,7 @@ public class ProvisioningController { throw new WebApplicationException(Response.Status.BAD_REQUEST); } - rateLimiters.getMessagesLimiter().validate(auth.getAccountIdentifier()); + rateLimiters.getMessagesLimiter().validate(auth.accountIdentifier()); final boolean subscriberPresent = provisioningManager.sendProvisioningMessage(provisioningAddress, Base64.getMimeDecoder().decode(message.body())); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/RemoteConfigController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/RemoteConfigController.java index 85791435c..85a71c1c2 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/RemoteConfigController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/RemoteConfigController.java @@ -72,7 +72,7 @@ public class RemoteConfigController { return new UserRemoteConfigList(Stream.concat(remoteConfigsManager.getAll().stream().map(config -> { final byte[] hashKey = config.getHashKey() != null ? config.getHashKey().getBytes(StandardCharsets.UTF_8) : config.getName().getBytes(StandardCharsets.UTF_8); - boolean inBucket = isInBucket(digest, auth.getAccountIdentifier(), hashKey, config.getPercentage(), + boolean inBucket = isInBucket(digest, auth.accountIdentifier(), hashKey, config.getPercentage(), config.getUuids()); return new UserRemoteConfig(config.getName(), inBucket, inBucket ? config.getValue() : config.getDefaultValue()); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SecureStorageController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SecureStorageController.java index 7df8de81a..5a3aa0dfd 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SecureStorageController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SecureStorageController.java @@ -47,6 +47,6 @@ public class SecureStorageController { ) @ApiResponse(responseCode = "200", description = "`JSON` with generated credentials.", useReturnTypeSchema = true) public ExternalServiceCredentials getAuth(@Auth AuthenticatedDevice auth) { - return storageServiceCredentialsGenerator.generateForUuid(auth.getAccountIdentifier()); + return storageServiceCredentialsGenerator.generateForUuid(auth.accountIdentifier()); } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SecureValueRecovery2Controller.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SecureValueRecovery2Controller.java index e74052085..6c456b567 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SecureValueRecovery2Controller.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SecureValueRecovery2Controller.java @@ -78,7 +78,7 @@ public class SecureValueRecovery2Controller { @ApiResponse(responseCode = "200", description = "`JSON` with generated credentials.", useReturnTypeSchema = true) @ApiResponse(responseCode = "401", description = "Account authentication check failed.") public ExternalServiceCredentials getAuth(@Auth final AuthenticatedDevice auth) { - return backupServiceCredentialGenerator.generateFor(auth.getAccountIdentifier().toString()); + return backupServiceCredentialGenerator.generateFor(auth.accountIdentifier().toString()); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/StickerController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/StickerController.java index 0a5001a3d..0fd1a23a2 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/StickerController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/StickerController.java @@ -49,7 +49,7 @@ public class StickerController { public StickerPackFormUploadAttributes getStickersForm(@Auth AuthenticatedDevice auth, @PathParam("count") @Min(1) @Max(201) int stickerCount) throws RateLimitExceededException { - rateLimiters.getStickerPackLimiter().validate(auth.getAccountIdentifier()); + rateLimiters.getStickerPackLimiter().validate(auth.accountIdentifier()); ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC); String packId = generatePackId(); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilter.java b/service/src/main/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilter.java index aa973a681..d1fedc744 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilter.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilter.java @@ -97,7 +97,7 @@ public class RestDeprecationFilter implements ContainerRequestFilter { } if (securityContext.getUserPrincipal() instanceof AuthenticatedDevice authenticatedDevice) { - return experimentEnrollmentManager.isEnrolled(authenticatedDevice.getAccountIdentifier(), AUTHENTICATED_EXPERIMENT_NAME); + return experimentEnrollmentManager.isEnrolled(authenticatedDevice.accountIdentifier(), AUTHENTICATED_EXPERIMENT_NAME); } else { log.error("Security context was not null but user principal was of type {}", securityContext.getUserPrincipal().getClass().getName()); return false; diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/websocket/AuthenticatedConnectListener.java b/service/src/main/java/org/whispersystems/textsecuregcm/websocket/AuthenticatedConnectListener.java index b609107c7..43ced48c7 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/websocket/AuthenticatedConnectListener.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/websocket/AuthenticatedConnectListener.java @@ -102,11 +102,11 @@ public class AuthenticatedConnectListener implements WebSocketConnectListener { if (authenticated) { final AuthenticatedDevice auth = context.getAuthenticated(AuthenticatedDevice.class); - final Optional maybeAuthenticatedAccount = accountsManager.getByAccountIdentifier(auth.getAccountIdentifier()); - final Optional maybeAuthenticatedDevice = maybeAuthenticatedAccount.flatMap(account -> account.getDevice(auth.getDeviceId()));; + final Optional maybeAuthenticatedAccount = accountsManager.getByAccountIdentifier(auth.accountIdentifier()); + final Optional maybeAuthenticatedDevice = maybeAuthenticatedAccount.flatMap(account -> account.getDevice(auth.deviceId()));; if (maybeAuthenticatedAccount.isEmpty() || maybeAuthenticatedDevice.isEmpty()) { - log.warn("{}:{} not found when opening authenticated WebSocket", auth.getAccountIdentifier(), auth.getDeviceId()); + log.warn("{}:{} not found when opening authenticated WebSocket", auth.accountIdentifier(), auth.deviceId()); context.getClient().close(1011, "Unexpected error initializing connection"); return; @@ -131,7 +131,7 @@ public class AuthenticatedConnectListener implements WebSocketConnectListener { // receive push notifications for inbound messages. We should do this first because, at this point, the // connection has already closed and attempts to actually deliver a message via the connection will not succeed. // It's preferable to start sending push notifications as soon as possible. - webSocketConnectionEventManager.handleClientDisconnected(auth.getAccountIdentifier(), auth.getDeviceId()); + webSocketConnectionEventManager.handleClientDisconnected(auth.accountIdentifier(), auth.deviceId()); // Finally, stop trying to deliver messages and send a push notification if the connection is aware of any // undelivered messages. @@ -147,7 +147,7 @@ public class AuthenticatedConnectListener implements WebSocketConnectListener { // Finally, we register this client's presence, which suppresses push notifications. We do this last because // receiving extra push notifications is generally preferable to missing out on a push notification. - webSocketConnectionEventManager.handleClientConnected(auth.getAccountIdentifier(), auth.getDeviceId(), connection); + webSocketConnectionEventManager.handleClientConnected(auth.accountIdentifier(), auth.deviceId(), connection); } catch (final Exception e) { log.warn("Failed to initialize websocket", e); context.getClient().close(1011, "Unexpected error initializing connection"); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticatorTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticatorTest.java index bcfe61f37..4ee52b251 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticatorTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/auth/AccountAuthenticatorTest.java @@ -31,6 +31,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import org.junitpioneer.jupiter.cartesian.CartesianTest; +import org.whispersystems.textsecuregcm.identity.IdentityType; import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.Device; @@ -78,8 +79,8 @@ class AccountAuthenticatorTest { void testUpdateLastSeenMiddleOfDay() { clock.pin(Instant.ofEpochMilli(currentTime)); - final Device device1 = acct1.getDevices().stream().findFirst().get(); - final Device device2 = acct2.getDevices().stream().findFirst().get(); + final Device device1 = acct1.getDevices().stream().findFirst().orElseThrow(); + final Device device2 = acct2.getDevices().stream().findFirst().orElseThrow(); final Account updatedAcct1 = accountAuthenticator.updateLastSeen(acct1, device1); final Account updatedAcct2 = accountAuthenticator.updateLastSeen(acct2, device2); @@ -98,8 +99,8 @@ class AccountAuthenticatorTest { void testUpdateLastSeenStartOfDay() { clock.pin(Instant.ofEpochMilli(today)); - final Device device1 = acct1.getDevices().stream().findFirst().get(); - final Device device2 = acct2.getDevices().stream().findFirst().get(); + final Device device1 = acct1.getDevices().stream().findFirst().orElseThrow(); + final Device device2 = acct2.getDevices().stream().findFirst().orElseThrow(); final Account updatedAcct1 = accountAuthenticator.updateLastSeen(acct1, device1); final Account updatedAcct2 = accountAuthenticator.updateLastSeen(acct2, device2); @@ -118,8 +119,8 @@ class AccountAuthenticatorTest { void testUpdateLastSeenEndOfDay() { clock.pin(Instant.ofEpochMilli(today + 86_400_000L - 1)); - final Device device1 = acct1.getDevices().stream().findFirst().get(); - final Device device2 = acct2.getDevices().stream().findFirst().get(); + final Device device1 = acct1.getDevices().stream().findFirst().orElseThrow(); + final Device device2 = acct2.getDevices().stream().findFirst().orElseThrow(); final Account updatedAcct1 = accountAuthenticator.updateLastSeen(acct1, device1); final Account updatedAcct2 = accountAuthenticator.updateLastSeen(acct2, device2); @@ -138,7 +139,7 @@ class AccountAuthenticatorTest { void testNeverWriteYesterday() { clock.pin(Instant.ofEpochMilli(today)); - final Device device = oldAccount.getDevices().stream().findFirst().get(); + final Device device = oldAccount.getDevices().stream().findFirst().orElseThrow(); accountAuthenticator.updateLastSeen(oldAccount, device); @@ -160,7 +161,9 @@ class AccountAuthenticatorTest { clock.unpin(); when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account)); when(account.getUuid()).thenReturn(uuid); + when(account.getIdentifier(IdentityType.ACI)).thenReturn(uuid); when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.getPrimaryDevice()).thenReturn(device); when(device.getId()).thenReturn(deviceId); when(device.getAuthTokenHash()).thenReturn(credentials); when(credentials.verify(password)).thenReturn(true); @@ -170,9 +173,9 @@ class AccountAuthenticatorTest { accountAuthenticator.authenticate(new BasicCredentials(uuid.toString(), password)); assertThat(maybeAuthenticatedAccount).isPresent(); - assertThat(maybeAuthenticatedAccount.get().getAccount().getUuid()).isEqualTo(uuid); - assertThat(maybeAuthenticatedAccount.get().getAuthenticatedDevice()).isEqualTo(device); - verify(accountsManager, never()).updateDeviceAuthentication(any(), any(), any());; + assertThat(maybeAuthenticatedAccount.orElseThrow().accountIdentifier()).isEqualTo(uuid); + assertThat(maybeAuthenticatedAccount.orElseThrow().deviceId()).isEqualTo(device.getId()); + verify(accountsManager, never()).updateDeviceAuthentication(any(), any(), any()); } @Test @@ -188,7 +191,9 @@ class AccountAuthenticatorTest { clock.unpin(); when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account)); when(account.getUuid()).thenReturn(uuid); + when(account.getIdentifier(IdentityType.ACI)).thenReturn(uuid); when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.getPrimaryDevice()).thenReturn(device); when(device.getId()).thenReturn(deviceId); when(device.getAuthTokenHash()).thenReturn(credentials); when(credentials.verify(password)).thenReturn(true); @@ -198,15 +203,13 @@ class AccountAuthenticatorTest { accountAuthenticator.authenticate(new BasicCredentials(uuid + "." + deviceId, password)); assertThat(maybeAuthenticatedAccount).isPresent(); - assertThat(maybeAuthenticatedAccount.get().getAccount().getUuid()).isEqualTo(uuid); - assertThat(maybeAuthenticatedAccount.get().getAuthenticatedDevice()).isEqualTo(device); + assertThat(maybeAuthenticatedAccount.orElseThrow().accountIdentifier()).isEqualTo(uuid); + assertThat(maybeAuthenticatedAccount.orElseThrow().deviceId()).isEqualTo(device.getId()); verify(accountsManager, never()).updateDeviceAuthentication(any(), any(), any()); } @CartesianTest void testAuthenticateEnabled( - @CartesianTest.Values(booleans = {true, false}) final boolean accountEnabled, - @CartesianTest.Values(booleans = {true, false}) final boolean deviceEnabled, @CartesianTest.Values(booleans = {true, false}) final boolean authenticatedDeviceIsPrimary) { final UUID uuid = UUID.randomUUID(); final byte deviceId = (byte) (authenticatedDeviceIsPrimary ? 1 : 2); @@ -219,7 +222,9 @@ class AccountAuthenticatorTest { clock.unpin(); when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account)); when(account.getUuid()).thenReturn(uuid); + when(account.getIdentifier(IdentityType.ACI)).thenReturn(uuid); when(account.getDevice(deviceId)).thenReturn(Optional.of(authenticatedDevice)); + when(account.getPrimaryDevice()).thenReturn(authenticatedDevice); when(authenticatedDevice.getId()).thenReturn(deviceId); when(authenticatedDevice.getAuthTokenHash()).thenReturn(credentials); when(credentials.verify(password)).thenReturn(true); @@ -235,9 +240,8 @@ class AccountAuthenticatorTest { accountAuthenticator.authenticate(new BasicCredentials(identifier, password)); assertThat(maybeAuthenticatedAccount).isPresent(); - assertThat(maybeAuthenticatedAccount.get().getAccount().getUuid()).isEqualTo(uuid); - assertThat(maybeAuthenticatedAccount.get().getAuthenticatedDevice()).isEqualTo(authenticatedDevice); - + assertThat(maybeAuthenticatedAccount.orElseThrow().accountIdentifier()).isEqualTo(uuid); + assertThat(maybeAuthenticatedAccount.orElseThrow().deviceId()).isEqualTo(authenticatedDevice.getId()); } @Test @@ -253,7 +257,9 @@ class AccountAuthenticatorTest { clock.unpin(); when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account)); when(account.getUuid()).thenReturn(uuid); + when(account.getIdentifier(IdentityType.ACI)).thenReturn(uuid); when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.getPrimaryDevice()).thenReturn(device); when(device.getId()).thenReturn(deviceId); when(device.getAuthTokenHash()).thenReturn(credentials); when(credentials.verify(password)).thenReturn(true); @@ -263,8 +269,8 @@ class AccountAuthenticatorTest { accountAuthenticator.authenticate(new BasicCredentials(uuid.toString(), password)); assertThat(maybeAuthenticatedAccount).isPresent(); - assertThat(maybeAuthenticatedAccount.get().getAccount().getUuid()).isEqualTo(uuid); - assertThat(maybeAuthenticatedAccount.get().getAuthenticatedDevice()).isEqualTo(device); + assertThat(maybeAuthenticatedAccount.orElseThrow().accountIdentifier()).isEqualTo(uuid); + assertThat(maybeAuthenticatedAccount.orElseThrow().deviceId()).isEqualTo(device.getId()); verify(accountsManager, times(1)).updateDeviceAuthentication( any(), // this won't be 'account', because it'll already be updated by updateDeviceLastSeen eq(device), any()); @@ -288,7 +294,9 @@ class AccountAuthenticatorTest { clock.unpin(); when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account)); when(account.getUuid()).thenReturn(uuid); + when(account.getIdentifier(IdentityType.ACI)).thenReturn(uuid); when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.getPrimaryDevice()).thenReturn(device); when(device.getId()).thenReturn(deviceId); when(device.getAuthTokenHash()).thenReturn(credentials); when(credentials.verify(password)).thenReturn(true); @@ -314,7 +322,9 @@ class AccountAuthenticatorTest { clock.unpin(); when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account)); when(account.getUuid()).thenReturn(uuid); + when(account.getIdentifier(IdentityType.ACI)).thenReturn(uuid); when(account.getDevice(deviceId)).thenReturn(Optional.of(device)); + when(account.getPrimaryDevice()).thenReturn(device); when(device.getId()).thenReturn(deviceId); when(device.getAuthTokenHash()).thenReturn(credentials); when(credentials.verify(password)).thenReturn(true); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/auth/IdlePrimaryDeviceAuthenticatedWebSocketUpgradeFilterTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/auth/IdlePrimaryDeviceAuthenticatedWebSocketUpgradeFilterTest.java index e824a8e49..28ea6d113 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/auth/IdlePrimaryDeviceAuthenticatedWebSocketUpgradeFilterTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/auth/IdlePrimaryDeviceAuthenticatedWebSocketUpgradeFilterTest.java @@ -8,12 +8,12 @@ package org.whispersystems.textsecuregcm.auth; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; import java.time.Duration; import java.time.Instant; import java.util.List; import java.util.Optional; +import java.util.UUID; import javax.annotation.Nullable; import org.eclipse.jetty.websocket.server.JettyServerUpgradeRequest; import org.eclipse.jetty.websocket.server.JettyServerUpgradeResponse; @@ -21,7 +21,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.util.TestClock; @@ -59,26 +58,8 @@ class IdlePrimaryDeviceAuthenticatedWebSocketUpgradeFilterTest { } private static List handleAuthentication() { - final Device activePrimaryDevice = mock(Device.class); - when(activePrimaryDevice.getId()).thenReturn(Device.PRIMARY_ID); - when(activePrimaryDevice.isPrimary()).thenReturn(true); - when(activePrimaryDevice.getLastSeen()).thenReturn(CLOCK.millis()); - - final Device minIdlePrimaryDevice = mock(Device.class); - when(minIdlePrimaryDevice.getId()).thenReturn(Device.PRIMARY_ID); - when(minIdlePrimaryDevice.isPrimary()).thenReturn(true); - when(minIdlePrimaryDevice.getLastSeen()) - .thenReturn(CLOCK.instant().minus(MIN_IDLE_DURATION).minusSeconds(1).toEpochMilli()); - - final Device linkedDevice = mock(Device.class); - when(linkedDevice.getId()).thenReturn((byte) (Device.PRIMARY_ID + 1)); - when(linkedDevice.isPrimary()).thenReturn(false); - - final Account accountWithActivePrimaryDevice = mock(Account.class); - when(accountWithActivePrimaryDevice.getPrimaryDevice()).thenReturn(activePrimaryDevice); - - final Account accountWithMinIdlePrimaryDevice = mock(Account.class); - when(accountWithMinIdlePrimaryDevice.getPrimaryDevice()).thenReturn(minIdlePrimaryDevice); + final Instant activePrimaryDeviceLastSeen = CLOCK.instant(); + final Instant idlePrimaryDeviceLastSeen = CLOCK.instant().minus(MIN_IDLE_DURATION).minusSeconds(1); return List.of( Arguments.argumentSet("Anonymous", @@ -86,19 +67,19 @@ class IdlePrimaryDeviceAuthenticatedWebSocketUpgradeFilterTest { null), Arguments.argumentSet("Authenticated as active primary device", - new AuthenticatedDevice(accountWithActivePrimaryDevice, activePrimaryDevice), + new AuthenticatedDevice(UUID.randomUUID(), Device.PRIMARY_ID, activePrimaryDeviceLastSeen), null), Arguments.argumentSet("Authenticated as idle primary device", - new AuthenticatedDevice(accountWithMinIdlePrimaryDevice, minIdlePrimaryDevice), + new AuthenticatedDevice(UUID.randomUUID(), Device.PRIMARY_ID, idlePrimaryDeviceLastSeen), null), Arguments.argumentSet("Authenticated as linked device with active primary device", - new AuthenticatedDevice(accountWithActivePrimaryDevice, linkedDevice), + new AuthenticatedDevice(UUID.randomUUID(), (byte) (Device.PRIMARY_ID + 1), activePrimaryDeviceLastSeen), null), - Arguments.argumentSet("Authenticated as linked device with min-idle primary device", - new AuthenticatedDevice(accountWithMinIdlePrimaryDevice, linkedDevice), + Arguments.argumentSet("Authenticated as linked device with idle primary device", + new AuthenticatedDevice(UUID.randomUUID(), (byte) (Device.PRIMARY_ID + 1), idlePrimaryDeviceLastSeen), IdlePrimaryDeviceAuthenticatedWebSocketUpgradeFilter.IDLE_PRIMARY_DEVICE_ALERT) ); } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/DirectoryControllerV2Test.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/DirectoryControllerV2Test.java index 991d84ec7..9fe34d7a7 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/DirectoryControllerV2Test.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/DirectoryControllerV2Test.java @@ -39,7 +39,7 @@ class DirectoryControllerV2Test { when(account.getIdentifier(IdentityType.ACI)).thenReturn(uuid); final ExternalServiceCredentials credentials = controller.getAuthToken( - new AuthenticatedDevice(account, mock(Device.class))); + new AuthenticatedDevice(uuid, Device.PRIMARY_ID, Instant.now())); assertEquals("d369bc712e2e0dd36258", credentials.username()); assertEquals("1633738643:4433b0fab41f25f79dd4", credentials.password()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilterTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilterTest.java index 84f190101..1b08a50d0 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilterTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilterTest.java @@ -14,6 +14,7 @@ import com.google.common.net.HttpHeaders; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.SecurityContext; import java.net.URI; +import java.time.Instant; import java.util.Random; import java.util.UUID; import org.glassfish.jersey.server.ContainerRequest; @@ -23,7 +24,6 @@ import org.junit.jupiter.params.provider.ValueSource; import org.whispersystems.textsecuregcm.auth.AuthenticatedDevice; import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration; import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager; -import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; import org.whispersystems.textsecuregcm.tests.util.FakeDynamicConfigurationManager; @@ -39,10 +39,8 @@ class RestDeprecationFilterTest { final RestDeprecationFilter filter = new RestDeprecationFilter(dynamicConfigurationManager, experimentEnrollmentManager); - final Account account = new Account(); - account.setUuid(UUID.randomUUID()); final SecurityContext securityContext = mock(SecurityContext.class); - when(securityContext.getUserPrincipal()).thenReturn(new AuthenticatedDevice(account, new Device())); + when(securityContext.getUserPrincipal()).thenReturn(new AuthenticatedDevice(UUID.randomUUID(), Device.PRIMARY_ID, Instant.now())); final ContainerRequest req = new ContainerRequest(null, new URI("/some/uri"), "GET", securityContext, null, null); req.getHeaders().add(HttpHeaders.USER_AGENT, "Signal-Android/100.0.0"); @@ -60,17 +58,15 @@ class RestDeprecationFilterTest { experiments: restDeprecation: uuidEnrollmentPercentage: 100 - """, + """, DynamicConfiguration.class); final DynamicConfigurationManager dynamicConfigurationManager = new FakeDynamicConfigurationManager<>(config); final ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager); final RestDeprecationFilter filter = new RestDeprecationFilter(dynamicConfigurationManager, experimentEnrollmentManager); - final Account account = new Account(); - account.setUuid(UUID.randomUUID()); final SecurityContext securityContext = mock(SecurityContext.class); - when(securityContext.getUserPrincipal()).thenReturn(new AuthenticatedDevice(account, new Device())); + when(securityContext.getUserPrincipal()).thenReturn(new AuthenticatedDevice(UUID.randomUUID(), Device.PRIMARY_ID, Instant.now())); final ContainerRequest req = new ContainerRequest(null, new URI("/some/uri"), "GET", securityContext, null, null); req.getHeaders().add(HttpHeaders.USER_AGENT, "Signal-Android/100.0.0"); @@ -90,7 +86,7 @@ class RestDeprecationFilterTest { experiments: restDeprecation: uuidEnrollmentPercentage: 100 - """, + """, DynamicConfiguration.class); final DynamicConfigurationManager dynamicConfigurationManager = new FakeDynamicConfigurationManager<>(config); final ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager); @@ -116,17 +112,15 @@ class RestDeprecationFilterTest { experiments: restDeprecation: enrollmentPercentage: 100 - """, + """, DynamicConfiguration.class); final DynamicConfigurationManager dynamicConfigurationManager = new FakeDynamicConfigurationManager<>(config); final ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager); final RestDeprecationFilter filter = new RestDeprecationFilter(dynamicConfigurationManager, experimentEnrollmentManager); - final Account account = new Account(); - account.setUuid(UUID.randomUUID()); final SecurityContext securityContext = mock(SecurityContext.class); - when(securityContext.getUserPrincipal()).thenReturn(new AuthenticatedDevice(account, new Device())); + when(securityContext.getUserPrincipal()).thenReturn(new AuthenticatedDevice(UUID.randomUUID(), Device.PRIMARY_ID, Instant.now())); final ContainerRequest req = new ContainerRequest(null, new URI("/some/path"), "GET", securityContext, null, null); req.getHeaders().putSingle(HttpHeaders.USER_AGENT, "Signal-Android/10.9.15"); @@ -152,7 +146,7 @@ class RestDeprecationFilterTest { ANDROID: minimumRestFreeVersion: 10.10.10 universalRolloutPercent: 70 - """, + """, DynamicConfiguration.class); final DynamicConfigurationManager dynamicConfigurationManager = new FakeDynamicConfigurationManager<>(config); final ExperimentEnrollmentManager experimentEnrollmentManager = new ExperimentEnrollmentManager(dynamicConfigurationManager); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/websocket/WebSocketAccountAuthenticatorTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/websocket/WebSocketAccountAuthenticatorTest.java index c1056bb26..4ecd722f3 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/websocket/WebSocketAccountAuthenticatorTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/websocket/WebSocketAccountAuthenticatorTest.java @@ -14,7 +14,9 @@ import static org.mockito.Mockito.when; import com.google.common.net.HttpHeaders; import com.google.i18n.phonenumbers.PhoneNumberUtil; import io.dropwizard.auth.basic.BasicCredentials; +import java.time.Instant; import java.util.Optional; +import java.util.UUID; import java.util.stream.Stream; import javax.annotation.Nullable; import org.eclipse.jetty.websocket.api.UpgradeRequest; @@ -24,7 +26,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.whispersystems.textsecuregcm.auth.AccountAuthenticator; import org.whispersystems.textsecuregcm.auth.AuthenticatedDevice; -import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.util.HeaderUtils; import org.whispersystems.websocket.auth.InvalidCredentialsException; @@ -50,7 +51,7 @@ class WebSocketAccountAuthenticatorTest { accountAuthenticator = mock(AccountAuthenticator.class); when(accountAuthenticator.authenticate(eq(new BasicCredentials(VALID_USER, VALID_PASSWORD)))) - .thenReturn(Optional.of(new AuthenticatedDevice(mock(Account.class), mock(Device.class)))); + .thenReturn(Optional.of(new AuthenticatedDevice(UUID.randomUUID(), Device.PRIMARY_ID, Instant.now()))); when(accountAuthenticator.authenticate(eq(new BasicCredentials(INVALID_USER, INVALID_PASSWORD)))) .thenReturn(Optional.empty()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/websocket/WebSocketConnectionTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/websocket/WebSocketConnectionTest.java index c05c50f9b..32ff55b51 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/websocket/WebSocketConnectionTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/websocket/WebSocketConnectionTest.java @@ -33,6 +33,7 @@ import io.lettuce.core.RedisException; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.time.Instant; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -79,7 +80,8 @@ import reactor.test.publisher.TestPublisher; class WebSocketConnectionTest { - private static final String VALID_USER = "+14152222222"; + private static final String VALID_E164 = "+14152222222"; + private static final UUID VALID_UUID = UUID.randomUUID(); private static final int SOURCE_DEVICE_ID = 1; @@ -127,8 +129,8 @@ class WebSocketConnectionTest { mock(ExperimentEnrollmentManager.class)); WebSocketSessionContext sessionContext = mock(WebSocketSessionContext.class); - when(accountAuthenticator.authenticate(eq(new BasicCredentials(VALID_USER, VALID_PASSWORD)))) - .thenReturn(Optional.of(new AuthenticatedDevice(account, device))); + when(accountAuthenticator.authenticate(eq(new BasicCredentials(VALID_E164, VALID_PASSWORD)))) + .thenReturn(Optional.of(new AuthenticatedDevice(VALID_UUID, Device.PRIMARY_ID, Instant.now()))); Optional account = webSocketAuthenticator.authenticate(upgradeRequest); when(sessionContext.getAuthenticated()).thenReturn(account.orElse(null));