From 430ed300e848ae69b332fb93222efa94747ddbc4 Mon Sep 17 00:00:00 2001 From: ltiongku Date: Thu, 25 Jul 2024 21:25:03 +0800 Subject: [PATCH] initial read gmail --- pom.xml | 15 ++ .../app/gmail/controller/GmailController.java | 202 +++++++++++++++++- .../app/gmail/service/GmailService.java | 23 +- 3 files changed, 234 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 9ac2fc1..8bc16f2 100644 --- a/pom.xml +++ b/pom.xml @@ -85,6 +85,21 @@ google-api-services-gmail v1-rev20240520-2.0.0 + + org.json + json + 20210307 + + + com.google.zxing + core + 3.4.1 + + + com.google.zxing + javase + 3.4.1 + diff --git a/src/main/java/com/safeqr/app/gmail/controller/GmailController.java b/src/main/java/com/safeqr/app/gmail/controller/GmailController.java index 2e38c76..dba90b8 100644 --- a/src/main/java/com/safeqr/app/gmail/controller/GmailController.java +++ b/src/main/java/com/safeqr/app/gmail/controller/GmailController.java @@ -1,32 +1,224 @@ package com.safeqr.app.gmail.controller; +import com.google.api.services.gmail.Gmail; +import com.google.api.services.gmail.model.MessagePart; +import com.google.api.services.gmail.model.MessagePartHeader; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.LuminanceSource; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.Result; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.common.HybridBinarizer; +import org.apache.commons.codec.binary.Base64; +import org.json.JSONArray; +import org.json.JSONObject; +import com.google.api.client.auth.oauth2.AuthorizationCodeRequestUrl; +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.auth.oauth2.TokenResponse; +import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; +import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.gson.GsonFactory; +import com.google.api.services.gmail.GmailScopes; +import com.google.api.services.gmail.model.ListMessagesResponse; +import com.google.api.services.gmail.model.Message; import com.safeqr.app.gmail.service.GmailService; +import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.view.RedirectView; -import java.util.Map; +import javax.imageio.ImageIO; import static com.safeqr.app.constants.APIConstants.API_VERSION; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + @RestController @RequestMapping(API_VERSION) public class GmailController { private static final Logger logger = LoggerFactory.getLogger(GmailController.class); GmailService gmailService; + + private static final String APPLICATION_NAME = "SafeQR App"; + private static HttpTransport httpTransport; + private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance(); + private static com.google.api.services.gmail.Gmail client; + + GoogleClientSecrets clientSecrets; + GoogleAuthorizationCodeFlow flow; + Credential credential; + + @Value("${gmail.client.clientId}") + private String clientId; + + @Value("${gmail.client.clientSecret}") + private String clientSecret; + + @Value("${gmail.client.redirectUri}") + private String redirectUri; + @Autowired public GmailController(GmailService gmailService) { this.gmailService = gmailService; } + @RequestMapping(value = "/gmail/login", method = RequestMethod.GET) + public RedirectView googleConnectionStatus(HttpServletRequest request) throws Exception { + return new RedirectView(authorize()); + } + private String authorize() throws Exception { + AuthorizationCodeRequestUrl authorizationUrl; + if (flow == null) { + GoogleClientSecrets.Details web = new GoogleClientSecrets.Details(); + web.setClientId(clientId); + web.setClientSecret(clientSecret); + clientSecrets = new GoogleClientSecrets().setWeb(web); + httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY, clientSecrets, + Collections.singleton(GmailScopes.GMAIL_READONLY)) + .build(); + } + authorizationUrl = flow.newAuthorizationUrl() + .setRedirectUri(redirectUri) + .setAccessType("offline") + //.setApprovalPrompt("force") // force refresh token + ; + + System.out.println("gmail authorizationUrl ->" + authorizationUrl); + return authorizationUrl.build(); + } + + @RequestMapping(value = "/gmail/callback", method = RequestMethod.GET, params = "code") + public ResponseEntity oauth2Callback(@RequestParam(value = "code") String code) { + + // System.out.println("code->" + code + " userId->" + userId + " + // query->" + query); + + JSONObject json = new JSONObject(); + JSONArray emailArray = new JSONArray(); + + // String message; + try { + TokenResponse response = flow.newTokenRequest(code).setRedirectUri(redirectUri).execute(); + credential = flow.createAndStoreCredential(response, "userID"); + logger.info(credential.getAccessToken()); + logger.info(credential.getRefreshToken()); + logger.info(credential.toString()); + + // Build the Gmail service + Gmail service = new Gmail.Builder(httpTransport, JSON_FACTORY, credential) + .setApplicationName(APPLICATION_NAME) + .build(); + + // Get the list of messages + ListMessagesResponse listResponse = service.users().messages().list("me").execute(); + List messages = listResponse.getMessages(); + + if (messages != null && !messages.isEmpty()) { + for (Message message : messages) { + Message fullMessage = service.users().messages().get("me", message.getId()).setFormat("full").execute(); + + if (containsQRCode(fullMessage)) { + JSONObject emailJson = new JSONObject(); + emailJson.put("id", fullMessage.getId()); + + // Extract subject + String subject = ""; + for (MessagePartHeader header : fullMessage.getPayload().getHeaders()) { + if (header.getName().equals("Subject")) { + subject = header.getValue(); + break; + } + } + emailJson.put("subject", subject); + + // Extract snippet + emailJson.put("snippet", fullMessage.getSnippet()); + + emailArray.put(emailJson); + } + } + } + + json.put("emails_with_qr_codes", emailArray); + + + + } catch (Exception e) { + + System.out.println("exception cached "); + e.printStackTrace(); + } + + return new ResponseEntity<>(json.toString(), HttpStatus.OK); + } + private boolean containsQRCode(Message message) throws IOException { + if (message.getPayload().getParts() != null) { + for (MessagePart part : message.getPayload().getParts()) { + if ("text/html".equals(part.getMimeType())) { + String data = new String(Base64.decodeBase64(part.getBody().getData())); + if (scanForQRCode(data)) { + return true; + } + } + } + } + return false; + } + + private boolean scanForQRCode(String htmlContent) { + // Extract all img tags + Pattern pattern = Pattern.compile("]+src\\s*=\\s*['\"]([^'\"]+)['\"][^>]*>"); + Matcher matcher = pattern.matcher(htmlContent); + + while (matcher.find()) { + String src = matcher.group(1); + if (src.startsWith("data:image")) { + // It's a base64 encoded image + String base64Image = src.split(",")[1]; + byte[] imageBytes = Base64.decodeBase64(base64Image); + + try { + BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageBytes)); + LuminanceSource source = new BufferedImageLuminanceSource(image); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + + Result result = new MultiFormatReader().decode(bitmap); + if (result != null) { + // QR Code detected + return true; + } + } catch (Exception e) { + // If there's an error reading the image or it's not a QR code, continue to the next image + continue; + } + } + } + return false; + } + + @GetMapping(value = "/gmail/authenticate", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity authenticate() { - logger.info("Health Check"); + logger.info("Invoking gmail authenticate endpoint"); return ResponseEntity.ok(Map.of("version", "SafeQR v1.0.2")); } } diff --git a/src/main/java/com/safeqr/app/gmail/service/GmailService.java b/src/main/java/com/safeqr/app/gmail/service/GmailService.java index eb76aeb..9555728 100644 --- a/src/main/java/com/safeqr/app/gmail/service/GmailService.java +++ b/src/main/java/com/safeqr/app/gmail/service/GmailService.java @@ -1,11 +1,32 @@ package com.safeqr.app.gmail.service; -import com.safeqr.app.qrcode.service.EmailVerificationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp; +import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver; +import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; +import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.gson.GsonFactory; +import com.google.api.client.util.store.FileDataStoreFactory; +import com.google.api.services.gmail.Gmail; +import com.google.api.services.gmail.GmailScopes; +import com.google.api.services.gmail.model.Label; +import com.google.api.services.gmail.model.ListLabelsResponse; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.security.GeneralSecurityException; +import java.util.Collections; +import java.util.List; @Service public class GmailService { private static final Logger logger = LoggerFactory.getLogger(GmailService.class); + }