From 359cf021618c76475ae0a35460fbd5d69268032a Mon Sep 17 00:00:00 2001 From: Ravi Khadiwala Date: Wed, 19 Mar 2025 13:44:10 -0500 Subject: [PATCH] Add new attachmentBackfill capability --- .../grpc/DeviceCapabilityUtil.java | 2 ++ .../storage/DeviceCapability.java | 24 ++++++++++++++++++- .../main/proto/org/signal/chat/common.proto | 1 + .../controllers/ProfileControllerTest.java | 5 +++- .../grpc/DevicesGrpcServiceTest.java | 11 ++++++++- 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/grpc/DeviceCapabilityUtil.java b/service/src/main/java/org/whispersystems/textsecuregcm/grpc/DeviceCapabilityUtil.java index 793ab7554..0b9bd4ee5 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/grpc/DeviceCapabilityUtil.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/grpc/DeviceCapabilityUtil.java @@ -19,6 +19,7 @@ public class DeviceCapabilityUtil { case DEVICE_CAPABILITY_TRANSFER -> DeviceCapability.TRANSFER; case DEVICE_CAPABILITY_DELETE_SYNC -> DeviceCapability.DELETE_SYNC; case DEVICE_CAPABILITY_STORAGE_SERVICE_RECORD_KEY_ROTATION -> DeviceCapability.STORAGE_SERVICE_RECORD_KEY_ROTATION; + case DEVICE_CAPABILITY_ATTACHMENT_BACKFILL -> DeviceCapability.ATTACHMENT_BACKFILL; case DEVICE_CAPABILITY_UNSPECIFIED, UNRECOGNIZED -> throw Status.INVALID_ARGUMENT.withDescription("Unrecognized device capability").asRuntimeException(); }; } @@ -29,6 +30,7 @@ public class DeviceCapabilityUtil { case TRANSFER -> org.signal.chat.common.DeviceCapability.DEVICE_CAPABILITY_TRANSFER; case DELETE_SYNC -> org.signal.chat.common.DeviceCapability.DEVICE_CAPABILITY_DELETE_SYNC; case STORAGE_SERVICE_RECORD_KEY_ROTATION -> org.signal.chat.common.DeviceCapability.DEVICE_CAPABILITY_STORAGE_SERVICE_RECORD_KEY_ROTATION; + case ATTACHMENT_BACKFILL -> org.signal.chat.common.DeviceCapability.DEVICE_CAPABILITY_ATTACHMENT_BACKFILL; }; } } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/DeviceCapability.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/DeviceCapability.java index 6b2f3c892..9893ff06f 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/DeviceCapability.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/DeviceCapability.java @@ -11,11 +11,21 @@ public enum DeviceCapability { STORAGE("storage", AccountCapabilityMode.ANY_DEVICE, false, false), TRANSFER("transfer", AccountCapabilityMode.PRIMARY_DEVICE, false, false), DELETE_SYNC("deleteSync", AccountCapabilityMode.ALL_DEVICES, true, true), - STORAGE_SERVICE_RECORD_KEY_ROTATION("ssre2", AccountCapabilityMode.ALL_DEVICES, true, true); + STORAGE_SERVICE_RECORD_KEY_ROTATION("ssre2", AccountCapabilityMode.ALL_DEVICES, true, true), + ATTACHMENT_BACKFILL("attachmentBackfill", AccountCapabilityMode.PRIMARY_DEVICE, false, true); public enum AccountCapabilityMode { + /** + * The account will have the capability iff the primary device has the capability + */ PRIMARY_DEVICE, + /** + * The account will have the capability iff any device on the account has the capability + */ ANY_DEVICE, + /** + * The account will have the capability iff all devices on the account have the capability + */ ALL_DEVICES, } @@ -24,6 +34,18 @@ public enum DeviceCapability { private final boolean preventDowngrade; private final boolean includeInProfile; + /** + * Create a DeviceCapability + * + * @param name The name of the device capability that clients will see + * @param accountCapabilityMode How to combine the constituent device's capabilities in the account to an overall + * account capability + * @param preventDowngrade If true, don't let linked devices join that don't have a device capability if the + * overall account has the capability. Most of the time this should only be used in + * conjunction with AccountCapabilityMode.ALL_DEVICES + * @param includeInProfile Whether to return this capability on the account's profile. If false, the capability + * is only visible to the server + */ DeviceCapability(final String name, final AccountCapabilityMode accountCapabilityMode, final boolean preventDowngrade, diff --git a/service/src/main/proto/org/signal/chat/common.proto b/service/src/main/proto/org/signal/chat/common.proto index 9bdeb7363..2f08a2bfa 100644 --- a/service/src/main/proto/org/signal/chat/common.proto +++ b/service/src/main/proto/org/signal/chat/common.proto @@ -100,6 +100,7 @@ enum DeviceCapability { DEVICE_CAPABILITY_DELETE_SYNC = 3; reserved 4; DEVICE_CAPABILITY_STORAGE_SERVICE_RECORD_KEY_ROTATION = 5; + DEVICE_CAPABILITY_ATTACHMENT_BACKFILL = 6; } message ZkCredential { diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ProfileControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ProfileControllerTest.java index 9cf91a58f..c3f61d9a6 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ProfileControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ProfileControllerTest.java @@ -442,8 +442,10 @@ class ProfileControllerTest { @CartesianTest void testProfileCapabilities( - @CartesianTest.Values(booleans = {true, false}) final boolean isDeleteSyncSupported) { + @CartesianTest.Values(booleans = {true, false}) final boolean isDeleteSyncSupported, + @CartesianTest.Values(booleans = {true, false}) final boolean isAttachmentBackfillSupported) { when(capabilitiesAccount.hasCapability(DeviceCapability.DELETE_SYNC)).thenReturn(isDeleteSyncSupported); + when(capabilitiesAccount.hasCapability(DeviceCapability.ATTACHMENT_BACKFILL)).thenReturn(isAttachmentBackfillSupported); final BaseProfileResponse profile = resources.getJerseyTest() .target("/v1/profile/" + AuthHelper.VALID_UUID) .request() @@ -451,6 +453,7 @@ class ProfileControllerTest { .get(BaseProfileResponse.class); assertEquals(isDeleteSyncSupported, profile.getCapabilities().get("deleteSync")); + assertEquals(isAttachmentBackfillSupported, profile.getCapabilities().get("attachmentBackfill")); } @Test diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcServiceTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcServiceTest.java index eea9581e2..cd99b894b 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcServiceTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/grpc/DevicesGrpcServiceTest.java @@ -434,7 +434,8 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest expectedCapabilities = new HashSet<>(); @@ -471,6 +476,10 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest