Files
netdisk-fast-download/parser/src/test/java/cn/qaiu/parser/PanDomainTemplateTest.java
T

370 lines
16 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cn.qaiu.parser;
import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.util.YeShareHostUtil;
import org.junit.Test;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static java.util.regex.Pattern.compile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* @author <a href="https://qaiu.top">QAIU</a>
* Create at 2024/8/8 2:39
*/
public class PanDomainTemplateTest {
@Test
public void normalizeShareLink() {
// 准备测试数据
String testShareUrl = "https://test.lanzoux.com/s/someShareKey";
ParserCreate parserCreate = ParserCreate.fromShareUrl(testShareUrl); // 假设使用LZ网盘模板
// 调用normalizeShareLink方法
ShareLinkInfo result = parserCreate.getShareLinkInfo();
System.out.println(result);
// 断言结果是否符合预期
assertNotNull("Result should not be null", result);
assertEquals("Share key should match", "someShareKey", result.getShareKey());
assertEquals("Standard URL should be generated correctly", parserCreate.getStandardUrlTemplate().replace("{shareKey}", "someShareKey"), result.getStandardUrl());
// 可以添加更多的断言来验证其他字段
}
@Test
public void fromShareUrl() throws InterruptedException {
// 准备测试数据
String lzUrl = "https://wwn.lanzouy.com/ihLkw1gezutg";
String cowUrl = "https://cowtransfer.com/s/9a644fe3e3a748";
String ceUrl = "https://pan.huang1111.cn/s/g31PcQ";
String wsUrl = "https://f.ws59.cn/f/f25625rv6p6";
// ParserCreate.fromShareUrl(wsUrl).createTool()
// .parse().onSuccess(System.out::println);
// ParserCreate.fromShareUrl(lzUrl).createTool()
// .parse().onSuccess(System.out::println);
// ParserCreate.fromShareUrl(cowUrl).createTool()
// .parse().onSuccess(System.out::println);
ParserCreate.fromShareUrl(lzUrl).createTool()
.parse().onSuccess(System.out::println);
// ParserCreate.fromType("lz").shareKey("ihLkw1gezutg")
// .createTool().parse().onSuccess(System.out::println);
// ParserCreate.LZ.shareKey("ihLkw1gezutg")
// .createTool().parse().onSuccess(System.out::println);
// 调用fromShareUrl方法
// PanDomainTemplate resultTemplate = ParserCreate.fromShareUrl(testShareUrl);
// System.out.println(resultTemplate.normalizeShareLink(testShareUrl));
// System.out.println(resultTemplate.shareKey("xxx"));
// System.out.println(resultTemplate.createTool("xxx",null).parse()
// .onSuccess(System.out::println));
// System.out.println(resultTemplate.getDisplayName());
// System.out.println(resultTemplate.getStandardUrlTemplate());
// System.out.println(resultTemplate.getRegexPattern());
//
// // 断言结果是否符合预期
// assertNotNull("Result should not be null", resultTemplate);
// assertEquals("Should return the correct template", ParserCreate.LZ, resultTemplate);
// // 可以添加更多的断言来验证正则表达式匹配逻辑
// new Scanner(System.in).nextLine();
TimeUnit.SECONDS.sleep(5);
}
@Test
public void testWsPatternMatching() {
Pattern wsPattern = PanDomainTemplate.WS.getPattern();
// 历史域名
String[] positiveUrls = {
"https://f.ws59.cn/f/f25625rv6p6",
"https://f.ws28.cn/f/somekey123",
"https://www.wenshushu.cn/f/abc123",
// 新增域名
"https://www.wenxiaozhan.net/f/testkey1",
"https://www.wenxiaozhan.cn/f/testkey2",
"https://www.wss.show/f/testkey3",
"https://www.ws28.cn/f/testkey4",
"https://www.wss.email/f/testkey5",
"https://www.wss1.cn/f/testkey6",
"https://www.ws59.cn/f/testkey7",
"https://www.wss.cc/f/testkey8",
"https://www.wss.pet/f/testkey9",
"https://www.wss.ink/f/testkey10",
"https://www.wenxiaozhan.com/f/testkey11",
"https://www.wenshushu.com/f/testkey12",
"https://www.wss.zone/f/testkey13",
};
for (String url : positiveUrls) {
Matcher m = wsPattern.matcher(url);
assertTrue("WS pattern should match: " + url, m.matches());
assertNotNull("KEY group should not be null for: " + url, m.group("KEY"));
}
// 验证 KEY 提取正确性
Matcher m1 = wsPattern.matcher("https://f.ws59.cn/f/f25625rv6p6");
assertTrue(m1.matches());
assertEquals("f25625rv6p6", m1.group("KEY"));
Matcher m2 = wsPattern.matcher("https://www.wenshushu.cn/f/abc123");
assertTrue(m2.matches());
assertEquals("abc123", m2.group("KEY"));
// 负例:错误路径不匹配
assertFalse("Wrong path should not match",
wsPattern.matcher("https://www.wenshushu.cn/x/abc123").matches());
// 负例:非白名单域名不匹配
assertFalse("Non-whitelisted domain should not match",
wsPattern.matcher("https://www.evil.com/f/abc123").matches());
}
@Test
public void testLzPatternWebgetstore() {
Pattern lzPattern = PanDomainTemplate.LZ.getPattern();
// webgetstore.com 以前遗漏,现已补入
Matcher m1 = lzPattern.matcher("https://webgetstore.com/somekey");
assertTrue("LZ should match webgetstore.com", m1.find());
assertEquals("somekey", m1.group("KEY"));
Matcher m2 = lzPattern.matcher("https://www.webgetstore.com/somekey");
assertTrue("LZ should match www.webgetstore.com", m2.find());
assertEquals("somekey", m2.group("KEY"));
// t-is.cn 以前遗漏,现已补入
Matcher m3 = lzPattern.matcher("https://t-is.cn/somekey");
assertTrue("LZ should match t-is.cn", m3.find());
assertEquals("somekey", m3.group("KEY"));
Matcher m4 = lzPattern.matcher("https://www.t-is.cn/somekey");
assertTrue("LZ should match www.t-is.cn", m4.find());
assertEquals("somekey", m4.group("KEY"));
// 已有域名仍然正常匹配
Matcher m5 = lzPattern.matcher("https://www.lanzoul.com/somekey");
assertTrue("LZ should match existing domain lanzoul.com", m5.find());
assertEquals("somekey", m5.group("KEY"));
}
@Test
public void testYeRedirectPatternAndUidDecode() {
Pattern yePattern = PanDomainTemplate.YE.getPattern();
Matcher oldUrl = yePattern.matcher("https://www.123pan.com/s/lN7UVv-pbYJ");
assertTrue("YE should match old 123pan share URL", oldUrl.find());
assertEquals("lN7UVv-pbYJ", oldUrl.group("KEY"));
Matcher redirectedUrl = yePattern.matcher("https://1813382308.mshare.123pan.cn/123pan/lN7UVv-pbYJ");
assertTrue("YE should match redirected mshare URL", redirectedUrl.find());
assertEquals("lN7UVv-pbYJ", redirectedUrl.group("KEY"));
Matcher htmlUrl = yePattern.matcher("https://www.123278.com/s/lN7UVv-pbYJ.html?pwd=abcd");
assertTrue("YE should match html URL with query", htmlUrl.find());
assertEquals("lN7UVv-pbYJ", htmlUrl.group("KEY"));
assertEquals("1813382308", YeShareHostUtil.getNumericSubdomainIdByShareKey("lN7UVv-pbYJ"));
assertEquals("lN7UVv-pbYJ", YeShareHostUtil.normalizeShareKey("https://1813382308.mshare.123pan.cn/123pan/lN7UVv-pbYJ?pwd=abcd"));
}
@Test
public void testLePatternFix() {
Pattern lePattern = PanDomainTemplate.LE.getPattern();
// /share/ 格式应匹配
Matcher m1 = lePattern.matcher("https://lecloud.lenovo.com/share/abc123");
assertTrue("LE should match /share/ format", m1.find());
assertEquals("abc123", m1.group("KEY"));
// /mshare/ 格式应匹配
Matcher m2 = lePattern.matcher("https://lecloud.lenovo.com/mshare/xyz789");
assertTrue("LE should match /mshare/ format", m2.find());
assertEquals("xyz789", m2.group("KEY"));
// leclou.lenovo.com (去掉'd') 不应匹配
assertFalse("LE should NOT match leclou.lenovo.com",
lePattern.matcher("https://leclou.lenovo.com/share/abc123").find());
// 错误路径不应匹配
assertFalse("LE should NOT match wrong path",
lePattern.matcher("https://lecloud.lenovo.com/s/abc123").find());
}
@Test
public void testCowPatternFix() {
Pattern cowPattern = PanDomainTemplate.COW.getPattern();
// 正常域名
Matcher m1 = cowPattern.matcher("https://cowtransfer.com/s/abc123");
assertTrue("COW should match cowtransfer.com", m1.find());
assertEquals("abc123", m1.group("KEY"));
Matcher m2 = cowPattern.matcher("https://share.cowtransfer.com/s/abc123");
assertTrue("COW should match share.cowtransfer.com", m2.find());
assertEquals("abc123", m2.group("KEY"));
// 潜在的URL注入:`(.*)` 是贪婪捕获组,可匹配 `evil.com/redirect/` 等前缀,
// 使形如 `https://evil.com/redirect/cowtransfer.com/s/key` 的 URL 被误识别。
// 修复后改为 `(?:[a-zA-Z\d-]+\.)?` 仅匹配一级合法子域名(可选),消除误匹配。
assertFalse("COW should NOT match redirect URLs containing cowtransfer.com in path",
cowPattern.matcher("https://evil.com/redirect/cowtransfer.com/s/abc").find());
}
@Test
public void testMnePatternFix() {
Pattern mnePattern = PanDomainTemplate.MNE.getPattern();
// 带 #/ 前缀的完整网页链接(修复前因 (y.) 未转义而存在 bug)
Matcher m1 = mnePattern.matcher("https://music.163.com/#/song?id=12345");
assertTrue("MNE should match #/song format", m1.find());
assertEquals("12345", m1.group("KEY"));
// 带 m/ 前缀的移动端链接
Matcher m2 = mnePattern.matcher("https://music.163.com/m/song?id=12345");
assertTrue("MNE should match m/song format", m2.find());
assertEquals("12345", m2.group("KEY"));
// y.music.163.com 子域名
Matcher m3 = mnePattern.matcher("https://y.music.163.com/song?id=12345");
assertTrue("MNE should match y.music.163.com", m3.find());
assertEquals("12345", m3.group("KEY"));
// 原 (y.) 中 `.` 未转义(`.` 匹配任意字符):对于 `yXmusic.163.com`
// `(y.)` 会消费 `yX`y + 任意字符),剩余 `music.163.com` 再被 `music\.163\.com` 匹配,导致误匹配。
// 修复后 `(y\.)` 要求字面 `.``yX` 中 X ≠ `.` 无法匹配,不再误匹配。
assertFalse("MNE should NOT match yXmusic.163.com (old (y.) could erroneously match via backtracking)",
mnePattern.matcher("https://yXmusic.163.com/song?id=12345").find());
}
@Test
public void testP115PatternFix() {
Pattern p115Pattern = PanDomainTemplate.P115.getPattern();
// 正常匹配
Matcher m1 = p115Pattern.matcher("https://115.com/s/abc123");
assertTrue("P115 should match 115.com", m1.find());
assertEquals("abc123", m1.group("KEY"));
Matcher m2 = p115Pattern.matcher("https://anxia.com/s/abc123");
assertTrue("P115 should match anxia.com", m2.find());
assertEquals("abc123", m2.group("KEY"));
// 原 .com 未转义时 115Xcom 会被误匹配(现已修复)
assertFalse("P115 should NOT match 115Xcom",
p115Pattern.matcher("https://115Xcom/s/abc123").find());
}
@Test
public void testPgdSubdomain() {
Pattern pgdPattern = PanDomainTemplate.PGD.getPattern();
// 标准链接
Matcher m1 = pgdPattern.matcher("https://drive.google.com/file/d/abc123/view?usp=sharing");
assertTrue("PGD should match standard drive.google.com", m1.find());
assertEquals("abc123", m1.group("KEY"));
// 带子域名的链接(修复后支持)
Matcher m2 = pgdPattern.matcher("https://adsd.drive.google.com/file/d/151bR-nk-tOBm9QAFaozJIVt2WYyCMkoz/view");
assertTrue("PGD should match subdomain.drive.google.com", m2.find());
assertEquals("151bR-nk-tOBm9QAFaozJIVt2WYyCMkoz", m2.group("KEY"));
}
@Test
public void testFsPatternMatching() {
Pattern fsPattern = PanDomainTemplate.FS.getPattern();
// 文件链接
Matcher m1 = fsPattern.matcher(
"https://kcncuknojm60.feishu.cn/file/VnCxbt35KoowKoxldO3c3C7VnMc");
assertTrue("FS should match file link", m1.matches());
assertEquals("VnCxbt35KoowKoxldO3c3C7VnMc", m1.group("KEY"));
// 文件链接带 ?from=from_copylink
Matcher m2 = fsPattern.matcher(
"https://kcncuknojm60.feishu.cn/file/VnCxbt35KoowKoxldO3c3C7VnMc?from=from_copylink");
assertTrue("FS should match file link with query param", m2.matches());
assertEquals("VnCxbt35KoowKoxldO3c3C7VnMc", m2.group("KEY"));
// 文件夹链接
Matcher m3 = fsPattern.matcher(
"https://kcncuknojm60.feishu.cn/drive/folder/RQSKf8EQ4l7dMedqzHucpMbancg");
assertTrue("FS should match folder link", m3.matches());
assertEquals("RQSKf8EQ4l7dMedqzHucpMbancg", m3.group("KEY"));
// 文件夹链接带 ?from=from_copylink
Matcher m4 = fsPattern.matcher(
"https://kcncuknojm60.feishu.cn/drive/folder/RQSKf8EQ4l7dMedqzHucpMbancg?from=from_copylink");
assertTrue("FS should match folder link with query param", m4.matches());
assertEquals("RQSKf8EQ4l7dMedqzHucpMbancg", m4.group("KEY"));
// 不同的 tenant 子域名
Matcher m5 = fsPattern.matcher(
"https://pokepangle.feishu.cn/file/VW30bpK74ontiTxvRg1cZcgvnGg");
assertTrue("FS should match different tenant", m5.matches());
assertEquals("VW30bpK74ontiTxvRg1cZcgvnGg", m5.group("KEY"));
// 负例: 非feishu域名不匹配
assertFalse("FS should NOT match non-feishu domain",
fsPattern.matcher("https://evil.com/file/abc123").matches());
// 负例: feishu.cn上的其他路径不匹配
assertFalse("FS should NOT match other feishu paths",
fsPattern.matcher("https://xxx.feishu.cn/docs/abc123").matches());
}
@Test
public void testFsFromShareUrl() {
// 测试文件链接解析
String fileUrl = "https://kcncuknojm60.feishu.cn/file/VnCxbt35KoowKoxldO3c3C7VnMc?from=from_copylink";
ParserCreate parserCreate = ParserCreate.fromShareUrl(fileUrl);
ShareLinkInfo info = parserCreate.getShareLinkInfo();
assertNotNull("ShareLinkInfo should not be null", info);
assertEquals("fs", info.getType());
assertEquals("飞书云盘", info.getPanName());
assertEquals("VnCxbt35KoowKoxldO3c3C7VnMc", info.getShareKey());
// 测试文件夹链接解析
String folderUrl = "https://kcncuknojm60.feishu.cn/drive/folder/RQSKf8EQ4l7dMedqzHucpMbancg";
ParserCreate parserCreate2 = ParserCreate.fromShareUrl(folderUrl);
ShareLinkInfo info2 = parserCreate2.getShareLinkInfo();
assertNotNull("ShareLinkInfo should not be null", info2);
assertEquals("fs", info2.getType());
assertEquals("飞书云盘", info2.getPanName());
assertEquals("RQSKf8EQ4l7dMedqzHucpMbancg", info2.getShareKey());
}
@Test
public void verifyDuplicates() {
// 校验重复
Set<String> collect =
Arrays.stream(PanDomainTemplate.values()).map(PanDomainTemplate::getRegex).collect(Collectors.toSet());
if (collect.size()<PanDomainTemplate.values().length) {
System.out.println("有重复枚举正则");
} else {
System.out.println("正则无重复");
}
Set<String> collect2 =
Arrays.stream(PanDomainTemplate.values()).map(PanDomainTemplate::getStandardUrlTemplate).collect(Collectors.toSet());
if (collect2.size()<PanDomainTemplate.values().length) {
System.out.println("有重复枚举标准链接");
} else {
System.out.println("标准链接无重复");
}
}
}