From c80b502e6251d5de374880cab0ad2ae17a52b1a5 Mon Sep 17 00:00:00 2001 From: Yixian Date: Thu, 20 Jan 2022 12:59:16 +0800 Subject: [PATCH 01/10] 2.4.5: replace aps board --- .../mappers/system/ClientRateMapper.xml | 20 ++++++++---------- .../ui/static/images/aggretage_aps_board.jpg | Bin 511363 -> 310711 bytes 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientRateMapper.xml b/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientRateMapper.xml index 4c713885d..cff095259 100644 --- a/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientRateMapper.xml +++ b/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientRateMapper.xml @@ -151,17 +151,15 @@ +
- +
-
- -

Example: geek-test-shop.myshopify.com

-
- +

{{resError}}

+
+ + Not a RoyalPay merchant yet, please register + diff --git a/src/main/ui/static/shopify/auth/templates/shopify_register.html b/src/main/ui/static/shopify/auth/templates/shopify_register.html index 8fcb9bd8d..5d73c2931 100644 --- a/src/main/ui/static/shopify/auth/templates/shopify_register.html +++ b/src/main/ui/static/shopify/auth/templates/shopify_register.html @@ -53,7 +53,7 @@ -
@@ -62,7 +62,7 @@ ng-if="partnerForm.shopifyShop.$dirty">

Required Field

- + -->
diff --git a/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplicationTest.java b/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplicationTest.java index 800559bf8..7751c2fd0 100644 --- a/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplicationTest.java +++ b/src/test/java/au/com/royalpay/payment/manage/shopify/store/domain/application/ShopifyStoreApplicationTest.java @@ -1,5 +1,6 @@ package au.com.royalpay.payment.manage.shopify.store.domain.application; +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyAccessToken; import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyPermissionURL; import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand; import au.com.royalpay.payment.manage.shopify.store.web.command.PaymentAccountCommand; @@ -46,7 +47,7 @@ class ShopifyStoreApplicationTest { .setPaymentAccount(accountCommand) .setShopifyShop("demo.myshopify.com"); - ShopifyPermissionURL shopifyPermissionURL = shopifyStoreApplication.register(command); - log.warn(JSON.toJSONString(shopifyPermissionURL)); + ShopifyAccessToken shopifyAccessToken = shopifyStoreApplication.register(command); + log.warn(JSON.toJSONString(shopifyAccessToken)); } } \ No newline at end of file From 296fafef7457686840567273c0f3624484829df5 Mon Sep 17 00:00:00 2001 From: ycfxx Date: Tue, 25 Jan 2022 18:49:36 +0800 Subject: [PATCH 06/10] add shopify request verify --- pom.xml | 6 ++ .../domain/ShopifyRequestVerifyException.java | 7 +++ .../domain/entity/ShopifyCommonParameter.java | 20 +++++++ .../domain/service/ShopifyAuthService.java | 2 +- .../service/ShopifyRequestValidator.java | 30 ++++++++++ .../auth/web/ShopifyAuthController.java | 24 ++++++++ .../web/ShopifyAuthTemplateController.java | 10 +++- .../web/command/ShopifyPermissionRequest.java | 38 ++++++++++-- .../web/command/ShopifyVerifyRequest.java | 41 +++++++++++++ .../command/CreateShopifyMerchantCommand.java | 18 +++++- .../shopify/support/HmacVerificationUtil.java | 58 +++++++++++++++++++ .../ui/static/shopify/auth/shopify.auth.js | 44 ++++++++++++-- .../service/ShopifyRequestValidatorTest.java | 46 +++++++++++++++ 13 files changed, 330 insertions(+), 14 deletions(-) create mode 100644 src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/ShopifyRequestVerifyException.java create mode 100644 src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/entity/ShopifyCommonParameter.java create mode 100644 src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java create mode 100644 src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java create mode 100644 src/main/java/au/com/royalpay/payment/manage/shopify/support/HmacVerificationUtil.java create mode 100644 src/test/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidatorTest.java diff --git a/pom.xml b/pom.xml index 166d20fcd..d85aa06be 100644 --- a/pom.xml +++ b/pom.xml @@ -237,6 +237,12 @@ spring-boot-starter-webflux + + commons-codec + commons-codec + 1.12 + + diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/ShopifyRequestVerifyException.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/ShopifyRequestVerifyException.java new file mode 100644 index 000000000..c72e75060 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/ShopifyRequestVerifyException.java @@ -0,0 +1,7 @@ +package au.com.royalpay.payment.manage.shopify.auth.domain; + +public class ShopifyRequestVerifyException extends RuntimeException{ + public ShopifyRequestVerifyException(String message) { + super(message); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/entity/ShopifyCommonParameter.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/entity/ShopifyCommonParameter.java new file mode 100644 index 000000000..c5f56f2d0 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/entity/ShopifyCommonParameter.java @@ -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; + +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java index 111839af2..751f33fed 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java @@ -39,7 +39,7 @@ public class ShopifyAuthService { private RestTemplate restTemplate; public ShopifyPermissionURL shopifyPermission(String shopifyStoreHost, String hmac, String timestamp) { - String redirectUri = PlatformEnvironment.getEnv().concatUrl("/auth.html#/shopify/login"); + String redirectUri = PlatformEnvironment.getEnv().concatUrl("/auth.html"); String permissionUrl = String.format(PERMISSION_URL, shopifyStoreHost, clientId, scope, redirectUri, String.valueOf(new Date().getTime()).substring(0,10)); return ShopifyPermissionURL.builder().url(permissionUrl).build(); } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java new file mode 100644 index 000000000..b3b6ec49f --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java @@ -0,0 +1,30 @@ +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); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java index 3e4183838..8c4a4e117 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java @@ -1,8 +1,12 @@ package au.com.royalpay.payment.manage.shopify.auth.web; +import au.com.royalpay.payment.manage.shopify.auth.domain.ShopifyRequestVerifyException; import au.com.royalpay.payment.manage.shopify.auth.domain.application.ShopifyMerchantAuthApplication; import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyAccessToken; +import au.com.royalpay.payment.manage.shopify.auth.domain.service.ShopifyRequestValidator; import au.com.royalpay.payment.manage.shopify.auth.web.command.ShopifyPermissionRequest; +import au.com.royalpay.payment.manage.shopify.auth.web.command.ShopifyVerifyRequest; +import com.alibaba.fastjson.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -21,6 +25,23 @@ public class ShopifyAuthController { @Autowired private ShopifyMerchantAuthApplication shopifyMerchantAuthApplication; + @Autowired + private ShopifyRequestValidator shopifyRequestValidator; + + /** + * 校验shopify请求 + * + * @param request + * @return + */ + @PostMapping("/verify") + public JSONObject verifyRequest(@RequestBody @Valid ShopifyVerifyRequest request) { + if (!shopifyRequestValidator.valid(request.build())) { + throw new ShopifyRequestVerifyException("This request parameters is invalid"); + } + return new JSONObject(); + } + /** * 获取shopify店铺授权URL * @@ -29,6 +50,9 @@ public class ShopifyAuthController { */ @PostMapping("/install") public ShopifyAccessToken shopifyPermission(@RequestBody @Valid ShopifyPermissionRequest request) { + if (!shopifyRequestValidator.valid(request.build())) { + throw new ShopifyRequestVerifyException("This request parameters is invalid"); + } ShopifyAccessToken shopifyAccessToken = shopifyMerchantAuthApplication.install(request); return shopifyAccessToken; } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java index 11a36c17e..b94a92bd9 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java @@ -1,7 +1,9 @@ package au.com.royalpay.payment.manage.shopify.auth.web; +import au.com.royalpay.payment.manage.shopify.auth.domain.ShopifyRequestVerifyException; import au.com.royalpay.payment.manage.shopify.auth.domain.application.ShopifyMerchantAuthApplication; import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyPermissionURL; +import au.com.royalpay.payment.manage.shopify.auth.domain.service.ShopifyRequestValidator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -16,6 +18,9 @@ public class ShopifyAuthTemplateController { @Autowired private ShopifyMerchantAuthApplication shopifyMerchantAuthApplication; + @Autowired + private ShopifyRequestValidator shopifyRequestValidator; + /** * shopify店铺安装入口 * @@ -25,9 +30,12 @@ public class ShopifyAuthTemplateController { * @return */ @GetMapping("/auth") - public RedirectView shopifyStoreInstall(@RequestParam("shop") String shopifyStoreHost, + public RedirectView shopifyStorePermission(@RequestParam("shop") String shopifyStoreHost, @RequestParam("hmac") String hmac, @RequestParam("timestamp") String timestamp) { + if (!shopifyRequestValidator.verifyPermission(shopifyStoreHost, hmac, timestamp)) { + throw new ShopifyRequestVerifyException("This request parameters is invalid"); + } ShopifyPermissionURL shopifyPermissionURL = shopifyMerchantAuthApplication.getShopifyPermissionUrl(shopifyStoreHost, hmac, timestamp); return new RedirectView(shopifyPermissionURL.getUrl()); } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java index fc5cab5f6..d2190a921 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java @@ -1,5 +1,6 @@ package au.com.royalpay.payment.manage.shopify.auth.web.command; +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter; import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand; import lombok.AllArgsConstructor; import lombok.Builder; @@ -7,6 +8,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; @Data @Builder @@ -14,9 +16,6 @@ import javax.validation.constraints.NotBlank; @AllArgsConstructor public class ShopifyPermissionRequest { - @NotBlank(message = "Shop can not blank") - private String shop; - @NotBlank(message = "Login Id can not blank") private String loginId; @@ -26,12 +25,43 @@ public class ShopifyPermissionRequest { @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; + public static ShopifyPermissionRequest instanceOf(CreateShopifyMerchantCommand command) { return ShopifyPermissionRequest.builder() .loginId(command.getPaymentAccount().getLoginId()) .password(command.getPaymentAccount().getPassword()) - .shop(command.getShopifyShop()) .code(command.getCode()) + .hmac(command.getHmac()) + .host(command.getHost()) + .shop(command.getShopifyShop()) + .state(command.getState()) + .timestamp(command.getTimestamp()) + .build(); + } + + public ShopifyCommonParameter build() { + return ShopifyCommonParameter.builder() + .code(code) + .hmac(hmac) + .host(host) + .shop(shop) + .state(state) + .timestamp(timestamp) .build(); } } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java new file mode 100644 index 000000000..76a89f34d --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java @@ -0,0 +1,41 @@ +package au.com.royalpay.payment.manage.shopify.auth.web.command; + +import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter; +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; + + public ShopifyCommonParameter build() { + return ShopifyCommonParameter.builder() + .code(code) + .hmac(hmac) + .host(host) + .shop(shop) + .state(state) + .timestamp(timestamp) + .build(); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java index 35337757c..eb29b9431 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java @@ -4,6 +4,7 @@ import lombok.Data; import lombok.experimental.Accessors; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; @Data @Accessors(chain = true) @@ -13,9 +14,22 @@ public class CreateShopifyMerchantCommand { private PaymentAccountCommand paymentAccount; + @NotBlank(message = "Auth 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 shopifyShop; - @NotBlank(message = "Auth code can not blank") - private String code; + @NotBlank(message = "state can not blank") + private String state; + + @NotBlank(message = "timestamp can not blank") + private String timestamp; } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/support/HmacVerificationUtil.java b/src/main/java/au/com/royalpay/payment/manage/shopify/support/HmacVerificationUtil.java new file mode 100644 index 000000000..5ba85aac0 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/support/HmacVerificationUtil.java @@ -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(); + } + + +} diff --git a/src/main/ui/static/shopify/auth/shopify.auth.js b/src/main/ui/static/shopify/auth/shopify.auth.js index d344747c1..a2e317838 100644 --- a/src/main/ui/static/shopify/auth/shopify.auth.js +++ b/src/main/ui/static/shopify/auth/shopify.auth.js @@ -35,7 +35,7 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { }).state('shopify.register', { url: '/register', templateUrl: '/static/shopify/auth/templates/shopify_register.html', - params: {'shop': null, 'code': null}, + params: {'code': null, 'hmac':null, 'host': null,'shop': null, 'state': null,'timestamp':null}, controller: 'ShopifyRegisterController' }); }]); @@ -69,14 +69,35 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { module.controller('ShopifyLoginController', ['$scope', '$http', '$state', '$stateParams', '$location', function ($scope, $http, $state, $stateParams, $location) { var that = $scope; + + var code = getQueryVariable("code") + var hmac = getQueryVariable("hmac") + var host = getQueryVariable("host") + var shop = getQueryVariable("shop") + var state = getQueryVariable("state") + var timestamp = getQueryVariable("timestamp") + that.model = { - shop: getQueryVariable("shop"), loginId: '', password: '', - code: getQueryVariable("code") + code: code, + hmac: hmac, + host:host, + shop: shop, + state: state, + timestamp: timestamp } - that.loginDisable = false + + that.verifyRequest = function () { + $http.post("/shopify/auth/verify", that.model).then(function (res) { + }, function (error) { + that.resError = error.data.message; + that.loginDisable = false + }) + } + that.verifyRequest() + that.activeShopifyMerchant = function () { that.loginDisable = true $http.post("/shopify/auth/install", that.model).then(function (res) { @@ -89,7 +110,14 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { } that.registerMerchant = function () { - $state.go('shopify.register', {shop: getQueryVariable("shop"), code: getQueryVariable("code")}); + $state.go('shopify.register', { + code: code, + hmac: hmac, + host: host, + shop: shop, + state: state, + timestamp: timestamp + }); } }]); @@ -241,8 +269,12 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { const param = { paymentMerchant, paymentAccount, + code: $stateParams.code, + hmac: $stateParams.hmac, + host: $stateParams.host, shopifyShop: $stateParams.shop, - code: $stateParams.code + state: $stateParams.state, + timestamp: $stateParams.timestamp } $http.post('shopify/store/register', param).then(function (resp) { location.href = resp.data.redirectUrl diff --git a/src/test/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidatorTest.java b/src/test/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidatorTest.java new file mode 100644 index 000000000..ceb8c17f0 --- /dev/null +++ b/src/test/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidatorTest.java @@ -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)); + } +} \ No newline at end of file From 20eb867b11b8567e0b954e0d28a97537d9b1cc23 Mon Sep 17 00:00:00 2001 From: ycfxx Date: Tue, 25 Jan 2022 19:25:14 +0800 Subject: [PATCH 07/10] upgrade shopify OAuth process --- .../application/ShopifyMerchantAuthApplication.java | 6 ++---- .../auth/domain/service/ShopifyAuthService.java | 13 +++++++++++-- .../shopify/auth/web/ShopifyAuthController.java | 9 +++++++++ .../auth/web/ShopifyAuthTemplateController.java | 2 +- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/application/ShopifyMerchantAuthApplication.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/application/ShopifyMerchantAuthApplication.java index 3d44a32ba..779b20d90 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/application/ShopifyMerchantAuthApplication.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/application/ShopifyMerchantAuthApplication.java @@ -55,12 +55,10 @@ public class ShopifyMerchantAuthApplication { /** * 获取shopify店铺授权url * @param shopifyStoreHost - * @param hmac - * @param timestamp * @return */ - public ShopifyPermissionURL getShopifyPermissionUrl(String shopifyStoreHost, String hmac, String timestamp) { - ShopifyPermissionURL shopifyPermissionURL = shopifyAuthService.shopifyPermission(shopifyStoreHost, hmac, timestamp); + public ShopifyPermissionURL getShopifyPermissionUrl(String shopifyStoreHost) { + ShopifyPermissionURL shopifyPermissionURL = shopifyAuthService.shopifyPermission(shopifyStoreHost); return shopifyPermissionURL; } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java index 751f33fed..ad99f0971 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClientException; @@ -38,9 +39,17 @@ public class ShopifyAuthService { @Qualifier("shopifyRestTemplate") private RestTemplate restTemplate; - public ShopifyPermissionURL shopifyPermission(String shopifyStoreHost, String hmac, String timestamp) { + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public ShopifyPermissionURL shopifyPermission(String shopifyStoreHost) { String redirectUri = PlatformEnvironment.getEnv().concatUrl("/auth.html"); - String permissionUrl = String.format(PERMISSION_URL, shopifyStoreHost, clientId, scope, redirectUri, String.valueOf(new Date().getTime()).substring(0,10)); + + String state = String.valueOf(new Date().getTime()).substring(0,10); + + stringRedisTemplate.boundValueOps("shopifyAuthState:"+shopifyStoreHost).set(state); + + String permissionUrl = String.format(PERMISSION_URL, shopifyStoreHost, clientId, scope, redirectUri, state); return ShopifyPermissionURL.builder().url(permissionUrl).build(); } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java index 8c4a4e117..516a155c0 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java @@ -8,6 +8,7 @@ import au.com.royalpay.payment.manage.shopify.auth.web.command.ShopifyPermission import au.com.royalpay.payment.manage.shopify.auth.web.command.ShopifyVerifyRequest; import com.alibaba.fastjson.JSONObject; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -28,6 +29,9 @@ public class ShopifyAuthController { @Autowired private ShopifyRequestValidator shopifyRequestValidator; + @Autowired + private StringRedisTemplate stringRedisTemplate; + /** * 校验shopify请求 * @@ -36,6 +40,11 @@ public class ShopifyAuthController { */ @PostMapping("/verify") public JSONObject verifyRequest(@RequestBody @Valid ShopifyVerifyRequest request) { + String state = stringRedisTemplate.boundValueOps("shopifyAuthState:" + request.getShop()).get(); + if (!request.getState().equals(state)) { + throw new ShopifyRequestVerifyException("This request parameters is invalid"); + } + stringRedisTemplate.delete("shopifyAuthState:" + request.getShop()); if (!shopifyRequestValidator.valid(request.build())) { throw new ShopifyRequestVerifyException("This request parameters is invalid"); } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java index b94a92bd9..424494079 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java @@ -36,7 +36,7 @@ public class ShopifyAuthTemplateController { if (!shopifyRequestValidator.verifyPermission(shopifyStoreHost, hmac, timestamp)) { throw new ShopifyRequestVerifyException("This request parameters is invalid"); } - ShopifyPermissionURL shopifyPermissionURL = shopifyMerchantAuthApplication.getShopifyPermissionUrl(shopifyStoreHost, hmac, timestamp); + ShopifyPermissionURL shopifyPermissionURL = shopifyMerchantAuthApplication.getShopifyPermissionUrl(shopifyStoreHost); return new RedirectView(shopifyPermissionURL.getUrl()); } From 1f8846a25acb64cfadd467b9acc030d00b1a30a4 Mon Sep 17 00:00:00 2001 From: ycfxx Date: Wed, 26 Jan 2022 10:03:07 +0800 Subject: [PATCH 08/10] upgrade shopify OAuth process --- .../domain/service/ShopifyAuthService.java | 2 +- .../auth/web/ShopifyAuthController.java | 35 +--------- .../web/ShopifyAuthTemplateController.java | 68 +++++++++++++++++-- .../web/command/ShopifyPermissionRequest.java | 29 +------- .../web/command/ShopifyVerifyRequest.java | 12 ---- .../store/web/ShopifyStoreController.java | 1 + .../command/CreateShopifyMerchantCommand.java | 13 +--- .../ui/static/shopify/auth/shopify.auth.js | 15 ++-- 8 files changed, 78 insertions(+), 97 deletions(-) diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java index ad99f0971..56bfbbfb3 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyAuthService.java @@ -43,7 +43,7 @@ public class ShopifyAuthService { private StringRedisTemplate stringRedisTemplate; public ShopifyPermissionURL shopifyPermission(String shopifyStoreHost) { - String redirectUri = PlatformEnvironment.getEnv().concatUrl("/auth.html"); + String redirectUri = PlatformEnvironment.getEnv().concatUrl("/shopify/auth/back"); String state = String.valueOf(new Date().getTime()).substring(0,10); diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java index 516a155c0..745dff1f6 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthController.java @@ -1,14 +1,9 @@ package au.com.royalpay.payment.manage.shopify.auth.web; -import au.com.royalpay.payment.manage.shopify.auth.domain.ShopifyRequestVerifyException; import au.com.royalpay.payment.manage.shopify.auth.domain.application.ShopifyMerchantAuthApplication; import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyAccessToken; -import au.com.royalpay.payment.manage.shopify.auth.domain.service.ShopifyRequestValidator; import au.com.royalpay.payment.manage.shopify.auth.web.command.ShopifyPermissionRequest; -import au.com.royalpay.payment.manage.shopify.auth.web.command.ShopifyVerifyRequest; -import com.alibaba.fastjson.JSONObject; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -26,31 +21,6 @@ public class ShopifyAuthController { @Autowired private ShopifyMerchantAuthApplication shopifyMerchantAuthApplication; - @Autowired - private ShopifyRequestValidator shopifyRequestValidator; - - @Autowired - private StringRedisTemplate stringRedisTemplate; - - /** - * 校验shopify请求 - * - * @param request - * @return - */ - @PostMapping("/verify") - public JSONObject verifyRequest(@RequestBody @Valid ShopifyVerifyRequest request) { - String state = stringRedisTemplate.boundValueOps("shopifyAuthState:" + request.getShop()).get(); - if (!request.getState().equals(state)) { - throw new ShopifyRequestVerifyException("This request parameters is invalid"); - } - stringRedisTemplate.delete("shopifyAuthState:" + request.getShop()); - if (!shopifyRequestValidator.valid(request.build())) { - throw new ShopifyRequestVerifyException("This request parameters is invalid"); - } - return new JSONObject(); - } - /** * 获取shopify店铺授权URL * @@ -58,10 +28,7 @@ public class ShopifyAuthController { * @return */ @PostMapping("/install") - public ShopifyAccessToken shopifyPermission(@RequestBody @Valid ShopifyPermissionRequest request) { - if (!shopifyRequestValidator.valid(request.build())) { - throw new ShopifyRequestVerifyException("This request parameters is invalid"); - } + public ShopifyAccessToken shopifyStoreInstall(@RequestBody @Valid ShopifyPermissionRequest request) { ShopifyAccessToken shopifyAccessToken = shopifyMerchantAuthApplication.install(request); return shopifyAccessToken; } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java index 424494079..c8e61b2e3 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java @@ -2,15 +2,21 @@ package au.com.royalpay.payment.manage.shopify.auth.web; import au.com.royalpay.payment.manage.shopify.auth.domain.ShopifyRequestVerifyException; 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.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 java.util.regex.Pattern; + @Controller @RequestMapping(value = "/shopify") public class ShopifyAuthTemplateController { @@ -21,23 +27,73 @@ public class ShopifyAuthTemplateController { @Autowired private ShopifyRequestValidator shopifyRequestValidator; + @Autowired + private StringRedisTemplate stringRedisTemplate; + /** * shopify店铺安装入口 * - * @param shopifyStoreHost + * @param shop * @param hmac * @param timestamp * @return */ @GetMapping("/auth") - public RedirectView shopifyStorePermission(@RequestParam("shop") String shopifyStoreHost, - @RequestParam("hmac") String hmac, - @RequestParam("timestamp") String timestamp) { - if (!shopifyRequestValidator.verifyPermission(shopifyStoreHost, hmac, timestamp)) { + public RedirectView shopifyStorePermission(@RequestParam("shop") String shop, + @RequestParam("hmac") String hmac, + @RequestParam("timestamp") String timestamp) { + 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(shopifyStoreHost); + ShopifyPermissionURL shopifyPermissionURL = shopifyMerchantAuthApplication.getShopifyPermissionUrl(shop); return new RedirectView(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) { + + 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); + return new RedirectView(redirectUri); + } + } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java index d2190a921..ef2526d07 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyPermissionRequest.java @@ -1,6 +1,5 @@ package au.com.royalpay.payment.manage.shopify.auth.web.command; -import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter; import au.com.royalpay.payment.manage.shopify.store.web.command.CreateShopifyMerchantCommand; import lombok.AllArgsConstructor; import lombok.Builder; @@ -25,43 +24,17 @@ public class ShopifyPermissionRequest { @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") + @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; - public static ShopifyPermissionRequest instanceOf(CreateShopifyMerchantCommand command) { return ShopifyPermissionRequest.builder() .loginId(command.getPaymentAccount().getLoginId()) .password(command.getPaymentAccount().getPassword()) .code(command.getCode()) - .hmac(command.getHmac()) - .host(command.getHost()) .shop(command.getShopifyShop()) - .state(command.getState()) - .timestamp(command.getTimestamp()) .build(); } - public ShopifyCommonParameter build() { - return ShopifyCommonParameter.builder() - .code(code) - .hmac(hmac) - .host(host) - .shop(shop) - .state(state) - .timestamp(timestamp) - .build(); - } } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java index 76a89f34d..fc7a8fb02 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/command/ShopifyVerifyRequest.java @@ -1,6 +1,5 @@ package au.com.royalpay.payment.manage.shopify.auth.web.command; -import au.com.royalpay.payment.manage.shopify.auth.domain.entity.ShopifyCommonParameter; import lombok.Data; import javax.validation.constraints.NotBlank; @@ -27,15 +26,4 @@ public class ShopifyVerifyRequest { @NotBlank(message = "timestamp can not blank") private String timestamp; - - public ShopifyCommonParameter build() { - return ShopifyCommonParameter.builder() - .code(code) - .hmac(hmac) - .host(host) - .shop(shop) - .state(state) - .timestamp(timestamp) - .build(); - } } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/ShopifyStoreController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/ShopifyStoreController.java index fd4f95db8..9cb987e35 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/ShopifyStoreController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/ShopifyStoreController.java @@ -24,6 +24,7 @@ public class ShopifyStoreController { * * @param partnerCode 商户标识 */ + @Deprecated @GetMapping("/exist") public Boolean validPaymentAppMerchant(@RequestParam("partnerCode") String partnerCode) { return shopifyStoreApplication.existMerchant(partnerCode); diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java index eb29b9431..8bad7393b 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/store/web/command/CreateShopifyMerchantCommand.java @@ -17,19 +17,8 @@ public class CreateShopifyMerchantCommand { @NotBlank(message = "Auth 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") + @Pattern(regexp = "^[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.myshopify\\.com", message = "Shop hostname is invalid") private String shopifyShop; - @NotBlank(message = "state can not blank") - private String state; - - @NotBlank(message = "timestamp can not blank") - private String timestamp; } diff --git a/src/main/ui/static/shopify/auth/shopify.auth.js b/src/main/ui/static/shopify/auth/shopify.auth.js index a2e317838..6e175b53b 100644 --- a/src/main/ui/static/shopify/auth/shopify.auth.js +++ b/src/main/ui/static/shopify/auth/shopify.auth.js @@ -70,12 +70,19 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { module.controller('ShopifyLoginController', ['$scope', '$http', '$state', '$stateParams', '$location', function ($scope, $http, $state, $stateParams, $location) { var that = $scope; - var code = getQueryVariable("code") + /*var code = getQueryVariable("code") var hmac = getQueryVariable("hmac") var host = getQueryVariable("host") var shop = getQueryVariable("shop") var state = getQueryVariable("state") - var timestamp = getQueryVariable("timestamp") + var timestamp = getQueryVariable("timestamp")*/ + + var code = $location.search().code + var hmac = $location.search().hmac + var host = $location.search().host + var shop = $location.search().shop + var state = $location.search().state + var timestamp = $location.search().timestamp that.model = { loginId: '', @@ -89,14 +96,14 @@ define(['angular', 'uiRouter', 'uiBootstrap'], function (angular) { } that.loginDisable = false - that.verifyRequest = function () { + /*that.verifyRequest = function () { $http.post("/shopify/auth/verify", that.model).then(function (res) { }, function (error) { that.resError = error.data.message; that.loginDisable = false }) } - that.verifyRequest() + that.verifyRequest()*/ that.activeShopifyMerchant = function () { that.loginDisable = true From a8bc6dfc626e5fc075368811dbdb6c9cc3ffd508 Mon Sep 17 00:00:00 2001 From: ycfxx Date: Wed, 26 Jan 2022 13:47:24 +0800 Subject: [PATCH 09/10] upgrade shopify webhook check --- .../domain/ShopifyRequestVerifyException.java | 7 --- .../ShopifyRequestVerifyException.java | 11 +++++ .../service/ShopifyRequestValidator.java | 4 ++ .../web/ShopifyAuthTemplateController.java | 17 ++++--- .../hooks/ShopifyWebhooksController.java | 46 +++++++++++++------ .../shopify/support/ShopifyHttpUtils.java | 33 +++++++++++++ 6 files changed, 91 insertions(+), 27 deletions(-) delete mode 100644 src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/ShopifyRequestVerifyException.java create mode 100644 src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/exception/ShopifyRequestVerifyException.java create mode 100644 src/main/java/au/com/royalpay/payment/manage/shopify/support/ShopifyHttpUtils.java diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/ShopifyRequestVerifyException.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/ShopifyRequestVerifyException.java deleted file mode 100644 index c72e75060..000000000 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/ShopifyRequestVerifyException.java +++ /dev/null @@ -1,7 +0,0 @@ -package au.com.royalpay.payment.manage.shopify.auth.domain; - -public class ShopifyRequestVerifyException extends RuntimeException{ - public ShopifyRequestVerifyException(String message) { - super(message); - } -} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/exception/ShopifyRequestVerifyException.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/exception/ShopifyRequestVerifyException.java new file mode 100644 index 000000000..6aa717dcb --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/exception/ShopifyRequestVerifyException.java @@ -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); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java index b3b6ec49f..cf90d7473 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/domain/service/ShopifyRequestValidator.java @@ -27,4 +27,8 @@ public class ShopifyRequestValidator { .append("×tamp=").append(timestamp); return HmacVerificationUtil.hmacSHA256(message.toString(),clientSecret,hmac); } + + public boolean verify(String message, String hmac) { + return HmacVerificationUtil.hmacSHA256(message,clientSecret,hmac); + } } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java index c8e61b2e3..f4443d1ce 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/auth/web/ShopifyAuthTemplateController.java @@ -1,9 +1,9 @@ package au.com.royalpay.payment.manage.shopify.auth.web; -import au.com.royalpay.payment.manage.shopify.auth.domain.ShopifyRequestVerifyException; 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; @@ -15,6 +15,7 @@ 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 @@ -39,9 +40,10 @@ public class ShopifyAuthTemplateController { * @return */ @GetMapping("/auth") - public RedirectView shopifyStorePermission(@RequestParam("shop") String shop, - @RequestParam("hmac") String hmac, - @RequestParam("timestamp") String timestamp) { + 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."); } @@ -49,7 +51,8 @@ public class ShopifyAuthTemplateController { throw new ShopifyRequestVerifyException("This request parameters is invalid"); } ShopifyPermissionURL shopifyPermissionURL = shopifyMerchantAuthApplication.getShopifyPermissionUrl(shop); - return new RedirectView(shopifyPermissionURL.getUrl()); + response.setHeader("content-security-policy", "frame-ancestors https://" + shop + ".myshopify.com https://admin.shopify.com"); + return "redirect:" + shopifyPermissionURL.getUrl(); } /** @@ -69,7 +72,8 @@ public class ShopifyAuthTemplateController { @RequestParam("host") String host, @RequestParam("state") String state, @RequestParam("shop") String shop, - @RequestParam("timestamp") String timestamp) { + @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."); @@ -93,6 +97,7 @@ public class ShopifyAuthTemplateController { } 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); } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/ShopifyWebhooksController.java b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/ShopifyWebhooksController.java index 255158085..0b620a206 100644 --- a/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/ShopifyWebhooksController.java +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/hooks/ShopifyWebhooksController.java @@ -1,16 +1,19 @@ 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 com.alibaba.fastjson.JSON; +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.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; @Slf4j @RestController @@ -20,35 +23,50 @@ public class ShopifyWebhooksController { @Autowired private ShopifyStoreService shopifyStoreService; + @Autowired + private ShopifyRequestValidator shopifyRequestValidator; + /** * 推送顾客信息查询请求 * - * @param command */ @PostMapping("/customer/request") - public void customerRequest(ShopifyCustomerRequestCommand command) { - log.warn(JSON.toJSONString(command)); + 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); } /** * 擦除顾客信息消息通知 * - * @param command */ @PostMapping("/customer/erasure") - public void customerRedact(ShopifyCustomerRedactCommand command) { - log.warn(JSON.toJSONString(command)); + 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事件 * - * @param command */ @PostMapping("/shop/erasure") - public void shopRedact(ShopifyShopRedactCommand command) { - log.warn(JSON.toJSONString(command)); - ShopifyStore shopifyShop = shopifyStoreService.getByShopifyShop(command.getShop_domain()); + 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; } diff --git a/src/main/java/au/com/royalpay/payment/manage/shopify/support/ShopifyHttpUtils.java b/src/main/java/au/com/royalpay/payment/manage/shopify/support/ShopifyHttpUtils.java new file mode 100644 index 000000000..6e82a1643 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/shopify/support/ShopifyHttpUtils.java @@ -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(); + } +} From fa42e449d0decd048952a3c7c3eaeab859556b09 Mon Sep 17 00:00:00 2001 From: Yixian Date: Fri, 4 Feb 2022 15:33:03 +0800 Subject: [PATCH 10/10] 2.4.5: hotfix-citypartner prize --- .../citypartner/core/impls/CityPartnerPrizeServiceImpl.java | 4 ++-- .../manage/tradelog/refund/impls/RefundServiceImpl.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/au/com/royalpay/payment/manage/citypartner/core/impls/CityPartnerPrizeServiceImpl.java b/src/main/java/au/com/royalpay/payment/manage/citypartner/core/impls/CityPartnerPrizeServiceImpl.java index a1abe55b4..a239ef6d7 100644 --- a/src/main/java/au/com/royalpay/payment/manage/citypartner/core/impls/CityPartnerPrizeServiceImpl.java +++ b/src/main/java/au/com/royalpay/payment/manage/citypartner/core/impls/CityPartnerPrizeServiceImpl.java @@ -511,7 +511,7 @@ public class CityPartnerPrizeServiceImpl implements CityPartnerPrizeService { PayChannel payChannel = PayChannel.fromChannelCode(channel); if (payChannel == PayChannel.ALIPAY_APS_IN_STORE || payChannel == PayChannel.ALIPAY_APS_CASHIER) { - Map> groupByPayType = oneChannel.getValue().stream().collect(Collectors.groupingBy(e -> e.getString("pay_type").equals("alipay_cn"))); + Map> groupByPayType = oneChannel.getValue().stream().collect(Collectors.groupingBy(e -> "alipay_cn".equalsIgnoreCase(e.getString("pay_type")))); for (Map.Entry> payType : groupByPayType.entrySet()) { BigDecimal totalAps = BigDecimal.ZERO; BigDecimal total_surageAps = BigDecimal.ZERO; @@ -525,7 +525,7 @@ public class CityPartnerPrizeServiceImpl implements CityPartnerPrizeService { BigDecimal channelRate = null; if (payChannel == PayChannel.ALIPAY_APS_IN_STORE) { if ("alipay_cn".equalsIgnoreCase(params.getString("pay_type"))) { - channelRate = params.get("org_rate") != null ? params.getBigDecimal("org_rate") : (orgInfo.getBigDecimal("aliapy_rate_value").divide(CommonConsts.HUNDRED, 4, RoundingMode.DOWN)); + channelRate = params.get("org_rate") != null ? params.getBigDecimal("org_rate") : (orgInfo.getBigDecimal("alipay_rate_value").divide(CommonConsts.HUNDRED, 4, RoundingMode.DOWN)); } else { channelRate = params.get("org_rate") != null ? params.getBigDecimal("org_rate") : ((orgInfo.getBigDecimal("retail_interchange_fee_value").add(orgInfo.getBigDecimal("retail_service_fee_value"))).divide(CommonConsts.HUNDRED, 4, RoundingMode.DOWN)); } diff --git a/src/main/java/au/com/royalpay/payment/manage/tradelog/refund/impls/RefundServiceImpl.java b/src/main/java/au/com/royalpay/payment/manage/tradelog/refund/impls/RefundServiceImpl.java index 8f91bc885..228e59105 100644 --- a/src/main/java/au/com/royalpay/payment/manage/tradelog/refund/impls/RefundServiceImpl.java +++ b/src/main/java/au/com/royalpay/payment/manage/tradelog/refund/impls/RefundServiceImpl.java @@ -35,6 +35,7 @@ import org.springframework.util.Assert; import javax.annotation.Resource; import java.math.BigDecimal; +import java.text.MessageFormat; import java.util.Date; import java.util.List; @@ -154,7 +155,7 @@ public class RefundServiceImpl implements RefundService, ApplicationEventPublish OperatorType type = account != null ? OperatorType.PARTNER : OperatorType.MANAGER; boolean requireAudit = type == OperatorType.PARTNER && PartnerRole.getRole(account.getIntValue("role")) == PartnerRole.CASHIER && clientConfig.getBooleanValue("enable_refund_auth"); - logger.debug("applyer type=" + type + "; require audit=" + requireAudit); + logger.debug("applyer type={}; require audit={}", type, requireAudit); paymentApi.clientRefundBalanceCheck(clientId, orderId, currency, feeAmount); Assert.notNull(order, "Order Not exists");