commit
f35a92b7fa
@ -0,0 +1,20 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.auth.domain.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ShopifyCommonParameter {
|
||||||
|
private String shop;
|
||||||
|
private String code;
|
||||||
|
private String state;
|
||||||
|
private String hmac;
|
||||||
|
private String host;
|
||||||
|
private String timestamp;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.auth.domain.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||||
|
public class ShopifyRequestVerifyException extends RuntimeException{
|
||||||
|
public ShopifyRequestVerifyException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.auth.domain.service;
|
||||||
|
|
||||||
|
import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.support.HmacVerificationUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ShopifyRequestValidator {
|
||||||
|
|
||||||
|
@Value("${shopify.auth.apiSecretKey}")
|
||||||
|
private String clientSecret;
|
||||||
|
|
||||||
|
public Boolean valid(ShopifyCommonParameter parameter) {
|
||||||
|
StringBuilder message =new StringBuilder();
|
||||||
|
message.append("code=").append(parameter.getCode())
|
||||||
|
.append("&host=").append(parameter.getHost())
|
||||||
|
.append("&shop=").append(parameter.getShop())
|
||||||
|
.append("&state=").append(parameter.getState())
|
||||||
|
.append("×tamp=").append(parameter.getTimestamp());
|
||||||
|
return HmacVerificationUtil.hmacSHA256(message.toString(),clientSecret,parameter.getHmac());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean verifyPermission(String shopifyStoreHost, String hmac, String timestamp) {
|
||||||
|
StringBuilder message =new StringBuilder();
|
||||||
|
message.append("shop=").append(shopifyStoreHost)
|
||||||
|
.append("×tamp=").append(timestamp);
|
||||||
|
return HmacVerificationUtil.hmacSHA256(message.toString(),clientSecret,hmac);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean verify(String message, String hmac) {
|
||||||
|
return HmacVerificationUtil.hmacSHA256(message,clientSecret,hmac);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.auth.web;
|
||||||
|
|
||||||
|
import au.com.royalpay.payment.manage.shopify.auth.domain.application.ShopifyMerchantAuthApplication;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyPermissionURL;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.auth.domain.exception.ShopifyRequestVerifyException;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.auth.domain.service.ShopifyRequestValidator;
|
||||||
|
import au.com.royalpay.payment.tools.env.PlatformEnvironment;
|
||||||
|
import au.com.royalpay.payment.tools.exceptions.BadRequestException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.servlet.view.RedirectView;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping(value = "/shopify")
|
||||||
|
public class ShopifyAuthTemplateController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ShopifyMerchantAuthApplication shopifyMerchantAuthApplication;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ShopifyRequestValidator shopifyRequestValidator;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private StringRedisTemplate stringRedisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shopify店铺安装入口
|
||||||
|
*
|
||||||
|
* @param shop
|
||||||
|
* @param hmac
|
||||||
|
* @param timestamp
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("/auth")
|
||||||
|
public String shopifyStorePermission(@RequestParam("shop") String shop,
|
||||||
|
@RequestParam("hmac") String hmac,
|
||||||
|
@RequestParam("timestamp") String timestamp,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
if (!Pattern.matches("^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", shop)) {
|
||||||
|
throw new BadRequestException("Parameter shop is invalid.");
|
||||||
|
}
|
||||||
|
if (!shopifyRequestValidator.verifyPermission(shop, hmac, timestamp)) {
|
||||||
|
throw new ShopifyRequestVerifyException("This request parameters is invalid");
|
||||||
|
}
|
||||||
|
ShopifyPermissionURL shopifyPermissionURL = shopifyMerchantAuthApplication.getShopifyPermissionUrl(shop);
|
||||||
|
response.setHeader("content-security-policy", "frame-ancestors https://" + shop + ".myshopify.com https://admin.shopify.com");
|
||||||
|
return "redirect:" + shopifyPermissionURL.getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shopify店铺授权后回调URL
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
* @param hmac
|
||||||
|
* @param host
|
||||||
|
* @param state
|
||||||
|
* @param shop
|
||||||
|
* @param timestamp
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("/auth/back")
|
||||||
|
public RedirectView shopifyStoreAuthRedirect(@RequestParam("code") String code,
|
||||||
|
@RequestParam("hmac") String hmac,
|
||||||
|
@RequestParam("host") String host,
|
||||||
|
@RequestParam("state") String state,
|
||||||
|
@RequestParam("shop") String shop,
|
||||||
|
@RequestParam("timestamp") String timestamp,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
|
||||||
|
if (!Pattern.matches("^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", shop)) {
|
||||||
|
throw new ShopifyRequestVerifyException("Parameter shop is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String preState = stringRedisTemplate.boundValueOps("shopifyAuthState:" + shop).get();
|
||||||
|
if (!state.equals(preState)) {
|
||||||
|
throw new ShopifyRequestVerifyException("This request parameters is invalid");
|
||||||
|
}
|
||||||
|
stringRedisTemplate.delete("shopifyAuthState:" + shop);
|
||||||
|
ShopifyCommonParameter shopifyCommonParameter = ShopifyCommonParameter.builder()
|
||||||
|
.code(code)
|
||||||
|
.hmac(hmac)
|
||||||
|
.host(host)
|
||||||
|
.state(state)
|
||||||
|
.shop(shop)
|
||||||
|
.timestamp(timestamp)
|
||||||
|
.build();
|
||||||
|
if (!shopifyRequestValidator.valid(shopifyCommonParameter)) {
|
||||||
|
throw new ShopifyRequestVerifyException("This request parameters is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
String redirectUri = PlatformEnvironment.getEnv().concatUrl("/auth.html#/shopify/login?code=" + code + "&hmac=" + hmac + "&host=" + host + "&state=" + state + "&shop=" + shop + "×tamp=" + timestamp);
|
||||||
|
response.setHeader("content-security-policy", "frame-ancestors https://" + shop + ".myshopify.com https://admin.shopify.com");
|
||||||
|
return new RedirectView(redirectUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.auth.web.command;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Pattern;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ShopifyVerifyRequest {
|
||||||
|
|
||||||
|
@NotBlank(message = "Code can not blank")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@NotBlank(message = "hmac can not blank")
|
||||||
|
private String hmac;
|
||||||
|
|
||||||
|
@NotBlank(message = "host can not blank")
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@NotBlank(message = "Shop can not blank")
|
||||||
|
@Pattern(regexp = "^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", message = "Shop hostname is invalid")
|
||||||
|
private String shop;
|
||||||
|
|
||||||
|
@NotBlank(message = "state can not blank")
|
||||||
|
private String state;
|
||||||
|
|
||||||
|
@NotBlank(message = "timestamp can not blank")
|
||||||
|
private String timestamp;
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.hooks;
|
||||||
|
|
||||||
|
import au.com.royalpay.payment.manage.shopify.auth.domain.exception.ShopifyRequestVerifyException;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.auth.domain.service.ShopifyRequestValidator;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.hooks.command.ShopifyCustomerRedactCommand;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.hooks.command.ShopifyCustomerRequestCommand;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.hooks.command.ShopifyShopRedactCommand;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.entity.ShopifyStore;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.service.ShopifyStoreService;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.support.ShopifyHttpUtils;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value = "/shopify")
|
||||||
|
public class ShopifyWebhooksController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ShopifyStoreService shopifyStoreService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ShopifyRequestValidator shopifyRequestValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推送顾客信息查询请求
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PostMapping("/customer/request")
|
||||||
|
public void customerRequest(@RequestHeader("X-Shopify-Hmac-SHA256") String hmac,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
String requestBody = ShopifyHttpUtils.getRequestBody(request);
|
||||||
|
if (!shopifyRequestValidator.verify(requestBody, hmac)) {
|
||||||
|
throw new ShopifyRequestVerifyException("Unauthorized");
|
||||||
|
}
|
||||||
|
ShopifyCustomerRequestCommand shopifyCustomerRequestCommand = JSONObject.parseObject(requestBody, ShopifyCustomerRequestCommand.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 擦除顾客信息消息通知
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PostMapping("/customer/erasure")
|
||||||
|
public void customerRedact(@RequestHeader("X-Shopify-Hmac-SHA256") String hmac,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
String requestBody = ShopifyHttpUtils.getRequestBody(request);
|
||||||
|
if (!shopifyRequestValidator.verify(requestBody, hmac)) {
|
||||||
|
throw new ShopifyRequestVerifyException("Unauthorized");
|
||||||
|
}
|
||||||
|
ShopifyCustomerRedactCommand shopifyCustomerRedactCommand = JSONObject.parseObject(requestBody, ShopifyCustomerRedactCommand.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shopify店铺卸载payment app事件
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PostMapping("/shop/erasure")
|
||||||
|
public void shopRedact(@RequestHeader("X-Shopify-Hmac-SHA256") String hmac,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
String requestBody = ShopifyHttpUtils.getRequestBody(request);
|
||||||
|
if (!shopifyRequestValidator.verify(requestBody, hmac)) {
|
||||||
|
throw new ShopifyRequestVerifyException("Unauthorized");
|
||||||
|
}
|
||||||
|
ShopifyShopRedactCommand shopifyShopRedactCommand = JSONObject.parseObject(requestBody, ShopifyShopRedactCommand.class);
|
||||||
|
ShopifyStore shopifyShop = shopifyStoreService.getByShopifyShop(shopifyShopRedactCommand.getShop_domain());
|
||||||
|
if (shopifyShop == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
shopifyStoreService.modifyShopifyStore(shopifyShop.setStatus(0));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.hooks.command;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ShopifyCustomer {
|
||||||
|
private String id;
|
||||||
|
private String email;
|
||||||
|
private String phone;
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.hooks.command;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ShopifyCustomerRedactCommand {
|
||||||
|
private String shop_id;
|
||||||
|
private String shop_domain;
|
||||||
|
private ShopifyCustomer customer;
|
||||||
|
private List<Long> orders_to_redact;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.hooks.command;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ShopifyCustomerRequestCommand {
|
||||||
|
private String shop_id;
|
||||||
|
private String shop_domain;
|
||||||
|
private List<Long> orders_requested;
|
||||||
|
private ShopifyCustomer customer;
|
||||||
|
private DataRequest data_request;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DataRequest{
|
||||||
|
private String id;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.hooks.command;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ShopifyShopRedactCommand {
|
||||||
|
private String shop_id;
|
||||||
|
private String shop_domain;
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.store.domain.entity;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class ShopifyMerchantApplyInfo {
|
||||||
|
|
||||||
|
private int clientId;
|
||||||
|
|
||||||
|
private String clientMoniker;
|
||||||
|
|
||||||
|
private String shopifyShop;
|
||||||
|
|
||||||
|
private String contactPerson;
|
||||||
|
|
||||||
|
private String contactPhone;
|
||||||
|
|
||||||
|
private String contactEmail;
|
||||||
|
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
private String companyName;
|
||||||
|
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
private String suburb;
|
||||||
|
|
||||||
|
private String postcode;
|
||||||
|
|
||||||
|
private String state;
|
||||||
|
|
||||||
|
private String country;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.store.domain.event;
|
||||||
|
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.application.ShopifyStoreApplication;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.entity.MerchantAccountRequest;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.entity.SimpleMerchant;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
public class ShopifyStoreCreatedEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
private SimpleMerchant simpleMerchant;
|
||||||
|
|
||||||
|
private CreateShopifyMerchantCommand command;
|
||||||
|
|
||||||
|
private MerchantAccountRequest accountRequest;
|
||||||
|
|
||||||
|
public ShopifyStoreCreatedEvent(ShopifyStoreApplication source, SimpleMerchant simpleMerchant, CreateShopifyMerchantCommand command, MerchantAccountRequest accountRequest) {
|
||||||
|
super(source);
|
||||||
|
this.simpleMerchant = simpleMerchant;
|
||||||
|
this.command = command;
|
||||||
|
this.accountRequest = accountRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleMerchant getSimpleMerchant() {
|
||||||
|
return simpleMerchant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateShopifyMerchantCommand getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MerchantAccountRequest getAccountRequest() {
|
||||||
|
return accountRequest;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.store.domain.listener;
|
||||||
|
|
||||||
|
import au.com.royalpay.payment.manage.notice.core.MailService;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.entity.ShopifyMerchantApplyInfo;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.event.ShopifyStoreCreatedEvent;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentMerchantCommand;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.thymeleaf.context.Context;
|
||||||
|
import org.thymeleaf.spring5.SpringTemplateEngine;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class ShopifyStoreCreatedListener {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MailService mailService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SpringTemplateEngine thymeleaf;
|
||||||
|
|
||||||
|
private static final String consignee = "info@royalpay.com.au";
|
||||||
|
|
||||||
|
@Async
|
||||||
|
@EventListener
|
||||||
|
public void onShopifyStoreCreated(ShopifyStoreCreatedEvent event) {
|
||||||
|
PaymentMerchantCommand paymentMerchant = event.getCommand().getPaymentMerchant();
|
||||||
|
ShopifyMerchantApplyInfo applyInfo = ShopifyMerchantApplyInfo.builder()
|
||||||
|
.clientId(event.getSimpleMerchant().getClientId())
|
||||||
|
.clientMoniker(event.getSimpleMerchant().getClientMoniker())
|
||||||
|
.contactEmail(event.getAccountRequest().getContactEmail())
|
||||||
|
.contactPhone(event.getAccountRequest().getContactPhone())
|
||||||
|
.contactPerson(paymentMerchant.getContactPerson())
|
||||||
|
.address(paymentMerchant.getAddress())
|
||||||
|
.shopifyShop(event.getCommand().getShopifyShop())
|
||||||
|
.displayName(event.getAccountRequest().getDisplayName())
|
||||||
|
.companyName(paymentMerchant.getCompanyName())
|
||||||
|
.suburb(paymentMerchant.getSuburb())
|
||||||
|
.state(paymentMerchant.getState())
|
||||||
|
.country(paymentMerchant.getCountry())
|
||||||
|
.postcode(paymentMerchant.getPostcode())
|
||||||
|
.build();
|
||||||
|
Context ctx = new Context();
|
||||||
|
ctx.setVariable("applyInfo", applyInfo);
|
||||||
|
|
||||||
|
final String content = thymeleaf.process("mail/shopify_merchant_application.html", ctx);
|
||||||
|
try {
|
||||||
|
mailService.sendEmail("Shopify merchant application", consignee, "", content);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.support;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.HmacAlgorithms;
|
||||||
|
import org.apache.commons.codec.digest.HmacUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.bouncycastle.crypto.RuntimeCryptoException;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class HmacVerificationUtil {
|
||||||
|
|
||||||
|
public static boolean checkParameters(String message, String secret, String hmac) {
|
||||||
|
try {
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
SecretKey secretKey = new SecretKeySpec(secret.getBytes("UTF8"), "HmacSHA256");
|
||||||
|
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
|
||||||
|
mac.init(secretKey);
|
||||||
|
byte[] digest = mac.doFinal(message.getBytes("UTF-8"));
|
||||||
|
String marshal = new HexBinaryAdapter().marshal(digest).toLowerCase(Locale.ROOT);
|
||||||
|
return StringUtils.equals(marshal, hmac);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeCryptoException("加密异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hmacSHA256(String input, String key, String hmac) {
|
||||||
|
String encode = encode(input, key, HmacAlgorithms.HMAC_SHA_256);
|
||||||
|
return StringUtils.equals(encode, hmac);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String encode(String input, String key, HmacAlgorithms algorithm) {
|
||||||
|
Mac mac = HmacUtils.getInitializedMac(algorithm, key.getBytes(StandardCharsets.UTF_8));
|
||||||
|
byte[] content = input.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] signResult = mac.doFinal(content);
|
||||||
|
return bytesToHex(signResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String bytesToHex(byte[] hash) {
|
||||||
|
StringBuilder hexString = new StringBuilder();
|
||||||
|
for (byte b : hash) {
|
||||||
|
String hex = Integer.toHexString(0xff & b);
|
||||||
|
if (hex.length() == 1) {
|
||||||
|
hexString.append('0');
|
||||||
|
}
|
||||||
|
hexString.append(hex);
|
||||||
|
}
|
||||||
|
return hexString.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.support;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class ShopifyHttpUtils {
|
||||||
|
|
||||||
|
public static String getRequestBody(HttpServletRequest request) {
|
||||||
|
BufferedReader br = null;
|
||||||
|
StringBuilder sb = new StringBuilder("");
|
||||||
|
try {
|
||||||
|
br = request.getReader();
|
||||||
|
String str;
|
||||||
|
while ((str = br.readLine()) != null) {
|
||||||
|
sb.append(str);
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (null != br) {
|
||||||
|
try {
|
||||||
|
br.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 499 KiB After Width: | Height: | Size: 895 KiB |
@ -0,0 +1,46 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.auth.domain.service;
|
||||||
|
|
||||||
|
import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@ActiveProfiles({"dev", "alipay", "bestpay", "jd", "wechat", "rpay", "yeepay", "rppaysvc", "common", "alipayplusaps"})
|
||||||
|
class ShopifyRequestValidatorTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ShopifyRequestValidator shopifyRequestValidator;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shopifyRequestValidatorTest() {
|
||||||
|
ShopifyCommonParameter parameter = ShopifyCommonParameter.builder()
|
||||||
|
.code("4618ddc9da54cee7be06b35f49c72349")
|
||||||
|
.host("Z2Vlay10ZXN0LXNob3AubXlzaG9waWZ5LmNvbS9hZG1pbg")
|
||||||
|
.shop("geek-test-shop.myshopify.com")
|
||||||
|
.timestamp("1643097047")
|
||||||
|
.state("1643097021")
|
||||||
|
.hmac("e7884f623057afd700b27ba8a5b7529a3f2a2943d2931d73fb82c57f2cf0baaa")
|
||||||
|
.build();
|
||||||
|
Boolean valid = shopifyRequestValidator.valid(parameter);
|
||||||
|
log.warn(String.format("---------------------result: [%s]-------------",valid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShopifyDomain() {
|
||||||
|
String shop = "exampleshop.myshopify.com";
|
||||||
|
|
||||||
|
boolean matches = Pattern.matches("^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", shop);
|
||||||
|
|
||||||
|
log.warn(String.format("---------------------matches: [%s]-------------",matches));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package au.com.royalpay.payment.manage.shopify.store.domain.listener;
|
||||||
|
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.application.ShopifyStoreApplication;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.entity.MerchantAccountRequest;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.entity.SimpleMerchant;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.domain.event.ShopifyStoreCreatedEvent;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentAccountCommand;
|
||||||
|
import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentMerchantCommand;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@ActiveProfiles({"dev", "alipay", "bestpay", "jd", "wechat", "rpay", "yeepay", "rppaysvc", "common", "alipayplusaps"})
|
||||||
|
class ShopifyStoreCreatedListenerTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ShopifyStoreCreatedListener shopifyStoreCreatedListener;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shopifyStoreRegisterTest() {
|
||||||
|
|
||||||
|
SimpleMerchant simpleMerchant = SimpleMerchant.builder().clientId(00001).clientMoniker("test").build();
|
||||||
|
PaymentMerchantCommand paymentMerchantCommand = new PaymentMerchantCommand()
|
||||||
|
.setCompanyName("test company ltd")
|
||||||
|
.setAddress("test address")
|
||||||
|
.setSuburb("test suburb")
|
||||||
|
.setState("test state")
|
||||||
|
.setCountry("test country")
|
||||||
|
.setContactPerson("test contact person")
|
||||||
|
.setContactPhone("test contact phone")
|
||||||
|
.setContactEmail("test contact email");
|
||||||
|
|
||||||
|
PaymentAccountCommand paymentAccountCommand = new PaymentAccountCommand()
|
||||||
|
.setLoginId("test login id")
|
||||||
|
.setPassword("test password")
|
||||||
|
.setConfirmPassword("test confirm password");
|
||||||
|
|
||||||
|
CreateShopifyMerchantCommand command = new CreateShopifyMerchantCommand().setShopifyShop("test.myshop.com").setPaymentMerchant(paymentMerchantCommand).setPaymentAccount(paymentAccountCommand);
|
||||||
|
ShopifyStoreCreatedEvent event = new ShopifyStoreCreatedEvent(new ShopifyStoreApplication(), simpleMerchant, command, MerchantAccountRequest.instanceOf(command, simpleMerchant));
|
||||||
|
|
||||||
|
shopifyStoreCreatedListener.onShopifyStoreCreated(event);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue