Stop ActiveCookieStore from logging database exception on plugin disable

Affects issues:
- Fixed #2188
This commit is contained in:
Aurora Lahtela 2022-05-07 09:26:54 +03:00
parent 64146cc6eb
commit 55ceeb3ad2
5 changed files with 54 additions and 20 deletions

View File

@ -18,12 +18,14 @@ package com.djrapitops.plan.delivery.webserver.auth;
import com.djrapitops.plan.SubSystem; import com.djrapitops.plan.SubSystem;
import com.djrapitops.plan.delivery.domain.auth.User; import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.processing.Processing; import com.djrapitops.plan.processing.Processing;
import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.config.paths.WebserverSettings; import com.djrapitops.plan.settings.config.paths.WebserverSettings;
import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries; import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries;
import com.djrapitops.plan.storage.database.transactions.events.CookieChangeTransaction; import com.djrapitops.plan.storage.database.transactions.events.CookieChangeTransaction;
import net.playeranalytics.plugin.server.PluginLogger;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import javax.inject.Inject; import javax.inject.Inject;
@ -38,24 +40,26 @@ import java.util.concurrent.TimeUnit;
public class ActiveCookieStore implements SubSystem { public class ActiveCookieStore implements SubSystem {
private static final Map<String, User> USERS_BY_COOKIE = new ConcurrentHashMap<>(); private static final Map<String, User> USERS_BY_COOKIE = new ConcurrentHashMap<>();
public static long cookieExpiresAfter = TimeUnit.HOURS.toMillis(2L); public static long cookieExpiresAfterMs = TimeUnit.HOURS.toMillis(2L);
private static ActiveCookieStore activeCookieStore;
private final ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask; private final ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask;
private final PlanConfig config; private final PlanConfig config;
private final DBSystem dbSystem; private final DBSystem dbSystem;
private final Processing processing; private final Processing processing;
private final PluginLogger logger;
@Inject @Inject
public ActiveCookieStore( public ActiveCookieStore(
ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask, ActiveCookieExpiryCleanupTask activeCookieExpiryCleanupTask,
PlanConfig config, PlanConfig config,
DBSystem dbSystem, DBSystem dbSystem,
Processing processing Processing processing,
PluginLogger logger
) { ) {
this.logger = logger;
Holder.setActiveCookieStore(this);
this.activeCookieExpiryCleanupTask = activeCookieExpiryCleanupTask; this.activeCookieExpiryCleanupTask = activeCookieExpiryCleanupTask;
ActiveCookieStore.activeCookieStore = this;
this.config = config; this.config = config;
this.dbSystem = dbSystem; this.dbSystem = dbSystem;
@ -63,7 +67,7 @@ public class ActiveCookieStore implements SubSystem {
} }
private static void removeCookieStatic(String cookie) { private static void removeCookieStatic(String cookie) {
activeCookieStore.removeCookie(cookie); Holder.getActiveCookieStore().removeCookie(cookie);
} }
public static void removeUserCookie(String username) { public static void removeUserCookie(String username) {
@ -73,19 +77,28 @@ public class ActiveCookieStore implements SubSystem {
.ifPresent(ActiveCookieStore::removeCookieStatic); .ifPresent(ActiveCookieStore::removeCookieStatic);
} }
private static void setCookiesExpireAfter(Long expireAfterMs) {
cookieExpiresAfterMs = expireAfterMs;
}
@Override @Override
public void enable() { public void enable() {
cookieExpiresAfter = config.get(WebserverSettings.COOKIES_EXPIRE_AFTER); ActiveCookieStore.setCookiesExpireAfter(config.get(WebserverSettings.COOKIES_EXPIRE_AFTER));
processing.submitNonCritical(this::loadActiveCookies); processing.submitNonCritical(this::loadActiveCookies);
} }
private void loadActiveCookies() { private void loadActiveCookies() {
USERS_BY_COOKIE.clear(); USERS_BY_COOKIE.clear();
try {
USERS_BY_COOKIE.putAll(dbSystem.getDatabase().query(WebUserQueries.fetchActiveCookies())); USERS_BY_COOKIE.putAll(dbSystem.getDatabase().query(WebUserQueries.fetchActiveCookies()));
for (Map.Entry<String, Long> entry : dbSystem.getDatabase().query(WebUserQueries.getCookieExpiryTimes()).entrySet()) { for (Map.Entry<String, Long> entry : dbSystem.getDatabase().query(WebUserQueries.getCookieExpiryTimes()).entrySet()) {
long timeToExpiry = Math.max(entry.getValue() - System.currentTimeMillis(), 0L); long timeToExpiry = Math.max(entry.getValue() - System.currentTimeMillis(), 0L);
activeCookieExpiryCleanupTask.addExpiry(entry.getKey(), System.currentTimeMillis() + timeToExpiry); activeCookieExpiryCleanupTask.addExpiry(entry.getKey(), System.currentTimeMillis() + timeToExpiry);
} }
} catch (DBOpException databaseClosedUnexpectedly) {
logger.info("Database closed unexpectedly so active cookies could not be loaded.");
// Safe to ignore https://github.com/plan-player-analytics/Plan/issues/2188
}
} }
@Override @Override
@ -101,13 +114,13 @@ public class ActiveCookieStore implements SubSystem {
String cookie = DigestUtils.sha256Hex(user.getUsername() + UUID.randomUUID() + System.currentTimeMillis()); String cookie = DigestUtils.sha256Hex(user.getUsername() + UUID.randomUUID() + System.currentTimeMillis());
USERS_BY_COOKIE.put(cookie, user); USERS_BY_COOKIE.put(cookie, user);
saveNewCookie(user, cookie, System.currentTimeMillis()); saveNewCookie(user, cookie, System.currentTimeMillis());
activeCookieExpiryCleanupTask.addExpiry(cookie, System.currentTimeMillis() + cookieExpiresAfter); activeCookieExpiryCleanupTask.addExpiry(cookie, System.currentTimeMillis() + cookieExpiresAfterMs);
return cookie; return cookie;
} }
private void saveNewCookie(User user, String cookie, long now) { private void saveNewCookie(User user, String cookie, long now) {
dbSystem.getDatabase().executeTransaction(CookieChangeTransaction.storeCookie( dbSystem.getDatabase().executeTransaction(CookieChangeTransaction.storeCookie(
user.getUsername(), cookie, now + cookieExpiresAfter user.getUsername(), cookie, now + cookieExpiresAfterMs
)); ));
} }
@ -127,4 +140,18 @@ public class ActiveCookieStore implements SubSystem {
disable(); disable();
dbSystem.getDatabase().executeTransaction(CookieChangeTransaction.removeAll()); dbSystem.getDatabase().executeTransaction(CookieChangeTransaction.removeAll());
} }
public static class Holder {
private static ActiveCookieStore activeCookieStore;
private Holder() {}
public static ActiveCookieStore getActiveCookieStore() {
return activeCookieStore;
}
public static void setActiveCookieStore(ActiveCookieStore activeCookieStore) {
Holder.activeCookieStore = activeCookieStore;
}
}
} }

View File

@ -64,7 +64,7 @@ public class LoginResolver implements NoAuthResolver {
public Response getResponse(String cookie) { public Response getResponse(String cookie) {
return Response.builder() return Response.builder()
.setStatus(200) .setStatus(200)
.setHeader("Set-Cookie", "auth=" + cookie + "; Path=/; Max-Age=" + ActiveCookieStore.cookieExpiresAfter + "; SameSite=Lax; Secure;") .setHeader("Set-Cookie", "auth=" + cookie + "; Path=/; Max-Age=" + ActiveCookieStore.cookieExpiresAfterMs + "; SameSite=Lax; Secure;")
.setJSONContent(Collections.singletonMap("success", true)) .setJSONContent(Collections.singletonMap("success", true))
.build(); .build();
} }

View File

@ -80,9 +80,9 @@ public abstract class Transaction {
try { try {
initializeConnection(db); initializeConnection(db);
if (shouldBeExecuted()) { if (shouldBeExecuted()) {
initializeTransaction(db); initializeTransaction();
if (this instanceof Patch) { if (this instanceof Patch) {
db.getLogger().info(db.getLocale().getString(PluginLang.DB_APPLY_PATCH, getClass().getSimpleName())); db.getLogger().info(db.getLocale().getString(PluginLang.DB_APPLY_PATCH, getName()));
} }
performOperations(); performOperations();
if (connection != null) connection.commit(); if (connection != null) connection.commit();
@ -171,7 +171,7 @@ public abstract class Transaction {
} }
} }
private void initializeTransaction(SQLDB db) { private void initializeTransaction() {
try { try {
createSavePoint(); createSavePoint();
} catch (SQLException e) { } catch (SQLException e) {
@ -269,4 +269,9 @@ public abstract class Transaction {
public boolean dbIsNotUnderHeavyLoad() { public boolean dbIsNotUnderHeavyLoad() {
return !db.isUnderHeavyLoad(); return !db.isUnderHeavyLoad();
} }
public String getName() {
String simpleName = getClass().getSimpleName();
return simpleName.isEmpty() ? getClass().getName() : simpleName;
}
} }

View File

@ -28,6 +28,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import utilities.TestConstants; import utilities.TestConstants;
import utilities.TestPluginLogger;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
@ -48,8 +49,8 @@ class ActiveCookieStoreTest {
Mockito.mock(ActiveCookieExpiryCleanupTask.class), Mockito.mock(ActiveCookieExpiryCleanupTask.class),
Mockito.mock(PlanConfig.class), Mockito.mock(PlanConfig.class),
dbSystem, dbSystem,
Mockito.mock(Processing.class) Mockito.mock(Processing.class),
); new TestPluginLogger());
user = new User(TestConstants.PLAYER_ONE_NAME, "console", null, PassEncryptUtil.createHash("testPass"), 0, WebUser.getPermissionsForLevel(0)); user = new User(TestConstants.PLAYER_ONE_NAME, "console", null, PassEncryptUtil.createHash("testPass"), 0, WebUser.getPermissionsForLevel(0));
} }

View File

@ -31,6 +31,7 @@ import com.djrapitops.plan.utilities.PassEncryptUtil;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import utilities.TestConstants; import utilities.TestConstants;
import utilities.TestPluginLogger;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
@ -122,8 +123,8 @@ public interface WebUserQueriesTest extends DatabaseTestPreparer {
Mockito.mock(ActiveCookieExpiryCleanupTask.class), Mockito.mock(ActiveCookieExpiryCleanupTask.class),
Mockito.mock(PlanConfig.class), Mockito.mock(PlanConfig.class),
dbSystem(), dbSystem(),
Mockito.mock(Processing.class) Mockito.mock(Processing.class),
); new TestPluginLogger());
} }
@Test @Test