host.anzo.core.webserver.WebService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-core Show documentation
Show all versions of commons-core Show documentation
Commons library to make me happy.
package host.anzo.core.webserver;
import com.google.gson.Gson;
import de.mxro.metrics.jre.Metrics;
import delight.async.properties.PropertyNode;
import host.anzo.classindex.ClassIndex;
import host.anzo.commons.concurrent.CloseableReentrantLock;
import host.anzo.commons.emergency.metric.IMetric;
import host.anzo.commons.emergency.metric.Metric;
import host.anzo.commons.emergency.metric.MetricGroupType;
import host.anzo.commons.emergency.metric.MetricResult;
import host.anzo.commons.model.enums.ERestrictionType;
import host.anzo.commons.utils.ConsoleUtils;
import host.anzo.commons.utils.VMUtils;
import host.anzo.core.config.EmergencyConfig;
import host.anzo.core.config.WebServerConfig;
import host.anzo.core.service.FirewallService;
import host.anzo.core.service.HttpService;
import host.anzo.core.startup.StartupComponent;
import host.anzo.core.webserver.engine.ThymeleafTemplateEngine;
import host.anzo.core.webserver.model.AWebArea;
import host.anzo.core.webserver.model.WebArea;
import host.anzo.core.webserver.model.WebSocketsArea;
import host.anzo.core.webserver.model.captcha.ReCaptchaResponse;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.jakarta.JakartaServletDiskFileUpload;
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import spark.Spark;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @author ANZO
* @since 18.08.2016
*/
@Slf4j
@Metric
@StartupComponent("AfterStart")
public class WebService implements IMetric {
@Getter(lazy = true)
private final static WebService instance = new WebService();
private @Getter ThymeleafTemplateEngine templateEngine;
private @Getter JakartaServletFileUpload fileUploadServlet;
private final static PropertyNode webMetrics = Metrics.create();
private final static Gson gson = new Gson();
private final ConcurrentHashMap lockersMap = new ConcurrentHashMap<>();
private WebService() {
ConsoleUtils.printSection("WebService Loading");
if (WebServerConfig.ENABLE) {
if (WebServerConfig.USE_FIDDLER_PROXY) {
System.setProperty("http.proxyHost", "127.0.0.1");
System.setProperty("https.proxyHost", "127.0.0.1");
System.setProperty("http.proxyPort", "18888");
System.setProperty("https.proxyPort", "18888");
System.setProperty("javax.net.ssl.trustStoreType","Windows-ROOT");
}
templateEngine = new ThymeleafTemplateEngine();
fileUploadServlet = new JakartaServletDiskFileUpload();
init();
}
else {
log.info("Embedded webserver disabled due config.");
}
}
private void init() {
if (StringUtils.isNoneEmpty(WebServerConfig.DATA_PATH)) {
try {
Files.createDirectories(Paths.get(WebServerConfig.DATA_PATH));
} catch (IOException e) {
throw new RuntimeException("Error while creating web root directory.", e);
}
Spark.staticFiles.externalLocation(WebServerConfig.DATA_PATH);
}
else {
log.info("Web server static files folder not defined. Ignoring.");
}
if (!WebServerConfig.DEBUG && !VMUtils.DEBUG) {
Spark.staticFiles.expireTime(600);
}
if (WebServerConfig.ALLOW_ONLY_CLOUDFLARE_IPS) {
Spark.untrustForwardHeaders();
}
if (WebServerConfig.ENABLE_HTTP2) {
Spark.useHTTP2(true);
}
Spark.port(WebServerConfig.PORT);
if (WebServerConfig.ENABLE_SOCKETS) {
for(Class> webSocketAreaClass : ClassIndex.getAnnotated(WebSocketsArea.class)) {
final WebSocketsArea webSocketsAreaAnnotation = webSocketAreaClass.getAnnotation(WebSocketsArea.class);
Spark.webSocket(webSocketsAreaAnnotation.path(), webSocketAreaClass);
log.info("Registered [{}] web sockets area at path [{}]", webSocketAreaClass.getSimpleName(), webSocketsAreaAnnotation.path());
}
}
if (WebServerConfig.ENABLE_SSL) {
try {
final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
try (final FileInputStream jksInputStream = (new FileInputStream(WebServerConfig.SSL_STORE_PATH))) {
keystore.load(jksInputStream, WebServerConfig.SSL_STORE_PASSWORD.toCharArray());
final Enumeration aliases = keystore.aliases();
while (aliases.hasMoreElements()) {
final String aliasName = aliases.nextElement();
final Date certExpiryDate = ((X509Certificate) keystore.getCertificate(aliasName)).getNotAfter();
final long dateDiff = certExpiryDate.getTime() - new Date().getTime();
final long expiresIn = dateDiff / TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS);
if (expiresIn <= 0) {
throw new RuntimeException("Certificate for alias [" + aliasName + "] is expired (valid until [" + certExpiryDate + "])");
}
else {
if (expiresIn > 30) {
log.info("Loaded certificate for alias [{}] with expire date [{}]", aliasName, certExpiryDate);
}
else {
log.warn("Certificate for alias [{}] will expire on [{}] ({} days left)", aliasName, certExpiryDate, expiresIn);
}
}
}
}
}
catch (Exception e) {
log.error("Error while loading web certificate", e);
}
Spark.secure(WebServerConfig.SSL_STORE_PATH, WebServerConfig.SSL_STORE_PASSWORD, null, null);
}
Spark.threadPool(WebServerConfig.THREAD_COUNT_MAX, WebServerConfig.THREAD_COUNT_MIN, WebServerConfig.TIMEOUT);
for(Class> webAreaClass : ClassIndex.getAnnotated(WebArea.class)) {
try {
final AWebArea webArea = (AWebArea)webAreaClass.getDeclaredConstructor().newInstance();
webArea.registerPaths();
log.info("Registered [{}] web area", webAreaClass.getSimpleName());
}
catch (Exception e) {
log.error("Error while registering web area [{}]", webAreaClass.getSimpleName(), e);
}
}
Spark.awaitInitialization();
}
public void onRequest(boolean authentificated) {
if (EmergencyConfig.ENABLE_METRICS) {
webMetrics.record(Metrics.increment(authentificated ? "authentificated" : "non-authentificated"));
}
}
/**
* @param ip client IP address
* @return {@code true} if request is passed firewall checks, {@code false} otherwise
*/
public boolean isAllowedAddress(String ip) {
if (!WebServerConfig.ENABLE_REQUEST_LIMITER) {
return true;
}
return FirewallService.getInstance().isAllowedAddress(WebService.class, ip, WebServerConfig.PORT, WebServerConfig.MAX_REQUESTS_PER_SECOND, ERestrictionType.BAN);
}
public CloseableReentrantLock getLock(long userNo) {
return lockersMap.computeIfAbsent(userNo, newLock -> new CloseableReentrantLock());
}
/**
* @return new captcha HTML object for displaying on page
*/
@SuppressWarnings("unused")
public String createReCaptcha() {
if (!WebServerConfig.RECAPTCHA_ENABLE) {
return "";
}
return "";
}
/**
* @param remoteIp client IP address
* @param response client captcha challenge answer
* @return challenge result for captcha, verified by google service
*/
@SuppressWarnings("unused")
public ReCaptchaResponse checkReCaptchaAnswer(String remoteIp, String response) {
if (!WebServerConfig.RECAPTCHA_ENABLE) {
return null;
}
final String postParameters = "secret=" + URLEncoder.encode(WebServerConfig.RECAPTCHA_PRIVATE_KEY) + "&remoteip=" + URLEncoder.encode(remoteIp) + "&response=" + URLEncoder.encode(response);
final String message = HttpService.getInstance().httpPost("https://www.google.com/recaptcha/api/siteverify", postParameters);
if (message == null) {
return new ReCaptchaResponse(false);
}
return gson.fromJson(message, ReCaptchaResponse.class);
}
@Override
public List getMetric() {
final MetricResult result = new MetricResult();
result.setMetricGroupType(MetricGroupType.WEB);
result.setName("WebServiceRequests");
result.setData(webMetrics.render().get());
return Collections.singletonList(result);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy