Create stripe api endpoint for apple pay donations
This commit is contained in:
parent
7bd7d0e84e
commit
17047513c3
|
@ -115,3 +115,20 @@ remoteConfig:
|
||||||
|
|
||||||
paymentService:
|
paymentService:
|
||||||
userAuthenticationTokenSharedSecret: # hex-encoded 32-byte secret shared with MobileCoin services used to generate auth tokens for Signal users
|
userAuthenticationTokenSharedSecret: # hex-encoded 32-byte secret shared with MobileCoin services used to generate auth tokens for Signal users
|
||||||
|
|
||||||
|
donation:
|
||||||
|
uri: # value
|
||||||
|
apiKey: # value
|
||||||
|
supportedCurrencies:
|
||||||
|
- # 1st supported currency
|
||||||
|
- # 2nd supported currency
|
||||||
|
- # ...
|
||||||
|
- # Nth supported currency
|
||||||
|
circuitBreaker:
|
||||||
|
failureRateThreshold: # value
|
||||||
|
ringBufferSizeInHalfOpenState: # value
|
||||||
|
ringBufferSizeInClosedState: # value
|
||||||
|
waitDurationInOpenStateInSeconds: # value
|
||||||
|
retry:
|
||||||
|
maxAttempts: # value
|
||||||
|
waitDuration: # value
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.whispersystems.textsecuregcm.configuration.AwsAttachmentsConfiguratio
|
||||||
import org.whispersystems.textsecuregcm.configuration.CdnConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.CdnConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.DatabaseConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.DatabaseConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.DirectoryConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.DirectoryConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.DonationConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.DynamoDbConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.DynamoDbConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.GcmConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.GcmConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.GcpAttachmentsConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.GcpAttachmentsConfiguration;
|
||||||
|
@ -250,6 +251,11 @@ public class WhisperServerConfiguration extends Configuration {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private TorExitNodeConfiguration tor;
|
private TorExitNodeConfiguration tor;
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NotNull
|
||||||
|
@JsonProperty
|
||||||
|
private DonationConfiguration donation;
|
||||||
|
|
||||||
private Map<String, String> transparentDataIndex = new HashMap<>();
|
private Map<String, String> transparentDataIndex = new HashMap<>();
|
||||||
|
|
||||||
public RecaptchaConfiguration getRecaptchaConfiguration() {
|
public RecaptchaConfiguration getRecaptchaConfiguration() {
|
||||||
|
@ -429,4 +435,8 @@ public class WhisperServerConfiguration extends Configuration {
|
||||||
public TorExitNodeConfiguration getTorExitNodeConfiguration() {
|
public TorExitNodeConfiguration getTorExitNodeConfiguration() {
|
||||||
return tor;
|
return tor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DonationConfiguration getDonationConfiguration() {
|
||||||
|
return donation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.configuration;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
public class DonationConfiguration {
|
||||||
|
|
||||||
|
private String uri;
|
||||||
|
private String apiKey;
|
||||||
|
private Set<String> supportedCurrencies;
|
||||||
|
private CircuitBreakerConfiguration circuitBreaker;
|
||||||
|
private RetryConfiguration retry;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotEmpty
|
||||||
|
public String getUri() {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setUri(final String uri) {
|
||||||
|
this.uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotEmpty
|
||||||
|
public String getApiKey() {
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setApiKey(final String apiKey) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotEmpty
|
||||||
|
public Set<String> getSupportedCurrencies() {
|
||||||
|
return supportedCurrencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setSupportedCurrencies(final Set<String> supportedCurrencies) {
|
||||||
|
this.supportedCurrencies = supportedCurrencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotNull
|
||||||
|
@Valid
|
||||||
|
public CircuitBreakerConfiguration getCircuitBreaker() {
|
||||||
|
return circuitBreaker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setCircuitBreaker(final CircuitBreakerConfiguration circuitBreaker) {
|
||||||
|
this.circuitBreaker = circuitBreaker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotNull
|
||||||
|
@Valid
|
||||||
|
public RetryConfiguration getRetry() {
|
||||||
|
return retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setRetry(final RetryConfiguration retry) {
|
||||||
|
this.retry = retry;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.controllers;
|
||||||
|
|
||||||
|
import com.codahale.metrics.annotation.Timed;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.dropwizard.auth.Auth;
|
||||||
|
import io.dropwizard.util.Strings;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient.Redirect;
|
||||||
|
import java.net.http.HttpClient.Version;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.net.http.HttpResponse.BodyHandlers;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.DonationConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.entities.ApplePayAuthorizationRequest;
|
||||||
|
import org.whispersystems.textsecuregcm.entities.ApplePayAuthorizationResponse;
|
||||||
|
import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient;
|
||||||
|
import org.whispersystems.textsecuregcm.http.FormDataBodyPublisher;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
|
|
||||||
|
@Path("/v1/donation")
|
||||||
|
public class DonationController {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(DonationController.class);
|
||||||
|
|
||||||
|
private final URI uri;
|
||||||
|
private final String apiKey;
|
||||||
|
private final Set<String> supportedCurrencies;
|
||||||
|
private final FaultTolerantHttpClient httpClient;
|
||||||
|
|
||||||
|
public DonationController(final Executor executor, final DonationConfiguration configuration) {
|
||||||
|
this.uri = URI.create(configuration.getUri());
|
||||||
|
this.apiKey = configuration.getApiKey();
|
||||||
|
this.supportedCurrencies = configuration.getSupportedCurrencies();
|
||||||
|
this.httpClient = FaultTolerantHttpClient.newBuilder()
|
||||||
|
.withCircuitBreaker(configuration.getCircuitBreaker())
|
||||||
|
.withRetry(configuration.getRetry())
|
||||||
|
.withVersion(Version.HTTP_2)
|
||||||
|
.withConnectTimeout(Duration.ofSeconds(10))
|
||||||
|
.withRedirect(Redirect.NEVER)
|
||||||
|
.withExecutor(executor)
|
||||||
|
.withName("donation")
|
||||||
|
.withSecurityProtocol(FaultTolerantHttpClient.SECURITY_PROTOCOL_TLS_1_3)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Timed
|
||||||
|
@POST
|
||||||
|
@Path("/authorize-apple-pay")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public CompletableFuture<Response> getApplePayAuthorization(@Auth Account account, @Valid ApplePayAuthorizationRequest request) {
|
||||||
|
if (!supportedCurrencies.contains(request.getCurrency())) {
|
||||||
|
return CompletableFuture.completedFuture(Response.status(422).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
final HttpRequest httpRequest = HttpRequest.newBuilder()
|
||||||
|
.uri(uri)
|
||||||
|
.POST(FormDataBodyPublisher.of(Map.of(
|
||||||
|
"amount", Long.toString(request.getAmount()),
|
||||||
|
"currency", request.getCurrency())))
|
||||||
|
.header("Authorization", "Basic " + Base64.getEncoder().encodeToString(
|
||||||
|
(apiKey + ":").getBytes(StandardCharsets.UTF_8)))
|
||||||
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
.build();
|
||||||
|
return httpClient.sendAsync(httpRequest, BodyHandlers.ofString())
|
||||||
|
.thenApply(this::processApplePayAuthorizationRemoteResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response processApplePayAuthorizationRemoteResponse(HttpResponse<String> response) {
|
||||||
|
ObjectMapper mapper = SystemMapper.getMapper();
|
||||||
|
|
||||||
|
if (response.statusCode() >= 200 && response.statusCode() < 300 &&
|
||||||
|
MediaType.APPLICATION_JSON.equalsIgnoreCase(response.headers().firstValue("Content-Type").orElse(null))) {
|
||||||
|
try {
|
||||||
|
final JsonNode jsonResponse = mapper.readTree(response.body());
|
||||||
|
final String id = jsonResponse.get("id").asText(null);
|
||||||
|
final String clientSecret = jsonResponse.get("client_secret").asText(null);
|
||||||
|
if (Strings.isNullOrEmpty(id) || Strings.isNullOrEmpty(clientSecret)) {
|
||||||
|
logger.warn("missing fields in json response in donation controller");
|
||||||
|
return Response.status(500).build();
|
||||||
|
}
|
||||||
|
final String responseJson = mapper.writeValueAsString(new ApplePayAuthorizationResponse(id, clientSecret));
|
||||||
|
return Response.ok(responseJson, MediaType.APPLICATION_JSON_TYPE).build();
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
logger.warn("json processing error in donation controller", e);
|
||||||
|
return Response.status(500).build();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warn("unexpected response code returned to donation controller");
|
||||||
|
return Response.status(500).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.entities;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.Pattern;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
public class ApplePayAuthorizationRequest {
|
||||||
|
|
||||||
|
private String currency;
|
||||||
|
private long amount;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@NotEmpty
|
||||||
|
@Size(min=3, max=3)
|
||||||
|
@Pattern(regexp="[a-z]{3}")
|
||||||
|
public String getCurrency() {
|
||||||
|
return currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrency(final String currency) {
|
||||||
|
this.currency = currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
@Min(0)
|
||||||
|
public long getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setAmount(final long amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.entities;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.dropwizard.util.Strings;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
|
public class ApplePayAuthorizationResponse {
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String clientSecret;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public ApplePayAuthorizationResponse(
|
||||||
|
@JsonProperty("id") final String id,
|
||||||
|
@JsonProperty("client_secret") final String clientSecret) {
|
||||||
|
if (Strings.isNullOrEmpty(id)) {
|
||||||
|
throw new IllegalArgumentException("id cannot be empty");
|
||||||
|
}
|
||||||
|
if (Strings.isNullOrEmpty(clientSecret)) {
|
||||||
|
throw new IllegalArgumentException("clientSecret cannot be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.id = id;
|
||||||
|
this.clientSecret = clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty("id")
|
||||||
|
@NotEmpty
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonProperty("client_secret")
|
||||||
|
@NotEmpty
|
||||||
|
public String getClientSecret() {
|
||||||
|
return clientSecret;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Signal Messenger, LLC
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||||
|
import static com.github.tomakehurst.wiremock.client.WireMock.post;
|
||||||
|
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||||
|
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import com.github.tomakehurst.wiremock.junit.WireMockRule;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
|
||||||
|
import io.dropwizard.testing.junit5.ResourceExtension;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import javax.ws.rs.client.Entity;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAccount;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.CircuitBreakerConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.DonationConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.RetryConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.DonationController;
|
||||||
|
import org.whispersystems.textsecuregcm.entities.ApplePayAuthorizationRequest;
|
||||||
|
import org.whispersystems.textsecuregcm.entities.ApplePayAuthorizationResponse;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.Account;
|
||||||
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
|
|
||||||
|
public class DonationControllerTest {
|
||||||
|
|
||||||
|
private static final Executor executor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort().dynamicHttpsPort());
|
||||||
|
|
||||||
|
private ResourceExtension resources;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() throws Throwable {
|
||||||
|
DonationConfiguration configuration = new DonationConfiguration();
|
||||||
|
configuration.setApiKey("test-api-key");
|
||||||
|
configuration.setUri("http://localhost:" + wireMockRule.port() + "/foo/bar");
|
||||||
|
configuration.setCircuitBreaker(new CircuitBreakerConfiguration());
|
||||||
|
configuration.setRetry(new RetryConfiguration());
|
||||||
|
configuration.setSupportedCurrencies(Set.of("usd", "gbp"));
|
||||||
|
resources = ResourceExtension.builder()
|
||||||
|
.addProvider(AuthHelper.getAuthFilter())
|
||||||
|
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(ImmutableSet.of(Account.class, DisabledPermittedAccount.class)))
|
||||||
|
.setMapper(SystemMapper.getMapper())
|
||||||
|
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
|
||||||
|
.addResource(new DonationController(executor, configuration))
|
||||||
|
.build();
|
||||||
|
resources.before();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() throws Throwable {
|
||||||
|
resources.after();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetApplePayAuthorizationReturns200() {
|
||||||
|
wireMockRule.stubFor(post(urlEqualTo("/foo/bar"))
|
||||||
|
.withBasicAuth("test-api-key", "")
|
||||||
|
.willReturn(aResponse()
|
||||||
|
.withHeader("Content-Type", MediaType.APPLICATION_JSON)
|
||||||
|
.withBody("{\"id\":\"an_id\",\"client_secret\":\"some_secret\"}")));
|
||||||
|
|
||||||
|
ApplePayAuthorizationRequest request = new ApplePayAuthorizationRequest();
|
||||||
|
request.setCurrency("usd");
|
||||||
|
request.setAmount(1000);
|
||||||
|
Response response = resources.getJerseyTest()
|
||||||
|
.target("/v1/donation/authorize-apple-pay")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
|
||||||
|
.post(Entity.entity(request, MediaType.APPLICATION_JSON_TYPE));
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
|
||||||
|
ApplePayAuthorizationResponse responseObject = response.readEntity(ApplePayAuthorizationResponse.class);
|
||||||
|
assertThat(responseObject.getId()).isEqualTo("an_id");
|
||||||
|
assertThat(responseObject.getClientSecret()).isEqualTo("some_secret");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetApplePayAuthorizationWithoutAuthHeaderReturns401() {
|
||||||
|
ApplePayAuthorizationRequest request = new ApplePayAuthorizationRequest();
|
||||||
|
request.setCurrency("usd");
|
||||||
|
request.setAmount(1000);
|
||||||
|
Response response = resources.getJerseyTest()
|
||||||
|
.target("/v1/donation/authorize-apple-pay")
|
||||||
|
.request()
|
||||||
|
.post(Entity.entity(request, MediaType.APPLICATION_JSON_TYPE));
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetApplePayAuthorizationWithUnsupportedCurrencyReturns422() {
|
||||||
|
ApplePayAuthorizationRequest request = new ApplePayAuthorizationRequest();
|
||||||
|
request.setCurrency("zzz");
|
||||||
|
request.setAmount(1000);
|
||||||
|
Response response = resources.getJerseyTest()
|
||||||
|
.target("/v1/donation/authorize-apple-pay")
|
||||||
|
.request()
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
|
||||||
|
.post(Entity.entity(request, MediaType.APPLICATION_JSON_TYPE));
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(422);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue