mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-11-07 17:36:07 +00:00
Improve session caching
- Change SessionCache.db to SessionCache.ini Allows users to view and edit session cache - Automatically import previous SessionCache.db But this file is only read, not updated - Automatically import Minecraft session If you are logged in in Minecraft, no need to login again This is only done if Disk session cache is enabled See #232 and #430 for more information - Disk session cache becomes default The feature is no longer experimental and now recommended as the Mojang login servers now have a severe rate limit Previous default was Memory session cache, not saved to disk
This commit is contained in:
parent
a37e340613
commit
18fd24d2d5
5 changed files with 155 additions and 32 deletions
|
|
@ -12,7 +12,7 @@ using MinecraftClient.WinAPI;
|
||||||
namespace MinecraftClient
|
namespace MinecraftClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Minecraft Console Client by ORelio and Contributors (c) 2012-2017.
|
/// Minecraft Console Client by ORelio and Contributors (c) 2012-2018.
|
||||||
/// Allows to connect to any Minecraft server, send and receive text, automated scripts.
|
/// Allows to connect to any Minecraft server, send and receive text, automated scripts.
|
||||||
/// This source code is released under the CDDL 1.0 License.
|
/// This source code is released under the CDDL 1.0 License.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -102,7 +102,7 @@ namespace MinecraftClient
|
||||||
{
|
{
|
||||||
bool cacheLoaded = SessionCache.InitializeDiskCache();
|
bool cacheLoaded = SessionCache.InitializeDiskCache();
|
||||||
if (Settings.DebugMessages)
|
if (Settings.DebugMessages)
|
||||||
ConsoleIO.WriteLineFormatted(cacheLoaded ? "§8Session cache has been successfully loaded from disk." : "§8Cached sessions could not be loaded from disk");
|
ConsoleIO.WriteLineFormatted(cacheLoaded ? "§8Session data has been successfully loaded from disk." : "§8No sessions could be loaded from disk");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Asking the user to type in missing data such as Username and Password
|
//Asking the user to type in missing data such as Username and Password
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ using System.Net.Sockets;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
using MinecraftClient.Protocol.Handlers.Forge;
|
using MinecraftClient.Protocol.Handlers.Forge;
|
||||||
|
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol
|
namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -229,10 +228,10 @@ namespace MinecraftClient.Protocol
|
||||||
if (Settings.DebugMessages)
|
if (Settings.DebugMessages)
|
||||||
ConsoleIO.WriteLineFormatted("§8Debug: Login Request: " + json_request);
|
ConsoleIO.WriteLineFormatted("§8Debug: Login Request: " + json_request);
|
||||||
int code = DoHTTPSPost("authserver.mojang.com", "/authenticate", json_request, ref result);
|
int code = DoHTTPSPost("authserver.mojang.com", "/authenticate", json_request, ref result);
|
||||||
if (code == 200)
|
|
||||||
{
|
|
||||||
if (Settings.DebugMessages)
|
if (Settings.DebugMessages)
|
||||||
ConsoleIO.WriteLineFormatted("§8Debug: Login Response: " + result);
|
ConsoleIO.WriteLineFormatted("§8Debug: Login Response: " + result);
|
||||||
|
if (code == 200)
|
||||||
|
{
|
||||||
if (result.Contains("availableProfiles\":[]}"))
|
if (result.Contains("availableProfiles\":[]}"))
|
||||||
{
|
{
|
||||||
return LoginResult.NotPremium;
|
return LoginResult.NotPremium;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,16 @@ namespace MinecraftClient.Protocol.SessionCache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class SessionCache
|
public static class SessionCache
|
||||||
{
|
{
|
||||||
private const string SessionCacheFile = "SessionCache.db";
|
private const string SessionCacheFilePlaintext = "SessionCache.ini";
|
||||||
|
private const string SessionCacheFileSerialized = "SessionCache.db";
|
||||||
|
private static readonly string SessionCacheFileMinecraft = String.Concat(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
Path.DirectorySeparatorChar,
|
||||||
|
".minecraft",
|
||||||
|
Path.DirectorySeparatorChar,
|
||||||
|
"launcher_profiles.json"
|
||||||
|
);
|
||||||
|
|
||||||
private static Dictionary<string, SessionToken> sessions = new Dictionary<string, SessionToken>();
|
private static Dictionary<string, SessionToken> sessions = new Dictionary<string, SessionToken>();
|
||||||
private static FileSystemWatcher cachemonitor = new FileSystemWatcher();
|
private static FileSystemWatcher cachemonitor = new FileSystemWatcher();
|
||||||
private static Timer updatetimer = new Timer(100);
|
private static Timer updatetimer = new Timer(100);
|
||||||
|
|
@ -74,7 +83,7 @@ namespace MinecraftClient.Protocol.SessionCache
|
||||||
{
|
{
|
||||||
cachemonitor.Path = AppDomain.CurrentDomain.BaseDirectory;
|
cachemonitor.Path = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
cachemonitor.IncludeSubdirectories = false;
|
cachemonitor.IncludeSubdirectories = false;
|
||||||
cachemonitor.Filter = SessionCacheFile;
|
cachemonitor.Filter = SessionCacheFilePlaintext;
|
||||||
cachemonitor.NotifyFilter = NotifyFilters.LastWrite;
|
cachemonitor.NotifyFilter = NotifyFilters.LastWrite;
|
||||||
cachemonitor.Changed += new FileSystemEventHandler(OnChanged);
|
cachemonitor.Changed += new FileSystemEventHandler(OnChanged);
|
||||||
cachemonitor.EnableRaisingEvents = true;
|
cachemonitor.EnableRaisingEvents = true;
|
||||||
|
|
@ -118,17 +127,71 @@ namespace MinecraftClient.Protocol.SessionCache
|
||||||
/// <returns>True if data is successfully loaded</returns>
|
/// <returns>True if data is successfully loaded</returns>
|
||||||
private static bool LoadFromDisk()
|
private static bool LoadFromDisk()
|
||||||
{
|
{
|
||||||
if (Settings.DebugMessages)
|
//Grab sessions in the Minecraft directory
|
||||||
ConsoleIO.WriteLineFormatted("§8Updating session cache from disk");
|
if (File.Exists(SessionCacheFileMinecraft))
|
||||||
|
|
||||||
if (File.Exists(SessionCacheFile))
|
|
||||||
{
|
{
|
||||||
|
if (Settings.DebugMessages)
|
||||||
|
ConsoleIO.WriteLineFormatted("§8Loading Minecraft profiles: " + Path.GetFileName(SessionCacheFileMinecraft));
|
||||||
|
Json.JSONData mcSession = new Json.JSONData(Json.JSONData.DataType.String);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (FileStream fs = new FileStream(SessionCacheFile, FileMode.Open, FileAccess.Read, FileShare.Read))
|
mcSession = Json.ParseJson(File.ReadAllText(SessionCacheFileMinecraft));
|
||||||
|
}
|
||||||
|
catch (IOException) { /* Failed to read file from disk -- ignoring */ }
|
||||||
|
if (mcSession.Type == Json.JSONData.DataType.Object
|
||||||
|
&& mcSession.Properties.ContainsKey("clientToken")
|
||||||
|
&& mcSession.Properties.ContainsKey("authenticationDatabase"))
|
||||||
{
|
{
|
||||||
sessions = (Dictionary<string, SessionToken>)formatter.Deserialize(fs);
|
Guid temp;
|
||||||
return true;
|
string clientID = mcSession.Properties["clientToken"].StringValue.Replace("-", "");
|
||||||
|
Dictionary<string, Json.JSONData> sessionItems = mcSession.Properties["authenticationDatabase"].Properties;
|
||||||
|
foreach (string key in sessionItems.Keys)
|
||||||
|
{
|
||||||
|
if (Guid.TryParseExact(key, "N", out temp))
|
||||||
|
{
|
||||||
|
Dictionary<string, Json.JSONData> sessionItem = sessionItems[key].Properties;
|
||||||
|
if (sessionItem.ContainsKey("displayName")
|
||||||
|
&& sessionItem.ContainsKey("accessToken")
|
||||||
|
&& sessionItem.ContainsKey("username")
|
||||||
|
&& sessionItem.ContainsKey("uuid"))
|
||||||
|
{
|
||||||
|
string login = sessionItem["username"].StringValue.ToLower();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SessionToken session = SessionToken.FromString(String.Join(",",
|
||||||
|
sessionItem["accessToken"].StringValue,
|
||||||
|
sessionItem["displayName"].StringValue,
|
||||||
|
sessionItem["uuid"].StringValue.Replace("-", ""),
|
||||||
|
clientID
|
||||||
|
));
|
||||||
|
if (Settings.DebugMessages)
|
||||||
|
ConsoleIO.WriteLineFormatted("§8Loaded session: " + login + ':' + session.ID);
|
||||||
|
sessions[login] = session;
|
||||||
|
}
|
||||||
|
catch (InvalidDataException) { /* Not a valid session */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Serialized session cache file in binary format
|
||||||
|
if (File.Exists(SessionCacheFileSerialized))
|
||||||
|
{
|
||||||
|
if (Settings.DebugMessages)
|
||||||
|
ConsoleIO.WriteLineFormatted("§8Converting session cache from disk: " + SessionCacheFileSerialized);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (FileStream fs = new FileStream(SessionCacheFileSerialized, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||||
|
{
|
||||||
|
Dictionary<string, SessionToken> sessionsTemp = (Dictionary<string, SessionToken>)formatter.Deserialize(fs);
|
||||||
|
foreach (KeyValuePair<string, SessionToken> item in sessionsTemp)
|
||||||
|
{
|
||||||
|
if (Settings.DebugMessages)
|
||||||
|
ConsoleIO.WriteLineFormatted("§8Loaded session: " + item.Key + ':' + item.Value.ID);
|
||||||
|
sessions[item.Key] = item.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
|
|
@ -140,7 +203,43 @@ namespace MinecraftClient.Protocol.SessionCache
|
||||||
ConsoleIO.WriteLineFormatted("§8Got malformed data while reading session cache from disk: " + ex2.Message);
|
ConsoleIO.WriteLineFormatted("§8Got malformed data while reading session cache from disk: " + ex2.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
//User-editable session cache file in text format
|
||||||
|
if (File.Exists(SessionCacheFilePlaintext))
|
||||||
|
{
|
||||||
|
if (Settings.DebugMessages)
|
||||||
|
ConsoleIO.WriteLineFormatted("§8Loading session cache from disk: " + SessionCacheFilePlaintext);
|
||||||
|
|
||||||
|
foreach (string line in File.ReadAllLines(SessionCacheFilePlaintext))
|
||||||
|
{
|
||||||
|
if (!line.Trim().StartsWith("#"))
|
||||||
|
{
|
||||||
|
string[] keyValue = line.Split('=');
|
||||||
|
if (keyValue.Length == 2)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string login = keyValue[0].ToLower();
|
||||||
|
SessionToken session = SessionToken.FromString(keyValue[1]);
|
||||||
|
if (Settings.DebugMessages)
|
||||||
|
ConsoleIO.WriteLineFormatted("§8Loaded session: " + login + ':' + session.ID);
|
||||||
|
sessions[login] = session;
|
||||||
|
}
|
||||||
|
catch (InvalidDataException e)
|
||||||
|
{
|
||||||
|
if (Settings.DebugMessages)
|
||||||
|
ConsoleIO.WriteLineFormatted("§8Ignoring session token string '" + keyValue[1] + "': " + e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Settings.DebugMessages)
|
||||||
|
{
|
||||||
|
ConsoleIO.WriteLineFormatted("§8Ignoring invalid session token line: " + line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessions.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -151,7 +250,7 @@ namespace MinecraftClient.Protocol.SessionCache
|
||||||
if (Settings.DebugMessages)
|
if (Settings.DebugMessages)
|
||||||
ConsoleIO.WriteLineFormatted("§8Saving session cache to disk");
|
ConsoleIO.WriteLineFormatted("§8Saving session cache to disk");
|
||||||
|
|
||||||
bool fileexists = File.Exists(SessionCacheFile);
|
bool fileexists = File.Exists(SessionCacheFilePlaintext);
|
||||||
IOException lastEx = null;
|
IOException lastEx = null;
|
||||||
int attempt = 1;
|
int attempt = 1;
|
||||||
|
|
||||||
|
|
@ -159,20 +258,13 @@ namespace MinecraftClient.Protocol.SessionCache
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (FileStream fs = new FileStream(SessionCacheFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
|
List<string> sessionCacheLines = new List<string>();
|
||||||
{
|
sessionCacheLines.Add("# Generated by MCC v" + Program.Version + " - Edit at own risk!");
|
||||||
cachemonitor.EnableRaisingEvents = false;
|
foreach (KeyValuePair<string, SessionToken> entry in sessions)
|
||||||
|
sessionCacheLines.Add(entry.Key + '=' + entry.Value.ToString());
|
||||||
// delete existing file contents
|
File.WriteAllLines(SessionCacheFilePlaintext, sessionCacheLines);
|
||||||
if (fileexists)
|
//if (File.Exists(SessionCacheFileSerialized))
|
||||||
{
|
// File.Delete(SessionCacheFileSerialized);
|
||||||
fs.SetLength(0);
|
|
||||||
fs.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
formatter.Serialize(fs, sessions);
|
|
||||||
cachemonitor.EnableRaisingEvents = true;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol
|
namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
|
|
@ -17,5 +19,35 @@ namespace MinecraftClient.Protocol
|
||||||
PlayerID = String.Empty;
|
PlayerID = String.Empty;
|
||||||
ClientID = String.Empty;
|
ClientID = String.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return String.Join(",", ID, PlayerName, PlayerID, ClientID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SessionToken FromString(string tokenString)
|
||||||
|
{
|
||||||
|
string[] fields = tokenString.Split(',');
|
||||||
|
if (fields.Length < 4)
|
||||||
|
throw new InvalidDataException("Invalid string format");
|
||||||
|
|
||||||
|
SessionToken session = new SessionToken();
|
||||||
|
session.ID = fields[0];
|
||||||
|
session.PlayerName = fields[1];
|
||||||
|
session.PlayerID = fields[2];
|
||||||
|
session.ClientID = fields[3];
|
||||||
|
|
||||||
|
Guid temp;
|
||||||
|
if (!Guid.TryParseExact(session.ID, "N", out temp))
|
||||||
|
throw new InvalidDataException("Invalid session ID");
|
||||||
|
if (!ChatBot.IsValidName(session.PlayerName))
|
||||||
|
throw new InvalidDataException("Invalid player name");
|
||||||
|
if (!Guid.TryParseExact(session.PlayerID, "N", out temp))
|
||||||
|
throw new InvalidDataException("Invalid player ID");
|
||||||
|
if (!Guid.TryParseExact(session.ClientID, "N", out temp))
|
||||||
|
throw new InvalidDataException("Invalid client ID");
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ namespace MinecraftClient
|
||||||
public static bool DisplayChatLinks = true;
|
public static bool DisplayChatLinks = true;
|
||||||
public static bool TerrainAndMovements = false;
|
public static bool TerrainAndMovements = false;
|
||||||
public static string PrivateMsgsCmdName = "tell";
|
public static string PrivateMsgsCmdName = "tell";
|
||||||
public static CacheType SessionCaching = CacheType.None;
|
public static CacheType SessionCaching = CacheType.Disk;
|
||||||
public static bool DebugMessages = false;
|
public static bool DebugMessages = false;
|
||||||
public static bool ResolveSrvRecords = true;
|
public static bool ResolveSrvRecords = true;
|
||||||
public static bool ResolveSrvRecordsShortTimeout = true;
|
public static bool ResolveSrvRecordsShortTimeout = true;
|
||||||
|
|
@ -539,7 +539,7 @@ namespace MinecraftClient
|
||||||
+ "showxpbarmessages=true # Messages displayed above xp bar\r\n"
|
+ "showxpbarmessages=true # Messages displayed above xp bar\r\n"
|
||||||
+ "showchatlinks=true # Show links embedded in chat messages\r\n"
|
+ "showchatlinks=true # Show links embedded in chat messages\r\n"
|
||||||
+ "terrainandmovements=false # Uses more ram, cpu, bandwidth\r\n"
|
+ "terrainandmovements=false # Uses more ram, cpu, bandwidth\r\n"
|
||||||
+ "sessioncache=memory # Use 'none', 'memory' or 'disk' (disk session storing is experimental)\r\n"
|
+ "sessioncache=disk # How to retain session tokens. Use 'none', 'memory' or 'disk'\r\n"
|
||||||
+ "resolvesrvrecords=fast # Use 'false', 'fast' (5s timeout), or 'true'. Required for joining some servers.\r\n"
|
+ "resolvesrvrecords=fast # Use 'false', 'fast' (5s timeout), or 'true'. Required for joining some servers.\r\n"
|
||||||
+ "accountlist=accounts.txt # See README > 'Servers and Accounts file' for more info about this file\r\n"
|
+ "accountlist=accounts.txt # See README > 'Servers and Accounts file' for more info about this file\r\n"
|
||||||
+ "serverlist=servers.txt # See README > 'Servers and Accounts file' for more info about this file\r\n"
|
+ "serverlist=servers.txt # See README > 'Servers and Accounts file' for more info about this file\r\n"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue