Imports System.IO Imports System.Net Imports System.Security.Cryptography.X509Certificates Imports System.Text Imports DigitalData.Modules.Logging Imports Newtonsoft.Json Public Class GraphQLInterface Private _logConfig As LogConfig Private _logger As Logger Private _baseUrl As String Private _userEmail As String Private _userPassword As String Private _certificate As X509Certificate2 Private _cookieJar As CookieContainer Private _Encoding As New UTF8Encoding Private Const MAX_COOKIE_SIZE As Integer = 32768 Private Const MAX_COOKIE_COUNT As Integer = 300 Private Const MAX_COOKIE_COUNT_PER_DOMAIN As Integer = 20 Public Property Proxy As WebProxy Public Property Credentials As NetworkCredential Public Sub New(LogConfig As LogConfig, BaseUrl As String, Email As String, Password As String, CertificateFingerprint As String) Try _logConfig = LogConfig _logger = LogConfig.GetLogger() _baseUrl = BaseUrl _userEmail = Email _userPassword = Password Dim oStoreNames As New List(Of StoreName) From {StoreName.Root, StoreName.My} Dim oCertificate As X509Certificate2 = Nothing For Each oStoreName In oStoreNames oCertificate = FindCertificateByFingerprint(oStoreName, CertificateFingerprint, False) If oCertificate IsNot Nothing Then _logger.Info("Certificate found in Store [{0}]!", oStoreName.ToString) Exit For End If Next If oCertificate Is Nothing Then _logger.Warn("Certificate could not be found! Exiting.") Exit Sub End If _certificate = oCertificate Catch ex As Exception _logger.Error(ex) End Try End Sub Private Function FindCertificateByFingerprint(pStoreName As StoreName, pFingerprint As String, pValidOnly As Boolean) As X509Certificate2 Dim oStore As New X509Store(pStoreName, StoreLocation.CurrentUser) oStore.Open(OpenFlags.ReadOnly) _logger.Info("Available Certificates in Store [{0}]: [{1}]", oStore.Name, oStore.Certificates.Count) For Each oCert In oStore.Certificates _logger.Debug("FriendlyName: {0}", oCert.FriendlyName) _logger.Debug("IssuerName: {0}", oCert.IssuerName.Name) _logger.Debug("SubjectName: {0}", oCert.SubjectName.Name) _logger.Debug("Fingerprint: {0}", oCert.Thumbprint) Next _logger.Debug("Looking for Certificate with Fingerprint [{0}]", pFingerprint) Dim oFoundCerts = oStore.Certificates.Find(X509FindType.FindByThumbprint, pFingerprint, pValidOnly) oStore.Close() If oFoundCerts.Count = 0 Then Return Nothing End If Return oFoundCerts.Item(0) End Function Public Sub SaveCookies(Cookie As Cookie) GetCookies().Add(Cookie) End Sub Public Function Login() As HttpWebResponse Try Dim oLoginData As New LoginData() With {.email = _userEmail, .token = _userPassword} Dim oBytes As Byte() = ToBytes(JsonConvert.SerializeObject(oLoginData)) Dim oRequest As HttpWebRequest = GetRequest("/login", oBytes) Using oStream = oRequest.GetRequestStream() oStream.Write(oBytes, 0, oBytes.Length) End Using Return oRequest.GetResponse() Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Public Function Logout() As HttpWebResponse Try Dim oLogoutData As New LogoutData() With {.email = _userEmail} Dim oBytes As Byte() = ToBytes(JsonConvert.SerializeObject(oLogoutData)) Dim oRequest As HttpWebRequest = GetRequest("/logout", oBytes) Using stream = oRequest.GetRequestStream() stream.Write(oBytes, 0, oBytes.Length) End Using Return oRequest.GetResponse() Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Public Function GetData(Query As String, OperationName As String) As HttpWebResponse Try Dim oQueryData As New QueryData() With { .operationName = OperationName, .query = Query, .variables = New Object } Dim oJson = JsonConvert.SerializeObject(oQueryData) Dim oBytes = ToBytes(oJson) Dim oRequest = GetRequest("/graphql", oBytes) Using stream = oRequest.GetRequestStream() stream.Write(oBytes, 0, oBytes.Length) End Using Return oRequest.GetResponse() Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Public Function ReadJSONPathFragmented(pObject As Linq.JObject, pJsonPath As String) Dim oSplitPath As List(Of String) = pJsonPath.Split(".").ToList() Dim oCurrentPath As String = String.Empty For Each oPart In oSplitPath If oCurrentPath = String.Empty Then oCurrentPath = oPart Else oCurrentPath &= "." & oPart End If _logger.Debug("Selecting Path Fragment [{0}]", oCurrentPath) Try pObject.SelectToken(oCurrentPath, errorWhenNoMatch:=True) Catch ex As Exception _logger.Warn("Path Fragment [{0}] did not return a valid token", oCurrentPath) Return False End Try Next Return True End Function Private Function GetRequest(Url As String, PostData As Byte()) As HttpWebRequest Try ' Set supported TLS versions for WebRequest ' Source: https://stackoverflow.com/questions/10822509/the-request-was-aborted-could-not-create-ssl-tls-secure-channel 'SetSecurityOptions() 'SetSecurityOptionsInsecure() 'SetSecurityOptionsModern() Dim oRequest As HttpWebRequest = WebRequest.Create($"{_baseUrl}{Url}") oRequest.Method = "POST" oRequest.ContentType = "application/json" oRequest.ContentLength = PostData.Length oRequest.ClientCertificates.Add(_certificate) oRequest.CookieContainer = GetCookies() oRequest.Proxy = Nothing If Proxy Is Nothing Then oRequest.Proxy = Nothing Else oRequest.Proxy = Proxy oRequest.Credentials = Credentials End If Return oRequest Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Private Sub SetSecurityOptions() ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12 End Sub Private Sub SetSecurityOptionsInsecure() ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12 Or SecurityProtocolType.Ssl3 End Sub Private Sub SetSecurityOptionsModern() ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 End Sub Private Function GetCookies() As CookieContainer If _cookieJar Is Nothing Then _cookieJar = New CookieContainer(MAX_COOKIE_COUNT, MAX_COOKIE_COUNT_PER_DOMAIN, MAX_COOKIE_SIZE) End If Return _cookieJar End Function Private Function ToBytes(Str As String) As Byte() Return _Encoding.GetBytes(Str) End Function End Class