-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
WordListsForm.cs
281 lines (248 loc) · 8.97 KB
/
WordListsForm.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using KeePass.UI;
namespace KeePassDiceware
{
/// <summary>
/// Class <c>WordListsForms</c> represents a form that allows user to add, modify and remove dictionaries.
/// </summary>
public partial class WordListsForm : Form
{
/// <value>Property <c>Result</c> represents the state of list after closing of the form.</value>
/// <remarks>
/// Contains modifications even if the form was closed with <c>DialogResult.Cancel</c> status.
/// In such cases the <c>Result</c> property should be considered invalid.
/// </remarks>
public List<WordList> Result { get; private set; } = null;
/// <value>Property <c>_wordListsBindingList</c> is a binding list on top of <c>Result</c> used inside <c>WordListDataGridView</c>.</value>
private BindingList<WordList> _wordListsBindingList;
/// <summary>
/// Creates a form with a initial wordlists contianed inside <paramref name="wordLists"/>.
/// </summary>
/// <param name="wordLists"> initial list of configured WordLists.</param>
public WordListsForm(List<WordList> wordLists)
{
InitializeComponent();
PopulateWordLists(wordLists);
}
/// <summary>
/// Load handeler. Registers window inside Keepass <c>GlobalWindowManager</c>.
/// </summary>
/// <param name="EventArgs"> OnLoad event arguments</param>
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
GlobalWindowManager.AddWindow(this);
}
/// <summary>
/// Unload handeler. Deregisters window inside Keepass <c>GlobalWindowManager</c>.
/// </summary>
/// <param name="EventArgs"> OnClosed event arguments</param>
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
GlobalWindowManager.RemoveWindow(this);
}
/// <summary>
/// Handles <c>OkButton</c> button press. Closes form with result <c>DialogResult.OK</c>.
/// </summary>
/// <param name="sender"> sender of click event</param>
/// <param name="e"> eventargs of click event</param>
private void OkButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
Close();
}
/// <summary>
/// Handles <c>CancelButton</c> button press. Closes form with result <c>DialogResult.Cancel</c>.
/// </summary>
/// <param name="sender"> sender of click event</param>
/// <param name="e"> eventargs of click event</param>
private void CancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
/// <summary>
/// Populates <c>WordListDataGridView</c> with WordLists inside <paramref name="wordLists"/> parameter.
/// </summary>
/// <param name="wordLists"> word lists to render</param>
internal void PopulateWordLists(List<WordList> wordLists)
{
Result = wordLists.ConvertAll(wl => (WordList)wl.Clone());
_wordListsBindingList = new(Result);
WordListDataGridView.DataSource = _wordListsBindingList;
}
/// <summary>
/// Populates <c>WordListDataGridView</c> with default WordLists values.
/// </summary>
/// <param name="sender"> sender of click event</param>
/// <param name="e"> eventargs of click event</param>
private void RestoreDefaultsButton_Click(object sender, EventArgs e)
{
PopulateWordLists(WordListEmbeded.Default);
}
/// <summary>
/// Validates modified row in <c>WordListDataGridView</c>.
/// </summary>
/// <param name="sender"> sender of cell event</param>
/// <param name="e"> eventargs of cell event</param>
private void WordListDataGridView_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
{
DataGridViewRow row = WordListDataGridView.Rows[e.RowIndex];
if (row.DataBoundItem is WordList wl)
{
row.ErrorText = string.Empty;
e.Cancel = false;
// Validate name
if (Result.Count(cwl => cwl.Key == wl.Key) >= 2)
{
row.ErrorText += "This wordlists's name is too similar to another wordlists. Please make it more unique.";
e.Cancel = true;
}
// Validate file
if (wl.Path == null || wl.Path == "")
{
row.ErrorText += "This wordlists does not have a path to file set. Please configure the file location.";
e.Cancel = true;
}
else if (!wl.Valid)
{
row.ErrorText += "This wordlists does not exist. Please set a correct path.";
e.Cancel = true;
}
}
}
/// <summary>
/// Finishes validation of row in <c>WordListDataGridView</c>.
/// </summary>
/// <param name="sender"> sender of cell event</param>
/// <param name="e"> eventargs of cell event</param>
private void WordListDataGridView_RowValidated(object sender, DataGridViewCellEventArgs e)
{
DataGridViewRow row = WordListDataGridView.Rows[e.RowIndex];
row.ErrorText = string.Empty;
}
/// <summary>
/// Opens a File dialog to let user select a new wordlist.
/// </summary>
/// <returns>
/// Path to the new wordlist. null if dialog was canceled.
/// </returns>
private string GetNewWordListPath()
{
var dialog = new OpenFileDialog();
dialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
dialog.Title = "Please select a new wordlist";
dialog.CheckFileExists = true;
if (dialog.ShowDialog() == DialogResult.OK)
{
return dialog.FileName;
}
return null;
}
/// <summary>
/// Checks if <paramref name="path"/> is already inside configured wordlists.
/// If so a Error message box is opened.
/// </summary>
/// <param name="path"> path to be checked for duplicities.</param>
/// <returns>
/// true if <paramref name="path"/>] is already in configured wordlists. false otherwise.
/// </returns>
private bool IsDuplicateFile(string path)
{
if (Result.Count(cwl => cwl.Path == path) >= 1)
{
string existingName = Result.Find(cwl => cwl.Path == path).Name;
MessageBox.Show(this, $"Same file is already configured as wordlist \"{existingName}\".",
$"Duplicate wordlists", MessageBoxButtons.OK, MessageBoxIcon.Error);
return true;
}
return false;
}
/// <summary>
/// Iterates on top of <paramref name="name"/> until a unique name is found.
/// Every iteration it increasese a number behind name.
/// </summary>
/// <param name="name"> name to be made unique</param>
/// <returns>
/// "<paramref name="name"/>" if not duplicate. "<paramref name="name"/> (x)" where x is a positive int that is not duplicate.
/// </returns>
private string GetNonconflictingName(string name)
{
WordList wl = new WordListCustom(name, "");
if (Result.Count(cwl => cwl.Key == wl.Key) < 1)
{
return name;
}
uint counter = 0;
do
{
counter++;
wl.Name = name + $" ({counter})";
} while (Result.Count(cwl => cwl.Key == wl.Key) >= 1);
return wl.Name;
}
/// <summary>
/// Adds a new WordLists value. Asks a user for a wordlist location.
/// </summary>
/// <param name="sender"> sender of click event</param>
/// <param name="e"> eventargs of click event</param>
private void AddNewButton_Click(object sender, EventArgs e)
{
string path = GetNewWordListPath();
if (path == null || IsDuplicateFile(path))
{
return;
}
var fileName = System.IO.Path.GetFileNameWithoutExtension(path);
WordList newList = new WordListCustom(GetNonconflictingName(fileName), path);
_wordListsBindingList.Add(newList);
}
/// <summary>
/// Asks a user for a new wordlist location after double clicking on path.
/// </summary>
/// <param name="sender"> sender of click event</param>
/// <param name="e"> eventargs of click event</param>
private void WordListDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
if ( e.RowIndex >= 0
&& e.ColumnIndex >= 0
&& WordListDataGridView.Columns[e.ColumnIndex].Name == "wordListPath"
&& WordListDataGridView.Rows[e.RowIndex].DataBoundItem is WordList wl
&& !wl.ReadOnly)
{
string newPath = GetNewWordListPath();
if (newPath != null && newPath != wl.Path && !IsDuplicateFile(newPath))
{
wl.Path = newPath;
}
}
}
/// <summary>
/// Runs after a databidning is complete. Sets name cells of embeded resources to ReadOnly.
/// </summary>
/// <remarks>
/// It is necesary to set this ReadOnly property outside of Constructor of this class. Otherwise it is not consistent.
/// </remarks>
/// <param name="sender"> sender of event</param>
/// <param name="e"> eventargs of event</param>
private void WordListDataGridView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewRow row in WordListDataGridView.Rows)
{
if (row.DataBoundItem != null && row.DataBoundItem is WordList wl)
{
if (wl.ReadOnly)
{
// Disable modifications of readonly list names.
row.Cells["wordListName"].ReadOnly = true;
}
}
}
}
}
}