using EVCB_OCPP.Domain; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using MongoDB.Driver.Core.Servers; 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; private readonly IConfiguration configuration; private readonly IServiceProvider serviceProvider; /// /// 可允許連線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, IServiceProvider serviceProvider) : base(subProtocols) { this.configuration = serviceProvider.GetService(); this.serviceProvider = serviceProvider; logger = serviceProvider.GetService>(); } /// /// Initializes a new instance of the class. /// /// The sub protocol. public OCPPWSServer(ISubProtocol subProtocol, IServiceProvider serviceProvider) : base(subProtocol) { this.configuration = serviceProvider.GetService(); this.serviceProvider = serviceProvider; logger = serviceProvider.GetService>(); } /// /// Initializes a new instance of the class. /// public OCPPWSServer(IServiceProvider serviceProvider) : base(new List>()) { this.configuration = serviceProvider.GetService(); this.serviceProvider = serviceProvider; 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(); if (configuration["MaintainMode"] == "1") { session.ChargeBoxId = session.ChargeBoxId + "_2"; } logger.LogInformation(string.Format("ValidateHandshake: {0}", session.Path)); bool isExistedSN = false; bool authorizated = false; using (var db = serviceProvider.GetService>().CreateDbContext()) { 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; 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(); 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")) { using (var db = serviceProvider.GetService>().CreateDbContext()) { authorizationKey = db.MachineConfigurations.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.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 = System.Text.ASCIIEncoding.ASCII.GetString(data).Split(':'); logger.LogInformation("***********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.LogInformation(sb); return false; } } return true; } } }