Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
FROM openjdk:17
FROM openjdk:17-alpine
COPY build/libs/team-c-back-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ dependencies {

// 크롤링
implementation 'org.jsoup:jsoup:1.17.2'

// Apple App Store Server Library
implementation 'com.apple.itunes.storekit:app-store-server-library:3.6.0'

}

dependencyManagement {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class OperatingScheduler {
private static Boolean isEvenWeek = null;

@Scheduled(cron = "0 0 0 * * *") // 매일 자정마다
@EventListener(ApplicationReadyEvent.class)
// @EventListener(ApplicationReadyEvent.class)
public void updateOperatingTime() {
setState();
log.info("운영 시간 업데이트");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package devkor.com.teamcback.domain.user.controller;

import com.apple.itunes.storekit.verification.VerificationException;
import devkor.com.teamcback.domain.user.dto.request.AppleNotationReq;
import devkor.com.teamcback.domain.user.dto.response.AppleNotificationRes;
import devkor.com.teamcback.domain.user.service.AppleService;
import devkor.com.teamcback.global.exception.exception.GlobalException;
import devkor.com.teamcback.global.response.CommonResponse;
import devkor.com.teamcback.global.response.ResultCode;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/apple")
public class AppleController {

private final AppleService appleService;

/**
* Apple 로그인 계정 상태 알림을 수신하는 엔드포인트
*/
@PostMapping("/notifications")
public CommonResponse<AppleNotificationRes> handleAppleNotification(@RequestBody AppleNotationReq request) throws VerificationException {

return CommonResponse.success(appleService.handleAppleNotification(request));

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package devkor.com.teamcback.domain.user.dto.request;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class AppleNotationReq {
private String signedPayload;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package devkor.com.teamcback.domain.user.dto.response;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties
public class AppleNotificationRes {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package devkor.com.teamcback.domain.user.service;

import com.apple.itunes.storekit.model.Environment;
import com.apple.itunes.storekit.model.JWSTransactionDecodedPayload;
import com.apple.itunes.storekit.model.ResponseBodyV2DecodedPayload;
import com.apple.itunes.storekit.verification.SignedDataVerifier;
import com.apple.itunes.storekit.verification.VerificationException;
import devkor.com.teamcback.domain.user.dto.request.AppleNotationReq;
import devkor.com.teamcback.domain.user.dto.response.AppleNotificationRes;
import devkor.com.teamcback.domain.user.repository.UserRepository;
import devkor.com.teamcback.global.exception.exception.GlobalException;
import devkor.com.teamcback.global.response.ResultCode;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;

@Service
public class AppleService {

@Autowired
private UserRepository userRepository;
private SignedDataVerifier verifier;
private static final String BUNDLE_ID = "com.devkor.kodaero";

@PostConstruct
public void init() throws FileNotFoundException {

InputStream certInputStream = getClass().getClassLoader().getResourceAsStream("static/apple/AppleRootCA-G3.cer");

Set<InputStream> rootCertificates = new HashSet<>();
rootCertificates.add(certInputStream);

this.verifier = new SignedDataVerifier(
rootCertificates,
BUNDLE_ID,
null,
Environment.LOCAL_TESTING,
// Environment.PRODUCTION,
false
);
}


@Transactional
public AppleNotificationRes handleAppleNotification(AppleNotationReq request) {

String signedPayload = request.getSignedPayload();

if (signedPayload == null || signedPayload.isEmpty()) {
throw new GlobalException(ResultCode.INVALID_INPUT);
}

try {
ResponseBodyV2DecodedPayload payload = verifier.verifyAndDecodeNotification(signedPayload);

String notificationType = payload.getNotificationType().toString();
String uuid = payload.getNotificationUUID();

System.out.println("알림 유형: " + notificationType);
System.out.println("UUID: " + uuid);

String signedTransactionInfo = payload.getData().getSignedTransactionInfo();
String signedRenewalInfo = payload.getData().getSignedRenewalInfo();

JWSTransactionDecodedPayload transactionInfo = verifier.verifyAndDecodeTransaction(signedTransactionInfo);
String originalTransactionId = transactionInfo.getOriginalTransactionId();

// 내부 사용자 ID 조회
// String userId = userRepository.findUserIdByOriginalTransactionId(originalTransactionId);

switch (notificationType) {
case "account_delete":
break;
case "email_change":
break;
default:
System.out.println("Unhandled Apple notification: " + notificationType);
break;
}

return new AppleNotificationRes();

} catch (Exception e) {
System.err.println("Apple SiWA Notification processing failed: " + e.getMessage());
throw new GlobalException(ResultCode.SYSTEM_ERROR);
}
}

}
Binary file added src/main/resources/static/apple/AppleRootCA-G3.cer
Binary file not shown.