diff --git a/client/error.html b/client/error.html index 595db3e..fe91e81 100644 --- a/client/error.html +++ b/client/error.html @@ -116,8 +116,10 @@

An error occurred.

Details:

- -

Please report this error to aleco@aroltd.com. +

+ Please report this error to aleco@aroltd.com. +

+

Click here to try again.

\ No newline at end of file diff --git a/client/src/Connection.ts b/client/src/Connection.ts index d5a7269..dbfb57f 100644 --- a/client/src/Connection.ts +++ b/client/src/Connection.ts @@ -13,6 +13,7 @@ class Connection { // FLAG replace hard coded url with one loaded from a config file Connection.sock = new WebSocket("ws://localhost:6770"); + Connection.sock.binaryType = "arraybuffer"; Connection.onOpenFunc = onOpen; Connection.sock.onopen = Connection.onOpen; @@ -28,8 +29,10 @@ class Connection { } private static onMessage(event: any): void { - var msg = Packet.fromBytes(event.data); + var raw = new Uint8Array(event.data); + var msg = Packet.fromBytes(raw); console.log(msg); + console.log(msg[1].toString()); switch(msg.id) { case kPacketId.KeyExchange: diff --git a/client/src/Entrypoint.ts b/client/src/Entrypoint.ts index abc61bc..c92133e 100644 --- a/client/src/Entrypoint.ts +++ b/client/src/Entrypoint.ts @@ -1,6 +1,3 @@ -/// -/// - class Entrypoint { private static initStatus = { fileCache: false @@ -16,6 +13,8 @@ class Entrypoint { } public static start(): void { + Connection.open(); + FileCache.initCache( // SUCCESS () => { diff --git a/client/src/Extensions.ts b/client/src/Extensions.ts index cdd3ccb..5499fc6 100644 --- a/client/src/Extensions.ts +++ b/client/src/Extensions.ts @@ -1,5 +1,3 @@ -/// - // ** STRING EXTENSIONS ** \\ interface String { @@ -162,6 +160,8 @@ interface Uint8Array { unpackFloat(offset?: number): number; unpackDouble(offset?: number): number; + + toHexString(): string; } Uint8Array.prototype.unpackInt16 = function(offset: number = 0): number { @@ -202,4 +202,34 @@ Uint8Array.prototype.toString = function(): string { raw += String.fromCharCode.apply(null, this.subarray(chunkSize*i, chunkSize*i + chunkSize)); } return utf8.decode(raw); +} + +Uint8Array.prototype.toHexString = function(): string { + var ret = ""; + for(var i = 0; i < this.byteLength; ++i) { + var byte = this[i].toString(16); + if(byte.length < 2) + byte = "0"+ byte; + + ret += byte +" "; + } + + return ret.trim(); +} + + +// ** BIGINT EXTENSIONS ** \\ + +interface bigInt { + toByteArray(): Uint8Array; +} + +bigInt.prototype.toByteArray = function(): Uint8Array { + var hexString: string = this.toString(16); + var byteCount = Math.ceil(hexString.length / 2); + var byteArray = new Uint8Array(byteCount); + + for(var i = 0; i < byteCount; ++i) { + byteArray[i] = parseInt(hexString.substr(Math.max(0, hexString.length - 2*(i+1)), hexString.length - 2*i), 16); + } } \ No newline at end of file diff --git a/client/src/FileCache.ts b/client/src/FileCache.ts index dce9442..2327f94 100644 --- a/client/src/FileCache.ts +++ b/client/src/FileCache.ts @@ -8,8 +8,10 @@ class FileCache { var db: IDBDatabase = event.target.result; var stores = db.objectStoreNames; + /* for(var i in stores) - db.deleteObjectStore(stores[i]); + db.deleteObjectStore(i); + */ db.createObjectStore("files", {keyPath: "name", autoIncrement: false}); db.createObjectStore("metadata", {keyPath: "name", autoIncrement: false}); diff --git a/client/src/Packet.ts b/client/src/Packet.ts index 3fb6abf..118280e 100644 --- a/client/src/Packet.ts +++ b/client/src/Packet.ts @@ -23,18 +23,26 @@ class Packet { public getRegionString(region: number): string { return this.getRegion(region).toString(); } - public addRegion(region: object): void { + public addRegion(region: object): Packet { if(typeof region == "string") this._regions.push((region).toByteArray()); else if(region instanceof Uint8Array) this._regions.push(region); + + this[this.regionCount-1] = this._regions[this.regionCount-1]; + return this; } - public Packet(id: kPacketId, regions: any[]) { - this._id = id; + private constructor() {} + + public static create(id: kPacketId, regions: any[]): Packet { + var packet = new Packet; + packet._id = id; regions.forEach(region => { - this.addRegion(region); + packet.addRegion(region); }); + + return packet; } public static fromBytes(bytes: Uint8Array): Packet { @@ -58,7 +66,7 @@ class Packet { } for(var i = 0; i < regionCount; ++i) { - packet.regions.push(bytes.subarray(ptr, ptr + regionLengths[i])); + packet.addRegion(bytes.subarray(ptr, ptr + regionLengths[i])); ptr += regionLengths[i]; } diff --git a/server/DAL/ScapeDb.Context.cs b/server/DAL/ScapeDb.Context.cs index d839c65..8918cb4 100644 --- a/server/DAL/ScapeDb.Context.cs +++ b/server/DAL/ScapeDb.Context.cs @@ -7,7 +7,7 @@ // //------------------------------------------------------------------------------ -namespace Server.DAL +namespace CircleScape.DAL { using System; using System.Data.Entity; diff --git a/server/DAL/Sessions.cs b/server/DAL/Sessions.cs index fd63ee1..47c442c 100644 --- a/server/DAL/Sessions.cs +++ b/server/DAL/Sessions.cs @@ -7,7 +7,7 @@ // //------------------------------------------------------------------------------ -namespace Server.DAL +namespace CircleScape.DAL { using System; using System.Collections.Generic; diff --git a/server/DAL/Users.cs b/server/DAL/Users.cs index a8d3abc..e8d1985 100644 --- a/server/DAL/Users.cs +++ b/server/DAL/Users.cs @@ -7,7 +7,7 @@ // //------------------------------------------------------------------------------ -namespace Server.DAL +namespace CircleScape.DAL { using System; using System.Collections.Generic; diff --git a/server/Encryption/Cipher.cs b/server/Encryption/Cipher.cs index 2ae5392..f0afa85 100644 --- a/server/Encryption/Cipher.cs +++ b/server/Encryption/Cipher.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using System.Numerics; using Square; -namespace Server.Encryption { +namespace CircleScape.Encryption { class Cipher { private byte[] Key = new byte[512 / 8]; private byte[] State = new byte[256]; diff --git a/server/Encryption/KeyExchange.cs b/server/Encryption/KeyExchange.cs index 2594069..ff0beaa 100644 --- a/server/Encryption/KeyExchange.cs +++ b/server/Encryption/KeyExchange.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using System.Numerics; using Square; -namespace Server.Encryption { +namespace CircleScape.Encryption { class KeyExchange { private BigInteger Secret; public BigInteger Generator { get; private set; } = 2; @@ -22,7 +22,12 @@ namespace Server.Encryption { } public Packet GenerateRequestPacket() { - return new Packet(Packet.kId.KeyExchange, Generator.ToHexString(), Modulus.ToHexString(), BigInteger.ModPow(Generator, Secret, Modulus).ToHexString()); + return new Packet( + Packet.kId.KeyExchange, + Generator.ToHexString(), + Modulus.ToHexString(), + BigInteger.ModPow(Generator, Secret, Modulus).ToHexString() + ); } public BigInteger ParseResponsePacket(Packet packet) { diff --git a/server/Entrypoint.cs b/server/Entrypoint.cs index c42f420..60010cf 100644 --- a/server/Entrypoint.cs +++ b/server/Entrypoint.cs @@ -4,22 +4,24 @@ using System.Data.SQLite; using System.Linq; using System.Text; using System.Threading.Tasks; -using Server.DAL; +using CircleScape.DAL; using System.Numerics; using Square; -namespace Server { +namespace CircleScape { class Entrypoint { static void Main(string[] args) { var server = new Kneesocks.Server(6770, PoolManager.Pending); server.Start(); - while(true) { + /*while(true) { var send = Console.ReadLine(); PoolManager.Pending.Broadcast(Encoding.UTF8.GetBytes(send)); // logic processing loop - } + }*/ + + Console.ReadLine(); server.Stop(); PoolManager.Dispose(); diff --git a/server/Libraries/Kneesocks/Connection.cs b/server/Libraries/Kneesocks/Connection.cs index 9602b84..1ab5a71 100644 --- a/server/Libraries/Kneesocks/Connection.cs +++ b/server/Libraries/Kneesocks/Connection.cs @@ -156,13 +156,13 @@ namespace Kneesocks { } private void ReadIfNotNull(ref byte[] buffer, int length) { - buffer = buffer == null ? Buffer.AttemptRead(length) - : buffer; + buffer = buffer ?? Buffer.AttemptRead(length) +; } private void ReadIfNotNull(ref byte[] buffer, string terminator) { - buffer = buffer == null ? Buffer.AttemptRead(terminator) - : buffer; + buffer = buffer ?? Buffer.AttemptRead(terminator) +; } internal void Parse() { diff --git a/server/Libraries/Kneesocks/Frame.cs b/server/Libraries/Kneesocks/Frame.cs index 4136dc6..30611c5 100644 --- a/server/Libraries/Kneesocks/Frame.cs +++ b/server/Libraries/Kneesocks/Frame.cs @@ -85,9 +85,13 @@ namespace Kneesocks { | (IsMasked ? 0x80 : 0x0)); if(headerLengthFirstByte >= 0x7E) { - var upperBound = headerLengthFirstByte == 0x7E ? 2 : 8; - for(var i = 0; i < upperBound; ++i) - returnValue[2 + i] |= (byte)((bodySize >> (8*(upperBound - i))) & 0xFF); + var lengthBytes = + headerLengthFirstByte == 0x7E + ? ((UInt16)bodySize).Pack() + : bodySize.Pack(); + + for(var i = 0; i < lengthBytes.Length; ++i) + returnValue[2 + i] = lengthBytes[i]; } if(IsMasked) diff --git a/server/Libraries/Kneesocks/Stack.cs b/server/Libraries/Kneesocks/Stack.cs index f7487fd..cc05643 100644 --- a/server/Libraries/Kneesocks/Stack.cs +++ b/server/Libraries/Kneesocks/Stack.cs @@ -51,8 +51,7 @@ namespace Kneesocks { if(connected) { try { client.Parse(); - if(CheckIfConnected(client)) - connected = false; + connected = CheckIfConnected(client); } catch { connected = false; } diff --git a/server/Socks/ActiveConnection.cs b/server/Socks/ActiveConnection.cs index 96342a0..c3b475a 100644 --- a/server/Socks/ActiveConnection.cs +++ b/server/Socks/ActiveConnection.cs @@ -5,7 +5,7 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; -namespace Server { +namespace CircleScape { class ActiveConnection : Kneesocks.Connection { } diff --git a/server/Socks/Packet.cs b/server/Socks/Packet.cs index df3304f..4fd0795 100644 --- a/server/Socks/Packet.cs +++ b/server/Socks/Packet.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; using Square; -namespace Server { +namespace CircleScape { class Packet { public enum kId { KeyExchange = 0, @@ -17,7 +17,7 @@ namespace Server { get => new Packet { IsLegal = false }; } - public static Packet FromRaw(byte[] raw) { + public static Packet FromBytes(byte[] raw) { if(raw.Length < 3) return ErrorPacket; @@ -82,11 +82,13 @@ namespace Server { get => new Region(Regions[i]); } - public void AddRegion(object region) { + public Packet AddRegion(object region) { if(region.GetType() == typeof(byte[])) Regions.Add((byte[])region); else if(region.GetType() == typeof(string)) Regions.Add(((string)region).GetBytes()); + + return this; } public byte[] GetBytes() { diff --git a/server/Socks/PendingConnection.cs b/server/Socks/PendingConnection.cs index 8a1fb14..a55bbb5 100644 --- a/server/Socks/PendingConnection.cs +++ b/server/Socks/PendingConnection.cs @@ -6,15 +6,21 @@ using System.Text; using System.Threading.Tasks; using Square; using Kneesocks; +using CircleScape.Encryption; -namespace Server { +namespace CircleScape { class PendingConnection : Connection { private DateTime ConnectionOpened; + private KeyExchange Key; + private Cipher Encryptor; protected override void OnOpen() { ConnectionOpened = DateTime.UtcNow; + Key = new KeyExchange(); + + Send(Key.GenerateRequestPacket().GetBytes()); } protected override void OnParse() { @@ -24,6 +30,24 @@ namespace Server { } protected override void OnReceive(byte[] data) { + var packet = Packet.FromBytes(data); + if(!packet.IsLegal) { + Disconnect(Frame.kClosingReason.ProtocolError, "Packet received was not legal."); + return; + } + + switch(packet.Id) { + case Packet.kId.KeyExchange: + Key.ParseResponsePacket(packet); + if(!Key.Succeeded) { + Disconnect(Frame.kClosingReason.ProtocolError, "Could not exchange keys."); + return; + } + + Encryptor = new Cipher(Key.PrivateKey); + break; + } + Console.WriteLine(Id + " says " + data.GetString()); } } diff --git a/server/Socks/PoolManager.cs b/server/Socks/PoolManager.cs index 091dad0..4782cd6 100644 --- a/server/Socks/PoolManager.cs +++ b/server/Socks/PoolManager.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Kneesocks; using System.Net.Sockets; -namespace Server { +namespace CircleScape { static class PoolManager { private static Pool PendingConnectionsPool; private static Pool ActiveConnectionsPool;