|
@@ -40,6 +40,9 @@ import java.util.regex.Pattern;
|
|
|
@RequiredArgsConstructor
|
|
@RequiredArgsConstructor
|
|
|
@Slf4j
|
|
@Slf4j
|
|
|
public class CommonMailServiceImpl implements CommonMailService {
|
|
public class CommonMailServiceImpl implements CommonMailService {
|
|
|
|
|
+ private static final String LQQQ_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36";
|
|
|
|
|
+ private static final String LQQQ_ACCEPT_LANGUAGE = "zh-CN,zh;q=0.9,en;q=0.8";
|
|
|
|
|
+
|
|
|
private final CuiQiuMailService cuiQiuMailService;
|
|
private final CuiQiuMailService cuiQiuMailService;
|
|
|
|
|
|
|
|
private final MailLuService mailLuService;
|
|
private final MailLuService mailLuService;
|
|
@@ -124,12 +127,12 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
|| (linkType == 1 && Boolean.TRUE.equals(isReturnDeviceUrl)))) {
|
|
|| (linkType == 1 && Boolean.TRUE.equals(isReturnDeviceUrl)))) {
|
|
|
try {
|
|
try {
|
|
|
String url = "https://ms.lqqq.cc/web/" + account + "----" + emailPwd;
|
|
String url = "https://ms.lqqq.cc/web/" + account + "----" + emailPwd;
|
|
|
- HttpRequest post = HttpUtil.createGet(url).timeout(Constant.CONNECT_MILLISECONDS);
|
|
|
|
|
|
|
+ HttpRequest post = createLqqqRequest(url, null);
|
|
|
HttpResponse execute = post.execute();
|
|
HttpResponse execute = post.execute();
|
|
|
String body = execute.body();
|
|
String body = execute.body();
|
|
|
String code = linkType != null && linkType == 1
|
|
String code = linkType != null && linkType == 1
|
|
|
- ? getNetflixHouseholdDeviceUrlByLqqqMail(account, body)
|
|
|
|
|
- : getNetflixVerifyCodeByLqqqMail(account, body);
|
|
|
|
|
|
|
+ ? getNetflixHouseholdDeviceUrlByLqqqMail(account, body, url)
|
|
|
|
|
+ : getNetflixVerifyCodeByLqqqMail(account, body, url);
|
|
|
if (StrUtil.isNotBlank(code)) {
|
|
if (StrUtil.isNotBlank(code)) {
|
|
|
return code;
|
|
return code;
|
|
|
}
|
|
}
|
|
@@ -151,7 +154,7 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
return yhMailService.getVerifyCode(account, relateEmail, goodsId, type, linkType, Boolean.TRUE.equals(isReturnDeviceUrl));
|
|
return yhMailService.getVerifyCode(account, relateEmail, goodsId, type, linkType, Boolean.TRUE.equals(isReturnDeviceUrl));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private String getNetflixVerifyCodeByLqqqMail(String account, String body) {
|
|
|
|
|
|
|
+ private String getNetflixVerifyCodeByLqqqMail(String account, String body, String mailboxUrl) {
|
|
|
if (StrUtil.isBlank(body)) {
|
|
if (StrUtil.isBlank(body)) {
|
|
|
return StrUtil.EMPTY;
|
|
return StrUtil.EMPTY;
|
|
|
}
|
|
}
|
|
@@ -160,7 +163,7 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
}
|
|
}
|
|
|
Matcher matcher = Pattern.compile("<a\\b[^>]*href=\"([^\"]*/show_email/[^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE).matcher(body);
|
|
Matcher matcher = Pattern.compile("<a\\b[^>]*href=\"([^\"]*/show_email/[^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE).matcher(body);
|
|
|
while (matcher.find()) {
|
|
while (matcher.find()) {
|
|
|
- String href = matcher.group(1);
|
|
|
|
|
|
|
+ String href = decodeHtmlEntities(matcher.group(1));
|
|
|
String emailItem = getMailListItemHtml(body, matcher.start());
|
|
String emailItem = getMailListItemHtml(body, matcher.start());
|
|
|
if (!emailItem.contains(Constant.NETFLIX) || !isNetflixLoginCodeMail(emailItem)) {
|
|
if (!emailItem.contains(Constant.NETFLIX) || !isNetflixLoginCodeMail(emailItem)) {
|
|
|
continue;
|
|
continue;
|
|
@@ -172,7 +175,7 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
}
|
|
}
|
|
|
try {
|
|
try {
|
|
|
String detailUrl = href.startsWith("http") ? href : "https://ms.lqqq.cc" + href;
|
|
String detailUrl = href.startsWith("http") ? href : "https://ms.lqqq.cc" + href;
|
|
|
- HttpResponse detailResp = HttpUtil.createGet(detailUrl).timeout(Constant.CONNECT_MILLISECONDS).execute();
|
|
|
|
|
|
|
+ HttpResponse detailResp = createLqqqRequest(detailUrl, mailboxUrl).execute();
|
|
|
code = getNetflixVerifyCode(detailResp.body());
|
|
code = getNetflixVerifyCode(detailResp.body());
|
|
|
if (StrUtil.isNotBlank(code)) {
|
|
if (StrUtil.isNotBlank(code)) {
|
|
|
log.info("Netflix {} get verify code from lqqq mail detail: {}", account, code);
|
|
log.info("Netflix {} get verify code from lqqq mail detail: {}", account, code);
|
|
@@ -185,7 +188,7 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
return StrUtil.EMPTY;
|
|
return StrUtil.EMPTY;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private String getNetflixHouseholdDeviceUrlByLqqqMail(String account, String body) {
|
|
|
|
|
|
|
+ private String getNetflixHouseholdDeviceUrlByLqqqMail(String account, String body, String mailboxUrl) {
|
|
|
if (StrUtil.isBlank(body)) {
|
|
if (StrUtil.isBlank(body)) {
|
|
|
return StrUtil.EMPTY;
|
|
return StrUtil.EMPTY;
|
|
|
}
|
|
}
|
|
@@ -202,7 +205,7 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
try {
|
|
try {
|
|
|
String href = decodeHtmlUrl(matcher.group(1));
|
|
String href = decodeHtmlUrl(matcher.group(1));
|
|
|
String detailUrl = href.startsWith("http") ? href : "https://ms.lqqq.cc" + href;
|
|
String detailUrl = href.startsWith("http") ? href : "https://ms.lqqq.cc" + href;
|
|
|
- HttpResponse detailResp = HttpUtil.createGet(detailUrl).timeout(Constant.CONNECT_MILLISECONDS).execute();
|
|
|
|
|
|
|
+ HttpResponse detailResp = createLqqqRequest(detailUrl, mailboxUrl).execute();
|
|
|
url = getNetflixHouseholdDeviceUrl(detailResp.body());
|
|
url = getNetflixHouseholdDeviceUrl(detailResp.body());
|
|
|
if (StrUtil.isNotBlank(url)) {
|
|
if (StrUtil.isNotBlank(url)) {
|
|
|
log.info("Netflix {} get household device url from lqqq mail detail", account);
|
|
log.info("Netflix {} get household device url from lqqq mail detail", account);
|
|
@@ -238,6 +241,17 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
return StrUtil.EMPTY;
|
|
return StrUtil.EMPTY;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private HttpRequest createLqqqRequest(String url, String referer) {
|
|
|
|
|
+ HttpRequest request = HttpUtil.createGet(url)
|
|
|
|
|
+ .timeout(Constant.CONNECT_MILLISECONDS)
|
|
|
|
|
+ .header("User-Agent", LQQQ_USER_AGENT)
|
|
|
|
|
+ .header("Accept-Language", LQQQ_ACCEPT_LANGUAGE);
|
|
|
|
|
+ if (StrUtil.isNotBlank(referer)) {
|
|
|
|
|
+ request.header("Referer", referer);
|
|
|
|
|
+ }
|
|
|
|
|
+ return request;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private String decodeHtmlUrl(String url) {
|
|
private String decodeHtmlUrl(String url) {
|
|
|
return StrUtil.blankToDefault(url, StrUtil.EMPTY)
|
|
return StrUtil.blankToDefault(url, StrUtil.EMPTY)
|
|
|
.replace("&", "&")
|
|
.replace("&", "&")
|
|
@@ -276,7 +290,7 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
};
|
|
};
|
|
|
for (String startStr : startStrs) {
|
|
for (String startStr : startStrs) {
|
|
|
if (text.contains(startStr)) {
|
|
if (text.contains(startStr)) {
|
|
|
- String verifyCode = getNetflixCodePattern(StrUtil.subAfter(text, startStr, false));
|
|
|
|
|
|
|
+ String verifyCode = getNetflixCodePattern(StrUtil.subAfter(text, startStr, true));
|
|
|
if (StrUtil.isNotBlank(verifyCode)) {
|
|
if (StrUtil.isNotBlank(verifyCode)) {
|
|
|
return verifyCode;
|
|
return verifyCode;
|
|
|
}
|
|
}
|
|
@@ -299,6 +313,7 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
if (StrUtil.isBlank(body)) {
|
|
if (StrUtil.isBlank(body)) {
|
|
|
return StrUtil.EMPTY;
|
|
return StrUtil.EMPTY;
|
|
|
}
|
|
}
|
|
|
|
|
+ body = decodeHtmlEntities(body);
|
|
|
String code = getNetflixCodeFromHtml(body);
|
|
String code = getNetflixCodeFromHtml(body);
|
|
|
if (StrUtil.isNotBlank(code)) {
|
|
if (StrUtil.isNotBlank(code)) {
|
|
|
return code;
|
|
return code;
|
|
@@ -311,7 +326,8 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
};
|
|
};
|
|
|
for (String startStr : startStrs) {
|
|
for (String startStr : startStrs) {
|
|
|
if (body.contains(startStr)) {
|
|
if (body.contains(startStr)) {
|
|
|
- code = cleanMailHtml(StrUtil.subAfter(body, startStr, false));
|
|
|
|
|
|
|
+ // Netflix 邮件会先放一段隐藏预览,再出现真实正文标题;从最后一个标题开始解析,避免命中预览后的 CSS 数字。
|
|
|
|
|
+ code = cleanMailHtml(StrUtil.subAfter(body, startStr, true));
|
|
|
String verifyCode = getNetflixCodePattern(code);
|
|
String verifyCode = getNetflixCodePattern(code);
|
|
|
if (StrUtil.isNotBlank(verifyCode)) {
|
|
if (StrUtil.isNotBlank(verifyCode)) {
|
|
|
return verifyCode;
|
|
return verifyCode;
|
|
@@ -322,9 +338,11 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private String getNetflixCodeFromHtml(String body) {
|
|
private String getNetflixCodeFromHtml(String body) {
|
|
|
- Matcher matcher = Pattern.compile("<td\\b[^>]*(?:font-size\\s*:\\s*28px|letter-spacing\\s*:\\s*6px)[^>]*>\\s*([0-9\\s]{4,30})\\s*</td>", Pattern.CASE_INSENSITIVE).matcher(body);
|
|
|
|
|
|
|
+ Matcher matcher = Pattern.compile(
|
|
|
|
|
+ "<(td|div|span)\\b(?=[^>]*(?:class\\s*=\\s*[\\\"'][^\\\"']*lrg-number[^\\\"']*[\\\"']|letter-spacing\\s*:\\s*6px))[^>]*>\\s*([0-9\\s]{4,30})\\s*</\\1>",
|
|
|
|
|
+ Pattern.CASE_INSENSITIVE).matcher(body);
|
|
|
while (matcher.find()) {
|
|
while (matcher.find()) {
|
|
|
- String code = matcher.group(1).replaceAll("\\D", "");
|
|
|
|
|
|
|
+ String code = matcher.group(2).replaceAll("\\D", "");
|
|
|
if (code.length() == 4) {
|
|
if (code.length() == 4) {
|
|
|
return code;
|
|
return code;
|
|
|
}
|
|
}
|
|
@@ -336,17 +354,39 @@ public class CommonMailServiceImpl implements CommonMailService {
|
|
|
if (StrUtil.isBlank(body)) {
|
|
if (StrUtil.isBlank(body)) {
|
|
|
return StrUtil.EMPTY;
|
|
return StrUtil.EMPTY;
|
|
|
}
|
|
}
|
|
|
- return body.replaceAll("<[^>]*>", " ")
|
|
|
|
|
|
|
+ return decodeHtmlEntities(body).replaceAll("<[^>]*>", " ")
|
|
|
.replaceAll("(?i) ", " ")
|
|
.replaceAll("(?i) ", " ")
|
|
|
.replaceAll("(?i)&#x?[0-9a-f]+;", " ")
|
|
.replaceAll("(?i)&#x?[0-9a-f]+;", " ")
|
|
|
.replaceAll("(?i)#[0-9a-f]{3,6}", " ");
|
|
.replaceAll("(?i)#[0-9a-f]{3,6}", " ");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private String decodeHtmlEntities(String body) {
|
|
|
|
|
+ String decoded = body;
|
|
|
|
|
+ for (int i = 0; i < 3; i++) {
|
|
|
|
|
+ String next = decoded
|
|
|
|
|
+ .replaceAll("(?i)<", "<")
|
|
|
|
|
+ .replaceAll("(?i)>", ">")
|
|
|
|
|
+ .replaceAll("(?i)"", "\"")
|
|
|
|
|
+ .replaceAll("(?i)'", "'")
|
|
|
|
|
+ .replace(""", "\"")
|
|
|
|
|
+ .replace("'", "'")
|
|
|
|
|
+ .replace(""", "\"")
|
|
|
|
|
+ .replace("'", "'")
|
|
|
|
|
+ .replaceAll("(?i) ", " ")
|
|
|
|
|
+ .replaceAll("(?i)&", "&");
|
|
|
|
|
+ if (next.equals(decoded)) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ decoded = next;
|
|
|
|
|
+ }
|
|
|
|
|
+ return decoded;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private String getNetflixCodePattern(String code) {
|
|
private String getNetflixCodePattern(String code) {
|
|
|
if (StrUtil.isBlank(code)) {
|
|
if (StrUtil.isBlank(code)) {
|
|
|
return StrUtil.EMPTY;
|
|
return StrUtil.EMPTY;
|
|
|
}
|
|
}
|
|
|
- Matcher spacedMatcher = Pattern.compile("(?<!\\d)(\\d)\\D{1,8}(\\d)\\D{1,8}(\\d)\\D{1,8}(\\d)(?!\\d)").matcher(code);
|
|
|
|
|
|
|
+ Matcher spacedMatcher = Pattern.compile("(?<!\\d)(\\d)\\s{1,8}(\\d)\\s{1,8}(\\d)\\s{1,8}(\\d)(?!\\d)").matcher(code);
|
|
|
while (spacedMatcher.find()) {
|
|
while (spacedMatcher.find()) {
|
|
|
return spacedMatcher.group(1) + spacedMatcher.group(2) + spacedMatcher.group(3) + spacedMatcher.group(4);
|
|
return spacedMatcher.group(1) + spacedMatcher.group(2) + spacedMatcher.group(3) + spacedMatcher.group(4);
|
|
|
}
|
|
}
|