using Microsoft.AspNetCore.Mvc; using Microsoft.Data.SqlClient; using System.Text.RegularExpressions; namespace Library; public abstract class AbstractController : Controller { private const string SESSION_COOKIE_NAME = "X-VTU"; private readonly ILogger m_Logger; private readonly IConfiguration m_Configuration; private readonly string m_DataDirectory = string.Empty; protected AbstractController( ILogger logger , IConfiguration configuration ) { m_Logger = logger; m_Configuration = configuration; m_DataDirectory = configuration.GetValue( "DataDirectory" ) ?? string.Empty; } protected string GetDataDirectory( ) { return m_DataDirectory; } protected void Trace( string function ) { #pragma warning disable CA2254 // Template should be a static expression m_Logger.Log( LogLevel.Trace , function + " called" ); #pragma warning restore CA2254 // Template should be a static expression } private SqlConnection? m_DBConnection = null; protected SqlConnection GetDBConnection( ) { if ( m_DBConnection == null ) { try { m_DBConnection = new SqlConnection( m_Configuration.GetValue( "ConnectionString" ) ); m_DBConnection.Open( ); HttpContext.Response.RegisterForDispose( m_DBConnection ); } catch ( SqlException ) { if ( m_DBConnection != null ) { m_DBConnection.Dispose( ); m_DBConnection = null; } throw; } } return m_DBConnection; } protected void SessionStart( string session_id ) { CookieOptions cookieOptions = new( ) { Secure = false, // only when HTTPS HttpOnly = true, IsEssential = true, }; Response.Cookies.Append( SESSION_COOKIE_NAME , session_id , cookieOptions ); } protected void SessionCancel( ) { Response.Cookies.Delete( SESSION_COOKIE_NAME ); } protected string? GetSessionKey( ) { if ( !Request.Cookies.TryGetValue( SESSION_COOKIE_NAME , out string? session_id ) || string.IsNullOrEmpty( session_id ) ) return null; return session_id; } private UserData? m_CurrentUser = null; private bool m_bUserValidated = false; protected UserData? GetUserData( ) { if ( m_bUserValidated ) return m_CurrentUser; m_bUserValidated = true; if ( m_CurrentUser != null ) return m_CurrentUser; string? session_id = GetSessionKey( ); if ( session_id == null ) return null; m_CurrentUser = UserData.FromSession( GetDBConnection( ) , session_id! ); if ( m_CurrentUser == null ) return null; HttpContext.SetUserID( m_CurrentUser!.ID ); HttpContext.Items.Add( "CONTEXT_IS_ADMIN" , m_CurrentUser?.IsAdmin ?? false ); return m_CurrentUser; } protected SQLBuilder PrepareSQL( string query , string? order_by = null ) { return new SQLBuilder( GetDBConnection( ) , query , order_by ); } protected void AssertLogin( string? id ) { string? session_id = GetSessionKey( ); if ( session_id != null ) { string? sql = @"select rec.idgnm, gnm.idlis1, lis.ime, c.* from gnm_rec rec left join gnm on gnm.id = rec.idgnm left join lis on lis.id = gnm.idlis1 left join tbl_cross c on c.id1 = (select top 1 iddom from livelog where id_session = @session_id) and c.id2 = gnm.idlis1 where rec.uuid = @id and c.id is not null"; SqlDataReader reader_x = PrepareSQL( sql ) .AddParameter( "@id" , id ) .AddParameter( "@session_id" , session_id ) .ExecuteReader( ); bool res_x = reader_x.Read( ); reader_x.Close( ); if ( res_x == false ) OnInvalidLogin( ); } else { if ( id == null ) { if ( GetUserData( ) == null ) OnInvalidLogin( ); } else { if ( GetUserData( ) != null ) return; SqlDataReader reader = PrepareSQL( @"SELECT gnm.access FROM gnm_rec left join gnm on gnm.id = gnm_rec.idgnm WHERE gnm.access is not null and gnm_rec.uuid = @uuid and gnm_rec.data_format = 'pdf'" ) .AddParameter( "@uuid" , id ) .ExecuteReader( ); bool res = reader.Read( ); reader.Close( ); if ( res == true ) OnInvalidLogin( ); } } } protected void AssertAdmin( ) { if ( GetUserData( ) == null || GetUserData( )!.IsAdmin == false ) OnInvalidLogin( ); } protected abstract void OnInvalidLogin( ); protected abstract void OnInvalidAdminLogin( ); protected bool ValidateString( string? parameter , int min_length ) { int length = parameter?.Length ?? 0; return length >= min_length; } private const string EMAIL_REGEX = @"^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"; protected bool ValidateEmail( string? email , bool required ) { return ValidateRegex( EMAIL_REGEX , email , required ); } private const string URL_REGEX = @"(?i)(http(s)?:\/\/)?(\w{2,25}\.)+\w{3}([a-z0-9\-?=$-_.+!*()]+)(?i)"; protected bool ValidateURL( string? email , bool required ) { return ValidateRegex( URL_REGEX , email , required ); } protected bool ValidateRegex( string regex , string? value , bool is_required ) { if ( value == null ) return is_required == false; try { return Regex.IsMatch( value! , regex , RegexOptions.IgnoreCase , TimeSpan.FromMilliseconds( 250 ) ); } catch ( RegexMatchTimeoutException ) { return false; } } }