Add a delay for disabling mods in bulk
This commit is contained in:
parent
b2a7493539
commit
3b7876532b
10 changed files with 57 additions and 39 deletions
|
@ -1,3 +1,3 @@
|
||||||
class Consts {
|
class Consts {
|
||||||
static const VERSION = "1.1.112324.1803";
|
static const VERSION = "1.1.112324.1951";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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!
|
||||||
|
|
|
@ -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();
|
||||||
|
if (modListText.isEmpty) {
|
||||||
|
DiscordHookHelper.sendWebHook(
|
||||||
|
settings.inst!.discord,
|
||||||
|
DiscordHookProps.INACTIVE,
|
||||||
|
"Mod List",
|
||||||
|
"The Server is currently vanilla");
|
||||||
|
} else {
|
||||||
DiscordHookHelper.sendWebHook(settings.inst!.discord,
|
DiscordHookHelper.sendWebHook(settings.inst!.discord,
|
||||||
DiscordHookProps.INACTIVE, "Mod List", modListText);
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -13,18 +13,21 @@ 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 {
|
||||||
Settings settings = Settings();
|
Settings settings = Settings();
|
||||||
|
@ -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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue