mirror of
https://github.com/valitydev/adapter-bank-spring-boot-starter.git
synced 2024-11-06 01:05:20 +00:00
Integration with adapter-common-lib (#7)
This commit is contained in:
parent
21fa50b2c9
commit
a12c4a0c32
22
README.md
22
README.md
@ -1 +1,21 @@
|
||||
# adapter-bank-spring-boot-starter
|
||||
### adapter-bank-spring-boot-starter
|
||||
|
||||
**Adapter-bank-spring-boot-starter** - это подключаемый Spring Boot модуль для стандартных
|
||||
компонентов proxy-алаптеров.
|
||||
|
||||
Для корректной работы Вашего адаптера необходимо:
|
||||
* подключить необходимые properties (AdapterProperties, TimerProperties). Если поля родителя
|
||||
не покрывают всех необходимых бизнес-полей, то необходимо унаследоваться от родителя и
|
||||
при помощи аннотаций @Configuration и @ConfigurationProperties создать соответствующий
|
||||
класс конфигураций .Если поля родителя полностью покрывают case, то можно не создавать
|
||||
класс-наследник, а создать соответствующий bean в конфигурации. Например:
|
||||
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConfigurationProperties("time.config")
|
||||
public TimerProperties timerProperties() {
|
||||
return new TimerProperties();
|
||||
}
|
||||
|
||||
|
5
pom.xml
5
pom.xml
@ -100,6 +100,11 @@
|
||||
<artifactId>hellgate-adapter-client</artifactId>
|
||||
<version>${hellgate-adapter-client.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.rbkmoney</groupId>
|
||||
<artifactId>adapter-common-lib</artifactId>
|
||||
<version>0.0.4-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
|
@ -0,0 +1,39 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rbkmoney.adapter.common.component.NetworkFilterComponent;
|
||||
import com.rbkmoney.adapter.common.mapper.SimpleErrorMapping;
|
||||
import com.rbkmoney.adapter.common.mapper.SimpleObjectMapper;
|
||||
import com.rbkmoney.error.mapping.ErrorMapping;
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Value("${error-mapping.file}")
|
||||
private Resource errorMappingFilePath;
|
||||
|
||||
@Value("${error-mapping.patternReason:\"'%s' - '%s'\"}")
|
||||
private String errorMappingPattern;
|
||||
|
||||
@Bean
|
||||
public ErrorMapping errorMapping() throws IOException {
|
||||
return new SimpleErrorMapping(errorMappingFilePath, errorMappingPattern).getErrorMapping();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper(){
|
||||
return new SimpleObjectMapper().getSimpleObjectMapper();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rbkmoney.error.mapping.ErrorMapping;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Configuration
|
||||
public class ErrorMappingConfiguration {
|
||||
|
||||
@Value("${error-mapping.file}")
|
||||
private Resource filePath;
|
||||
|
||||
@Value("${error-mapping.patternReason:\"'%s' - '%s'\"}")
|
||||
private String patternReason;
|
||||
|
||||
@Bean
|
||||
ErrorMapping errorMapping() throws IOException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
|
||||
|
||||
ErrorMapping errorMapping = new ErrorMapping(filePath.getInputStream(), patternReason, mapper);
|
||||
errorMapping.validateMappingFormat();
|
||||
return errorMapping;
|
||||
}
|
||||
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.config;
|
||||
|
||||
import com.rbkmoney.woody.api.flow.WFlow;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@Configuration
|
||||
public class FilterConfiguration {
|
||||
|
||||
public static final String HEALTH = "/actuator/health";
|
||||
|
||||
@Value("${server.rest.port}")
|
||||
private int restPort;
|
||||
|
||||
@Value("/${server.rest.endpoint}/")
|
||||
private String restEndpoint;
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean externalPortRestrictingFilter() {
|
||||
Filter filter = new OncePerRequestFilter() {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
String servletPath = request.getServletPath();
|
||||
if ((request.getLocalPort() == restPort)
|
||||
&& !(servletPath.startsWith(restEndpoint) || servletPath.startsWith(HEALTH))) {
|
||||
response.sendError(404, "Unknown address");
|
||||
return;
|
||||
}
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
};
|
||||
|
||||
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
|
||||
filterRegistrationBean.setFilter(filter);
|
||||
filterRegistrationBean.setOrder(-100);
|
||||
filterRegistrationBean.setName("httpPortFilter");
|
||||
filterRegistrationBean.addUrlPatterns("/*");
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean woodyFilter() {
|
||||
WFlow wFlow = new WFlow();
|
||||
Filter filter = new OncePerRequestFilter() {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
if ((request.getLocalPort() == restPort)
|
||||
&& request.getServletPath().startsWith(restEndpoint)) {
|
||||
wFlow.createServiceFork(() -> {
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
} catch (IOException | ServletException e) {
|
||||
sneakyThrow(e);
|
||||
}
|
||||
}).run();
|
||||
return;
|
||||
}
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private <E extends Throwable, T> T sneakyThrow(Throwable t) throws E {
|
||||
throw (E) t;
|
||||
}
|
||||
};
|
||||
|
||||
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
|
||||
filterRegistrationBean.setFilter(filter);
|
||||
filterRegistrationBean.setOrder(-50);
|
||||
filterRegistrationBean.setName("woodyFilter");
|
||||
filterRegistrationBean.addUrlPatterns(restEndpoint + "*");
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Slf4j
|
||||
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
|
||||
|
||||
private AtomicInteger requestNumberSequence = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
|
||||
int requestNumber = requestNumberSequence.incrementAndGet();
|
||||
logRequest(requestNumber, request, body);
|
||||
ClientHttpResponse response = execution.execute(request, body);
|
||||
response = new BufferedClientHttpResponse(response);
|
||||
logResponse(requestNumber, response);
|
||||
return response;
|
||||
}
|
||||
|
||||
private void logRequest(int requestNumber, HttpRequest request, byte[] body) {
|
||||
if (log.isDebugEnabled()) {
|
||||
String prefix = requestNumber + " > ";
|
||||
log.debug("{} Request: {} {}", prefix, request.getMethod(), request.getURI());
|
||||
log.debug("{} Headers: {}", prefix, request.getHeaders());
|
||||
if (body.length > 0) {
|
||||
log.debug("{} Body: \n{}", prefix, new String(body, StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void logResponse(int requestNumber, ClientHttpResponse response) throws IOException {
|
||||
if (log.isDebugEnabled()) {
|
||||
String prefix = requestNumber + " < ";
|
||||
log.debug("{} Response: {} {} {}", prefix, response.getStatusCode(), response.getStatusCode().name(), response.getStatusText());
|
||||
log.debug("{} Headers: {}", prefix, response.getHeaders());
|
||||
String body = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);
|
||||
if (body.length() > 0) {
|
||||
log.debug("{} Body: \n{}", prefix, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around ClientHttpResponse, buffers the body so it can be read repeatedly (for logging & consuming the result).
|
||||
*/
|
||||
private class BufferedClientHttpResponse implements ClientHttpResponse {
|
||||
|
||||
private final ClientHttpResponse response;
|
||||
private byte[] body;
|
||||
|
||||
public BufferedClientHttpResponse(ClientHttpResponse response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatus getStatusCode() throws IOException {
|
||||
return response.getStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return response.getRawStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusText() throws IOException {
|
||||
return response.getStatusText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
response.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
if (body == null) {
|
||||
body = StreamUtils.copyToByteArray(response.getBody());
|
||||
}
|
||||
return new ByteArrayInputStream(body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return response.getHeaders();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.config;
|
||||
|
||||
import com.rbkmoney.adapter.common.component.NetworkFilterComponent;
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class NetworkConfig {
|
||||
|
||||
@Value("${server.rest.port}")
|
||||
private int restPort;
|
||||
|
||||
@Value("/${server.rest.endpoint}/")
|
||||
private String restEndpoint;
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean externalPortRestrictingFilter() {
|
||||
return new NetworkFilterComponent().externalPortRestrictingFilter(restPort, restEndpoint);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean woodyFilter() {
|
||||
return new NetworkFilterComponent().woodyFilter(restPort, restEndpoint);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletWebServerFactory servletContainer() {
|
||||
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
|
||||
Connector connector = new Connector();
|
||||
connector.setPort(restPort);
|
||||
tomcat.addAdditionalTomcatConnectors(connector);
|
||||
return tomcat;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rbkmoney.adapter.common.serializer.AdapterSerializer;
|
||||
import com.rbkmoney.adapter.common.serializer.CallbackSerializer;
|
||||
import com.rbkmoney.adapter.common.serializer.RecTokenSerializer;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class SerializerConfig {
|
||||
|
||||
@Bean
|
||||
public CallbackSerializer callbackSerializer(ObjectMapper objectMapper) {
|
||||
return new CallbackSerializer(objectMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AdapterSerializer adapterSerializer(ObjectMapper objectMapper) {
|
||||
return new AdapterSerializer(objectMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RecTokenSerializer recTokenSerializer(ObjectMapper objectMapper) {
|
||||
return new RecTokenSerializer(objectMapper);
|
||||
}
|
||||
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.config.properties;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Configuration
|
||||
@ConfigurationProperties("adapter")
|
||||
@Validated
|
||||
public class AdapterProperties {
|
||||
|
||||
@NotEmpty
|
||||
private String url;
|
||||
|
||||
@NotEmpty
|
||||
private String callbackUrl;
|
||||
|
||||
@NotEmpty
|
||||
private String pathCallbackUrl;
|
||||
|
||||
@NotEmpty
|
||||
private String pathRecurrentCallbackUrl;
|
||||
|
||||
@NotEmpty
|
||||
private String tagPrefix;
|
||||
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.config.properties;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties("time.config")
|
||||
@Validated
|
||||
@Getter
|
||||
@Setter
|
||||
public class TimerProperties {
|
||||
|
||||
@NotNull
|
||||
private int redirectTimeout;
|
||||
|
||||
@NotNull
|
||||
private int maxTimePolling;
|
||||
|
||||
@NotNull
|
||||
private int pollingDelay;
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.constants;
|
||||
|
||||
public enum TargetStatus {
|
||||
|
||||
PROCESSED,
|
||||
CAPTURED,
|
||||
CANCELLED,
|
||||
REFUNDED,
|
||||
AUTH_RECURRENT
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.constants;
|
||||
|
||||
public class ThreeDsFields {
|
||||
|
||||
public static final String MD = "MD";
|
||||
public static final String PA_REQ = "PaReq";
|
||||
public static final String PA_RES = "PaRes";
|
||||
public static final String TERM_URL = "TermUrl";
|
||||
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.controller;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.Callback;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.serializer.CallbackSerializer;
|
||||
import com.rbkmoney.adapter.helpers.hellgate.HellgateAdapterClient;
|
||||
import com.rbkmoney.adapter.helpers.hellgate.exception.HellgateException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
|
||||
/**
|
||||
* Handler callback 3DS
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/${server.rest.endpoint}")
|
||||
public class AdapterController {
|
||||
|
||||
private final HellgateAdapterClient hgClient;
|
||||
private final CallbackSerializer callbackSerializer;
|
||||
|
||||
@PostMapping(value = "term_url")
|
||||
public String receivePaymentIncomingParameters(HttpServletRequest request, HttpServletResponse servletResponse) throws IOException {
|
||||
return processCallback(request, servletResponse, hgClient::processPaymentCallback);
|
||||
}
|
||||
|
||||
@PostMapping(value = "rec_term_url")
|
||||
public String receiveRecurrentIncomingParameters(HttpServletRequest request, HttpServletResponse servletResponse) throws IOException {
|
||||
return processCallback(request, servletResponse, hgClient::processRecurrentTokenCallback);
|
||||
}
|
||||
|
||||
private String processCallback(HttpServletRequest servletRequest, HttpServletResponse servletResponse, BiFunction<String, ByteBuffer, ByteBuffer> hgFunction) throws IOException {
|
||||
String resp = "";
|
||||
Callback callbackObj = callbackSerializer.read(servletRequest);
|
||||
log.info("ProcessCallback {}", callbackObj);
|
||||
try {
|
||||
String tag = callbackObj.getMd();
|
||||
ByteBuffer callback = ByteBuffer.wrap(callbackSerializer.writeByte(callbackObj));
|
||||
ByteBuffer response = hgFunction.apply(tag, callback);
|
||||
resp = new String(response.array(), StandardCharsets.UTF_8);
|
||||
} catch (HellgateException e) {
|
||||
log.warn("Failed handle callback for recurrent", e);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed handle callback for recurrent", e);
|
||||
}
|
||||
if (StringUtils.hasText(callbackObj.getTermUrl())) {
|
||||
servletResponse.sendRedirect(callbackObj.getTermUrl());
|
||||
}
|
||||
log.info("ProcessCallback response {}", resp);
|
||||
return resp;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.controller;
|
||||
|
||||
import com.rbkmoney.adapter.common.controller.AdapterController;
|
||||
import com.rbkmoney.adapter.common.serializer.CallbackSerializer;
|
||||
import com.rbkmoney.adapter.helpers.hellgate.HellgateAdapterClient;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/** Handler callback 3DS */
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/${server.rest.endpoint}")
|
||||
public class AdapterControllerDecorator {
|
||||
|
||||
private AdapterController adapterController;
|
||||
|
||||
public AdapterControllerDecorator(HellgateAdapterClient hgClient, CallbackSerializer callbackSerializer) {
|
||||
adapterController = new AdapterController(hgClient, callbackSerializer);
|
||||
}
|
||||
|
||||
@PostMapping(value = "term_url")
|
||||
public String receivePaymentIncomingParameters(HttpServletRequest servletRequest,
|
||||
HttpServletResponse servletResponse) throws IOException {
|
||||
return adapterController.receivePaymentIncomingParameters(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
@PostMapping(value = "rec_term_url")
|
||||
public String receiveRecurrentIncomingParameters(HttpServletRequest servletRequest,
|
||||
HttpServletResponse servletResponse) throws IOException {
|
||||
return adapterController.receiveRecurrentIncomingParameters(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.exception;
|
||||
|
||||
public class UnknownTargetStatusException extends RuntimeException {
|
||||
|
||||
public UnknownTargetStatusException() {
|
||||
super("Unknown target status!");
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.exception;
|
||||
|
||||
import org.apache.thrift.TException;
|
||||
|
||||
public class UnsupportedMethodException extends TException {
|
||||
|
||||
public UnsupportedMethodException() {
|
||||
super("Unsupported method");
|
||||
}
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.flow;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.rbkmoney.adapter.common.enums.Step;
|
||||
|
||||
@Component
|
||||
public class DefaultStepResolverImpl implements StepResolver<StateModel, ExitStateModel> {
|
||||
public class DefaultStepResolverImpl implements StepResolver<StateModel> {
|
||||
|
||||
@Override
|
||||
public Step resolveEntry(StateModel stateModel) {
|
||||
@ -17,8 +16,6 @@ public class DefaultStepResolverImpl implements StepResolver<StateModel, ExitSta
|
||||
return Step.REFUND;
|
||||
case CANCELLED:
|
||||
return Step.CANCEL;
|
||||
case AUTH_RECURRENT:
|
||||
return resolveAuthRecurrent(stateModel);
|
||||
default:
|
||||
throw new IllegalStateException("Unknown status of entryState");
|
||||
}
|
||||
@ -35,17 +32,6 @@ public class DefaultStepResolverImpl implements StepResolver<StateModel, ExitSta
|
||||
return Step.AUTH;
|
||||
}
|
||||
|
||||
private Step resolveAuthRecurrent(StateModel stateModel) {
|
||||
AdapterContext adapterContext = stateModel.getAdapterContext();
|
||||
if (adapterContext != null
|
||||
&& (Step.GENERATE_TOKEN_FINISH_THREE_DS.equals(adapterContext.getNextStep())
|
||||
|| Step.GENERATE_TOKEN_CAPTURE.equals(adapterContext.getNextStep())
|
||||
|| Step.GENERATE_TOKEN_REFUND.equals(adapterContext.getNextStep()))) {
|
||||
return adapterContext.getNextStep();
|
||||
}
|
||||
return Step.AUTH_RECURRENT;
|
||||
}
|
||||
|
||||
private static boolean isNextThreeDs(StateModel stateModel) {
|
||||
return stateModel.getAdapterContext() != null && stateModel.getAdapterContext().getNextStep() != null
|
||||
&& (Step.FINISH_THREE_DS.equals(stateModel.getAdapterContext().getNextStep())
|
||||
@ -53,9 +39,9 @@ public class DefaultStepResolverImpl implements StepResolver<StateModel, ExitSta
|
||||
}
|
||||
|
||||
@Override
|
||||
public Step resolveExit(ExitStateModel stateModel) {
|
||||
EntryStateModel entryStateModel = stateModel.getEntryStateModel();
|
||||
Step step = entryStateModel.getStateModel().getStep();
|
||||
public Step resolveExit(StateModel stateModel) {
|
||||
|
||||
Step step = stateModel.getStep();
|
||||
switch (step) {
|
||||
case AUTH_RECURRENT:
|
||||
if (Step.FINISH_THREE_DS.equals(stateModel.getNextStep())) {
|
||||
|
@ -1,14 +1,12 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.flow;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.EntryStateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.ExitStateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.StateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.Step;
|
||||
import com.rbkmoney.adapter.common.enums.Step;
|
||||
|
||||
public interface StepResolver<T extends StateModel, R extends ExitStateModel> {
|
||||
public interface StepResolver<T extends StateModel> {
|
||||
|
||||
Step resolveEntry(T stateModel);
|
||||
|
||||
Step resolveExit(R stateModel);
|
||||
Step resolveExit(T stateModel);
|
||||
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.flow;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.constants.TargetStatus;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.exception.UnknownTargetStatusException;
|
||||
import com.rbkmoney.damsel.domain.TargetInvoicePaymentStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TargetStatusResolver {
|
||||
|
||||
public TargetStatus resolve(TargetInvoicePaymentStatus target) {
|
||||
if (target != null) {
|
||||
if (target.isSetCaptured()) {
|
||||
return TargetStatus.CAPTURED;
|
||||
} else if (target.isSetProcessed()) {
|
||||
return TargetStatus.PROCESSED;
|
||||
} else if (target.isSetRefunded()) {
|
||||
return TargetStatus.REFUNDED;
|
||||
} else if (target.isSetCancelled()) {
|
||||
return TargetStatus.CANCELLED;
|
||||
}
|
||||
}
|
||||
throw new UnknownTargetStatusException();
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.handler;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.EntryStateModel;
|
||||
import org.apache.thrift.TException;
|
||||
|
||||
public interface CommonHandler<T, R, E extends EntryStateModel> {
|
||||
|
||||
boolean isHandler(final E entryStateModel);
|
||||
|
||||
T handle(E context) throws TException;
|
||||
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.handler;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.EntryStateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.ExitStateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.processor.Processor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public abstract class CommonHandlerImpl<T extends ExitStateModel, P, R, E extends EntryStateModel> implements CommonHandler<T, R, E> {
|
||||
|
||||
private final Function<P, R> requestFunction;
|
||||
private final Converter<E, P> converter;
|
||||
private final Processor<T, E, R> processor;
|
||||
|
||||
@Override
|
||||
public T handle(E entryStateModel) {
|
||||
P request = converter.convert(entryStateModel);
|
||||
R response = requestFunction.apply(request);
|
||||
return processor.process(response, entryStateModel);
|
||||
}
|
||||
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.handler;
|
||||
|
||||
import com.rbkmoney.damsel.proxy_provider.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.thrift.TException;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.rbkmoney.java.damsel.utils.extractors.ProxyProviderPackageExtractors.*;
|
||||
import static com.rbkmoney.java.damsel.utils.verification.ProxyProviderVerification.isUndefinedResultOrUnavailable;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ServerHandlerLogDecorator implements ProviderProxySrv.Iface {
|
||||
|
||||
private final ProviderProxySrv.Iface handler;
|
||||
|
||||
@Override
|
||||
public RecurrentTokenProxyResult generateToken(RecurrentTokenContext context) throws TException {
|
||||
String recurrentId = extractRecurrentId(context);
|
||||
log.info("Generate token started with recurrentId {}", recurrentId);
|
||||
try {
|
||||
RecurrentTokenProxyResult proxyResult = handler.generateToken(context);
|
||||
log.info("Generate token finished {} with recurrentId {}", proxyResult, recurrentId);
|
||||
return proxyResult;
|
||||
} catch (Exception ex) {
|
||||
String message = "Failed handle generate token with recurrentId " + recurrentId;
|
||||
logMessage(ex, message);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecurrentTokenCallbackResult handleRecurrentTokenCallback(ByteBuffer byteBuffer, RecurrentTokenContext context) throws TException {
|
||||
String recurrentId = context.getTokenInfo().getPaymentTool().getId();
|
||||
log.info("handleRecurrentTokenCallback: start with recurrentId {}", recurrentId);
|
||||
RecurrentTokenCallbackResult result = handler.handleRecurrentTokenCallback(byteBuffer, context);
|
||||
log.info("handleRecurrentTokenCallback end {} with recurrentId {}", result, recurrentId);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaymentProxyResult processPayment(PaymentContext context) throws TException {
|
||||
String invoiceId = extractInvoiceId(context);
|
||||
String invoicePaymentStatus = extractTargetInvoicePaymentStatus(context);
|
||||
log.info("Process payment handle {} start with invoiceId {}", invoicePaymentStatus, invoiceId);
|
||||
try {
|
||||
PaymentProxyResult proxyResult = handler.processPayment(context);
|
||||
log.info("Process payment handle {} finished with invoiceId {} and proxyResult {}", invoicePaymentStatus, invoiceId, proxyResult);
|
||||
return proxyResult;
|
||||
} catch (Exception e) {
|
||||
String message = String.format("Failed handle %s process payment for operation with invoiceId %s", invoicePaymentStatus, invoiceId);
|
||||
logMessage(e, message);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaymentCallbackResult handlePaymentCallback(ByteBuffer byteBuffer, PaymentContext context) throws TException {
|
||||
String invoiceId = context.getPaymentInfo().getInvoice().getId();
|
||||
log.info("handlePaymentCallback start with invoiceId {}", invoiceId);
|
||||
PaymentCallbackResult result = handler.handlePaymentCallback(byteBuffer, context);
|
||||
log.info("handlePaymentCallback finish {} with invoiceId {}", result, invoiceId);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void logMessage(Exception ex, String message) {
|
||||
if (isUndefinedResultOrUnavailable(ex)) {
|
||||
log.warn(message, ex);
|
||||
} else {
|
||||
log.error(message, ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AdapterContext {
|
||||
|
||||
@JsonProperty(value = "max_date_time_polling")
|
||||
private Instant maxDateTimePolling;
|
||||
private Step nextStep;
|
||||
@JsonProperty(value = "pares")
|
||||
private String paRes;
|
||||
private String md;
|
||||
@JsonProperty(value = "trx_id")
|
||||
private String trxId;
|
||||
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Callback {
|
||||
|
||||
@JsonProperty(value = "MD")
|
||||
private String md;
|
||||
@JsonProperty(value = "PaRes")
|
||||
private String paRes;
|
||||
@JsonProperty(value = "termination_uri")
|
||||
private String termUrl;
|
||||
|
||||
}
|
@ -5,7 +5,7 @@ import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class EntryStateModel {
|
||||
public class GeneralEntryStateModel {
|
||||
|
||||
private OperationModel operationModel;
|
||||
private StateModel stateModel;
|
@ -1,5 +1,7 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.model;
|
||||
|
||||
import com.rbkmoney.adapter.common.enums.Step;
|
||||
import com.rbkmoney.adapter.common.model.AdapterContext;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -11,17 +13,14 @@ import java.util.Map;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ExitStateModel {
|
||||
public class GeneralExitStateModel {
|
||||
|
||||
private Step nextStep;
|
||||
private String errorCode;
|
||||
private String errorMessage;
|
||||
private AdapterContext adapterContext;
|
||||
private EntryStateModel entryStateModel;
|
||||
private String paReq;
|
||||
private String md;
|
||||
private String acsUrl;
|
||||
private String trxId;
|
||||
private GeneralEntryStateModel generalEntryStateModel;
|
||||
|
||||
private Map<String, String> trxExtra;
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class RecurrentContext {
|
||||
|
||||
private String recToken;
|
||||
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.model;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.constants.TargetStatus;
|
||||
import com.rbkmoney.adapter.common.enums.Step;
|
||||
import com.rbkmoney.adapter.common.enums.TargetStatus;
|
||||
import com.rbkmoney.adapter.common.model.AdapterContext;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@ -8,11 +10,12 @@ import lombok.Data;
|
||||
@Builder
|
||||
public class StateModel {
|
||||
|
||||
private String recToken;
|
||||
private TargetStatus targetStatus;
|
||||
private boolean makeRecurrent;
|
||||
private AdapterContext adapterContext;
|
||||
|
||||
private TargetStatus targetStatus;
|
||||
private Step step;
|
||||
private Step nextStep;
|
||||
|
||||
private String recToken;
|
||||
private boolean makeRecurrent;
|
||||
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.model;
|
||||
|
||||
public enum Step {
|
||||
|
||||
PRE_AUTH,
|
||||
AUTH,
|
||||
RECURRENT,
|
||||
AUTH_RECURRENT,
|
||||
CANCEL,
|
||||
CHECK_STATUS,
|
||||
FINISH_THREE_DS,
|
||||
GENERATE_TOKEN_FINISH_THREE_DS,
|
||||
GENERATE_TOKEN_CHECK_STATUS,
|
||||
GENERATE_TOKEN_CAPTURE,
|
||||
GENERATE_TOKEN_REFUND,
|
||||
GENERATE_TOKEN_FINISH,
|
||||
CAPTURE,
|
||||
REFUND
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.processor;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.EntryStateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.ExitStateModel;
|
||||
|
||||
public interface Processor<T extends ExitStateModel, E extends EntryStateModel, R> {
|
||||
|
||||
T process(R response, E context);
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.serializer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.AdapterContext;
|
||||
import com.rbkmoney.damsel.proxy_provider.PaymentContext;
|
||||
import com.rbkmoney.damsel.proxy_provider.RecurrentTokenContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class AdapterSerializer extends StateSerializer<AdapterContext> {
|
||||
|
||||
public AdapterSerializer(ObjectMapper mapper) {
|
||||
super(mapper);
|
||||
}
|
||||
|
||||
public AdapterContext read(byte[] data) {
|
||||
if (data == null) {
|
||||
return new AdapterContext();
|
||||
}
|
||||
try {
|
||||
return getMapper().readValue(data, AdapterContext.class);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public AdapterContext getAdapterContext(Object context) {
|
||||
AdapterContext adapterContext = new AdapterContext();
|
||||
byte[] state = getState(context);
|
||||
if (state != null && state.length > 0) {
|
||||
return this.read(state);
|
||||
}
|
||||
return adapterContext;
|
||||
}
|
||||
|
||||
public static byte[] getState(Object context) {
|
||||
if (context instanceof RecurrentTokenContext) {
|
||||
if (((RecurrentTokenContext) context).getSession() == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
return ((RecurrentTokenContext) context).getSession().getState();
|
||||
}
|
||||
return ((PaymentContext) context).getSession().getState();
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.serializer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.Callback;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class CallbackSerializer extends StateSerializer<Callback> {
|
||||
|
||||
public CallbackSerializer(ObjectMapper mapper) {
|
||||
super(mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback read(byte[] data) {
|
||||
if (data == null) {
|
||||
return new Callback();
|
||||
}
|
||||
try {
|
||||
return getMapper().readValue(data, Callback.class);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Callback read(HttpServletRequest request) {
|
||||
Map<String, String> stringMap = Optional.ofNullable(request.getParameterMap())
|
||||
.orElseGet(HashMap::new)
|
||||
.entrySet().stream()
|
||||
.collect(Collectors.toMap(k -> k.getKey().trim(),
|
||||
v -> v.getValue()[0]));
|
||||
return mapper.convertValue(stringMap, Callback.class);
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.serializer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.RecurrentContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class RecurrentContextSerializer extends StateSerializer<RecurrentContext> {
|
||||
|
||||
public RecurrentContextSerializer(ObjectMapper mapper) {
|
||||
super(mapper);
|
||||
}
|
||||
|
||||
public RecurrentContext read(byte[] data) {
|
||||
if (data == null) {
|
||||
return new RecurrentContext();
|
||||
}
|
||||
try {
|
||||
return getMapper().readValue(data, RecurrentContext.class);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.serializer;
|
||||
|
||||
public interface Serializer<TState> {
|
||||
|
||||
byte[] writeByte(Object obj);
|
||||
|
||||
String writeString(Object obj);
|
||||
|
||||
TState read(byte[] data);
|
||||
|
||||
TState read(String data);
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.serializer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
@Component
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
public abstract class StateSerializer<T> implements Serializer<T> {
|
||||
|
||||
protected final ObjectMapper mapper;
|
||||
|
||||
@Override
|
||||
public byte[] writeByte(Object obj) {
|
||||
try {
|
||||
return mapper.writeValueAsBytes(obj);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String writeString(Object obj) {
|
||||
try {
|
||||
return Base64.getEncoder().encodeToString(getMapper().writeValueAsBytes(obj));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(byte[] data) {
|
||||
throw new RuntimeException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(String data) {
|
||||
throw new RuntimeException("Not supported");
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.service;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.ExitStateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.GeneralExitStateModel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ThreeDsPropertiesService {
|
||||
|
||||
Map<String, String> initProperties(ExitStateModel exitStateModel);
|
||||
Map<String, String> initProperties(GeneralExitStateModel generalExitStateModel);
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.service;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.config.properties.AdapterProperties;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.constants.ThreeDsFields;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.ExitStateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.utils.RedirectUtils;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.GeneralExitStateModel;
|
||||
import com.rbkmoney.adapter.common.constants.ThreeDsFields;
|
||||
import com.rbkmoney.adapter.common.model.AdapterContext;
|
||||
import com.rbkmoney.adapter.common.properties.CommonAdapterProperties;
|
||||
import com.rbkmoney.adapter.common.utils.converter.RedirectUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -14,14 +15,18 @@ import java.util.Map;
|
||||
@RequiredArgsConstructor
|
||||
public class ThreeDsPropertiesServiceImpl implements ThreeDsPropertiesService {
|
||||
|
||||
private final AdapterProperties adapterProperties;
|
||||
private final CommonAdapterProperties adapterProperties;
|
||||
|
||||
@Override
|
||||
public Map<String, String> initProperties(ExitStateModel exitStateModel) {
|
||||
public Map<String, String> initProperties(GeneralExitStateModel generalExitStateModel) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put(ThreeDsFields.PA_REQ, exitStateModel.getPaReq());
|
||||
params.put(ThreeDsFields.MD, exitStateModel.getMd());
|
||||
params.put(ThreeDsFields.TERM_URL, RedirectUtils.getCallbackUrl(adapterProperties.getCallbackUrl(), adapterProperties.getPathCallbackUrl()));
|
||||
AdapterContext adapterContext = generalExitStateModel.getAdapterContext();
|
||||
params.put(ThreeDsFields.PA_REQ, adapterContext.getPaReq());
|
||||
params.put(ThreeDsFields.MD, adapterContext.getMd());
|
||||
params.put(ThreeDsFields.TERM_URL, RedirectUtils.getCallbackUrl(
|
||||
adapterProperties.getCallbackUrl(),
|
||||
adapterProperties.getPathCallbackUrl())
|
||||
);
|
||||
return params;
|
||||
}
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.utils;
|
||||
|
||||
import com.rbkmoney.damsel.cds.ExpDate;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CardDateConverter {
|
||||
|
||||
public static String getYearFromExpDate(ExpDate expDate) {
|
||||
return String.format("%1$02d", expDate.getYear() % 100);
|
||||
}
|
||||
|
||||
public static String getYearFromShort(short year) {
|
||||
return String.format("%1$02d", year % 100);
|
||||
}
|
||||
|
||||
public static String getMonthFromExpDate(ExpDate expDate) {
|
||||
return String.format("%02d", expDate.getMonth());
|
||||
}
|
||||
|
||||
public static String getMonthFromByte(byte month) {
|
||||
return String.format("%02d", month);
|
||||
}
|
||||
|
||||
public static BigDecimal getFormattedAmount(long amount) {
|
||||
return new BigDecimal(amount).movePointLeft(2);
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
@Slf4j
|
||||
public class RedirectUtils {
|
||||
|
||||
public static String getCallbackUrl(String callbackUrl, String path) {
|
||||
return UriComponentsBuilder.fromUriString(callbackUrl)
|
||||
.path(path)
|
||||
.build()
|
||||
.toUriString();
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.utils;
|
||||
|
||||
import com.rbkmoney.damsel.cds.SessionData;
|
||||
|
||||
public class SessionDataUtils {
|
||||
|
||||
public static String getCvv2(SessionData sessionData) {
|
||||
if (sessionData == null
|
||||
|| sessionData.getAuthData() == null
|
||||
|| !sessionData.getAuthData().isSetCardSecurityCode()) {
|
||||
return null;
|
||||
}
|
||||
return sessionData.getAuthData().getCardSecurityCode().getValue();
|
||||
}
|
||||
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.utils;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class SignGenerator {
|
||||
|
||||
public static String prepareDataForHmac(String[] fields, MultiValueMap<String, String> params) {
|
||||
StringBuilder dataHmac = new StringBuilder();
|
||||
Arrays.asList(fields)
|
||||
.forEach(field -> {
|
||||
if (params.get(field) != null
|
||||
&& !params.get(field).isEmpty()
|
||||
&& params.get(field).get(0) != null
|
||||
&& !params.get(field).get(0).isEmpty()
|
||||
) {
|
||||
dataHmac.append(params.get(field).get(0).length());
|
||||
dataHmac.append(params.get(field).get(0));
|
||||
} else {
|
||||
dataHmac.append("-");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return dataHmac.toString();
|
||||
}
|
||||
|
||||
public static String sign(String[] fieldsForSign, MultiValueMap<String, String> params, String key, String algorithm) {
|
||||
String dataHmac = prepareDataForHmac(fieldsForSign, params);
|
||||
String pSign = sign(dataHmac, key, algorithm);
|
||||
return pSign.toUpperCase();
|
||||
}
|
||||
|
||||
public static String sign(String data, String key, String algorithm) {
|
||||
try {
|
||||
byte[] decodedKey = Hex.decodeHex(key.toCharArray());
|
||||
SecretKeySpec keySpec = new SecretKeySpec(decodedKey, algorithm);
|
||||
Mac mac = Mac.getInstance(algorithm);
|
||||
mac.init(keySpec);
|
||||
|
||||
byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] signatureBytes = mac.doFinal(dataBytes);
|
||||
|
||||
return new String(new Hex().encode(signatureBytes));
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.validator;
|
||||
|
||||
public interface Validator<T> {
|
||||
|
||||
void validate(T request);
|
||||
|
||||
}
|
@ -1,12 +1,5 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.config.ErrorMappingConfiguration,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.config.properties.TimerProperties,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.config.properties.AdapterProperties,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.config.FilterConfiguration,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.flow.TargetStatusResolver,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.serializer.AdapterSerializer,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.serializer.CallbackSerializer,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.serializer.RecurrentContextSerializer,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.controller.AdapterController,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.service.ThreeDsPropertiesServiceImpl,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.flow.DefaultStepResolverImpl
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.config.AppConfig,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.config.SerializerConfig,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.controller.AdapterControllerDecorator,\
|
||||
com.rbkmoney.adapter.bank.spring.boot.starter.service.ThreeDsPropertiesServiceImpl
|
||||
|
@ -1,79 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.flow;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.constants.TargetStatus;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.EntryStateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.ExitStateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.StateModel;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.model.Step;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DefaultStepResolverImplTest {
|
||||
|
||||
private DefaultStepResolverImpl defaultStepResolver = new DefaultStepResolverImpl();
|
||||
|
||||
@Test
|
||||
public void resolveEntry() {
|
||||
StateModel stateModel = StateModel.builder()
|
||||
.targetStatus(TargetStatus.CANCELLED)
|
||||
.build();
|
||||
Step step = defaultStepResolver.resolveEntry(stateModel);
|
||||
Assert.assertEquals(Step.CANCEL, step);
|
||||
|
||||
stateModel.setTargetStatus(TargetStatus.CAPTURED);
|
||||
step = defaultStepResolver.resolveEntry(stateModel);
|
||||
Assert.assertEquals(Step.CAPTURE, step);
|
||||
|
||||
stateModel.setTargetStatus(TargetStatus.PROCESSED);
|
||||
step = defaultStepResolver.resolveEntry(stateModel);
|
||||
Assert.assertEquals(Step.AUTH, step);
|
||||
|
||||
stateModel.setTargetStatus(TargetStatus.AUTH_RECURRENT);
|
||||
step = defaultStepResolver.resolveEntry(stateModel);
|
||||
Assert.assertEquals(Step.AUTH_RECURRENT, step);
|
||||
|
||||
stateModel.setTargetStatus(TargetStatus.REFUNDED);
|
||||
step = defaultStepResolver.resolveEntry(stateModel);
|
||||
Assert.assertEquals(Step.REFUND, step);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveExit() {
|
||||
EntryStateModel entryStateModel = EntryStateModel.builder()
|
||||
.stateModel(StateModel.builder()
|
||||
.step(Step.AUTH)
|
||||
.build())
|
||||
.build();
|
||||
ExitStateModel exitStateModel = ExitStateModel.builder()
|
||||
.entryStateModel(entryStateModel)
|
||||
.nextStep(Step.FINISH_THREE_DS)
|
||||
.build();
|
||||
Step step = defaultStepResolver.resolveExit(exitStateModel);
|
||||
Assert.assertEquals(Step.FINISH_THREE_DS, step);
|
||||
|
||||
entryStateModel.setStateModel(StateModel.builder()
|
||||
.step(Step.AUTH_RECURRENT).build());
|
||||
step = defaultStepResolver.resolveExit(exitStateModel);
|
||||
Assert.assertEquals(Step.GENERATE_TOKEN_FINISH_THREE_DS, step);
|
||||
|
||||
exitStateModel.setNextStep(Step.GENERATE_TOKEN_CAPTURE);
|
||||
step = defaultStepResolver.resolveExit(exitStateModel);
|
||||
Assert.assertEquals(Step.GENERATE_TOKEN_CAPTURE, step);
|
||||
|
||||
entryStateModel.setStateModel(StateModel.builder()
|
||||
.step(Step.GENERATE_TOKEN_FINISH_THREE_DS).build());
|
||||
step = defaultStepResolver.resolveExit(exitStateModel);
|
||||
Assert.assertEquals(Step.GENERATE_TOKEN_CAPTURE, step);
|
||||
|
||||
entryStateModel.setStateModel(StateModel.builder()
|
||||
.step(Step.GENERATE_TOKEN_CAPTURE).build());
|
||||
step = defaultStepResolver.resolveExit(exitStateModel);
|
||||
Assert.assertEquals(Step.GENERATE_TOKEN_REFUND, step);
|
||||
|
||||
entryStateModel.setStateModel(StateModel.builder()
|
||||
.step(Step.GENERATE_TOKEN_REFUND).build());
|
||||
step = defaultStepResolver.resolveExit(exitStateModel);
|
||||
Assert.assertEquals(Step.GENERATE_TOKEN_FINISH, step);
|
||||
}
|
||||
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.flow;
|
||||
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.constants.TargetStatus;
|
||||
import com.rbkmoney.adapter.bank.spring.boot.starter.exception.UnknownTargetStatusException;
|
||||
import com.rbkmoney.damsel.domain.*;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TargetStatusResolverTest {
|
||||
|
||||
private TargetStatusResolver targetStatusResolver = new TargetStatusResolver();
|
||||
|
||||
@Test
|
||||
public void resolve() {
|
||||
TargetStatus resolve = targetStatusResolver.resolve(TargetInvoicePaymentStatus.cancelled(new InvoicePaymentCancelled()));
|
||||
Assert.assertEquals(TargetStatus.CANCELLED, resolve);
|
||||
|
||||
resolve = targetStatusResolver.resolve(TargetInvoicePaymentStatus.captured(new InvoicePaymentCaptured()));
|
||||
Assert.assertEquals(TargetStatus.CAPTURED, resolve);
|
||||
|
||||
resolve = targetStatusResolver.resolve(TargetInvoicePaymentStatus.processed(new InvoicePaymentProcessed()));
|
||||
Assert.assertEquals(TargetStatus.PROCESSED, resolve);
|
||||
|
||||
resolve = targetStatusResolver.resolve(TargetInvoicePaymentStatus.refunded(new InvoicePaymentRefunded()));
|
||||
Assert.assertEquals(TargetStatus.REFUNDED, resolve);
|
||||
}
|
||||
|
||||
@Test(expected = UnknownTargetStatusException.class)
|
||||
public void resolveException() {
|
||||
TargetStatus resolve = targetStatusResolver.resolve(null);
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.utils;
|
||||
|
||||
|
||||
import com.rbkmoney.adapter.common.utils.converter.CardDataUtils;
|
||||
import com.rbkmoney.damsel.cds.AuthData;
|
||||
import com.rbkmoney.damsel.cds.CardSecurityCode;
|
||||
import com.rbkmoney.damsel.cds.SessionData;
|
||||
@ -14,25 +14,25 @@ public class SessionDataUtilsTest {
|
||||
@Test
|
||||
public void getCvv2() {
|
||||
SessionData sessionData = new SessionData();
|
||||
String cvv2 = SessionDataUtils.getCvv2(sessionData);
|
||||
String cvv2 = CardDataUtils.getCvv2(sessionData);
|
||||
|
||||
Assert.assertNull(cvv2);
|
||||
|
||||
AuthData authData = new AuthData();
|
||||
sessionData.setAuthData(authData);
|
||||
cvv2 = SessionDataUtils.getCvv2(sessionData);
|
||||
cvv2 = CardDataUtils.getCvv2(sessionData);
|
||||
|
||||
Assert.assertNull(cvv2);
|
||||
|
||||
CardSecurityCode cardSecurityCode = new CardSecurityCode();
|
||||
authData.setCardSecurityCode(cardSecurityCode);
|
||||
cvv2 = SessionDataUtils.getCvv2(sessionData);
|
||||
cvv2 = CardDataUtils.getCvv2(sessionData);
|
||||
|
||||
Assert.assertNull(cvv2);
|
||||
|
||||
cardSecurityCode.setValue(CARD_SECURITY_CODE);
|
||||
|
||||
cvv2 = SessionDataUtils.getCvv2(sessionData);
|
||||
cvv2 = CardDataUtils.getCvv2(sessionData);
|
||||
|
||||
Assert.assertEquals(CARD_SECURITY_CODE, cvv2);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.rbkmoney.adapter.bank.spring.boot.starter.utils;
|
||||
|
||||
import com.rbkmoney.adapter.common.utils.encryption.HmacEncryption;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -7,13 +8,11 @@ import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class SignGeneratorTest {
|
||||
|
||||
public static final String HMAC_SHA_1 = "HmacSHA1";
|
||||
|
||||
@Test
|
||||
public void sign() throws NoSuchAlgorithmException {
|
||||
String test = "511.483USD677144616IT Books. Qty: 217Books Online Inc.14www.sample.com1512345678901234589999999919pgw@mail.sample.com11--142003010515302116F2B2DD7E603A7ADA33https://www.sample.com/shop/reply";
|
||||
|
||||
String s = SignGenerator.sign(test, "00112233445566778899AABBCCDDEEFF", HMAC_SHA_1);
|
||||
String s = HmacEncryption.calculateHMacSha1(test, "00112233445566778899AABBCCDDEEFF");
|
||||
Assert.assertEquals("FACC882CA67E109E409E3974DDEDA8AAB13A5E48", s.toUpperCase());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user