Skip to content

Commit ab21ef6

Browse files
authored
Merge pull request #235 from DevKor-github/feat/apple
배포 오류 수정
2 parents 45371e7 + 8efd4e8 commit ab21ef6

8 files changed

Lines changed: 152 additions & 2 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
FROM openjdk:17
1+
FROM openjdk:17-alpine
22
COPY build/libs/team-c-back-0.0.1-SNAPSHOT.jar app.jar
33
ENTRYPOINT ["java", "-jar", "app.jar"]

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ dependencies {
126126

127127
// 크롤링
128128
implementation 'org.jsoup:jsoup:1.17.2'
129+
130+
// Apple App Store Server Library
131+
implementation 'com.apple.itunes.storekit:app-store-server-library:3.6.0'
132+
129133
}
130134

131135
dependencyManagement {

src/main/java/devkor/com/teamcback/domain/operatingtime/scheduler/OperatingScheduler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class OperatingScheduler {
3030
private static Boolean isEvenWeek = null;
3131

3232
@Scheduled(cron = "0 0 0 * * *") // 매일 자정마다
33-
@EventListener(ApplicationReadyEvent.class)
33+
// @EventListener(ApplicationReadyEvent.class)
3434
public void updateOperatingTime() {
3535
setState();
3636
log.info("운영 시간 업데이트");
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package devkor.com.teamcback.domain.user.controller;
2+
3+
import com.apple.itunes.storekit.verification.VerificationException;
4+
import devkor.com.teamcback.domain.user.dto.request.AppleNotationReq;
5+
import devkor.com.teamcback.domain.user.dto.response.AppleNotificationRes;
6+
import devkor.com.teamcback.domain.user.service.AppleService;
7+
import devkor.com.teamcback.global.exception.exception.GlobalException;
8+
import devkor.com.teamcback.global.response.CommonResponse;
9+
import devkor.com.teamcback.global.response.ResultCode;
10+
import lombok.RequiredArgsConstructor;
11+
import org.springframework.web.bind.annotation.PostMapping;
12+
import org.springframework.web.bind.annotation.RequestBody;
13+
import org.springframework.web.bind.annotation.RequestMapping;
14+
import org.springframework.web.bind.annotation.RestController;
15+
16+
@RestController
17+
@RequiredArgsConstructor
18+
@RequestMapping("/api/apple")
19+
public class AppleController {
20+
21+
private final AppleService appleService;
22+
23+
/**
24+
* Apple 로그인 계정 상태 알림을 수신하는 엔드포인트
25+
*/
26+
@PostMapping("/notifications")
27+
public CommonResponse<AppleNotificationRes> handleAppleNotification(@RequestBody AppleNotationReq request) throws VerificationException {
28+
29+
return CommonResponse.success(appleService.handleAppleNotification(request));
30+
31+
}
32+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package devkor.com.teamcback.domain.user.dto.request;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
6+
@Getter
7+
@Setter
8+
public class AppleNotationReq {
9+
private String signedPayload;
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package devkor.com.teamcback.domain.user.dto.response;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
5+
@JsonIgnoreProperties
6+
public class AppleNotificationRes {
7+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package devkor.com.teamcback.domain.user.service;
2+
3+
import com.apple.itunes.storekit.model.Environment;
4+
import com.apple.itunes.storekit.model.JWSTransactionDecodedPayload;
5+
import com.apple.itunes.storekit.model.ResponseBodyV2DecodedPayload;
6+
import com.apple.itunes.storekit.verification.SignedDataVerifier;
7+
import com.apple.itunes.storekit.verification.VerificationException;
8+
import devkor.com.teamcback.domain.user.dto.request.AppleNotationReq;
9+
import devkor.com.teamcback.domain.user.dto.response.AppleNotificationRes;
10+
import devkor.com.teamcback.domain.user.repository.UserRepository;
11+
import devkor.com.teamcback.global.exception.exception.GlobalException;
12+
import devkor.com.teamcback.global.response.ResultCode;
13+
import jakarta.annotation.PostConstruct;
14+
import org.springframework.beans.factory.annotation.Autowired;
15+
import org.springframework.stereotype.Service;
16+
import org.springframework.transaction.annotation.Transactional;
17+
18+
import java.io.File;
19+
import java.io.FileInputStream;
20+
import java.io.FileNotFoundException;
21+
import java.io.InputStream;
22+
import java.util.HashSet;
23+
import java.util.Set;
24+
25+
@Service
26+
public class AppleService {
27+
28+
@Autowired
29+
private UserRepository userRepository;
30+
private SignedDataVerifier verifier;
31+
private static final String BUNDLE_ID = "com.devkor.kodaero";
32+
33+
@PostConstruct
34+
public void init() throws FileNotFoundException {
35+
36+
InputStream certInputStream = getClass().getClassLoader().getResourceAsStream("static/apple/AppleRootCA-G3.cer");
37+
38+
Set<InputStream> rootCertificates = new HashSet<>();
39+
rootCertificates.add(certInputStream);
40+
41+
this.verifier = new SignedDataVerifier(
42+
rootCertificates,
43+
BUNDLE_ID,
44+
null,
45+
Environment.LOCAL_TESTING,
46+
// Environment.PRODUCTION,
47+
false
48+
);
49+
}
50+
51+
52+
@Transactional
53+
public AppleNotificationRes handleAppleNotification(AppleNotationReq request) {
54+
55+
String signedPayload = request.getSignedPayload();
56+
57+
if (signedPayload == null || signedPayload.isEmpty()) {
58+
throw new GlobalException(ResultCode.INVALID_INPUT);
59+
}
60+
61+
try {
62+
ResponseBodyV2DecodedPayload payload = verifier.verifyAndDecodeNotification(signedPayload);
63+
64+
String notificationType = payload.getNotificationType().toString();
65+
String uuid = payload.getNotificationUUID();
66+
67+
System.out.println("알림 유형: " + notificationType);
68+
System.out.println("UUID: " + uuid);
69+
70+
String signedTransactionInfo = payload.getData().getSignedTransactionInfo();
71+
String signedRenewalInfo = payload.getData().getSignedRenewalInfo();
72+
73+
JWSTransactionDecodedPayload transactionInfo = verifier.verifyAndDecodeTransaction(signedTransactionInfo);
74+
String originalTransactionId = transactionInfo.getOriginalTransactionId();
75+
76+
// 내부 사용자 ID 조회
77+
// String userId = userRepository.findUserIdByOriginalTransactionId(originalTransactionId);
78+
79+
switch (notificationType) {
80+
case "account_delete":
81+
break;
82+
case "email_change":
83+
break;
84+
default:
85+
System.out.println("Unhandled Apple notification: " + notificationType);
86+
break;
87+
}
88+
89+
return new AppleNotificationRes();
90+
91+
} catch (Exception e) {
92+
System.err.println("Apple SiWA Notification processing failed: " + e.getMessage());
93+
throw new GlobalException(ResultCode.SYSTEM_ERROR);
94+
}
95+
}
96+
97+
}
583 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)