diff --git a/rc-service/rc-service-order/order-start/src/main/java/com/red/circle/component/pay/google/GooglePayGlobalProperties.java b/rc-service/rc-service-order/order-start/src/main/java/com/red/circle/component/pay/google/GooglePayGlobalProperties.java new file mode 100644 index 00000000..424130a7 --- /dev/null +++ b/rc-service/rc-service-order/order-start/src/main/java/com/red/circle/component/pay/google/GooglePayGlobalProperties.java @@ -0,0 +1,165 @@ +package com.red.circle.component.pay.google; + +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.androidpublisher.AndroidPublisher; +import com.google.api.services.androidpublisher.AndroidPublisherScopes; +import com.google.auth.http.HttpCredentialsAdapter; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.auth.oauth2.ServiceAccountCredentials; +import com.red.circle.component.core.enums.ISysOriginPlatform; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; + +/** + * Overrides component-pay's classpath-only Google service account loading. + */ +public class GooglePayGlobalProperties { + + private static final String FILE_PREFIX = "file:"; + private static final String CLASSPATH_PREFIX = "classpath:"; + + private String classPatchServiceAccountJson; + private String serverAccount; + private Map googlePay = new HashMap<>(); + + public String getPublicKey(ISysOriginPlatform sysOriginPlatform) { + return googlePay.get(sysOriginPlatform.getSysOrigin()).getPublicKey(); + } + + public Map getServiceAccountAndroidPublisher() + throws GeneralSecurityException, IOException { + Map androidPublisherMap = new HashMap<>(); + for (Map.Entry entry : googlePay.entrySet()) { + GoogleCredentials credentials = ServiceAccountCredentials + .fromStream(getServiceAccountJsonStream(entry.getKey())) + .createScoped(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER)); + + AndroidPublisher androidPublisher = new AndroidPublisher.Builder( + GoogleNetHttpTransport.newTrustedTransport(), + JacksonFactory.getDefaultInstance(), + new HttpCredentialsAdapter(credentials)) + .setApplicationName(entry.getKey()) + .build(); + androidPublisherMap.put(entry.getKey(), androidPublisher); + } + return androidPublisherMap; + } + + private InputStream getServiceAccountJsonStream(String sysOrigin) throws IOException { + String location = getClassPatchServiceAccountJson(sysOrigin); + if (isBlank(location)) { + throw new FileNotFoundException("Google service account json location is blank."); + } + + Resource resource = resolveServiceAccountJsonResource(location.trim()); + if (!resource.exists()) { + throw new FileNotFoundException( + "Google service account json not found: " + resource.getDescription()); + } + return resource.getInputStream(); + } + + private Resource resolveServiceAccountJsonResource(String location) throws MalformedURLException { + if (location.startsWith(FILE_PREFIX)) { + return new UrlResource(location); + } + + if (location.startsWith(CLASSPATH_PREFIX)) { + return new ClassPathResource(location.substring(CLASSPATH_PREFIX.length())); + } + + if (isAbsolutePath(location)) { + return new FileSystemResource(location); + } + + return new ClassPathResource(location); + } + + private boolean isAbsolutePath(String location) { + try { + return Path.of(location).isAbsolute(); + } catch (InvalidPathException ignore) { + return false; + } + } + + private String getClassPatchServiceAccountJson(String sysOrigin) { + GooglePayProperties properties = googlePay.get(sysOrigin); + String location = Objects.isNull(properties) ? null : properties.getClassPatchServiceAccountJson(); + return isBlank(location) ? classPatchServiceAccountJson : location; + } + + private boolean isBlank(String value) { + return value == null || value.trim().isEmpty(); + } + + public String getClassPatchServiceAccountJson() { + return classPatchServiceAccountJson; + } + + public void setClassPatchServiceAccountJson(String classPatchServiceAccountJson) { + this.classPatchServiceAccountJson = classPatchServiceAccountJson; + } + + public String getServerAccount() { + return serverAccount; + } + + public void setServerAccount(String serverAccount) { + this.serverAccount = serverAccount; + } + + public Map getGooglePay() { + return googlePay; + } + + public void setGooglePay(Map googlePay) { + this.googlePay = googlePay; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof GooglePayGlobalProperties other)) { + return false; + } + if (!other.canEqual(this)) { + return false; + } + return Objects.equals(classPatchServiceAccountJson, other.classPatchServiceAccountJson) + && Objects.equals(serverAccount, other.serverAccount) + && Objects.equals(googlePay, other.googlePay); + } + + protected boolean canEqual(Object other) { + return other instanceof GooglePayGlobalProperties; + } + + @Override + public int hashCode() { + return Objects.hash(classPatchServiceAccountJson, serverAccount, googlePay); + } + + @Override + public String toString() { + return "GooglePayGlobalProperties(classPatchServiceAccountJson=" + + classPatchServiceAccountJson + ", serverAccount=" + serverAccount + + ", googlePay=" + googlePay + ")"; + } +}