once as a kid i cried over a mario flash animation

my mom looked very disappointed
This commit is contained in:
Malloc of Kuzkycyziklistan 2017-09-14 14:14:07 -05:00
parent 07e50a3301
commit 4d281dac5a
7 changed files with 105 additions and 37 deletions

View file

@ -287,24 +287,18 @@ Communication between the master server and clients will be done over a WebSocke
</tr>
<tr>
<td class="center">2</td>
<td>Session Id</td>
<td>Packed Unsigned Long</td>
<td>R<sub>1</sub></td>
</tr>
<tr>
<td class="center">3</td>
<td>Secret</td>
<td>Bytes (16)</td>
<td>R<sub>1</sub></td>
</tr>
<tr>
<td class="center">4</td>
<td class="center">3</td>
<td>Server Address</td>
<td>IPv4 String</td>
<td>R<sub>1</sub></td>
</tr>
<tr>
<td class="center">5</td>
<td class="center">4</td>
<td>Server Port</td>
<td>Packed Unsigned Short</td>
<td>R<sub>1</sub></td>

View file

@ -26,6 +26,16 @@ namespace SockScape {
}
},
new SectionRules {
Name = "Mail",
Required = true,
RequiredFields = new[] {
"Host",
"UseTLS",
"Auth"
}
},
new SectionRules {
Name = "Database",
Required = true,

View file

@ -8,7 +8,6 @@ using System.Security.Cryptography;
namespace Glove {
public static class RNG {
// TODO add cryptographically secure rng
private static readonly Random RandCtx = new Random();
private static readonly RNGCryptoServiceProvider CsRandCtx
= new RNGCryptoServiceProvider();

View file

@ -21,6 +21,12 @@ namespace SockScape {
}
}
public static Server Get(ushort id) {
lock(_Servers) {
return _Servers[id];
}
}
public static void Write(Server server) {
lock(_Servers) {
if(HasId(server.Id) && !_Servers[server.Id].Address.Equals(server.Address))

View file

@ -13,8 +13,8 @@ using SockScape.Encryption;
namespace SockScape {
class MasterConnection : Connection {
private Regex UsernameRegex = new Regex("[A-Z0-9_]", RegexOptions.IgnoreCase);
private Regex EmailRegex = new Regex("\\B[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\B", RegexOptions.IgnoreCase);
private readonly Regex UsernameRegex = new Regex("[A-Z0-9_]", RegexOptions.IgnoreCase);
private readonly Regex EmailRegex = new Regex(@"\B[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\B", RegexOptions.IgnoreCase);
private Key Key;
public StreamCipher Encryptor { get; private set; }
@ -55,9 +55,10 @@ namespace SockScape {
Encryptor = new StreamCipher(Key.PrivateKey);
break;
case kInterMasterId.LoginAttempt:
if(packet.RegionCount != 3 || !packet.CheckRegions(2, 2))
if(packet.RegionCount != 3 || !packet.CheckRegionsMaxLength(0, 16, 255) || !packet.CheckRegionLengths(2, 2))
break;
Session session;
using(var db = new ScapeDb()) {
User user;
if((user = db.Users.FirstOrDefault(x => x.Username == packet[0])) == null) {
@ -75,8 +76,8 @@ namespace SockScape {
break;
}
ushort server = packet[2].Raw.UnpackUInt16();
if(!MasterServerList.HasId(server)) {
ushort serverId = packet[2].Raw.UnpackUInt16();
if(!MasterServerList.HasId(serverId)) {
SendEncrypted(new Packet(kInterMasterId.LoginAttempt, Convert.ToByte(false), "The world you have specified is offline."));
break;
}
@ -86,32 +87,65 @@ namespace SockScape {
db.SaveChanges();
}
db.Sessions.Add(new Session {
db.Sessions.Add(session = new Session {
Id = user.Id,
Secret = RNG.NextBytes(16),
ServerId = server,
ServerId = serverId,
LastPing = DateTime.UtcNow
});
db.SaveChanges();
}
var server = MasterServerList.Get((ushort)session.ServerId);
SendEncrypted(new Packet(kInterMasterId.LoginAttempt, Convert.ToByte(true), session.Secret, server.Address.ToString(), server.Port.Pack()));
break;
case kInterMasterId.RegistrationAttempt:
if(packet.RegionCount != 3)
if(packet.RegionCount != 3 || !packet.CheckAllMaxLength(0xFF))
break;
using(var db = new ScapeDb()) {
if(!packet[0].Raw.IsAsciiString()) {
SendEncrypted(new Packet(kInterMasterId.RegistrationAttempt, Convert.ToByte(false), "Your username cannot contain unicode characters."));
break;
}
if(packet[0].Raw.Length > 16 || !UsernameRegex.IsMatch(packet[0].Str)) {
SendEncrypted(new Packet(kInterMasterId.RegistrationAttempt, Convert.ToByte(false), "The username is max 16 characters and can only be letters, numbers, and underscores."));
break;
}
if(!packet[0].Raw.IsAsciiString()) {
SendEncrypted(new Packet(kInterMasterId.RegistrationAttempt, Convert.ToByte(false), "Your username cannot contain unicode characters."));
break;
}
string username = packet[0].Str.Trim(),
password = packet[1].Str.Trim(),
email = packet[2].Str.Trim();
if(username.Length > 16 || !UsernameRegex.IsMatch(username)) {
SendEncrypted(new Packet(kInterMasterId.RegistrationAttempt, Convert.ToByte(false), "The username is max 16 characters and can only be letters, numbers, and underscores."));
break;
}
if(!EmailRegex.IsMatch(email)) {
SendEncrypted(new Packet(kInterMasterId.RegistrationAttempt, Convert.ToByte(false), "The email address is malformed."));
break;
}
using(var db = new ScapeDb()) {
if(db.Users.FirstOrDefault(x => x.Username == username) != null) {
SendEncrypted(new Packet(kInterMasterId.RegistrationAttempt, Convert.ToByte(false), "This username is already in use."));
break;
}
if(db.Users.FirstOrDefault(x => x.Email == email) != null) {
SendEncrypted(new Packet(kInterMasterId.RegistrationAttempt, Convert.ToByte(false), "This email address is already in use."));
break;
}
// TODO email activation
db.Users.Add(new User {
Username = username,
Password = password.HashPassword(),
Email = email,
Joined = DateTime.UtcNow
});
db.SaveChanges();
}
SendEncrypted(new Packet(kInterMasterId.RegistrationAttempt, Convert.ToByte(true), "Registration was successful."));
break;
case kInterMasterId.ServerListing:
SendEncrypted(MasterServerList.ReportPacket);

View file

@ -102,7 +102,7 @@ namespace SockScape {
if(!IsClientConnected(client) || packet.RegionCount < 1)
break;
if(!packet.CheckRegions(0, 1)) {
if(!packet.CheckRegionLengths(0, 1)) {
NegativeAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate, "Server count is malformed.");
break;
}
@ -114,7 +114,7 @@ namespace SockScape {
}
for(byte i = 0; i < serverCount; ++i) {
if(!packet.CheckRegions(1 + 3 * i, 2, 2, 2))
if(!packet.CheckRegionLengths(1 + 3 * i, 2, 2, 2))
continue;
MasterServerList.Write(new Server {
@ -132,7 +132,7 @@ namespace SockScape {
}
Prospects = Prospects.Where(x => x.Value.ReceiveDelta.TotalSeconds < 10)
.ToDictionary(x => x.Key, x => x.Value);
.ToDictionary(x => x.Key, x => x.Value);
var expiredClients = Clients.Where(x => x.Value.ReceiveDelta.TotalSeconds > 60).Select(x => x.Value).ToList();
if(expiredClients.Count > 0)

View file

@ -50,7 +50,7 @@ namespace SockScape {
long bodyPtr = headerPtr;
foreach(var regionLength in regionLengths) {
// FLAG this could fail if one region exceeds 2^31-1 in size, check later
// FLAG TODO this could fail if one region exceeds 2^31-1 in size, check later
packet.Regions.Add(raw.Subset((int)bodyPtr, (int)regionLength));
bodyPtr += regionLength;
}
@ -103,7 +103,7 @@ namespace SockScape {
return this;
}
public bool CheckRegions(int startIndex, params int[] lengths) {
public bool CheckRegionLengths(int startIndex, params int[] lengths) {
if(startIndex + lengths.Length > RegionCount)
return false;
@ -115,6 +115,30 @@ namespace SockScape {
return true;
}
public bool CheckRegionsMaxLength(int startIndex, params int[] lengths) {
if(startIndex + lengths.Length > RegionCount)
return false;
for(int i = 0; i < lengths.Length; ++i) {
if(this[startIndex + i].Raw.Length > lengths[i])
return false;
}
return true;
}
public bool CheckAllMaxLength(int length, int startIndex = 0) {
if(startIndex > RegionCount)
return false;
for(int i = startIndex; i < RegionCount; ++i) {
if(this[i].Raw.Length > length)
return false;
}
return true;
}
public byte[] GetBytes() {
var header = new List<byte>();
header.AddRange(MagicNumber);
@ -162,8 +186,9 @@ namespace SockScape {
}
}
// FLAG TODO determine if you still need this thing, probably not
public class PacketBuffer {
private short MaxSize;
private readonly short MaxSize;
private Dictionary<uint, byte[]> Buffer
= new Dictionary<uint, byte[]>();
@ -174,9 +199,9 @@ namespace SockScape {
public void Add(uint id, byte[] packet) {
Buffer[id] = packet;
if(Buffer.Count > 10)
if(Buffer.Count > MaxSize)
Buffer =
Buffer.Where(x => x.Key >= id - 10)
Buffer.Where(x => x.Key >= id - MaxSize)
.ToDictionary(x => x.Key, x => x.Value);
}