diff --git a/.gitignore b/.gitignore index defecbd..3bd6e85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ Password\ Manager/bin Password\ Manager/obj .vs/ +Password\ Manager/PasswordManagerForm.resx diff --git a/.vs/Password Manager/DesignTimeBuild/.dtbcache.v2 b/.vs/Password Manager/DesignTimeBuild/.dtbcache.v2 index b6703d9..6b2ed91 100644 Binary files a/.vs/Password Manager/DesignTimeBuild/.dtbcache.v2 and b/.vs/Password Manager/DesignTimeBuild/.dtbcache.v2 differ diff --git a/.vs/Password Manager/v17/.suo b/.vs/Password Manager/v17/.suo index 22215e2..5991f33 100644 Binary files a/.vs/Password Manager/v17/.suo and b/.vs/Password Manager/v17/.suo differ diff --git a/Password Manager/MainForm.Designer.cs b/Password Manager/MainForm.Designer.cs index 2f7fbb8..f7b2773 100644 --- a/Password Manager/MainForm.Designer.cs +++ b/Password Manager/MainForm.Designer.cs @@ -1,6 +1,6 @@ namespace Password_Manager { - partial class MainForm + sealed partial class MainForm : PasswordManagerForm { /// /// Required designer variable. @@ -28,9 +28,9 @@ /// private void InitializeComponent() { - searchBox = new TextBox(); - resultList = new PasswordListBox(); - profileSelection = new ComboBox(); + SearchBox = new TextBox(); + ResultList = new PasswordListBox(); + ProfileSelection = new ComboBox(); addProfile = new Button(); removeProfile = new Button(); generatePassword = new Button(); @@ -38,82 +38,82 @@ // // searchBox // - searchBox.Location = new Point(10, 20); - searchBox.Margin = new Padding(3, 2, 3, 2); - searchBox.Name = "searchBox"; - searchBox.PlaceholderText = "Search for a password"; - searchBox.Size = new Size(225, 23); - searchBox.TabIndex = 0; - searchBox.TextChanged += resultList.ReloadResults; + SearchBox.Location = new Point(10, 20); + SearchBox.Margin = new Padding(3, 2, 3, 2); + SearchBox.Name = "searchBox"; + SearchBox.PlaceholderText = "Search for a password"; + SearchBox.Size = new Size(225, 23); + SearchBox.TabIndex = 0; + SearchBox.TextChanged += ResultList.ReloadResults; // // resultList // - resultList.FormattingEnabled = true; - resultList.ItemHeight = 15; - resultList.Location = new Point(10, 45); - resultList.Margin = new Padding(3, 2, 3, 2); - resultList.Name = "resultList"; - resultList.Size = new Size(225, 274); - resultList.TabIndex = 1; - resultList.CurrentProfilePathRequest += CurrentProfilePathRequest; - resultList.SearchQueryRequest += () => searchBox.Text; + ResultList.FormattingEnabled = true; + ResultList.ItemHeight = 15; + ResultList.Location = new Point(10, 45); + ResultList.Margin = new Padding(3, 2, 3, 2); + ResultList.Name = "resultList"; + ResultList.Size = new Size(225, 274); + ResultList.TabIndex = 1; + ResultList.CurrentProfilePathRequest += () => CurrentProfilePathRequest(); + ResultList.SearchQueryRequest += () => SearchBox.Text; // // profileSelection // - profileSelection.DisplayMember = "Name"; - profileSelection.DropDownHeight = 100; - profileSelection.DropDownWidth = 200; - profileSelection.FormattingEnabled = true; - profileSelection.IntegralHeight = false; - profileSelection.Location = new Point(513, 20); - profileSelection.Margin = new Padding(3, 2, 3, 2); - profileSelection.Name = "profileSelection"; - profileSelection.Size = new Size(176, 23); - profileSelection.TabIndex = 2; - profileSelection.SelectionChangeCommitted += ChangeProfile; + ProfileSelection.DisplayMember = "Name"; + ProfileSelection.DropDownHeight = 100; + ProfileSelection.DropDownWidth = 176; + ProfileSelection.FormattingEnabled = true; + ProfileSelection.IntegralHeight = false; + ProfileSelection.Location = new Point(513, 20); + ProfileSelection.Margin = new Padding(3, 2, 3, 2); + ProfileSelection.Name = "profileSelection"; + ProfileSelection.Size = new Size(176, 23); + ProfileSelection.TabIndex = 2; + ProfileSelection.SelectionChangeCommitted += ChangeProfile; // // addProfile // - addProfile.Location = new Point(513, 45); - addProfile.Margin = new Padding(3, 2, 3, 2); - addProfile.Name = "addProfile"; - addProfile.Size = new Size(83, 22); - addProfile.TabIndex = 3; - addProfile.Text = "Add"; - addProfile.UseVisualStyleBackColor = true; - addProfile.Click += AddProfile; + AddProfile.Location = new Point(513, 45); + AddProfile.Margin = new Padding(3, 2, 3, 2); + AddProfile.Name = "addProfile"; + AddProfile.Size = new Size(83, 22); + AddProfile.TabIndex = 3; + AddProfile.Text = "Add"; + AddProfile.UseVisualStyleBackColor = true; + AddProfile.Click += OpenProfileCreator; // // removeProfile // - removeProfile.Location = new Point(605, 45); - removeProfile.Margin = new Padding(3, 2, 3, 2); - removeProfile.Name = "removeProfile"; - removeProfile.Size = new Size(83, 22); - removeProfile.TabIndex = 4; - removeProfile.Text = "Delete"; - removeProfile.UseVisualStyleBackColor = true; + DeleteProfile.Location = new Point(605, 45); + DeleteProfile.Margin = new Padding(3, 2, 3, 2); + DeleteProfile.Name = "removeProfile"; + DeleteProfile.Size = new Size(83, 22); + DeleteProfile.TabIndex = 4; + DeleteProfile.Text = "Delete"; + DeleteProfile.UseVisualStyleBackColor = true; // // button1 // - generatePassword.Location = new Point(241, 20); - generatePassword.Name = "button1"; - generatePassword.Size = new Size(75, 23); - generatePassword.TabIndex = 5; - generatePassword.Text = "Generate"; - generatePassword.UseVisualStyleBackColor = true; - generatePassword.Click += Generate; + GeneratePassword.Location = new Point(241, 20); + GeneratePassword.Name = "button1"; + GeneratePassword.Size = new Size(75, 23); + GeneratePassword.TabIndex = 5; + GeneratePassword.Text = "Generate"; + GeneratePassword.UseVisualStyleBackColor = true; + GeneratePassword.Click += OpenPasswordGenerator; // // MainForm // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; ClientSize = new Size(700, 338); - Controls.Add(generatePassword); - Controls.Add(removeProfile); - Controls.Add(addProfile); - Controls.Add(profileSelection); - Controls.Add(resultList); - Controls.Add(searchBox); + Controls.Add(GeneratePassword); + Controls.Add(DeleteProfile); + Controls.Add(AddProfile); + Controls.Add(ProfileSelection); + Controls.Add(ResultList); + Controls.Add(SearchBox); Margin = new Padding(3, 2, 3, 2); Name = "MainForm"; Text = "Password Manager"; @@ -123,11 +123,11 @@ #endregion - private TextBox searchBox; - private PasswordListBox resultList; - private ComboBox profileSelection; - private Button addProfile; - private Button removeProfile; - private Button generatePassword; + protected override TextBox SearchBox { get; } + protected override PasswordListBox ResultList { get; } + protected override ComboBox ProfileSelection { get; } + protected override Button AddProfile { get; } + protected override Button DeleteProfile { get; } + protected override Button GeneratePassword { get; } } } \ No newline at end of file diff --git a/Password Manager/MainForm.cs b/Password Manager/MainForm.cs index 0bdf045..97c0c25 100644 --- a/Password Manager/MainForm.cs +++ b/Password Manager/MainForm.cs @@ -1,61 +1,43 @@ namespace Password_Manager { - public delegate void ProfileChanges(string profileName); - public delegate string[] ProfileList(); - public delegate void Save(); - public partial class MainForm : Form + sealed public partial class MainForm : PasswordManagerForm { - public event ProfileDataRequest? CurrentProfilePathRequest; - public event ProfileDataRequest? CurrentProfileNameRequest; - public event ProfileList? CurrentProfileListRequest; - public event ProfileChanges? CurrentProfileChanged; - public event Save? SaveRequest; + public override event ProfileDataRequest CurrentProfilePathRequest; + public override event ProfileDataRequest CurrentProfileNameRequest; + public override event ProfileList CurrentProfileListRequest; + public override event ProfileChange CurrentProfileChanged; + public override event Save SaveRequest; + public override event NewProfile NewProfileRequest; - public MainForm(ProfileDataRequest CurrentProfileNameRequest, ProfileDataRequest CurrentProfilePathRequest, ProfileList CurrentProfileListRequest, ProfileChanges CurrentProfileChanged) + public MainForm(ProfileDataRequest CurrentProfileNameRequest, ProfileDataRequest CurrentProfilePathRequest, ProfileList CurrentProfileListRequest, ProfileChange CurrentProfileChanged, Save SaveRequest, NewProfile NewProfileRequest) + : base(CurrentProfileNameRequest, CurrentProfilePathRequest, CurrentProfileListRequest, CurrentProfileChanged, SaveRequest, NewProfileRequest) { - this.CurrentProfileNameRequest = CurrentProfileNameRequest; - this.CurrentProfilePathRequest = CurrentProfilePathRequest; - this.CurrentProfileListRequest = CurrentProfileListRequest; - this.CurrentProfileChanged = CurrentProfileChanged; InitializeComponent(); - LoadCurrentProfile(); - - foreach (string s in CurrentProfileListRequest?.Invoke()) - { - profileSelection.Items.Add(s); - } - profileSelection.SelectedIndex = 0; - - SaveRequest?.Invoke(); + RefreshCurrentProfile(); + SaveRequest(); } - private void LoadCurrentProfile() - { - this.Text = CurrentProfileNameRequest?.Invoke(); - resultList.ReloadResults(); - } - - private void ChangeProfile(object sender, EventArgs e) - { - CurrentProfileChanged?.Invoke(profileSelection.Text); - - foreach (string s in CurrentProfileListRequest?.Invoke()) - { - profileSelection.Items.Add(s); - } - } - - private void AddProfile(object sender, EventArgs e) + private void OpenProfileCreator(object sender, EventArgs e) { NewProfileForm npf = new NewProfileForm(); - npf.ReloadPasswordsRequest += () => resultList.ReloadResults(); - npf.Show(); + npf.ReloadMainFormRequest += () => RefreshCurrentProfile(); + npf.SaveRequest += this.SaveRequest; + npf.NewProfileRequest += this.NewProfileRequest; + npf.ShowDialog(); } - private void Generate(object sender, EventArgs e) + private void OpenPasswordGenerator(object sender, EventArgs e) { - GeneratePassword gp = new GeneratePassword(searchBox.Text, CurrentProfilePathRequest?.Invoke()); - gp.Show(); + string? tmp = CurrentProfilePathRequest(); + if (tmp != null) + { + GeneratePassword gp = new GeneratePassword(SearchBox.Text, tmp); + gp.ShowDialog(); + } + else + { + MessageBox.Show("No path specified", "Event error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } } } \ No newline at end of file diff --git a/Password Manager/NewProfileForm.cs b/Password Manager/NewProfileForm.cs index f3d1222..4bb854e 100644 --- a/Password Manager/NewProfileForm.cs +++ b/Password Manager/NewProfileForm.cs @@ -1,14 +1,16 @@ namespace Password_Manager { - public delegate void NewProfile(string profileName, string profilePath); public delegate void ReloadPasswords(); public partial class NewProfileForm : Form { - public event NewProfile NewProfileRequest; - public event ReloadPasswords ReloadPasswordsRequest; + public event NewProfile? NewProfileRequest; + public event ReloadPasswords? ReloadMainFormRequest; + public event Save? SaveRequest; public NewProfileForm() { + //test + MessageBox.Show(this.Parent.Text, this.Parent.Text); InitializeComponent(); } @@ -26,13 +28,15 @@ if (nameTextBox.Text != "" && pathTextBox.Text != "") { NewProfileRequest?.Invoke(nameTextBox.Text, pathTextBox.Text); - ReloadPasswordsRequest?.Invoke(); + ReloadMainFormRequest?.Invoke(); this.Close(); } else { MessageBox.Show("You must fill in all fields to continue.", "Error: Empty fields", MessageBoxButtons.OK, MessageBoxIcon.Error); } + + SaveRequest?.Invoke(); } private void Cancel(object sender, EventArgs e) diff --git a/Password Manager/Password Manager.csproj.user b/Password Manager/Password Manager.csproj.user index b307696..f096714 100644 --- a/Password Manager/Password Manager.csproj.user +++ b/Password Manager/Password Manager.csproj.user @@ -13,5 +13,8 @@ Component + + Form + \ No newline at end of file diff --git a/Password Manager/PasswordManagerForm.cs b/Password Manager/PasswordManagerForm.cs new file mode 100644 index 0000000..c7e22a0 --- /dev/null +++ b/Password Manager/PasswordManagerForm.cs @@ -0,0 +1,61 @@ +namespace Password_Manager +{ + public delegate void ProfileChange(string profileName); //Fires when we want to change the CurrentProfile field of ProfileHandler based on the combobox selection + public delegate string[] ProfileList(); //Fires when we need a list of Profile names, like for the combobox items + public delegate void Save(); //Fire whenever we want to save the current state of profiles + public delegate void NewProfile(string profileName, string profilePath); //Fires whenever a NewProfileForm has requested the creation of a new profile. This just forwards that request to ProfileHandler + + public abstract class PasswordManagerForm : Form + { + protected abstract ComboBox ProfileSelection { get; } + protected abstract PasswordListBox ResultList { get; } + protected abstract TextBox SearchBox { get; } + protected abstract Button AddProfile { get; } + protected abstract Button DeleteProfile { get; } + protected abstract Button GeneratePassword { get; } + + public abstract event ProfileDataRequest CurrentProfilePathRequest; + public abstract event ProfileDataRequest CurrentProfileNameRequest; + public abstract event ProfileList CurrentProfileListRequest; + public abstract event ProfileChange CurrentProfileChanged; + public abstract event Save SaveRequest; + public abstract event NewProfile NewProfileRequest; + + public PasswordManagerForm( + ProfileDataRequest CurrentProfileNameRequest, + ProfileDataRequest CurrentProfilePathRequest, + ProfileList CurrentProfileListRequest, + ProfileChange CurrentProfileChanged, + Save SaveRequest, + NewProfile NewProfileRequest) + { + this.CurrentProfileNameRequest = CurrentProfileNameRequest; + this.CurrentProfilePathRequest = CurrentProfilePathRequest; + this.CurrentProfileListRequest = CurrentProfileListRequest; + this.CurrentProfileChanged = CurrentProfileChanged; + this.SaveRequest = SaveRequest; + this.NewProfileRequest = NewProfileRequest; + } + + protected virtual void ChangeProfile(object sender, EventArgs e) + { + CurrentProfileChanged(ProfileSelection.Text); + } + + public virtual void RefreshCurrentProfile() + { + ProfileSelection.SelectedIndex = -1; + string[] items = CurrentProfileListRequest(); + for (int i = 0; i < items.Length; i++) + { + ProfileSelection.Items.Add(items[i]); + if (items[i] == CurrentProfileNameRequest()) + { + ProfileSelection.SelectedIndex = i; + } + } + this.Text = CurrentProfileNameRequest(); + ResultList.ReloadResults(); + } + } +} diff --git a/Password Manager/Profiles/IList.cs b/Password Manager/Profiles/IList.cs index 0d89055..bfba39f 100644 --- a/Password Manager/Profiles/IList.cs +++ b/Password Manager/Profiles/IList.cs @@ -1,6 +1,8 @@ -namespace Profiles +using System.Collections; + +namespace Profiles { - abstract class IList + abstract class IList : IEnumerable { protected T[] list; @@ -32,5 +34,15 @@ { list = new T[0]; } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)list).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return list.GetEnumerator(); + } } } diff --git a/Password Manager/Profiles/ProfileHandler.cs b/Password Manager/Profiles/ProfileHandler.cs index d14d3f2..df0fc6b 100644 --- a/Password Manager/Profiles/ProfileHandler.cs +++ b/Password Manager/Profiles/ProfileHandler.cs @@ -7,11 +7,23 @@ namespace Profiles { public static Profile CurrentProfile; public static ProfileList ListOfProfiles; - private static string filePath = SpecialDirectories.CurrentUserApplicationData + "Profiles.csv"; + private static string filePath = SpecialDirectories.CurrentUserApplicationData + "\\Profiles.csv"; + + public static void AddProfile(string profileName, string profilePath) + { + ListOfProfiles.Add(new Profile(profileName, profilePath)); + ChangeProfiles(profileName); + } public static void ChangeProfiles(string profileName) { - CurrentProfile = ListOfProfiles.SearchByName(profileName); + try + { + CurrentProfile = ListOfProfiles.SearchByName(profileName); + } catch (ProfileNotFoundException) + { + MessageBox.Show("The selected profile cannot be found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } public static void Init() @@ -20,14 +32,14 @@ namespace Profiles if (File.Exists(filePath)) { - LoadProfiles(); + LoadProfilesFile(); } else { - CreateProfiles(); + CreateProfilesFile(); } } - private static void LoadProfiles() + private static void LoadProfilesFile() { try { @@ -43,7 +55,7 @@ namespace Profiles { //File is messed up, creating new one sr.Close(); - CreateProfiles(); + CreateProfilesFile(); break; } } @@ -56,11 +68,53 @@ namespace Profiles private static void TrimLastLine() { - List lines = File.ReadAllLines(filePath).ToList(); - File.WriteAllLines(filePath, lines.GetRange(0, lines.Count - 1).ToArray()); + try + { + StreamReader sr = new StreamReader(filePath); + List validLines = new List(); + + while (!sr.EndOfStream) + { + string? line = sr.ReadLine(); + if (line != null) + { + validLines.Add(line); + } + } + + sr.Close(); + File.WriteAllLines(filePath, validLines); + } catch (IOException e) + { + MessageBox.Show(e.ToString(), "IO Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } catch (UnauthorizedAccessException e) + { + MessageBox.Show(e.ToString(), "Can't access profiles file", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } - private static void CreateProfiles() + public static void SaveProfiles() + { + try + { + StreamWriter sw = new StreamWriter(filePath); + + foreach (Profile p in ListOfProfiles) + { + sw.WriteLine($"{p.Name},{p.Path}"); + } + + sw.Close(); + } catch (IOException e) + { + MessageBox.Show(e.ToString(), "IO Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } catch (UnauthorizedAccessException e) + { + MessageBox.Show(e.ToString(), "Can't access profiles file", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private static void CreateProfilesFile() { try { @@ -69,10 +123,9 @@ namespace Profiles string[] parameters = new string[2]; NewProfileForm np = new NewProfileForm(); - Profile firstProfile = null; np.NewProfileRequest += (string profileName, string profilePath) => { - firstProfile = new Profile(profileName, profilePath); + Profile firstProfile = new Profile(profileName, profilePath); ListOfProfiles.Add(firstProfile); ChangeProfiles(firstProfile.Name); sw.WriteLine($"{firstProfile.Name},{firstProfile.Path}"); diff --git a/Password Manager/Profiles/ProfileList.cs b/Password Manager/Profiles/ProfileList.cs index ee8073e..5bc1a3c 100644 --- a/Password Manager/Profiles/ProfileList.cs +++ b/Password Manager/Profiles/ProfileList.cs @@ -38,7 +38,7 @@ public override Profile SearchByName(string name) { - Profile result = null; + Profile? result = null; for (int i = 0; i < this.Length; i++) { diff --git a/Password Manager/Program.cs b/Password Manager/Program.cs index 6e90c91..5105163 100644 --- a/Password Manager/Program.cs +++ b/Password Manager/Program.cs @@ -2,7 +2,7 @@ using Profiles; namespace Password_Manager { - public delegate string ProfileDataRequest(); + public delegate string ProfileDataRequest(); //Fire whenever a specific field of ProfileHandler.CurrentProfile is needed internal static class Program { /// @@ -13,7 +13,6 @@ namespace Password_Manager { ApplicationConfiguration.Initialize(); ProfileHandler.Init(); - Application.Run(mainForm); } @@ -21,7 +20,9 @@ namespace Password_Manager () => ProfileHandler.CurrentProfile.Name, () => ProfileHandler.CurrentProfile.Path, () => ProfileHandler.ListOfProfiles.GetNameList(), - (profileName) => ProfileHandler.ChangeProfiles(profileName) + (profileName) => ProfileHandler.ChangeProfiles(profileName), + () => ProfileHandler.SaveProfiles(), + (profileName, profilePath) => ProfileHandler.AddProfile(profileName, profilePath) ); //needed at creation so that MainForm may pass this method down to other classes in its constructor } } \ No newline at end of file