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.Name = "listBox1";
|
||||||
this.listBox1.Size = new System.Drawing.Size(473, 368);
|
this.listBox1.Size = new System.Drawing.Size(473, 368);
|
||||||
this.listBox1.TabIndex = 0;
|
this.listBox1.TabIndex = 0;
|
||||||
|
this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
|
||||||
//
|
//
|
||||||
// label1
|
// label1
|
||||||
//
|
//
|
||||||
@ -61,6 +62,7 @@
|
|||||||
//
|
//
|
||||||
// button1
|
// button1
|
||||||
//
|
//
|
||||||
|
this.button1.Enabled = false;
|
||||||
this.button1.Location = new System.Drawing.Point(556, 294);
|
this.button1.Location = new System.Drawing.Point(556, 294);
|
||||||
this.button1.Name = "button1";
|
this.button1.Name = "button1";
|
||||||
this.button1.Size = new System.Drawing.Size(85, 23);
|
this.button1.Size = new System.Drawing.Size(85, 23);
|
||||||
@ -171,6 +173,8 @@
|
|||||||
this.Name = "Form1";
|
this.Name = "Form1";
|
||||||
this.Text = "Main Window";
|
this.Text = "Main Window";
|
||||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
|
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.ResumeLayout(false);
|
||||||
this.PerformLayout();
|
this.PerformLayout();
|
||||||
|
|
||||||
|
133
OTP/Form1.cs
133
OTP/Form1.cs
@ -8,6 +8,10 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using OtpNet;
|
using OtpNet;
|
||||||
|
using System.IO;
|
||||||
|
using System.Data.SQLite;
|
||||||
|
using System.Reflection;
|
||||||
|
using ZXing.QrCode.Internal;
|
||||||
|
|
||||||
namespace OTP
|
namespace OTP
|
||||||
{
|
{
|
||||||
@ -16,18 +20,28 @@ namespace OTP
|
|||||||
private byte[] secretKey;
|
private byte[] secretKey;
|
||||||
private Totp totp;
|
private Totp totp;
|
||||||
private Timer timer;
|
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()
|
public Form1()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
//button1.Enabled = false;
|
||||||
secretKey = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP"); // 示例的 base32 编码
|
//secretKey = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP"); // 示例的 base32 编码
|
||||||
totp = new Totp(secretKey);
|
//totp = new Totp(secretKey);
|
||||||
|
|
||||||
timer = new Timer();
|
timer = new Timer();
|
||||||
timer.Interval = 1000; // 设置计时器间隔为 1 秒
|
timer.Interval = 1000; // 设置计时器间隔为 1 秒
|
||||||
timer.Tick += Timer_Tick;
|
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)
|
private void Timer_Tick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
@ -55,17 +69,106 @@ namespace OTP
|
|||||||
{
|
{
|
||||||
button1.Enabled = false; // 禁用生成按钮
|
button1.Enabled = false; // 禁用生成按钮
|
||||||
button2.Enabled = true; // 启用复制按钮
|
button2.Enabled = true; // 启用复制按钮
|
||||||
|
if (totp != null)
|
||||||
|
{
|
||||||
GenerateAndDisplayTotp(); // 生成并显示 TOTP 密码
|
GenerateAndDisplayTotp(); // 生成并显示 TOTP 密码
|
||||||
|
timer.Start();// 开始计时器
|
||||||
// 开始计时器
|
}
|
||||||
timer.Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Form1_Load(object sender, EventArgs e)
|
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)
|
private void button2_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Clipboard.SetText(label1.Text);
|
Clipboard.SetText(label1.Text);
|
||||||
@ -95,5 +198,21 @@ namespace OTP
|
|||||||
// 如果用户选择 Yes,什么都不需要做,窗体会继续关闭
|
// 如果用户选择 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.TabIndex = 2;
|
||||||
this.button2.Text = "Delete Record(s)";
|
this.button2.Text = "Delete Record(s)";
|
||||||
this.button2.UseVisualStyleBackColor = true;
|
this.button2.UseVisualStyleBackColor = true;
|
||||||
|
this.button2.Click += new System.EventHandler(this.button2_Click);
|
||||||
//
|
//
|
||||||
// button3
|
// button3
|
||||||
//
|
//
|
||||||
@ -90,6 +91,7 @@
|
|||||||
this.button3.TabIndex = 3;
|
this.button3.TabIndex = 3;
|
||||||
this.button3.Text = "Save Changes";
|
this.button3.Text = "Save Changes";
|
||||||
this.button3.UseVisualStyleBackColor = true;
|
this.button3.UseVisualStyleBackColor = true;
|
||||||
|
this.button3.Click += new System.EventHandler(this.button3_Click);
|
||||||
//
|
//
|
||||||
// button4
|
// button4
|
||||||
//
|
//
|
||||||
@ -99,17 +101,20 @@
|
|||||||
this.button4.TabIndex = 4;
|
this.button4.TabIndex = 4;
|
||||||
this.button4.Text = "Discard Changes";
|
this.button4.Text = "Discard Changes";
|
||||||
this.button4.UseVisualStyleBackColor = true;
|
this.button4.UseVisualStyleBackColor = true;
|
||||||
|
this.button4.Click += new System.EventHandler(this.button4_Click);
|
||||||
//
|
//
|
||||||
// Form2
|
// Form2
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.ClientSize = new System.Drawing.Size(619, 367);
|
this.ClientSize = new System.Drawing.Size(619, 367);
|
||||||
|
this.ControlBox = false;
|
||||||
this.Controls.Add(this.button4);
|
this.Controls.Add(this.button4);
|
||||||
this.Controls.Add(this.button3);
|
this.Controls.Add(this.button3);
|
||||||
this.Controls.Add(this.button2);
|
this.Controls.Add(this.button2);
|
||||||
this.Controls.Add(this.button1);
|
this.Controls.Add(this.button1);
|
||||||
this.Controls.Add(this.panel1);
|
this.Controls.Add(this.panel1);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||||
this.Name = "Form2";
|
this.Name = "Form2";
|
||||||
this.Text = "Data Manage";
|
this.Text = "Data Manage";
|
||||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form2_FormClosing);
|
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.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace OTP
|
namespace OTP
|
||||||
{
|
{
|
||||||
public partial class Form2 : Form
|
public partial class Form2 : Form
|
||||||
{
|
{
|
||||||
private string connectionString = "Data Source=key.db;Version=3;";
|
private string connectionString = "Data Source=key.db;Version=3;";
|
||||||
|
private string backupPath = "key.db.bak"; // 备份数据库文件的路径
|
||||||
|
private string sourceFileHash = ""; // 原始数据库文件的哈希值
|
||||||
|
|
||||||
public Form2()
|
public Form2()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
InitializeDataGridView();
|
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();
|
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()
|
private void InitializeDataGridView()
|
||||||
{
|
{
|
||||||
@ -34,19 +97,23 @@ namespace OTP
|
|||||||
{
|
{
|
||||||
connection.Open();
|
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())
|
using (SQLiteDataReader reader = command.ExecuteReader())
|
||||||
{
|
{
|
||||||
while (reader.Read())
|
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)
|
private void button1_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
using (Form3 form3 = new Form3())
|
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>
|
<AutoGen>True</AutoGen>
|
||||||
<DependentUpon>Resources.resx</DependentUpon>
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<None Include="key.db">
|
<EmbeddedResource Include="empty_key.db" />
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<None Include="key.db" />
|
||||||
</None>
|
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
<None Include="Properties\Settings.settings">
|
<None Include="Properties\Settings.settings">
|
||||||
<Generator>SettingsSingleFileGenerator</Generator>
|
<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