1 using System.Collections.Generic;
2 using Jayrock.Json.Conversion;
3 
4 namespace KeePassRPC.DataExchangeModel
5 {
6     public class Utilities
7     {
FormFieldTypeToDisplay(FormFieldType fft, bool titleCase)8         public static string FormFieldTypeToDisplay(FormFieldType fft, bool titleCase)
9         {
10             string type = "Text";
11             if (fft == FormFieldType.FFTpassword)
12                 type = "Password";
13             else if (fft == FormFieldType.FFTselect)
14                 type = "Select";
15             else if (fft == FormFieldType.FFTradio)
16                 type = "Radio";
17             else if (fft == FormFieldType.FFTtext)
18                 type = "Text";
19             else if (fft == FormFieldType.FFTusername)
20                 type = "Username";
21             else if (fft == FormFieldType.FFTcheckbox)
22                 type = "Checkbox";
23             if (!titleCase)
24                 return type.ToLower();
25             return type;
26         }
27 
FormFieldTypeFromDisplay(string type)28         public static FormFieldType FormFieldTypeFromDisplay(string type)
29         {
30             type = type.ToLower();
31             FormFieldType fft = FormFieldType.FFTusername;
32             if (type == "password")
33                 fft = FormFieldType.FFTpassword;
34             else if (type == "select")
35                 fft = FormFieldType.FFTselect;
36             else if (type == "radio")
37                 fft = FormFieldType.FFTradio;
38             else if (type == "text")
39                 fft = FormFieldType.FFTtext;
40             else if (type == "username")
41                 fft = FormFieldType.FFTusername;
42             else if (type == "checkbox")
43                 fft = FormFieldType.FFTcheckbox;
44             return fft;
45         }
46     }
47 
48     public class AuthenticationResult
49     {
50         // private int _result;
51         public int Result;// { get { return _result; } }
52         //private string _name;
53         public string Name;// { get { return _name; } }
54 
AuthenticationResult()55         public AuthenticationResult() { }
AuthenticationResult(int res, string name)56         public AuthenticationResult(int res, string name)
57         {
58             Name = name;
59             Result = res;
60             //_name = name;
61             //_result = res;
62         }
63     }
64 
65     public class Configuration
66     {
67         //bool allowUnencryptedMetaData; // doesn't affect encryption of passwords themselves
68         //KPDatabaseList knownDatabases; // the MRU list (to expand this in v1+, maybe Firefox preferences can be used?)
69         public string[] KnownDatabases;
70         public bool AutoCommit; // whether KeePass should save the active database after every change
71 
Configuration()72         public Configuration() { }
Configuration(string[] MRUList, bool autoCommit)73         public Configuration(string[] MRUList, bool autoCommit)
74         {
75             KnownDatabases = MRUList;
76             AutoCommit = autoCommit;
77         }
78     }
79 
80     public enum LoginSearchType { LSTall, LSTnoForms, LSTnoRealms }
81     public enum FormFieldType { FFTradio, FFTusername, FFTtext, FFTpassword, FFTselect, FFTcheckbox } // ..., HTML 5, etc.
82     // FFTusername is special type because bultin FF supports with only username and password
83 
84     public enum PlaceholderHandling { Default, Enabled, Disabled }
85 
86     public enum MatchAccuracyEnum
87     {
88         // Best = Non-URL match (i.e. we matched by UUID instead)
89         // Best = Regex match (it is impossible for us to infer how
90         // accurate a regex match is in comparison with other classes
91         // of match so we always treat it as the best possible match
92         // even if the regex itself is very loose)
93         // Best = Same URL including query string
94 
95         // Close = Same URL excluding query string
96 
97         // HostnameAndPort = Same hostname and port
98 
99         // Hostname = Same hostname (domain + subdomains)
100 
101         // Domain = Same domain
102 
103         // None = No match (e.g. when we are being asked to return all entries)
104 
105         Best = 50,
106         Close = 40,
107         HostnameAndPort = 30,
108         Hostname = 20,
109         Domain = 10,
110         None = 0
111     }
112 
113     public struct MatchAccuracy
114     {
115         // Best = Non-URL match (i.e. we matched by UUID instead)
116         // Best = Regex match (it is impossible for us to infer how
117         // accurate a regex match is in comparison with other classes
118         // of match so we always treat it as the best possible match
119         // even if the regex itself is very loose)
120         // Best = Same URL including query string
121 
122         // Close = Same URL excluding query string
123 
124         // HostnameAndPort = Same hostname and port
125 
126         // Hostname = Same hostname (domain + subdomains)
127 
128         // Domain = Same domain
129 
130         // None = No match (e.g. when we are being asked to return all entries)
131 
132         public static readonly int Best = (int)MatchAccuracyEnum.Best;
133         public static readonly int Close = (int)MatchAccuracyEnum.Close;
134         public static readonly int HostnameAndPort = (int)MatchAccuracyEnum.HostnameAndPort;
135         public static readonly int Hostname = (int)MatchAccuracyEnum.Hostname;
136         public static readonly int Domain = (int)MatchAccuracyEnum.Domain;
137         public static readonly int None = (int)MatchAccuracyEnum.None;
138     }
139 
140     public class FormField
141     {
142         public string Name;
143         public string DisplayName;
144         public string Value;
145         public FormFieldType @Type;
146         public string Id;
147         public int Page;
148         public PlaceholderHandling PlaceholderHandling;
149 
FormField()150         public FormField() { }
151 
FormField(string name, string displayName, string value, FormFieldType @type, string id, int page, PlaceholderHandling placeholderHandling)152         public FormField(string name,
153         string displayName,
154         string value,
155         FormFieldType @type,
156         string id,
157         int page,
158         PlaceholderHandling placeholderHandling)
159         {
160             Name = name;
161             DisplayName = displayName;
162             Value = value;
163             @Type = @type;
164             Id = id;
165             Page = page;
166             PlaceholderHandling = placeholderHandling;
167         }
168     }
169 
170     public class Group
171     {
172         public string Title;
173         public string UniqueID;
174         public string IconImageData;
175         public string Path;
176 
177         public Group[] ChildGroups;
178         public Entry[] ChildEntries;
179         public LightEntry[] ChildLightEntries;
180 
Group()181         public Group() { }
182 
Group(string title, string uniqueID, string iconImageData, string path)183         public Group(string title,
184         string uniqueID,
185         string iconImageData,
186         string path)
187         {
188             Title = title;
189             UniqueID = uniqueID;
190             IconImageData = iconImageData;
191             Path = path;
192         }
193     }
194 
195     public class Entry : LightEntry
196     {
197         public string HTTPRealm;
198         public FormField[] FormFieldList;
199 
200         // How accurately do the URLs in this entry match the URL we are looking for?
201         // Higher = better match.
202         // We don't consider protocol
203         public int MatchAccuracy;
204 
205         public bool AlwaysAutoFill;
206         public bool NeverAutoFill;
207         public bool AlwaysAutoSubmit;
208         public bool NeverAutoSubmit;
209         public int Priority; // "Kee priority" = 1 (1 = 30000 relevancy score, 2 = 29999 relevancy score)
210 
211         public Group Parent;
212         public Database Db;
213 
Entry()214         public Entry() { }
215 
Entry( string[] urls, string hTTPRealm, string title, FormField[] formFieldList, string uniqueID, bool alwaysAutoFill, bool neverAutoFill, bool alwaysAutoSubmit, bool neverAutoSubmit, int priority, Group parent, string iconImageData, Database db, int matchAccuracy)216         public Entry(
217             string[] urls,
218             string hTTPRealm,
219             string title,
220             FormField[] formFieldList,
221             string uniqueID,
222             bool alwaysAutoFill,
223             bool neverAutoFill,
224             bool alwaysAutoSubmit,
225             bool neverAutoSubmit,
226             int priority,
227             Group parent,
228             string iconImageData,
229             Database db,
230             int matchAccuracy)
231         {
232             URLs = urls;
233             HTTPRealm = hTTPRealm;
234             Title = title;
235             FormFieldList = formFieldList;
236             UniqueID = uniqueID;
237             AlwaysAutoFill = alwaysAutoFill;
238             NeverAutoFill = neverAutoFill;
239             AlwaysAutoSubmit = alwaysAutoSubmit;
240             NeverAutoSubmit = neverAutoSubmit;
241             Priority = priority;
242             Parent = parent;
243             IconImageData = iconImageData;
244             Db = db;
245             MatchAccuracy = matchAccuracy;
246         }
247     }
248 
249     public class LightEntry
250     {
251         public string[] URLs;
252         public string Title;
253         public string UniqueID;
254         public string UsernameValue;
255         public string UsernameName;
256         public string IconImageData;
257 
LightEntry()258         public LightEntry() { }
259 
LightEntry( string[] urls, string title, string uniqueID, string iconImageData, string usernameName, string usernameValue)260         public LightEntry(
261             string[] urls,
262             string title,
263             string uniqueID,
264             string iconImageData,
265             string usernameName,
266             string usernameValue)
267         {
268             URLs = urls;
269             Title = title;
270             UniqueID = uniqueID;
271             IconImageData = iconImageData;
272             UsernameName = usernameName;
273             UsernameValue = usernameValue;
274         }
275     }
276 
277     // We have no immutable properties and no known need for GetHashCode so default behaviour is as good as any
278 #pragma warning disable CS0659
279     public class EntryConfig
280 #pragma warning restore CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode()
281     {
282         public int Version = 1;
283         public string FormActionURL;
284         public string HTTPRealm;
285         public FormField[] FormFieldList;
286         public bool AlwaysAutoFill;
287         public bool NeverAutoFill;
288         public bool AlwaysAutoSubmit;
289         public bool NeverAutoSubmit;
290         public int Priority;
291         public string[] AltURLs;
292         public bool Hide;
293         public string[] BlockedURLs;
294         public string[] RegExBlockedURLs;
295         public string[] RegExURLs;
296 
297         /// <summary>
298         /// Exact match required
299         /// </summary>
300         /// <remarks>This has to be public because Jayrock</remarks>
301         public bool BlockHostnameOnlyMatch;
302 
303         /// <summary>
304         /// Hostname/port match required
305         /// </summary>
306         /// <remarks>This has to be public because Jayrock</remarks>
307         public bool BlockDomainOnlyMatch;
308 
309         /// <remarks>This has to be a method because Jayrock</remarks>
GetMatchAccuracyMethod()310         public MatchAccuracyMethod GetMatchAccuracyMethod()
311         {
312             if (BlockHostnameOnlyMatch) return MatchAccuracyMethod.Exact;
313             else if (BlockDomainOnlyMatch) return MatchAccuracyMethod.Hostname;
314             else return MatchAccuracyMethod.Domain;
315         }
316 
317         /// <remarks>This has to be a method because Jayrock</remarks>
SetMatchAccuracyMethod(MatchAccuracyMethod value)318         public void SetMatchAccuracyMethod(MatchAccuracyMethod value)
319         {
320             if (value == MatchAccuracyMethod.Domain)
321             {
322                 BlockDomainOnlyMatch = false;
323                 BlockHostnameOnlyMatch = false;
324             }
325             else if (value == MatchAccuracyMethod.Hostname)
326             {
327                 BlockDomainOnlyMatch = true;
328                 BlockHostnameOnlyMatch = false;
329             } else
330             {
331                 BlockDomainOnlyMatch = false;
332                 BlockHostnameOnlyMatch = true;
333             }
334         }
335 
336 
337         /// <summary>
338         /// Initializes a new instance of the <see cref="EntryConfig"/> class.
339         /// Match configuration depends on defaults in DB settings
340         /// </summary>
EntryConfig(MatchAccuracyMethod accuracyMethod)341         public EntryConfig(MatchAccuracyMethod accuracyMethod)
342         {
343             switch (accuracyMethod)
344             {
345                 case MatchAccuracyMethod.Exact: BlockDomainOnlyMatch = false; BlockHostnameOnlyMatch = true; break;
346                 case MatchAccuracyMethod.Hostname: BlockDomainOnlyMatch = true; BlockHostnameOnlyMatch = false; break;
347                 case MatchAccuracyMethod.Domain: BlockDomainOnlyMatch = false; BlockHostnameOnlyMatch = false; break;
348             }
349         }
350 
351         /// <summary>
352         /// Initializes a new instance of the <see cref="EntryConfig"/> class.
353         /// Match configuration defaults to MatchAccuracyMethod.Domain. In practice
354         /// this is only called by Jayrock deserialisation methods so the match accuracy
355         /// method will be set to whatever value is stored in the JSON being used to
356         /// represent this EntryConfig when at rest inside a custom string.
357         /// </summary>
EntryConfig()358         public EntryConfig()
359         {
360         }
361 
Equals(System.Object obj)362         public override bool Equals(System.Object obj)
363         {
364             if (obj == null)
365                 return false;
366 
367             EntryConfig p = obj as EntryConfig;
368             if ((System.Object)p == null)
369                 return false;
370 
371             return Version == p.Version
372                 && FormActionURL == p.FormActionURL
373                 && HTTPRealm == p.HTTPRealm
374                 && AlwaysAutoFill == p.AlwaysAutoFill
375                 && NeverAutoFill == p.NeverAutoFill
376                 && AlwaysAutoSubmit == p.AlwaysAutoSubmit
377                 && NeverAutoSubmit == p.NeverAutoSubmit
378                 && Priority == p.Priority
379                 && Hide == p.Hide
380                 && BlockHostnameOnlyMatch == p.BlockHostnameOnlyMatch
381                 && BlockDomainOnlyMatch == p.BlockDomainOnlyMatch
382                 && AreEqual(FormFieldList, p.FormFieldList)
383                 && AreEqual(AltURLs, p.AltURLs)
384                 && AreEqual(BlockedURLs, p.BlockedURLs)
385                 && AreEqual(RegExBlockedURLs, p.RegExBlockedURLs)
386                 && AreEqual(RegExURLs, p.RegExURLs);
387         }
388 
AreEqual(T[] a, T[] b)389         bool AreEqual<T>(T[] a, T[] b)
390         {
391             return AreEqual(a, b, EqualityComparer<T>.Default);
392         }
393 
AreEqual(T[] a, T[] b, IEqualityComparer<T> comparer)394         bool AreEqual<T>(T[] a, T[] b, IEqualityComparer<T> comparer)
395         {
396             if (a == null && b == null)
397             {
398                 return true;
399             }
400 
401             if (a == null || b == null)
402             {
403                 return false;
404             }
405 
406             if (a.Length != b.Length)
407             {
408                 return false;
409             }
410 
411             for (int i = 0; i < a.Length; i++)
412             {
413                 if (!comparer.Equals(a[i], b[i]))
414                 {
415                     return false;
416                 }
417             }
418             return true;
419         }
420 
421     }
422 
423     public class Database
424     {
425         public string Name;
426         public string FileName;
427         public Group Root;
428         public bool Active;
429         public string IconImageData;
430 
Database()431         public Database() { }
432 
Database(string name, string fileName, Group root, bool active, string iconImageData)433         public Database(string name,
434         string fileName,
435         Group root,
436         bool active,
437         string iconImageData)
438         {
439             Name = name;
440             Root = root;
441             FileName = fileName;
442             Active = active;
443             IconImageData = iconImageData;
444         }
445     }
446 
447     public class IconCache<T>
448     {
449         private static object iconCacheLock = new object();
450         public static Dictionary<T, string> _icons = new Dictionary<T, string>();
451         // public static Dictionary<PwUuid, string> Icons { get { } set { } }
AddIcon(T iconId, string base64representation)452         public static void AddIcon(T iconId, string base64representation)
453         {
454             lock (iconCacheLock)
455             {
456                 if (!_icons.ContainsKey(iconId))
457                     _icons.Add(iconId, base64representation);
458             }
459         }
460 
GetIconEncoding(T iconId)461         public static string GetIconEncoding(T iconId)
462         {
463             string base64representation = null;
464             lock (iconCacheLock)
465             {
466                 if (!_icons.TryGetValue(iconId, out base64representation))
467                     return null;
468                 return base64representation;
469             }
470         }
471 
472 
473 
474     }
475 
476     public enum Signal
477     {
478         /// <summary>
479         ///
480         /// </summary>
481         PLEASE_AUTHENTICATE = 0,
482         /// <summary>
483         /// deprecated?
484         /// </summary>
485         JSCALLBACKS_SETUP = 1,
486         /// <summary>
487         /// deprecated?
488         /// </summary>
489         ICECALLBACKS_SETUP = 2,
490 
491         DATABASE_OPENING = 3,
492         DATABASE_OPEN = 4,
493         DATABASE_CLOSING = 5,
494         DATABASE_CLOSED = 6,
495         DATABASE_SAVING = 7,
496         DATABASE_SAVED = 8,
497         DATABASE_DELETING = 9,
498         DATABASE_DELETED = 10,
499         DATABASE_SELECTED = 11,
500         EXITING = 12
501     }
502 
503     public enum ErrorCode
504     {
505         SUCCESS = 0, // Convention suggests we should not use 0 as an error condition
506         UNKNOWN = 1, // A catchall - hopefully won't ever need to use this
507         INVALID_MESSAGE = 2,
508         UNRECOGNISED_PROTOCOL = 3,
509         VERSION_CLIENT_TOO_LOW = 4,
510         VERSION_CLIENT_TOO_HIGH = 5,
511         AUTH_CLIENT_SECURITY_LEVEL_TOO_LOW = 6,
512         AUTH_SERVER_SECURITY_LEVEL_TOO_LOW = 7,
513         AUTH_FAILED = 8,
514         AUTH_RESTART = 9,
515         AUTH_EXPIRED = 10,
516         AUTH_INVALID_PARAM = 11,
517         AUTH_MISSING_PARAM = 12
518     }
519 
520     public class KPRPCMessage
521     {
522         public string protocol;
523         public JSONRPCContainer jsonrpc;
524         public SRPParams srp;
525         public KeyParams key;
526         public int version;
527         public string clientDisplayName;
528         public string clientDisplayDescription;
529         public string clientTypeId;
530         public Error error;
531         public string[] features;
532     }
533 
534     public class JSONRPCContainer
535     {
536         public string message;
537         public string iv;
538         public string hmac;
539     }
540 
541     public class KeyParams
542     {
543         public string username;
544         public int securityLevel;
545         public string cc;
546         public string cr;
547         public string sc;
548         public string sr;
549     }
550 
551     public class Error
552     {
553         public ErrorCode code;
554         public string[] messageParams;
555 
Error()556         public Error() { }
Error(ErrorCode code, string[] messageParams)557         public Error(ErrorCode code, string[] messageParams) { this.code = code; this.messageParams = messageParams; }
Error(ErrorCode code)558         public Error(ErrorCode code) { this.code = code; }
559     }
560 
561     public class SRPParams
562     {
563         [JsonMemberName("I")]
564         public string I;
565         [JsonMemberName("A")]
566         public string A;
567         [JsonMemberName("S")]
568         public string S;
569         [JsonMemberName("B")]
570         public string B;
571         [JsonMemberName("M")]
572         public string M;
573         [JsonMemberName("M2")]
574         public string M2;
575         [JsonMemberName("s")]
576         public string s;
577         public string stage;
578         public int securityLevel;
579     }
580 
581     public class ApplicationMetadata
582     {
583         public string KeePassVersion;
584         public bool IsMono;
585         public string NETCLR;
586         public string NETversion;
587         public string MonoVersion;
588 
ApplicationMetadata()589         public ApplicationMetadata() { }
ApplicationMetadata(string keePassVersion, bool isMono, string nETCLR, string nETversion, string monoVersion)590         public ApplicationMetadata(string keePassVersion, bool isMono, string nETCLR, string nETversion, string monoVersion)
591         {
592             KeePassVersion = keePassVersion;
593             IsMono = isMono;
594             NETCLR = nETCLR;
595             NETversion = nETversion;
596             MonoVersion = monoVersion;
597         }
598     }
599 
600 }