Now supports reading secretKey from the database to calculate totp。
But there are some known bugs that need to be resolved.
This commit is contained in:
parent
a3b6fde6a6
commit
a3beff62a0
4
OTP/Form1.Designer.cs
generated
4
OTP/Form1.Designer.cs
generated
@ -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();
|
||||
|
||||
|
135
OTP/Form1.cs
135
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
5
OTP/Form2.Designer.cs
generated
5
OTP/Form2.Designer.cs
generated
@ -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);
|
||||
|
154
OTP/Form2.cs
154
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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -156,9 +156,8 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<None Include="key.db">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<EmbeddedResource Include="empty_key.db" />
|
||||
<None Include="key.db" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
|
BIN
OTP/empty_key.db
Normal file
BIN
OTP/empty_key.db
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user