From a3beff62a07def68f47f314a3e530e3a5eac4281 Mon Sep 17 00:00:00 2001 From: Chenx221 Date: Wed, 23 Aug 2023 13:33:38 +0800 Subject: [PATCH] =?UTF-8?q?Now=20supports=20reading=20secretKey=20from=20t?= =?UTF-8?q?he=20database=20to=20calculate=20totp=E3=80=82=20But=20there=20?= =?UTF-8?q?are=20some=20known=20bugs=20that=20need=20to=20be=20resolved.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OTP/Form1.Designer.cs | 4 ++ OTP/Form1.cs | 135 +++++++++++++++++++++++++++++++++--- OTP/Form2.Designer.cs | 5 ++ OTP/Form2.cs | 154 +++++++++++++++++++++++++++++++++++++++++- OTP/OTP.csproj | 5 +- OTP/empty_key.db | Bin 0 -> 8192 bytes 6 files changed, 290 insertions(+), 13 deletions(-) create mode 100644 OTP/empty_key.db diff --git a/OTP/Form1.Designer.cs b/OTP/Form1.Designer.cs index 39e0eab..14bb647 100644 --- a/OTP/Form1.Designer.cs +++ b/OTP/Form1.Designer.cs @@ -46,6 +46,7 @@ this.listBox1.Name = "listBox1"; this.listBox1.Size = new System.Drawing.Size(473, 368); this.listBox1.TabIndex = 0; + this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged); // // label1 // @@ -61,6 +62,7 @@ // // button1 // + this.button1.Enabled = false; this.button1.Location = new System.Drawing.Point(556, 294); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(85, 23); @@ -171,6 +173,8 @@ this.Name = "Form1"; this.Text = "Main Window"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); + this.Load += new System.EventHandler(this.Form1_Load); + this.VisibleChanged += new System.EventHandler(this.Form1_VisibleChanged); this.ResumeLayout(false); this.PerformLayout(); diff --git a/OTP/Form1.cs b/OTP/Form1.cs index eacded1..d8864e3 100644 --- a/OTP/Form1.cs +++ b/OTP/Form1.cs @@ -8,6 +8,10 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using OtpNet; +using System.IO; +using System.Data.SQLite; +using System.Reflection; +using ZXing.QrCode.Internal; namespace OTP { @@ -16,18 +20,28 @@ namespace OTP private byte[] secretKey; private Totp totp; private Timer timer; + private string connectionString = "Data Source=key.db;Version=3;"; + private string embeddedDatabaseResource = "OTP.empty_key.db"; + private int runonce=0; public Form1() { InitializeComponent(); - - secretKey = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP"); // 示例的 base32 编码 - totp = new Totp(secretKey); + //button1.Enabled = false; + //secretKey = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP"); // 示例的 base32 编码 + //totp = new Totp(secretKey); timer = new Timer(); timer.Interval = 1000; // 设置计时器间隔为 1 秒 timer.Tick += Timer_Tick; } + public class TitleInfo + { + public int Id { get; set; } + public string Title { get; set; } + public string SecretKey { get; set; } + } + private void Timer_Tick(object sender, EventArgs e) { @@ -55,16 +69,105 @@ namespace OTP { button1.Enabled = false; // 禁用生成按钮 button2.Enabled = true; // 启用复制按钮 - GenerateAndDisplayTotp(); // 生成并显示 TOTP 密码 - - // 开始计时器 - timer.Start(); + if (totp != null) + { + GenerateAndDisplayTotp(); // 生成并显示 TOTP 密码 + timer.Start();// 开始计时器 + } } private void Form1_Load(object sender, EventArgs e) { - button1.Enabled = true; // 在窗体加载时启用按钮 + //button1.Enabled = true; // 在窗体加载时启用按钮 + // 判断是否存在 key.db 数据库文件 + if (!File.Exists("key.db")) + { + ExtractEmbeddedDatabase(); + } + + } + private void ExtractEmbeddedDatabase() + { + // 从嵌入的资源中复制数据库文件到同目录下 + try + { + using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedDatabaseResource)) + { + using (FileStream fileStream = new FileStream("key.db", FileMode.Create)) + { + resourceStream.CopyTo(fileStream); + } + } + } + catch (Exception ex) + { + MessageBox.Show($"An error occurred while extracting embedded database: {ex.Message}"); + } + } + + private void LoadTitlesToListBox() + { + try + { + using (SQLiteConnection connection = new SQLiteConnection(connectionString)) + { + connection.Open(); + + using (SQLiteCommand command = new SQLiteCommand("SELECT Id, Title, SecretKey FROM TotpData", connection)) + { + using (SQLiteDataReader reader = command.ExecuteReader()) + { + listBox1.Items.Clear(); // 清空现有数据 + while (reader.Read()) + { + int id = reader.GetInt32(0); + string title = reader.GetString(1); + string secretKey = reader.GetString(2); + + TitleInfo titleInfo = new TitleInfo + { + Id = id, + Title = title, + SecretKey = secretKey + }; + + listBox1.Items.Add(titleInfo); + } + } + } + } + } + catch (Exception ex) + { + MessageBox.Show($"An error occurred while loading titles: {ex.Message}"); + } + } + + private void listBox1_SelectedIndexChanged(object sender, EventArgs e) + { + if (listBox1.SelectedIndex >= 0) // Ensure an item is selected + { + TitleInfo selectedTitleInfo = listBox1.SelectedItem as TitleInfo; + if (selectedTitleInfo != null) + { + if (runonce == 0) + { + button1.Enabled = true; + runonce++; + } + secretKey = Base32Encoding.ToBytes(selectedTitleInfo.SecretKey); + totp = new Totp(secretKey); + //string totpCode = totp.ComputeTotp(); + //label1.Text = totpCode; + } + else + { + MessageBox.Show("Selected item is not of the expected type."); + } + } + } + private void button2_Click(object sender, EventArgs e) { @@ -95,5 +198,21 @@ namespace OTP // 如果用户选择 Yes,什么都不需要做,窗体会继续关闭 } + private void Form1_VisibleChanged(object sender, EventArgs e) + { + if (this.Visible) // 检查窗体是否可见 + { + LoadTitlesToListBox(); + runonce = 0; + label1.Text = "TOTP Code"; + button1.Enabled = false; + button2.Enabled = false; + } + else + { + timer.Stop(); + } + } + } } diff --git a/OTP/Form2.Designer.cs b/OTP/Form2.Designer.cs index 0d664ac..615c1f1 100644 --- a/OTP/Form2.Designer.cs +++ b/OTP/Form2.Designer.cs @@ -81,6 +81,7 @@ this.button2.TabIndex = 2; this.button2.Text = "Delete Record(s)"; this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); // // button3 // @@ -90,6 +91,7 @@ this.button3.TabIndex = 3; this.button3.Text = "Save Changes"; this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); // // button4 // @@ -99,17 +101,20 @@ this.button4.TabIndex = 4; this.button4.Text = "Discard Changes"; this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); // // Form2 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(619, 367); + this.ControlBox = false; this.Controls.Add(this.button4); this.Controls.Add(this.button3); this.Controls.Add(this.button2); this.Controls.Add(this.button1); this.Controls.Add(this.panel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Name = "Form2"; this.Text = "Data Manage"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form2_FormClosing); diff --git a/OTP/Form2.cs b/OTP/Form2.cs index 906afc9..ae275fb 100644 --- a/OTP/Form2.cs +++ b/OTP/Form2.cs @@ -8,19 +8,82 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using System.IO; +using System.Security.Cryptography; namespace OTP { public partial class Form2 : Form { private string connectionString = "Data Source=key.db;Version=3;"; + private string backupPath = "key.db.bak"; // 备份数据库文件的路径 + private string sourceFileHash = ""; // 原始数据库文件的哈希值 public Form2() { InitializeComponent(); InitializeDataGridView(); + // 获取原始数据库文件的哈希值 + sourceFileHash = CalculateSHA256Hash("key.db"); + // 备份数据库文件并判断完整性 + bool backupSuccessful = BackupDatabase(); + + if (!backupSuccessful) + { + // 备份创建失败,禁用按钮并提示用户 + button1.Enabled = false; + button2.Enabled = false; + button3.Enabled = false; + + MessageBox.Show("Backup of data failed, modification is prohibited.", "Backup Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } LoadData(); } + private bool BackupDatabase() + { + try + { + if (File.Exists("key.db")) + { + // 备份数据库文件 + File.Copy("key.db", backupPath, true); + + // 计算备份文件的哈希值 + string backupFileHash = CalculateSHA256Hash(backupPath); + + // 比较原始文件和备份文件的哈希值 + if (sourceFileHash == backupFileHash) + { + return true; // 备份创建成功且完整性通过 + } + else + { + return false; // 备份创建成功但完整性未通过 + } + } + else + { + return false; // 原始文件不存在,备份创建失败 + } + } + catch (Exception) + { + return false; // 备份创建失败 + } + } + // 计算文件的SHA-256哈希值 + private string CalculateSHA256Hash(string filePath) + { + using (SHA256 sha256 = SHA256.Create()) + { + using (FileStream stream = File.OpenRead(filePath)) + { + byte[] hashBytes = sha256.ComputeHash(stream); + return BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); + } + } + } + private void InitializeDataGridView() { @@ -34,19 +97,23 @@ namespace OTP { connection.Open(); - using (SQLiteCommand command = new SQLiteCommand("SELECT Title FROM TotpData", connection)) + using (SQLiteCommand command = new SQLiteCommand("SELECT Id, Title FROM TotpData", connection)) { using (SQLiteDataReader reader = command.ExecuteReader()) { while (reader.Read()) { - dataGridView1.Rows.Add(reader.GetString(0)); + int id = reader.GetInt32(0); + string title = reader.GetString(1); + dataGridView1.Rows.Add(title); + dataGridView1.Rows[dataGridView1.Rows.Count - 1].Tag = id; // 将 Id 存储在行的 Tag 属性中 } } } } } + private void button1_Click(object sender, EventArgs e) { using (Form3 form3 = new Form3()) @@ -70,6 +137,89 @@ namespace OTP } } + private void button2_Click(object sender, EventArgs e) + { + try + { + // 获取选中的行 + foreach (DataGridViewRow selectedRow in dataGridView1.SelectedRows) + { + // 获取选中行的数据 + int id = (int)selectedRow.Tag; // 从行的 Tag 属性获取 Id 值 + + // 执行删除数据库记录的操作 + DeleteRecordFromDatabase(id); + + // 从 DataGridView 中移除选中行 + dataGridView1.Rows.Remove(selectedRow); + } + } + catch (Exception ex) + { + MessageBox.Show($"An error occurred while deleting the record: {ex.Message}"); + } + } + + private void DeleteRecordFromDatabase(int recordId) + { + try + { + using (SQLiteConnection connection = new SQLiteConnection(connectionString)) + { + connection.Open(); + + using (SQLiteCommand command = new SQLiteCommand("DELETE FROM TotpData WHERE ID = @ID", connection)) + { + command.Parameters.AddWithValue("@ID", recordId); + command.ExecuteNonQuery(); + } + } + } + catch (Exception ex) + { + MessageBox.Show($"An error occurred while deleting the record: {ex.Message}"); + } + } + + private void button3_Click(object sender, EventArgs e) + { + // 删除备份文件 + if (File.Exists(backupPath)) + { + File.Delete(backupPath); + } + + // 关闭当前的 Form2 实例,返回到 Form1 + this.Close(); + } + + private void button4_Click(object sender, EventArgs e) + { + try + { + // 恢复备份文件 + if (File.Exists(backupPath)) + { + File.Copy(backupPath, "key.db", true); + + // 删除备份文件 + File.Delete(backupPath); + + MessageBox.Show("The operation was successful.", "Undo Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + else + { + MessageBox.Show("No backup file found to undo changes.", "Undo Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + catch (Exception ex) + { + MessageBox.Show($"An error occurred while undoing changes: {ex.Message}", "Undo Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + // 关闭当前的 Form2 实例,返回到 Form1,不进行保存操作 + this.Close(); + } } } diff --git a/OTP/OTP.csproj b/OTP/OTP.csproj index ffdbe92..584983f 100644 --- a/OTP/OTP.csproj +++ b/OTP/OTP.csproj @@ -156,9 +156,8 @@ True Resources.resx - - Always - + + SettingsSingleFileGenerator diff --git a/OTP/empty_key.db b/OTP/empty_key.db new file mode 100644 index 0000000000000000000000000000000000000000..acb0eed3b8f3363262b1c55210bcc8cc90d97f72 GIT binary patch literal 8192 zcmeI#y$ZrG5C`x?1!9u;1!)@uB5H|gf2)x}%~sY$av*H2`qB&o0$OA^_! zpnBkYBH9TrnkYGxNz?V}U`|?iO0E=5rZ$&x{JvP|?M<7JzJIx#CDAxc)-;mqy8E#a i_zgFk+o2x;0SG_<0uX=z1Rwwb2tWV=5P-lR3%me3H7~dT literal 0 HcmV?d00001