Compare commits

...

5 Commits

Author SHA1 Message Date
774b328a41 更新 README.md 2024-08-22 20:22:23 +08:00
d2b21eb414 上传文件至 img 2024-08-22 20:21:18 +08:00
8a6676062d up 2024-08-22 20:08:10 +08:00
ec4fd3eaa6 update 2024-08-22 19:07:59 +08:00
56a7c37bec 依赖更新
升级了两个包的版本

更新了`OTP.csproj`中的`EntityFramework`和`System.Drawing.Common`包版本。`EntityFramework`包从`6.4.4`升级到`6.5.1`,`System.Drawing.Common`包从`8.0.6`升级到`8.0.7`。
2024-07-22 00:29:31 +08:00
14 changed files with 180 additions and 723 deletions

83
OTP/Form1.Designer.cs generated
View File

@ -36,63 +36,65 @@
label2 = new System.Windows.Forms.Label();
button3 = new System.Windows.Forms.Button();
button4 = new System.Windows.Forms.Button();
button5 = new System.Windows.Forms.Button();
progressBar1 = new System.Windows.Forms.ProgressBar();
label3 = new System.Windows.Forms.Label();
label4 = new System.Windows.Forms.Label();
label5 = new System.Windows.Forms.Label();
SuspendLayout();
//
// listBox1
//
listBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
listBox1.Font = new System.Drawing.Font("微软雅黑", 15F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0);
listBox1.FormattingEnabled = true;
listBox1.ItemHeight = 20;
listBox1.ItemHeight = 27;
listBox1.Location = new System.Drawing.Point(49, 44);
listBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
listBox1.Name = "listBox1";
listBox1.Size = new System.Drawing.Size(551, 404);
listBox1.Size = new System.Drawing.Size(551, 409);
listBox1.TabIndex = 0;
listBox1.SelectedIndexChanged += listBox1_SelectedIndexChanged;
listBox1.SelectedIndexChanged += ListBox1_SelectedIndexChanged;
//
// label1
//
label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 24F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
label1.Location = new System.Drawing.Point(640, 68);
label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 24F, System.Drawing.FontStyle.Bold);
label1.Location = new System.Drawing.Point(640, 56);
label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label1.Name = "label1";
label1.Size = new System.Drawing.Size(230, 43);
label1.TabIndex = 1;
label1.Text = "TOTP Code";
label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
label1.Click += Label1_Click;
//
// button1
//
button1.Enabled = false;
button1.Location = new System.Drawing.Point(640, 339);
button1.Location = new System.Drawing.Point(640, 354);
button1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
button1.Name = "button1";
button1.Size = new System.Drawing.Size(107, 27);
button1.TabIndex = 3;
button1.Text = "Generate";
button1.UseVisualStyleBackColor = true;
button1.Click += button1_Click;
button1.Click += Button1_Click;
//
// button2
//
button2.Enabled = false;
button2.Location = new System.Drawing.Point(755, 339);
button2.Location = new System.Drawing.Point(755, 354);
button2.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
button2.Name = "button2";
button2.Size = new System.Drawing.Size(115, 128);
button2.Size = new System.Drawing.Size(115, 94);
button2.TabIndex = 3;
button2.Text = "Copy";
button2.UseVisualStyleBackColor = true;
button2.Click += button2_Click;
button2.Click += Button2_Click;
//
// label2
//
label2.BackColor = System.Drawing.Color.Transparent;
label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
label2.Location = new System.Drawing.Point(640, 285);
label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
label2.Location = new System.Drawing.Point(640, 297);
label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label2.Name = "label2";
label2.Size = new System.Drawing.Size(230, 23);
@ -102,40 +104,29 @@
//
// button3
//
button3.Location = new System.Drawing.Point(640, 373);
button3.Location = new System.Drawing.Point(640, 388);
button3.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
button3.Name = "button3";
button3.Size = new System.Drawing.Size(107, 27);
button3.TabIndex = 7;
button3.Text = "Manage";
button3.UseVisualStyleBackColor = true;
button3.Click += button3_Click;
button3.Click += Button3_Click;
//
// button4
//
button4.Location = new System.Drawing.Point(640, 406);
button4.Location = new System.Drawing.Point(640, 421);
button4.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
button4.Name = "button4";
button4.Size = new System.Drawing.Size(107, 27);
button4.TabIndex = 8;
button4.Text = "Refresh";
button4.UseVisualStyleBackColor = true;
button4.Click += button4_Click;
//
// button5
//
button5.Location = new System.Drawing.Point(640, 441);
button5.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
button5.Name = "button5";
button5.Size = new System.Drawing.Size(107, 27);
button5.TabIndex = 9;
button5.Text = "Troubleshooting";
button5.UseVisualStyleBackColor = true;
button5.Click += button5_Click;
button4.Click += Button4_Click;
//
// progressBar1
//
progressBar1.Location = new System.Drawing.Point(640, 165);
progressBar1.Location = new System.Drawing.Point(640, 177);
progressBar1.Maximum = 30;
progressBar1.Name = "progressBar1";
progressBar1.Size = new System.Drawing.Size(230, 51);
@ -143,22 +134,44 @@
//
// label3
//
label3.Font = new System.Drawing.Font("Segoe UI", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
label3.Location = new System.Drawing.Point(640, 219);
label3.Font = new System.Drawing.Font("Segoe UI", 24F);
label3.Location = new System.Drawing.Point(640, 231);
label3.Name = "label3";
label3.Size = new System.Drawing.Size(230, 45);
label3.TabIndex = 11;
label3.Text = "1";
label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label4
//
label4.AutoSize = true;
label4.Font = new System.Drawing.Font("Segoe UI", 12F);
label4.Location = new System.Drawing.Point(640, 129);
label4.Name = "label4";
label4.Size = new System.Drawing.Size(45, 21);
label4.TabIndex = 12;
label4.Text = "Next:";
//
// label5
//
label5.AutoSize = true;
label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold);
label5.Location = new System.Drawing.Point(713, 130);
label5.Name = "label5";
label5.Size = new System.Drawing.Size(92, 20);
label5.TabIndex = 13;
label5.Text = "Next Code";
label5.Click += Label5_Click;
//
// Form1
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(904, 508);
Controls.Add(label5);
Controls.Add(label4);
Controls.Add(label3);
Controls.Add(progressBar1);
Controls.Add(button5);
Controls.Add(button4);
Controls.Add(button3);
Controls.Add(label2);
@ -175,6 +188,7 @@
Load += Form1_Load;
VisibleChanged += Form1_VisibleChanged;
ResumeLayout(false);
PerformLayout();
}
#endregion
@ -186,9 +200,10 @@
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label5;
}
}

View File

@ -12,8 +12,8 @@ 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 const string connectionString = "Data Source=key.db;Version=3;";
private const string embeddedDatabaseResource = "OTP.empty_key.db";
private int runonce = 0;
public Form1()
@ -23,8 +23,10 @@ namespace OTP
//secretKey = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP"); // 示例的 base32 编码
//totp = new Totp(secretKey);
timer = new Timer();
timer.Interval = 1000; // 设置计时器间隔为 1 秒
timer = new Timer
{
Interval = 1000 // 设置计时器间隔为 1 秒
};
timer.Tick += Timer_Tick;
}
public class TitleInfo
@ -54,14 +56,16 @@ namespace OTP
{
// 生成新的 TOTP 密码
string newTotpCode = totp.ComputeTotp();
string newNextTotpCode = totp.ComputeTotp(DateTime.UtcNow.AddSeconds(30));
// 在标签上显示新生成的密码
// 使用Invoke确保在UI线程上更新UI元素
this.Invoke((System.Windows.Forms.MethodInvoker)(() => label1.Text = newTotpCode));
this.Invoke((System.Windows.Forms.MethodInvoker)(() => label5.Text = newNextTotpCode));
}
private void button1_Click(object sender, EventArgs e)
private void Button1_Click(object sender, EventArgs e)
{
button1.Enabled = false; // 禁用生成按钮
button2.Enabled = true; // 启用复制按钮
@ -83,18 +87,14 @@ namespace OTP
}
private void ExtractEmbeddedDatabase()
private static void ExtractEmbeddedDatabase()
{
// 从嵌入的资源中复制数据库文件到同目录下
try
{
using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedDatabaseResource))
{
using (FileStream fileStream = new FileStream("key.db", FileMode.Create))
{
resourceStream.CopyTo(fileStream);
}
}
using Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedDatabaseResource);
using FileStream fileStream = new("key.db", FileMode.Create);
resourceStream.CopyTo(fileStream);
}
catch (Exception ex)
{
@ -106,32 +106,26 @@ namespace OTP
{
try
{
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
using SQLiteConnection connection = new(connectionString);
connection.Open();
using SQLiteCommand command = new("SELECT Id, Title, SecretKey FROM TotpData", connection);
using SQLiteDataReader reader = command.ExecuteReader();
listBox1.Items.Clear(); // 清空现有数据
while (reader.Read())
{
connection.Open();
int id = reader.GetInt32(0);
string title = reader.GetString(1);
string secretKey = reader.GetString(2);
using (SQLiteCommand command = new SQLiteCommand("SELECT Id, Title, SecretKey FROM TotpData", connection))
TitleInfo titleInfo = new()
{
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);
Id = id,
Title = title,
SecretKey = secretKey
};
TitleInfo titleInfo = new TitleInfo
{
Id = id,
Title = title,
SecretKey = secretKey
};
listBox1.Items.Add(titleInfo);
}
}
}
listBox1.Items.Add(titleInfo);
}
}
catch (Exception ex)
@ -140,12 +134,11 @@ namespace OTP
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
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 (listBox1.SelectedItem is TitleInfo selectedTitleInfo)
{
if (runonce == 0)
{
@ -170,15 +163,15 @@ namespace OTP
}
private void button2_Click(object sender, EventArgs e)
private void Button2_Click(object sender, EventArgs e)
{
Clipboard.SetText(label1.Text);
}
private void button3_Click(object sender, EventArgs e)
private void Button3_Click(object sender, EventArgs e)
{
// 创建 Form2 实例
Form2 form2 = new Form2();
Form2 form2 = new();
// 显示新创建的 Form2 实例
form2.Show();
@ -206,6 +199,7 @@ namespace OTP
LoadTitlesToListBox();
runonce = 0;
label1.Text = "TOTP Code";
label1.Text = "Next Code";
button1.Enabled = false;
button2.Enabled = false;
label3.Text = "time";
@ -217,15 +211,19 @@ namespace OTP
}
}
private void button4_Click(object sender, EventArgs e)
private void Button4_Click(object sender, EventArgs e)
{
LoadTitlesToListBox();
}
private void button5_Click(object sender, EventArgs e)
private void Label1_Click(object sender, EventArgs e)
{
Form4 form4 = new Form4();
form4.Show();
Clipboard.SetText(label1.Text);
}
private void Label5_Click(object sender, EventArgs e)
{
Clipboard.SetText(label5.Text);
}
}
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Microsoft ResX Schema
Version 2.0
@ -48,7 +48,7 @@
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter

8
OTP/Form2.Designer.cs generated
View File

@ -74,7 +74,7 @@
button1.TabIndex = 1;
button1.Text = "New Record";
button1.UseVisualStyleBackColor = true;
button1.Click += button1_Click;
button1.Click += Button1_Click;
//
// button2
//
@ -85,7 +85,7 @@
button2.TabIndex = 2;
button2.Text = "Delete Record(s)";
button2.UseVisualStyleBackColor = true;
button2.Click += button2_Click;
button2.Click += Button2_Click;
//
// button3
//
@ -96,7 +96,7 @@
button3.TabIndex = 3;
button3.Text = "Save Changes";
button3.UseVisualStyleBackColor = true;
button3.Click += button3_Click;
button3.Click += Button3_Click;
//
// button4
//
@ -107,7 +107,7 @@
button4.TabIndex = 4;
button4.Text = "Discard Changes";
button4.UseVisualStyleBackColor = true;
button4.Click += button4_Click;
button4.Click += Button4_Click;
//
// Form2
//

View File

@ -8,8 +8,8 @@ namespace OTP
{
public partial class Form2 : Form
{
private string connectionString = "Data Source=key.db;Version=3;";
private string backupPath = "key.db.bak"; // 备份数据库文件的路径
private const string connectionString = "Data Source=key.db;Version=3;";
private const string backupPath = "key.db.bak"; // 备份数据库文件的路径
private string sourceFileHash = ""; // 原始数据库文件的哈希值
public Form2()
@ -65,16 +65,12 @@ namespace OTP
}
}
// 计算文件的SHA-256哈希值
private string CalculateSHA256Hash(string filePath)
private static 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();
}
}
using SHA256 sha256 = SHA256.Create();
using FileStream stream = File.OpenRead(filePath);
byte[] hashBytes = sha256.ComputeHash(stream);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
@ -86,51 +82,42 @@ namespace OTP
{
dataGridView1.Rows.Clear(); // 清空现有数据
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
{
connection.Open();
using SQLiteConnection connection = new(connectionString);
connection.Open();
using (SQLiteCommand command = new SQLiteCommand("SELECT Id, Title FROM TotpData", connection))
{
using (SQLiteDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
int id = reader.GetInt32(0);
string title = reader.GetString(1);
dataGridView1.Rows.Add(title);
dataGridView1.Rows[dataGridView1.Rows.Count - 1].Tag = id; // 将 Id 存储在行的 Tag 属性中
}
}
}
using SQLiteCommand command = new("SELECT Id, Title FROM TotpData", connection);
using SQLiteDataReader reader = command.ExecuteReader();
while (reader.Read())
{
int id = reader.GetInt32(0);
string title = reader.GetString(1);
dataGridView1.Rows.Add(title);
dataGridView1.Rows[^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())
{
DialogResult result = form3.ShowDialog();
using Form3 form3 = new();
DialogResult result = form3.ShowDialog();
if (result == DialogResult.OK)
{
// 在 Form3 中添加数据完成后,刷新数据
LoadData();
}
if (result == DialogResult.OK)
{
// 在 Form3 中添加数据完成后,刷新数据
LoadData();
}
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
Form1 form1 = Application.OpenForms["Form1"] as Form1;
if (form1 != null)
if (Application.OpenForms["Form1"] is Form1 form1)
{
form1.Show();
}
}
private void button2_Click(object sender, EventArgs e)
private void Button2_Click(object sender, EventArgs e)
{
try
{
@ -153,20 +140,16 @@ namespace OTP
}
}
private void DeleteRecordFromDatabase(int recordId)
private static void DeleteRecordFromDatabase(int recordId)
{
try
{
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
{
connection.Open();
using SQLiteConnection connection = new(connectionString);
connection.Open();
using (SQLiteCommand command = new SQLiteCommand("DELETE FROM TotpData WHERE ID = @ID", connection))
{
command.Parameters.AddWithValue("@ID", recordId);
command.ExecuteNonQuery();
}
}
using SQLiteCommand command = new("DELETE FROM TotpData WHERE ID = @ID", connection);
command.Parameters.AddWithValue("@ID", recordId);
command.ExecuteNonQuery();
}
catch (Exception ex)
{
@ -174,7 +157,7 @@ namespace OTP
}
}
private void button3_Click(object sender, EventArgs e)
private void Button3_Click(object sender, EventArgs e)
{
// 删除备份文件
if (File.Exists(backupPath))
@ -186,7 +169,7 @@ namespace OTP
this.Close();
}
private void button4_Click(object sender, EventArgs e)
private void Button4_Click(object sender, EventArgs e)
{
try
{

71
OTP/Form3.Designer.cs generated
View File

@ -34,18 +34,13 @@
textBox2 = new System.Windows.Forms.TextBox();
button1 = new System.Windows.Forms.Button();
button2 = new System.Windows.Forms.Button();
button3 = new System.Windows.Forms.Button();
button4 = new System.Windows.Forms.Button();
button5 = new System.Windows.Forms.Button();
button6 = new System.Windows.Forms.Button();
label3 = new System.Windows.Forms.Label();
label4 = new System.Windows.Forms.Label();
label5 = new System.Windows.Forms.Label();
groupBox1 = new System.Windows.Forms.GroupBox();
button8 = new System.Windows.Forms.Button();
pictureBox1 = new System.Windows.Forms.PictureBox();
groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit();
SuspendLayout();
//
// label1
@ -93,7 +88,7 @@
button1.TabIndex = 4;
button1.Text = "Add";
button1.UseVisualStyleBackColor = true;
button1.Click += button1_Click;
button1.Click += Button1_Click;
//
// button2
//
@ -106,49 +101,27 @@
button2.Text = "Cancel";
button2.UseVisualStyleBackColor = true;
//
// button3
//
button3.Location = new System.Drawing.Point(341, 5);
button3.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
button3.Name = "button3";
button3.Size = new System.Drawing.Size(205, 27);
button3.TabIndex = 6;
button3.Text = "Scan QR Code from Screenshot";
button3.UseVisualStyleBackColor = true;
button3.Click += button3_Click;
//
// button4
//
button4.Location = new System.Drawing.Point(341, 38);
button4.Location = new System.Drawing.Point(341, 9);
button4.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
button4.Name = "button4";
button4.Size = new System.Drawing.Size(205, 27);
button4.TabIndex = 7;
button4.Text = "Scan QR Code from Image File";
button4.UseVisualStyleBackColor = true;
button4.Click += button4_Click;
//
// button5
//
button5.Location = new System.Drawing.Point(341, 72);
button5.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
button5.Name = "button5";
button5.Size = new System.Drawing.Size(205, 27);
button5.TabIndex = 8;
button5.Text = "Scan QR Code with Camera";
button5.UseVisualStyleBackColor = true;
button5.Click += button5_Click;
button4.Click += Button4_Click;
//
// button6
//
button6.Location = new System.Drawing.Point(341, 105);
button6.Location = new System.Drawing.Point(341, 44);
button6.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
button6.Name = "button6";
button6.Size = new System.Drawing.Size(205, 27);
button6.TabIndex = 9;
button6.Text = "Import from Clipboard";
button6.UseVisualStyleBackColor = true;
button6.Click += button6_Click;
button6.Click += Button6_Click;
//
// label3
//
@ -182,8 +155,6 @@
//
// groupBox1
//
groupBox1.Controls.Add(button8);
groupBox1.Controls.Add(pictureBox1);
groupBox1.Controls.Add(label4);
groupBox1.Controls.Add(label5);
groupBox1.Controls.Add(label3);
@ -191,42 +162,20 @@
groupBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
groupBox1.Name = "groupBox1";
groupBox1.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3);
groupBox1.Size = new System.Drawing.Size(528, 332);
groupBox1.Size = new System.Drawing.Size(528, 214);
groupBox1.TabIndex = 14;
groupBox1.TabStop = false;
groupBox1.Text = "Debug Info";
//
// button8
//
button8.Location = new System.Drawing.Point(427, 0);
button8.Name = "button8";
button8.Size = new System.Drawing.Size(101, 23);
button8.TabIndex = 15;
button8.Text = "Stop Camera";
button8.UseVisualStyleBackColor = true;
button8.Click += button8_Click;
//
// pictureBox1
//
pictureBox1.Location = new System.Drawing.Point(122, 130);
pictureBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
pictureBox1.Name = "pictureBox1";
pictureBox1.Size = new System.Drawing.Size(298, 195);
pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
pictureBox1.TabIndex = 14;
pictureBox1.TabStop = false;
//
// Form3
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
CancelButton = button2;
ClientSize = new System.Drawing.Size(569, 517);
ClientSize = new System.Drawing.Size(569, 404);
Controls.Add(groupBox1);
Controls.Add(button6);
Controls.Add(button5);
Controls.Add(button4);
Controls.Add(button3);
Controls.Add(button2);
Controls.Add(button1);
Controls.Add(textBox2);
@ -241,10 +190,8 @@
ShowIcon = false;
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "New Record";
FormClosing += Form3_FormClosing;
groupBox1.ResumeLayout(false);
groupBox1.PerformLayout();
((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit();
ResumeLayout(false);
PerformLayout();
}
@ -257,15 +204,11 @@
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.Button button6;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Button button8;
}
}

View File

@ -1,12 +1,6 @@
using FlashCap;
using FlashCap.Utilities;
using ScreenCapturerNS;
using System;
using System;
using System.Data.SQLite;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using ZXing;
@ -14,49 +8,15 @@ namespace OTP
{
public partial class Form3 : Form
{
private string connectionString = "Data Source=key.db;Version=3;";
private bool isCapturing = false; // 添加标识截图状态的成员变量
private const string connectionString = "Data Source=key.db;Version=3;";
private bool isLocalfile = false;
private bool isScanningPaused = false;
private bool isRecording = false;
private SynchronizationContext synchContext;
private System.Windows.Forms.Timer timer;
private CaptureDevice captureDevice;
public Form3()
{
InitializeComponent();
// 初始化定时器间隔为1秒1000毫秒
timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
timer.Tick += Timer_Tick;
}
private void Timer_Tick(object sender, EventArgs e)
{
if (pictureBox1.Image != null && isRecording)
{
ScanQRCode((Bitmap)pictureBox1.Image);
}
InitializeComponent(); // 确保调用了这个方法
}
private async void Form3_FormClosing(object sender, FormClosingEventArgs e)
{
StopCapturing();
if (isRecording)
{
await this.captureDevice.StopAsync();
pictureBox1.Image = null;
isRecording = false;
// Discard capture device.
this.captureDevice?.Dispose();
this.captureDevice = null;
}
}
private void button1_Click(object sender, EventArgs e)
private void Button1_Click(object sender, EventArgs e)
{
try
{
@ -65,16 +25,14 @@ namespace OTP
if (!string.IsNullOrWhiteSpace(title) && !string.IsNullOrWhiteSpace(secretKey))
{
using (SQLiteConnection connection = new SQLiteConnection(connectionString))
using (SQLiteConnection connection = new(connectionString))
{
connection.Open();
using (SQLiteCommand command = new SQLiteCommand("INSERT INTO TotpData (Title, SecretKey) VALUES (@Title, @SecretKey)", connection))
{
command.Parameters.AddWithValue("@Title", title);
command.Parameters.AddWithValue("@SecretKey", secretKey);
command.ExecuteNonQuery();
}
using SQLiteCommand command = new("INSERT INTO TotpData (Title, SecretKey) VALUES (@Title, @SecretKey)", connection);
command.Parameters.AddWithValue("@Title", title);
command.Parameters.AddWithValue("@SecretKey", secretKey);
command.ExecuteNonQuery();
}
this.DialogResult = DialogResult.OK;
MessageBox.Show("Record added successfully.");
@ -92,40 +50,8 @@ namespace OTP
MessageBox.Show($"An error occurred: {ex.Message}");
}
}
private void button3_Click(object sender, EventArgs e)
{
if (isCapturing)
{
label5.Text = "Stopped";
StopCapturing(); // 停止截图
}
else
{
label3.Text = "None";
label5.Text = "Running";
label4.Text = "No QR code found.";
StartCapturing(); // 开始截图
}
}
private void StartCapturing()
{
//deactivateButton(3);
isCapturing = true; // 设置截图状态为正在截图
ScreenCapturer.StartCapture((Bitmap bitmap) =>
{
ScanQRCode(bitmap);
});
}
private void StopCapturing()
{
//activeButton();
isCapturing = false; // 设置截图状态为未截图
ScreenCapturer.StopCapture(); // 停止截图
}
private async void ScanQRCode(Bitmap bitmap)
private void ScanQRCode(Bitmap bitmap)
{
// 创建二维码读取器实例
var barcodeReader = new ZXing.Windows.Compatibility.BarcodeReader();
@ -136,49 +62,35 @@ namespace OTP
{
// 扫描成功,显示扫描结果
string decodedText = result.Text;
this.Invoke((MethodInvoker)(() => label3.Text = decodedText));
label3.Text = decodedText;
// 判断是否符合期望的格式
if (decodedText.StartsWith("otpauth://totp/") && decodedText.Contains("?secret="))
{
if (!isLocalfile && !isScanningPaused)
{
StopCapturing();
this.Invoke((MethodInvoker)(() => label5.Text = "Stopped"));
}
else
if (isLocalfile)
{
isLocalfile = false;
}
string[] parts = decodedText.Split(new char[] { '/', '=', '&', '?' });
string[] parts = decodedText.Split(['/', '=', '&', '?']);
if (parts.Length >= 6)
{
//扫码成功
string title = parts[3]; // 获取 title 部分
// 扫码成功
string title = Uri.UnescapeDataString(parts[3]); // 解码 title 部分
string secretKey = parts[5]; // 获取 secretKey 部分
// 在窗体上显示 title 和 secretKey
this.Invoke((MethodInvoker)(() => textBox1.Text = title));
this.Invoke((MethodInvoker)(() => textBox2.Text = secretKey));
this.Invoke((MethodInvoker)(() => label4.Text = "Success"));
if (isRecording)
{
await this.captureDevice.StopAsync();
pictureBox1.Image = null;
isRecording = false;
// Discard capture device.
this.captureDevice?.Dispose();
this.captureDevice = null;
}
textBox1.Text = title;
textBox2.Text = secretKey;
label4.Text = "Success";
}
else
{
this.Invoke((MethodInvoker)(() => label4.Text = "Invalid QR code format."));
label4.Text = "Invalid QR code format.";
}
}
else
{
this.Invoke((MethodInvoker)(() => label4.Text = "QR code format not recognized."));
label4.Text = "QR code format not recognized.";
}
}
else
@ -188,81 +100,24 @@ namespace OTP
label3.Text = "None";
label4.Text = "QR code not detected.";
}
else if (isScanningPaused)
{
this.Invoke((MethodInvoker)(() => label3.Text = "None"));
this.Invoke((MethodInvoker)(() => label4.Text = "QR code not detected."));
}
}
}
private void button4_Click(object sender, EventArgs e)
private void Button4_Click(object sender, EventArgs e)
{
isLocalfile = true;
using (OpenFileDialog openFileDialog = new OpenFileDialog())
using OpenFileDialog openFileDialog = new();
openFileDialog.Filter = "Image Files|*.jpg;*.jpeg;*.png;*.bmp;*.gif";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
openFileDialog.Filter = "Image Files|*.jpg;*.jpeg;*.png;*.bmp;*.gif";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string filePath = openFileDialog.FileName;
string filePath = openFileDialog.FileName;
using (Bitmap image = new Bitmap(filePath))
{
ScanQRCode(image);
}
}
using Bitmap image = new(filePath);
ScanQRCode(image);
}
}
private async void button5_Click(object sender, EventArgs e)
{
this.synchContext = SynchronizationContext.Current;
var devices = new CaptureDevices();
var descriptors = devices.EnumerateDescriptors().
//Where(d => d.DeviceType == DeviceTypes.DirectShow). // Only DirectShow device.
Where(d => d.Characteristics.Length >= 1). // One or more valid video characteristics.
ToArray();
// Use first device.
var descriptor0 = descriptors.ElementAtOrDefault(0);
if (descriptor0 != null)
{
var characteristics = descriptor0.Characteristics.
FirstOrDefault(c => c.PixelFormat != PixelFormats.Unknown);
if (characteristics != null)
{
this.captureDevice = await descriptor0.OpenAsync(
characteristics,
this.OnPixelBufferArrived);
await this.captureDevice.StartAsync();
}
}
}
private void OnPixelBufferArrived(PixelBufferScope bufferScope)
{
ArraySegment<byte> image = bufferScope.Buffer.ReferImage();
using (var stream = image.AsStream())
{
var bitmap = Image.FromStream(stream);
bufferScope.ReleaseNow();
this.synchContext.Post(_ =>
{
pictureBox1.Image = bitmap;
if (!isRecording)
{
isRecording = true;
timer.Start();
}
}, null);
}
}
private void button6_Click(object sender, EventArgs e)
private void Button6_Click(object sender, EventArgs e)
{
string clipboardText = Clipboard.GetText();
@ -270,10 +125,10 @@ namespace OTP
clipboardText.StartsWith("otpauth://totp/") &&
clipboardText.Contains("?secret="))
{
string[] parts = clipboardText.Split(new char[] { '/', '=', '&', '?' });
string[] parts = clipboardText.Split(['/', '=', '&', '?']);
if (parts.Length >= 6)
{
string title = parts[3]; // 获取 title 部分
string title = Uri.UnescapeDataString(parts[3]); // 解码 title 部分
string secretKey = parts[5]; // 获取 secretKey 部分
MessageBox.Show("OTP link successfully pasted.");
@ -288,18 +143,5 @@ namespace OTP
MessageBox.Show("Clipboard content is not a valid OTP link.");
}
}
private async void button8_Click(object sender, EventArgs e)
{
if (isRecording)
{
await this.captureDevice.StopAsync();
pictureBox1.Image = null;
isRecording = false;
// Discard capture device.
this.captureDevice?.Dispose();
this.captureDevice = null;
}
}
}
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Microsoft ResX Schema
Version 2.0
@ -48,7 +48,7 @@
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter

118
OTP/Form4.Designer.cs generated
View File

@ -1,118 +0,0 @@
namespace OTP
{
partial class Form4
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label2
//
this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label2.AutoSize = true;
this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 36F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label2.Location = new System.Drawing.Point(12, 64);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(152, 55);
this.label2.TabIndex = 1;
this.label2.Text = "label2";
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label3
//
this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label3.AutoSize = true;
this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 36F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label3.Location = new System.Drawing.Point(12, 119);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(216, 55);
this.label3.TabIndex = 2;
this.label3.Text = "网络时间";
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label1
//
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label1.AutoSize = true;
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 36F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(360, 55);
this.label1.TabIndex = 3;
this.label1.Text = "计算机本地时间";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label4
//
this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label4.AutoSize = true;
this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 36F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label4.Location = new System.Drawing.Point(12, 174);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(152, 55);
this.label4.TabIndex = 4;
this.label4.Text = "label4";
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// Form4
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(705, 242);
this.Controls.Add(this.label2);
this.Controls.Add(this.label3);
this.Controls.Add(this.label1);
this.Controls.Add(this.label4);
this.Name = "Form4";
this.Text = "Troubleshooting";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form4_FormClosing);
this.Load += new System.EventHandler(this.Form4_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label4;
}
}

View File

@ -1,81 +0,0 @@
using GuerrillaNtp;
using System;
using System.Windows.Forms;
namespace OTP
{
public partial class Form4 : Form
{
private NtpClient ntpClient;
private NtpClock clock;
private Timer timer;
public Form4()
{
InitializeComponent();
ntpClient = new NtpClient("time.pool.aliyun.com");
// Create and configure the timer
timer = new Timer();
timer.Interval = 1000; // 1 second interval
timer.Tick += Timer_Tick;
}
private async void Form4_Load(object sender, EventArgs e)
{
try
{
// Display local time
UpdateLocalTimeLabel();
// Query time from NTP server
clock = await ntpClient.QueryAsync();
// Display network time from NTP server
UpdateNetworkTimeLabel();
// Start the timer to update network time periodically
timer.Start();
}
catch (Exception ex)
{
// Handle any exceptions that might occur during NTP query
label4.Text = "NTP Error: " + ex.Message;
}
}
private void Timer_Tick(object sender, EventArgs e)
{
// Update the time label
UpdateLocalTimeLabel();
UpdateNetworkTimeLabel();
}
private void UpdateLocalTimeLabel()
{
DateTime localTime = DateTime.Now;
label2.Text = localTime.ToString();
}
private void UpdateNetworkTimeLabel()
{
if (clock != null)
{
DateTimeOffset networkTime = clock.UtcNow;
// Convert network time to user's local time zone
TimeZoneInfo localTimeZone = TimeZoneInfo.Local;
DateTimeOffset localTime = TimeZoneInfo.ConvertTime(networkTime, localTimeZone);
label4.Text = localTime.ToString();
}
}
// Form4 closing event
private void Form4_FormClosing(object sender, FormClosingEventArgs e)
{
// Stop the timer when the form is closing
timer.Stop();
}
}
}

View File

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -23,7 +23,7 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>none</DebugType>
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup>
<StartupObject>OTP.Program</StartupObject>
@ -38,7 +38,7 @@
<SignAssembly>False</SignAssembly>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>none</DebugType>
<DebugType>full</DebugType>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="empty_key.db" />
@ -59,25 +59,16 @@
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<PackageReference Include="FlashCap" Version="1.10.0" />
<PackageReference Include="GuerrillaNtp" Version="3.1.0" />
<PackageReference Include="Otp.NET" Version="1.4.0" />
<PackageReference Include="ScreenCapturer" Version="3.0.1" />
<PackageReference Include="SharpDX" Version="4.2.0" />
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
<PackageReference Include="SharpDX.DXGI" Version="4.2.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
<PackageReference Include="System.Data.SQLite" Version="1.0.118.0" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118.0" />
<PackageReference Include="System.Data.SQLite.EF6" Version="1.0.118.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="ZXing.Net" Version="0.16.9" />
<PackageReference Include="ZXing.Net.Bindings.Windows.Compatibility" Version="0.16.12" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="EntityFramework" Version="6.5.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.6" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Settings.Designer.cs">

View File

@ -1,5 +1,9 @@
# OTP
这是一个不太靠谱的适用于Windows平台的二步验证代码生成器
这是一个适用于Windows平台的二步验证代码生成器
.net8.0移植版本,功能基本已完成
可满足基本TOTP验证器需求
------
<img src="https://git.chenx221.cyou/chenx221/OTP/raw/branch/net8.0/img/2024-08-22_201918.png">

BIN
img/2024-08-22_201918.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB