2017-06-05 12:20:39 +00:00
using System ;
using System.Collections.Generic ;
2017-09-12 20:59:55 +00:00
using System.Data.Entity ;
2017-06-05 12:20:39 +00:00
using System.Linq ;
2017-09-08 21:06:55 +00:00
using System.Net ;
2017-06-05 12:20:39 +00:00
using System.Text ;
2017-09-13 21:02:39 +00:00
using System.Text.RegularExpressions ;
2017-06-05 12:20:39 +00:00
using System.Threading.Tasks ;
2017-06-16 21:00:01 +00:00
using Kneesocks ;
2017-07-22 19:27:41 +00:00
using Glove ;
2017-09-08 21:06:55 +00:00
using SockScape.DAL ;
2017-08-18 21:01:11 +00:00
using SockScape.Encryption ;
2017-06-05 12:20:39 +00:00
2017-08-18 21:01:11 +00:00
namespace SockScape {
2017-06-06 21:13:25 +00:00
class MasterConnection : Connection {
2017-09-14 19:14:07 +00:00
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 ) ;
2017-09-13 21:02:39 +00:00
2017-08-18 21:01:11 +00:00
private Key Key ;
2017-09-07 21:00:03 +00:00
public StreamCipher Encryptor { get ; private set ; }
2017-08-18 21:01:11 +00:00
protected override void OnOpen ( ) {
Key = new Key ( ) ;
2017-09-12 20:59:55 +00:00
Send ( Key . GenerateRequestPacket ( ) ) ;
2017-08-18 21:01:11 +00:00
}
2017-06-05 12:20:39 +00:00
2017-08-18 21:01:11 +00:00
protected override void OnParse ( ) {
2017-09-08 21:06:55 +00:00
2017-08-18 21:01:11 +00:00
}
protected override void OnReceive ( byte [ ] data ) {
Packet packet =
Encryptor = = null ? Packet . FromBytes ( data )
: Packet . FromBytes ( Encryptor . Parse ( data ) ) ;
if ( packet = = null ) {
Disconnect ( Frame . kClosingReason . ProtocolError , "Packet received was not legal." ) ;
return ;
}
2017-09-08 21:06:55 +00:00
if ( packet . Id ! = ( int ) kInterMasterId . KeyExchange & & Encryptor = = null ) {
Disconnect ( Frame . kClosingReason . ProtocolError , "You must exchange keys before performing any other operations." ) ;
return ;
}
2017-09-13 21:02:39 +00:00
// TODO rate limiting by ip
2017-08-18 21:01:11 +00:00
switch ( ( kInterMasterId ) packet . Id ) {
case kInterMasterId . KeyExchange :
Key . ParseResponsePacket ( packet ) ;
if ( ! Key . Succeeded ) {
Disconnect ( Frame . kClosingReason . ProtocolError , "Could not exchange keys." ) ;
return ;
}
2017-09-07 21:00:03 +00:00
Encryptor = new StreamCipher ( Key . PrivateKey ) ;
2017-08-18 21:01:11 +00:00
break ;
case kInterMasterId . LoginAttempt :
2017-09-14 19:14:07 +00:00
if ( packet . RegionCount ! = 3 | | ! packet . CheckRegionsMaxLength ( 0 , 16 , 255 ) | | ! packet . CheckRegionLengths ( 2 , 2 ) )
2017-09-08 21:06:55 +00:00
break ;
2017-08-18 21:01:11 +00:00
2017-09-14 19:14:07 +00:00
Session session ;
2017-09-08 21:06:55 +00:00
using ( var db = new ScapeDb ( ) ) {
2017-09-12 20:59:55 +00:00
User user ;
if ( ( user = db . Users . FirstOrDefault ( x = > x . Username = = packet [ 0 ] ) ) = = null ) {
SendEncrypted ( new Packet ( kInterMasterId . LoginAttempt , Convert . ToByte ( false ) , "User does not exist." ) ) ;
break ;
}
2017-09-13 21:02:39 +00:00
if ( packet [ 1 ] . Str . Trim ( ) = = "" | | ! packet [ 1 ] . Str . CheckPassword ( user . Password ) ) {
2017-09-12 20:59:55 +00:00
SendEncrypted ( new Packet ( kInterMasterId . LoginAttempt , Convert . ToByte ( false ) , "Password is incorrect." ) ) ;
break ;
}
if ( user . Session ? . DeltaLastPing . TotalMinutes < 3 ) {
SendEncrypted ( new Packet ( kInterMasterId . LoginAttempt , Convert . ToByte ( false ) , "You are already logged in. Log out or try again shortly." ) ) ;
break ;
}
2017-09-14 19:14:07 +00:00
ushort serverId = packet [ 2 ] . Raw . UnpackUInt16 ( ) ;
if ( ! MasterServerList . HasId ( serverId ) ) {
2017-09-12 20:59:55 +00:00
SendEncrypted ( new Packet ( kInterMasterId . LoginAttempt , Convert . ToByte ( false ) , "The world you have specified is offline." ) ) ;
break ;
}
if ( user . Session ? . DeltaLastPing . TotalMinutes > = 3 ) {
db . Entry ( user . Session ) . State = EntityState . Deleted ;
db . SaveChanges ( ) ;
}
2017-09-14 19:14:07 +00:00
db . Sessions . Add ( session = new Session {
2017-09-12 20:59:55 +00:00
Id = user . Id ,
Secret = RNG . NextBytes ( 16 ) ,
2017-09-14 19:14:07 +00:00
ServerId = serverId ,
2017-09-12 20:59:55 +00:00
LastPing = DateTime . UtcNow
} ) ;
2017-09-14 19:14:07 +00:00
2017-09-12 20:59:55 +00:00
db . SaveChanges ( ) ;
2017-09-08 21:06:55 +00:00
}
2017-09-14 19:14:07 +00:00
var server = MasterServerList . Get ( ( ushort ) session . ServerId ) ;
SendEncrypted ( new Packet ( kInterMasterId . LoginAttempt , Convert . ToByte ( true ) , session . Secret , server . Address . ToString ( ) , server . Port . Pack ( ) ) ) ;
2017-08-18 21:01:11 +00:00
break ;
case kInterMasterId . RegistrationAttempt :
2017-09-14 19:14:07 +00:00
if ( packet . RegionCount ! = 3 | | ! packet . CheckAllMaxLength ( 0xFF ) )
break ;
if ( ! packet [ 0 ] . Raw . IsAsciiString ( ) ) {
SendEncrypted ( new Packet ( kInterMasterId . RegistrationAttempt , Convert . ToByte ( false ) , "Your username cannot contain unicode characters." ) ) ;
2017-09-13 21:02:39 +00:00
break ;
2017-09-14 19:14:07 +00:00
}
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 ;
}
2017-09-13 21:02:39 +00:00
2017-09-08 21:06:55 +00:00
using ( var db = new ScapeDb ( ) ) {
2017-09-14 19:14:07 +00:00
if ( db . Users . FirstOrDefault ( x = > x . Username = = username ) ! = null ) {
SendEncrypted ( new Packet ( kInterMasterId . RegistrationAttempt , Convert . ToByte ( false ) , "This username is already in use." ) ) ;
2017-09-13 21:02:39 +00:00
break ;
}
2017-09-14 19:14:07 +00:00
if ( db . Users . FirstOrDefault ( x = > x . Email = = email ) ! = null ) {
SendEncrypted ( new Packet ( kInterMasterId . RegistrationAttempt , Convert . ToByte ( false ) , "This email address is already in use." ) ) ;
2017-09-13 21:02:39 +00:00
break ;
}
2017-09-14 19:14:07 +00:00
// TODO email activation
db . Users . Add ( new User {
Username = username ,
Password = password . HashPassword ( ) ,
Email = email ,
Joined = DateTime . UtcNow
} ) ;
2017-09-13 21:02:39 +00:00
2017-09-14 19:14:07 +00:00
db . SaveChanges ( ) ;
2017-09-08 21:06:55 +00:00
}
2017-09-14 19:14:07 +00:00
SendEncrypted ( new Packet ( kInterMasterId . RegistrationAttempt , Convert . ToByte ( true ) , "Registration was successful." ) ) ;
2017-08-18 21:01:11 +00:00
break ;
2017-09-13 21:02:39 +00:00
case kInterMasterId . ServerListing :
SendEncrypted ( MasterServerList . ReportPacket ) ;
break ;
2017-08-18 21:01:11 +00:00
default :
Disconnect ( Frame . kClosingReason . ProtocolError , "Packet ID could not be understood at this time." ) ;
break ;
}
2017-09-06 20:59:38 +00:00
Console . WriteLine ( $"{Id} says {data.GetString()}" ) ;
2017-08-18 21:01:11 +00:00
}
2017-09-12 20:59:55 +00:00
private void Send ( Packet packet ) {
Send ( packet . GetBytes ( ) ) ;
}
private void SendEncrypted ( Packet packet ) {
Send ( Encryptor . Parse ( packet . GetBytes ( ) ) ) ;
}
2017-06-05 12:20:39 +00:00
}
}