diff --git a/Esiur/Core/ExceptionCode.cs b/Esiur/Core/ExceptionCode.cs index 05314c1..9ce4ff5 100644 --- a/Esiur/Core/ExceptionCode.cs +++ b/Esiur/Core/ExceptionCode.cs @@ -43,5 +43,7 @@ public enum ExceptionCode : ushort AlreadyUnlistened, NotListenable, ParseError, - Timeout + Timeout, + NotSupported, + NotImplemented } diff --git a/Esiur/Data/Map.cs b/Esiur/Data/Map.cs index e216ea5..087bb81 100644 --- a/Esiur/Data/Map.cs +++ b/Esiur/Data/Map.cs @@ -63,15 +63,22 @@ public interface IMap public class Map : IEnumerable>, IMap { - //public struct StructureMetadata - //{ - // public KT[] Keys; - // public VT[] Types; - //} - - private Dictionary dic = new Dictionary();// StringComparer.OrdinalIgnoreCase); + private Dictionary dic = new Dictionary(); private object syncRoot = new object(); + // Change map types + public Map Select + (Func, KeyValuePair> selector) + { + var rt = new Map(); + foreach(var kv in dic) + { + var nt = selector(kv); + rt.dic.Add(nt.Key, nt.Value); + } + + return rt; + } public bool ContainsKey(KT key) { diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj index 1a0a12b..77e43da 100644 --- a/Esiur/Esiur.csproj +++ b/Esiur/Esiur.csproj @@ -49,6 +49,7 @@ + diff --git a/Esiur/Misc/Global.cs b/Esiur/Misc/Global.cs index 05053ae..be21d23 100644 --- a/Esiur/Misc/Global.cs +++ b/Esiur/Misc/Global.cs @@ -318,7 +318,6 @@ public static class Global } - public static byte[] GenerateBytes(int length) { var b = new byte[length]; diff --git a/Esiur/Net/HTTP/HTTPConnection.cs b/Esiur/Net/HTTP/HTTPConnection.cs index 1cd1db8..3fa345d 100644 --- a/Esiur/Net/HTTP/HTTPConnection.cs +++ b/Esiur/Net/HTTP/HTTPConnection.cs @@ -33,10 +33,11 @@ using System.Collections; using System.Collections.Generic; using Esiur.Net.Sockets; using Esiur.Data; -using Esiur.Net.Packets; using Esiur.Misc; using System.Security.Cryptography; using Esiur.Core; +using Esiur.Net.Packets.WebSocket; +using Esiur.Net.Packets.HTTP; namespace Esiur.Net.HTTP; public class HTTPConnection : NetworkConnection @@ -131,7 +132,7 @@ public class HTTPConnection : NetworkConnection response.Headers["Sec-WebSocket-Protocol"] = request.Headers["Sec-WebSocket-Protocol"]; - response.Number = HTTPResponsePacket.ResponseCode.Switching; + response.Number = HTTPResponseCode.Switching; response.Text = "Switching Protocols"; return true; @@ -172,7 +173,7 @@ public class HTTPConnection : NetworkConnection Send(); } - public void Send(HTTPResponsePacket.ComposeOptions Options = HTTPResponsePacket.ComposeOptions.AllCalculateLength) + public void Send(HTTPComposeOption Options = HTTPComposeOption.AllCalculateLength) { if (Response.Handled) return; @@ -210,7 +211,7 @@ public class HTTPConnection : NetworkConnection // Create a new one session = Server.CreateSession(Global.GenerateCode(12), 60 * 20); - HTTPResponsePacket.HTTPCookie cookie = new HTTPResponsePacket.HTTPCookie("SID", session.Id); + HTTPCookie cookie = new HTTPCookie("SID", session.Id); cookie.Expires = DateTime.MaxValue; cookie.Path = "/"; cookie.HttpOnly = true; @@ -253,7 +254,7 @@ public class HTTPConnection : NetworkConnection if (BL == 0) { - if (Request.Method == HTTPRequestPacket.HTTPMethod.UNKNOWN) + if (Request.Method == HTTPMethod.UNKNOWN) { Close(); return; @@ -312,7 +313,7 @@ public class HTTPConnection : NetworkConnection { if (!Server.Execute(this)) { - Response.Number = HTTPResponsePacket.ResponseCode.InternalServerError; + Response.Number = HTTPResponseCode.InternalServerError; Send("Bad Request"); Close(); } @@ -361,7 +362,7 @@ public class HTTPConnection : NetworkConnection if (!File.Exists(filename)) { - Response.Number = HTTPResponsePacket.ResponseCode.NotFound; + Response.Number = HTTPResponseCode.NotFound; Send("File Not Found"); return true; } @@ -375,10 +376,10 @@ public class HTTPConnection : NetworkConnection var ims = DateTime.Parse(Request.Headers["if-modified-since"]); if ((fileEditTime - ims).TotalSeconds < 2) { - Response.Number = HTTPResponsePacket.ResponseCode.NotModified; + Response.Number = HTTPResponseCode.NotModified; Response.Headers.Clear(); //Response.Text = "Not Modified"; - Send(HTTPResponsePacket.ComposeOptions.SpecifiedHeadersOnly); + Send(HTTPComposeOption.SpecifiedHeadersOnly); return true; } } @@ -390,12 +391,12 @@ public class HTTPConnection : NetworkConnection - Response.Number = HTTPResponsePacket.ResponseCode.OK; + Response.Number = HTTPResponseCode.OK; // Fri, 30 Oct 2007 14:19:41 GMT Response.Headers["Last-Modified"] = fileEditTime.ToString("ddd, dd MMM yyyy HH:mm:ss"); FileInfo fi = new FileInfo(filename); Response.Headers["Content-Length"] = fi.Length.ToString(); - Send(HTTPResponsePacket.ComposeOptions.SpecifiedHeadersOnly); + Send(HTTPComposeOption.SpecifiedHeadersOnly); //var fd = File.ReadAllBytes(filename); diff --git a/Esiur/Net/HTTP/HTTPServer.cs b/Esiur/Net/HTTP/HTTPServer.cs index 1fded44..affe307 100644 --- a/Esiur/Net/HTTP/HTTPServer.cs +++ b/Esiur/Net/HTTP/HTTPServer.cs @@ -35,12 +35,12 @@ using Esiur.Net.Sockets; using Esiur.Data; using Esiur.Misc; using Esiur.Core; -using Esiur.Net.Packets; using System.Security.Cryptography.X509Certificates; using Esiur.Resource; using System.Text.RegularExpressions; using System.Linq; using System.Reflection; +using Esiur.Net.Packets.HTTP; namespace Esiur.Net.HTTP; public class HTTPServer : NetworkServer, IResource @@ -48,17 +48,17 @@ public class HTTPServer : NetworkServer, IResource Dictionary sessions = new Dictionary(); HTTPFilter[] filters = new HTTPFilter[0]; - Dictionary> routes = new() + Dictionary> routes = new() { - [HTTPRequestPacket.HTTPMethod.GET] = new List(), - [HTTPRequestPacket.HTTPMethod.POST] = new List(), - [HTTPRequestPacket.HTTPMethod.HEAD] = new List(), - [HTTPRequestPacket.HTTPMethod.OPTIONS] = new List(), - [HTTPRequestPacket.HTTPMethod.UNKNOWN] = new List(), - [HTTPRequestPacket.HTTPMethod.DELETE] = new List(), - [HTTPRequestPacket.HTTPMethod.TRACE] = new List(), - [HTTPRequestPacket.HTTPMethod.CONNECT] = new List(), - [HTTPRequestPacket.HTTPMethod.PUT] = new List() + [HTTPMethod.GET] = new List(), + [HTTPMethod.POST] = new List(), + [HTTPMethod.HEAD] = new List(), + [HTTPMethod.OPTIONS] = new List(), + [HTTPMethod.UNKNOWN] = new List(), + [HTTPMethod.DELETE] = new List(), + [HTTPMethod.TRACE] = new List(), + [HTTPMethod.CONNECT] = new List(), + [HTTPMethod.PUT] = new List() }; //List GetRoutes = new List(); @@ -243,14 +243,14 @@ public class HTTPServer : NetworkServer, IResource public void MapGet(string pattern, Delegate handler) { var regex = Global.GetRouteRegex(pattern); - var list = routes[HTTPRequestPacket.HTTPMethod.GET]; + var list = routes[HTTPMethod.GET]; list.Add(new RouteInfo(handler, regex)); } public void MapPost(string pattern, Delegate handler) { var regex = Global.GetRouteRegex(pattern); - var list = routes[HTTPRequestPacket.HTTPMethod.POST]; + var list = routes[HTTPMethod.POST]; list.Add(new RouteInfo(handler, regex)); } diff --git a/Esiur/Net/HTTP/IIPoHTTP.cs b/Esiur/Net/HTTP/IIPoHTTP.cs index 6ee669b..6b3a64f 100644 --- a/Esiur/Net/HTTP/IIPoHTTP.cs +++ b/Esiur/Net/HTTP/IIPoHTTP.cs @@ -17,9 +17,9 @@ public class IIPoHTTP : HTTPFilter if (sender.Request.URL != "iip") return new AsyncReply(false); - IIPPacket.IIPPacketAction action = (IIPPacket.IIPPacketAction)Convert.ToByte(sender.Request.Query["a"]); + IIPPacketAction action = (IIPPacketAction)Convert.ToByte(sender.Request.Query["a"]); - if (action == IIPPacket.IIPPacketAction.QueryLink) + if (action == IIPPacketAction.QueryLink) { EntryPoint.Query(sender.Request.Query["l"], null).Then(x => { diff --git a/Esiur/Net/HTTP/IIPoWS.cs b/Esiur/Net/HTTP/IIPoWS.cs index 9779fc8..3ddd5fd 100644 --- a/Esiur/Net/HTTP/IIPoWS.cs +++ b/Esiur/Net/HTTP/IIPoWS.cs @@ -70,48 +70,6 @@ public class IIPoWS : HTTPFilter return new AsyncReply(false); - /* - if (sender.Request.Filename.StartsWith("/iip/")) - { - // find the service - var path = sender.Request.Filename.Substring(5);// sender.Request.Query["path"]; - - - Warehouse.Get(path).Then((r) => - { - if (r is DistributedServer) - { - var httpServer = sender.Parent; - var iipServer = r as DistributedServer; - var tcpSocket = sender.Unassign(); - if (tcpSocket == null) - return; - - var wsSocket = new WSSocket(tcpSocket); - httpServer.RemoveConnection(sender); - - //httpServer.Connections.Remove(sender); - var iipConnection = new DistributedConnection(); -// iipConnection.OnReady += IipConnection_OnReady; -// iipConnection.Server = iipServer; -// iipConnection.Assign(wsSocket); - - iipServer.AddConnection(iipConnection); - iipConnection.Assign(wsSocket); - wsSocket.Begin(); - } - }); - - return true; - } - - return false; - */ - } - - private void IipConnection_OnReady(DistributedConnection sender) - { - Warehouse.Put(sender.RemoteUsername, sender, null, sender.Server).Wait(); } public override AsyncReply Trigger(ResourceTrigger trigger) diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs index 577af26..2c0d0e0 100644 --- a/Esiur/Net/IIP/DistributedConnection.cs +++ b/Esiur/Net/IIP/DistributedConnection.cs @@ -32,7 +32,6 @@ using Esiur.Net.Sockets; using Esiur.Data; using Esiur.Misc; using Esiur.Core; -using Esiur.Net.Packets; using Esiur.Resource; using Esiur.Security.Authority; using Esiur.Resource.Template; @@ -43,17 +42,24 @@ using Esiur.Net.HTTP; using System.Timers; using System.Threading.Tasks; using System.Runtime.InteropServices; +using Esiur.Net.Packets.HTTP; +using System.ComponentModel.DataAnnotations; +using static System.Collections.Specialized.BitVector32; +using Esiur.Security.Membership; +using Esiur.Net.Packets; +using System.Reflection.PortableExecutable; +using System.Net.Http.Headers; namespace Esiur.Net.IIP; public partial class DistributedConnection : NetworkConnection, IStore { + + // Delegates public delegate void ReadyEvent(DistributedConnection sender); public delegate void ErrorEvent(DistributedConnection sender, byte errorCode, string errorMessage); public delegate void ResumedEvent(DistributedConnection sender); - - Timer keepAliveTimer; - + // Events /// /// Ready event is raised when autoReconnect is enabled and the connection is restored. @@ -71,17 +77,23 @@ public partial class DistributedConnection : NetworkConnection, IStore public event ErrorEvent OnError; + // Fields + bool invalidCredentials = false; + + Timer keepAliveTimer; + DateTime? lastKeepAliveSent; + DateTime? lastKeepAliveReceived; + IIPPacket packet = new IIPPacket(); IIPAuthPacket authPacket = new IIPAuthPacket(); + Session session; AsyncReply openReply; byte[] localPasswordOrToken; - byte[] localNonce, remoteNonce; - bool ready, readyToEstablish; string _hostname; @@ -89,30 +101,10 @@ public partial class DistributedConnection : NetworkConnection, IStore bool initialPacket = true; - DateTime loginDate; + // Properties - - /// - /// Local username to authenticate ourselves. - /// - public string LocalUsername => session.LocalAuthentication.Username;// { get; set; } - - /// - /// Peer's username. - /// - public string RemoteUsername => session.RemoteAuthentication.Username;// { get; set; } - - /// - /// Working domain. - /// - //public string Domain { get { return domain; } } - - - /// - /// The session related to this connection. - /// - public Session Session => session; + public DateTime LoginDate { get; private set; } /// /// Distributed server responsible for this connection, usually for incoming connections. @@ -120,7 +112,55 @@ public partial class DistributedConnection : NetworkConnection, IStore public DistributedServer Server { get; internal set; } - [Export] public virtual ConnectionStatus Status { get; set; } + /// + /// The session related to this connection. + /// + public Session Session => session; + + [Export] + public virtual ConnectionStatus Status { get; private set; } + + [Export] + public virtual uint Jitter { get; private set; } + + // Attributes + + [Attribute] + public uint KeepAliveTime { get; set; } = 10; + + [Attribute] + public ExceptionLevel ExceptionLevel { get; set; } + = ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace; + + [Attribute] + public Func, AsyncReply> Authenticator { get; set; } + + [Attribute] + public bool AutoReconnect { get; set; } = false; + + [Attribute] + public uint ReconnectInterval { get; set; } = 5; + + [Attribute] + public string Username { get; set; } + + [Attribute] + public bool UseWebSocket { get; set; } + + [Attribute] + public bool SecureWebSocket { get; set; } + + [Attribute] + public string Password { get; set; } + + [Attribute] + public string Token { get; set; } + + [Attribute] + public ulong TokenIndex { get; set; } + + [Attribute] + public string Domain { get; set; } public bool Remove(IResource resource) { @@ -132,50 +172,9 @@ public partial class DistributedConnection : NetworkConnection, IStore /// Send data to the other end as parameters /// /// Values will be converted to bytes then sent. - internal SendList SendParams(AsyncReply reply = null)//params object[] values) + internal SendList SendParams(AsyncReply reply = null) { return new SendList(this, reply); - - /* - var data = BinaryList.ToBytes(values); - - if (ready) - { - var cmd = (IIPPacketCommand)(data[0] >> 6); - - if (cmd == IIPPacketCommand.Event) - { - var evt = (IIPPacketEvent)(data[0] & 0x3f); - //Console.Write("Sent: " + cmd.ToString() + " " + evt.ToString()); - } - else if (cmd == IIPPacketCommand.Report) - { - var r = (IIPPacketReport)(data[0] & 0x3f); - //Console.Write("Sent: " + cmd.ToString() + " " + r.ToString()); - - } - else - { - var act = (IIPPacketAction)(data[0] & 0x3f); - //Console.Write("Sent: " + cmd.ToString() + " " + act.ToString()); - - } - - //foreach (var param in values) - // Console.Write(", " + param); - - //Console.WriteLine(); - } - - - Send(data); - - //StackTrace stackTrace = new StackTrace(; - - // Get calling method name - - //Console.WriteLine("TX " + hostType + " " + ar.Length + " " + stackTrace.GetFrame(1).GetMethod().ToString()); - */ } /// @@ -212,13 +211,9 @@ public partial class DistributedConnection : NetworkConnection, IStore { base.Assign(socket); - session.RemoteAuthentication.Source.Attributes[SourceAttributeType.IPv4] = socket.RemoteEndPoint.Address; - session.RemoteAuthentication.Source.Attributes[SourceAttributeType.Port] = socket.RemoteEndPoint.Port; - session.LocalAuthentication.Source.Attributes[SourceAttributeType.IPv4] = socket.LocalEndPoint.Address; - session.LocalAuthentication.Source.Attributes[SourceAttributeType.Port] = socket.LocalEndPoint.Port; - + session.LocalHeaders[IIPAuthPacketHeader.IPv4] = socket.RemoteEndPoint.Address.Address; if (socket.State == SocketState.Established && - session.LocalAuthentication.Type == AuthenticationType.Client) + session.AuthenticationType == AuthenticationType.Client) { Declare(); } @@ -226,105 +221,56 @@ public partial class DistributedConnection : NetworkConnection, IStore private void Declare() { - var dmn = DC.ToBytes(session.LocalAuthentication.Domain); if (session.KeyExchanger != null) { // create key var key = session.KeyExchanger.GetPublicKey(); + session.LocalHeaders[IIPAuthPacketHeader.CipherKey] = key; + } - if (session.LocalAuthentication.Method == AuthenticationMethod.Credentials) - { - // declare (Credentials -> No Auth, No Enctypt) - var un = DC.ToBytes(session.LocalAuthentication.Username); + if (session.LocalMethod == AuthenticationMethod.Credentials + && session.RemoteMethod == AuthenticationMethod.None) + { + // change to Map for compatibility + var headers = Codec.Compose(session.LocalHeaders.Select(x => new KeyValuePair((byte)x.Key, x.Value)), this); - SendParams() - .AddUInt8(0x60 | 0x2) - .AddUInt8((byte)dmn.Length) - .AddUInt8Array(dmn) - .AddUInt16(session.KeyExchanger.Identifier) - .AddUInt16((ushort)key.Length) - .AddUInt8Array(key) - .AddUInt8Array(localNonce) - .AddUInt8((byte)un.Length) - .AddUInt8Array(un) - .Done();//, dmn, localNonce, (byte)un.Length, un); - } - else if (session.LocalAuthentication.Method == AuthenticationMethod.Token) - { + // declare (Credentials -> No Auth, No Enctypt) + SendParams() + .AddUInt8((byte)IIPAuthPacketInitialize.CredentialsNoAuth) + .AddUInt8Array(headers) + .Done(); - SendParams() - .AddUInt8(0x70 | 0x2) - .AddUInt8((byte)dmn.Length) - .AddUInt8Array(dmn) - .AddUInt16(session.KeyExchanger.Identifier) - .AddUInt16((ushort)key.Length) - .AddUInt8Array(key) - .AddUInt8Array(localNonce) - .AddUInt64(session.LocalAuthentication.TokenIndex) - .Done();//, dmn, localNonce, token + } + else if (session.LocalMethod == AuthenticationMethod.Token + && session.RemoteMethod == AuthenticationMethod.None) + { + // change to Map for compatibility + var headers = Codec.Compose(session.LocalHeaders.Select(x => new KeyValuePair((byte)x.Key, x.Value)), this); - } - else if (session.LocalAuthentication.Method == AuthenticationMethod.None) - { - // @REVIEW: MITM Attack can still occure - SendParams() - .AddUInt8(0x40 | 0x2) - .AddUInt8((byte)dmn.Length) - .AddUInt8Array(dmn) - .AddUInt16(session.KeyExchanger.Identifier) - .AddUInt16((ushort)key.Length) - .AddUInt8Array(key) - .Done();//, dmn, localNonce, token - } - else - { - throw new NotImplementedException("Authentication method is not implemented."); - } + SendParams() + .AddUInt8((byte)IIPAuthPacketInitialize.TokenNoAuth) + .AddUInt8Array(headers) + .Done(); + } + else if (session.LocalMethod == AuthenticationMethod.None + && session.RemoteMethod == AuthenticationMethod.None) + { + // change to Map for compatibility + var headers = Codec.Compose(session.LocalHeaders.Select(x => new KeyValuePair((byte)x.Key, x.Value)), this); + + // @REVIEW: MITM Attack can still occure + SendParams() + .AddUInt8((byte)IIPAuthPacketInitialize.NoAuthNoAuth) + .AddUInt8Array(headers) + .Done(); } else { - if (session.LocalAuthentication.Method == AuthenticationMethod.Credentials) - { - // declare (Credentials -> No Auth, No Enctypt) - - var un = DC.ToBytes(session.LocalAuthentication.Username); - - SendParams() - .AddUInt8(0x60) - .AddUInt8((byte)dmn.Length) - .AddUInt8Array(dmn) - .AddUInt8Array(localNonce) - .AddUInt8((byte)un.Length) - .AddUInt8Array(un) - .Done();//, dmn, localNonce, (byte)un.Length, un); - } - else if (session.LocalAuthentication.Method == AuthenticationMethod.Token) - { - - SendParams() - .AddUInt8(0x70) - .AddUInt8((byte)dmn.Length) - .AddUInt8Array(dmn) - .AddUInt8Array(localNonce) - .AddUInt64(session.LocalAuthentication.TokenIndex) - .Done();//, dmn, localNonce, token - - } - else if (session.LocalAuthentication.Method == AuthenticationMethod.None) - { - SendParams() - .AddUInt8(0x40) - .AddUInt8((byte)dmn.Length) - .AddUInt8Array(dmn) - .Done();//, dmn, localNonce, token - } - else - { - throw new NotImplementedException("Authentication method is not implemented."); - } + throw new NotImplementedException("Authentication method is not implemented."); } + } /// @@ -336,15 +282,15 @@ public partial class DistributedConnection : NetworkConnection, IStore /// Password. public DistributedConnection(Sockets.ISocket socket, string domain, string username, string password) { - this.session = new Session(new ClientAuthentication() - , new HostAuthentication()); - //Instance.Name = Global.GenerateCode(12); - //this.hostType = AuthenticationType.Client; - //this.domain = domain; - //this.localUsername = username; - session.LocalAuthentication.Domain = domain; - session.LocalAuthentication.Username = username; - session.LocalAuthentication.Method = AuthenticationMethod.Credentials; + this.session = new Session(); + + session.AuthenticationType = AuthenticationType.Client; + session.LocalHeaders[IIPAuthPacketHeader.Domain] = domain; + session.LocalHeaders[IIPAuthPacketHeader.Username] = username; + session.LocalMethod = AuthenticationMethod.Credentials; + session.RemoteMethod = AuthenticationMethod.None; + + this.localPasswordOrToken = DC.ToBytes(password); init(); @@ -354,16 +300,14 @@ public partial class DistributedConnection : NetworkConnection, IStore public DistributedConnection(Sockets.ISocket socket, string domain, ulong tokenIndex, string token) { - this.session = new Session(new ClientAuthentication() - , new HostAuthentication()); - //Instance.Name = Global.GenerateCode(12); - //this.hostType = AuthenticationType.Client; - //this.domain = domain; - //this.localUsername = username; - session.LocalAuthentication.Domain = domain; - session.LocalAuthentication.TokenIndex = tokenIndex; - session.LocalAuthentication.Method = AuthenticationMethod.Token; + this.session = new Session(); + + session.AuthenticationType = AuthenticationType.Client; + session.LocalHeaders[IIPAuthPacketHeader.Domain] = domain; + session.LocalHeaders[IIPAuthPacketHeader.TokenIndex] = tokenIndex; + session.LocalMethod = AuthenticationMethod.Credentials; + session.RemoteMethod = AuthenticationMethod.None; this.localPasswordOrToken = DC.ToBytes(token); init(); @@ -377,9 +321,9 @@ public partial class DistributedConnection : NetworkConnection, IStore /// public DistributedConnection() { - //myId = Global.GenerateCode(12); - // localParams.Host = DistributedParameters.HostType.Host; - session = new Session(new HostAuthentication(), new ClientAuthentication()); + session = new Session(); + session.AuthenticationType = AuthenticationType.Host; + session.LocalMethod = AuthenticationMethod.None; init(); } @@ -409,20 +353,13 @@ public partial class DistributedConnection : NetworkConnection, IStore x.Resource._UpdatePropertyByIndex(x.Index, x.Value); }); - - var r = new Random(); - localNonce = new byte[32]; - r.NextBytes(localNonce); + // set local nonce + session.LocalHeaders[IIPAuthPacketHeader.Nonce] = Global.GenerateBytes(32); keepAliveTimer = new Timer(KeepAliveInterval * 1000); keepAliveTimer.Elapsed += KeepAliveTimer_Elapsed; } - [Export] public virtual uint Jitter { get; set; } - - public uint KeepAliveTime { get; set; } = 10; - - DateTime? lastKeepAliveSent; private void KeepAliveTimer_Elapsed(object sender, ElapsedEventArgs e) { @@ -477,37 +414,13 @@ public partial class DistributedConnection : NetworkConnection, IStore private uint processPacket(byte[] msg, uint offset, uint ends, NetworkBuffer data, int chunkId) { - //var packet = new IIPPacket(); - - - - // packets++; - if (ready) { var rt = packet.Parse(msg, offset, ends); - //Console.WriteLine("Rec: " + chunkId + " " + packet.ToString()); - - /* - if (packet.Command == IIPPacketCommand.Event) - Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Event.ToString()); - else if (packet.Command == IIPPacketCommand.Report) - Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Report.ToString()); - else - Console.WriteLine("Rec: " + packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.ResourceId + " " + offset + "/" + ends); - */ - - - //packs.Add(packet.Command.ToString() + " " + packet.Action.ToString() + " " + packet.Event.ToString()); - - //if (packs.Count > 1) - // Console.WriteLine("P2"); - - //Console.WriteLine(""); if (rt <= 0) { - //Console.WriteLine("Hold"); + var size = ends - offset; data.HoldFor(msg, offset, size, size + (uint)(-rt)); return ends; @@ -515,25 +428,23 @@ public partial class DistributedConnection : NetworkConnection, IStore else { - //Console.WriteLine($"CMD {packet.Command} {offset} {ends}"); - offset += (uint)rt; - if (packet.Command == IIPPacket.IIPPacketCommand.Event) + if (packet.Command == IIPPacketCommand.Event) { switch (packet.Event) { - case IIPPacket.IIPPacketEvent.ResourceReassigned: + case IIPPacketEvent.ResourceReassigned: IIPEventResourceReassigned(packet.ResourceId, packet.NewResourceId); break; - case IIPPacket.IIPPacketEvent.ResourceDestroyed: + case IIPPacketEvent.ResourceDestroyed: IIPEventResourceDestroyed(packet.ResourceId); break; - case IIPPacket.IIPPacketEvent.PropertyUpdated: - IIPEventPropertyUpdated(packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg);// packet.Content); + case IIPPacketEvent.PropertyUpdated: + IIPEventPropertyUpdated(packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg); break; - case IIPPacket.IIPPacketEvent.EventOccurred: - IIPEventEventOccurred(packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg);//packet.Content); + case IIPPacketEvent.EventOccurred: + IIPEventEventOccurred(packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg); break; case IIPPacketEvent.ChildAdded: @@ -551,25 +462,25 @@ public partial class DistributedConnection : NetworkConnection, IStore break; } } - else if (packet.Command == IIPPacket.IIPPacketCommand.Request) + else if (packet.Command == IIPPacketCommand.Request) { switch (packet.Action) { // Manage - case IIPPacket.IIPPacketAction.AttachResource: + case IIPPacketAction.AttachResource: IIPRequestAttachResource(packet.CallbackId, packet.ResourceId); break; - case IIPPacket.IIPPacketAction.ReattachResource: + case IIPPacketAction.ReattachResource: IIPRequestReattachResource(packet.CallbackId, packet.ResourceId, packet.ResourceAge); break; - case IIPPacket.IIPPacketAction.DetachResource: + case IIPPacketAction.DetachResource: IIPRequestDetachResource(packet.CallbackId, packet.ResourceId); break; - case IIPPacket.IIPPacketAction.CreateResource: + case IIPPacketAction.CreateResource: //@TODO : fix this //IIPRequestCreateResource(packet.CallbackId, packet.StoreId, packet.ResourceId, packet.Content); break; - case IIPPacket.IIPPacketAction.DeleteResource: + case IIPPacketAction.DeleteResource: IIPRequestDeleteResource(packet.CallbackId, packet.ResourceId); break; case IIPPacketAction.AddChild: @@ -583,13 +494,13 @@ public partial class DistributedConnection : NetworkConnection, IStore break; // Inquire - case IIPPacket.IIPPacketAction.TemplateFromClassName: + case IIPPacketAction.TemplateFromClassName: IIPRequestTemplateFromClassName(packet.CallbackId, packet.ClassName); break; - case IIPPacket.IIPPacketAction.TemplateFromClassId: + case IIPPacketAction.TemplateFromClassId: IIPRequestTemplateFromClassId(packet.CallbackId, packet.ClassId); break; - case IIPPacket.IIPPacketAction.TemplateFromResourceId: + case IIPPacketAction.TemplateFromResourceId: IIPRequestTemplateFromResourceId(packet.CallbackId, packet.ResourceId); break; case IIPPacketAction.QueryLink: @@ -603,7 +514,7 @@ public partial class DistributedConnection : NetworkConnection, IStore IIPRequestResourceParents(packet.CallbackId, packet.ResourceId); break; - case IIPPacket.IIPPacketAction.ResourceHistory: + case IIPPacketAction.ResourceHistory: IIPRequestInquireResourceHistory(packet.CallbackId, packet.ResourceId, packet.FromDate, packet.ToDate); break; @@ -612,7 +523,7 @@ public partial class DistributedConnection : NetworkConnection, IStore break; // Invoke - case IIPPacket.IIPPacketAction.InvokeFunction: + case IIPPacketAction.InvokeFunction: IIPRequestInvokeFunction(packet.CallbackId, packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg); break; @@ -627,15 +538,15 @@ public partial class DistributedConnection : NetworkConnection, IStore // IIPRequestGetPropertyIfModifiedSince(packet.CallbackId, packet.ResourceId, packet.MethodIndex, packet.ResourceAge); // break; - case IIPPacket.IIPPacketAction.Listen: + case IIPPacketAction.Listen: IIPRequestListen(packet.CallbackId, packet.ResourceId, packet.MethodIndex); break; - case IIPPacket.IIPPacketAction.Unlisten: + case IIPPacketAction.Unlisten: IIPRequestUnlisten(packet.CallbackId, packet.ResourceId, packet.MethodIndex); break; - case IIPPacket.IIPPacketAction.SetProperty: + case IIPPacketAction.SetProperty: IIPRequestSetProperty(packet.CallbackId, packet.ResourceId, packet.MethodIndex, (TransmissionType)packet.DataType, msg); break; @@ -679,28 +590,28 @@ public partial class DistributedConnection : NetworkConnection, IStore } } - else if (packet.Command == IIPPacket.IIPPacketCommand.Reply) + else if (packet.Command == IIPPacketCommand.Reply) { switch (packet.Action) { // Manage - case IIPPacket.IIPPacketAction.AttachResource: + case IIPPacketAction.AttachResource: IIPReply(packet.CallbackId, packet.ClassId, packet.ResourceAge, packet.ResourceLink, packet.DataType, msg); break; - case IIPPacket.IIPPacketAction.ReattachResource: + case IIPPacketAction.ReattachResource: IIPReply(packet.CallbackId, packet.ResourceAge, packet.DataType, msg); break; - case IIPPacket.IIPPacketAction.DetachResource: + case IIPPacketAction.DetachResource: IIPReply(packet.CallbackId); break; - case IIPPacket.IIPPacketAction.CreateResource: + case IIPPacketAction.CreateResource: IIPReply(packet.CallbackId, packet.ResourceId); break; - case IIPPacket.IIPPacketAction.DeleteResource: + case IIPPacketAction.DeleteResource: case IIPPacketAction.AddChild: case IIPPacketAction.RemoveChild: case IIPPacketAction.RenameResource: @@ -709,9 +620,9 @@ public partial class DistributedConnection : NetworkConnection, IStore // Inquire - case IIPPacket.IIPPacketAction.TemplateFromClassName: - case IIPPacket.IIPPacketAction.TemplateFromClassId: - case IIPPacket.IIPPacketAction.TemplateFromResourceId: + case IIPPacketAction.TemplateFromClassName: + case IIPPacketAction.TemplateFromClassId: + case IIPPacketAction.TemplateFromResourceId: var content = msg.Clip(packet.DataType.Value.Offset, (uint)packet.DataType.Value.ContentLength); IIPReply(packet.CallbackId, TypeTemplate.Parse(content)); @@ -779,7 +690,7 @@ public partial class DistributedConnection : NetworkConnection, IStore IIPReportProgress(packet.CallbackId, ProgressType.Execution, packet.ProgressValue, packet.ProgressMax); break; case IIPPacketReport.ChunkStream: - IIPReportChunk(packet.CallbackId, (TransmissionType)packet.DataType, msg);// packet.Content); + IIPReportChunk(packet.CallbackId, (TransmissionType)packet.DataType, msg); break; } @@ -815,7 +726,7 @@ public partial class DistributedConnection : NetworkConnection, IStore HTTPConnection.Upgrade(req, res); - res.Compose(HTTPResponsePacket.ComposeOptions.AllCalculateLength); + res.Compose(HTTPComposeOption.AllCalculateLength); Send(res.Data); // replace my socket with websockets var tcpSocket = this.Unassign(); @@ -826,8 +737,8 @@ public partial class DistributedConnection : NetworkConnection, IStore { var res = new HTTPResponsePacket(); - res.Number = HTTPResponsePacket.ResponseCode.BadRequest; - res.Compose(HTTPResponsePacket.ComposeOptions.AllCalculateLength); + res.Number = HTTPResponseCode.BadRequest; + res.Compose(HTTPComposeOption.AllCalculateLength); Send(res.Data); //@TODO: kill the connection } @@ -847,7 +758,6 @@ public partial class DistributedConnection : NetworkConnection, IStore var rt = authPacket.Parse(msg, offset, ends); - //Console.WriteLine(session.LocalAuthentication.Type.ToString() + " " + offset + " " + ends + " " + rt + " " + authPacket.ToString()); if (rt <= 0) { @@ -858,400 +768,13 @@ public partial class DistributedConnection : NetworkConnection, IStore { offset += (uint)rt; - if (session.LocalAuthentication.Type == AuthenticationType.Host) + if (session.AuthenticationType == AuthenticationType.Host) + { + ProcessHostAuth(msg); + } else if (session.AuthenticationType == AuthenticationType.Client) { - if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Declare) - { - session.RemoteAuthentication.Method = authPacket.RemoteMethod; - - if (authPacket.RemoteMethod == AuthenticationMethod.Credentials && authPacket.LocalMethod == AuthenticationMethod.None) - { - try - { - if (Server.Membership == null) - { - var errMsg = DC.ToBytes("Membership not set."); - - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16((ushort)errMsg.Length) - .AddUInt8Array(errMsg).Done(); - } - else Server.Membership.UserExists(authPacket.RemoteUsername, authPacket.Domain).Then(x => - { - if (x) - { - session.RemoteAuthentication.Username = authPacket.RemoteUsername; - remoteNonce = authPacket.RemoteNonce; - session.RemoteAuthentication.Domain = authPacket.Domain; - SendParams() - .AddUInt8(0xa0) - .AddUInt8Array(localNonce) - .Done(); - //SendParams((byte)0xa0, localNonce); - } - else - { - // Send user not found error - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) - .AddUInt16(14) - .AddString("User not found") - .Done(); - } - }); - } - catch (Exception ex) - { - // Send the server side error - var errMsg = DC.ToBytes(ex.Message); - - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16((ushort)errMsg.Length) - .AddUInt8Array(errMsg) - .Done(); - } - } - else if (authPacket.RemoteMethod == AuthenticationMethod.Token && authPacket.LocalMethod == AuthenticationMethod.None) - { - try - { - if (Server.Membership == null) - { - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) - .AddUInt16(15) - .AddString("Token not found") - .Done(); - } - // Check if user and token exists - else - { - Server.Membership.TokenExists(authPacket.RemoteTokenIndex, authPacket.Domain).Then(x => - { - if (x != null) - { - session.RemoteAuthentication.Username = x; - session.RemoteAuthentication.TokenIndex = authPacket.RemoteTokenIndex; - remoteNonce = authPacket.RemoteNonce; - session.RemoteAuthentication.Domain = authPacket.Domain; - SendParams() - .AddUInt8(0xa0) - .AddUInt8Array(localNonce) - .Done(); - } - else - { - // Send token not found error. - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) - .AddUInt16(15) - .AddString("Token not found") - .Done(); - } - }); - } - } - catch (Exception ex) - { - // Sender server side error. - - var errMsg = DC.ToBytes(ex.Message); - - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16((ushort)errMsg.Length) - .AddUInt8Array(errMsg) - .Done(); - } - } - else if (authPacket.RemoteMethod == AuthenticationMethod.None && authPacket.LocalMethod == AuthenticationMethod.None) - { - try - { - // Check if guests are allowed - if (Server.Membership?.GuestsAllowed ?? true) - { - session.RemoteAuthentication.Username = "g-" + Global.GenerateCode(); - session.RemoteAuthentication.Domain = authPacket.Domain; - readyToEstablish = true; - SendParams() - .AddUInt8(0x80) - .Done(); - } - else - { - // Send access denied error because the server does not allow guests. - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.AccessDenied) - .AddUInt16(18) - .AddString("Guests not allowed") - .Done(); - } - } - catch (Exception ex) - { - // Send the server side error. - var errMsg = DC.ToBytes(ex.Message); - - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16((ushort)errMsg.Length) - .AddUInt8Array(errMsg).Done(); - } - } - - } - else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) - { - if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) - { - var remoteHash = authPacket.Hash; - AsyncReply reply = null; - - try - { - if (session.RemoteAuthentication.Method == AuthenticationMethod.Credentials) - { - reply = Server.Membership.GetPassword(session.RemoteAuthentication.Username, - session.RemoteAuthentication.Domain); - } - else if (session.RemoteAuthentication.Method == AuthenticationMethod.Token) - { - reply = Server.Membership.GetToken(session.RemoteAuthentication.TokenIndex, - session.RemoteAuthentication.Domain); - } - else - { - // Error - } - - reply.Then((pw) => - { - if (pw != null) - { - var hashFunc = SHA256.Create(); - var hash = hashFunc.ComputeHash((new BinaryList()) - .AddUInt8Array(remoteNonce) - .AddUInt8Array(pw) - .AddUInt8Array(localNonce) - .ToArray()); - - if (hash.SequenceEqual(remoteHash)) - { - // send our hash - var localHash = hashFunc.ComputeHash((new BinaryList()) - .AddUInt8Array(localNonce) - .AddUInt8Array(pw) - .AddUInt8Array(remoteNonce) - .ToArray()); - - SendParams() - .AddUInt8(0) - .AddUInt8Array(localHash) - .Done(); - - readyToEstablish = true; - } - else - { - //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:DENIED"); - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.AccessDenied) - .AddUInt16(13) - .AddString("Access Denied") - .Done(); - } - } - }); - } - catch (Exception ex) - { - var errMsg = DC.ToBytes(ex.Message); - - SendParams().AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16((ushort)errMsg.Length) - .AddUInt8Array(errMsg).Done(); - } - } - else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.NewConnection) - { - if (readyToEstablish) - { - var r = new Random(); - session.Id = new byte[32]; - r.NextBytes(session.Id); - - SendParams().AddUInt8(0x28) - .AddUInt8Array(session.Id) - .Done(); - - if (this.Instance == null) - { - Warehouse.Put(this.RemoteUsername.Replace("/", "_"), this, null, Server).Then(x => - { - ready = true; - Status = ConnectionStatus.Connected; - openReply?.Trigger(true); - openReply = null; - OnReady?.Invoke(this); - - Server?.Membership?.Login(session); - loginDate = DateTime.Now; - - }).Error(x => - { - openReply?.TriggerError(x); - openReply = null; - - }); - } - else - { - ready = true; - Status = ConnectionStatus.Connected; - - openReply?.Trigger(true); - openReply = null; - - OnReady?.Invoke(this); - Server?.Membership?.Login(session); - } - - //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:AUTH"); - - } - else - { - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.GeneralFailure) - .AddUInt16(9) - .AddString("Not ready") - .Done(); - } - } - } - } - else if (session.LocalAuthentication.Type == AuthenticationType.Client) - { - if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Acknowledge) - { - if (authPacket.RemoteMethod == AuthenticationMethod.None) - { - // send establish - SendParams() - .AddUInt8(0x20) - .AddUInt16(0) - .Done(); - } - else if (authPacket.RemoteMethod == AuthenticationMethod.Credentials - || authPacket.RemoteMethod == AuthenticationMethod.Token) - { - remoteNonce = authPacket.RemoteNonce; - - // send our hash - var hashFunc = SHA256.Create(); - // local nonce + password or token + remote nonce - var localHash = hashFunc.ComputeHash(new BinaryList() - .AddUInt8Array(localNonce) - .AddUInt8Array(localPasswordOrToken) - .AddUInt8Array(remoteNonce) - .ToArray()); - - SendParams() - .AddUInt8(0) - .AddUInt8Array(localHash) - .Done(); - } - //SendParams((byte)0, localHash); - } - else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Action) - { - if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.AuthenticateHash) - { - // check if the server knows my password - var hashFunc = SHA256.Create(); - //var remoteHash = hashFunc.ComputeHash(BinaryList.ToBytes(remoteNonce, localNonce, localPassword)); - var remoteHash = hashFunc.ComputeHash(new BinaryList() - .AddUInt8Array(remoteNonce) - .AddUInt8Array(localNonce) - .AddUInt8Array(localPasswordOrToken) - .ToArray()); - - - if (remoteHash.SequenceEqual(authPacket.Hash)) - { - // send establish request - SendParams() - .AddUInt8(0x20) - .AddUInt16(0) - .Done(); - } - else - { - SendParams() - .AddUInt8(0xc0) - .AddUInt8((byte)ExceptionCode.ChallengeFailed) - .AddUInt16(16) - .AddString("Challenge Failed") - .Done(); - - //SendParams((byte)0xc0, 1, (ushort)5, DC.ToBytes("Error")); - } - } - else if (authPacket.Action == IIPAuthPacket.IIPAuthPacketAction.ConnectionEstablished) - { - session.Id = authPacket.SessionId; - - ready = true; - Status = ConnectionStatus.Connected; - - // put it in the warehouse - - if (this.Instance == null) - { - Warehouse.Put(this.LocalUsername.Replace("/", "_"), this, null, Server).Then(x => - { - openReply?.Trigger(true); - OnReady?.Invoke(this); - openReply = null; - - - }).Error(x => - { - openReply?.TriggerError(x); - openReply = null; - }); - } - else - { - openReply?.Trigger(true); - openReply = null; - - OnReady?.Invoke(this); - } - - // start perodic keep alive timer - keepAliveTimer.Start(); - } - } - else if (authPacket.Command == IIPAuthPacket.IIPAuthPacketCommand.Error) - { - invalidCredentials = true; - openReply?.TriggerError(new AsyncException(ErrorType.Management, authPacket.ErrorCode, authPacket.ErrorMessage)); - openReply = null; - OnError?.Invoke(this, authPacket.ErrorCode, authPacket.ErrorMessage); - Close(); - } + ProcessClientAuth(msg); } } } @@ -1259,7 +782,694 @@ public partial class DistributedConnection : NetworkConnection, IStore return offset; //if (offset < ends) - // processPacket(msg, offset, ends, data, chunkId); + // processPacket(msg, offset, ends, data, chunkId); + } + + private void ProcessClientAuth(byte[] data) + { + if (authPacket.Command == IIPAuthPacketCommand.Acknowledge) + { + // if there is a mismatch in authentication + if (session.LocalMethod != authPacket.RemoteMethod + || session.RemoteMethod != authPacket.LocalMethod) + { + openReply?.TriggerError(new Exception("Peer refused authentication method.")); + openReply = null; + } + + // Parse remote headers + + var dataType = authPacket.DataType.Value; + + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, null, dataType); + + var rt = (Map)parsed.Wait(); + + session.RemoteHeaders = rt.Select(x => new KeyValuePair((IIPAuthPacketHeader)x.Key, x.Value)); + + if (session.LocalMethod == AuthenticationMethod.None) + { + // send establish + SendParams() + .AddUInt8((byte)IIPAuthPacketAction.EstablishNewSession) + .Done(); + } + else if (session.LocalMethod == AuthenticationMethod.Credentials + || session.LocalMethod == AuthenticationMethod.Token) + { + var remoteNonce = (byte[])session.RemoteHeaders[IIPAuthPacketHeader.Nonce]; + var localNonce = (byte[])session.LocalHeaders[IIPAuthPacketHeader.Nonce]; + + // send our hash + var hashFunc = SHA256.Create(); + // local nonce + password or token + remote nonce + var challenge = hashFunc.ComputeHash(new BinaryList() + .AddUInt8Array(localNonce) + .AddUInt8Array(localPasswordOrToken) + .AddUInt8Array(remoteNonce) + .ToArray()); + + SendParams() + .AddUInt8((byte)IIPAuthPacketAction.AuthenticateHash) + .AddUInt8((byte)IIPAuthPacketHashAlgorithm.SHA256) + .AddUInt16((ushort)challenge.Length) + .AddUInt8Array(challenge) + .Done(); + } + + } + else if (authPacket.Command == IIPAuthPacketCommand.Action) + { + if (authPacket.Action == IIPAuthPacketAction.AuthenticateHash) + { + var remoteNonce = (byte[])session.RemoteHeaders[IIPAuthPacketHeader.Nonce]; + var localNonce = (byte[])session.LocalHeaders[IIPAuthPacketHeader.Nonce]; + + // check if the server knows my password + var hashFunc = SHA256.Create(); + + var challenge = hashFunc.ComputeHash(new BinaryList() + .AddUInt8Array(remoteNonce) + .AddUInt8Array(localPasswordOrToken) + .AddUInt8Array(localNonce) + .ToArray()); + + + if (challenge.SequenceEqual(authPacket.Challenge)) + { + // send establish request + SendParams() + .AddUInt8((byte)IIPAuthPacketAction.EstablishNewSession) + .Done(); + } + else + { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.ChallengeFailed) + .AddUInt16(16) + .AddString("Challenge Failed") + .Done(); + + } + } + } + else if (authPacket.Command == IIPAuthPacketCommand.Event) + { + if (authPacket.Event == IIPAuthPacketEvent.ErrorTerminate + || authPacket.Event == IIPAuthPacketEvent.ErrorMustEncrypt + || authPacket.Event == IIPAuthPacketEvent.ErrorRetry) + { + invalidCredentials = true; + openReply?.TriggerError(new AsyncException(ErrorType.Management, authPacket.ErrorCode, authPacket.Message)); + openReply = null; + OnError?.Invoke(this, authPacket.ErrorCode, authPacket.Message); + Close(); + } + else if (authPacket.Event == IIPAuthPacketEvent.IndicationEstablished) + { + session.Id = authPacket.SessionId; + + ready = true; + Status = ConnectionStatus.Connected; + + // put it in the warehouse + + if (this.Instance == null) + { + Warehouse.Put(this.GetHashCode().ToString().Replace("/", "_"), this, null, Server).Then(x => + { + openReply?.Trigger(true); + OnReady?.Invoke(this); + openReply = null; + + + }).Error(x => + { + openReply?.TriggerError(x); + openReply = null; + }); + } + else + { + openReply?.Trigger(true); + openReply = null; + + OnReady?.Invoke(this); + } + + // start perodic keep alive timer + keepAliveTimer.Start(); + + } + else if (authPacket.Event == IIPAuthPacketEvent.IAuthPlain) + { + var dataType = authPacket.DataType.Value; + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, null, dataType); + var rt = (Map)parsed.Wait(); + + var headers = rt.Select(x => new KeyValuePair((IIPAuthPacketIAuthHeader)x.Key, x.Value)); + //headers[IIPAuthPacketIAuthHeader.Reference] = rt; + + if (Authenticator == null) + { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.NotSupported) + .AddUInt16(13) + .AddString("Not supported") + .Done(); + } + else + { + Authenticator(headers).Then(response => + { + SendParams() + .AddUInt8((byte)IIPAuthPacketAction.IAuthPlain) + .AddUInt32((uint)headers[IIPAuthPacketIAuthHeader.Reference]) + .AddUInt8Array(Codec.Compose(response, this)) + .Done(); + }) + .Timeout(headers.ContainsKey(IIPAuthPacketIAuthHeader.Timeout) ? + (ushort)headers[IIPAuthPacketIAuthHeader.Timeout] * 1000 : 30000, + () => { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.Timeout) + .AddUInt16(7) + .AddString("Timeout") + .Done(); + }); + } + } + else if (authPacket.Event == IIPAuthPacketEvent.IAuthHashed) + { + var dataType = authPacket.DataType.Value; + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, null, dataType); + var rt = (Map)parsed.Wait(); + + + var headers = rt.Select(x => new KeyValuePair((IIPAuthPacketIAuthHeader)x.Key, x.Value)); + //headers[IIPAuthPacketIAuthHeader.Reference] = rt; + + if (Authenticator == null) + { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.NotSupported) + .AddUInt16(13) + .AddString("Not supported") + .Done(); + } + else + { + + Authenticator(headers).Then(response => + { + var sha = SHA256.Create(); + var hash = sha.ComputeHash(new BinaryList() + .AddUInt8Array((byte[])session.LocalHeaders[IIPAuthPacketHeader.Nonce]) + .AddUInt8Array(Codec.Compose(response, this)) + .AddUInt8Array((byte[])session.RemoteHeaders[IIPAuthPacketHeader.Nonce]) + .ToArray()); + + SendParams() + .AddUInt8((byte)IIPAuthPacketAction.IAuthHashed) + .AddUInt32((uint)headers[IIPAuthPacketIAuthHeader.Reference]) + .AddUInt8((byte)IIPAuthPacketHashAlgorithm.SHA256) + .AddUInt16((ushort)hash.Length) + .AddUInt8Array(hash) + .Done(); + }) + .Timeout(headers.ContainsKey(IIPAuthPacketIAuthHeader.Timeout) ? + (ushort)headers[IIPAuthPacketIAuthHeader.Timeout] * 1000 : 30000, + () => { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.Timeout) + .AddUInt16(7) + .AddString("Timeout") + .Done(); + }); + } + } + else if (authPacket.Event == IIPAuthPacketEvent.IAuthEncrypted) + { + throw new NotImplementedException("IAuthEncrypted not implemented."); + } + } + } + + private void ProcessHostAuth(byte[] data) + { + if (authPacket.Command == IIPAuthPacketCommand.Initialize) + { + // Parse headers + + var dataType = authPacket.DataType.Value; + + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, null, dataType); + + var rt = (Map)parsed.Wait(); + + + session.RemoteHeaders = rt.Select(x => new KeyValuePair((IIPAuthPacketHeader)x.Key, x.Value)); + + session.RemoteMethod = authPacket.LocalMethod; + + + if (authPacket.Initialization == IIPAuthPacketInitialize.CredentialsNoAuth) + { + try + { + + var username = (string)session.RemoteHeaders[IIPAuthPacketHeader.Username]; + var domain = (string)session.RemoteHeaders[IIPAuthPacketHeader.Domain]; + //var remoteNonce = (byte[])session.RemoteHeaders[IIPAuthPacketHeader.Nonce]; + + if (Server.Membership == null) + { + var errMsg = DC.ToBytes("Membership not set."); + + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg) + .Done(); + } + else Server.Membership.UserExists(username, domain).Then(x => + { + if (x != null) + { + session.AuthorizedAccount = x; + + var localHeaders = session.LocalHeaders.Select(x => new KeyValuePair((byte)x.Key, x.Value)); + + SendParams() + .AddUInt8((byte)IIPAuthPacketAcknowledge.NoAuthCredentials) + .AddUInt8Array(Codec.Compose(localHeaders, this)) + .Done(); + } + else + { + // Send user not found error + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) + .AddUInt16(14) + .AddString("User not found") + .Done(); + } + }); + } + catch (Exception ex) + { + // Send the server side error + var errMsg = DC.ToBytes(ex.Message); + + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg) + .Done(); + } + } + else if (authPacket.Initialization == IIPAuthPacketInitialize.TokenNoAuth) + { + try + { + if (Server.Membership == null) + { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) + .AddUInt16(15) + .AddString("Token not found") + .Done(); + } + // Check if user and token exists + else + { + var tokenIndex = (ulong)session.RemoteHeaders[IIPAuthPacketHeader.TokenIndex]; + var domain = (string)session.RemoteHeaders[IIPAuthPacketHeader.Domain]; + //var nonce = (byte[])session.RemoteHeaders[IIPAuthPacketHeader.Nonce]; + + Server.Membership.TokenExists(tokenIndex, domain).Then(x => + { + if (x != null) + { + session.AuthorizedAccount = x; + + var localHeaders = session.LocalHeaders.Select(x => new KeyValuePair((byte)x.Key, x.Value)); + + SendParams() + .AddUInt8((byte)IIPAuthPacketAcknowledge.NoAuthToken) + .AddUInt8Array(Codec.Compose(localHeaders, this)) + .Done(); + + } + else + { + // Send token not found error. + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.UserOrTokenNotFound) + .AddUInt16(15) + .AddString("Token not found") + .Done(); + } + }); + } + } + catch (Exception ex) + { + // Sender server side error. + + var errMsg = DC.ToBytes(ex.Message); + + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg) + .Done(); + } + } + else if (authPacket.Initialization == IIPAuthPacketInitialize.NoAuthNoAuth) + { + try + { + // Check if guests are allowed + if (Server.Membership?.GuestsAllowed ?? true) + { + var localHeaders = session.LocalHeaders.Select(x => new KeyValuePair((byte)x.Key, x.Value)); + + session.AuthorizedAccount = "g-" + Global.GenerateCode(); + + readyToEstablish = true; + + SendParams() + .AddUInt8((byte)IIPAuthPacketAcknowledge.NoAuthNoAuth) + .AddUInt8Array(Codec.Compose(localHeaders, this)) + .Done(); + } + else + { + // Send access denied error because the server does not allow guests. + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.AccessDenied) + .AddUInt16(18) + .AddString("Guests not allowed") + .Done(); + } + } + catch (Exception ex) + { + // Send the server side error. + var errMsg = DC.ToBytes(ex.Message); + + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg) + .Done(); + } + } + + } + else if (authPacket.Command == IIPAuthPacketCommand.Action) + { + if (authPacket.Action == IIPAuthPacketAction.AuthenticateHash) + { + var remoteHash = authPacket.Challenge; + AsyncReply reply = null; + + try + { + if (session.RemoteMethod == AuthenticationMethod.Credentials) + { + reply = Server.Membership.GetPassword((string)session.RemoteHeaders[IIPAuthPacketHeader.Username], + (string)session.RemoteHeaders[IIPAuthPacketHeader.Domain]); + } + else if (session.RemoteMethod == AuthenticationMethod.Token) + { + reply = Server.Membership.GetToken((ulong)session.RemoteHeaders[IIPAuthPacketHeader.TokenIndex], + (string)session.RemoteHeaders[IIPAuthPacketHeader.Domain]); + } + else + { + // Error + } + + reply.Then((pw) => + { + if (pw != null) + { + var localNonce = (byte[])session.LocalHeaders[IIPAuthPacketHeader.Nonce]; + var remoteNonce = (byte[])session.RemoteHeaders[IIPAuthPacketHeader.Nonce]; + + var hashFunc = SHA256.Create(); + var hash = hashFunc.ComputeHash((new BinaryList()) + .AddUInt8Array(remoteNonce) + .AddUInt8Array(pw) + .AddUInt8Array(localNonce) + .ToArray()); + + if (hash.SequenceEqual(remoteHash)) + { + // send our hash + var localHash = hashFunc.ComputeHash((new BinaryList()) + .AddUInt8Array(localNonce) + .AddUInt8Array(pw) + .AddUInt8Array(remoteNonce) + .ToArray()); + + SendParams() + .AddUInt8((byte)IIPAuthPacketAction.AuthenticateHash) + .AddUInt8((byte)IIPAuthPacketHashAlgorithm.SHA256) + .AddUInt16((ushort)localHash.Length) + .AddUInt8Array(localHash) + .Done(); + + readyToEstablish = true; + } + else + { + //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:DENIED"); + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.AccessDenied) + .AddUInt16(13) + .AddString("Access Denied") + .Done(); + } + } + }); + } + catch (Exception ex) + { + var errMsg = DC.ToBytes(ex.Message); + + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16((ushort)errMsg.Length) + .AddUInt8Array(errMsg) + .Done(); + } + } + else if (authPacket.Action == IIPAuthPacketAction.IAuthPlain) + { + var reference = authPacket.Reference; + var dataType = authPacket.DataType.Value; + + var (_, parsed) = Codec.Parse(data, dataType.Offset, this, null, dataType); + + var value = parsed.Wait(); + + Server.Membership.AuthorizePlain(session, reference, value) + .Then(x => ProcessAuthorization(x)); + + + } + else if (authPacket.Action == IIPAuthPacketAction.IAuthHashed) + { + var reference = authPacket.Reference; + var value = authPacket.Challenge; + var algorithm = authPacket.HashAlgorithm; + + Server.Membership.AuthorizeHashed(session, reference, algorithm, value) + .Then(x => ProcessAuthorization(x)); + + } + else if (authPacket.Action == IIPAuthPacketAction.IAuthEncrypted) + { + var reference = authPacket.Reference; + var value = authPacket.Challenge; + var algorithm = authPacket.PublicKeyAlgorithm; + + Server.Membership.AuthorizeEncrypted(session, reference, algorithm, value) + .Then(x => ProcessAuthorization(x)); + } + else if (authPacket.Action == IIPAuthPacketAction.EstablishNewSession) + { + if (readyToEstablish) + { + + if (Server.Membership == null) + { + ProcessAuthorization(null); + } + else + { + Server.Membership?.Authorize(session).Then(x => + { + ProcessAuthorization(x); + }); + } + + //Global.Log("auth", LogType.Warning, "U:" + RemoteUsername + " IP:" + Socket.RemoteEndPoint.Address.ToString() + " S:AUTH"); + + } + else + { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16(9) + .AddString("Not ready") + .Done(); + } + } + } + } + + internal void ProcessAuthorization(AuthorizationResults results) + { + if (results == null || results.Response == Security.Membership.AuthorizationResultsResponse.Success) + { + var r = new Random(); + session.Id = new byte[32]; + r.NextBytes(session.Id); + + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.IndicationEstablished) + .AddUInt8((byte)session.Id.Length) + .AddUInt8Array(session.Id) + .Done(); + + if (this.Instance == null) + { + Warehouse.Put(this.GetHashCode().ToString().Replace("/", "_"), this, null, Server).Then(x => + { + ready = true; + Status = ConnectionStatus.Connected; + openReply?.Trigger(true); + openReply = null; + OnReady?.Invoke(this); + + Server?.Membership?.Login(session); + LoginDate = DateTime.Now; + + }).Error(x => + { + openReply?.TriggerError(x); + openReply = null; + + }); + } + else + { + ready = true; + Status = ConnectionStatus.Connected; + + openReply?.Trigger(true); + openReply = null; + + OnReady?.Invoke(this); + Server?.Membership?.Login(session); + } + } + else if (results.Response == Security.Membership.AuthorizationResultsResponse.Failed) + { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.ChallengeFailed) + .AddUInt16(21) + .AddString("Authentication failed") + .Done(); + } + else if (results.Response == Security.Membership.AuthorizationResultsResponse.Expired) + { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.Timeout) + .AddUInt16(22) + .AddString("Authentication expired") + .Done(); + } + else if (results.Response == Security.Membership.AuthorizationResultsResponse.ServiceUnavailable) + { + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.ErrorTerminate) + .AddUInt8((byte)ExceptionCode.GeneralFailure) + .AddUInt16(19) + .AddString("Service unavailable") + .Done(); + } + else if (results.Response == Security.Membership.AuthorizationResultsResponse.IAuthPlain) + { + var args = new Map() + { + [IIPAuthPacketIAuthHeader.Reference] = results.Reference, + [IIPAuthPacketIAuthHeader.Destination] = results.Destination, + [IIPAuthPacketIAuthHeader.Timeout] = results.Timeout, + [IIPAuthPacketIAuthHeader.Clue] = results.Clue, + [IIPAuthPacketIAuthHeader.RequiredFormat] = results.RequiredFormat, + }.Select(m => new KeyValuePair((byte)m.Key, m.Value)); + + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.IAuthPlain) + .AddUInt8Array(Codec.Compose(args, this)) + .Done(); + + } + else if (results.Response == Security.Membership.AuthorizationResultsResponse.IAuthHashed) + { + var args = new Map() + { + [IIPAuthPacketIAuthHeader.Reference] = results.Reference, + [IIPAuthPacketIAuthHeader.Destination] = results.Destination, + [IIPAuthPacketIAuthHeader.Timeout] = results.Timeout, + [IIPAuthPacketIAuthHeader.Clue] = results.Clue, + [IIPAuthPacketIAuthHeader.RequiredFormat] = results.RequiredFormat, + }.Select(m => new KeyValuePair((byte)m.Key, m.Value)); + + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.IAuthHashed) + .AddUInt8Array(Codec.Compose(args, this)) + .Done(); + + } + else if (results.Response == Security.Membership.AuthorizationResultsResponse.IAuthEncrypted) + { + var args = new Map() + { + [IIPAuthPacketIAuthHeader.Destination] = results.Destination, + [IIPAuthPacketIAuthHeader.Timeout] = results.Timeout, + [IIPAuthPacketIAuthHeader.Clue] = results.Clue, + [IIPAuthPacketIAuthHeader.RequiredFormat] = results.RequiredFormat, + }.Select(m => new KeyValuePair((byte)m.Key, m.Value)); + + SendParams() + .AddUInt8((byte)IIPAuthPacketEvent.IAuthEncrypted) + .AddUInt8Array(Codec.Compose(args, this)) + .Done(); + } } protected override void DataReceived(NetworkBuffer data) @@ -1295,39 +1505,6 @@ public partial class DistributedConnection : NetworkConnection, IStore } } - [Attribute] - public ExceptionLevel ExceptionLevel { get; set; } - = ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace; - - - bool invalidCredentials = false; - - [Attribute] - public bool AutoReconnect { get; set; } = false; - - [Attribute] - public uint ReconnectInterval { get; set; } = 5; - - [Attribute] - public string Username { get; set; } - - [Attribute] - public bool UseWebSocket { get; set; } - - [Attribute] - public bool SecureWebSocket { get; set; } - - [Attribute] - public string Password { get; set; } - - [Attribute] - public string Token { get; set; } - - [Attribute] - public ulong TokenIndex { get; set; } - - [Attribute] - public string Domain { get; set; } /// /// Resource interface /// @@ -1381,17 +1558,29 @@ public partial class DistributedConnection : NetworkConnection, IStore if (hostname != null) { - session = new Session(new ClientAuthentication() - , new HostAuthentication()); + session = new Session(); + session.AuthenticationType = AuthenticationType.Client; + session.LocalMethod = method; + session.RemoteMethod = AuthenticationMethod.None; + + session.LocalHeaders[IIPAuthPacketHeader.Domain] = domain; + session.LocalHeaders[IIPAuthPacketHeader.Nonce] = Global.GenerateBytes(32); + + if (method == AuthenticationMethod.Credentials) + { + session.LocalHeaders[IIPAuthPacketHeader.Username] = username; + } + else if (method == AuthenticationMethod.Token) + { + session.LocalHeaders[IIPAuthPacketHeader.TokenIndex] = tokenIndex; + } + else + { + throw new NotImplementedException("Unsupported authentication method."); + } - session.LocalAuthentication.Method = method; - session.LocalAuthentication.TokenIndex = tokenIndex; - session.LocalAuthentication.Domain = domain; - session.LocalAuthentication.Username = username; localPasswordOrToken = passwordOrToken; - invalidCredentials = false; - //localPassword = password; } if (session == null) @@ -1464,7 +1653,7 @@ public partial class DistributedConnection : NetworkConnection, IStore try { - var ar = await SendRequest(IIPPacket.IIPPacketAction.QueryLink) + var ar = await SendRequest(IIPPacketAction.QueryLink) .AddUInt16((ushort)link.Length) .AddUInt8Array(link) .Done(); @@ -1592,9 +1781,8 @@ public partial class DistributedConnection : NetworkConnection, IStore protected override void Connected() { - if (session.LocalAuthentication.Type == AuthenticationType.Client) + if (session.AuthenticationType == AuthenticationType.Client) Declare(); - } protected override void Disconencted() @@ -1685,22 +1873,4 @@ public partial class DistributedConnection : NetworkConnection, IStore } - /* - public AsyncBag Children(IResource resource) - { - if (Codec.IsLocalReso turce(resource, this)) - return (resource as DistributedResource).children.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); - - return null; - } - - public AsyncBag Parents(IResource resource) - { - if (Codec.IsLocalResource(resource, this)) - return (resource as DistributedResource).parents.Where(x => x.GetType() == typeof(T)).Select(x => (T)x); - - return null; - } - */ - } diff --git a/Esiur/Net/IIP/DistributedConnectionConfig.cs b/Esiur/Net/IIP/DistributedConnectionConfig.cs new file mode 100644 index 0000000..23343fe --- /dev/null +++ b/Esiur/Net/IIP/DistributedConnectionConfig.cs @@ -0,0 +1,35 @@ +using Esiur.Core; +using Esiur.Data; +using Esiur.Net.Packets; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.IIP +{ + public class DistributedConnectionConfig + { + public ExceptionLevel ExceptionLevel { get; set; } + = ExceptionLevel.Code | ExceptionLevel.Message | ExceptionLevel.Source | ExceptionLevel.Trace; + + public Func, AsyncReply> Authenticator { get; set; } + + public bool AutoReconnect { get; set; } = false; + + public uint ReconnectInterval { get; set; } = 5; + + public string Username { get; set; } + + public bool UseWebSocket { get; set; } + + public bool SecureWebSocket { get; set; } + + public string Password { get; set; } + + public string Token { get; set; } + + public ulong TokenIndex { get; set; } + + public string Domain { get; set; } + } +} diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs index 1e2bb6e..7f74a38 100644 --- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs @@ -24,7 +24,6 @@ SOFTWARE. using Esiur.Data; using Esiur.Core; -using Esiur.Net.Packets; using Esiur.Resource; using Esiur.Resource.Template; using Esiur.Security.Authority; @@ -38,6 +37,7 @@ using System.Text; using System.Threading.Tasks; using System.Security.Cryptography.X509Certificates; using Esiur.Misc; +using Esiur.Net.Packets; namespace Esiur.Net.IIP; @@ -69,7 +69,6 @@ partial class DistributedConnection AsyncQueue queue = new AsyncQueue(); - DateTime? lastKeepAliveReceived; /// /// Send IIP request. @@ -77,7 +76,7 @@ partial class DistributedConnection /// Packet action. /// Arguments to send. /// - internal SendList SendRequest(IIPPacket.IIPPacketAction action) + internal SendList SendRequest(IIPPacketAction action) { var reply = new AsyncReply(); var c = callbackCounter++; // avoid thread racing @@ -101,12 +100,12 @@ partial class DistributedConnection //uint maxcallerid = 0; - internal SendList SendReply(IIPPacket.IIPPacketAction action, uint callbackId) + internal SendList SendReply(IIPPacketAction action, uint callbackId) { return (SendList)SendParams().AddUInt8((byte)(0x80 | (byte)action)).AddUInt32(callbackId); } - internal SendList SendEvent(IIPPacket.IIPPacketEvent evt) + internal SendList SendEvent(IIPPacketEvent evt) { return (SendList)SendParams().AddUInt8((byte)(evt)); } @@ -117,7 +116,7 @@ partial class DistributedConnection var c = callbackCounter++; requests.Add(c, reply); - SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.Listen)) + SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacketAction.Listen)) .AddUInt32(c) .AddUInt32(instanceId) .AddUInt8(index) @@ -132,7 +131,7 @@ partial class DistributedConnection var c = callbackCounter++; requests.Add(c, reply); - SendParams().AddUInt8((byte)(0x40 | (byte)Packets.IIPPacket.IIPPacketAction.Unlisten)) + SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacketAction.Unlisten)) .AddUInt32(c) .AddUInt32(instanceId) .AddUInt8(index) @@ -151,7 +150,7 @@ partial class DistributedConnection requests.Add(c, reply); - SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacket.IIPPacketAction.StaticCall)) + SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacketAction.StaticCall)) .AddUInt32(c) .AddGuid(classId) .AddUInt8(index) @@ -179,7 +178,7 @@ partial class DistributedConnection var callName = DC.ToBytes(procedureCall); - SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacket.IIPPacketAction.ProcedureCall)) + SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacketAction.ProcedureCall)) .AddUInt32(c) .AddUInt16((ushort)callName.Length) .AddUInt8Array(callName) @@ -197,7 +196,7 @@ partial class DistributedConnection var c = callbackCounter++; requests.Add(c, reply); - SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacket.IIPPacketAction.InvokeFunction)) + SendParams().AddUInt8((byte)(0x40 | (byte)IIPPacketAction.InvokeFunction)) .AddUInt32(c) .AddUInt32(instanceId) .AddUInt8(index) @@ -210,7 +209,7 @@ partial class DistributedConnection { try { - return SendRequest(IIPPacket.IIPPacketAction.DetachResource).AddUInt32(instanceId).Done(); + return SendRequest(IIPPacketAction.DetachResource).AddUInt32(instanceId).Done(); } catch { @@ -241,13 +240,13 @@ partial class DistributedConnection var msg = DC.ToBytes(errorMessage); if (type == ErrorType.Management) SendParams() - .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ManagementError)) + .AddUInt8((byte)(0xC0 | (byte)IIPPacketReport.ManagementError)) .AddUInt32(callbackId) .AddUInt16(errorCode) .Done(); else if (type == ErrorType.Exception) SendParams() - .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ExecutionError)) + .AddUInt8((byte)(0xC0 | (byte)IIPPacketReport.ExecutionError)) .AddUInt32(callbackId) .AddUInt16(errorCode) .AddUInt16((ushort)msg.Length) @@ -258,7 +257,7 @@ partial class DistributedConnection void SendProgress(uint callbackId, int value, int max) { SendParams() - .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ProgressReport)) + .AddUInt8((byte)(0xC0 | (byte)IIPPacketReport.ProgressReport)) .AddUInt32(callbackId) .AddInt32(value) .AddInt32(max) @@ -270,7 +269,7 @@ partial class DistributedConnection { var c = Codec.Compose(chunk, this); SendParams() - .AddUInt8((byte)(0xC0 | (byte)IIPPacket.IIPPacketReport.ChunkStream)) + .AddUInt8((byte)(0xC0 | (byte)IIPPacketReport.ChunkStream)) .AddUInt32(callbackId) .AddUInt8Array(c) .Done(); @@ -555,7 +554,7 @@ partial class DistributedConnection if (r is DistributedResource) { // reply ok - SendReply(IIPPacket.IIPPacketAction.AttachResource, callback) + SendReply(IIPPacketAction.AttachResource, callback) .AddGuid(r.Instance.Template.ClassId) .AddUInt64(r.Instance.Age) .AddUInt16((ushort)link.Length) @@ -567,7 +566,7 @@ partial class DistributedConnection else { // reply ok - SendReply(IIPPacket.IIPPacketAction.AttachResource, callback) + SendReply(IIPPacketAction.AttachResource, callback) .AddGuid(r.Instance.Template.ClassId) .AddUInt64(r.Instance.Age) .AddUInt16((ushort)link.Length) @@ -611,7 +610,7 @@ partial class DistributedConnection { var instance = (sender.Owner as Instance); var name = DC.ToBytes(newValue.ToString()); - SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved) + SendEvent(IIPPacketEvent.ChildRemoved) .AddUInt32(instance.Id) .AddUInt16((ushort)name.Length) .AddUInt8Array(name) @@ -621,7 +620,7 @@ partial class DistributedConnection private void Children_OnRemoved(Instance sender, IResource value) { - SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved) + SendEvent(IIPPacketEvent.ChildRemoved) .AddUInt32(sender.Id) .AddUInt32(value.Instance.Id) .Done(); @@ -630,7 +629,7 @@ partial class DistributedConnection private void Children_OnAdd(Instance sender, IResource value) { //if (sender.Applicable(sender.Resource, this.session, ActionType.)) - SendEvent(IIPPacket.IIPPacketEvent.ChildAdded) + SendEvent(IIPPacketEvent.ChildAdded) .AddUInt32(sender.Id) .AddUInt32(value.Instance.Id) .Done(); @@ -639,7 +638,7 @@ partial class DistributedConnection public bool RemoveChild(IResource parent, IResource child) { - SendEvent(IIPPacket.IIPPacketEvent.ChildRemoved) + SendEvent(IIPPacketEvent.ChildRemoved) .AddUInt32((parent as DistributedResource).DistributedResourceInstanceId) .AddUInt32((child as DistributedResource).DistributedResourceInstanceId) .Done(); @@ -649,7 +648,7 @@ partial class DistributedConnection public bool AddChild(IResource parent, IResource child) { - SendEvent(IIPPacket.IIPPacketEvent.ChildAdded) + SendEvent(IIPPacketEvent.ChildAdded) .AddUInt32((parent as DistributedResource).DistributedResourceInstanceId) .AddUInt32((child as DistributedResource).DistributedResourceInstanceId) .Done(); @@ -691,7 +690,7 @@ partial class DistributedConnection //r.Instance.Attributes.OnModified += Attributes_OnModified; // reply ok - SendReply(IIPPacket.IIPPacketAction.ReattachResource, callback) + SendReply(IIPPacketAction.ReattachResource, callback) .AddUInt64(r.Instance.Age) .AddUInt8Array(Codec.Compose(r.Instance.Serialize(), this)) .Done(); @@ -720,7 +719,7 @@ partial class DistributedConnection //attachedResources.Remove(res); // reply ok - SendReply(IIPPacket.IIPPacketAction.DetachResource, callback).Done(); + SendReply(IIPPacketAction.DetachResource, callback).Done(); } else { @@ -847,7 +846,7 @@ partial class DistributedConnection Warehouse.Put(name, resource, store as IStore, parent).Then(ok => { - SendReply(IIPPacket.IIPPacketAction.CreateResource, callback) + SendReply(IIPPacketAction.CreateResource, callback) .AddUInt32(resource.Instance.Id) .Done(); @@ -880,7 +879,7 @@ partial class DistributedConnection } if (Warehouse.Remove(r)) - SendReply(IIPPacket.IIPPacketAction.DeleteResource, callback).Done(); + SendReply(IIPPacketAction.DeleteResource, callback).Done(); //SendParams((byte)0x84, callback); else SendError(ErrorType.Management, callback, (ushort)ExceptionCode.DeleteFailed); @@ -912,7 +911,7 @@ partial class DistributedConnection var st = r.Instance.GetAttributes(attrs); if (st != null) - SendReply(all ? IIPPacket.IIPPacketAction.GetAllAttributes : IIPPacket.IIPPacketAction.GetAttributes, callback) + SendReply(all ? IIPPacketAction.GetAllAttributes : IIPPacketAction.GetAttributes, callback) .AddUInt8Array(Codec.Compose(st, this)) .Done(); else @@ -953,7 +952,7 @@ partial class DistributedConnection parent.Instance.Store.AddChild(parent, child); - SendReply(IIPPacket.IIPPacketAction.AddChild, callback).Done(); + SendReply(IIPPacketAction.AddChild, callback).Done(); //child.Instance.Parents }); @@ -992,7 +991,7 @@ partial class DistributedConnection parent.Instance.Store.RemoveChild(parent, child);// Children.Remove(child); - SendReply(IIPPacket.IIPPacketAction.RemoveChild, callback).Done(); + SendReply(IIPPacketAction.RemoveChild, callback).Done(); //child.Instance.Parents }); @@ -1017,7 +1016,7 @@ partial class DistributedConnection resource.Instance.Name = name; - SendReply(IIPPacket.IIPPacketAction.RenameResource, callback).Done(); + SendReply(IIPPacketAction.RenameResource, callback).Done(); }); } @@ -1033,7 +1032,7 @@ partial class DistributedConnection resource.Instance.Children().Then(children => { - SendReply(IIPPacket.IIPPacketAction.ResourceChildren, callback) + SendReply(IIPPacketAction.ResourceChildren, callback) .AddUInt8Array(Codec.Compose(children, this))// Codec.ComposeResourceArray(children, this, true)) .Done(); @@ -1055,7 +1054,7 @@ partial class DistributedConnection resource.Instance.Parents().Then(parents => { - SendReply(IIPPacket.IIPPacketAction.ResourceParents, callback) + SendReply(IIPPacketAction.ResourceParents, callback) .AddUInt8Array(Codec.Compose(parents, this)) //.AddUInt8Array(Codec.ComposeResourceArray(parents, this, true)) .Done(); @@ -1087,7 +1086,7 @@ partial class DistributedConnection attrs = attributes.GetStringArray(0, (uint)attributes.Length); if (r.Instance.RemoveAttributes(attrs)) - SendReply(all ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, callback).Done(); + SendReply(all ? IIPPacketAction.ClearAllAttributes : IIPPacketAction.ClearAttributes, callback).Done(); else SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); @@ -1114,7 +1113,7 @@ partial class DistributedConnection DataDeserializer.TypedMapParser(attributes, 0, (uint)attributes.Length, this, null).Then(attrs => { if (r.Instance.SetAttributes((Map)attrs, clearAttributes)) - SendReply(clearAttributes ? IIPPacket.IIPPacketAction.ClearAllAttributes : IIPPacket.IIPPacketAction.ClearAttributes, + SendReply(clearAttributes ? IIPPacketAction.ClearAllAttributes : IIPPacketAction.ClearAttributes, callback).Done(); else SendError(ErrorType.Management, callback, (ushort)ExceptionCode.UpdateAttributeFailed); @@ -1153,7 +1152,7 @@ partial class DistributedConnection } // digggg - SendReply(IIPPacket.IIPPacketAction.LinkTemplates, callback) + SendReply(IIPPacketAction.LinkTemplates, callback) //.AddInt32(msg.Length) //.AddUInt8Array(msg.ToArray()) .AddUInt8Array(TransmissionType.Compose(TransmissionTypeIdentifier.RawData, msg.ToArray())) @@ -1173,7 +1172,7 @@ partial class DistributedConnection var t = Warehouse.GetTemplateByClassName(className); if (t != null) - SendReply(IIPPacket.IIPPacketAction.TemplateFromClassName, callback) + SendReply(IIPPacketAction.TemplateFromClassName, callback) .AddUInt8Array(TransmissionType.Compose(TransmissionTypeIdentifier.RawData, t.Content)) //.AddInt32(t.Content.Length) //.AddUInt8Array(t.Content) @@ -1190,7 +1189,7 @@ partial class DistributedConnection var t = Warehouse.GetTemplateByClassId(classId); if (t != null) - SendReply(IIPPacket.IIPPacketAction.TemplateFromClassId, callback) + SendReply(IIPPacketAction.TemplateFromClassId, callback) .AddUInt8Array(TransmissionType.Compose(TransmissionTypeIdentifier.RawData, t.Content)) //.AddInt32(t.Content.Length) //.AddUInt8Array(t.Content) @@ -1209,7 +1208,7 @@ partial class DistributedConnection Warehouse.GetById(resourceId).Then((r) => { if (r != null) - SendReply(IIPPacket.IIPPacketAction.TemplateFromResourceId, callback) + SendReply(IIPPacketAction.TemplateFromResourceId, callback) .AddInt32(r.Instance.Template.Content.Length) .AddUInt8Array(r.Instance.Template.Content) .Done(); @@ -1238,7 +1237,7 @@ partial class DistributedConnection if (list.Length == 0) SendError(ErrorType.Management, callback, (ushort)ExceptionCode.ResourceNotFound); else - SendReply(IIPPacket.IIPPacketAction.QueryLink, callback) + SendReply(IIPPacketAction.QueryLink, callback) .AddUInt8Array(Codec.Compose(list, this)) //.AddUInt8Array(Codec.ComposeResourceArray(list, this, true)) .Done(); @@ -1304,7 +1303,7 @@ partial class DistributedConnection // return; //} - InvokeFunction(call.Value.Template, callback, arguments, IIPPacket.IIPPacketAction.ProcedureCall, call.Value.Delegate.Target); + InvokeFunction(call.Value.Template, callback, arguments, IIPPacketAction.ProcedureCall, call.Value.Delegate.Target); }).Error(x => { @@ -1357,7 +1356,7 @@ partial class DistributedConnection // return; //} - InvokeFunction(ft, callback, arguments, IIPPacket.IIPPacketAction.StaticCall, null); + InvokeFunction(ft, callback, arguments, IIPPacketAction.StaticCall, null); }).Error(x => { @@ -1403,7 +1402,7 @@ partial class DistributedConnection { rt.Then(res => { - SendReply(IIPPacket.IIPPacketAction.InvokeFunction, callback) + SendReply(IIPPacketAction.InvokeFunction, callback) .AddUInt8Array(Codec.Compose(res, this)) .Done(); }); @@ -1434,7 +1433,7 @@ partial class DistributedConnection return; } - InvokeFunction(ft, callback, arguments, IIPPacket.IIPPacketAction.InvokeFunction, r); + InvokeFunction(ft, callback, arguments, IIPPacketAction.InvokeFunction, r); } }); }); @@ -1442,7 +1441,7 @@ partial class DistributedConnection - void InvokeFunction(FunctionTemplate ft, uint callback, Map arguments, IIPPacket.IIPPacketAction actionType, object target = null) + void InvokeFunction(FunctionTemplate ft, uint callback, Map arguments, IIPPacketAction actionType, object target = null) { // cast arguments @@ -1575,7 +1574,7 @@ partial class DistributedConnection { (r as DistributedResource).Listen(et).Then(x => { - SendReply(IIPPacket.IIPPacketAction.Listen, callback).Done(); + SendReply(IIPPacketAction.Listen, callback).Done(); }).Error(x => SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.GeneralFailure)); } else @@ -1596,7 +1595,7 @@ partial class DistributedConnection subscriptions[r].Add(index); - SendReply(IIPPacket.IIPPacketAction.Listen, callback).Done(); + SendReply(IIPPacketAction.Listen, callback).Done(); } } } @@ -1629,7 +1628,7 @@ partial class DistributedConnection { (r as DistributedResource).Unlisten(et).Then(x => { - SendReply(IIPPacket.IIPPacketAction.Unlisten, callback).Done(); + SendReply(IIPPacketAction.Unlisten, callback).Done(); }).Error(x => SendError(ErrorType.Exception, callback, (ushort)ExceptionCode.GeneralFailure)); } else @@ -1650,7 +1649,7 @@ partial class DistributedConnection subscriptions[r].Remove(index); - SendReply(IIPPacket.IIPPacketAction.Unlisten, callback).Done(); + SendReply(IIPPacketAction.Unlisten, callback).Done(); } } } @@ -1743,7 +1742,7 @@ partial class DistributedConnection }*/ - SendReply(IIPPacket.IIPPacketAction.ResourceHistory, callback) + SendReply(IIPPacketAction.ResourceHistory, callback) .AddUInt8Array(history) .Done(); @@ -1820,7 +1819,7 @@ partial class DistributedConnection // propagation (r as DistributedResource)._Set(index, value).Then((x) => { - SendReply(IIPPacket.IIPPacketAction.SetProperty, callback).Done(); + SendReply(IIPPacketAction.SetProperty, callback).Done(); }).Error(x => { SendError(x.Type, callback, (ushort)x.Code, x.Message); @@ -1871,7 +1870,7 @@ partial class DistributedConnection { pi.SetValue(r, value); - SendReply(IIPPacket.IIPPacketAction.SetProperty, callback).Done(); + SendReply(IIPPacketAction.SetProperty, callback).Done(); } catch (Exception ex) { @@ -2053,7 +2052,7 @@ partial class DistributedConnection var reply = new AsyncReply(); templateRequests.Add(classId, reply); - SendRequest(IIPPacket.IIPPacketAction.TemplateFromClassId) + SendRequest(IIPPacketAction.TemplateFromClassId) .AddGuid(classId) .Done() .Then((rt) => @@ -2085,7 +2084,7 @@ partial class DistributedConnection var classNameBytes = DC.ToBytes(className); - SendRequest(IIPPacket.IIPPacketAction.TemplateFromClassName) + SendRequest(IIPPacketAction.TemplateFromClassName) .AddUInt8((byte)classNameBytes.Length) .AddUInt8Array(classNameBytes) .Done() @@ -2179,7 +2178,7 @@ partial class DistributedConnection var l = DC.ToBytes(link); - SendRequest(IIPPacket.IIPPacketAction.LinkTemplates) + SendRequest(IIPPacketAction.LinkTemplates) .AddUInt16((ushort)l.Length) .AddUInt8Array(l) .Done() @@ -2249,7 +2248,7 @@ partial class DistributedConnection var newSequence = requestSequence != null ? requestSequence.Concat(new uint[] { id }).ToArray() : new uint[] { id }; - SendRequest(IIPPacket.IIPPacketAction.AttachResource) + SendRequest(IIPPacketAction.AttachResource) .AddUInt32(id) .Done() .Then((rt) => @@ -2352,7 +2351,7 @@ partial class DistributedConnection { var rt = new AsyncReply(); - SendRequest(IIPPacket.IIPPacketAction.ResourceChildren) + SendRequest(IIPPacketAction.ResourceChildren) .AddUInt32(resource.Instance.Id) .Done() .Then(ar => @@ -2378,7 +2377,7 @@ partial class DistributedConnection { var rt = new AsyncReply(); - SendRequest(IIPPacket.IIPPacketAction.ResourceParents) + SendRequest(IIPPacketAction.ResourceParents) .AddUInt32(resource.Instance.Id) .Done() .Then(ar => @@ -2404,7 +2403,7 @@ partial class DistributedConnection var rt = new AsyncReply(); if (attributes == null) - SendRequest(IIPPacket.IIPPacketAction.ClearAllAttributes) + SendRequest(IIPPacketAction.ClearAllAttributes) .AddUInt32(resource.Instance.Id) .Done() .Then(ar => rt.Trigger(true)) @@ -2412,7 +2411,7 @@ partial class DistributedConnection else { var attrs = DC.ToBytes(attributes); - SendRequest(IIPPacket.IIPPacketAction.ClearAttributes) + SendRequest(IIPPacketAction.ClearAttributes) .AddUInt32(resource.Instance.Id) .AddInt32(attrs.Length) .AddUInt8Array(attrs) @@ -2428,7 +2427,7 @@ partial class DistributedConnection { var rt = new AsyncReply(); - SendRequest(clearAttributes ? IIPPacket.IIPPacketAction.UpdateAllAttributes : IIPPacket.IIPPacketAction.UpdateAttributes) + SendRequest(clearAttributes ? IIPPacketAction.UpdateAllAttributes : IIPPacketAction.UpdateAttributes) .AddUInt32(resource.Instance.Id) //.AddUInt8Array(Codec.ComposeStructure(attributes, this, true, true, true)) .AddUInt8Array(Codec.Compose(attributes, this)) @@ -2445,7 +2444,7 @@ partial class DistributedConnection if (attributes == null) { - SendRequest(IIPPacket.IIPPacketAction.GetAllAttributes) + SendRequest(IIPPacketAction.GetAllAttributes) .AddUInt32(resource.Instance.Id) .Done() .Then(ar => @@ -2466,7 +2465,7 @@ partial class DistributedConnection else { var attrs = DC.ToBytes(attributes); - SendRequest(IIPPacket.IIPPacketAction.GetAttributes) + SendRequest(IIPPacketAction.GetAttributes) .AddUInt32(resource.Instance.Id) .AddInt32(attrs.Length) .AddUInt8Array(attrs) @@ -2508,7 +2507,7 @@ partial class DistributedConnection var reply = new AsyncReply>(); - SendRequest(IIPPacket.IIPPacketAction.ResourceHistory) + SendRequest(IIPPacketAction.ResourceHistory) .AddUInt32(dr.DistributedResourceInstanceId) .AddDateTime(fromDate) .AddDateTime(toDate) @@ -2538,7 +2537,7 @@ partial class DistributedConnection var str = DC.ToBytes(path); var reply = new AsyncReply(); - SendRequest(IIPPacket.IIPPacketAction.QueryLink) + SendRequest(IIPPacketAction.QueryLink) .AddUInt16((ushort)str.Length) .AddUInt8Array(str) .Done() @@ -2584,7 +2583,7 @@ partial class DistributedConnection pkt.InsertInt32(8, pkt.Length); - SendRequest(IIPPacket.IIPPacketAction.CreateResource) + SendRequest(IIPPacketAction.CreateResource) .AddUInt8Array(pkt.ToArray()) .Done() .Then(args => @@ -2650,7 +2649,7 @@ partial class DistributedConnection Unsubscribe(resource); // compose the packet - SendEvent(IIPPacket.IIPPacketEvent.ResourceDestroyed) + SendEvent(IIPPacketEvent.ResourceDestroyed) .AddUInt32(resource.Instance.Id) .Done(); @@ -2663,7 +2662,7 @@ partial class DistributedConnection // if (pt == null) // return; - SendEvent(IIPPacket.IIPPacketEvent.PropertyUpdated) + SendEvent(IIPPacketEvent.PropertyUpdated) .AddUInt32(info.Resource.Instance.Id) .AddUInt8(info.PropertyTemplate.Index) .AddUInt8Array(Codec.Compose(info.Value, this)) @@ -2696,7 +2695,7 @@ partial class DistributedConnection // compose the packet - SendEvent(IIPPacket.IIPPacketEvent.EventOccurred) + SendEvent(IIPPacketEvent.EventOccurred) .AddUInt32(info.Resource.Instance.Id) .AddUInt8((byte)info.EventTemplate.Index) .AddUInt8Array(Codec.Compose(info.Value, this)) @@ -2722,7 +2721,7 @@ partial class DistributedConnection return; // compose the packet - SendEvent(IIPPacket.IIPPacketEvent.EventOccurred) + SendEvent(IIPPacketEvent.EventOccurred) .AddUInt32(info.Resource.Instance.Id) .AddUInt8((byte)info.EventTemplate.Index) .AddUInt8Array(Codec.Compose(info.Value, this)) @@ -2747,7 +2746,7 @@ partial class DistributedConnection } SendParams() - .AddUInt8((byte)(0x80 | (byte)IIPPacket.IIPPacketAction.KeepAlive)) + .AddUInt8((byte)(0x80 | (byte)IIPPacketAction.KeepAlive)) .AddUInt32(callbackId) .AddDateTime(now) .AddUInt32(jitter) diff --git a/Esiur/Net/IIP/DistributedResource.cs b/Esiur/Net/IIP/DistributedResource.cs index a297a4a..159eea5 100644 --- a/Esiur/Net/IIP/DistributedResource.cs +++ b/Esiur/Net/IIP/DistributedResource.cs @@ -41,6 +41,7 @@ using System.Linq.Expressions; using System.Threading.Tasks; using Esiur.Resource; using Esiur.Resource.Template; +using Esiur.Net.Packets; namespace Esiur.Net.IIP; @@ -459,7 +460,7 @@ public class DistributedResource : DynamicObject, IResource, INotifyPropertyChan var reply = new AsyncReply(); var parameters = Codec.Compose(value, connection); - connection.SendRequest(Packets.IIPPacket.IIPPacketAction.SetProperty) + connection.SendRequest(IIPPacketAction.SetProperty) .AddUInt32(instanceId) .AddUInt8(index) .AddUInt8Array(parameters) diff --git a/Esiur/Net/IIP/DistributedServer.cs b/Esiur/Net/IIP/DistributedServer.cs index b370825..9ca8549 100644 --- a/Esiur/Net/IIP/DistributedServer.cs +++ b/Esiur/Net/IIP/DistributedServer.cs @@ -41,7 +41,6 @@ namespace Esiur.Net.IIP; public class DistributedServer : NetworkServer, IResource { - [Attribute] public string IP @@ -50,11 +49,30 @@ public class DistributedServer : NetworkServer, IResource set; } + IMembership membership; + [Attribute] public IMembership Membership { - get; - set; + get => membership; + set + { + if (membership != null) + membership.Authorization -= Membership_Authorization; + + membership = value; + + if (membership != null) + membership.Authorization += Membership_Authorization; + } + } + + private void Membership_Authorization(AuthorizationIndication indication) + { + lock (Connections.SyncRoot) + foreach (var connection in Connections) + if (connection.Session == indication.Session) + connection.ProcessAuthorization(indication.Results); } [Attribute] @@ -116,41 +134,6 @@ public class DistributedServer : NetworkServer, IResource - //protected override void DataReceived(DistributedConnection sender, NetworkBuffer data) - //{ - // //throw new NotImplementedException(); - - //} - - - - //protected override void ClientConnected(DistributedConnection sender) - //{ - // //Console.WriteLine("DistributedConnection Client Connected"); - //} - - //private void ConnectionReadyEventReceiver(DistributedConnection sender) - //{ - // sender.OnReady -= ConnectionReadyEventReceiver; - // Warehouse.Put(sender, sender.LocalUsername, null, this); - //} - - - //public override void RemoveConnection(DistributedConnection connection) - //{ - // connection.OnReady -= Sender_OnReady; - // //connection.Server = null; - // base.RemoveConnection(connection); - //} - - //public override void AddConnection(DistributedConnection connection) - //{ - // connection.OnReady += Sender_OnReady; - // connection.Server = this; - // base.AddConnection(connection); - //} - - protected override void ClientConnected(DistributedConnection connection) { //Task.Delay(10000).ContinueWith((x) => @@ -180,8 +163,6 @@ public class DistributedServer : NetworkServer, IResource { //connection.OnReady -= ConnectionReadyEventReceiver; //Warehouse.Remove(connection); - - } public KeyList Calls { get; } = new KeyList(); @@ -195,7 +176,7 @@ public class DistributedServer : NetworkServer, IResource public DistributedServer MapCall(string call, Delegate handler) { var ft = FunctionTemplate.MakeFunctionTemplate(null, handler.Method); - Calls.Add(call, new CallInfo(){ Delegate = handler, Template = ft}); + Calls.Add(call, new CallInfo() { Delegate = handler, Template = ft }); return this; } diff --git a/Esiur/Net/Packets/HTTP/HTTPComposeOption.cs b/Esiur/Net/Packets/HTTP/HTTPComposeOption.cs new file mode 100644 index 0000000..782f96c --- /dev/null +++ b/Esiur/Net/Packets/HTTP/HTTPComposeOption.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets.HTTP +{ + public enum HTTPComposeOption : int + { + AllCalculateLength, + AllDontCalculateLength, + SpecifiedHeadersOnly, + DataOnly + } +} diff --git a/Esiur/Net/Packets/HTTP/HTTPCookie.cs b/Esiur/Net/Packets/HTTP/HTTPCookie.cs new file mode 100644 index 0000000..aac0fcf --- /dev/null +++ b/Esiur/Net/Packets/HTTP/HTTPCookie.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets.HTTP +{ + public struct HTTPCookie + { + public string Name; + public string Value; + public DateTime Expires; + public string Path; + public bool HttpOnly; + public string Domain; + + public HTTPCookie(string name, string value) + { + Name = name; + Value = value; + Path = null; + Expires = DateTime.MinValue; + HttpOnly = false; + Domain = null; + } + + public HTTPCookie(string name, string value, DateTime expires) + { + Name = name; + Value = value; + Expires = expires; + HttpOnly = false; + Domain = null; + Path = null; + } + + public override string ToString() + { + //Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/ + //Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/ + var cookie = Name + "=" + Value; + + if (Expires.Ticks != 0) + cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT"; + + if (Domain != null) + cookie += "; domain=" + Domain; + + if (Path != null) + cookie += "; path=" + Path; + + if (HttpOnly) + cookie += "; HttpOnly"; + + return cookie; + } + } + +} diff --git a/Esiur/Net/Packets/HTTP/HTTPMethod.cs b/Esiur/Net/Packets/HTTP/HTTPMethod.cs new file mode 100644 index 0000000..2fb3f62 --- /dev/null +++ b/Esiur/Net/Packets/HTTP/HTTPMethod.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets.HTTP +{ + public enum HTTPMethod : byte + { + GET, + POST, + HEAD, + PUT, + DELETE, + OPTIONS, + TRACE, + CONNECT, + UNKNOWN + } +} diff --git a/Esiur/Net/Packets/HTTPRequestPacket.cs b/Esiur/Net/Packets/HTTP/HTTPRequestPacket.cs similarity index 92% rename from Esiur/Net/Packets/HTTPRequestPacket.cs rename to Esiur/Net/Packets/HTTP/HTTPRequestPacket.cs index 6ddb003..b699daa 100644 --- a/Esiur/Net/Packets/HTTPRequestPacket.cs +++ b/Esiur/Net/Packets/HTTP/HTTPRequestPacket.cs @@ -32,22 +32,10 @@ using Esiur.Data; using System.Net; using System.Text.Json.Serialization; -namespace Esiur.Net.Packets; +namespace Esiur.Net.Packets.HTTP; public class HTTPRequestPacket : Packet { - public enum HTTPMethod : byte - { - GET, - POST, - HEAD, - PUT, - DELETE, - OPTIONS, - TRACE, - CONNECT, - UNKNOWN - } public StringKeyList Query; public HTTPMethod Method; @@ -59,12 +47,12 @@ public class HTTPRequestPacket : Packet public StringKeyList Cookies; // String public string URL; /// With query public string Filename; /// Without query - //public byte[] PostContents; + public KeyList PostForms; public byte[] Message; - private HTTPMethod getMethod(string method) + private HTTPMethod GetMethod(string method) { switch (method.ToLower()) { @@ -127,7 +115,7 @@ public class HTTPRequestPacket : Packet Headers = new StringKeyList(); sMethod = sLines[0].Split(' '); - Method = getMethod(sMethod[0].Trim()); + Method = GetMethod(sMethod[0].Trim()); if (sMethod.Length == 3) { @@ -163,7 +151,7 @@ public class HTTPRequestPacket : Packet for (int i = 1; i < sLines.Length; i++) { - if (sLines[i] == String.Empty) + if (sLines[i] == string.Empty) { // Invalid header return 0; @@ -191,14 +179,14 @@ public class HTTPRequestPacket : Packet string[] splitCookie = cookie.Split('='); splitCookie[0] = splitCookie[0].Trim(); splitCookie[1] = splitCookie[1].Trim(); - if (!(Cookies.ContainsKey(splitCookie[0].Trim()))) + if (!Cookies.ContainsKey(splitCookie[0].Trim())) Cookies.Add(splitCookie[0], splitCookie[1]); } else { - if (!(Cookies.ContainsKey(cookie.Trim()))) + if (!Cookies.ContainsKey(cookie.Trim())) { - Cookies.Add(cookie.Trim(), String.Empty); + Cookies.Add(cookie.Trim(), string.Empty); } } } @@ -222,7 +210,7 @@ public class HTTPRequestPacket : Packet } else { - if (!(Query.ContainsKey(WebUtility.UrlDecode(S)))) + if (!Query.ContainsKey(WebUtility.UrlDecode(S))) { Query.Add(WebUtility.UrlDecode(S), null); } @@ -236,7 +224,7 @@ public class HTTPRequestPacket : Packet try { - uint postSize = uint.Parse((string)Headers["content-length"]); + uint postSize = uint.Parse(Headers["content-length"]); // check limit if (postSize > data.Length - headerSize) @@ -298,7 +286,7 @@ public class HTTPRequestPacket : Packet else { //PostForms.Add(Headers["content-type"], Encoding.Default.GetString( )); - Message = DC.Clip(data, headerSize, postSize); + Message = data.Clip(headerSize, postSize); } return headerSize + postSize; diff --git a/Esiur/Net/Packets/HTTP/HTTPResponseCode.cs b/Esiur/Net/Packets/HTTP/HTTPResponseCode.cs new file mode 100644 index 0000000..676aaed --- /dev/null +++ b/Esiur/Net/Packets/HTTP/HTTPResponseCode.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets.HTTP +{ + public enum HTTPResponseCode : int + { + Switching = 101, + OK = 200, + Created = 201, + Accepted = 202, + NoContent = 204, + MovedPermanently = 301, + Found = 302, + SeeOther = 303, + NotModified = 304, + TemporaryRedirect = 307, + BadRequest = 400, + Unauthorized = 401, + Forbidden = 403, + NotFound = 404, + MethodNotAllowed = 405, + NotAcceptable = 406, + PreconditionFailed = 412, + UnsupportedMediaType = 415, + InternalServerError = 500, + NotImplemented = 501, + } +} diff --git a/Esiur/Net/Packets/HTTPResponsePacket.cs b/Esiur/Net/Packets/HTTP/HTTPResponsePacket.cs similarity index 66% rename from Esiur/Net/Packets/HTTPResponsePacket.cs rename to Esiur/Net/Packets/HTTP/HTTPResponsePacket.cs index 1c167f5..79a5795 100644 --- a/Esiur/Net/Packets/HTTPResponsePacket.cs +++ b/Esiur/Net/Packets/HTTP/HTTPResponsePacket.cs @@ -28,98 +28,15 @@ using System.Text; using Esiur.Misc; using Esiur.Data; -namespace Esiur.Net.Packets; +namespace Esiur.Net.Packets.HTTP; public class HTTPResponsePacket : Packet { - public enum ComposeOptions : int - { - AllCalculateLength, - AllDontCalculateLength, - SpecifiedHeadersOnly, - DataOnly - } - - public enum ResponseCode : int - { - Switching = 101, - OK = 200, - Created = 201, - Accepted = 202, - NoContent = 204, - MovedPermanently = 301, - Found = 302, - SeeOther = 303, - NotModified = 304, - TemporaryRedirect = 307, - BadRequest = 400, - Unauthorized = 401, - Forbidden = 403, - NotFound = 404, - MethodNotAllowed = 405, - NotAcceptable = 406, - PreconditionFailed = 412, - UnsupportedMediaType = 415, - InternalServerError = 500, - NotImplemented = 501, - } - - public struct HTTPCookie - { - public string Name; - public string Value; - public DateTime Expires; - public string Path; - public bool HttpOnly; - public string Domain; - - public HTTPCookie(string name, string value) - { - this.Name = name; - this.Value = value; - this.Path = null; - this.Expires = DateTime.MinValue; - this.HttpOnly = false; - this.Domain = null; - } - - public HTTPCookie(string name, string value, DateTime expires) - { - this.Name = name; - this.Value = value; - this.Expires = expires; - this.HttpOnly = false; - this.Domain = null; - this.Path = null; - } - - public override string ToString() - { - //Set-Cookie: ckGeneric=CookieBody; expires=Sun, 30-Dec-2001 21:00:00 GMT; domain=.com.au; path=/ - //Set-Cookie: SessionID=another; expires=Fri, 29 Jun 2006 20:47:11 UTC; path=/ - var cookie = Name + "=" + Value; - - if (Expires.Ticks != 0) - cookie += "; expires=" + Expires.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss") + " GMT"; - - if (Domain != null) - cookie += "; domain=" + Domain; - - if (Path != null) - cookie += "; path=" + Path; - - if (HttpOnly) - cookie += "; HttpOnly"; - - return cookie; - } - } - public StringKeyList Headers { get; } = new StringKeyList(true); public string Version { get; set; } = "HTTP/1.1"; public byte[] Message; - public ResponseCode Number { get; set; } = ResponseCode.OK; + public HTTPResponseCode Number { get; set; } = HTTPResponseCode.OK; public string Text; public List Cookies { get; } = new List(); @@ -134,11 +51,11 @@ public class HTTPResponsePacket : Packet + "\n\tMessage: " + (Message != null ? Message.Length.ToString() : "NULL"); } - private string MakeHeader(ComposeOptions options) + private string MakeHeader(HTTPComposeOption options) { string header = $"{Version} {(int)Number} {Text}\r\nServer: Esiur {Global.Version}\r\nDate: {DateTime.Now.ToUniversalTime().ToString("r")}\r\n"; - if (options == ComposeOptions.AllCalculateLength) + if (options == HTTPComposeOption.AllCalculateLength) Headers["Content-Length"] = Message?.Length.ToString() ?? "0"; foreach (var kv in Headers) @@ -158,16 +75,16 @@ public class HTTPResponsePacket : Packet } - public bool Compose(ComposeOptions options) + public bool Compose(HTTPComposeOption options) { List msg = new List(); - if (options != ComposeOptions.DataOnly) + if (options != HTTPComposeOption.DataOnly) { msg.AddRange(Encoding.UTF8.GetBytes(MakeHeader(options))); } - if (options != ComposeOptions.SpecifiedHeadersOnly) + if (options != HTTPComposeOption.SpecifiedHeadersOnly) { if (Message != null) msg.AddRange(Message); @@ -180,7 +97,7 @@ public class HTTPResponsePacket : Packet public override bool Compose() { - return Compose(ComposeOptions.AllDontCalculateLength); + return Compose(HTTPComposeOption.AllDontCalculateLength); } public override long Parse(byte[] data, uint offset, uint ends) @@ -212,7 +129,7 @@ public class HTTPResponsePacket : Packet if (sMethod.Length == 3) { Version = sMethod[0].Trim(); - Number = (ResponseCode)(Convert.ToInt32(sMethod[1].Trim())); + Number = (HTTPResponseCode)Convert.ToInt32(sMethod[1].Trim()); Text = sMethod[2]; } @@ -220,7 +137,7 @@ public class HTTPResponsePacket : Packet for (int i = 1; i < sLines.Length; i++) { - if (sLines[i] == String.Empty) + if (sLines[i] == string.Empty) { // Invalid header return 0; @@ -279,7 +196,7 @@ public class HTTPResponsePacket : Packet try { - uint contentLength = uint.Parse((string)Headers["content-length"]); + uint contentLength = uint.Parse(Headers["content-length"]); // check limit if (contentLength > data.Length - headerSize) @@ -287,7 +204,7 @@ public class HTTPResponsePacket : Packet return contentLength - (data.Length - headerSize); } - Message = DC.Clip(data, offset, contentLength); + Message = data.Clip(offset, contentLength); return headerSize + contentLength; diff --git a/Esiur/Net/Packets/IIPAuthExtensions.cs b/Esiur/Net/Packets/IIPAuthExtensions.cs new file mode 100644 index 0000000..8705ba9 --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthExtensions.cs @@ -0,0 +1,25 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public static class IIPAuthExtensions + { + public static IIPAuthPacketIAuthFormat GetIAuthFormat(this object value) + { + if (value is string) + return IIPAuthPacketIAuthFormat.Text; + else if (value is int || value is uint + || value is byte || value is sbyte + || value is short || value is ushort + || value is long || value is ulong) + return IIPAuthPacketIAuthFormat.Number; + else if (value.GetType().IsArray) + return IIPAuthPacketIAuthFormat.Choice; + + throw new Exception("Unknown IAuth format"); + } + } +} diff --git a/Esiur/Net/Packets/IIPAuthPacket.cs b/Esiur/Net/Packets/IIPAuthPacket.cs index 039e8c0..15c1876 100644 --- a/Esiur/Net/Packets/IIPAuthPacket.cs +++ b/Esiur/Net/Packets/IIPAuthPacket.cs @@ -26,55 +26,47 @@ using Esiur.Data; using Esiur.Security.Authority; using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Data.Common; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; +using System.Timers; namespace Esiur.Net.Packets; -class IIPAuthPacket : Packet + +public class IIPAuthPacket : Packet { - public enum IIPAuthPacketCommand : byte - { - Action = 0, - Declare = 0x1, - Acknowledge = 0x2, - Report = 0x3, - DeclareEncrypted = 0x5, - AcknowledgeEncrypted = 0x6 - } - - public enum IIPAuthPacketAction : byte - { - AuthenticateHash = 0x0, - AuthenticatePublicHash = 0x1, - AuthenticatePrivateHash, - EstablishRequest, - EstablishReply, - TwoFactorAuthtenticate, - - NewConnection = 0x20, - ResumeConnection, - - ConnectionEstablished = 0x28 - } - - - public IIPAuthPacketCommand Command { get; set; } + public IIPAuthPacketInitialize Initialization + { + get; + set; + } + + public IIPAuthPacketAcknowledge Acknowledgement + { + get; + set; + } + public IIPAuthPacketAction Action { get; set; } - public byte ErrorCode { get; set; } - public string ErrorMessage { get; set; } + public IIPAuthPacketEvent Event + { + get; + set; + } public AuthenticationMethod LocalMethod { @@ -82,71 +74,45 @@ class IIPAuthPacket : Packet set; } - public byte[] SourceInfo - { - get; - set; - } - - public byte[] Hash - { - get; - set; - } - - public byte[] SessionId - { - get; - set; - } - public AuthenticationMethod RemoteMethod { get; set; } - public string Domain + public byte ErrorCode { get; set; } - public long CertificateId - { - get; set; - } - - public string LocalUsername + public string Message { get; set; } - public string RemoteUsername + + public IIPAuthPacketPublicKeyAlgorithm PublicKeyAlgorithm { get; set; } - public byte[] LocalPassword - { - get; - set; - } - public byte[] RemotePassword + public IIPAuthPacketHashAlgorithm HashAlgorithm { get; set; } - public byte[] LocalToken + + public byte[] Certificate { get; set; } - public byte[] RemoteToken + public byte[] Challenge { get; set; @@ -158,19 +124,27 @@ class IIPAuthPacket : Packet set; } - public byte[] LocalNonce + + public byte[] SessionId { get; set; } - public byte[] RemoteNonce + public TransmissionType? DataType { get; set; } - public ulong RemoteTokenIndex { get; set; } + // IAuth Reference + public uint Reference + { + get; + set; + } + + private uint dataLengthNeeded; @@ -199,174 +173,178 @@ class IIPAuthPacket : Packet Command = (IIPAuthPacketCommand)(data[offset] >> 6); - if (Command == IIPAuthPacketCommand.Action) + if (Command == IIPAuthPacketCommand.Initialize) { - Action = (IIPAuthPacketAction)(data[offset++] & 0x3f); - - if (Action == IIPAuthPacketAction.AuthenticateHash) - { - if (NotEnough(offset, ends, 32)) - return -dataLengthNeeded; - - Hash = data.Clip(offset, 32); - - //var hash = new byte[32]; - //Buffer.BlockCopy(data, (int)offset, hash, 0, 32); - //Hash = hash; - - offset += 32; - } - else if (Action == IIPAuthPacketAction.NewConnection) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - - var length = data.GetUInt16(offset, Endian.Little); - - offset += 2; - - if (NotEnough(offset, ends, length)) - return -dataLengthNeeded; - - SourceInfo = data.Clip(offset, length); - - //var sourceInfo = new byte[length]; - //Buffer.BlockCopy(data, (int)offset, sourceInfo, 0, length); - //SourceInfo = sourceInfo; - - offset += 32; - } - else if (Action == IIPAuthPacketAction.ResumeConnection - || Action == IIPAuthPacketAction.ConnectionEstablished) - { - //var sessionId = new byte[32]; - - if (NotEnough(offset, ends, 32)) - return -dataLengthNeeded; - - SessionId = data.Clip(offset, 32); - - //Buffer.BlockCopy(data, (int)offset, sessionId, 0, 32); - //SessionId = sessionId; - - offset += 32; - } - } - else if (Command == IIPAuthPacketCommand.Declare) - { - RemoteMethod = (AuthenticationMethod)((data[offset] >> 4) & 0x3); - LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3); - var encrypt = ((data[offset++] & 0x2) == 0x2); + LocalMethod = (AuthenticationMethod)(data[offset] >> 4 & 0x3); + RemoteMethod = (AuthenticationMethod)(data[offset] >> 2 & 0x3); + Initialization = (IIPAuthPacketInitialize)(data[offset++] & 0xFC); // remove last two reserved LSBs if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - var domainLength = data[offset++]; - if (NotEnough(offset, ends, domainLength)) - return -dataLengthNeeded; + (var size, DataType) = TransmissionType.Parse(data, offset, ends); - var domain = data.GetString(offset, domainLength); - - Domain = domain; - - offset += domainLength; - - if (RemoteMethod == AuthenticationMethod.Certificate) - { - - } - else if (RemoteMethod == AuthenticationMethod.Credentials) - { - if (LocalMethod == AuthenticationMethod.None) - { - if (NotEnough(offset, ends, 33)) - return -dataLengthNeeded; - - //var remoteNonce = new byte[32]; - //Buffer.BlockCopy(data, (int)offset, remoteNonce, 0, 32); - //RemoteNonce = remoteNonce; - - RemoteNonce = data.Clip(offset, 32); - - offset += 32; - - var length = data[offset++]; - - if (NotEnough(offset, ends, length)) - return -dataLengthNeeded; - - RemoteUsername = data.GetString(offset, length); + if (DataType == null) + return -(int)size; - offset += length; - } - } - else if (RemoteMethod == AuthenticationMethod.Token) - { - if (LocalMethod == AuthenticationMethod.None) - { - if (NotEnough(offset, ends, 37)) - return -dataLengthNeeded; + offset += (uint)size; - RemoteNonce = data.Clip(offset, 32); - - offset += 32; - - RemoteTokenIndex = data.GetUInt64(offset, Endian.Little); - offset += 8; - } - } - - if (encrypt) - { - if (NotEnough(offset, ends, 2)) - return -dataLengthNeeded; - - var keyLength = data.GetUInt16(offset, Endian.Little); - - offset += 2; - - if (NotEnough(offset, ends, keyLength)) - return -dataLengthNeeded; - - //var key = new byte[keyLength]; - //Buffer.BlockCopy(data, (int)offset, key, 0, keyLength); - //AsymetricEncryptionKey = key; - - AsymetricEncryptionKey = data.Clip(offset, keyLength); - - offset += keyLength; - } } else if (Command == IIPAuthPacketCommand.Acknowledge) { - RemoteMethod = (AuthenticationMethod)((data[offset] >> 4) & 0x3); - LocalMethod = (AuthenticationMethod)((data[offset] >> 2) & 0x3); - var encrypt = ((data[offset++] & 0x2) == 0x2); - if (RemoteMethod == AuthenticationMethod.None) + LocalMethod = (AuthenticationMethod)(data[offset] >> 4 & 0x3); + RemoteMethod = (AuthenticationMethod)(data[offset] >> 2 & 0x3); + + Acknowledgement = (IIPAuthPacketAcknowledge)(data[offset++] & 0xFC); // remove last two reserved LSBs + + if (NotEnough(offset, ends, 1)) + return -dataLengthNeeded; + + (var size, DataType) = TransmissionType.Parse(data, offset, ends); + + if (DataType == null) + return -(int)size; + + + offset += (uint)size; + } + else if (Command == IIPAuthPacketCommand.Action) + { + Action = (IIPAuthPacketAction)data[offset++]; // (IIPAuthPacketAction)(data[offset++] & 0x3f); + + if (Action == IIPAuthPacketAction.AuthenticateHash + || Action == IIPAuthPacketAction.AuthenticatePublicHash + || Action == IIPAuthPacketAction.AuthenticatePrivateHash + || Action == IIPAuthPacketAction.AuthenticatePublicPrivateHash) { - if (LocalMethod == AuthenticationMethod.None) - { - // do nothing - } + if (NotEnough(offset, ends, 3)) + return -dataLengthNeeded; + + HashAlgorithm = (IIPAuthPacketHashAlgorithm)data[offset++]; + + var hashLength = data.GetUInt16(offset, Endian.Little); + offset += 2; + + + if (NotEnough(offset, ends, hashLength)) + return -dataLengthNeeded; + + Challenge = data.Clip(offset, hashLength); + offset += hashLength; + } - else if (RemoteMethod == AuthenticationMethod.Credentials - || RemoteMethod == AuthenticationMethod.Token) + else if (Action == IIPAuthPacketAction.AuthenticatePrivateHashCert + || Action == IIPAuthPacketAction.AuthenticatePublicPrivateHashCert) { - if (LocalMethod == AuthenticationMethod.None) - { - if (NotEnough(offset, ends, 32)) - return -dataLengthNeeded; + if (NotEnough(offset, ends, 3)) + return -dataLengthNeeded; - RemoteNonce = data.Clip(offset, 32); - offset += 32; + HashAlgorithm = (IIPAuthPacketHashAlgorithm)data[offset++]; - } + var hashLength = data.GetUInt16(offset, Endian.Little); + offset += 2; + + + if (NotEnough(offset, ends, hashLength)) + return -dataLengthNeeded; + + Challenge = data.Clip(offset, hashLength); + offset += hashLength; + + if (NotEnough(offset, ends, 2)) + return -dataLengthNeeded; + + var certLength = data.GetUInt16(offset, Endian.Little); + offset += 2; + + if (NotEnough(offset, ends, certLength)) + return -dataLengthNeeded; + + Certificate = data.Clip(offset, certLength); + + offset += certLength; + } + else if (Action == IIPAuthPacketAction.IAuthPlain) + { + if (NotEnough(offset, ends, 5)) + return -dataLengthNeeded; + + Reference = data.GetUInt32(offset, Endian.Little); + offset += 4; + + (var size, DataType) = TransmissionType.Parse(data, offset, ends); + + if (DataType == null) + return -(int)size; + + offset += (uint)size; + + } + else if (Action == IIPAuthPacketAction.IAuthHashed) + { + if (NotEnough(offset, ends, 7)) + return -dataLengthNeeded; + + Reference = data.GetUInt32(offset, Endian.Little); + offset += 4; + + HashAlgorithm = (IIPAuthPacketHashAlgorithm)data[offset++]; + + var cl = data.GetUInt16(offset, Endian.Little); + offset += 2; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Challenge = data.Clip(offset, cl); + + offset += cl; + + } + else if (Action == IIPAuthPacketAction.IAuthEncrypted) + { + if (NotEnough(offset, ends, 7)) + return -dataLengthNeeded; + + Reference = data.GetUInt32(offset, Endian.Little); + offset += 4; + + PublicKeyAlgorithm = (IIPAuthPacketPublicKeyAlgorithm)data[offset++]; + + var cl = data.GetUInt16(offset, Endian.Little); + offset += 2; + + if (NotEnough(offset, ends, cl)) + return -dataLengthNeeded; + + Challenge = data.Clip(offset, cl); + + offset += cl; + + } + else if (Action == IIPAuthPacketAction.EstablishNewSession) + { + // Nothing here + } + else if (Action == IIPAuthPacketAction.EstablishResumeSession) + { + if (NotEnough(offset, ends, 1)) + return -dataLengthNeeded; + + var sessionLength = data[offset++]; + + if (NotEnough(offset, ends, sessionLength)) + return -dataLengthNeeded; + + SessionId = data.Clip(offset, sessionLength); + + offset += sessionLength; } - if (encrypt) + else if (Action == IIPAuthPacketAction.EncryptKeyExchange) { if (NotEnough(offset, ends, 2)) return -dataLengthNeeded; @@ -378,33 +356,86 @@ class IIPAuthPacket : Packet if (NotEnough(offset, ends, keyLength)) return -dataLengthNeeded; - //var key = new byte[keyLength]; - //Buffer.BlockCopy(data, (int)offset, key, 0, keyLength); - //AsymetricEncryptionKey = key; - AsymetricEncryptionKey = data.Clip(offset, keyLength); offset += keyLength; } + + else if (Action == IIPAuthPacketAction.RegisterEndToEndKey + || Action == IIPAuthPacketAction.RegisterHomomorphic) + { + if (NotEnough(offset, ends, 3)) + return -dataLengthNeeded; + + PublicKeyAlgorithm = (IIPAuthPacketPublicKeyAlgorithm)data[offset++]; + + var keyLength = data.GetUInt16(offset, Endian.Little); + + offset += 2; + + if (NotEnough(offset, ends, keyLength)) + return -dataLengthNeeded; + + AsymetricEncryptionKey = data.Clip(offset, keyLength); + + offset += keyLength; + + } } - else if (Command == IIPAuthPacketCommand.Error) + else if (Command == IIPAuthPacketCommand.Event) { - if (NotEnough(offset, ends, 4)) - return -dataLengthNeeded; - offset++; - ErrorCode = data[offset++]; + Event = (IIPAuthPacketEvent)data[offset++]; + + if (Event == IIPAuthPacketEvent.ErrorTerminate + || Event == IIPAuthPacketEvent.ErrorMustEncrypt + || Event == IIPAuthPacketEvent.ErrorRetry) + { + if (NotEnough(offset, ends, 3)) + return -dataLengthNeeded; + + ErrorCode = data[offset++]; + var msgLength = data.GetUInt16(offset, Endian.Little); + offset += 2; + + if (NotEnough(offset, ends, msgLength)) + return -dataLengthNeeded; - var cl = data.GetUInt16(offset, Endian.Little); - offset += 2; + Message = data.GetString(offset, msgLength); - if (NotEnough(offset, ends, cl)) - return -dataLengthNeeded; + offset += msgLength; + } + else if (Event == IIPAuthPacketEvent.IndicationEstablished) + { + if (NotEnough(offset, ends, 1)) + return -dataLengthNeeded; - ErrorMessage = data.GetString(offset, cl); - offset += cl; + var sessionLength = data[offset++]; + if (NotEnough(offset, ends, sessionLength)) + return -dataLengthNeeded; + + SessionId = data.Clip(offset, sessionLength); + + offset += sessionLength; + } + + else if (Event == IIPAuthPacketEvent.IAuthPlain + || Event == IIPAuthPacketEvent.IAuthHashed + || Event == IIPAuthPacketEvent.IAuthEncrypted) + { + if (NotEnough(offset, ends, 1)) + return -dataLengthNeeded; + + (var size, DataType) = TransmissionType.Parse(data, offset, ends); + + if (DataType == null) + return -(int)size; + + offset += (uint)size; + + } } diff --git a/Esiur/Net/Packets/IIPAuthPacketAcknowledge.cs b/Esiur/Net/Packets/IIPAuthPacketAcknowledge.cs new file mode 100644 index 0000000..1feec89 --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketAcknowledge.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketAcknowledge : byte + { + NoAuthNoAuth = 0x40, // 0b01000000, + NoAuthCredentials = 0x44, // 0b01000100, + NoAuthToken = 0x48, //0b01001000, + NoAuthCertificate = 0x4c, //0b01001100, + CredentialsNoAuth = 0x50, //0b01010000, + CredentialsCredentials = 0x54, //0b01010100, + CredentialsToken = 0x58, //0b01011000, + CredentialsCertificate = 0x5c, //0b01011100, + TokenNoAuth = 0x60, //0b01100000, + TokenCredentials = 0x64, //0b01100100, + TokenToken = 0x68, //0b01101000, + TokenCertificate = 0x6c, //0b01101100, + CertificateNoAuth = 0x70, //0b01110000, + CertificateCredentials = 0x74, //0b01110100, + CertificateToken = 0x78, //0b01111000, + CertificateCertificate = 0x7c, // 0b01111100, + } +} diff --git a/Esiur/Net/Packets/IIPAuthPacketAction.cs b/Esiur/Net/Packets/IIPAuthPacketAction.cs new file mode 100644 index 0000000..f4a581d --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketAction.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketAction : byte + { + AuthenticateHash = 0x80, + AuthenticatePublicHash = 0x81, + AuthenticatePrivateHash = 0x82, + AuthenticatePublicPrivateHash = 0x83, + + AuthenticatePrivateHashCert = 0x88, + AuthenticatePublicPrivateHashCert = 0x89, + + IAuthPlain = 0x90, + IAuthHashed = 0x91, + IAuthEncrypted = 0x92, + + + EstablishNewSession = 0x98, + EstablishResumeSession = 0x99, + + EncryptKeyExchange = 0xA0, + + RegisterEndToEndKey = 0xA8, + RegisterHomomorphic = 0xA9, + + } +} diff --git a/Esiur/Net/Packets/IIPAuthPacketCommand.cs b/Esiur/Net/Packets/IIPAuthPacketCommand.cs new file mode 100644 index 0000000..6d810f9 --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketCommand.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketCommand : byte + { + Initialize = 0x0, + Acknowledge = 0x1, + Action = 0x2, + Event = 0x3, + } + +} diff --git a/Esiur/Net/Packets/IIPAuthPacketEvent.cs b/Esiur/Net/Packets/IIPAuthPacketEvent.cs new file mode 100644 index 0000000..4f3079b --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketEvent.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketEvent : byte + { + ErrorTerminate = 0xC0, + ErrorMustEncrypt = 0xC1, + ErrorRetry = 0xC2, + + IndicationEstablished = 0xC8, + + IAuthPlain = 0xD0, + IAuthHashed = 0xD1, + IAuthEncrypted = 0xD2 + } +} diff --git a/Esiur/Net/Packets/IIPAuthPacketHashAlgorithm.cs b/Esiur/Net/Packets/IIPAuthPacketHashAlgorithm.cs new file mode 100644 index 0000000..08eb245 --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketHashAlgorithm.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketHashAlgorithm + { + SHA256, + SHA3, + } +} diff --git a/Esiur/Net/Packets/IIPAuthPacketHeader.cs b/Esiur/Net/Packets/IIPAuthPacketHeader.cs new file mode 100644 index 0000000..bbf321f --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketHeader.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketHeader + { + Version = 0, + Domain = 1, + SupportedAuthentications = 2, + SupportedHashAlgorithms = 3, + SupportedCiphers = 4, + SupportedCompression = 5, + SupportedPersonalAuth = 6, + Nonce = 7, + Username = 8, + TokenIndex = 9, + CertificateId = 10, + CachedCertificates = 11, + CipherType = 12, + CipherKey = 13, + SoftwareIdentity = 14, + Referrer = 15, + Time = 16, + Certificate = 17, + IPv4 = 18 + } +} diff --git a/Esiur/Net/Packets/IIPAuthPacketIAuthDestination.cs b/Esiur/Net/Packets/IIPAuthPacketIAuthDestination.cs new file mode 100644 index 0000000..4817886 --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketIAuthDestination.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketIAuthDestination + { + Self = 0, + Device = 1, // logged in device + Email = 2, + SMS = 3, + App = 4, // Authenticator app + ThirdParty = 5, // usualy a second person + } +} diff --git a/Esiur/Net/Packets/IIPAuthPacketIAuthFormat.cs b/Esiur/Net/Packets/IIPAuthPacketIAuthFormat.cs new file mode 100644 index 0000000..e0746d9 --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketIAuthFormat.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketIAuthFormat + { + None = 0, + Number = 1, + Text = 2, + LowercaseText = 3, + Choice = 4, + Photo = 5, + Signature = 6, + Fingerprint = 7, + } + +} diff --git a/Esiur/Net/Packets/IIPAuthPacketIAuthHeader.cs b/Esiur/Net/Packets/IIPAuthPacketIAuthHeader.cs new file mode 100644 index 0000000..7009c64 --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketIAuthHeader.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketIAuthHeader : byte + { + Reference = 0, + Destination = 1, + Clue = 2, + RequiredFormat = 3, + ContentFormat = 4, + Content = 5, + Timeout = 6, + } +} diff --git a/Esiur/Net/Packets/IIPAuthPacketInitialize.cs b/Esiur/Net/Packets/IIPAuthPacketInitialize.cs new file mode 100644 index 0000000..e09d0ad --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketInitialize.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketInitialize + { + NoAuthNoAuth = 0x0, //0b00000000, + NoAuthCredentials = 0x4, //0b00000100, + NoAuthToken = 0x8, //0b00001000, + NoAuthCertificate = 0xC, //0b00001100, + CredentialsNoAuth = 0x10, //0b00010000, + CredentialsCredentials = 0x14, //0b00010100, + CredentialsToken = 0x18, //0b00011000, + CredentialsCertificate = 0x1c, //0b00011100, + TokenNoAuth = 0x20, //0b00100000, + TokenCredentials = 0x24, //0b00100100, + TokenToken = 0x28, //0b00101000, + TokenCertificate = 0x2c, //0b00101100, + CertificateNoAuth = 0x30, //0b00110000, + CertificateCredentials = 0x34,// 0b00110100, + CertificateToken = 0x38, //0b00111000, + CertificateCertificate = 0x3c, //0b00111100, + } +} diff --git a/Esiur/Net/Packets/IIPAuthPacketPublicKeyAlgorithm.cs b/Esiur/Net/Packets/IIPAuthPacketPublicKeyAlgorithm.cs new file mode 100644 index 0000000..27895b7 --- /dev/null +++ b/Esiur/Net/Packets/IIPAuthPacketPublicKeyAlgorithm.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPAuthPacketPublicKeyAlgorithm + { + RSA = 0, + CKKS = 1, + } +} diff --git a/Esiur/Net/Packets/IIPPacket.cs b/Esiur/Net/Packets/IIPPacket.cs index 40a08b9..4e26bf3 100644 --- a/Esiur/Net/Packets/IIPPacket.cs +++ b/Esiur/Net/Packets/IIPPacket.cs @@ -25,7 +25,6 @@ SOFTWARE. using Esiur.Data; using Esiur.Core; using Esiur.Misc; -using Esiur.Net.Packets; using System; using System.Collections.Generic; using System.Linq; @@ -62,81 +61,6 @@ class IIPPacket : Packet return rt; } - public enum IIPPacketCommand : byte - { - Event = 0, - Request, - Reply, - Report, - } - - public enum IIPPacketEvent : byte - { - // Event Manage - ResourceReassigned = 0, - ResourceDestroyed, - ChildAdded, - ChildRemoved, - Renamed, - // Event Invoke - PropertyUpdated = 0x10, - EventOccurred, - - // Attribute - AttributesUpdated = 0x18 - } - - public enum IIPPacketAction : byte - { - // Request Manage - AttachResource = 0, - ReattachResource, - DetachResource, - CreateResource, - DeleteResource, - AddChild, - RemoveChild, - RenameResource, - - // Request Inquire - TemplateFromClassName = 0x8, - TemplateFromClassId, - TemplateFromResourceId, - QueryLink, - ResourceHistory, - ResourceChildren, - ResourceParents, - LinkTemplates, - - // Request Invoke - InvokeFunction = 0x10, - Reserved, - Listen, - Unlisten, - SetProperty, - - // Request Attribute - GetAllAttributes = 0x18, - UpdateAllAttributes, - ClearAllAttributes, - GetAttributes, - UpdateAttributes, - ClearAttributes, - - - // Static calling - KeepAlive = 0x20, - ProcedureCall, - StaticCall - } - - public enum IIPPacketReport : byte - { - ManagementError, - ExecutionError, - ProgressReport = 0x8, - ChunkStream = 0x9 - } public IIPPacketReport Report @@ -648,7 +572,7 @@ class IIPPacket : Packet if (NotEnough(offset, ends, cl)) return -dataLengthNeeded; - + Procedure = data.GetString(offset, cl); offset += cl; @@ -662,7 +586,8 @@ class IIPPacket : Packet offset += (uint)size; - } else if (Action == IIPPacketAction.StaticCall) + } + else if (Action == IIPPacketAction.StaticCall) { if (NotEnough(offset, ends, 18)) return -dataLengthNeeded; diff --git a/Esiur/Net/Packets/IIPPacketAction.cs b/Esiur/Net/Packets/IIPPacketAction.cs new file mode 100644 index 0000000..ef14df3 --- /dev/null +++ b/Esiur/Net/Packets/IIPPacketAction.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPPacketAction : byte + { + // Request Manage + AttachResource = 0, + ReattachResource, + DetachResource, + CreateResource, + DeleteResource, + AddChild, + RemoveChild, + RenameResource, + + // Request Inquire + TemplateFromClassName = 0x8, + TemplateFromClassId, + TemplateFromResourceId, + QueryLink, + ResourceHistory, + ResourceChildren, + ResourceParents, + LinkTemplates, + + // Request Invoke + InvokeFunction = 0x10, + Reserved, + Listen, + Unlisten, + SetProperty, + + // Request Attribute + GetAllAttributes = 0x18, + UpdateAllAttributes, + ClearAllAttributes, + GetAttributes, + UpdateAttributes, + ClearAttributes, + + + // Static calling + KeepAlive = 0x20, + ProcedureCall, + StaticCall + } +} diff --git a/Esiur/Net/Packets/IIPPacketCommand.cs b/Esiur/Net/Packets/IIPPacketCommand.cs new file mode 100644 index 0000000..c3d6b3f --- /dev/null +++ b/Esiur/Net/Packets/IIPPacketCommand.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPPacketCommand : byte + { + Event = 0, + Request, + Reply, + Report, + } +} diff --git a/Esiur/Net/Packets/IIPPacketEvent.cs b/Esiur/Net/Packets/IIPPacketEvent.cs new file mode 100644 index 0000000..52e0da8 --- /dev/null +++ b/Esiur/Net/Packets/IIPPacketEvent.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPPacketEvent : byte + { + // Event Manage + ResourceReassigned = 0, + ResourceDestroyed, + ChildAdded, + ChildRemoved, + Renamed, + // Event Invoke + PropertyUpdated = 0x10, + EventOccurred, + + // Attribute + AttributesUpdated = 0x18 + } +} diff --git a/Esiur/Net/Packets/IIPPacketReport.cs b/Esiur/Net/Packets/IIPPacketReport.cs new file mode 100644 index 0000000..846fb74 --- /dev/null +++ b/Esiur/Net/Packets/IIPPacketReport.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Net.Packets +{ + public enum IIPPacketReport : byte + { + ManagementError, + ExecutionError, + ProgressReport = 0x8, + ChunkStream = 0x9 + } + +} diff --git a/Esiur/Net/Packets/WebsocketPacket.cs b/Esiur/Net/Packets/WebSocket/WebsocketPacket.cs similarity index 86% rename from Esiur/Net/Packets/WebsocketPacket.cs rename to Esiur/Net/Packets/WebSocket/WebsocketPacket.cs index 5650f00..677ef06 100644 --- a/Esiur/Net/Packets/WebsocketPacket.cs +++ b/Esiur/Net/Packets/WebSocket/WebsocketPacket.cs @@ -29,7 +29,7 @@ using System.Text; using Esiur.Misc; using Esiur.Data; -namespace Esiur.Net.Packets; +namespace Esiur.Net.Packets.WebSocket; public class WebsocketPacket : Packet { public enum WSOpcode : byte @@ -84,17 +84,17 @@ public class WebsocketPacket : Packet (byte)Opcode)); // calculate length - if (Message.Length > UInt16.MaxValue) + if (Message.Length > ushort.MaxValue) // 4 bytes { pkt.Add((byte)((Mask ? 0x80 : 0x0) | 127)); - pkt.AddRange(DC.ToBytes((UInt64)Message.LongCount(), Endian.Big)); + pkt.AddRange(((ulong)Message.LongCount()).ToBytes(Endian.Big)); } else if (Message.Length > 125) // 2 bytes { pkt.Add((byte)((Mask ? 0x80 : 0x0) | 126)); - pkt.AddRange(DC.ToBytes((UInt16)Message.Length, Endian.Big)); + pkt.AddRange(((ushort)Message.Length).ToBytes(Endian.Big)); } else { @@ -118,7 +118,7 @@ public class WebsocketPacket : Packet try { long needed = 2; - var length = (ends - offset); + var length = ends - offset; if (length < needed) { //Console.WriteLine("stage 1 " + needed); @@ -126,13 +126,13 @@ public class WebsocketPacket : Packet } uint oOffset = offset; - FIN = ((data[offset] & 0x80) == 0x80); - RSV1 = ((data[offset] & 0x40) == 0x40); - RSV2 = ((data[offset] & 0x20) == 0x20); - RSV3 = ((data[offset] & 0x10) == 0x10); + FIN = (data[offset] & 0x80) == 0x80; + RSV1 = (data[offset] & 0x40) == 0x40; + RSV2 = (data[offset] & 0x20) == 0x20; + RSV3 = (data[offset] & 0x10) == 0x10; Opcode = (WSOpcode)(data[offset++] & 0xF); - Mask = ((data[offset] & 0x80) == 0x80); - PayloadLength = (long)(data[offset++] & 0x7F); + Mask = (data[offset] & 0x80) == 0x80; + PayloadLength = data[offset++] & 0x7F; if (Mask) needed += 4; @@ -192,23 +192,23 @@ public class WebsocketPacket : Packet MaskKey[2] = data[offset++]; MaskKey[3] = data[offset++]; - Message = DC.Clip(data, offset, (uint)PayloadLength); + Message = data.Clip(offset, (uint)PayloadLength); //var aMask = BitConverter.GetBytes(MaskKey); for (int i = 0; i < Message.Length; i++) Message[i] = (byte)(Message[i] ^ MaskKey[i % 4]); } else - Message = DC.Clip(data, offset, (uint)PayloadLength); + Message = data.Clip(offset, (uint)PayloadLength); - return (offset - oOffset) + (int)PayloadLength; + return offset - oOffset + (int)PayloadLength; } } catch (Exception ex) { Console.WriteLine(ex.ToString()); - Console.WriteLine(offset + "::" + DC.ToHex(data)); + Console.WriteLine(offset + "::" + data.ToHex()); throw ex; } } diff --git a/Esiur/Net/Sockets/WSocket.cs b/Esiur/Net/Sockets/WSocket.cs index dc6e75d..0b9394b 100644 --- a/Esiur/Net/Sockets/WSocket.cs +++ b/Esiur/Net/Sockets/WSocket.cs @@ -28,13 +28,13 @@ using System.Linq; using System.Text; using System.Net.Sockets; using System.Net; -using Esiur.Net.Packets; using Esiur.Misc; using System.IO; using Esiur.Core; using Esiur.Resource; using Esiur.Data; using System.Globalization; +using Esiur.Net.Packets.WebSocket; namespace Esiur.Net.Sockets; public class WSocket : ISocket, INetworkReceiver diff --git a/Esiur/Security/Authority/AuthenticationMethod.cs b/Esiur/Security/Authority/AuthenticationMethod.cs index fdaa3a9..7bb4606 100644 --- a/Esiur/Security/Authority/AuthenticationMethod.cs +++ b/Esiur/Security/Authority/AuthenticationMethod.cs @@ -7,7 +7,7 @@ namespace Esiur.Security.Authority; public enum AuthenticationMethod : byte { None, - Certificate, Credentials, - Token + Token, + Certificate } diff --git a/Esiur/Security/Authority/Session.cs b/Esiur/Security/Authority/Session.cs index e25a83e..92ea867 100644 --- a/Esiur/Security/Authority/Session.cs +++ b/Esiur/Security/Authority/Session.cs @@ -31,34 +31,34 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Esiur.Security.Cryptography; +using static System.Collections.Specialized.BitVector32; +using Esiur.Net.Packets; namespace Esiur.Security.Authority; public class Session { - public Authentication LocalAuthentication => localAuth; - public Authentication RemoteAuthentication => remoteAuth; - - // public Source Source { get; } public byte[] Id { get; set; } public DateTime Creation { get; } public DateTime Modification { get; } public KeyList Variables { get; } = new KeyList(); - //KeyList Variables { get; } - //IStore Store { get; } - - //string id; - Authentication localAuth, remoteAuth; - //string domain; public IKeyExchanger KeyExchanger { get; set; } = null; public ISymetricCipher SymetricCipher { get; set; } = null; - public Session(Authentication localAuthentication, Authentication remoteAuthentication) - { - this.localAuth = localAuthentication; - this.remoteAuth = remoteAuthentication; - } + public Map LocalHeaders { get; set; } = new Map(); + public Map RemoteHeaders { get; set; } = new Map(); + + public AuthenticationMethod LocalMethod { get; set; } + public AuthenticationMethod RemoteMethod { get; set; } + + public AuthenticationType AuthenticationType { get; set; } + + + public string AuthorizedAccount { get; set; } + + + } diff --git a/Esiur/Security/Membership/AuthorizationResponse.cs b/Esiur/Security/Membership/AuthorizationIndication.cs similarity index 66% rename from Esiur/Security/Membership/AuthorizationResponse.cs rename to Esiur/Security/Membership/AuthorizationIndication.cs index 3ebb221..5bb085f 100644 --- a/Esiur/Security/Membership/AuthorizationResponse.cs +++ b/Esiur/Security/Membership/AuthorizationIndication.cs @@ -5,9 +5,9 @@ using System.Text; namespace Esiur.Security.Membership { - public class AuthorizationResponse + public class AuthorizationIndication { public Session Session { get; set; } - public bool Succeeded { get; set; } + public AuthorizationResults Results { get; set; } } } diff --git a/Esiur/Security/Membership/AuthorizationResults.cs b/Esiur/Security/Membership/AuthorizationResults.cs index 1b7125b..68e2f64 100644 --- a/Esiur/Security/Membership/AuthorizationResults.cs +++ b/Esiur/Security/Membership/AuthorizationResults.cs @@ -1,4 +1,5 @@ -using System; +using Esiur.Net.Packets; +using System; using System.Collections.Generic; using System.Text; @@ -6,11 +7,16 @@ namespace Esiur.Security.Membership { public class AuthorizationResults { - AuthorizationResultsResponse Response { get; set; } - TwoFactorAuthorizationMethod TwoFactorMethod { get; set; } + public AuthorizationResultsResponse Response { get; set; } + public IIPAuthPacketIAuthDestination Destination { get; set; } + public IIPAuthPacketIAuthFormat RequiredFormat { get; set; } public string Clue { get; set; } - public string AppName { get; set; } - public string Code { get; set; } - public int Timeout { get; set; } + + public ushort Timeout { get; set; } // 0 means no timeout + public uint Reference { get; set; } + + public DateTime Issue { get; set; } = DateTime.UtcNow; + + public bool Expired => Timeout == 0 ? false : (DateTime.UtcNow - Issue).TotalSeconds > Timeout; } } diff --git a/Esiur/Security/Membership/AuthorizationResultsResponse.cs b/Esiur/Security/Membership/AuthorizationResultsResponse.cs index 730cdb5..fe3acde 100644 --- a/Esiur/Security/Membership/AuthorizationResultsResponse.cs +++ b/Esiur/Security/Membership/AuthorizationResultsResponse.cs @@ -7,7 +7,11 @@ namespace Esiur.Security.Membership public enum AuthorizationResultsResponse { Success, + Failed, + Expired, ServiceUnavailable, - TwoFactoryAuthorization, + IAuthPlain, + IAuthHashed, + IAuthEncrypted } } diff --git a/Esiur/Security/Membership/IMembership.cs b/Esiur/Security/Membership/IMembership.cs index eb994df..7bf2126 100644 --- a/Esiur/Security/Membership/IMembership.cs +++ b/Esiur/Security/Membership/IMembership.cs @@ -32,21 +32,28 @@ using Esiur.Net.IIP; using Esiur.Core; using Esiur.Security.Authority; using Esiur.Resource; +using Esiur.Net.Packets; namespace Esiur.Security.Membership; public interface IMembership { - public event ResourceEventHandler Authorization; + public event ResourceEventHandler Authorization; + + AsyncReply UserExists(string username, string domain); + AsyncReply TokenExists(ulong tokenIndex, string domain); - AsyncReply UserExists(string username, string domain); AsyncReply GetPassword(string username, string domain); AsyncReply GetToken(ulong tokenIndex, string domain); AsyncReply Authorize(Session session); + AsyncReply AuthorizePlain(Session session, uint reference, object value); + AsyncReply AuthorizeHashed(Session session, uint reference, IIPAuthPacketHashAlgorithm algorithm, byte[] value); + AsyncReply AuthorizeEncrypted(Session session, uint reference, IIPAuthPacketPublicKeyAlgorithm algorithm, byte[] value); + AsyncReply Login(Session session); AsyncReply Logout(Session session); bool GuestsAllowed { get; } - AsyncReply TokenExists(ulong tokenIndex, string domain); + } diff --git a/Esiur/Security/Membership/SimpleMembership.cs b/Esiur/Security/Membership/SimpleMembership.cs new file mode 100644 index 0000000..d584164 --- /dev/null +++ b/Esiur/Security/Membership/SimpleMembership.cs @@ -0,0 +1,184 @@ +using Esiur.Core; +using Esiur.Data; +using Esiur.Net.Packets; +using Esiur.Resource; +using Esiur.Security.Authority; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace Esiur.Security.Membership +{ + public class SimpleMembership : IMembership + { + public bool GuestsAllowed { get; set; } = false; + + public event ResourceEventHandler Authorization; + + KeyList users = new KeyList(); + + KeyList tokens = new KeyList(); + + public class QuestionAnswer + { + public string Question { get; set; } + public object Answer { get; set; } + public bool Hashed { get; set; } + } + + public class UserInfo + { + public string Username { get; set; } + public string Password { get; set; } + public QuestionAnswer[] Questions { get; set; } + + public List Results { get; set; } = new List(); + } + + public class TokenInfo + { + public ulong Index { get; set; } + public string Token { get; set; } + public string Username { get; set; } + } + + public void AddToken(ulong index, string value, string username) + { + if (users.ContainsKey(username)) + throw new Exception("User not found."); + + tokens.Add(index, new TokenInfo() { Index = index, Token = value, Username = username }); + } + + public void AddUser(string username, string password, QuestionAnswer[] questions) + { + users.Add(username, new UserInfo() { Password = password, Username = username, Questions = questions }); + } + + public void RemoveToken(ulong index) => tokens.Remove(index); + + public void RemoveUser(string username) => users.Remove(username); + + + + public AsyncReply Authorize(Session session) + { + if (session.AuthorizedAccount.StartsWith("g-")) + return new AsyncReply(new AuthorizationResults() { Response = AuthorizationResultsResponse.Success }); + + if (users[session.AuthorizedAccount].Questions.Length > 0) + { + var q = users[session.AuthorizedAccount].Questions.First(); + + var r = new Random(); + + var format = q.Answer.GetIAuthFormat(); + + var ar = new AuthorizationResults() + { + Clue = q.Question, + Destination = IIPAuthPacketIAuthDestination.Self, + Reference = (uint)r.Next(), + RequiredFormat = format, + Timeout = 30, + Response = q.Hashed ? AuthorizationResultsResponse.IAuthHashed : AuthorizationResultsResponse.IAuthPlain + }; + + users[session.AuthorizedAccount].Results.Add(ar); + + return new AsyncReply(ar); + } + else + { + return new AsyncReply(new AuthorizationResults() { Response = AuthorizationResultsResponse.Success }); + } + } + + public AsyncReply AuthorizeEncrypted(Session session, uint reference, IIPAuthPacketPublicKeyAlgorithm algorithm, byte[] value) + { + throw new NotImplementedException(); + } + + public AsyncReply AuthorizeHashed(Session session, uint reference, IIPAuthPacketHashAlgorithm algorithm, byte[] value) + { + if (algorithm != IIPAuthPacketHashAlgorithm.SHA256) + throw new NotImplementedException(); + + var ar = users[session.AuthorizedAccount].Results.First(x => x.Reference == reference); + + var qa = users[session.AuthorizedAccount].Questions.First(x => x.Question == ar.Clue); + + + // compute hash + var remoteNonce = (byte[])session.RemoteHeaders[IIPAuthPacketHeader.Nonce]; + var localNonce = (byte[])session.LocalHeaders[IIPAuthPacketHeader.Nonce]; + + var hashFunc = SHA256.Create(); + // local nonce + password or token + remote nonce + var challenge = hashFunc.ComputeHash(new BinaryList() + .AddUInt8Array(remoteNonce) + .AddUInt8Array(Codec.Compose(qa.Answer, null)) + .AddUInt8Array(localNonce) + .ToArray()); + + if (challenge.SequenceEqual(value)) + return new AsyncReply(new AuthorizationResults() { Response = AuthorizationResultsResponse.Success }); + else + return new AsyncReply(new AuthorizationResults() { Response = AuthorizationResultsResponse.Failed }); + + } + + public AsyncReply AuthorizePlain(Session session, uint reference, object value) + { + var ar = users[session.AuthorizedAccount].Results.First(x => x.Reference == reference); + + var qa = users[session.AuthorizedAccount].Questions.First(x => x.Question == ar.Clue); + + + if (qa.Answer.ToString() == value.ToString()) + return new AsyncReply(new AuthorizationResults() { Response = AuthorizationResultsResponse.Success }); + else + return new AsyncReply(new AuthorizationResults() { Response = AuthorizationResultsResponse.Failed }); + + } + + public AsyncReply GetPassword(string username, string domain) + { + return new AsyncReply(DC.ToBytes(users[username].Password)); + } + + public AsyncReply GetToken(ulong tokenIndex, string domain) + { + return new AsyncReply(DC.ToBytes(tokens[tokenIndex].Token)); + } + + public AsyncReply Login(Session session) + { + return new AsyncReply(true); + } + + public AsyncReply Logout(Session session) + { + return new AsyncReply(true); + } + + public AsyncReply TokenExists(ulong tokenIndex, string domain) + { + if (!tokens.ContainsKey(tokenIndex)) + return new AsyncReply(null); + else + return new AsyncReply(tokens[tokenIndex].Username); + } + + public AsyncReply UserExists(string username, string domain) + { + if (!users.ContainsKey(username)) + return new AsyncReply(null); + else + return new AsyncReply(username); + } + + } +} diff --git a/Esiur/Security/Permissions/UserPermissionsManager.cs b/Esiur/Security/Permissions/UserPermissionsManager.cs index 536483f..c3e4082 100644 --- a/Esiur/Security/Permissions/UserPermissionsManager.cs +++ b/Esiur/Security/Permissions/UserPermissionsManager.cs @@ -44,8 +44,8 @@ public class UserPermissionsManager : IPermissionsManager { Map userPermissions = null; - if (settings.ContainsKey(session.RemoteAuthentication.FullName)) - userPermissions = settings[session.RemoteAuthentication.FullName] as Map; + if (settings.ContainsKey(session.AuthorizedAccount)) + userPermissions = settings[session.AuthorizedAccount] as Map; else if (settings.ContainsKey("public")) userPermissions = settings["public"] as Map; else diff --git a/Test/Program.cs b/Test/Program.cs index 3543033..9269c70 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -46,6 +46,8 @@ using System.Reflection; using System.Security.Cryptography; using System.Text; using Esiur.Security.Cryptography; +using Esiur.Security.Membership; +using Esiur.Net.Packets; namespace Test { @@ -67,9 +69,23 @@ namespace Test Console.WriteLine(ska.ToHex()); Console.WriteLine(skb.ToHex()); + // Simple membership provider + var membership = new SimpleMembership() { GuestsAllowed = true }; + + membership.AddUser("user", "123456", new SimpleMembership.QuestionAnswer[0]); + membership.AddUser("admin", "admin", new SimpleMembership.QuestionAnswer[] + { + new SimpleMembership.QuestionAnswer() + { + Question = "What is 5+5", + Answer = 10, + Hashed = true, + } + }); + // Create stores to keep objects. var system = await Warehouse.Put("sys", new MemoryStore()); - var server = await Warehouse.Put("sys/server", new DistributedServer()); + var server = await Warehouse.Put("sys/server", new DistributedServer() { Membership = membership }); var web = await Warehouse.Put("sys/web", new HTTPServer() { Port = 8088 }); @@ -112,12 +128,33 @@ namespace Test + static AsyncReply Authenticator(Map x) + { + Console.WriteLine($"Authenticator: {x[IIPAuthPacketIAuthHeader.Clue]}"); + + var format = (IIPAuthPacketIAuthFormat)x[IIPAuthPacketIAuthHeader.RequiredFormat]; + + if (format == IIPAuthPacketIAuthFormat.Number) + return new AsyncReply(Convert.ToInt32(Console.ReadLine())); + else if (format == IIPAuthPacketIAuthFormat.Text) + return new AsyncReply(Console.ReadLine().Trim()); + + throw new NotImplementedException("Not supported format."); + } + private static async void TestClient(IResource local) { - var con = await Warehouse.Get("iip://localhost", new { AutoReconnect = true }); + var con = await Warehouse.Get("iip://localhost", new DistributedConnectionConfig + { + AutoReconnect = true, + Username = "admin", + Password = "admin", + Authenticator = Authenticator + }); + dynamic remote = await con.Get("sys/service"); var pcall = await con.Call("Hello", "whats up ?", DateTime.UtcNow); diff --git a/Test/Test.csproj b/Test/Test.csproj index 299d50e..9cb0db4 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -6,7 +6,7 @@ - +