Skip to content

Commit

Permalink
Accomodate unrecorded IP address in applicability calculation
Browse files Browse the repository at this point in the history
Plus a couple tweaks to code style
  • Loading branch information
A248 committed Mar 5, 2024
1 parent 75eaf01 commit 8ad0d65
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* LibertyBans
* Copyright © 2022 Anand Beh
* Copyright © 2024 Anand Beh
*
* LibertyBans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -77,6 +77,9 @@ public interface PunishmentSelector {
* the player's UUID and IP. It may be, the player's IP is banned, the player's UUID is banned,
* or the player has played on a banned IP and that IP is banned while strict address enforcement is enabled. <br>
* <br>
* For maximum accuracy, the UUID and IP address pair should be taken from an actual user who has logged on before.
* Due to specifics in terms of how applicability is computed, some punishments
* <br>
* By default, the server's configured address strictness is used, but this may be changed if desired.
*
* @param uuid the uuid of the user for whom to select applicable punishments
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* LibertyBans
* Copyright © 2023 Anand Beh
* Copyright © 2024 Anand Beh
*
* LibertyBans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -31,7 +31,6 @@
import space.arim.libertybans.core.scope.ScopeType;

import java.time.Instant;
import java.util.Objects;
import java.util.UUID;

public record ApplicableViewFields<R extends Record14<
Expand Down Expand Up @@ -111,7 +110,11 @@ public Field<ScopeType> scopeType() {
}

public Field<UUID> uuid() {
return Objects.requireNonNull(fieldSupplier.field11(), "uuid field does not exist");
return fieldSupplier.field11();
}

public Field<NetworkAddress> address() {
return fieldSupplier.field12();
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* LibertyBans
* Copyright © 2022 Anand Beh
* Copyright © 2024 Anand Beh
*
* LibertyBans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -152,8 +152,8 @@ interface AltsRegistry {
"If you are planning to use this feature, make sure to have enabled 'enforce-server-switch' option."
})
@ConfKey("servers-without-ip-registration")
@DefaultStrings("")
List<String> servers();
@DefaultStrings({"auth"})
List<String> serversWithoutRegistration();

@ConfComments({"If you want to register the IP address of the player connecting, set this to true.",
"If you are running a Proxy and don't want to register the IP when players connect, ",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* LibertyBans
* Copyright © 2023 Anand Beh
* Copyright © 2024 Anand Beh
*
* LibertyBans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -78,13 +78,15 @@ CentralisedFuture<Component> executeAndCheckConnection(UUID uuid, String name, N
Instant currentTime = time.currentTimestamp();
EnforcementConfig config = configs.getMainConfig().enforcement();

if (config.altsRegistry().shouldRegisterOnConnection()) {
boolean recordUserAssociation = config.altsRegistry().shouldRegisterOnConnection();
if (recordUserAssociation) {
doAssociation(uuid, name, address, currentTime, context);
}

Punishment ban = selector.selectionByApplicabilityBuilder(uuid, address)
.type(PunishmentType.BAN)
.scopes(SelectionPredicate.matchingAnyOf(scopes))
.canAssumeUserRecorded(recordUserAssociation)
.build()
.findFirstSpecificPunishment(context, () -> currentTime, SortPunishments.LATEST_END_DATE_FIRST);
if (ban != null) {
Expand Down Expand Up @@ -124,10 +126,11 @@ CentralisedFuture<Component> executeAndCheckConnection(UUID uuid, String name, N
}

return queryExecutor.get().queryWithRetry((context, transaction) -> {
boolean shouldRegister = configs.getMainConfig().enforcement().altsRegistry().shouldRegisterOnConnection();
List<String> servers = configs.getMainConfig().enforcement().altsRegistry().servers();
var altsRegistry = configs.getMainConfig().enforcement().altsRegistry();
boolean registerOnConnection = altsRegistry.shouldRegisterOnConnection();
List<String> serversWithoutAssociation = altsRegistry.serversWithoutRegistration();

if (!shouldRegister && !servers.contains(destinationServer)) {
if (!registerOnConnection && !serversWithoutAssociation.contains(destinationServer)) {
doAssociation(uuid, name, address, time.currentTimestamp(), context);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* LibertyBans
* Copyright © 2023 Anand Beh
* Copyright © 2024 Anand Beh
*
* LibertyBans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -39,6 +39,7 @@ public final class SelectionByApplicabilityBuilderImpl
private final NetworkAddress address;
private AddressStrictness strictness;
private final AddressStrictness defaultStrictness;
private boolean potentialNewEntrant;

SelectionByApplicabilityBuilderImpl(SelectionResources resources,
UUID uuid, NetworkAddress address, AddressStrictness defaultStrictness) {
Expand Down Expand Up @@ -68,7 +69,7 @@ SelectionByApplicabilityBuilder yieldSelf() {
@Override
SelectionByApplicability buildWith(SelectionBaseImpl.Details details) {
return new SelectionByApplicabilityImpl(
details, resources, uuid, address, strictness
details, resources, uuid, address, strictness, potentialNewEntrant
);
}

Expand All @@ -89,4 +90,17 @@ public SelectionByApplicabilityImpl build() {
return (SelectionByApplicabilityImpl) super.build();
}

/**
* For internal use, to accomodate a new user whose UUID and IP address combination
* has not yet been entered to the database. Sets whether this scenario is potential.
*
* @param canAssumeUserRecorded if the user is definitely registered, set to true. True by default.
* @return this builder
*/
public SelectionByApplicabilityBuilderImpl canAssumeUserRecorded(boolean canAssumeUserRecorded) {
// A user is a potential new entrant if we can't assume they're recorded
this.potentialNewEntrant = !canAssumeUserRecorded;
return this;
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* LibertyBans
* Copyright © 2023 Anand Beh
* Copyright © 2024 Anand Beh
*
* LibertyBans is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -38,20 +38,24 @@
import java.util.UUID;

import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.or;
import static space.arim.libertybans.core.schema.tables.StrictLinks.STRICT_LINKS;

public final class SelectionByApplicabilityImpl extends SelectionBaseSQL implements SelectionByApplicability {

private final UUID uuid;
private final NetworkAddress address;
private final AddressStrictness strictness;
private final boolean potentialNewEntrant;

SelectionByApplicabilityImpl(Details details, SelectionResources resources,
UUID uuid, NetworkAddress address, AddressStrictness strictness) {
UUID uuid, NetworkAddress address, AddressStrictness strictness,
boolean potentialNewEntrant) {
super(details, resources);
this.uuid = Objects.requireNonNull(uuid, "uuid");
this.address = Objects.requireNonNull(address, "address");
this.strictness = Objects.requireNonNull(strictness, "strictness");
this.potentialNewEntrant = potentialNewEntrant;
}

@Override
Expand All @@ -69,6 +73,16 @@ public AddressStrictness getAddressStrictness() {
return strictness;
}

/*
If the potentialNewEntrant flag is set, our task becomes significantly more complicated.
We now have to account for the enforcement of non-lenient address strictness by acting as if
the user had their IP address recorded already. This means attaching additional predication
to scans for IP-based punishments and patching over the applicability links we are accustomed
to having the database account for.
Thanks to SnakeAmazing for providing this marvelous intellectual puzzle.
*/

@Override
Query<?> requestQuery(QueryParameters parameters) {
PunishmentFields fields = null;
Expand All @@ -83,21 +97,74 @@ Query<?> requestQuery(QueryParameters parameters) {
ApplicableViewFields<?> applView = requestApplicableView();
fields = applView;
table = fields.table();
if (potentialNewEntrant) {
// appl.uuid = uuid
// OR victim_type != 'PLAYER' AND victim_address = address
//
// Note: It must be victim_address and not appl.address
// Exercise for understanding: Why?
//
yield or(
applView.uuid().eq(uuid),
applView.victimType().notEqual(inline(VictimType.PLAYER))
.and(applView.victimAddress().eq(address))
);
}
yield applView.uuid().eq(uuid); // appl.uuid = uuid
}
case STERN -> {
if (potentialNewEntrant) {
ApplicableViewFields<?> applView = requestApplicableView();
fields = applView;
table = fields
.table()
.leftJoin(STRICT_LINKS)
.on(applView.uuid().eq(STRICT_LINKS.UUID1));
// appl.uuid = uuid # NORMAL
// OR victim_type != 'PLAYER' AND (
// appl.address = address # NORMAL + STERN
// OR strict_links.uuid2 IS NOT NULL AND strict_links.uuid2 = uuid # STERN
// )
//
// Note: The last predicate must use appl.address and not victim_address
// Exercise for understanding: Why?
//
yield or(
applView.uuid().eq(uuid),
applView.victimType().notEqual(inline(VictimType.PLAYER)).and(or(
STRICT_LINKS.UUID2.isNotNull().and(STRICT_LINKS.UUID2.eq(uuid)),
applView.address().eq(address)
))
);
}
ApplicableViewFields<?> applView = requestApplicableView();
fields = applView;
table = fields
.table()
.innerJoin(STRICT_LINKS)
.on(applView.uuid().eq(STRICT_LINKS.UUID1));
// appl.uuid = strict_links.uuid1 = uuid
// OR victim_type != 'PLAYER' AND strict_links.uuid2 = uuid
// appl.uuid = strict_links.uuid1 = uuid # NORMAL
// OR victim_type != 'PLAYER' AND strict_links.uuid2 = uuid # STERN
yield STRICT_LINKS.UUID1.eq(uuid).or(
STRICT_LINKS.UUID2.eq(uuid).and(applView.victimType().notEqual(inline(VictimType.PLAYER))));
}
case STRICT -> {
if (potentialNewEntrant) {
ApplicableViewFields<?> applView = requestApplicableView();
fields = applView;
table = fields
.table()
.leftJoin(STRICT_LINKS)
.on(applView.uuid().eq(STRICT_LINKS.UUID1));
// appl.uuid = uuid # NORMAL
// OR appl.address = address # NORMAL + STRICT
// OR strict_links.uuid2 IS NOT NULL AND strict_links.uuid2 = uuid # STRICT
yield or(
applView.uuid().eq(uuid),
applView.address().eq(address),
STRICT_LINKS.UUID2.isNotNull().and(STRICT_LINKS.UUID2.eq(uuid))
);
}
ApplicableViewFields<?> applView = requestApplicableView();
fields = applView;
table = fields
Expand Down

0 comments on commit 8ad0d65

Please sign in to comment.