From f65cee37f9dddca505ae9b5ad5a3a3e37e64315a Mon Sep 17 00:00:00 2001 From: heyethereum Date: Wed, 17 Jul 2024 00:32:22 +0800 Subject: [PATCH] added comments and clean up --- .../qrcode/dto/response/BaseScanResponse.java | 2 +- .../app/qrcode/dto/response/URLResponse.java | 2 +- .../com/safeqr/app/qrcode/entity/QRCode.java | 7 +- .../safeqr/app/qrcode/entity/QRCodeURL.java | 6 +- .../app/qrcode/service/QRCodeTypeService.java | 102 +++--------------- .../service/URLVerificationService.java | 95 ++++++++++++++++ 6 files changed, 116 insertions(+), 98 deletions(-) diff --git a/src/main/java/com/safeqr/app/qrcode/dto/response/BaseScanResponse.java b/src/main/java/com/safeqr/app/qrcode/dto/response/BaseScanResponse.java index 16b71ee..4848c39 100644 --- a/src/main/java/com/safeqr/app/qrcode/dto/response/BaseScanResponse.java +++ b/src/main/java/com/safeqr/app/qrcode/dto/response/BaseScanResponse.java @@ -13,5 +13,5 @@ import lombok.experimental.SuperBuilder; @NoArgsConstructor public class BaseScanResponse { private QRCode scannedQRCode; - private QRCodeType qrCodeType; + private QRCodeType qrCode; } diff --git a/src/main/java/com/safeqr/app/qrcode/dto/response/URLResponse.java b/src/main/java/com/safeqr/app/qrcode/dto/response/URLResponse.java index 1c38967..cb5a767 100644 --- a/src/main/java/com/safeqr/app/qrcode/dto/response/URLResponse.java +++ b/src/main/java/com/safeqr/app/qrcode/dto/response/URLResponse.java @@ -10,5 +10,5 @@ import lombok.experimental.SuperBuilder; @AllArgsConstructor @NoArgsConstructor public final class URLResponse extends BaseScanResponse{ - private QRCodeURL qrCodeURL; + private QRCodeURL details; } diff --git a/src/main/java/com/safeqr/app/qrcode/entity/QRCode.java b/src/main/java/com/safeqr/app/qrcode/entity/QRCode.java index 8650d39..b009181 100644 --- a/src/main/java/com/safeqr/app/qrcode/entity/QRCode.java +++ b/src/main/java/com/safeqr/app/qrcode/entity/QRCode.java @@ -7,7 +7,7 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.UuidGenerator; import java.time.LocalDateTime; import java.util.UUID; @@ -21,15 +21,16 @@ import java.util.UUID; public class QRCode { @Id - @JsonIgnore @GeneratedValue(generator = "UUID") - @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @UuidGenerator @Column(updatable = false, nullable = false) private UUID id; @JsonIgnore @Column(name = "qr_code_type_id", nullable = false) private Long qrCodeTypeId; + + @JsonIgnore private String userId; private String contents; diff --git a/src/main/java/com/safeqr/app/qrcode/entity/QRCodeURL.java b/src/main/java/com/safeqr/app/qrcode/entity/QRCodeURL.java index 2c16bc0..c6c6ded 100644 --- a/src/main/java/com/safeqr/app/qrcode/entity/QRCodeURL.java +++ b/src/main/java/com/safeqr/app/qrcode/entity/QRCodeURL.java @@ -7,10 +7,9 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; import lombok.Builder; -import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.UuidGenerator; import java.util.List; -import java.util.Map; import java.util.UUID; @Entity @@ -20,11 +19,10 @@ import java.util.UUID; @NoArgsConstructor @AllArgsConstructor public class QRCodeURL { - @Id @JsonIgnore @GeneratedValue(generator = "UUID") - @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @UuidGenerator @Column(updatable = false, nullable = false) private UUID id; diff --git a/src/main/java/com/safeqr/app/qrcode/service/QRCodeTypeService.java b/src/main/java/com/safeqr/app/qrcode/service/QRCodeTypeService.java index 22a63b6..067df79 100644 --- a/src/main/java/com/safeqr/app/qrcode/service/QRCodeTypeService.java +++ b/src/main/java/com/safeqr/app/qrcode/service/QRCodeTypeService.java @@ -23,6 +23,7 @@ import reactor.core.publisher.Mono; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.security.NoSuchAlgorithmException; import java.time.LocalDateTime; import java.util.ArrayList; @@ -44,6 +45,9 @@ public class QRCodeTypeService { @Autowired private URLRepository urlRepository; + + @Autowired + private URLVerificationService urlVerificationService; @Autowired private SafeBrowsingService safeBrowsingService; @@ -98,109 +102,29 @@ public class QRCodeTypeService { .findFirst() .orElse(defaultQRCodeType); } + private BaseScanResponse insertIntoRespectiveTable(QRCode qrCode, QRCodeType qrCodeType) { + String contents = qrCode.getContents(); try { - String url = qrCode.getContents(); - QRCodeURL urlObj = breakdownURL(url); + QRCodeURL urlObj = urlVerificationService.breakdownURL(contents); + List redirectChain = urlVerificationService.countAndTrackRedirects(contents); urlObj.setQrCodeId(qrCode.getId()); - List redirectChain = countAndTrackRedirects(url); - logger.info("Redirect chain: {}", redirectChain); - for (int i = 0; i < redirectChain.size(); i++) { - logger.info((i == 0 ? "Initial URL: " : "Redirect #" + i + ": ") + redirectChain.get(i)); - } urlObj.setRedirect(redirectChain.size() - 1); urlObj.setRedirectChain(redirectChain); + + // Insert into URL table urlRepository.save(urlObj); - return URLResponse.builder() - .scannedQRCode(qrCode) - .qrCodeType(qrCodeType) - .qrCodeURL(urlObj) - .build(); - } catch (IOException e) { + return URLResponse.builder().scannedQRCode(qrCode).qrCode(qrCodeType).details(urlObj).build(); + } catch (IOException | URISyntaxException e) { logger.error("Error: ", e); } return BaseScanResponse.builder() .scannedQRCode(qrCode) - .qrCodeType(qrCodeType) + .qrCode(qrCodeType) .build(); } - // Function to breakdown URL into subdomain, domain, topLevelDomain, query params, fragment - public QRCodeURL breakdownURL(String urlString) throws MalformedURLException { - URL url = new URL(urlString); - QRCodeURL urlObj = new QRCodeURL(); - - String host = url.getHost(); - String[] hostParts = host.split("\\."); - String subdomain = ""; - - if (hostParts.length >= 2) { - urlObj.setTopLevelDomain(hostParts[hostParts.length - 1]); - urlObj.setDomain(hostParts[hostParts.length - 2]); - if (hostParts.length > 2) { - subdomain = String.join(".", java.util.Arrays.copyOfRange(hostParts, 0, hostParts.length - 2)); - } - } - - urlObj.setSubdomain(subdomain); - - String path = url.getPath(); - urlObj.setPath(path.isEmpty() ? "/" : path); - - String query = url.getQuery(); - Map queryParams = new HashMap<>(); - if (query != null) { - for (String param : query.split("&")) { - String[] pair = param.split("="); - queryParams.put(pair[0], pair.length > 1 ? pair[1] : ""); - } - logger.info("queryParams: {}", queryParams); - } - urlObj.setQuery(queryParams.toString()); - - String fragment = url.getRef(); - - urlObj.setFragment(fragment); - - return urlObj; - } - - List countAndTrackRedirects(String urlString) throws IOException { - URL url = new URL(urlString); - List redirectChain = new ArrayList<>(); - redirectChain.add(urlString); // Add the initial URL to the chain - boolean redirected; - int redirectCount = 0; - - do { - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - connection.setInstanceFollowRedirects(false); - - int responseCode = connection.getResponseCode(); - redirected = (responseCode >= 300 && responseCode < 400); - - if (redirected) { - String newUrl = connection.getHeaderField("Location"); - if (newUrl == null) { - break; - } - // Handle relative URLs - if (!newUrl.startsWith("http://") && !newUrl.startsWith("https://")) { - newUrl = new URL(url, newUrl).toString(); - } - url = new URL(newUrl); - redirectChain.add(newUrl); - redirectCount++; - logger.info("Redirect #{}: {}",redirectCount, newUrl); - } - - connection.disconnect(); - } while (redirected && redirectCount < CommonConstants.MAX_REDIRECT_COUNT); - - return redirectChain; - } public Mono detectType(QRCodePayload payload) { String data = payload.getData(); diff --git a/src/main/java/com/safeqr/app/qrcode/service/URLVerificationService.java b/src/main/java/com/safeqr/app/qrcode/service/URLVerificationService.java index 1d362a6..6668dc5 100644 --- a/src/main/java/com/safeqr/app/qrcode/service/URLVerificationService.java +++ b/src/main/java/com/safeqr/app/qrcode/service/URLVerificationService.java @@ -1,12 +1,107 @@ package com.safeqr.app.qrcode.service; +import com.safeqr.app.constants.CommonConstants; import com.safeqr.app.qrcode.dto.QRCodePayload; import com.safeqr.app.qrcode.dto.URLVerificationResponse; +import com.safeqr.app.qrcode.entity.QRCodeURL; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; +import java.io.IOException; +import java.net.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + @Service public class URLVerificationService { + private static final Logger logger = LoggerFactory.getLogger(URLVerificationService.class); + // Function to breakdown URL into subdomain, domain, topLevelDomain, query params, fragment + public QRCodeURL breakdownURL(String urlString) throws MalformedURLException, URISyntaxException { + URI uri = new URI(urlString); + URL url = uri.toURL(); + QRCodeURL urlObj = new QRCodeURL(); + + String host = url.getHost(); + // split host into subdomain, domain, topLevelDomain + String[] hostParts = host.split("\\."); + String subdomain = ""; + + if (hostParts.length >= 2) { + // set topLevelDomain to the last part of the host + urlObj.setTopLevelDomain(hostParts[hostParts.length - 1]); + // set domain to the second last part of the host + urlObj.setDomain(hostParts[hostParts.length - 2]); + // set subdomain to the first part of the host + if (hostParts.length > 2) { + subdomain = String.join(".", java.util.Arrays.copyOfRange(hostParts, 0, hostParts.length - 2)); + } + } + // set subdomain to URL host + urlObj.setSubdomain(subdomain); + + String path = url.getPath(); + //set path to URL path if it's not empty, otherwise set it to root path + urlObj.setPath(path.isEmpty() ? "/" : path); + + String query = url.getQuery(); + Map queryParams = new HashMap<>(); + if (query != null) { + // split query params into key value pairs + for (String param : query.split("&")) { + String[] pair = param.split("="); + queryParams.put(pair[0], pair.length > 1 ? pair[1] : ""); + } + logger.info("queryParams: {}", queryParams); + } + // set query params to URL query + urlObj.setQuery(queryParams.toString()); + // set fragment to URL ref + urlObj.setFragment(url.getRef()); + + return urlObj; + } + + List countAndTrackRedirects(String urlString) throws IOException, URISyntaxException { + URI uri = new URI(urlString); + URL url = uri.toURL(); + List redirectChain = new ArrayList<>(); + + // Add the initial URL to the chain + redirectChain.add(urlString); + boolean redirected; + int redirectCount = 0; + + do { + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setInstanceFollowRedirects(false); + + int responseCode = connection.getResponseCode(); + redirected = (responseCode >= 300 && responseCode < 400); + // Handle redirects + if (redirected) { + // Location header contains the URL to redirect to + String newUrl = connection.getHeaderField("Location"); + if (newUrl == null) { + break; + } + // Handle relative URLs + uri = uri.resolve(newUrl); + url = uri.toURL(); + redirectChain.add(url.toString()); + redirectCount++; + logger.info("Redirect #{}: {}",redirectCount, newUrl); + } + + connection.disconnect(); + } while (redirected && redirectCount < CommonConstants.MAX_REDIRECT_COUNT); + + return redirectChain; + } public URLVerificationResponse verifyURL(QRCodePayload payload) { URLVerificationResponse response = new URLVerificationResponse(); try {