package app.annotations.impl; import app.annotations.enums.AuthMethod; import app.annotations.exceptions.InvalidCookie; import app.annotations.exceptions.InvalidSecretKey; import app.annotations.exceptions.NeedCookie; import app.annotations.interfaces.CheckWebAccess; import app.entities.a2s.external.ExternalValveClient; import app.utils.SaltedCookie; import jakarta.servlet.http.HttpServletRequest; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.WebSocketSession; import java.io.IOException; import java.util.List; /** * АОП для обработки уровня доступа к ендпоинтам */ @Aspect @Configuration public class WebAccessAspect { SaltedCookie saltedCookie; private final Logger logger = LoggerFactory.getLogger(WebAccessAspect.class); private boolean enabled = true; @Autowired private HttpServletRequest request; @Autowired public WebAccessAspect(SaltedCookie saltedCookie) { this.saltedCookie = saltedCookie; if (System.getenv("DISABLE_AUTH") != null) this.enabled = !System.getenv("DISABLE_AUTH").equals("true"); if (!this.enabled) { logger.warn("!!!AUTH DISABLED!!!"); } } @Before("@annotation(app.annotations.interfaces.CheckWebAccess) && args(session,..)") public void before(JoinPoint joinPoint, WebSocketSession session) throws IOException { AuthMethod auth_method = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CheckWebAccess.class).auth_method(); if(!(session instanceof WebSocketSession)) { logger.error("Invalid websocket session"); session.close(CloseStatus.NOT_ACCEPTABLE); return; } if(session.getHandshakeHeaders().get("cookie") == null) { logger.warn("Session {} [{}] Request not contain cookies", session.getId(), session.getHandshakeHeaders().get("X-Forwarded-For")); session.close(CloseStatus.NOT_ACCEPTABLE); return; } List rawCookie = session.getHandshakeHeaders().get("cookie"); switch (auth_method) { case SECRET_KEY -> { String secret_key = ""; try { secret_key = rawCookie.stream().filter(s -> s.contains("secretkey=")).map(s -> s.split("=")[1]).findFirst().orElse(null); } catch (Exception e) { session.close(CloseStatus.NOT_ACCEPTABLE); } if(!saltedCookie.ValidateSecretKey(secret_key)){ logger.error("Invalid secret key on session {}", session.getId()); session.close(CloseStatus.NOT_ACCEPTABLE); } return; } default -> {session.close(CloseStatus.NOT_ACCEPTABLE);return;} } } @Before("@annotation(app.annotations.interfaces.CheckWebAccess)") public void before(JoinPoint joinPoint) { if (!enabled) return; AuthMethod auth_method = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CheckWebAccess.class).auth_method(); checkWebAccess(auth_method, this.request); } @Before("@annotation(app.annotations.interfaces.CheckWebAccess) && args(request,..)") public void before(JoinPoint joinPoint, HttpServletRequest request){ if (!enabled) return; AuthMethod auth_method = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CheckWebAccess.class).auth_method(); checkWebAccess(auth_method, request); } private void checkWebAccess(AuthMethod auth_method, HttpServletRequest request) { logger.info("check web access"); if(!(request instanceof HttpServletRequest)) { logger.error("Invalid request"); throw new RuntimeException("cannot read cookie from invalid request"); } if(request.getHeader("Cookie") == null) { logger.warn("[{}] Request not contain cookies", request.getHeader("X-Forwarded-For")); throw new NeedCookie(); } String[] rawCookieParams = request.getHeader("Cookie").split(";"); String steam64 = ""; String steam64_secured = ""; String secret_key = ""; try { for (String rawCookie : rawCookieParams) { if ((!steam64.isEmpty() && !steam64_secured.isEmpty() || (!steam64.isEmpty() && !secret_key.isEmpty()))) { break; } if (rawCookie.contains("steam64=")) { steam64 = rawCookie.split("=")[1]; continue; } if (rawCookie.contains("steam64_secured=")) { steam64_secured = rawCookie.split("=")[1]; continue; } if (rawCookie.contains("secretkey=")) { secret_key = rawCookie.split("=")[1]; continue; } } } catch (Exception e) { throw new InvalidSecretKey(); } switch (auth_method){ case COMBINED -> { if (!secret_key.isEmpty() && !steam64.isEmpty()) { if (saltedCookie.ValidateSecretKey(secret_key)) { logger.info("used secret key with steamid: {}", steam64); return; } else { logger.warn("[{}] Request contain invalid secret key: {}, requested steam64: {}", request.getHeader("X-Forwarded-For"), secret_key, steam64); throw new InvalidSecretKey(); } } CheckSteamID(steam64, steam64_secured); } case SECRET_KEY -> { if (secret_key.isEmpty()) throw new InvalidSecretKey(); if (saltedCookie.ValidateSecretKey(secret_key)) { logger.info("used secret key without steamid"); return; } else { logger.warn("[{}] Request contain invalid secret key: {}", request.getHeader("X-Forwarded-For"), secret_key); throw new InvalidSecretKey(); } } case STEAM64 -> { CheckSteamID(steam64, steam64_secured); } } } public void CheckSteamID(String steam64, String steam64_secured) { if (steam64.isEmpty() || steam64_secured.isEmpty()) { throw new NeedCookie(); } if (!saltedCookie.Validate(steam64, steam64_secured)) { throw new InvalidCookie(); } } }