mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-17 11:18:55 -04:00
Add WIP fallback Mojang authentication support
This commit is contained in:
parent
af62cdf0c0
commit
17eaca3a80
@ -168,33 +168,33 @@ namespace MCGalaxy.SQL
|
||||
#region Low level functions
|
||||
|
||||
/// <summary> Executes an SQL command that does not return any results. </summary>
|
||||
public static void Execute(string sql, params object[] args) {
|
||||
Do(sql, false, null, args);
|
||||
public static int Execute(string sql, params object[] args) {
|
||||
return Do(sql, false, null, args);
|
||||
}
|
||||
|
||||
/// <summary> Executes an SQL query, invoking callback function on each returned row. </summary>
|
||||
public static void Iterate(string sql, ReaderCallback callback, params object[] args) {
|
||||
Do(sql, false, callback, args);
|
||||
public static int Iterate(string sql, ReaderCallback callback, params object[] args) {
|
||||
return Do(sql, false, callback, args);
|
||||
}
|
||||
|
||||
internal static void Do(string sql, bool createDB, ReaderCallback callback, object[] args) {
|
||||
internal static int Do(string sql, bool createDB, ReaderCallback callback, object[] args) {
|
||||
IDatabaseBackend db = Backend;
|
||||
Exception e = null;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
try {
|
||||
if (callback != null) {
|
||||
db.Iterate(sql, args, callback);
|
||||
return db.Iterate(sql, args, callback);
|
||||
} else {
|
||||
db.Execute(sql, args, createDB);
|
||||
return db.Execute(sql, args, createDB);
|
||||
}
|
||||
return;
|
||||
} catch (Exception ex) {
|
||||
e = ex; // try yet again
|
||||
}
|
||||
}
|
||||
|
||||
Logger.LogError("Error executing SQL statement: " + sql, e);
|
||||
return 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -170,7 +170,9 @@ namespace MCGalaxy.SQL
|
||||
}
|
||||
|
||||
/// <summary> Excecutes an SQL query, invoking a callback on the returned rows one by one. </summary>
|
||||
public void Iterate(string sql, object[] parameters, ReaderCallback callback) {
|
||||
public int Iterate(string sql, object[] parameters, ReaderCallback callback) {
|
||||
int rows = 0;
|
||||
|
||||
using (ISqlConnection conn = CreateConnection()) {
|
||||
conn.Open();
|
||||
if (MultipleSchema)
|
||||
@ -179,11 +181,12 @@ namespace MCGalaxy.SQL
|
||||
using (ISqlCommand cmd = conn.CreateCommand(sql)) {
|
||||
FillParams(cmd, parameters);
|
||||
using (ISqlReader reader = cmd.ExecuteReader()) {
|
||||
while (reader.Read()) { callback(reader); }
|
||||
while (reader.Read()) { callback(reader); rows++; }
|
||||
}
|
||||
}
|
||||
conn.Close();
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,6 +18,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using MCGalaxy.Network;
|
||||
|
||||
namespace MCGalaxy.Authentication
|
||||
@ -27,6 +30,7 @@ namespace MCGalaxy.Authentication
|
||||
public string URL;
|
||||
public string NameSuffix = "";
|
||||
public string SkinPrefix = "";
|
||||
public bool MojangAuth;
|
||||
}
|
||||
|
||||
public class AuthService
|
||||
@ -37,8 +41,24 @@ namespace MCGalaxy.Authentication
|
||||
public Heartbeat Beat;
|
||||
public AuthServiceConfig Config;
|
||||
|
||||
/// <summary> Attempts to authenticate the given player with the given mppass </summary>
|
||||
public virtual bool Authenticate(Player p, string mppass) {
|
||||
if (!VerifyLogin(p, mppass)) return false;
|
||||
string calculated = Server.CalcMppass(p.truename, Beat.Salt);
|
||||
if (!mppass.CaselessEq(calculated)) return false;
|
||||
|
||||
AcceptPlayer(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool FallbackAuthenticate(Player p) {
|
||||
if (!Config.MojangAuth) return false;
|
||||
if (!MojangAuth.HasJoined(p.truename)) return false;
|
||||
|
||||
AcceptPlayer(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void AcceptPlayer(Player p) {
|
||||
AuthServiceConfig cfg = Config;
|
||||
|
||||
p.verifiedName = true;
|
||||
@ -47,13 +67,6 @@ namespace MCGalaxy.Authentication
|
||||
p.name += cfg.NameSuffix;
|
||||
p.truename += cfg.NameSuffix;
|
||||
p.DisplayName += cfg.NameSuffix;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary> Whether the given player is allowed to login with the given mppass </summary>
|
||||
protected virtual bool VerifyLogin(Player p, string mppass) {
|
||||
string calculated = Server.CalcMppass(p.truename, Beat.Salt);
|
||||
return mppass.CaselessEq(calculated);
|
||||
}
|
||||
|
||||
|
||||
@ -132,6 +145,9 @@ namespace MCGalaxy.Authentication
|
||||
} else if (key.CaselessEq("skin-prefix")) {
|
||||
if (cur == null) return;
|
||||
cur.SkinPrefix = value;
|
||||
} else if (key.CaselessEq("mojang-auth")) {
|
||||
if (cur == null) return;
|
||||
bool.TryParse(value, out cur.MojangAuth);
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,6 +167,9 @@ namespace MCGalaxy.Authentication
|
||||
w.WriteLine("#skin-prefix = string");
|
||||
w.WriteLine("# Characters that are prefixed to skin name of players that login through the authentication service");
|
||||
w.WriteLine("# (used to ensure players from other authentication services see the correct skin)");
|
||||
w.WriteLine("#mojang-auth = boolean");
|
||||
w.WriteLine("# Whether to try verifying users using Mojang's authentication servers if mppass verification fails");
|
||||
w.WriteLine("# NOTE: This should only be used for the Betacraft.uk authentication service");
|
||||
w.WriteLine();
|
||||
|
||||
foreach (AuthServiceConfig c in configs)
|
||||
@ -158,9 +177,59 @@ namespace MCGalaxy.Authentication
|
||||
w.WriteLine("URL = " + c.URL);
|
||||
w.WriteLine("name-suffix = " + c.NameSuffix);
|
||||
w.WriteLine("skin-prefix = " + c.SkinPrefix);
|
||||
w.WriteLine("mojang-auth = " + c.MojangAuth);
|
||||
w.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class MojangAuth
|
||||
{
|
||||
const string HAS_JOINED_URL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username={0}&serverId={1}";
|
||||
public static bool HasJoined(string username) {
|
||||
string url = string.Format(HAS_JOINED_URL, username, GetServerID());
|
||||
try
|
||||
{
|
||||
HttpWebRequest req = HttpUtil.CreateRequest(url);
|
||||
req.Timeout = 5 * 1000;
|
||||
req.ReadWriteTimeout = 5 * 1000;
|
||||
|
||||
using (HttpWebResponse response = (HttpWebResponse)req.GetResponse())
|
||||
{
|
||||
return response.StatusCode == HttpStatusCode.OK;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
HttpUtil.DisposeErrorResponse(ex);
|
||||
Logger.LogError("Verifying Mojang session for " + username, ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static string GetServerID() {
|
||||
UpdateExternalIP();
|
||||
byte[] data = Encoding.UTF8.GetBytes(externalIP + ":" + Server.Config.Port);
|
||||
byte[] hash = new SHA1Managed().ComputeHash(data);
|
||||
|
||||
// TODO this is bad, redo it
|
||||
return hash.Join(b => b.ToString("x2"), "");
|
||||
}
|
||||
|
||||
static string externalIP;
|
||||
static void UpdateExternalIP() {
|
||||
if (externalIP != null) return;
|
||||
|
||||
try {
|
||||
HttpWebRequest req = HttpUtil.CreateRequest("http://classicube.net/api/myip/");
|
||||
|
||||
using (WebResponse response = req.GetResponse())
|
||||
{
|
||||
externalIP = HttpUtil.GetResponseText(response);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.LogError("Retrieving external IP", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -38,6 +38,11 @@ namespace MCGalaxy.Authentication
|
||||
if (auth.Authenticate(p, mppass)) return true;
|
||||
}
|
||||
|
||||
foreach (AuthService auth in AuthService.Services)
|
||||
{
|
||||
if (auth.FallbackAuthenticate(p)) return true;
|
||||
}
|
||||
|
||||
return !Server.Config.VerifyNames || IPUtil.IsPrivate(p.IP);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user