Imports System.Configuration
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.Web
Imports System.Web.Configuration
Imports Newtonsoft.Json
'''
''' VB.NET Client Library for 602TechSec API v2 Integration
''' Provides easy integration for verification calls in web applications
'''
Public Class TechSec602Client
Private ReadOnly _httpClient As HttpClient
Private ReadOnly _config As TechSec602Config
Public Sub New(config As TechSec602Config)
_config = config
_httpClient = New HttpClient() With {
.Timeout = TimeSpan.FromMilliseconds(_config.TimeoutMs)
}
If Not String.IsNullOrEmpty(_config.ApiKey) Then
_httpClient.DefaultRequestHeaders.Add("X-API-Key", _config.ApiKey)
End If
End Sub
Public Sub New()
Me.New(TechSec602Config.FromAppSettings())
End Sub
'''
''' Primary verification method using v2 API format (URL-based)
'''
''' The URL to verify
''' The client IP address (direct connection)
''' Optional X-Forwarded-For IP for proxy scenarios. When provided, BOTH IPs are checked.
''' Optional API key override
Public Async Function VerifyRequestAsync(url As String, Optional ipAddress As String = Nothing, Optional forwardedForIp As String = Nothing, Optional apiKey As String = Nothing) As Task(Of VerificationResult)
Try
Dim requestApiKey = If(apiKey, _config.ApiKey)
Dim clientIp = If(ipAddress, GetClientIpAddress())
Dim formData = New List(Of KeyValuePair(Of String, String)) From {
New KeyValuePair(Of String, String)("url", url)
}
If Not String.IsNullOrEmpty(requestApiKey) Then
formData.Add(New KeyValuePair(Of String, String)("apiKey", requestApiKey))
End If
If Not String.IsNullOrEmpty(clientIp) Then
formData.Add(New KeyValuePair(Of String, String)("ipAddress", clientIp))
End If
' Add forwarded IP for proxy/load balancer scenarios
' When provided, the API will check BOTH the direct IP and forwarded IP
If Not String.IsNullOrEmpty(forwardedForIp) Then
formData.Add(New KeyValuePair(Of String, String)("forwardedForIp", forwardedForIp))
End If
Dim content = New FormUrlEncodedContent(formData)
Dim response = Await _httpClient.PostAsync($"{_config.BaseUrl}/api/verify", content)
If response.IsSuccessStatusCode Then
Dim jsonResponse = Await response.Content.ReadAsStringAsync()
Dim apiResult = JsonConvert.DeserializeObject(Of ApiVerificationResponse)(jsonResponse)
Return New VerificationResult With {
.IsAllowed = apiResult.IsAllowed,
.Reason = apiResult.Reason,
.ProcessingTimeMs = apiResult.ProcessingTimeMs,
.Success = True
}
Else
Return New VerificationResult With {
.IsAllowed = _config.FailOpen,
.Reason = $"HTTP {response.StatusCode}: {response.ReasonPhrase}",
.Success = False
}
End If
Catch ex As TaskCanceledException
' Timeout occurred
Return New VerificationResult With {
.IsAllowed = _config.FailOpen,
.Reason = "Request timeout",
.Success = False
}
Catch ex As Exception
' Network or other error
Return New VerificationResult With {
.IsAllowed = _config.FailOpen,
.Reason = ex.Message,
.Success = False
}
End Try
End Function
'''
''' Synchronous verification method (not recommended for production)
'''
''' The URL to verify
''' The client IP address (direct connection)
''' Optional X-Forwarded-For IP for proxy scenarios. When provided, BOTH IPs are checked.
''' Optional API key override
Public Function VerifyRequest(url As String, Optional ipAddress As String = Nothing, Optional forwardedForIp As String = Nothing, Optional apiKey As String = Nothing) As VerificationResult
Return VerifyRequestAsync(url, ipAddress, forwardedForIp, apiKey).Result
End Function
'''
''' Quick verification for current HTTP context.
''' Automatically extracts both the direct IP and X-Forwarded-For IP if present.
'''
Public Async Function VerifyCurrentRequestAsync() As Task(Of VerificationResult)
If HttpContext.Current Is Nothing Then
Return New VerificationResult With {.IsAllowed = _config.FailOpen, .Reason = "No HTTP context", .Success = False}
End If
Dim request = HttpContext.Current.Request
Dim url = request.Url.ToString()
Dim ipAddress = request.UserHostAddress
' Extract X-Forwarded-For IP separately for dual-IP verification
Dim forwardedForIp = GetForwardedForIp()
Return Await VerifyRequestAsync(url, ipAddress, forwardedForIp).ConfigureAwait(False)
End Function
'''
''' Gets the X-Forwarded-For IP address from the request headers.
''' Returns the first IP in the chain (client IP).
'''
Private Function GetForwardedForIp() As String
If HttpContext.Current Is Nothing Then Return Nothing
Dim forwarded = HttpContext.Current.Request.Headers("X-Forwarded-For")
If Not String.IsNullOrEmpty(forwarded) Then
Return forwarded.Split(","c)(0).Trim()
End If
' Also check X-Real-IP as an alternative
Dim realIp = HttpContext.Current.Request.Headers("X-Real-IP")
If Not String.IsNullOrEmpty(realIp) Then
Return realIp
End If
Return Nothing
End Function
'''
''' Health check for the verification service
'''
Public Async Function HealthCheckAsync() As Task(Of Boolean)
Try
Dim response = Await _httpClient.GetAsync($"{_config.BaseUrl}/api/verify/health")
Return response.IsSuccessStatusCode
Catch
Return False
End Try
End Function
'''
''' Get API information and capabilities
'''
Public Async Function GetApiInfoAsync() As Task(Of Object)
Try
Dim response = Await _httpClient.GetAsync($"{_config.BaseUrl}/api/verify/info")
If response.IsSuccessStatusCode Then
Dim json = Await response.Content.ReadAsStringAsync()
Return JsonConvert.DeserializeObject(json)
End If
Catch
' Ignore errors
End Try
Return Nothing
End Function
'''
''' Gets the client IP address - returns direct connection IP (UserHostAddress).
''' For proxy scenarios, use GetForwardedForIp() separately.
'''
Private Function GetClientIpAddress() As String
If HttpContext.Current Is Nothing Then Return Nothing
Return HttpContext.Current.Request.UserHostAddress
End Function
Public Sub Dispose()
_httpClient?.Dispose()
End Sub
End Class
'''
''' Configuration class for TechSec602Client
'''
Public Class TechSec602Config
Public Property BaseUrl As String = "https://sec.602.tech"
Public Property ApiKey As String = ""
Public Property TimeoutMs As Integer = 5000
Public Property FailOpen As Boolean = True ' Allow requests when service is unavailable
Public Property EnableLogging As Boolean = False
Public Property CacheResults As Boolean = True
Public Property CacheTimeoutMinutes As Integer = 5
Public Shared Function FromAppSettings() As TechSec602Config
Return New TechSec602Config With {
.BaseUrl = ConfigurationManager.AppSettings("TechSec602.BaseUrl") ?: "https://sec.602.tech",
.ApiKey = ConfigurationManager.AppSettings("TechSec602.ApiKey") ?: "",
.TimeoutMs = Integer.Parse(ConfigurationManager.AppSettings("TechSec602.TimeoutMs") ?: "5000"),
.FailOpen = Boolean.Parse(ConfigurationManager.AppSettings("TechSec602.FailOpen") ?: "true"),
.EnableLogging = Boolean.Parse(ConfigurationManager.AppSettings("TechSec602.EnableLogging") ?: "false"),
.CacheResults = Boolean.Parse(ConfigurationManager.AppSettings("TechSec602.CacheResults") ?: "true"),
.CacheTimeoutMinutes = Integer.Parse(ConfigurationManager.AppSettings("TechSec602.CacheTimeoutMinutes") ?: "5")
}
End Function
End Class
'''
''' Result of verification request
'''
Public Class VerificationResult
Public Property IsAllowed As Boolean
Public Property Reason As String
Public Property ProcessingTimeMs As Double?
Public Property Success As Boolean
End Class
'''
''' API response model
'''
Friend Class ApiVerificationResponse
Public Property IsAllowed As Boolean
Public Property Reason As String
Public Property ProcessingTimeMs As Double
End Class