Retire `AttachmentControllerV2`
This commit is contained in:
parent
5abfef50fc
commit
bda4788a34
|
@ -21,9 +21,6 @@ svr3.userIdTokenSharedSecret: dbcdefghijklmnopqrstuvwxyz0123456789ABCDEFG= # bas
|
|||
|
||||
tus.userAuthenticationTokenSharedSecret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG=
|
||||
|
||||
awsAttachments.accessKey: test
|
||||
awsAttachments.accessSecret: test
|
||||
|
||||
gcpAttachments.rsaSigningKey: |
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ/0123456789+abcdefghijklmnopqrstuvwxyz
|
||||
|
|
|
@ -239,13 +239,6 @@ messageCache: # Redis server configuration for message store cache
|
|||
cluster:
|
||||
configurationUri: redis://redis.example.com:6379/
|
||||
|
||||
awsAttachments: # AWS S3 configuration
|
||||
bucket: aws-attachments
|
||||
credentials:
|
||||
accessKeyId: secret://awsAttachments.accessKey
|
||||
secretAccessKey: secret://awsAttachments.accessSecret
|
||||
region: us-west-2
|
||||
|
||||
gcpAttachments: # GCP Storage configuration
|
||||
domain: example.com
|
||||
email: user@example.cocm
|
||||
|
|
|
@ -17,7 +17,6 @@ import org.whispersystems.textsecuregcm.attachments.TusConfiguration;
|
|||
import org.whispersystems.textsecuregcm.configuration.ApnConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.AppleAppStoreConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.ArtServiceConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.AwsAttachmentsConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.AwsCredentialsProviderFactory;
|
||||
import org.whispersystems.textsecuregcm.configuration.BadgesConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.BraintreeConfiguration;
|
||||
|
@ -109,11 +108,6 @@ public class WhisperServerConfiguration extends Configuration {
|
|||
@JsonProperty
|
||||
private DynamoDbTables dynamoDbTables;
|
||||
|
||||
@NotNull
|
||||
@Valid
|
||||
@JsonProperty
|
||||
private AwsAttachmentsConfiguration awsAttachments;
|
||||
|
||||
@NotNull
|
||||
@Valid
|
||||
@JsonProperty
|
||||
|
@ -397,10 +391,6 @@ public class WhisperServerConfiguration extends Configuration {
|
|||
return webSocket;
|
||||
}
|
||||
|
||||
public AwsAttachmentsConfiguration getAwsAttachmentsConfiguration() {
|
||||
return awsAttachments;
|
||||
}
|
||||
|
||||
public GcpAttachmentsConfiguration getGcpAttachmentsConfiguration() {
|
||||
return gcpAttachments;
|
||||
}
|
||||
|
|
|
@ -110,7 +110,6 @@ import org.whispersystems.textsecuregcm.controllers.AccountController;
|
|||
import org.whispersystems.textsecuregcm.controllers.AccountControllerV2;
|
||||
import org.whispersystems.textsecuregcm.controllers.ArchiveController;
|
||||
import org.whispersystems.textsecuregcm.controllers.ArtController;
|
||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV2;
|
||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV4;
|
||||
import org.whispersystems.textsecuregcm.controllers.CallLinkController;
|
||||
import org.whispersystems.textsecuregcm.controllers.CallRoutingController;
|
||||
|
@ -1096,10 +1095,6 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
new AccountControllerV2(accountsManager, changeNumberManager, phoneVerificationTokenManager,
|
||||
registrationLockVerificationManager, rateLimiters),
|
||||
new ArtController(rateLimiters, artCredentialsGenerator),
|
||||
new AttachmentControllerV2(rateLimiters,
|
||||
config.getAwsAttachmentsConfiguration().credentials().accessKeyId().value(),
|
||||
config.getAwsAttachmentsConfiguration().credentials().secretAccessKey().value(),
|
||||
config.getAwsAttachmentsConfiguration().region(), config.getAwsAttachmentsConfiguration().bucket()),
|
||||
new AttachmentControllerV4(rateLimiters, gcsAttachmentGenerator, tusAttachmentGenerator,
|
||||
experimentEnrollmentManager),
|
||||
new ArchiveController(backupAuthManager, backupManager),
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package org.whispersystems.textsecuregcm.configuration;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
public record AwsAttachmentsConfiguration(@NotNull @Valid StaticAwsCredentialsFactory credentials,
|
||||
@NotBlank String bucket,
|
||||
@NotBlank String region) {
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.controllers;
|
||||
|
||||
import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name;
|
||||
|
||||
import com.google.common.net.HttpHeaders;
|
||||
import io.dropwizard.auth.Auth;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedDevice;
|
||||
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptorV2;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.metrics.UserAgentTagUtil;
|
||||
import org.whispersystems.textsecuregcm.s3.PolicySigner;
|
||||
import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator;
|
||||
import org.whispersystems.textsecuregcm.util.Conversions;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import org.whispersystems.websocket.auth.ReadOnly;
|
||||
|
||||
// To be removed when Android 7.12 reaches saturation, likely some time toward the end of October 2024
|
||||
@Deprecated(forRemoval = true)
|
||||
@Path("/v2/attachments")
|
||||
@Tag(name = "Attachments")
|
||||
public class AttachmentControllerV2 {
|
||||
|
||||
private final PostPolicyGenerator policyGenerator;
|
||||
private final PolicySigner policySigner;
|
||||
private final RateLimiter rateLimiter;
|
||||
|
||||
private static final String CREATE_UPLOAD_COUNTER_NAME = name(AttachmentControllerV2.class, "uploadForm");
|
||||
|
||||
public AttachmentControllerV2(RateLimiters rateLimiters, String accessKey, String accessSecret, String region,
|
||||
String bucket) {
|
||||
this.rateLimiter = rateLimiters.getAttachmentLimiter();
|
||||
this.policyGenerator = new PostPolicyGenerator(region, bucket, accessKey);
|
||||
this.policySigner = new PolicySigner(accessSecret, region);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/form/upload")
|
||||
public AttachmentDescriptorV2 getAttachmentUploadForm(
|
||||
@ReadOnly @Auth AuthenticatedDevice auth,
|
||||
@HeaderParam(HttpHeaders.USER_AGENT) String userAgent)
|
||||
throws RateLimitExceededException {
|
||||
rateLimiter.validate(auth.getAccount().getUuid());
|
||||
|
||||
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
|
||||
long attachmentId = generateAttachmentId();
|
||||
String objectName = String.valueOf(attachmentId);
|
||||
Pair<String, String> policy = policyGenerator.createFor(now, objectName, 100 * 1024 * 1024);
|
||||
String signature = policySigner.getSignature(now, policy.second());
|
||||
|
||||
Metrics.counter(CREATE_UPLOAD_COUNTER_NAME, Tags.of(UserAgentTagUtil.getPlatformTag(userAgent))).increment();
|
||||
|
||||
return new AttachmentDescriptorV2(attachmentId, objectName, policy.first(),
|
||||
"private", "AWS4-HMAC-SHA256",
|
||||
now.format(PostPolicyGenerator.AWS_DATE_TIME),
|
||||
policy.second(), signature);
|
||||
}
|
||||
|
||||
private long generateAttachmentId() {
|
||||
byte[] attachmentBytes = new byte[8];
|
||||
new SecureRandom().nextBytes(attachmentBytes);
|
||||
|
||||
attachmentBytes[0] = (byte) (attachmentBytes[0] & 0x7F);
|
||||
return Conversions.byteArrayToLong(attachmentBytes);
|
||||
}
|
||||
|
||||
}
|
|
@ -30,7 +30,8 @@ import org.whispersystems.websocket.auth.ReadOnly;
|
|||
|
||||
|
||||
/**
|
||||
* The V4 API is identical to the {@link AttachmentControllerV3} API, but supports an additional TUS based cdn type (cdn3)
|
||||
* The attachment controller generates "upload forms" for authenticated users that permit them to upload files
|
||||
* (message attachments) to a remote storage location. The location may be selected by the server at runtime.
|
||||
*/
|
||||
@Path("/v4/attachments")
|
||||
@Tag(name = "Attachments")
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public record AttachmentDescriptorV2(long attachmentId,
|
||||
String key,
|
||||
String credential,
|
||||
String acl,
|
||||
String algorithm,
|
||||
String date,
|
||||
String policy,
|
||||
String signature) {
|
||||
|
||||
@JsonProperty
|
||||
public String attachmentIdString() {
|
||||
return String.valueOf(attachmentId);
|
||||
}
|
||||
}
|
|
@ -36,7 +36,6 @@ import org.whispersystems.textsecuregcm.attachments.TusAttachmentGenerator;
|
|||
import org.whispersystems.textsecuregcm.attachments.TusConfiguration;
|
||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedDevice;
|
||||
import org.whispersystems.textsecuregcm.configuration.secrets.SecretBytes;
|
||||
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptorV2;
|
||||
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptorV3;
|
||||
import org.whispersystems.textsecuregcm.experiment.ExperimentEnrollmentManager;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||
|
@ -47,7 +46,7 @@ import org.whispersystems.textsecuregcm.util.SystemMapper;
|
|||
import org.whispersystems.textsecuregcm.util.TestRandomUtil;
|
||||
|
||||
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||
class AttachmentControllerTest {
|
||||
class AttachmentControllerV4Test {
|
||||
|
||||
private static final RateLimiter RATE_LIMITER = mock(RateLimiter.class);
|
||||
|
||||
|
@ -93,8 +92,6 @@ class AttachmentControllerTest {
|
|||
.addProvider(new AuthValueFactoryProvider.Binder<>(AuthenticatedDevice.class))
|
||||
.setMapper(SystemMapper.jsonMapper())
|
||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||
.addResource(new AttachmentControllerV2(RATE_LIMITERS, "accessKey", "accessSecret", "us-east-1",
|
||||
"attachmentv2-bucket"))
|
||||
.addProvider(new AttachmentControllerV4(RATE_LIMITERS,
|
||||
gcsAttachmentGenerator,
|
||||
new TusAttachmentGenerator(new TusConfiguration(new SecretBytes(TUS_SECRET), TUS_URL)),
|
||||
|
@ -179,33 +176,4 @@ class AttachmentControllerTest {
|
|||
assertThat(credentialParts[3]).isEqualTo("storage");
|
||||
assertThat(credentialParts[4]).isEqualTo("goog4_request");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testV2Form() throws IOException {
|
||||
AttachmentDescriptorV2 descriptor = resources.getJerseyTest()
|
||||
.target("/v2/attachments/form/upload")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||
.get(AttachmentDescriptorV2.class);
|
||||
|
||||
assertThat(descriptor.key()).isEqualTo(descriptor.attachmentIdString());
|
||||
assertThat(descriptor.acl()).isEqualTo("private");
|
||||
assertThat(descriptor.algorithm()).isEqualTo("AWS4-HMAC-SHA256");
|
||||
assertThat(descriptor.attachmentId()).isGreaterThan(0);
|
||||
assertThat(String.valueOf(descriptor.attachmentId())).isEqualTo(descriptor.attachmentIdString());
|
||||
|
||||
String[] credentialParts = descriptor.credential().split("/");
|
||||
|
||||
assertThat(credentialParts[0]).isEqualTo("accessKey");
|
||||
assertThat(credentialParts[2]).isEqualTo("us-east-1");
|
||||
assertThat(credentialParts[3]).isEqualTo("s3");
|
||||
assertThat(credentialParts[4]).isEqualTo("aws4_request");
|
||||
|
||||
assertThat(descriptor.date()).isNotBlank();
|
||||
assertThat(descriptor.policy()).isNotBlank();
|
||||
assertThat(descriptor.signature()).isNotBlank();
|
||||
|
||||
assertThat(new String(Base64.getDecoder().decode(descriptor.policy()))).contains("[\"content-length-range\", 1, 104857600]");
|
||||
}
|
||||
|
||||
}
|
|
@ -58,9 +58,6 @@ svr3.userIdTokenSharedSecret: dbcdefghijklmnopqrstuvwxyz0123456789ABCDEFG= # bas
|
|||
|
||||
tus.userAuthenticationTokenSharedSecret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG=
|
||||
|
||||
awsAttachments.accessKey: test
|
||||
awsAttachments.accessSecret: test
|
||||
|
||||
# The below private key was key generated exclusively for testing purposes. Do not use it in any other context.
|
||||
gcpAttachments.rsaSigningKey: |
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
|
|
|
@ -235,13 +235,6 @@ messageCache: # Redis server configuration for message store cache
|
|||
cluster:
|
||||
type: local
|
||||
|
||||
awsAttachments: # AWS S3 configuration
|
||||
bucket: aws-attachments
|
||||
credentials:
|
||||
accessKeyId: secret://awsAttachments.accessKey
|
||||
secretAccessKey: secret://awsAttachments.accessSecret
|
||||
region: us-west-2
|
||||
|
||||
gcpAttachments: # GCP Storage configuration
|
||||
domain: example.com
|
||||
email: user@example.cocm
|
||||
|
|
Loading…
Reference in New Issue