using EVCB_OCPP.WSServer.Service; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using OCPPServer.Protocol; using SuperSocket.SocketBase; using SuperWebSocket; using SuperWebSocket.SubProtocol; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Text; namespace EVCB_OCPP.WSServer.SuperSocket; public class OCPPWSServer : WebSocketServer { private readonly ILogger logger; private readonly IConfiguration configuration; private readonly IMainDbService mainDbService; /// /// 可允許連線Clinet數 /// public int connectNum { get; set; } /// /// 是否限制連線Clinet數 /// public bool beConnectLimit { get; set; } /// /// Initializes a new instance of the class. /// /// The sub protocols. public OCPPWSServer( IConfiguration configuration, IMainDbService mainDbService, ILogger logger) : base(new List>()) { this.configuration = configuration; this.mainDbService = mainDbService; this.logger = logger; } /// /// Initializes a new instance of the class. /// /// The sub protocol. //public OCPPWSServer(ISubProtocol subProtocol, IServiceProvider serviceProvider) // : base(subProtocol) //{ // this.configuration = serviceProvider.GetService(); // logger = serviceProvider.GetService>(); //} /// /// Initializes a new instance of the class. /// //public OCPPWSServer(IServiceProvider serviceProvider) // : base(new List>()) //{ // this.configuration = serviceProvider.GetService(); // logger = serviceProvider.GetService>(); //} 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.Log(); logger.LogWarning("==========================================="); logger.LogWarning("session.Path EMPTY"); logger.LogWarning("==========================================="); } 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.LogTrace(sb); return false; } } if (configuration["MaintainMode"] == "1") { session.ChargeBoxId = session.ChargeBoxId + "_2"; } logger.LogInformation(string.Format("ValidateHandshake: {0}", session.Path)); bool isExistedSN = false; bool authorizated = false; var info = mainDbService.GetMachineIdAndCustomerInfo(session.ChargeBoxId).Result; //var machine = db.Machine.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).AsNoTracking().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; session.CustomerName = info.CustomerName; session.CustomerId = info.CustomerId; session.MachineId = info.MachineId; isExistedSN = !string.IsNullOrEmpty(info.MachineId);// 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.LogInformation(sb); return false; } //var configVaule = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.SecurityProfile) // .Select(x => x.ConfigureSetting).FirstOrDefault(); var configVaule = mainDbService.GetMachineSecurityProfile(session.ChargeBoxId).Result; 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.LogInformation(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")) { //authorizationKey = db.MachineConfigurations.Where(x => x.ChargeBoxId == session.ChargeBoxId && x.ConfigureName == StandardConfiguration.AuthorizationKey) // .Select(x => x.ConfigureSetting).FirstOrDefault(); authorizationKey = mainDbService.GetMachineAuthorizationKey(session.ChargeBoxId).Result; if (session.ISOCPP20) { // 1.6 server only support change server function securityProfile = 0; } logger.LogInformation("***********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 = Encoding.ASCII.GetString(data).Split(':'); logger.LogInformation("***********Authorization " + Encoding.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.LogInformation(sb); return false; } } logger.LogInformation(string.Format("ValidateHandshake PASS: {0}", session.Path)); return true; } }