Files
raven/server/AyaNova/PickList/PickListFetcher.cs
John Cardinal b1944b7ca3 case 4716 - pick-list search text passed as SQL parameters
PickListSqlBuilder put the search text and the tag search text into the SQL
inside quotes with no escaping, reachable by any login (security review F18);
an apostrophe in a search also made the query fail. The builder now writes
@plq / @pltag and PickListFetcher adds them as Npgsql parameters (same %text%
match; wildcards typed by the user still apply).

Changelog: searching selection lists for text with an apostrophe now works.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 12:28:43 -07:00

106 lines
4.3 KiB
C#

using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using AyaNova.Models;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace AyaNova.PickList
{
internal static class PickListFetcher
{
internal static async Task<List<NameIdActiveItem>> GetResponseAsync(IAyaPickList PickList, string autoCompleteQuery,
string tagSpecificQuery, bool includeInactive, long[] preIds, string variant, AyContext ct, ILogger log, string overrideTemplate)
{
//Sort out effective Template
string Template = null;
if (string.IsNullOrWhiteSpace(overrideTemplate))
{
//Attempt to fetch custom template
var t = await ct.PickListTemplate.FirstOrDefaultAsync(z => z.Id == ((long)PickList.DefaultListAType));
if (t == null)
{
Template = PickList.DefaultTemplate;
}
else
{
Template = t.Template;
}
}
else
{
Template = overrideTemplate;
}
//parse the template
var jTemplate = JArray.Parse(Template);
//Get the field key names in a list from the template
List<string> TemplateColumnNames = PickList.GetFieldListFromTemplate(jTemplate);
//BUILD THE QUERY
var q = PickListSqlBuilder.Build(PickList, TemplateColumnNames, autoCompleteQuery, tagSpecificQuery, includeInactive, preIds, variant);
//If want to log all queries
//log.LogInformation(q);
//RETURN OBJECTS
var ret = new List<NameIdActiveItem>();
//QUERY THE DB
using (var command = ct.Database.GetDbConnection().CreateCommand())
{
await ct.Database.OpenConnectionAsync();
//GET DATA RETURN ROWS
command.CommandText = q;
//case 4716: search texts go in as parameters (same %text% match as before, wildcards typed by the user still apply)
if (q.Contains("@plq"))
command.Parameters.Add(new Npgsql.NpgsqlParameter("plq", $"%{autoCompleteQuery}%"));
if (q.Contains("@pltag"))
command.Parameters.Add(new Npgsql.NpgsqlParameter("pltag", $"%{tagSpecificQuery}%"));
try
{
using (var dr = await command.ExecuteReaderAsync())
{
while (dr.Read())
{
//query is always in the same order:
//plId, plActive, plName
ret.Add(new NameIdActiveItem
{
Id = dr.GetInt64(0),
Active = dr.GetBoolean(1),
Name = dr.GetString(2)
});
}
}
}
catch (Npgsql.PostgresException e)
{
//log out the exception and the query
//This may be called internally in *Biz classes who don't have a log of their own
if (log == null)
log = AyaNova.Util.ApplicationLogging.CreateLogger("PickListFetcher");
log.LogError("PickList query failed unexpectedly. Query was:");
log.LogError(q);
log.LogError(e, "DB Exception");
throw new System.Exception("PickListFetcher - Query failed see log");
}
catch (System.Exception e)
{
//ensure any other type of exception gets surfaced properly
//log out the exception and the query
log.LogError("PickListFetcher unexpected failure. Query was:");
log.LogError(q);
log.LogError(e, "Exception");
throw new System.Exception("PickListFetcher - unexpected failure see log");
}
}
return ret;
}
}//eoc
}//eons