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 }