- 核心新增: ICON_CLICK(PNG图标方案,预渲染资源)/SCRATCH/JIGSAW/CURVE_SLIDER(V1-V3)/ANGLE/CURVE_DRAW/WORD_ORDER_CLICK/PROOF_OF_WORK 等生成器 - 图标点选: classpath PNG 加载替代运行时字体渲染(Linux容器无emoji字体),提示条图作为 templateImage 返回前端 - 新增模块: crypto(AES+RSA)/obfuscator(背景乱序/噪声/扭曲)/risk(风控/IP黑名单/限流)/site(站点管理)/ml(轨迹规则引擎) - 平台后端: 站点管理/验证码API(generate/verify/secondary-verify)/统计/ML轨迹学习 - 前端SDK: TPCaptcha兼容,支持全部新型号渲染与交互 - 工具: tools/icon-render 图标预渲染工具
84 lines
2.9 KiB
Java
84 lines
2.9 KiB
Java
package cloud.tianai.captcha.site;
|
|
|
|
import java.security.SecureRandom;
|
|
import java.util.Base64;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Set;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
public class SiteManager {
|
|
|
|
private final ConcurrentHashMap<String, SiteConfig> sitesBySiteKey = new ConcurrentHashMap<>();
|
|
private final ConcurrentHashMap<String, SiteConfig> sitesBySiteId = new ConcurrentHashMap<>();
|
|
private final SecureRandom random = new SecureRandom();
|
|
|
|
public SiteConfig registerSite(String name, Set<String> domains, Set<String> allowedTypes) {
|
|
SiteConfig config = new SiteConfig();
|
|
config.setSiteId(generateId());
|
|
config.setSiteKey(generateKey());
|
|
config.setSecretKey(generateKey());
|
|
config.setName(name);
|
|
config.setDomains(domains);
|
|
config.setAllowedTypes(allowedTypes);
|
|
|
|
sitesBySiteKey.put(config.getSiteKey(), config);
|
|
sitesBySiteId.put(config.getSiteId(), config);
|
|
return config;
|
|
}
|
|
|
|
public SiteConfig getSiteBySiteKey(String siteKey) {
|
|
return sitesBySiteKey.get(siteKey);
|
|
}
|
|
|
|
public SiteConfig getSiteBySiteId(String siteId) {
|
|
return sitesBySiteId.get(siteId);
|
|
}
|
|
|
|
public boolean validateSiteKey(String siteKey, String domain) {
|
|
SiteConfig config = sitesBySiteKey.get(siteKey);
|
|
if (config == null || !config.isEnabled()) {
|
|
return false;
|
|
}
|
|
if (domain != null && config.getDomains() != null && !config.getDomains().isEmpty()) {
|
|
return config.getDomains().contains(domain) || config.getDomains().contains("*");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public boolean validateSecretKey(String siteKey, String secretKey) {
|
|
SiteConfig config = sitesBySiteKey.get(siteKey);
|
|
return config != null && config.getSecretKey().equals(secretKey);
|
|
}
|
|
|
|
public boolean isTypeAllowed(String siteKey, String type) {
|
|
SiteConfig config = sitesBySiteKey.get(siteKey);
|
|
if (config == null) return false;
|
|
if (config.getAllowedTypes() == null || config.getAllowedTypes().isEmpty()) return true;
|
|
return config.getAllowedTypes().contains(type);
|
|
}
|
|
|
|
public void removeSite(String siteKey) {
|
|
SiteConfig config = sitesBySiteKey.remove(siteKey);
|
|
if (config != null) {
|
|
sitesBySiteId.remove(config.getSiteId());
|
|
}
|
|
}
|
|
|
|
public Collection<SiteConfig> getAllSites() {
|
|
return Collections.unmodifiableCollection(sitesBySiteKey.values());
|
|
}
|
|
|
|
private String generateId() {
|
|
byte[] bytes = new byte[16];
|
|
random.nextBytes(bytes);
|
|
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
|
|
}
|
|
|
|
private String generateKey() {
|
|
byte[] bytes = new byte[32];
|
|
random.nextBytes(bytes);
|
|
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
|
|
}
|
|
}
|