From 459871fef9970ce5c1454d23a442edf0dd1f9f36 Mon Sep 17 00:00:00 2001 From: Rookiestyle Date: Thu, 1 Oct 2020 10:51:52 +0200 Subject: [PATCH] Add support for Steam OTP (#20) Allow adding Steam OTP data (compatible with KeePassXC) Enable migration of Steam OTP settings from/to KeeTrayTotp --- Translations/KeePassOTP.de.language.xml | 4 +- Translations/KeePassOTP.fr.language.xml | 4 +- Translations/KeePassOTP.template.language.xml | 2 +- src/DAO/OTPDAO_DB.cs | 2 +- src/DAO/OTPDAO_Entry.cs | 2 +- src/KeePassOTP.cs | 89 ++++++++++++++----- src/KeePassOTPSetup.Designer.cs | 69 +++++++------- src/KeePassOTPSetup.cs | 25 ++++-- src/Migration.cs | 54 ++++++----- src/PluginTranslation.cs | 2 +- src/Properties/AssemblyInfo.cs | 6 +- src/Util.cs | 2 + version.info | 6 +- 13 files changed, 169 insertions(+), 98 deletions(-) diff --git a/Translations/KeePassOTP.de.language.xml b/Translations/KeePassOTP.de.language.xml index 50cbf0a..79c2d03 100644 --- a/Translations/KeePassOTP.de.language.xml +++ b/Translations/KeePassOTP.de.language.xml @@ -1,6 +1,6 @@ - 9 + 10 OTPCopyTrayNoEntries KPOTP - Keine Einträge vorhanden @@ -79,7 +79,7 @@ TimeCorrection - Zeitversatz ausgleichen - TOTP spezifisch + Zeitversatz ausgleichen - Nur für TOTP && Steam URL diff --git a/Translations/KeePassOTP.fr.language.xml b/Translations/KeePassOTP.fr.language.xml index 8a5c5d3..b32be00 100644 --- a/Translations/KeePassOTP.fr.language.xml +++ b/Translations/KeePassOTP.fr.language.xml @@ -1,6 +1,6 @@  -2 +3 OTPCopyTrayNoEntries KPOTP - Aucune entrée disponible @@ -79,7 +79,7 @@ TimeCorrection -Correction de temps - seulement pour TOTP +Correction de temps - seulement pour TOTP et Steam URL diff --git a/Translations/KeePassOTP.template.language.xml b/Translations/KeePassOTP.template.language.xml index 94c7579..104ac84 100644 --- a/Translations/KeePassOTP.template.language.xml +++ b/Translations/KeePassOTP.template.language.xml @@ -79,7 +79,7 @@ TimeCorrection - Time correction - TOTP only + Time correction - TOTP && Steam only URL diff --git a/src/DAO/OTPDAO_DB.cs b/src/DAO/OTPDAO_DB.cs index d6e1f9d..fbd982c 100644 --- a/src/DAO/OTPDAO_DB.cs +++ b/src/DAO/OTPDAO_DB.cs @@ -467,7 +467,7 @@ public override string GetReadableOTP(PwEntry pe) if (otp.kpotp.Type == KPOTPType.HOTP) return otp.ReadableOTP; int r = (otp.ValidTo - DateTime.UtcNow).Seconds + 1; - return otp.ReadableOTP + (r < 6 ? " (" + r.ToString() + ")" : string.Empty); + return otp.ReadableOTP + (r <= Config.TOTPSoonExpiring ? " (" + r.ToString() + ")" : string.Empty); } public override KPOTP GetOTP(PwEntry pe) diff --git a/src/DAO/OTPDAO_Entry.cs b/src/DAO/OTPDAO_Entry.cs index 14b7624..9ed0dda 100644 --- a/src/DAO/OTPDAO_Entry.cs +++ b/src/DAO/OTPDAO_Entry.cs @@ -43,7 +43,7 @@ public override string GetReadableOTP(PwEntry pe) else { int r = (otp.ValidTo - DateTime.UtcNow).Seconds + 1; - return otp.ReadableOTP + (r < 6 ? " (" + r.ToString() + ")" : string.Empty); + return otp.ReadableOTP + (r <= Config.TOTPSoonExpiring ? " (" + r.ToString() + ")" : string.Empty); } } diff --git a/src/KeePassOTP.cs b/src/KeePassOTP.cs index 9b0977c..c9f68b6 100644 --- a/src/KeePassOTP.cs +++ b/src/KeePassOTP.cs @@ -13,7 +13,8 @@ namespace KeePassOTP public enum KPOTPType : int { HOTP = 0, - TOTP + TOTP, + STEAM } public enum KPOTPHash : int @@ -39,14 +40,29 @@ public class KPOTP private static Dictionary m_timeCorrectionUrls = new Dictionary(); public KPOTPHash Hash = KPOTPHash.SHA1; - public KPOTPType Type = KPOTPType.TOTP; + private KPOTPType m_Type = KPOTPType.TOTP; + public KPOTPType Type + { + get { return m_Type; } + set + { + m_Type = value; + if (m_Type == KPOTPType.STEAM) Length = 5; + else Length = Length; // Ensure proper length (Steam = 5 digits) + } + } + public KPOTPEncoding Encoding = KPOTPEncoding.BASE32; public int m_length = 6; public int Length { get { return m_length; } - set { m_length = Math.Min(10, Math.Max(value, 6)); } + set + { + if (Type == KPOTPType.STEAM) m_length = 5; + else m_length = Math.Min(10, Math.Max(value, 6)); + } } private int m_timestep = 30; @@ -79,7 +95,7 @@ public string TimeCorrectionUrl get { return m_url; } set { SetURL(value); } } - + public string Issuer; public string Label; public ProtectedString OTPAuthString @@ -113,10 +129,10 @@ public int RemainingSeconds static KPOTP() { - miConfigureWebClient = typeof(IOConnection).GetMethod("ConfigureWebClient", - System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, - null, - new Type[] { typeof(System.Net.WebClient) }, + miConfigureWebClient = typeof(IOConnection).GetMethod("ConfigureWebClient", + System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, + null, + new Type[] { typeof(System.Net.WebClient) }, null); } @@ -131,18 +147,19 @@ public string GetOTP(bool ShowNext, bool CheckTime) //List of time correction data is filled asynchronously //Call it synchronously as it is required now! if (CheckTime) GetTimeCorrection(m_url); - byte[] data =(Type == KPOTPType.TOTP) ? GetTOTPData(ShowNext) : GetHOTPData(ShowNext); + byte[] data = (Type == KPOTPType.HOTP) ? GetHOTPData(ShowNext) : GetTOTPData(ShowNext); byte[] hash = ComputeHash(data); MemUtil.ZeroByteArray(data); int offset = hash[hash.Length - 1] & 0xF; int binary = ((hash[offset] & 0x7F) << 24) | - ((hash[offset + 1] & 0xFF) << 16) | - ((hash[offset + 2] & 0xFF) << 8) | - (hash[offset + 3] & 0xFF); - - string result = (binary % (int)Math.Pow(10, Length)).ToString().PadLeft(Length, '0'); + ((hash[offset + 1] & 0xFF) << 16) | + ((hash[offset + 2] & 0xFF) << 8) | + (hash[offset + 3] & 0xFF); + string result = string.Empty; + if (Type != KPOTPType.STEAM) result = (binary % (int)Math.Pow(10, Length)).ToString().PadLeft(Length, '0'); + else result = GetSteamData(binary); return result + (string.IsNullOrEmpty(m_url) || m_timeCorrectionUrls.ContainsKey(m_url) ? string.Empty : "*"); } @@ -168,6 +185,24 @@ private byte[] GetTOTPData(bool showNext) return GetOTPData(showNext, Ticks); } + /// + /// Character set for authenticator code + /// + private static readonly char[] aSteamChars = new char[] { '2', '3', '4', '5', + '6', '7', '8', '9', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', + 'Q', 'R', 'T', 'V', 'W', 'X', 'Y' }; + private string GetSteamData(int binary) + { + string result = string.Empty; + for (int i = 0; i < Length; i++) + { + result += aSteamChars[binary % aSteamChars.Length]; + binary /= aSteamChars.Length; + } + + return result; + } + private byte[] GetOTPData(bool showNext, long value) { byte[] result = new byte[0]; @@ -215,6 +250,8 @@ private ProtectedString GetOTPAuthString() otpSuffix += "&encoder=" + Encoding.ToString(); if (!string.IsNullOrEmpty(Issuer)) otpSuffix += "&issuer=" + Encode(Issuer, false); + if (Type == KPOTPType.STEAM) + otpSuffix += "&encoder=steam"; return new ProtectedString(true, otpPrefix) + m_seed + new ProtectedString(true, otpSuffix); } @@ -296,16 +333,20 @@ private void SetOTPAuthString(ProtectedString value) else if (hash == "sha512") Hash = KPOTPHash.SHA512; Length = MigrateInt(parameters.Get("digits"), 6); + string encoding = parameters.Get("encoding"); + if (!string.IsNullOrEmpty(encoding)) encoding = encoding.ToLowerInvariant(); + if (encoding == "base64") Encoding = KPOTPEncoding.BASE64; + else if (encoding == "hex") Encoding = KPOTPEncoding.HEX; + else if (encoding == "utf8") Encoding = KPOTPEncoding.UTF8; + string encoder = parameters.Get("encoder"); - if (!string.IsNullOrEmpty(encoder)) encoder = encoder.ToLowerInvariant(); - if (encoder == "base64") Encoding = KPOTPEncoding.BASE64; - else if (encoder == "hex") Encoding = KPOTPEncoding.HEX; - else if (encoder == "utf8") Encoding = KPOTPEncoding.UTF8; + KPOTPType tType = Type; + if (Enum.TryParse(encoder, true, out tType)) + Type = tType; string sIssuerParameter = parameters.Get("issuer"); if (!string.IsNullOrEmpty(sIssuerParameter)) Issuer = Decode(sIssuerParameter); - //Remove %3d / %3D at the end of the seed c = seed.ReadChars(); idx = c.Length - 3; @@ -453,7 +494,7 @@ private static TimeSpan GetTimeCorrection(string value) { if (!string.IsNullOrEmpty(value) && !bKeyFound) PluginDebug.AddError("OTP time correction", 0, "Invalid URL: " + value, "Time correction: " + TimeSpan.Zero.ToString()); - lock (m_timeCorrectionUrls) { m_timeCorrectionUrls[value] = TimeSpan.Zero; } + lock (m_timeCorrectionUrls) { m_timeCorrectionUrls[value] = TimeSpan.Zero; } return m_timeCorrectionUrls[value]; } @@ -551,10 +592,10 @@ public static bool Equals(KPOTP otp1, KPOTP otp2, string url, out bool OnlyCount if (!otp1.OTPSeed.Equals(otp2.OTPSeed, false)) return false; if (otp1.SanitizeChanged || otp2.SanitizeChanged) return false; - if (otp1.Encoding != otp2.Encoding) return false; - if (otp1.Hash != otp2.Hash) return false; - if (otp1.Type != otp2.Type) return false; - if (otp1.Length != otp2.Length) return false; + if (otp1.Encoding != otp2.Encoding) return false; + if (otp1.Hash != otp2.Hash) return false; + if (otp1.Type != otp2.Type) return false; + if (otp1.Length != otp2.Length) return false; if ((otp1.Type == KPOTPType.TOTP) && (otp1.TOTPTimestep != otp2.TOTPTimestep)) return false; if ((otp1.Type == KPOTPType.TOTP) && (otp1.TimeCorrectionUrlOwn != otp2.TimeCorrectionUrlOwn)) return false; if (otp1.TimeCorrectionUrlOwn && (otp1.Type == KPOTPType.TOTP)) diff --git a/src/KeePassOTPSetup.Designer.cs b/src/KeePassOTPSetup.Designer.cs index 3d5abee..7e9c372 100644 --- a/src/KeePassOTPSetup.Designer.cs +++ b/src/KeePassOTPSetup.Designer.cs @@ -144,7 +144,7 @@ private void InitializeComponent() this.tbOTPSeed.Location = new System.Drawing.Point(100, 26); this.tbOTPSeed.Name = "tbOTPSeed"; this.tbOTPSeed.Size = new System.Drawing.Size(400, 26); - this.tbOTPSeed.TabIndex = 1; + this.tbOTPSeed.TabIndex = 100; this.tbOTPSeed.Leave += new System.EventHandler(this.OnValueChanged); // // lSeed @@ -182,18 +182,18 @@ private void InitializeComponent() this.cbOTPFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbOTPFormat.FormattingEnabled = true; this.cbOTPFormat.Items.AddRange(new object[] { - "BASE32", - "BASE64", - "HEX", - "UTF8"}); - this.cbOTPFormat.Location = new System.Drawing.Point(100, 20); + "BASE32", + "BASE64", + "HEX", + "UTF8"}); + this.cbOTPFormat.Location = new System.Drawing.Point(100, 58); this.cbOTPFormat.Name = "cbOTPFormat"; this.cbOTPFormat.Size = new System.Drawing.Size(121, 28); - this.cbOTPFormat.TabIndex = 8; + this.cbOTPFormat.TabIndex = 230; // // lFormat // - this.lFormat.Location = new System.Drawing.Point(8, 26); + this.lFormat.Location = new System.Drawing.Point(8, 62); this.lFormat.Name = "lFormat"; this.lFormat.Size = new System.Drawing.Size(90, 23); this.lFormat.TabIndex = 9; @@ -201,15 +201,15 @@ private void InitializeComponent() // // tbTOTPTimestep // - this.tbTOTPTimestep.Location = new System.Drawing.Point(380, 58); + this.tbTOTPTimestep.Location = new System.Drawing.Point(380, 20); this.tbTOTPTimestep.Name = "tbTOTPTimestep"; this.tbTOTPTimestep.Size = new System.Drawing.Size(100, 26); - this.tbTOTPTimestep.TabIndex = 4; + this.tbTOTPTimestep.TabIndex = 210; this.tbTOTPTimestep.Leave += new System.EventHandler(this.OnValueChanged); // // lTimestep // - this.lTimestep.Location = new System.Drawing.Point(250, 62); + this.lTimestep.Location = new System.Drawing.Point(250, 24); this.lTimestep.Name = "lTimestep"; this.lTimestep.Size = new System.Drawing.Size(120, 23); this.lTimestep.TabIndex = 7; @@ -217,15 +217,15 @@ private void InitializeComponent() // // tbHOTPCounter // - this.tbHOTPCounter.Location = new System.Drawing.Point(380, 58); + this.tbHOTPCounter.Location = new System.Drawing.Point(380, 20); this.tbHOTPCounter.Name = "tbHOTPCounter"; this.tbHOTPCounter.Size = new System.Drawing.Size(100, 26); - this.tbHOTPCounter.TabIndex = 5; + this.tbHOTPCounter.TabIndex = 5220; this.tbHOTPCounter.TextChanged += new System.EventHandler(this.OnValueChanged); // // lCounter // - this.lCounter.Location = new System.Drawing.Point(250, 62); + this.lCounter.Location = new System.Drawing.Point(250, 26); this.lCounter.Name = "lCounter"; this.lCounter.Size = new System.Drawing.Size(120, 23); this.lCounter.TabIndex = 7; @@ -236,13 +236,13 @@ private void InitializeComponent() this.cbOTPHashFunc.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbOTPHashFunc.FormattingEnabled = true; this.cbOTPHashFunc.Items.AddRange(new object[] { - "SHA1", - "SHA256", - "SHA512"}); + "SHA1", + "SHA256", + "SHA512"}); this.cbOTPHashFunc.Location = new System.Drawing.Point(100, 134); this.cbOTPHashFunc.Name = "cbOTPHashFunc"; this.cbOTPHashFunc.Size = new System.Drawing.Size(121, 28); - this.cbOTPHashFunc.TabIndex = 7; + this.cbOTPHashFunc.TabIndex = 250; this.cbOTPHashFunc.SelectedIndexChanged += new System.EventHandler(this.OnValueChanged); // // cbOTPLength @@ -250,15 +250,15 @@ private void InitializeComponent() this.cbOTPLength.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbOTPLength.FormattingEnabled = true; this.cbOTPLength.Items.AddRange(new object[] { - "6", - "7", - "8", - "9", - "10"}); + "6", + "7", + "8", + "9", + "10"}); this.cbOTPLength.Location = new System.Drawing.Point(100, 96); this.cbOTPLength.Name = "cbOTPLength"; this.cbOTPLength.Size = new System.Drawing.Size(121, 28); - this.cbOTPLength.TabIndex = 6; + this.cbOTPLength.TabIndex = 240; this.cbOTPLength.SelectedIndexChanged += new System.EventHandler(this.OnValueChanged); // // cbOTPType @@ -266,12 +266,13 @@ private void InitializeComponent() this.cbOTPType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbOTPType.FormattingEnabled = true; this.cbOTPType.Items.AddRange(new object[] { - "HOTP", - "TOTP"}); - this.cbOTPType.Location = new System.Drawing.Point(100, 58); + "HOTP", + "TOTP", + "Steam"}); + this.cbOTPType.Location = new System.Drawing.Point(100, 20); this.cbOTPType.Name = "cbOTPType"; this.cbOTPType.Size = new System.Drawing.Size(121, 28); - this.cbOTPType.TabIndex = 3; + this.cbOTPType.TabIndex = 200; this.cbOTPType.SelectedIndexChanged += new System.EventHandler(this.OnValueChanged); // // lHash @@ -292,7 +293,7 @@ private void InitializeComponent() // // lType // - this.lType.Location = new System.Drawing.Point(6, 62); + this.lType.Location = new System.Drawing.Point(6, 24); this.lType.Name = "lType"; this.lType.Size = new System.Drawing.Size(90, 23); this.lType.TabIndex = 0; @@ -305,7 +306,7 @@ private void InitializeComponent() this.buttonOK.Location = new System.Drawing.Point(316, 486); this.buttonOK.Name = "buttonOK"; this.buttonOK.Size = new System.Drawing.Size(100, 30); - this.buttonOK.TabIndex = 10; + this.buttonOK.TabIndex = 400; this.buttonOK.Text = "OK"; this.buttonOK.UseVisualStyleBackColor = true; // @@ -316,7 +317,7 @@ private void InitializeComponent() this.buttonCancel.Location = new System.Drawing.Point(433, 486); this.buttonCancel.Name = "buttonCancel"; this.buttonCancel.Size = new System.Drawing.Size(100, 30); - this.buttonCancel.TabIndex = 11; + this.buttonCancel.TabIndex = 410; this.buttonCancel.Text = "Cancel"; this.buttonCancel.UseVisualStyleBackColor = true; // @@ -334,7 +335,7 @@ private void InitializeComponent() this.gTime.Size = new System.Drawing.Size(528, 120); this.gTime.TabIndex = 10; this.gTime.TabStop = false; - this.gTime.Text = "Time correction - TOTP only"; + this.gTime.Text = "Time correction - TOTP && Steam only"; // // totpTimeCorrectionValue // @@ -368,7 +369,7 @@ private void InitializeComponent() this.totpTimeCorrectionType.Location = new System.Drawing.Point(100, 29); this.totpTimeCorrectionType.Name = "totpTimeCorrectionType"; this.totpTimeCorrectionType.Size = new System.Drawing.Size(400, 28); - this.totpTimeCorrectionType.TabIndex = 8; + this.totpTimeCorrectionType.TabIndex = 300; this.totpTimeCorrectionType.SelectedIndexChanged += new System.EventHandler(this.OnValueChanged); // // tbTOTPTimeCorrectionURL @@ -376,7 +377,7 @@ private void InitializeComponent() this.tbTOTPTimeCorrectionURL.Location = new System.Drawing.Point(100, 63); this.tbTOTPTimeCorrectionURL.Name = "tbTOTPTimeCorrectionURL"; this.tbTOTPTimeCorrectionURL.Size = new System.Drawing.Size(400, 26); - this.tbTOTPTimeCorrectionURL.TabIndex = 9; + this.tbTOTPTimeCorrectionURL.TabIndex = 310; // // lURL // diff --git a/src/KeePassOTPSetup.cs b/src/KeePassOTPSetup.cs index 276677f..13f1703 100644 --- a/src/KeePassOTPSetup.cs +++ b/src/KeePassOTPSetup.cs @@ -100,7 +100,7 @@ private void InitSettings(bool bCheckAdvancedMode) private bool SettingsChanged() { - return !KPOTP.Equals(OTP, m_OTPInitial); + return !KPOTP.Equals(OTP, m_OTPInitial); } private void UpdatePreview() @@ -111,8 +111,7 @@ private void UpdatePreview() OTP.OTPAuthString = new ProtectedString(true, tbOTPSeed.Text); InitSettings(true); } - else - OTP.OTPSeed = new ProtectedString(true, tbOTPSeed.Text); + else OTP.OTPSeed = new ProtectedString(true, tbOTPSeed.Text); if (cbOTPFormat.SelectedIndex == 0) OTP.Encoding = KPOTPEncoding.BASE32; if (cbOTPFormat.SelectedIndex == 1) OTP.Encoding = KPOTPEncoding.BASE64; @@ -130,13 +129,27 @@ private void UpdatePreview() if (cbOTPHashFunc.SelectedIndex == 2) OTP.Hash = KPOTPHash.SHA512; if (cbOTPType.SelectedIndex == 0) OTP.Type = KPOTPType.HOTP; - if (cbOTPType.SelectedIndex == 1) OTP.Type = KPOTPType.TOTP; + else if (cbOTPType.SelectedIndex == 1) OTP.Type = KPOTPType.TOTP; + else if (cbOTPType.SelectedIndex == 2) OTP.Type = KPOTPType.STEAM; pbTOTPLifetime.Maximum = OTP.TOTPTimestep; pbTOTPLifetime.Value = OTP.RemainingSeconds; - gTime.Enabled = pbTOTPLifetime.Visible = tbTOTPTimestep.Visible = lTimestep.Visible = OTP.Type == KPOTPType.TOTP; + gTime.Enabled = tbTOTPTimestep.Visible = lTimestep.Visible = OTP.Type == KPOTPType.TOTP; + pbTOTPLifetime.Visible = OTP.Type != KPOTPType.HOTP; tbHOTPCounter.Visible = lCounter.Visible = OTP.Type == KPOTPType.HOTP; + cbOTPLength.Enabled = OTP.Type != KPOTPType.STEAM; + if (OTP.Type == KPOTPType.STEAM) + { + if (!cbOTPLength.Items.Contains("5")) cbOTPLength.Items.Add("5"); + cbOTPLength.SelectedIndex = cbOTPLength.Items.Count - 1; + } + else if (cbOTPLength.Items.Contains("5")) + { + cbOTPLength.Items.RemoveAt(cbOTPLength.Items.Count - 1); + cbOTPLength.SelectedIndex = 0; + } + if (!tbTOTPTimeCorrectionURL.Focused) { if (totpTimeCorrectionType.SelectedIndex == 0) @@ -168,7 +181,7 @@ private void UpdatePreview() string otpValue = OTP.Valid ? OTP.ReadableOTP(OTP.GetOTP(false, true)) : PluginTranslate.Error; otpPreview.Text = "OTP: " + (string.IsNullOrEmpty(otpValue) ? "N/A" : otpValue); - if ((OTP.Type == KPOTPType.TOTP) && OTP.RemainingSeconds <= 5) + if ((OTP.Type != KPOTPType.HOTP) && OTP.RemainingSeconds <= Config.TOTPSoonExpiring) { otpPreview.ForeColor = System.Drawing.Color.Red; pbTOTPLifetime.ForeColor = System.Drawing.Color.Red; diff --git a/src/Migration.cs b/src/Migration.cs index 16f8495..a77b280 100644 --- a/src/Migration.cs +++ b/src/Migration.cs @@ -112,7 +112,7 @@ protected void IncreaseLogger() m_EntryIndex++; uint percentage = (uint)(100 * m_EntryIndex / m_EntryCount); m_sl.SetProgress(percentage); - m_sl.SetText(percentage.ToString() +"% - " + m_EntryIndex.ToString() + " / " + m_EntryCount.ToString(), LogStatusType.Info); + m_sl.SetText(percentage.ToString() + "% - " + m_EntryIndex.ToString() + " / " + m_EntryCount.ToString(), LogStatusType.Info); } protected void EndLogger() @@ -295,14 +295,24 @@ public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, public class MigrationTraytotp : MigrationBase { - private const string OtherPluginPlaceholder = "{TOTP}"; + private string m_OtherPluginPlaceholder = "TOTP"; + private string m_TOTP_Seed = "TOTP Seed"; + private string m_TOTP_Settings = "TOTP Settings"; + + public MigrationTraytotp() + { + m_OtherPluginPlaceholder = "{" + KeePass.Program.Config.CustomConfig.GetString("autotype_fieldname", m_OtherPluginPlaceholder) + "}"; + m_TOTP_Seed = KeePass.Program.Config.CustomConfig.GetString("totpseed_stringname", m_TOTP_Seed); + m_TOTP_Settings = KeePass.Program.Config.CustomConfig.GetString("totpsettings_stringname", m_TOTP_Settings); + } + public override void MigrateToKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = -1; if (!m_bInitialized) return; EntriesOverall = EntriesMigrated = 0; - List lEntries = m_db.RootGroup.GetEntries(true).Where(x => x.Strings.Exists("TOTP Seed")).ToList(); + List lEntries = m_db.RootGroup.GetEntries(true).Where(x => x.Strings.Exists(m_TOTP_Seed)).ToList(); EntriesOverall = lEntries.Count; if (lEntries.Count == 0) return; @@ -314,8 +324,8 @@ public override void MigrateToKeePassOTP(bool bRemove, out int EntriesOverall, o foreach (PwEntry pe in lEntries) { IncreaseLogger(); - string seed = pe.Strings.ReadSafe("TOTP Seed"); - string settings = pe.Strings.ReadSafe("TOTP Settings"); + string seed = pe.Strings.ReadSafe(m_TOTP_Seed); + string settings = pe.Strings.ReadSafe(m_TOTP_Settings); if (string.IsNullOrEmpty(settings)) { PluginDebug.AddError("Migration of entry failed", @@ -334,15 +344,19 @@ public override void MigrateToKeePassOTP(bool bRemove, out int EntriesOverall, o var otp = OTPDAO.GetOTP(pe); otp.OTPSeed = new ProtectedString(true, MigrateString(seed)); otp.TOTPTimestep = MigrateInt(parameters[0], 30); - int l = MigrateInt(parameters[1], -1); - if (l == -1) + if (parameters[1].ToLowerInvariant() == "s") otp.Type = KPOTPType.STEAM; + else { - PluginDebug.AddError("Migration of entry failed", - "Uuid: " + pe.Uuid.ToHexString(), - "OTP data: " + settings); - continue; + int l = MigrateInt(parameters[1], -1); + if (l == -1) + { + PluginDebug.AddError("Migration of entry failed", + "Uuid: " + pe.Uuid.ToHexString(), + "OTP data: " + settings); + continue; + } + otp.Length = l; } - otp.Length = l; if ((parameters.Count() > 2) && !string.IsNullOrEmpty(parameters[2])) otp.TimeCorrectionUrl = parameters[2]; if (otp.Valid) @@ -356,8 +370,8 @@ public override void MigrateToKeePassOTP(bool bRemove, out int EntriesOverall, o finally { handler.IgnoreBuffer = false; } if (bRemove) { - pe.Strings.Remove("TOTP Seed"); - pe.Strings.Remove("TOTP Settings"); + pe.Strings.Remove(m_TOTP_Seed); + pe.Strings.Remove(m_TOTP_Settings); } } else @@ -381,7 +395,7 @@ public override void MigrateToKeePassOTP(bool bRemove, out int EntriesOverall, o { EndLogger(); } - MigratePlaceholder(OtherPluginPlaceholder, Config.Placeholder, false); + MigratePlaceholder(m_OtherPluginPlaceholder, Config.Placeholder, false); } public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) @@ -420,20 +434,20 @@ public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, "Hash not supported: " + otp.Hash.ToString()); continue; } - if (otp.Type != KPOTPType.TOTP) + if (otp.Type == KPOTPType.HOTP) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Type not supported: " + otp.Type.ToString()); continue; } - string settings = otp.TOTPTimestep.ToString() + ";" + otp.Length.ToString(); + string settings = otp.TOTPTimestep.ToString() + ";" + (otp.Type == KPOTPType.TOTP ? otp.Length.ToString() : "S"); if (otp.TimeCorrectionUrlOwn) settings += ";" + pe.Strings.ReadSafe(PwDefs.UrlField); else if (!string.IsNullOrEmpty(otp.TimeCorrectionUrl)) settings += ";" + otp.TimeCorrectionUrl; - pe.Strings.Set("TOTP Seed", otp.OTPSeed); - pe.Strings.Set("TOTP Settings", new ProtectedString(false, settings)); + pe.Strings.Set(m_TOTP_Seed, otp.OTPSeed); + pe.Strings.Set(m_TOTP_Settings, new ProtectedString(false, settings)); EntriesMigrated++; if (bRemove) { @@ -448,7 +462,7 @@ public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, } } finally { EndLogger(); } - MigratePlaceholder(Config.Placeholder, OtherPluginPlaceholder, false); + MigratePlaceholder(Config.Placeholder, m_OtherPluginPlaceholder, false); } } } diff --git a/src/PluginTranslation.cs b/src/PluginTranslation.cs index bf30e41..374aa62 100644 --- a/src/PluginTranslation.cs +++ b/src/PluginTranslation.cs @@ -52,7 +52,7 @@ public static class PluginTranslate public static readonly string OTPHash = @"Hash:"; public static readonly string OTPTimestep = @"Timestep:"; public static readonly string OTPCounter = @"Counter:"; - public static readonly string TimeCorrection = @"Time correction - TOTP only"; + public static readonly string TimeCorrection = @"Time correction - TOTP && Steam only"; public static readonly string URL = @"URL: "; public static readonly string TimeDiff = @"Diff: "; public static readonly string TimeCorrectionOff = @"No time correction"; diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs index 1146522..f592836 100644 --- a/src/Properties/AssemblyInfo.cs +++ b/src/Properties/AssemblyInfo.cs @@ -7,7 +7,7 @@ // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle ("KeePassOTP")] -[assembly: AssemblyDescription("Adds TOTP and HOTP functionality")] +[assembly: AssemblyDescription("Adds TOTP, HOTP & Steam OTP functionality")] [assembly: AssemblyConfiguration ("")] [assembly: AssemblyCompany ("rookiestyle")] [assembly: AssemblyProduct ("KeePass Plugin")] @@ -30,5 +30,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.15.1")] -[assembly: AssemblyFileVersion("0.15.1")] +[assembly: AssemblyVersion("0.16")] +[assembly: AssemblyFileVersion("0.16")] diff --git a/src/Util.cs b/src/Util.cs index 582bbf0..1343dfe 100644 --- a/src/Util.cs +++ b/src/Util.cs @@ -20,6 +20,8 @@ internal static class Config internal const string DBUsage = "KeePassOTP.UseDBForOTPSeeds"; internal const string DBPreload = "KeePassOTP.PreloadOTP"; + internal const int TOTPSoonExpiring = 5; + private const string Config_CheckTFA = "KeePassOTP.CheckTFA"; private const string Config_Hotkey = "KeePassOTP.Hotkey"; private const string Config_Placeholder = "KeePassOTP.Placeholder"; diff --git a/version.info b/version.info index c097a85..b4d2f55 100644 --- a/version.info +++ b/version.info @@ -1,5 +1,5 @@ : -KeePassOTP:0.15.1 -KeePassOTP!de:9 -KeePassOTP!fr:2 +KeePassOTP:0.16 +KeePassOTP!de:10 +KeePassOTP!fr:3 :