using EVCB_OCPP.Domain; using EVCB_OCPP.WSServer; using NLog; using OCPPPackage.Profiles; using SuperWebSocket; using SuperWebSocket.SubProtocol; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Text; namespace OCPPServer.Protocol { public class OCPPWSServer : WebSocketServer { static private ILogger logger = NLog.LogManager.GetCurrentClassLogger(); /// /// 可允許連線Clinet數 /// public int connectNum { get; set; } /// /// 是否限制連線Clinet數 /// public bool beConnectLimit { get; set; } /// /// Initializes a new instance of the class. /// /// The sub protocols. public OCPPWSServer(IEnumerable> subProtocols) : base(subProtocols) { } /// /// Initializes a new instance of the class. /// /// The sub protocol. public OCPPWSServer(ISubProtocol subProtocol) : base(subProtocol) { } /// /// Initializes a new instance of the class. /// public OCPPWSServer() : base(new List>()) { } protected override bool ValidateClientCertificate(ClientData session, object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { // Console.WriteLine(string.Format("{0} :{1}", session.ChargeBoxId + " ValidateClientCertificate", sslPolicyErrors)); return true; // return base.ValidateClientCertificate(session, sender, certificate, chain, sslPolicyErrors); } protected override bool ValidateHandshake(ClientData session, string origin) { session.ISOCPP20 = session.SecWebSocketProtocol.ToLower().Contains("ocpp2.0"); int securityProfile = 0; string authorizationKey = string.Empty; if (string.IsNullOrEmpty(session.Path)) { logger.Warn("==========================================="); logger.Warn("session.Path EMPTY"); logger.Warn("==========================================="); } string[] words = session.Path.Split('/'); session.ChargeBoxId = words.Last(); foreach(var denyModel in GlobalConfig.DenyModelNames) { if (string.IsNullOrEmpty(denyModel)) break; if (session.ChargeBoxId.StartsWith(denyModel)) { StringBuilder responseBuilder = new StringBuilder(); responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1", (int)HttpStatusCode.Unauthorized, @"Unauthorized"); responseBuilder.AppendWithCrCf(); string sb = responseBuilder.ToString(); byte[] data = Encoding.UTF8.GetBytes(sb); ((IWebSocketSession)session).SendRawData(data, 0, data.Length); logger.Info(sb); return false; } } if (ConfigurationManager.AppSettings["MaintainMode"] == "1") { session.ChargeBoxId = session.ChargeBoxId + "_2"; } logger.Info(string.Format("ValidateHandshake: {0}", session.Path)); bool isExistedSN = false; bool authorizated = false; using (var db = new MainDBContext()) { var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).FirstOrDefault(); session.CustomerName = machine == null ? "Unknown" : db.Customer.Where(x => x.Id == machine.CustomerId).Select(x => x.Name).FirstOrDefault(); session.CustomerId = machine == null ? Guid.Empty : machine.CustomerId; session.MachineId = machine == null ? String.Empty : machine.Id; isExistedSN = machine == null ? false : true; if (!isExistedSN) { StringBuilder responseBuilder = new StringBuilder(); responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1", (int)HttpStatusCode.NotFound, @"Not Found"); responseBuilder.AppendWithCrCf(); string sb = responseBuilder.ToString(); byte[] data = Encoding.UTF8.GetBytes(sb); ((IWebSocketSession)session).SendRawData(data, 0, data.Length); logger.Info(sb); return false; } var configVaule = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.SecurityProfile) .Select(x => x.ConfigureSetting).FirstOrDefault(); int.TryParse(configVaule, out securityProfile); if (session.ISOCPP20) { // 1.6 server only support change server function securityProfile = 0; } } if (securityProfile == 3 && session.UriScheme == "ws") { StringBuilder responseBuilder = new StringBuilder(); responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1", (int)HttpStatusCode.Unauthorized, @"Unauthorized"); responseBuilder.AppendWithCrCf(); string sb = responseBuilder.ToString(); byte[] data = Encoding.UTF8.GetBytes(sb); ((IWebSocketSession)session).SendRawData(data, 0, data.Length); logger.Info(sb); return false; } if ((securityProfile == 1 || securityProfile == 2)) { if (securityProfile == 2 && session.UriScheme == "ws") { authorizated = false; } if (session.Items.ContainsKey("Authorization") || session.Items.ContainsKey("authorization")) { using (var db = new MainDBContext()) { authorizationKey = db.MachineConfiguration.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.AuthorizationKey) .Select(x => x.ConfigureSetting).FirstOrDefault(); if (session.ISOCPP20) { // 1.6 server only support change server function securityProfile = 0; } } logger.Info("***********Authorization "); if (!string.IsNullOrEmpty(authorizationKey)) { string base64Encoded = session.Items.ContainsKey("Authorization") ? session.Items["Authorization"].ToString().Replace("Basic ", "") : session.Items["authorization"].ToString().Replace("Basic ", ""); byte[] data = Convert.FromBase64String(base64Encoded); string[] base64Decoded = System.Text.ASCIIEncoding.ASCII.GetString(data).Split(':'); logger.Info("***********Authorization " + System.Text.ASCIIEncoding.ASCII.GetString(data)); if (base64Decoded.Count() == 2 && base64Decoded[0] == session.ChargeBoxId && base64Decoded[1] == authorizationKey) { authorizated = true; } } } else { authorizated = true; } if (!authorizated) { StringBuilder responseBuilder = new StringBuilder(); responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1", (int)HttpStatusCode.Unauthorized, @"Unauthorized"); responseBuilder.AppendWithCrCf(); string sb = responseBuilder.ToString(); byte[] data = Encoding.UTF8.GetBytes(sb); ((IWebSocketSession)session).SendRawData(data, 0, data.Length); logger.Info(sb); return false; } } return true; } } }