리크 테스트 gui
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

296 lines
10 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Housing.Services
{
// 1. DatabaseSettings
public class DatabaseSettings
{
public string ConnectionString { get; set; } = string.Empty;
public static DatabaseSettings Load(string path)
{
var settings = new DatabaseSettings();
try
{
if (File.Exists(path))
{
var lines = File.ReadAllLines(path);
foreach (var line in lines)
{
var trimmed = line.Trim();
if (trimmed.StartsWith("ConnectionString", StringComparison.OrdinalIgnoreCase))
{
var parts = trimmed.Split(new[] { '=' }, 2);
if (parts.Length == 2)
{
settings.ConnectionString = parts[1].Trim();
}
}
}
}
}
catch
{
// 로드 실패 시 무시
}
return settings;
}
}
// 2. LoginSettings
public class LoginSettings
{
public bool OfflinePreview { get; set; } = true; // 기본값은 오프라인 테스트 편의를 위해 true
public static LoginSettings Load(string path)
{
var settings = new LoginSettings();
try
{
if (File.Exists(path))
{
var lines = File.ReadAllLines(path);
foreach (var line in lines)
{
var trimmed = line.Trim();
if (trimmed.StartsWith("OfflinePreview", StringComparison.OrdinalIgnoreCase))
{
var parts = trimmed.Split(new[] { '=' }, 2);
if (parts.Length == 2)
{
if (bool.TryParse(parts[1].Trim(), out var val))
{
settings.OfflinePreview = val;
}
else if (int.TryParse(parts[1].Trim(), out var intVal))
{
settings.OfflinePreview = intVal != 0;
}
}
}
}
}
}
catch
{
// 로드 실패 시 무시
}
return settings;
}
}
// 3. LoginHistoryStore
public class LoginHistoryStore
{
private readonly string _filePath;
private readonly Dictionary<string, List<string>> _history = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
private LoginHistoryStore(string filePath)
{
_filePath = filePath;
}
public static LoginHistoryStore Load(string path)
{
var store = new LoginHistoryStore(path);
store.LoadFromFile();
return store;
}
public List<string> GetValues(string fieldName)
{
if (_history.TryGetValue(fieldName, out var list))
{
return new List<string>(list);
}
return new List<string>();
}
public void Remember(string fieldName, string value)
{
if (string.IsNullOrWhiteSpace(value)) return;
value = value.Trim();
if (!_history.TryGetValue(fieldName, out var list))
{
list = new List<string>();
_history[fieldName] = list;
}
// 중복 제거 및 맨 앞으로 이동
list.RemoveAll(x => string.Equals(x, value, StringComparison.OrdinalIgnoreCase));
list.Insert(0, value);
// 최대 5개 이력 유지
if (list.Count > 5)
{
list.RemoveRange(5, list.Count - 5);
}
}
public bool Forget(string fieldName, string value)
{
if (string.IsNullOrWhiteSpace(value)) return false;
value = value.Trim();
if (_history.TryGetValue(fieldName, out var list))
{
bool removed = list.RemoveAll(x => string.Equals(x, value, StringComparison.OrdinalIgnoreCase)) > 0;
return removed;
}
return false;
}
public void Save()
{
try
{
var dir = Path.GetDirectoryName(_filePath);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
// 초간단 JSON 형식으로 직렬화 (의존성 최소화)
using (var sw = new StreamWriter(_filePath))
{
sw.WriteLine("{");
var keys = new List<string>(_history.Keys);
for (int i = 0; i < keys.Count; i++)
{
var key = keys[i];
var values = _history[key];
var arrayItems = new List<string>();
foreach (var val in values)
{
// 따옴표 escape
var escaped = val.Replace("\"", "\\\"");
arrayItems.Add($"\"{escaped}\"");
}
var line = $" \"{key}\": [{string.Join(", ", arrayItems)}]";
if (i < keys.Count - 1)
{
line += ",";
}
sw.WriteLine(line);
}
sw.WriteLine("}");
}
}
catch
{
// 저장 오류 시 무시
}
}
private void LoadFromFile()
{
try
{
if (!File.Exists(_filePath)) return;
var text = File.ReadAllText(_filePath);
// 정규식이나 아주 심플한 파싱으로 키와 배열 파싱
// 형식 예: "Maker": ["MOBI", "TEST"]
var matches = Regex.Matches(text, @"""([^""]+)""\s*:\s*\[([^\]]*)\]");
foreach (Match match in matches)
{
var key = match.Groups[1].Value;
var arrayContent = match.Groups[2].Value;
var valueMatches = Regex.Matches(arrayContent, @"""([^""]*)""");
var list = new List<string>();
foreach (Match valMatch in valueMatches)
{
list.Add(valMatch.Groups[1].Value);
}
_history[key] = list;
}
}
catch
{
// 로드 오류 시 무시
}
}
}
// 4. LoginAccountRepository
public class LoginAccountRepository
{
private readonly DatabaseSettings _dbSettings;
private readonly LoginSettings _loginSettings;
public LoginAccountRepository(DatabaseSettings dbSettings, LoginSettings loginSettings)
{
_dbSettings = dbSettings;
_loginSettings = loginSettings;
}
public async Task<bool> ExistsAsync(string operatorId, string password)
{
// 오프라인 모드인 경우 기본 성공
if (_loginSettings.OfflinePreview)
{
return true;
}
// DB 커넥션 스트링이 비어있으면 기본값 확인
if (string.IsNullOrWhiteSpace(_dbSettings.ConnectionString))
{
return IsDefaultAccount(operatorId, password);
}
try
{
// 실제 DB에서 계정을 조회해보기 위한 시도
using (var conn = new System.Data.SqlClient.SqlConnection(_dbSettings.ConnectionString))
{
await conn.OpenAsync();
// 우선 Users 또는 Accounts와 같이 로그인 테이블명이 뭔지 모를 수 있으므로
// 쿼리 실패 시 default 계정 검증으로 fallback 하도록 구성
const string query = "SELECT COUNT(*) FROM [Users] WHERE [OperatorId] = @Id AND [Password] = @Pw";
using (var cmd = new System.Data.SqlClient.SqlCommand(query, conn))
{
cmd.Parameters.AddWithValue("@Id", operatorId);
cmd.Parameters.AddWithValue("@Pw", password);
var count = (int)await cmd.ExecuteScalarAsync();
return count > 0;
}
}
}
catch
{
// DB 연결이나 쿼리 오류 발생 시, 테스트 편의를 위해 test/test 혹은 admin/admin 등 디폴트 계정을 제공
return IsDefaultAccount(operatorId, password);
}
}
private bool IsDefaultAccount(string operatorId, string password)
{
// 기본 개발/테스트용 계정 처리
if (string.Equals(operatorId, "test", StringComparison.OrdinalIgnoreCase) &&
string.Equals(password, "test", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (string.Equals(operatorId, "admin", StringComparison.OrdinalIgnoreCase) &&
string.Equals(password, "admin", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (string.Equals(operatorId, "su", StringComparison.OrdinalIgnoreCase) &&
string.Equals(password, "su", StringComparison.OrdinalIgnoreCase))
{
return true;
}
return false;
}
}
}