213 lines
8.0 KiB
C#
213 lines
8.0 KiB
C#
using Microsoft.Data.Sqlite;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace SimPas2_Windows.Managers
|
|
{
|
|
internal class CreditcardManager
|
|
{
|
|
private readonly string mConnectionString;
|
|
private readonly byte[] mEncryptionKey;
|
|
private readonly string mCulture;
|
|
|
|
private string mJpLang;
|
|
|
|
public CreditcardManager(string databasePath, byte[] encryptionKey, string culture)
|
|
{
|
|
mConnectionString = $"Data Source={databasePath}";
|
|
mEncryptionKey = encryptionKey ?? throw new ArgumentNullException(nameof(encryptionKey));
|
|
mCulture = culture;
|
|
|
|
mJpLang = "ja-JP";
|
|
}
|
|
|
|
private bool AlreadyExists(string cardnumber, int? excludeId = null)
|
|
{
|
|
using (SqliteConnection conn = new SqliteConnection(mConnectionString))
|
|
{
|
|
conn.Open();
|
|
SqliteCommand com = conn.CreateCommand();
|
|
com.CommandText = @"
|
|
SELECT COUNT(*) FROM Cc
|
|
WHERE UPPER(Cardnumber) = UPPER(@cardnumber)";
|
|
com.Parameters.AddWithValue("@cardnumber", cardnumber);
|
|
|
|
if (excludeId.HasValue)
|
|
{
|
|
com.CommandText += " AND Id != @excludeId";
|
|
com.Parameters.AddWithValue("@excludeId", excludeId.Value);
|
|
}
|
|
|
|
return Convert.ToInt32(com.ExecuteScalar()) > 0;
|
|
}
|
|
}
|
|
|
|
public void AddCc(string brand, string cardnumber, string expiration, string cvc, string holdername, string note)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(brand) || string.IsNullOrWhiteSpace(cardnumber) || string.IsNullOrWhiteSpace(expiration) || string.IsNullOrWhiteSpace(cvc) || string.IsNullOrWhiteSpace(holdername))
|
|
{
|
|
string err = mCulture == mJpLang
|
|
? "ブランド、カード番号、氏名、有効期限及び、CVCを御入力下さい。"
|
|
: "Please fill in the brand, card number, full name, expiration, and CVC.";
|
|
throw new ArgumentException(err);
|
|
}
|
|
|
|
string encryptedCvc = EncryptCvc(cvc);
|
|
|
|
if (AlreadyExists(cardnumber))
|
|
{
|
|
string err = mCulture == mJpLang
|
|
? $"カード「{brand}/{holdername} ({expiration})」は既に存在します。"
|
|
: $"The card '{brand}/{holdername} ({expiration})' already exists.";
|
|
throw new ArgumentException(err);
|
|
}
|
|
|
|
using (SqliteConnection conn = new SqliteConnection(mConnectionString))
|
|
{
|
|
conn.Open();
|
|
SqliteCommand com = conn.CreateCommand();
|
|
com.CommandText = @"
|
|
INSERT INTO Cc (Brand, Cardnumber, Expiration, Cvc, Holdername, Note)
|
|
VALUES ($brand, $cardnumber, $expiration, $cvc, $holdername, $note)";
|
|
com.Parameters.AddWithValue("$brand", brand);
|
|
com.Parameters.AddWithValue("$cardnumber", cardnumber);
|
|
com.Parameters.AddWithValue("$expiration", expiration);
|
|
com.Parameters.AddWithValue("$cvc", encryptedCvc);
|
|
com.Parameters.AddWithValue("$holdername", holdername);
|
|
com.Parameters.AddWithValue("$note", string.IsNullOrEmpty(note) ? DBNull.Value : note);
|
|
com.ExecuteNonQuery();
|
|
}
|
|
}
|
|
|
|
public bool EditCc(int id, string brand, string cardnumber, string expiration, string cvc, string holdername, string note)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(brand) || string.IsNullOrWhiteSpace(cardnumber) || string.IsNullOrWhiteSpace(expiration) || string.IsNullOrWhiteSpace(cvc) || string.IsNullOrWhiteSpace(holdername))
|
|
{
|
|
string err = mCulture == mJpLang
|
|
? "ブランド、カード番号、氏名、有効期限及び、CVCを御入力下さい。"
|
|
: "Please fill in the brand, card number, full name, expiration, and CVC.";
|
|
throw new ArgumentException(err);
|
|
}
|
|
|
|
string encryptedCvc = EncryptCvc(cvc);
|
|
|
|
using (SqliteConnection conn = new SqliteConnection(mConnectionString))
|
|
{
|
|
conn.Open();
|
|
SqliteCommand com = conn.CreateCommand();
|
|
com.CommandText = @"
|
|
UPDATE Cc
|
|
SET Brand = $brand, Cardnumber = $cardnumber, Expiration = $expiration, Cvc = $cvc, Holdername = $holdername, Note = $note
|
|
WHERE Id = $id";
|
|
com.Parameters.AddWithValue("$id", id);
|
|
com.Parameters.AddWithValue("$brand", brand);
|
|
com.Parameters.AddWithValue("$cardnumber", cardnumber);
|
|
com.Parameters.AddWithValue("$expiration", expiration);
|
|
com.Parameters.AddWithValue("$cvc", encryptedCvc);
|
|
com.Parameters.AddWithValue("$holdername", holdername);
|
|
com.Parameters.AddWithValue("$note", string.IsNullOrEmpty(note) ? DBNull.Value : note);
|
|
return com.ExecuteNonQuery() > 0;
|
|
}
|
|
}
|
|
|
|
public bool DeleteCc(int id)
|
|
{
|
|
using (SqliteConnection conn = new SqliteConnection(mConnectionString))
|
|
{
|
|
conn.Open();
|
|
SqliteCommand com = conn.CreateCommand();
|
|
com.CommandText = "DELETE FROM Cc WHERE Id = $id";
|
|
com.Parameters.AddWithValue("$id", id);
|
|
return com.ExecuteNonQuery() > 0;
|
|
}
|
|
}
|
|
|
|
public List<(int Id, string Brand, string Cardnumber, string Expiration, string Cvc, string Holdername, string Note)> GetAll(string keyword = "")
|
|
{
|
|
var ccs = new List<(int, string, string, string, string, string, string)>();
|
|
using (SqliteConnection conn = new SqliteConnection(mConnectionString))
|
|
{
|
|
conn.Open();
|
|
SqliteCommand com = conn.CreateCommand();
|
|
if (string.IsNullOrWhiteSpace(keyword))
|
|
{
|
|
com.CommandText = @"
|
|
SELECT Id, Brand, Cardnumber, Expiration, Cvc, Holdername, Note FROM Cc
|
|
ORDER BY Brand ASC";
|
|
}
|
|
else
|
|
{
|
|
com.CommandText = @"
|
|
SELECT Id, Brand, Cardnumber, Expiration, Cvc, Holdername, Note FROM Cc
|
|
WHERE Brand LIKE @keyword OR Holdername LIKE @keyword OR Cardnumber LIKE @keyword
|
|
ORDER BY Brand ASC";
|
|
com.Parameters.AddWithValue("@keyword", $"%{keyword}%");
|
|
}
|
|
|
|
using (SqliteDataReader reader = com.ExecuteReader())
|
|
{
|
|
while (reader.Read())
|
|
{
|
|
string encryptedCvc = reader.GetString(4);
|
|
string decryptedCvc = DecryptCvc(encryptedCvc);
|
|
ccs.Add((
|
|
reader.GetInt32(0),
|
|
reader.GetString(1),
|
|
reader.GetString(2),
|
|
reader.GetString(3),
|
|
decryptedCvc,
|
|
reader.GetString(5),
|
|
reader.IsDBNull(6) ? string.Empty : reader.GetString(6)
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
return ccs;
|
|
}
|
|
|
|
private string EncryptCvc(string answer)
|
|
{
|
|
using (Aes aes = Aes.Create())
|
|
{
|
|
aes.Key = mEncryptionKey;
|
|
aes.GenerateIV();
|
|
byte[] iv = aes.IV;
|
|
|
|
using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, iv))
|
|
{
|
|
byte[] plainBytes = Encoding.UTF8.GetBytes(answer);
|
|
byte[] encryptedBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
|
|
byte[] result = new byte[iv.Length + encryptedBytes.Length];
|
|
|
|
Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
|
|
Buffer.BlockCopy(encryptedBytes, 0, result, iv.Length, encryptedBytes.Length);
|
|
|
|
return Convert.ToBase64String(result);
|
|
}
|
|
}
|
|
}
|
|
|
|
private string DecryptCvc(string encryptedAnswer)
|
|
{
|
|
byte[] combined = Convert.FromBase64String(encryptedAnswer);
|
|
byte[] iv = new byte[16];
|
|
byte[] encryptedBytes = new byte[combined.Length - iv.Length];
|
|
Buffer.BlockCopy(combined, 0, iv, 0, iv.Length);
|
|
Buffer.BlockCopy(combined, iv.Length, encryptedBytes, 0, encryptedBytes.Length);
|
|
|
|
using (Aes aes = Aes.Create())
|
|
{
|
|
aes.Key = mEncryptionKey;
|
|
aes.IV = iv;
|
|
|
|
using (ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
|
|
{
|
|
byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
|
|
return Encoding.UTF8.GetString(decryptedBytes);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|