Add a delay for disabling mods in bulk

This commit is contained in:
zontreck 2024-11-23 19:52:37 -07:00
parent b2a7493539
commit 3b7876532b
10 changed files with 57 additions and 39 deletions

View file

@ -1,3 +1,3 @@
class Consts { class Consts {
static const VERSION = "1.1.112324.1803"; static const VERSION = "1.1.112324.1951";
} }

View file

@ -89,10 +89,11 @@ class ServerPage extends StatelessWidget {
int retryCount = 0; int retryCount = 0;
while (true) { while (true) {
try { try {
if (retryCount > 0) if (retryCount > 0) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text( content: Text(
"> Retrying to download settings in 10 seconds (Attempt $retryCount"))); "> Retrying to download settings in 10 seconds (Attempt $retryCount")));
}
await Future.delayed(Duration(seconds: 10)); await Future.delayed(Duration(seconds: 10));
S2CResponse settingsData = await settings.client! S2CResponse settingsData = await settings.client!

View file

@ -106,12 +106,12 @@ class C2SLoginPacket implements IPacket {
// Attempt to log in. // Attempt to log in.
Settings settings = Settings(); Settings settings = Settings();
if (settings.superuser!.login(username, password)) { if (settings.superuser.login(username, password)) {
settings.remoteLoginToken = UUID.generate(4); settings.remoteLoginToken = UUID.generate(4);
loginReply.valid = true; loginReply.valid = true;
loginReply.token = settings.remoteLoginToken; loginReply.token = settings.remoteLoginToken;
settings.superuser!.sendDiscordActionLog("Login Success"); settings.superuser.sendDiscordActionLog("Login Success");
settings.loggedInUser = settings.superuser; settings.loggedInUser = settings.superuser;
} else { } else {
@ -121,7 +121,7 @@ class C2SLoginPacket implements IPacket {
// Properly handle the disabled account // Properly handle the disabled account
if (loginReply.valid && username == "_disabled") loginReply.valid = false; if (loginReply.valid && username == "_disabled") loginReply.valid = false;
if (!loginReply.valid && settings.superuser!.name != username) { if (!loginReply.valid && settings.superuser.name != username) {
// Check for a lower level user // Check for a lower level user
if (settings.inst!.admins.any((T) => T.name == username)) { if (settings.inst!.admins.any((T) => T.name == username)) {
User theUser = User theUser =
@ -358,12 +358,20 @@ class C2SUploadSettingsPacket implements IPacket {
// Send a webhook with all the mods listed // Send a webhook with all the mods listed
String modListText = ""; String modListText = "";
for (var entry in settings.inst!.mods) { for (var entry in settings.inst!.mods) {
modListText += "${entry.mod_name}\n"; if (entry.enabled) modListText += "${entry.mod_name}\n";
} }
modListText = modListText.trim(); modListText = modListText.trim();
DiscordHookHelper.sendWebHook(settings.inst!.discord, if (modListText.isEmpty) {
DiscordHookProps.INACTIVE, "Mod List", modListText); DiscordHookHelper.sendWebHook(
settings.inst!.discord,
DiscordHookProps.INACTIVE,
"Mod List",
"The Server is currently vanilla");
} else {
DiscordHookHelper.sendWebHook(settings.inst!.discord,
DiscordHookProps.INACTIVE, "Mod List", modListText);
}
// Check if server is running, if not, stop immediately // Check if server is running, if not, stop immediately
// If server is running, schedule restart for 1 minute and send a alert to all players, then perform stop or restart depending on if running in Pterodactyl Compatibility mode // If server is running, schedule restart for 1 minute and send a alert to all players, then perform stop or restart depending on if running in Pterodactyl Compatibility mode
@ -456,7 +464,7 @@ class C2SRequestCreateBackup implements IPacket {
world.copy(pth.build()); world.copy(pth.build());
settings.loggedInUser! settings.loggedInUser!
.sendDiscordActionLog("Created a new backup named ${fileName}"); .sendDiscordActionLog("Created a new backup named $fileName");
} }
return PacketResponse.nil; return PacketResponse.nil;
@ -651,7 +659,7 @@ class C2SRequestSnapshotDeletion implements IPacket {
ph.deleteFile(); ph.deleteFile();
settings.loggedInUser!.sendDiscordActionLog( settings.loggedInUser!.sendDiscordActionLog(
"Requested snapshot deletion of backup named: ${snapshotName}"); "Requested snapshot deletion of backup named: $snapshotName");
return PacketResponse.nil; return PacketResponse.nil;
} }
@ -714,7 +722,7 @@ class C2SRequestWorldRestore implements IPacket {
SessionData.CURRENT_INTERVAL = WarnIntervals.NONE; SessionData.CURRENT_INTERVAL = WarnIntervals.NONE;
settings.loggedInUser!.sendDiscordActionLog( settings.loggedInUser!.sendDiscordActionLog(
"Requested world restore, and initiated a immediate restart. World restored: ${snapshot}"); "Requested world restore, and initiated a immediate restart. World restored: $snapshot");
return PacketResponse.nil; return PacketResponse.nil;
} }

View file

@ -27,7 +27,7 @@ class AccessControlState extends State<AccessControlListPage> {
if (reply == null) return; if (reply == null) return;
if (reply is User) { if (reply is User) {
setState(() { setState(() {
settings.inst!.admins.add(reply as User); settings.inst!.admins.add(reply);
}); });
} }
}, },

View file

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:servermanager/structs/discordHookHelper.dart';
import '../structs/mod.dart'; import '../structs/mod.dart';
import '../structs/settings.dart'; import '../structs/settings.dart';
@ -24,28 +23,31 @@ class ModManagerState extends State<ModManager> {
backgroundColor: Color.fromARGB(255, 100, 0, 0), backgroundColor: Color.fromARGB(255, 100, 0, 0),
actions: [ actions: [
IconButton( IconButton(
onPressed: () { onPressed: () async {
for (Mod M in settings.inst!.mods) { for (Mod M in settings.inst!.mods) {
M.enabled = false; M.enabled = false;
await Future.delayed(Duration(milliseconds: 500));
settings.loggedInUser! settings.loggedInUser!
.sendDiscordActionLog("${M.mod_name} was disabled"); .sendDiscordActionLog("${M.mod_name} was disabled");
;
}
setState(() {}); setState(() {});
}
}, },
icon: Icon(Icons.swipe_down)), icon: Icon(Icons.swipe_down)),
IconButton( IconButton(
onPressed: () { onPressed: () async {
for (Mod M in settings.inst!.mods) { for (Mod M in settings.inst!.mods) {
M.enabled = true; M.enabled = true;
await Future.delayed(Duration(milliseconds: 500));
settings.loggedInUser! settings.loggedInUser!
.sendDiscordActionLog("${M.mod_name} was enabled"); .sendDiscordActionLog("${M.mod_name} was enabled");
}
setState(() {}); setState(() {});
}
}, },
icon: Icon(Icons.swipe_up)) icon: Icon(Icons.swipe_up))
], ],
@ -65,7 +67,7 @@ class ModManagerState extends State<ModManager> {
settings.inst!.mods[end] = item; settings.inst!.mods[end] = item;
settings.loggedInUser!.sendDiscordActionLog( settings.loggedInUser!.sendDiscordActionLog(
"Reordered Mod List\n\n${item.mod_name} is now in load order ${end}"); "Reordered Mod List\n\n${item.mod_name} is now in load order $end");
} else if (oldIndex > newIndex) { } else if (oldIndex > newIndex) {
//From bottom to top //From bottom to top
Mod item = settings.inst!.mods[oldIndex]; Mod item = settings.inst!.mods[oldIndex];
@ -75,7 +77,7 @@ class ModManagerState extends State<ModManager> {
settings.inst!.mods[newIndex] = item; settings.inst!.mods[newIndex] = item;
settings.loggedInUser!.sendDiscordActionLog( settings.loggedInUser!.sendDiscordActionLog(
"Reordered Mod List\n\n${item.mod_name} is now in load order ${newIndex}"); "Reordered Mod List\n\n${item.mod_name} is now in load order $newIndex");
} }
setState(() { setState(() {
settings.Write(); settings.Write();

View file

@ -119,7 +119,7 @@ class AutoRestartState extends State<AutoRestartPage> {
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
settings.loggedInUser!.sendDiscordActionLog( settings.loggedInUser!.sendDiscordActionLog(
"Updated AutoRestart Information\n\nEnabled: ${enabled}\nTimer: ${time}"); "Updated AutoRestart Information\n\nEnabled: $enabled\nTimer: $time");
Navigator.pop(context, Navigator.pop(context,
AutomaticRestartInfo(enabled: enabled, time: time)); AutomaticRestartInfo(enabled: enabled, time: time));

View file

@ -13,17 +13,20 @@ class User {
final String userHash; final String userHash;
bool login(String username, String passwordHash) { bool login(String username, String passwordHash) {
if (userHash != generateValidityCheck()) if (userHash != generateValidityCheck()) {
return false; // User will be thrown away next time the data is reloaded return false; // User will be thrown away next time the data is reloaded
}
if (name == username) { if (name == username) {
if (Hashing.sha256Hash("${passwordSalt}:${passwordHash}") == if (Hashing.sha256Hash("$passwordSalt:$passwordHash") ==
this.passwordHash) { this.passwordHash) {
return true; return true;
} else } else {
return false; return false;
} else }
} else {
return false; return false;
}
} }
Future<void> sendDiscordActionLog(String actionMessage) async { Future<void> sendDiscordActionLog(String actionMessage) async {
@ -33,7 +36,7 @@ class User {
settings.inst!.discord, settings.inst!.discord,
DiscordHookProps.ALERT, DiscordHookProps.ALERT,
"User Action Alert", "User Action Alert",
"${this}: ${actionMessage}"); "$this: $actionMessage");
} }
User( User(
@ -65,8 +68,8 @@ class User {
factory User.make(String name, String password, UserLevel level) { factory User.make(String name, String password, UserLevel level) {
String salt = Hashing.sha256Hash( String salt = Hashing.sha256Hash(
"${Hashing.md5Hash("${Hashing.sha256Hash("${DateTime.now().millisecondsSinceEpoch}")}")}"); Hashing.md5Hash(Hashing.sha256Hash("${DateTime.now().millisecondsSinceEpoch}")));
String hash = Hashing.sha256Hash("${salt}:${Hashing.sha256Hash(password)}"); String hash = Hashing.sha256Hash("$salt:${Hashing.sha256Hash(password)}");
String validityCode = generateValidityCode(name, hash, salt, level); String validityCode = generateValidityCode(name, hash, salt, level);
return User( return User(
@ -79,13 +82,13 @@ class User {
String generateValidityCheck() { String generateValidityCheck() {
return Hashing.sha256Hash( return Hashing.sha256Hash(
"${name}:${passwordHash}:${passwordSalt}:${permissions.ord()}}"); "$name:$passwordHash:$passwordSalt:${permissions.ord()}}");
} }
static String generateValidityCode(String name, String passwordHash, static String generateValidityCode(String name, String passwordHash,
String passwordSalt, UserLevel permissions) { String passwordSalt, UserLevel permissions) {
return Hashing.sha256Hash( return Hashing.sha256Hash(
"${name}:${passwordHash}:${passwordSalt}:${permissions.ord()}}"); "$name:$passwordHash:$passwordSalt:${permissions.ord()}}");
} }
static const TAG_NAME = "name"; static const TAG_NAME = "name";
@ -96,7 +99,7 @@ class User {
@override @override
String toString() { String toString() {
return "${permissions.name}: ${name}"; return "${permissions.name}: $name";
} }
} }

View file

@ -85,11 +85,13 @@ class Settings {
FTS = NbtUtils.readBoolean(tag, "fts"); // First Time Setup. FTS = NbtUtils.readBoolean(tag, "fts"); // First Time Setup.
// FTS should be disabled by the client when sending it back to the server in a C2SApplySettingsPacket // FTS should be disabled by the client when sending it back to the server in a C2SApplySettingsPacket
if (tag.containsKey("superuser")) if (tag.containsKey("superuser")) {
superuser = User.deserialize(tag.get("superuser")!.asCompoundTag()); superuser = User.deserialize(tag.get("superuser")!.asCompoundTag());
}
if (tag.containsKey("wine_init")) if (tag.containsKey("wine_init")) {
wineInitialized = NbtUtils.readBoolean(tag, "wine_init"); wineInitialized = NbtUtils.readBoolean(tag, "wine_init");
}
if (tag.containsKey("main")) { if (tag.containsKey("main")) {
inst = SettingsEntry.deserialize(tag.get("main")!.asCompoundTag()); inst = SettingsEntry.deserialize(tag.get("main")!.asCompoundTag());
@ -105,11 +107,13 @@ class Settings {
inst = SettingsEntry.deserialize(tag.get("entry") as CompoundTag); inst = SettingsEntry.deserialize(tag.get("entry") as CompoundTag);
if (tag.containsKey("wine_init")) if (tag.containsKey("wine_init")) {
wineInitialized = NbtUtils.readBoolean(tag, "wine_init"); wineInitialized = NbtUtils.readBoolean(tag, "wine_init");
}
if (tag.containsKey("superuser")) if (tag.containsKey("superuser")) {
superuser = User.deserialize(tag.get("superuser")!.asCompoundTag()); superuser = User.deserialize(tag.get("superuser")!.asCompoundTag());
}
FTS = NbtUtils.readBoolean(tag, "fts"); FTS = NbtUtils.readBoolean(tag, "fts");
} catch (E) { } catch (E) {

View file

@ -52,7 +52,7 @@ class SettingsEntry {
st.admins.add(loadedUser); st.admins.add(loadedUser);
} else { } else {
print( print(
"/!\\ FATAL /!\\\n\n${loadedUser} failed to pass the validity check and has been tampered with"); "/!\\ FATAL /!\\\n\n$loadedUser failed to pass the validity check and has been tampered with");
} }
} }
} }

View file

@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.1.112324+1803 version: 1.1.112324+1951
environment: environment:
sdk: ">=3.1.4 <4.0.0" sdk: ">=3.1.4 <4.0.0"