mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-04-19 19:21:18 +00:00
disable fingerpritning
This commit is contained in:
parent
c59d3ff3e0
commit
3b5b7772a9
@ -1,68 +1,68 @@
|
||||
package stirling.software.SPDF.config.fingerprint;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class FingerprintBasedSessionFilter extends OncePerRequestFilter {
|
||||
private final FingerprintGenerator fingerprintGenerator;
|
||||
private final FingerprintBasedSessionManager sessionManager;
|
||||
|
||||
@Autowired
|
||||
public FingerprintBasedSessionFilter(
|
||||
FingerprintGenerator fingerprintGenerator,
|
||||
FingerprintBasedSessionManager sessionManager) {
|
||||
this.fingerprintGenerator = fingerprintGenerator;
|
||||
this.sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
if (RequestUriUtils.isStaticResource(request.getContextPath(), request.getRequestURI())) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
String fingerprint = fingerprintGenerator.generateFingerprint(request);
|
||||
log.debug("Generated fingerprint for request: {}", fingerprint);
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
boolean isNewSession = session.isNew();
|
||||
String sessionId = session.getId();
|
||||
|
||||
if (isNewSession) {
|
||||
log.info("New session created: {}", sessionId);
|
||||
}
|
||||
|
||||
if (!sessionManager.isFingerPrintAllowed(fingerprint)) {
|
||||
log.info("Blocked fingerprint detected, redirecting: {}", fingerprint);
|
||||
response.sendRedirect(request.getContextPath() + "/too-many-requests");
|
||||
return;
|
||||
}
|
||||
|
||||
session.setAttribute("userFingerprint", fingerprint);
|
||||
session.setAttribute(
|
||||
FingerprintBasedSessionManager.STARTUP_TIMESTAMP,
|
||||
FingerprintBasedSessionManager.APP_STARTUP_TIME);
|
||||
|
||||
sessionManager.registerFingerprint(fingerprint, sessionId);
|
||||
|
||||
log.debug("Proceeding with request: {}", request.getRequestURI());
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
//package stirling.software.SPDF.config.fingerprint;
|
||||
//
|
||||
//import java.io.IOException;
|
||||
//
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import org.springframework.web.filter.OncePerRequestFilter;
|
||||
//
|
||||
//import jakarta.servlet.FilterChain;
|
||||
//import jakarta.servlet.ServletException;
|
||||
//import jakarta.servlet.http.HttpServletRequest;
|
||||
//import jakarta.servlet.http.HttpServletResponse;
|
||||
//import jakarta.servlet.http.HttpSession;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import stirling.software.SPDF.utils.RequestUriUtils;
|
||||
//
|
||||
////@Component
|
||||
//@Slf4j
|
||||
//public class FingerprintBasedSessionFilter extends OncePerRequestFilter {
|
||||
// private final FingerprintGenerator fingerprintGenerator;
|
||||
// private final FingerprintBasedSessionManager sessionManager;
|
||||
//
|
||||
// @Autowired
|
||||
// public FingerprintBasedSessionFilter(
|
||||
// FingerprintGenerator fingerprintGenerator,
|
||||
// FingerprintBasedSessionManager sessionManager) {
|
||||
// this.fingerprintGenerator = fingerprintGenerator;
|
||||
// this.sessionManager = sessionManager;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void doFilterInternal(
|
||||
// HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
// throws ServletException, IOException {
|
||||
//
|
||||
// if (RequestUriUtils.isStaticResource(request.getContextPath(), request.getRequestURI())) {
|
||||
// filterChain.doFilter(request, response);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// String fingerprint = fingerprintGenerator.generateFingerprint(request);
|
||||
// log.debug("Generated fingerprint for request: {}", fingerprint);
|
||||
//
|
||||
// HttpSession session = request.getSession();
|
||||
// boolean isNewSession = session.isNew();
|
||||
// String sessionId = session.getId();
|
||||
//
|
||||
// if (isNewSession) {
|
||||
// log.info("New session created: {}", sessionId);
|
||||
// }
|
||||
//
|
||||
// if (!sessionManager.isFingerPrintAllowed(fingerprint)) {
|
||||
// log.info("Blocked fingerprint detected, redirecting: {}", fingerprint);
|
||||
// response.sendRedirect(request.getContextPath() + "/too-many-requests");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// session.setAttribute("userFingerprint", fingerprint);
|
||||
// session.setAttribute(
|
||||
// FingerprintBasedSessionManager.STARTUP_TIMESTAMP,
|
||||
// FingerprintBasedSessionManager.APP_STARTUP_TIME);
|
||||
//
|
||||
// sessionManager.registerFingerprint(fingerprint, sessionId);
|
||||
//
|
||||
// log.debug("Proceeding with request: {}", request.getRequestURI());
|
||||
// filterChain.doFilter(request, response);
|
||||
// }
|
||||
//}
|
||||
|
@ -1,134 +1,134 @@
|
||||
package stirling.software.SPDF.config.fingerprint;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.servlet.http.HttpSessionAttributeListener;
|
||||
import jakarta.servlet.http.HttpSessionEvent;
|
||||
import jakarta.servlet.http.HttpSessionListener;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FingerprintBasedSessionManager
|
||||
implements HttpSessionListener, HttpSessionAttributeListener {
|
||||
private static final ConcurrentHashMap<String, FingerprintInfo> activeFingerprints =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
// To be reduced in later version to 8~
|
||||
private static final int MAX_ACTIVE_FINGERPRINTS = 30;
|
||||
|
||||
static final String STARTUP_TIMESTAMP = "appStartupTimestamp";
|
||||
static final long APP_STARTUP_TIME = System.currentTimeMillis();
|
||||
private static final long FINGERPRINT_EXPIRATION = TimeUnit.MINUTES.toMillis(30);
|
||||
|
||||
@Override
|
||||
public void sessionCreated(HttpSessionEvent se) {
|
||||
HttpSession session = se.getSession();
|
||||
String sessionId = session.getId();
|
||||
String fingerprint = (String) session.getAttribute("userFingerprint");
|
||||
|
||||
if (fingerprint == null) {
|
||||
log.warn("Session created without fingerprint: {}", sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (activeFingerprints) {
|
||||
if (activeFingerprints.size() >= MAX_ACTIVE_FINGERPRINTS
|
||||
&& !activeFingerprints.containsKey(fingerprint)) {
|
||||
log.info("Max fingerprints reached. Marking session as blocked: {}", sessionId);
|
||||
session.setAttribute("blocked", true);
|
||||
} else {
|
||||
activeFingerprints.put(
|
||||
fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis()));
|
||||
log.info(
|
||||
"New fingerprint registered: {}. Total active fingerprints: {}",
|
||||
fingerprint,
|
||||
activeFingerprints.size());
|
||||
}
|
||||
session.setAttribute(STARTUP_TIMESTAMP, APP_STARTUP_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionDestroyed(HttpSessionEvent se) {
|
||||
HttpSession session = se.getSession();
|
||||
String fingerprint = (String) session.getAttribute("userFingerprint");
|
||||
|
||||
if (fingerprint != null) {
|
||||
synchronized (activeFingerprints) {
|
||||
activeFingerprints.remove(fingerprint);
|
||||
log.info(
|
||||
"Fingerprint removed: {}. Total active fingerprints: {}",
|
||||
fingerprint,
|
||||
activeFingerprints.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFingerPrintAllowed(String fingerprint) {
|
||||
synchronized (activeFingerprints) {
|
||||
return activeFingerprints.size() < MAX_ACTIVE_FINGERPRINTS
|
||||
|| activeFingerprints.containsKey(fingerprint);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerFingerprint(String fingerprint, String sessionId) {
|
||||
synchronized (activeFingerprints) {
|
||||
activeFingerprints.put(
|
||||
fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterFingerprint(String fingerprint) {
|
||||
synchronized (activeFingerprints) {
|
||||
activeFingerprints.remove(fingerprint);
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 1800000) // Run every 30 mins
|
||||
public void cleanupStaleFingerprints() {
|
||||
log.info("Starting cleanup of stale fingerprints");
|
||||
long now = System.currentTimeMillis();
|
||||
int removedCount = 0;
|
||||
|
||||
synchronized (activeFingerprints) {
|
||||
Iterator<Map.Entry<String, FingerprintInfo>> iterator =
|
||||
activeFingerprints.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, FingerprintInfo> entry = iterator.next();
|
||||
FingerprintInfo info = entry.getValue();
|
||||
|
||||
if (now - info.getLastAccessTime() > FINGERPRINT_EXPIRATION) {
|
||||
iterator.remove();
|
||||
removedCount++;
|
||||
log.info("Removed stale fingerprint: {}", entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Cleanup complete. Removed {} stale fingerprints", removedCount);
|
||||
}
|
||||
|
||||
public void updateLastAccessTime(String fingerprint) {
|
||||
FingerprintInfo info = activeFingerprints.get(fingerprint);
|
||||
if (info != null) {
|
||||
info.setLastAccessTime(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
private static class FingerprintInfo {
|
||||
private String sessionId;
|
||||
private long lastAccessTime;
|
||||
}
|
||||
}
|
||||
//package stirling.software.SPDF.config.fingerprint;
|
||||
//
|
||||
//import java.util.Iterator;
|
||||
//import java.util.Map;
|
||||
//import java.util.concurrent.ConcurrentHashMap;
|
||||
//import java.util.concurrent.TimeUnit;
|
||||
//
|
||||
//import org.springframework.scheduling.annotation.Scheduled;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import jakarta.servlet.http.HttpSession;
|
||||
//import jakarta.servlet.http.HttpSessionAttributeListener;
|
||||
//import jakarta.servlet.http.HttpSessionEvent;
|
||||
//import jakarta.servlet.http.HttpSessionListener;
|
||||
//import lombok.AllArgsConstructor;
|
||||
//import lombok.Data;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//
|
||||
//@Slf4j
|
||||
//@Component
|
||||
//public class FingerprintBasedSessionManager
|
||||
// implements HttpSessionListener, HttpSessionAttributeListener {
|
||||
// private static final ConcurrentHashMap<String, FingerprintInfo> activeFingerprints =
|
||||
// new ConcurrentHashMap<>();
|
||||
//
|
||||
// // To be reduced in later version to 8~
|
||||
// private static final int MAX_ACTIVE_FINGERPRINTS = 30;
|
||||
//
|
||||
// static final String STARTUP_TIMESTAMP = "appStartupTimestamp";
|
||||
// static final long APP_STARTUP_TIME = System.currentTimeMillis();
|
||||
// private static final long FINGERPRINT_EXPIRATION = TimeUnit.MINUTES.toMillis(30);
|
||||
//
|
||||
// @Override
|
||||
// public void sessionCreated(HttpSessionEvent se) {
|
||||
// HttpSession session = se.getSession();
|
||||
// String sessionId = session.getId();
|
||||
// String fingerprint = (String) session.getAttribute("userFingerprint");
|
||||
//
|
||||
// if (fingerprint == null) {
|
||||
// log.warn("Session created without fingerprint: {}", sessionId);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// synchronized (activeFingerprints) {
|
||||
// if (activeFingerprints.size() >= MAX_ACTIVE_FINGERPRINTS
|
||||
// && !activeFingerprints.containsKey(fingerprint)) {
|
||||
// log.info("Max fingerprints reached. Marking session as blocked: {}", sessionId);
|
||||
// session.setAttribute("blocked", true);
|
||||
// } else {
|
||||
// activeFingerprints.put(
|
||||
// fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis()));
|
||||
// log.info(
|
||||
// "New fingerprint registered: {}. Total active fingerprints: {}",
|
||||
// fingerprint,
|
||||
// activeFingerprints.size());
|
||||
// }
|
||||
// session.setAttribute(STARTUP_TIMESTAMP, APP_STARTUP_TIME);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void sessionDestroyed(HttpSessionEvent se) {
|
||||
// HttpSession session = se.getSession();
|
||||
// String fingerprint = (String) session.getAttribute("userFingerprint");
|
||||
//
|
||||
// if (fingerprint != null) {
|
||||
// synchronized (activeFingerprints) {
|
||||
// activeFingerprints.remove(fingerprint);
|
||||
// log.info(
|
||||
// "Fingerprint removed: {}. Total active fingerprints: {}",
|
||||
// fingerprint,
|
||||
// activeFingerprints.size());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public boolean isFingerPrintAllowed(String fingerprint) {
|
||||
// synchronized (activeFingerprints) {
|
||||
// return activeFingerprints.size() < MAX_ACTIVE_FINGERPRINTS
|
||||
// || activeFingerprints.containsKey(fingerprint);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void registerFingerprint(String fingerprint, String sessionId) {
|
||||
// synchronized (activeFingerprints) {
|
||||
// activeFingerprints.put(
|
||||
// fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis()));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public void unregisterFingerprint(String fingerprint) {
|
||||
// synchronized (activeFingerprints) {
|
||||
// activeFingerprints.remove(fingerprint);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Scheduled(fixedRate = 1800000) // Run every 30 mins
|
||||
// public void cleanupStaleFingerprints() {
|
||||
// log.info("Starting cleanup of stale fingerprints");
|
||||
// long now = System.currentTimeMillis();
|
||||
// int removedCount = 0;
|
||||
//
|
||||
// synchronized (activeFingerprints) {
|
||||
// Iterator<Map.Entry<String, FingerprintInfo>> iterator =
|
||||
// activeFingerprints.entrySet().iterator();
|
||||
// while (iterator.hasNext()) {
|
||||
// Map.Entry<String, FingerprintInfo> entry = iterator.next();
|
||||
// FingerprintInfo info = entry.getValue();
|
||||
//
|
||||
// if (now - info.getLastAccessTime() > FINGERPRINT_EXPIRATION) {
|
||||
// iterator.remove();
|
||||
// removedCount++;
|
||||
// log.info("Removed stale fingerprint: {}", entry.getKey());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// log.info("Cleanup complete. Removed {} stale fingerprints", removedCount);
|
||||
// }
|
||||
//
|
||||
// public void updateLastAccessTime(String fingerprint) {
|
||||
// FingerprintInfo info = activeFingerprints.get(fingerprint);
|
||||
// if (info != null) {
|
||||
// info.setLastAccessTime(System.currentTimeMillis());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Data
|
||||
// @AllArgsConstructor
|
||||
// private static class FingerprintInfo {
|
||||
// private String sessionId;
|
||||
// private long lastAccessTime;
|
||||
// }
|
||||
//}
|
||||
|
@ -1,77 +1,77 @@
|
||||
package stirling.software.SPDF.config.fingerprint;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@Component
|
||||
public class FingerprintGenerator {
|
||||
|
||||
public String generateFingerprint(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder fingerprintBuilder = new StringBuilder();
|
||||
|
||||
// Add IP address
|
||||
fingerprintBuilder.append(request.getRemoteAddr());
|
||||
|
||||
// Add X-Forwarded-For header if present (for clients behind proxies)
|
||||
String forwardedFor = request.getHeader("X-Forwarded-For");
|
||||
if (forwardedFor != null) {
|
||||
fingerprintBuilder.append(forwardedFor);
|
||||
}
|
||||
|
||||
// Add User-Agent
|
||||
String userAgent = request.getHeader("User-Agent");
|
||||
if (userAgent != null) {
|
||||
fingerprintBuilder.append(userAgent);
|
||||
}
|
||||
|
||||
// Add Accept-Language header
|
||||
String acceptLanguage = request.getHeader("Accept-Language");
|
||||
if (acceptLanguage != null) {
|
||||
fingerprintBuilder.append(acceptLanguage);
|
||||
}
|
||||
|
||||
// Add Accept header
|
||||
String accept = request.getHeader("Accept");
|
||||
if (accept != null) {
|
||||
fingerprintBuilder.append(accept);
|
||||
}
|
||||
|
||||
// Add Connection header
|
||||
String connection = request.getHeader("Connection");
|
||||
if (connection != null) {
|
||||
fingerprintBuilder.append(connection);
|
||||
}
|
||||
|
||||
// Add server port
|
||||
fingerprintBuilder.append(request.getServerPort());
|
||||
|
||||
// Add secure flag
|
||||
fingerprintBuilder.append(request.isSecure());
|
||||
|
||||
// Generate a hash of the fingerprint
|
||||
return generateHash(fingerprintBuilder.toString());
|
||||
}
|
||||
|
||||
private String generateHash(String input) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] hash = digest.digest(input.getBytes());
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte b : hash) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) hexString.append('0');
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Failed to generate fingerprint hash", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
//package stirling.software.SPDF.config.fingerprint;
|
||||
//
|
||||
//import java.security.MessageDigest;
|
||||
//import java.security.NoSuchAlgorithmException;
|
||||
//
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import jakarta.servlet.http.HttpServletRequest;
|
||||
//
|
||||
//@Component
|
||||
//public class FingerprintGenerator {
|
||||
//
|
||||
// public String generateFingerprint(HttpServletRequest request) {
|
||||
// if (request == null) {
|
||||
// return "";
|
||||
// }
|
||||
// StringBuilder fingerprintBuilder = new StringBuilder();
|
||||
//
|
||||
// // Add IP address
|
||||
// fingerprintBuilder.append(request.getRemoteAddr());
|
||||
//
|
||||
// // Add X-Forwarded-For header if present (for clients behind proxies)
|
||||
// String forwardedFor = request.getHeader("X-Forwarded-For");
|
||||
// if (forwardedFor != null) {
|
||||
// fingerprintBuilder.append(forwardedFor);
|
||||
// }
|
||||
//
|
||||
// // Add User-Agent
|
||||
// String userAgent = request.getHeader("User-Agent");
|
||||
// if (userAgent != null) {
|
||||
// fingerprintBuilder.append(userAgent);
|
||||
// }
|
||||
//
|
||||
// // Add Accept-Language header
|
||||
// String acceptLanguage = request.getHeader("Accept-Language");
|
||||
// if (acceptLanguage != null) {
|
||||
// fingerprintBuilder.append(acceptLanguage);
|
||||
// }
|
||||
//
|
||||
// // Add Accept header
|
||||
// String accept = request.getHeader("Accept");
|
||||
// if (accept != null) {
|
||||
// fingerprintBuilder.append(accept);
|
||||
// }
|
||||
//
|
||||
// // Add Connection header
|
||||
// String connection = request.getHeader("Connection");
|
||||
// if (connection != null) {
|
||||
// fingerprintBuilder.append(connection);
|
||||
// }
|
||||
//
|
||||
// // Add server port
|
||||
// fingerprintBuilder.append(request.getServerPort());
|
||||
//
|
||||
// // Add secure flag
|
||||
// fingerprintBuilder.append(request.isSecure());
|
||||
//
|
||||
// // Generate a hash of the fingerprint
|
||||
// return generateHash(fingerprintBuilder.toString());
|
||||
// }
|
||||
//
|
||||
// private String generateHash(String input) {
|
||||
// try {
|
||||
// MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
// byte[] hash = digest.digest(input.getBytes());
|
||||
// StringBuilder hexString = new StringBuilder();
|
||||
// for (byte b : hash) {
|
||||
// String hex = Integer.toHexString(0xff & b);
|
||||
// if (hex.length() == 1) hexString.append('0');
|
||||
// hexString.append(hex);
|
||||
// }
|
||||
// return hexString.toString();
|
||||
// } catch (NoSuchAlgorithmException e) {
|
||||
// throw new RuntimeException("Failed to generate fingerprint hash", e);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
Loading…
x
Reference in New Issue
Block a user