Remove deprecated /v1/attachments
This commit is contained in:
parent
c05692e417
commit
4c677ec2da
|
@ -289,10 +289,6 @@
|
|||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-s3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>dynamodb-lock-client</artifactId>
|
||||
|
|
|
@ -80,7 +80,6 @@ import org.whispersystems.textsecuregcm.badges.ResourceBundleLevelTranslator;
|
|||
import org.whispersystems.textsecuregcm.configuration.DirectoryServerConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.controllers.AccountController;
|
||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV1;
|
||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV2;
|
||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV3;
|
||||
import org.whispersystems.textsecuregcm.controllers.CertificateController;
|
||||
|
@ -136,7 +135,6 @@ import org.whispersystems.textsecuregcm.metrics.MicrometerRegistryManager;
|
|||
import org.whispersystems.textsecuregcm.metrics.NetworkReceivedGauge;
|
||||
import org.whispersystems.textsecuregcm.metrics.NetworkSentGauge;
|
||||
import org.whispersystems.textsecuregcm.metrics.OperatingSystemMemoryGauge;
|
||||
import org.whispersystems.textsecuregcm.push.PushLatencyManager;
|
||||
import org.whispersystems.textsecuregcm.metrics.ReportedMessageMetricsListener;
|
||||
import org.whispersystems.textsecuregcm.metrics.TrafficSource;
|
||||
import org.whispersystems.textsecuregcm.providers.MultiRecipientMessageProvider;
|
||||
|
@ -148,6 +146,7 @@ import org.whispersystems.textsecuregcm.push.ClientPresenceManager;
|
|||
import org.whispersystems.textsecuregcm.push.FcmSender;
|
||||
import org.whispersystems.textsecuregcm.push.MessageSender;
|
||||
import org.whispersystems.textsecuregcm.push.ProvisioningManager;
|
||||
import org.whispersystems.textsecuregcm.push.PushLatencyManager;
|
||||
import org.whispersystems.textsecuregcm.push.PushNotificationManager;
|
||||
import org.whispersystems.textsecuregcm.push.ReceiptSender;
|
||||
import org.whispersystems.textsecuregcm.recaptcha.RecaptchaClient;
|
||||
|
@ -632,7 +631,6 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
environment.jersey().register(new KeysController(rateLimiters, keys, accountsManager));
|
||||
|
||||
final List<Object> commonControllers = Lists.newArrayList(
|
||||
new AttachmentControllerV1(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getBucket()),
|
||||
new AttachmentControllerV2(rateLimiters, config.getAwsAttachmentsConfiguration().getAccessKey(), config.getAwsAttachmentsConfiguration().getAccessSecret(), config.getAwsAttachmentsConfiguration().getRegion(), config.getAwsAttachmentsConfiguration().getBucket()),
|
||||
new AttachmentControllerV3(rateLimiters, config.getGcpAttachmentsConfiguration().getDomain(), config.getGcpAttachmentsConfiguration().getEmail(), config.getGcpAttachmentsConfiguration().getMaxSizeInBytes(), config.getGcpAttachmentsConfiguration().getPathPrefix(), config.getGcpAttachmentsConfiguration().getRsaSigningKey()),
|
||||
new CertificateController(new CertificateGenerator(config.getDeliveryCertificate().getCertificate(), config.getDeliveryCertificate().getPrivateKey(), config.getDeliveryCertificate().getExpiresDays()), zkAuthOperations, clock),
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.controllers;
|
||||
|
||||
import org.whispersystems.textsecuregcm.util.Conversions;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class AttachmentControllerBase {
|
||||
|
||||
protected long generateAttachmentId() {
|
||||
byte[] attachmentBytes = new byte[8];
|
||||
new SecureRandom().nextBytes(attachmentBytes);
|
||||
|
||||
attachmentBytes[0] = (byte)(attachmentBytes[0] & 0x7F);
|
||||
return Conversions.byteArrayToLong(attachmentBytes);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013-2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package org.whispersystems.textsecuregcm.controllers;
|
||||
|
||||
import com.amazonaws.HttpMethod;
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import io.dropwizard.auth.Auth;
|
||||
import java.net.URL;
|
||||
import java.util.stream.Stream;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptorV1;
|
||||
import org.whispersystems.textsecuregcm.entities.AttachmentUri;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.s3.UrlSigner;
|
||||
|
||||
|
||||
@Path("/v1/attachments")
|
||||
public class AttachmentControllerV1 extends AttachmentControllerBase {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Logger logger = LoggerFactory.getLogger(AttachmentControllerV1.class);
|
||||
|
||||
private static final String[] UNACCELERATED_REGIONS = {"+20", "+971", "+968", "+974"};
|
||||
|
||||
private final RateLimiters rateLimiters;
|
||||
private final UrlSigner urlSigner;
|
||||
|
||||
public AttachmentControllerV1(RateLimiters rateLimiters, String accessKey, String accessSecret, String bucket) {
|
||||
this.rateLimiters = rateLimiters;
|
||||
this.urlSigner = new UrlSigner(accessKey, accessSecret, bucket);
|
||||
}
|
||||
|
||||
@Timed
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public AttachmentDescriptorV1 allocateAttachment(@Auth AuthenticatedAccount auth) throws RateLimitExceededException {
|
||||
|
||||
rateLimiters.getAttachmentLimiter().validate(auth.getAccount().getUuid());
|
||||
|
||||
long attachmentId = generateAttachmentId();
|
||||
URL url = urlSigner.getPreSignedUrl(attachmentId, HttpMethod.PUT,
|
||||
Stream.of(UNACCELERATED_REGIONS).anyMatch(region -> auth.getAccount().getNumber().startsWith(region)));
|
||||
|
||||
return new AttachmentDescriptorV1(attachmentId, url.toExternalForm());
|
||||
}
|
||||
|
||||
@Timed
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("/{attachmentId}")
|
||||
public AttachmentUri redirectToAttachment(@Auth AuthenticatedAccount auth,
|
||||
@PathParam("attachmentId") long attachmentId) {
|
||||
return new AttachmentUri(urlSigner.getPreSignedUrl(attachmentId, HttpMethod.GET,
|
||||
Stream.of(UNACCELERATED_REGIONS).anyMatch(region -> auth.getAccount().getNumber().startsWith(region))));
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ package org.whispersystems.textsecuregcm.controllers;
|
|||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import io.dropwizard.auth.Auth;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.ws.rs.GET;
|
||||
|
@ -19,19 +20,21 @@ import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
|||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.s3.PolicySigner;
|
||||
import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator;
|
||||
import org.whispersystems.textsecuregcm.util.Conversions;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
|
||||
@Path("/v2/attachments")
|
||||
public class AttachmentControllerV2 extends AttachmentControllerBase {
|
||||
public class AttachmentControllerV2 {
|
||||
|
||||
private final PostPolicyGenerator policyGenerator;
|
||||
private final PolicySigner policySigner;
|
||||
private final RateLimiter rateLimiter;
|
||||
private final PolicySigner policySigner;
|
||||
private final RateLimiter rateLimiter;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
@Timed
|
||||
|
@ -54,5 +57,12 @@ public class AttachmentControllerV2 extends AttachmentControllerBase {
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
|||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
|
||||
@Path("/v3/attachments")
|
||||
public class AttachmentControllerV3 extends AttachmentControllerBase {
|
||||
public class AttachmentControllerV3 {
|
||||
|
||||
@Nonnull
|
||||
private final RateLimiter rateLimiter;
|
||||
|
|
|
@ -1,39 +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 class AttachmentDescriptorV1 {
|
||||
|
||||
@JsonProperty
|
||||
private long id;
|
||||
|
||||
@JsonProperty
|
||||
private String idString;
|
||||
|
||||
@JsonProperty
|
||||
private String location;
|
||||
|
||||
public AttachmentDescriptorV1(long id, String location) {
|
||||
this.id = id;
|
||||
this.idString = String.valueOf(id);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public AttachmentDescriptorV1() {}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public String getIdString() {
|
||||
return idString;
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package org.whispersystems.textsecuregcm.s3;
|
||||
|
||||
import com.amazonaws.HttpMethod;
|
||||
import com.amazonaws.auth.AWSCredentials;
|
||||
import com.amazonaws.auth.BasicAWSCredentials;
|
||||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.AmazonS3Client;
|
||||
import com.amazonaws.services.s3.S3ClientOptions;
|
||||
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
|
||||
public class UrlSigner {
|
||||
|
||||
private static final long DURATION = 60 * 60 * 1000;
|
||||
|
||||
private final AWSCredentials credentials;
|
||||
private final String bucket;
|
||||
|
||||
public UrlSigner(String accessKey, String accessSecret, String bucket) {
|
||||
this.credentials = new BasicAWSCredentials(accessKey, accessSecret);
|
||||
this.bucket = bucket;
|
||||
}
|
||||
|
||||
public URL getPreSignedUrl(long attachmentId, HttpMethod method, boolean unaccelerated) {
|
||||
AmazonS3 client = new AmazonS3Client(credentials);
|
||||
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, String.valueOf(attachmentId), method);
|
||||
|
||||
request.setExpiration(new Date(System.currentTimeMillis() + DURATION));
|
||||
request.setContentType("application/octet-stream");
|
||||
|
||||
if (unaccelerated) {
|
||||
client.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).build());
|
||||
} else {
|
||||
client.setS3ClientOptions(S3ClientOptions.builder().setAccelerateModeEnabled(true).build());
|
||||
}
|
||||
|
||||
return client.generatePresignedUrl(request);
|
||||
}
|
||||
|
||||
}
|
|
@ -35,13 +35,10 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
|
||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV1;
|
||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV2;
|
||||
import org.whispersystems.textsecuregcm.controllers.AttachmentControllerV3;
|
||||
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptorV1;
|
||||
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptorV2;
|
||||
import org.whispersystems.textsecuregcm.entities.AttachmentDescriptorV3;
|
||||
import org.whispersystems.textsecuregcm.entities.AttachmentUri;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||
|
@ -83,7 +80,6 @@ class AttachmentControllerTest {
|
|||
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
|
||||
.setMapper(SystemMapper.getMapper())
|
||||
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||
.addResource(new AttachmentControllerV1(rateLimiters, "accessKey", "accessSecret", "attachment-bucket"))
|
||||
.addResource(new AttachmentControllerV2(rateLimiters, "accessKey", "accessSecret", "us-east-1", "attachmentv2-bucket"))
|
||||
.addResource(new AttachmentControllerV3(rateLimiters, "some-cdn.signal.org", "signal@example.com", 1000, "/attach-here", RSA_PRIVATE_KEY_PEM))
|
||||
.build();
|
||||
|
@ -198,53 +194,4 @@ class AttachmentControllerTest {
|
|||
assertThat(response.getStatus()).isEqualTo(401);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testAcceleratedPut() {
|
||||
AttachmentDescriptorV1 descriptor = resources.getJerseyTest()
|
||||
.target("/v1/attachments/")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||
.get(AttachmentDescriptorV1.class);
|
||||
|
||||
assertThat(descriptor.getLocation()).startsWith("https://attachment-bucket.s3-accelerate.amazonaws.com");
|
||||
assertThat(descriptor.getId()).isGreaterThan(0);
|
||||
assertThat(descriptor.getIdString()).isNotBlank();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnacceleratedPut() {
|
||||
AttachmentDescriptorV1 descriptor = resources.getJerseyTest()
|
||||
.target("/v1/attachments/")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
|
||||
.get(AttachmentDescriptorV1.class);
|
||||
|
||||
assertThat(descriptor.getLocation()).startsWith("https://s3.amazonaws.com");
|
||||
assertThat(descriptor.getId()).isGreaterThan(0);
|
||||
assertThat(descriptor.getIdString()).isNotBlank();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAcceleratedGet() throws MalformedURLException {
|
||||
AttachmentUri uri = resources.getJerseyTest()
|
||||
.target("/v1/attachments/1234")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
|
||||
.get(AttachmentUri.class);
|
||||
|
||||
assertThat(uri.getLocation().getHost()).isEqualTo("attachment-bucket.s3-accelerate.amazonaws.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnacceleratedGet() throws MalformedURLException {
|
||||
AttachmentUri uri = resources.getJerseyTest()
|
||||
.target("/v1/attachments/1234")
|
||||
.request()
|
||||
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
|
||||
.get(AttachmentUri.class);
|
||||
|
||||
assertThat(uri.getLocation().getHost()).isEqualTo("s3.amazonaws.com");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013-2020 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.tests.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.amazonaws.HttpMethod;
|
||||
import java.net.URL;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.whispersystems.textsecuregcm.s3.UrlSigner;
|
||||
|
||||
class UrlSignerTest {
|
||||
|
||||
@Test
|
||||
void testTransferAcceleration() {
|
||||
UrlSigner signer = new UrlSigner("foo", "bar", "attachments-test");
|
||||
URL url = signer.getPreSignedUrl(1234, HttpMethod.GET, false);
|
||||
|
||||
assertThat(url).hasHost("attachments-test.s3-accelerate.amazonaws.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTransferUnaccelerated() {
|
||||
UrlSigner signer = new UrlSigner("foo", "bar", "attachments-test");
|
||||
URL url = signer.getPreSignedUrl(1234, HttpMethod.GET, true);
|
||||
|
||||
assertThat(url).hasHost("s3.amazonaws.com");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue