diff --git a/src/Build/Clean.bat b/src/Build/Clean.bat new file mode 100644 index 0000000..8ac526f --- /dev/null +++ b/src/Build/Clean.bat @@ -0,0 +1,73 @@ +RMDIR /S /Q KeePass +RMDIR /S /Q KeePass_Distrib +RMDIR /S /Q KeePassLib +RMDIR /S /Q KeePassLibDoc +REM RMDIR /S /Q KeePassLibSD +REM RMDIR /S /Q KeePassNtv +RMDIR /S /Q ShInstUtil + +RMDIR /S /Q ..\Ext\Output + +RMDIR /S /Q ..\KeePass\obj +DEL ..\KeePass\KeePass.csproj.user + +RMDIR /S /Q ..\KeePassLib\obj +DEL ..\KeePassLib\KeePassLib.csproj.user + +REM RMDIR /S /Q ..\KeePassLibSD\obj +REM DEL ..\KeePassLibSD\KeePassLibSD.csproj.user + +REM RMDIR /S /Q ..\ShInstUtil\obj +REM DEL ..\ShInstUtil\ShInstUtil.csproj.user +DEL ..\ShInstUtil\ShInstUtil.aps +DEL ..\ShInstUtil\ShInstUtil.ncb +DEL /A:H ..\ShInstUtil\ShInstUtil.suo +DEL /Q ..\ShInstUtil\*.user + +DEL /A:H ..\KeePass.suo +DEL ..\KeePass.ncb + +REM DEL /Q ..\KeePassNtv\*.aps +REM DEL /Q ..\KeePassNtv\*.user + +RMDIR /S /Q ArcFourCipher +RMDIR /S /Q ..\Plugins\ArcFourCipher\obj +DEL ..\Plugins\ArcFourCipher\ArcFourCipher.csproj.user +DEL /A:H ..\Plugins\ArcFourCipher\ArcFourCipher.suo + +RMDIR /S /Q KPScript +RMDIR /S /Q ..\Plugins\KPScript\obj +DEL ..\Plugins\KPScript\KPScript.csproj.user +DEL /A:H ..\Plugins\KPScript\KPScript.suo + +RMDIR /S /Q SamplePlugin +RMDIR /S /Q ..\Plugins\SamplePlugin\obj +DEL ..\Plugins\SamplePlugin\SamplePlugin.csproj.user +DEL /A:H ..\Plugins\SamplePlugin\SamplePlugin.suo + +RMDIR /S /Q ..\Plugins\SamplePluginCpp\Build +DEL /Q ..\Plugins\SamplePluginCpp\*.aps +DEL /Q ..\Plugins\SamplePluginCpp\*.user +DEL /Q ..\Plugins\SamplePluginCpp\*.ncb +DEL /A:H ..\Plugins\SamplePluginCpp\SamplePluginCpp.suo + +RMDIR /S /Q ..\Translation\TrlUtil\Build +RMDIR /S /Q ..\Translation\TrlUtil\obj +DEL ..\Translation\KeePass.config.xml +DEL ..\Translation\KeePass.exe +DEL ..\Translation\KeePass.exe.config +DEL ..\Translation\KeePass.pdb +DEL ..\Translation\KeePass.XmlSerializers.dll +DEL ..\Translation\TrlUtil.exe +DEL ..\Translation\TrlUtil.exe.config +DEL ..\Translation\TrlUtil.pdb +DEL ..\Translation\TrlUtil.vshost.exe +DEL ..\Translation\TrlUtil.vshost.exe.manifest + +DEL /A:H ..\Ext\KeePassMsi\KeePassMsi.suo +RMDIR /S /Q ..\Ext\KeePassMsi\.vs +RMDIR /S /Q KeePassMsi + +RMDIR /S /Q KPScript + +CLS \ No newline at end of file diff --git a/src/Build/KeePassLib_Distrib/KeePassLib.dll b/src/Build/KeePassLib_Distrib/KeePassLib.dll new file mode 100644 index 0000000..3c0f0d6 Binary files /dev/null and b/src/Build/KeePassLib_Distrib/KeePassLib.dll differ diff --git a/src/Build/KeePassLib_Distrib/KeePassLib.xml b/src/Build/KeePassLib_Distrib/KeePassLib.xml new file mode 100644 index 0000000..9cdaeee --- /dev/null +++ b/src/Build/KeePassLib_Distrib/KeePassLib.xml @@ -0,0 +1,3152 @@ + + + + KeePassLib + + + + + A class containing various static path utility helper methods (like + stripping extension from a file, etc.). + + + + + Get the directory (path) of a file name. The returned string may be + terminated by a directory separator character. Example: + passing C:\\My Documents\\My File.kdb in + and true to + would produce this string: C:\\My Documents\\. + + Full path of a file. + Append a terminating directory separator + character to the returned path. + If true, the returned path + is guaranteed to be a valid directory path (for example X:\\ instead + of X:, overriding ). + This should only be set to true, if the returned path is directly + passed to some directory API. + Directory of the file. + + + + Gets the file name of the specified file (full path). Example: + if is C:\\My Documents\\My File.kdb + the returned string is My File.kdb. + + Full path of a file. + File name of the specified file. + + + + Strip the extension of a file. + + Full path of a file with extension. + File name without extension. + + + + Get the extension of a file. + + Full path of a file with extension. + Extension without prepending dot. + + + + Ensure that a path is terminated with a directory separator character. + + Input path. + If true, a slash (/) is appended to + the string if it's not terminated already. If false, the + default system directory separator character is used. + Path having a directory separator as last character. + + + + Get the host component of a URL. + This method is faster and more fault-tolerant than creating + an Uri object and querying its Host + property. + + + For the input s://u:p@d.tld:p/p?q#f the return + value is d.tld. + + + + + Expand shell variables in a string. + [0] is the value of %1, etc. + + + + + The fully qualified name of the form. + + + + + Serialization to KeePass KDBX files. + + + Serialization to KeePass KDBX files. + + + Serialization to KeePass KDBX files. + + + Serialization to KeePass KDBX files. + + + + + File identifier, first 32-bit value. + + + + + File identifier, second 32-bit value. + + + + + Maximum supported version of database files. + KeePass 2.07 has version 1.01, 2.08 has 1.02, 2.09 has 2.00, + 2.10 has 2.02, 2.11 has 2.04, 2.15 has 3.00, 2.20 has 3.01. + The first 2 bytes are critical (i.e. loading will fail, if the + file version is too high), the last 2 bytes are informational. + + + + + Load a KDBX file. + + File to load. + Format. + Status logger (optional). + + + + Load a KDBX file from a stream. + + Stream to read the data from. Must contain + a KDBX stream. + Format. + Status logger (optional). + + + + Save the contents of the current PwDatabase to a KDBX file. + + Stream to write the KDBX file into. + Group containing all groups and + entries to write. If null, the complete database will + be written. + Format of the file to create. + Logger that recieves status information. + + + + Default constructor. + + The PwDatabase instance that the + class will load file data into or use to create a KDBX file. + + + + Call this once to determine the current localization settings. + + + + + Detach binaries when opening a file. If this isn't null, + all binaries are saved to the specified path and are removed + from the database. + + + + + Contains KeePassLib-global definitions and enums. + + + + + Default identifier string for the title field. + Should not contain spaces, tabs or other whitespace. + + + + + Default identifier string for the user name field. + Should not contain spaces, tabs or other whitespace. + + + + + Default identifier string for the password field. + Should not contain spaces, tabs or other whitespace. + + + + + Default identifier string for the URL field. + Should not contain spaces, tabs or other whitespace. + + + + + Default identifier string for the notes field. + Should not contain spaces, tabs or other whitespace. + + + + + Maximum time (in milliseconds) after which the user interface + should be updated. + + + + + The product name. + + + + + A short, simple string representing the product name. The string + should contain no spaces, directory separator characters, etc. + + + + + Version, encoded as 32-bit unsigned integer. + 2.00 = 0x02000000, 2.01 = 0x02000100, ..., 2.18 = 0x02010800. + As of 2.19, the version is encoded component-wise per byte, + e.g. 2.19 = 0x02130000. + It is highly recommended to use FileVersion64 instead. + + + + + Version, encoded as 64-bit unsigned integer + (component-wise, 16 bits per component). + + + + + Version, encoded as string. + + + + + Product website URL. Terminated by a forward slash. + + + + + URL to the online translations page. + + + + + URL to the online plugins page. + + + + + Product donations URL. + + + + + URL to the root path of the online KeePass help. Terminated by + a forward slash. + + + + + URL to a TXT file (eventually compressed) that contains information + about the latest KeePass version available on the website. + + + + + A DateTime object that represents the time when the assembly + was loaded. + + + + + Default number of master key encryption/transformation rounds + (making dictionary attacks harder). + + + + + Default identifier string for the field which will contain TAN indices. + + + + + Default title of an entry that is really a TAN entry. + + + + + Prefix of a custom auto-type string field. + + + + + Default string representing a hidden password. + + + + + Default auto-type keystroke sequence. If no custom sequence is + specified, this sequence is used. + + + + + Default auto-type keystroke sequence for TAN entries. If no custom + sequence is specified, this sequence is used. + + + + + Check if a name is a standard field name. + + Input field name. + Returns true, if the field name is a standard + field name (title, user name, password, ...), otherwise false. + + + + Check whether an entry is a TAN entry. + + + + + Search parameters for group and entry searches. + + + + + Construct a new search parameters object. + + + + + String comparison type. Specifies the condition when the specified + text matches a group/entry string. + + + + + Only for serialization. + + + + + Memory protection configuration structure (for default fields). + + + + + Interface for objects that are deeply cloneable. + + Reference type. + + + + Deeply clone the object. + + Cloned object. + + + + Validate a key. + + Key to validate. + Type of the validation to perform. + Returns null, if the validation is successful. + If there is a problem with the key, the returned string describes + the problem. + + + + Name of your key validator (should be unique). + + + + + Generate HMAC-based one-time passwords as specified in RFC 4226. + + + + + A dictionary of ProtectedString objects. + + + + + Construct a new dictionary of protected strings. + + + + + Get one of the protected strings. + + String identifier. + Protected string. If the string identified by + cannot be found, the function + returns null. + Thrown if the input + parameter is null. + + + + Get one of the protected strings. The return value is never null. + If the requested string cannot be found, an empty protected string + object is returned. + + String identifier. + Returns a protected string object. If the standard string + has not been set yet, the return value is an empty string (""). + Thrown if the input + parameter is null. + + + + Test if a named string exists. + + Name of the string to try. + Returns true if the string exists, otherwise false. + Thrown if + is null. + + + + Get one of the protected strings. If the string doesn't exist, the + return value is an empty string (""). + + Name of the requested string. + Requested string value or an empty string, if the named + string doesn't exist. + Thrown if the input + parameter is null. + + + + Get one of the entry strings. If the string doesn't exist, the + return value is an empty string (""). If the string is + in-memory protected, the return value is PwDefs.HiddenPassword. + + Name of the requested string. + Returns the requested string in plain-text or + PwDefs.HiddenPassword if the string cannot be found. + Thrown if the input + parameter is null. + + + + Set a string. + + Identifier of the string field to modify. + New value. This parameter must not be null. + Thrown if one of the input + parameters is null. + + + + Delete a string. + + Name of the string field to delete. + Returns true if the field has been successfully + removed, otherwise the return value is false. + Thrown if the input + parameter is null. + + + + Get the number of strings. + + + + + A strongly-typed resource class, for looking up localized strings, etc. + + + + + Look up a localized string similar to + 'The algorithm is unknown.'. + + + + + Look up a localized string similar to + 'The character set is invalid.'. + + + + + Look up a localized string similar to + 'There are too few characters in the character set.'. + + + + + Look up a localized string similar to + 'Failed to initialize encryption/decryption stream!'. + + + + + Look up a localized string similar to + 'The data is too large to be encrypted/decrypted securely using {PARAM}.'. + + + + + Look up a localized string similar to + 'entry'. + + + + + Look up a localized string similar to + 'An extended error report has been copied to the clipboard.'. + + + + + Look up a localized string similar to + 'Expect 100-Continue responses'. + + + + + Look up a localized string similar to + 'Fatal Error'. + + + + + Look up a localized string similar to + 'A fatal error has occurred!'. + + + + + Look up a localized string similar to + 'The file is corrupted.'. + + + + + Look up a localized string similar to + 'The file header is corrupted.'. + + + + + Look up a localized string similar to + 'Data is missing at the end of the file, i.e. the file is incomplete.'. + + + + + Look up a localized string similar to + 'Less data than expected could be read from the file.'. + + + + + Look up a localized string similar to + 'Failed to load the specified file!'. + + + + + Look up a localized string similar to + 'The file is locked, because the following user is currently writing to it:'. + + + + + Look up a localized string similar to + 'A newer KeePass version or a plugin is required to open this file.'. + + + + + Look up a localized string similar to + 'A newer KeePass version is required to open this file.'. + + + + + Look up a localized string similar to + 'The target file might be corrupted. Please try saving again. If that fails, save the database to a different location.'. + + + + + Look up a localized string similar to + 'Failed to save to the specified file!'. + + + + + Look up a localized string similar to + 'The file signature is invalid. Either the file isn't a KeePass database file at all or it is corrupted.'. + + + + + Look up a localized string similar to + 'The file is encrypted using an unknown encryption algorithm!'. + + + + + Look up a localized string similar to + 'The file is compressed using an unknown compression algorithm!'. + + + + + Look up a localized string similar to + 'The file format version is unsupported.'. + + + + + Look up a localized string similar to + 'Failed to create the final encryption/decryption key!'. + + + + + Look up a localized string similar to + 'The .NET Framework/runtime under which KeePass is currently running does not support this operation.'. + + + + + Look up a localized string similar to + 'General'. + + + + + Look up a localized string similar to + 'group'. + + + + + Look up a localized string similar to + 'The master key is invalid!'. + + + + + Look up a localized string similar to + 'Make sure that the master key is correct and try it again.'. + + + + + Look up a localized string similar to + 'Found invalid data while decoding.'. + + + + + Look up a localized string similar to + 'In order to import KeePass 1.x KDB files, create a new 2.x database file and click 'File' -> 'Import' in the main menu. In the import dialog, choose 'KeePass KDB (1.x)' as file format.'. + + + + + Look up a localized string similar to + '{PARAM}-bit key'. + + + + + Look up a localized string similar to + 'Database files cannot be used as key files.'. + + + + + Look up a localized string similar to + 'The key and the hash do not match, i.e. the key or the hash is invalid.'. + + + + + Look up a localized string similar to + 'The length of the master key seed is invalid!'. + + + + + Look up a localized string similar to + 'The selected file appears to be an old format'. + + + + + Look up a localized string similar to + 'Passive'. + + + + + Look up a localized string similar to + 'The path contains a backslash. Such paths are not supported (for security reasons).'. + + + + + Look up a localized string similar to + 'The pattern is invalid.'. + + + + + Look up a localized string similar to + 'Pre-authenticate'. + + + + + Look up a localized string similar to + 'Failed to generate a password.'. + + + + + Look up a localized string similar to + 'Structures are nested too deeply.'. + + + + + Look up a localized string similar to + 'Timeout'. + + + + + Look up a localized string similar to + 'Please try it again in a few seconds.'. + + + + + Look up a localized string similar to + 'An unknown error occurred.'. + + + + + Look up a localized string similar to + 'Unknown header ID!'. + + + + + Look up a localized string similar to + 'Unknown key derivation function!'. + + + + + Look up a localized string similar to + 'The operating system did not grant KeePass read/write access to the user profile folder, where the protected user key is stored.'. + + + + + Look up a localized string similar to + 'User agent'. + + + + + Algorithms supported by CryptoRandomStream. + + + + + Not supported. + + + + + A variant of the ARCFour algorithm (RC4 incompatible). + Insecure; for backward compatibility only. + + + + + Salsa20 stream cipher algorithm. + + + + + ChaCha20 stream cipher algorithm. + + + + + A random stream class. The class is initialized using random + bytes provided by the caller. The produced stream has random + properties, but for the same seed always the same stream + is produced, i.e. this class can be used as stream cipher. + + + + + Construct a new cryptographically secure random stream object. + + Algorithm to use. + Initialization key. Must not be null + and must contain at least 1 byte. + + + + Get random bytes. + + Number of random bytes to retrieve. + Returns random bytes. + + + + Character stream class. + + + + + Size of a character in bytes. + + + + + Start signature of the text (byte order mark). + May be null or empty, if no signature is known. + + + + + A class containing various string helper methods. + + + + + Convert a string to a HTML sequence representing that string. + + String to convert. + String, HTML-encoded. + + + + Convert a Color to a HTML color identifier string. + + Color to convert. + If this is true, an empty string + is returned if the color is transparent. + HTML color identifier string. + + + + Format an exception and convert it to a string. + + Exception to convert/format. + String representing the exception. + + + + Removes all characters that are not valid XML characters, + according to https://www.w3.org/TR/xml/#charsets . + + Source text. + Text containing only valid XML characters. + + + + Normalize new line characters in a string. Input strings may + contain mixed new line character sequences from all commonly + used operating systems (i.e. \r\n from Windows, \n from Unix + and \r from MacOS. + + String with mixed new line characters. + If true, new line characters + are normalized for Windows (\r\n); if false, new line + characters are normalized for Unix (\n). + String with normalized new line characters. + + + + Split a string and include the separators in the splitted array. + + String to split. + Separators. + Specifies whether separators are + matched case-sensitively or not. + Splitted string including separators. + + + + Create a data URI (according to RFC 2397). + + Data to encode. + Optional MIME type. If null, + an appropriate type is used. + Data URI. + + + + Convert a data URI (according to RFC 2397) to binary data. + + Data URI to decode. + Decoded binary data. + + + + Remove placeholders from a string (wrapped in '{' and '}'). + This doesn't remove environment variables (wrapped in '%'). + + + + + Find a character that does not occur within a given text. + + + + + Generate random seeds and store them in . + + + + + Set the value of the private shown_raised member + variable of a form. + + Previous shown_raised value. + + + + Ensure that the file ~/.recently-used is valid (in order to + prevent Mono's FileDialog from crashing). + + + + + Member variable name of the control to be translated. + + + + + A XorredBuffer object stores data that is encrypted + using a XOR pad. + + + + + Construct a new XorredBuffer object. + The byte array must have the same + length as the byte array. + The XorredBuffer object takes ownership of the two byte + arrays, i.e. the caller must not use them afterwards. + + Data with XOR pad applied. + XOR pad that can be used to decrypt the + byte array. + + + + Get a copy of the plain-text. The caller is responsible + for clearing the byte array safely after using it. + + Plain-text byte array. + + + + Contains various static time structure manipulation and conversion + routines. + + + + + Length of a compressed PW_TIME structure in bytes. + + + + + Pack a DateTime object into 5 bytes. Layout: 2 zero bits, + year 12 bits, month 4 bits, day 5 bits, hour 5 bits, minute 6 + bits, second 6 bits. + + + + + Unpack a packed time (5 bytes, packed by the PackTime + member function) to a DateTime object. + + Packed time, 5 bytes. + Unpacked DateTime object. + + + + Pack a DateTime object into 7 bytes (PW_TIME). + + Object to be encoded. + Packed time, 7 bytes (PW_TIME). + + + + Unpack a packed time (7 bytes, PW_TIME) to a DateTime object. + + Packed time, 7 bytes. + Unpacked DateTime object. + + + + Convert a DateTime object to a displayable string. + + DateTime object to convert to a string. + String representing the specified DateTime object. + + + + Parse a US textual date string, like e.g. "January 02, 2012". + + + + + Check equality of two times with precision 1 s, floor-rounded. + Ticks finer than 1 s are ignored. + + + + + Do not remember user name or password. + + + + + Remember the user name only, not the password. + + + + + Save both user name and password. + + + + + For serialization only; use Properties in code. + + + + + Status message types. + + + + + Default type: simple information type. + + + + + Warning message. + + + + + Error message. + + + + + Additional information. Depends on lines above. + + + + + Status logging interface. + + + + + Function which needs to be called when logging is started. + + This string should roughly describe + the operation, of which the status is logged. + Specifies whether the + operation is written to the log or not. + + + + Function which needs to be called when logging is ended + (i.e. when no more messages will be logged and when the + percent value won't change any more). + + + + + Set the current progress in percent. + + Percent of work finished. + Returns true if the caller should continue + the current work. + + + + Set the current status text. + + Status text. + Type of the message. + Returns true if the caller should continue + the current work. + + + + Check whether the user cancelled the current work. + + Returns true if the caller should continue + the current work. + + + + Interface for objects that support various times (creation time, last + access time, last modification time and expiry time). Offers + several helper functions (for example a function to touch the current + object). + + + + + Touch the object. This function updates the internal last access + time. If the parameter is true, + the last modification time gets updated, too. Each time you call + Touch, the usage count of the object is increased by one. + + Update last modification time. + + + + The date/time when the object was created. + + + + + The date/time when the object was last modified. + + + + + The date/time when the object was last accessed. + + + + + The date/time when the object expires. + + + + + Flag that determines whether the object expires. + + + + + Get or set the usage count of the object. To increase the usage + count by one, use the Touch function. + + + + + The date/time when the location of the object was last changed. + + + + + UUID of the engine. If you want to write an engine/plugin, + please contact the KeePass team to obtain a new UUID. + + + + + Name displayed in the list of available encryption/decryption + engines in the GUI. + + + + + Interface to a user key, like a password, key file data, etc. + + + + + Get key data. Querying this property is fast (it returns a + reference to a cached ProtectedBinary object). + If no key data is available, null is returned. + + + + + Let the user interface save the current database. + + If true, the UI will not ask for + whether to synchronize or overwrite, it'll simply overwrite the + file. + Returns true if the file has been saved. + + + + Latin-1 Supplement except U+00A0 (NBSP) and U+00AD (SHY). + + + + + Create a new, empty character set. + + + + + Remove all characters from this set. + + + + + Add characters to the set. + + Character to add. + + + + Add characters to the set. + + String containing characters to add. + + + + Convert the character set to a string containing all its characters. + + String containing all character set characters. + + + + Number of characters in this set. + + + + + Get a character of the set using an index. + + Index of the character to get. + Character at the specified position. If the index is invalid, + an ArgumentOutOfRangeException is thrown. + + + + Create a cryptographic key of length + (in bytes) from . + + + + + Password generator. + + + + + Rename/move a file. For local file system and WebDAV, the + specified file is moved, i.e. the file destination can be + in a different directory/path. In contrast, for FTP the + file is renamed, i.e. its destination must be in the same + directory/path. + + Source file path. + Target file path. + + + + A group containing subgroups and entries. + + + + + Search this group and all subgroups for entries. + + Specifies the search parameters. + Entry list in which the search results + will be stored. + + + + Search this group and all subgroups for entries. + + Specifies the search parameters. + Entry list in which the search results + will be stored. + Optional status reporting object. + + + + Construct a new, empty group. + + + + + Construct a new, empty group. + + Create a new UUID for this group. + Set creation, last access and last modification times to the current time. + + + + Construct a new group. + + Create a new UUID for this group. + Set creation, last access and last modification times to the current time. + Name of the new group. + Icon of the new group. + + + + Deeply clone the current group. The returned group will be an exact + value copy of the current object (including UUID, etc.). + + Exact value copy of the current PwGroup object. + + + + Assign properties to the current group based on a template group. + + Template group. Must not be null. + Only set the properties of the template group + if it is newer than the current one. + If true, the + LocationChanged property is copied, otherwise not. + + + + Touch the group. This function updates the internal last access + time. If the parameter is true, + the last modification time gets updated, too. + + Modify last modification time. + + + + Touch the group. This function updates the internal last access + time. If the parameter is true, + the last modification time gets updated, too. + + Modify last modification time. + If true, all parent objects + get touched, too. + + + + Get number of groups and entries in the current group. This function + can also traverse through all subgroups and accumulate their counts + (recursive mode). + + If this parameter is true, all + subgroups and entries in subgroups will be counted and added to + the returned value. If it is false, only the number of + subgroups and entries of the current group is returned. + Number of subgroups. + Number of entries. + + + + Traverse the group/entry tree in the current group. Various traversal + methods are available. + + Specifies the traversal method. + Function that performs an action on + the currently visited group (see GroupHandler for more). + This parameter may be null, in this case the tree is traversed but + you don't get notifications for each visited group. + Function that performs an action on + the currently visited entry (see EntryHandler for more). + This parameter may be null. + Returns true if all entries and groups have been + traversed. If the traversal has been canceled by one of the two + handlers, the return value is false. + + + + Pack all groups into one flat linked list of references (recursively). + + Flat list of all groups. + + + + Pack all entries into one flat linked list of references. Temporary + group IDs are assigned automatically. + + A flat group list created by + GetFlatGroupList. + Flat list of all entries. + + + + Enable protection of a specific string field type. + + Name of the string field to protect or unprotect. + Enable protection or not. + Returns true, if the operation completed successfully, + otherwise false. + + + + Find a group. + + UUID identifying the group the caller is looking for. + If true, the search is recursive. + Returns reference to found group, otherwise null. + + + + Find an object. + + UUID of the object to find. + Specifies whether to search recursively. + If null, groups and entries are + searched. If true, only entries are searched. If false, + only groups are searched. + Reference to the object, if found. Otherwise null. + + + + Try to find a subgroup and create it, if it doesn't exist yet. + + Name of the subgroup. + If the group isn't found: create it. + Returns a reference to the requested group or null if + it doesn't exist and shouldn't be created. + + + + Find an entry. + + UUID identifying the entry the caller is looking for. + If true, the search is recursive. + Returns reference to found entry, otherwise null. + + + + Get the full path of the group. + + + + + Get the full path of the group. + + String that separates the group + names. + Specifies whether the returned + path starts with the topmost group. + + + + Assign new UUIDs to groups and entries. + + Create new UUIDs for subgroups. + Create new UUIDs for entries. + Recursive tree traversal. + + + + Find/create a subtree of groups. + + Tree string. + Separators that delimit groups in the + strTree parameter. + + + + Get the depth of this group (i.e. the number of ancestors). + + Depth of this group. + + + + Get a list of subgroups (not including this one). + + If true, subgroups are added + recursively, i.e. all child groups are returned, too. + List of subgroups. If is + true, it is guaranteed that subsubgroups appear after + subgroups. + + + + Get objects contained in this group. + + Specifies whether to search recursively. + If null, the returned list contains + groups and entries. If true, the returned list contains only + entries. If false, the returned list contains only groups. + List of objects. + + + + Add a subgroup to this group. + + Group to be added. Must not be null. + If this parameter is true, the + parent group reference of the subgroup will be set to the current + group (i.e. the current group takes ownership of the subgroup). + + + + Add a subgroup to this group. + + Group to be added. Must not be null. + If this parameter is true, the + parent group reference of the subgroup will be set to the current + group (i.e. the current group takes ownership of the subgroup). + If true, the + LocationChanged property of the subgroup is updated. + + + + Add an entry to this group. + + Entry to be added. Must not be null. + If this parameter is true, the + parent group reference of the entry will be set to the current + group (i.e. the current group takes ownership of the entry). + + + + Add an entry to this group. + + Entry to be added. Must not be null. + If this parameter is true, the + parent group reference of the entry will be set to the current + group (i.e. the current group takes ownership of the entry). + If true, the + LocationChanged property of the entry is updated. + + + + UUID of this group. + + + + + Reference to the group to which this group belongs. May be null. + + + + + The date/time when the location of the object was last changed. + + + + + The name of this group. Cannot be null. + + + + + Comments about this group. Cannot be null. + + + + + Icon of the group. + + + + + Get the custom icon ID. This value is 0, if no custom icon is + being used (i.e. the icon specified by the IconID property + should be displayed). + + + + + A flag that specifies if the group is shown as expanded or + collapsed in the user interface. + + + + + The date/time when this group was created. + + + + + The date/time when this group was last modified. + + + + + The date/time when this group was last accessed (read). + + + + + The date/time when this group expires. + + + + + Flag that determines if the group expires. + + + + + Get or set the usage count of the group. To increase the usage + count by one, use the Touch function. + + + + + Get a list of subgroups in this group. + + + + + Get a list of entries in this group. + + + + + A flag specifying whether this group is virtual or not. Virtual + groups can contain links to entries stored in other groups. + Note that this flag has to be interpreted and set by the calling + code; it won't prevent you from accessing and modifying the list + of entries in this group in any way. + + + + + Default auto-type keystroke sequence for all entries in + this group. This property can be an empty string, which + means that the value should be inherited from the parent. + + + + + Custom data container that can be used by plugins to store + own data in KeePass groups. + The data is stored in the encrypted part of encrypted + database files. + Use unique names for your items, e.g. "PluginName_ItemName". + + + + + Password generation function. + + Password generation options chosen + by the user. This may be null, if the default + options should be used. + Source that the algorithm + can use to generate random numbers. + Generated password or null in case + of failure. If returning null, the caller assumes + that an error message has already been shown to the user. + + + + Each custom password generation algorithm must have + its own unique UUID. + + + + + Displayable name of the password generation algorithm. + + + + + A list of auto-type associations. + + + + + Construct a new auto-type associations list. + + + + + Remove all associations. + + + + + Clone the auto-type associations list. + + New, cloned object. + + + + Specify whether auto-type is enabled or not. + + + + + Specify whether the typing should be obfuscated. + + + + + The default keystroke sequence that is auto-typed if + no matching window is found in the Associations + container. + + + + + Get all auto-type window/keystroke sequence pairs. + + + + + Name of your key provider (should be unique). + + + + + Property indicating whether the provider is exclusive. + If the provider is exclusive, KeePass does not allow other + key sources (master password, Windows user account, ...) + to be combined with the provider. + Key providers typically should return false + (to allow non-exclusive use), i.e. do not override this + property. + + + + + Property that specifies whether the returned key data + gets hashed by KeePass first or is written directly to + the user key data stream. + Standard key provider plugins should return false + (i.e. don't overwrite this property). Returning true + may cause severe security problems and is highly + discouraged. + + + + + This property specifies whether the GetKey method might + show a form or dialog. If there is any chance that the method shows + one, this property must return true. Only if it's guaranteed + that the GetKey method doesn't show any form or dialog, this + property should return false. + + + + + This property specifies whether the key provider is compatible + with the secure desktop mode. This almost never is the case, + so you usually won't override this property. + + + + + Implementation of the ChaCha20 cipher with a 96-bit nonce, + as specified in RFC 7539. + https://tools.ietf.org/html/rfc7539 + + + + + Constructor. + + Key (32 bytes). + Nonce (12 bytes). + If false, the RFC 7539 version + of ChaCha20 is used. In this case, only 256 GB of data can be + encrypted securely (because the block counter is a 32-bit variable); + an attempt to encrypt more data throws an exception. + If is true, the 32-bit + counter overflows to another 32-bit variable (i.e. the counter + effectively is a 64-bit variable), like in the original ChaCha20 + specification by D. J. Bernstein (which has a 64-bit counter and a + 64-bit nonce). To be compatible with this version, the 64-bit nonce + must be stored in the last 8 bytes of + and the first 4 bytes must be 0. + If the IV was generated randomly, a 12-byte IV and a large counter + can be used to securely encrypt more than 256 GB of data (but note + this is incompatible with RFC 7539 and the original specification). + + + + List of objects that implement IDeepCloneable + and cannot be null. + + Object type. + + + + Type of the password generator. Different types like generators + based on given patterns, based on character sets, etc. are + available. + + + + + Generator based on character spaces/sets, i.e. groups + of characters like lower-case, upper-case or numeric characters. + + + + + Password generation based on a pattern. The user has provided + a pattern, which describes how the generated password has to + look like. + + + + + Cryptographically secure pseudo-random number generator. + The returned values are unpredictable and cannot be reproduced. + CryptoRandom is a singleton class. + + + + + Update the internal seed of the random number generator based + on entropy data. + This method is thread-safe. + + Entropy bytes. + + + + Get a number of cryptographically strong random bytes. + This method is thread-safe. + + Number of requested random bytes. + A byte array consisting of + random bytes. + + + + Get the number of random bytes that this instance generated so far. + Note that this number can be higher than the number of random bytes + actually requested using the GetRandomBytes method. + + + + + Event that is triggered whenever the internal GenerateRandom256 + method is called to generate random bytes. + + + + + Interface to native library (library containing fast versions of + several cryptographic functions). + + + + + Determine if the native library is installed. + + Returns true, if the native library is installed. + + + + Transform a key. + + Source and destination buffer. + Key to use for the transformation. + Number of transformation rounds. + Returns true, if the key was transformed successfully. + + + + Benchmark key transformation. + + Number of milliseconds to perform the benchmark. + Number of transformations done. + Returns true, if the benchmark was successful. + + + + If true, the native library is used. + + + + + Resize an image. + + Image to resize. + Width of the returned image. + Height of the returned image. + Flags to customize scaling behavior. + Resized image. This object is always different + from (i.e. they can be + disposed separately). + + + + Buffer manipulation and conversion routines. + + + + + Convert a hexadecimal string to a byte array. The input string must be + even (i.e. its length is a multiple of 2). + + String containing hexadecimal characters. + Returns a byte array. Returns null if the string parameter + was null or is an uneven string (i.e. if its length isn't a + multiple of 2). + Thrown if + is null. + + + + Convert a byte array to a hexadecimal string. + + Input byte array. + Returns the hexadecimal string representing the byte + array. Returns null, if the input byte array was null. Returns + an empty string, if the input byte array has length 0. + + + + Decode Base32 strings according to RFC 4648. + + + + + Set all bytes in a byte array to zero. + + Input array. All bytes of this array + will be set to zero. + + + + Set all elements of an array to the default value. + + Input array. + + + + Convert 2 bytes to a 16-bit unsigned integer (little-endian). + + + + + Convert 2 bytes to a 16-bit unsigned integer (little-endian). + + + + + Convert 4 bytes to a 32-bit unsigned integer (little-endian). + + + + + Convert 4 bytes to a 32-bit unsigned integer (little-endian). + + + + + Convert 8 bytes to a 64-bit unsigned integer (little-endian). + + + + + Convert 8 bytes to a 64-bit unsigned integer (little-endian). + + + + + Convert a 16-bit unsigned integer to 2 bytes (little-endian). + + + + + Convert a 32-bit unsigned integer to 4 bytes (little-endian). + + + + + Convert a 32-bit unsigned integer to 4 bytes (little-endian). + + + + + Convert a 64-bit unsigned integer to 8 bytes (little-endian). + + + + + Convert a 64-bit unsigned integer to 8 bytes (little-endian). + + + + + Fast 32-bit hash (e.g. for hash tables). + The algorithm might change in the future; do not store + the hashes for later use. + + + + + A user key depending on the currently logged on Windows user account. + + + + + Construct a user account key. + + + + + Get key data. Querying this property is fast (it returns a + reference to a cached ProtectedBinary object). + If no key data is available, null is returned. + + + + + Function definition of a method that performs an action on a group. + When traversing the internal tree, this function will be invoked + for all visited groups. + + Currently visited group. + You must return true if you want to continue the + traversal. If you want to immediately stop the whole traversal, + return false. + + + + Function definition of a method that performs an action on an entry. + When traversing the internal tree, this function will be invoked + for all visited entries. + + Currently visited entry. + You must return true if you want to continue the + traversal. If you want to immediately stop the whole traversal, + return false. + + + + Pool of encryption/decryption algorithms (ciphers). + + + + + Remove all cipher engines from the current pool. + + + + + Add a cipher engine to the pool. + + Cipher engine to add. Must not be null. + + + + Get a cipher identified by its UUID. + + UUID of the cipher to return. + Reference to the requested cipher. If the cipher is + not found, null is returned. + + + + Get the index of a cipher. This index is temporary and should + not be stored or used to identify a cipher. + + UUID of the cipher. + Index of the requested cipher. Returns -1 if + the specified cipher is not found. + + + + Get the index of a cipher. This index is temporary and should + not be stored or used to identify a cipher. + + Name of the cipher. Note that + multiple ciphers can have the same name. In this case, the + first matching cipher is returned. + Cipher with the specified name or -1 if + no cipher with that name is found. + + + + Get the number of cipher engines in this pool. + + + + + Get the cipher engine at the specified position. Throws + an exception if the index is invalid. You can use this + to iterate over all ciphers, but do not use it to + identify ciphers. + + Index of the requested cipher engine. + Reference to the cipher engine at the specified + position. + + + + The core password manager class. It contains a number of groups, which + contain the actual entries. + + + + + Constructs an empty password manager object. + + + + + Initialize the class for managing a new database. Previously loaded + data is deleted. + + I/O connection of the new database. + Key to open the database. + + + + Open a database. The URL may point to any supported data source. + + I/O connection to load the database from. + Key used to open the specified database. + Logger, which gets all status messages. + + + + Save the currently open database. The file is written to the + location it has been opened from. + + Logger that recieves status information. + + + + Save the currently open database to a different location. If + is true, the specified + location is made the default location for future saves + using SaveDatabase. + + New location to serialize the database to. + If true, the new location is made + the standard location for the database. If false, a copy of the + currently open database is saved to the specified location, but it + isn't made the default location (i.e. no lock files will be moved for + example). + Logger that recieves status information. + + + + Closes the currently open database. No confirmation message + is shown before closing. Unsaved changes will be lost. + + + + + Load only the unencrypted header of a database file. + In the returned database object, any data that is not stored + in the unencrypted header is set to its default value. + Intended primarily for plugins. + + + + + Get the index of a custom icon. + + ID of the icon. + Index of the icon. + + + + Get a custom icon. This method can return null, + e.g. if no cached image of the icon is available. + + ID of the icon. + Width of the returned image. If this is + negative, the image is returned in its original size. + Height of the returned image. If this is + negative, the image is returned in its original size. + + + + Get the root group that contains all groups and entries stored in the + database. + + Root group. The return value is null, if the database + is not open. + + + + IOConnection of the currently open database file. + Is never null. + + + + + If this is true, a database is currently open. + + + + + Modification flag. If true, the class has been modified and the + user interface should prompt the user to save the changes before + closing the database for example. + + + + + The user key used for database encryption. This key must be created + and set before using any of the database load/save functions. + + + + + Name of the database. + + + + + Database description. + + + + + Default user name used for new entries. + + + + + Number of days until history entries are being deleted + in a database maintenance operation. + + + + + The encryption algorithm used to encrypt the data part of the database. + + + + + Compression algorithm used to encrypt the data part of the database. + + + + + Memory protection configuration (for default fields). + + + + + Get a list of all deleted objects. + + + + + Get all custom icons stored in this database. + + + + + This is a dirty-flag for the UI. It is used to indicate when an + icon list update is required. + + + + + UUID of the group containing template entries. May be + PwUuid.Zero, if no entry templates group has been specified. + + + + + Custom data container that can be used by plugins to store + own data in KeePass databases. + The data is stored in the encrypted part of encrypted + database files. + Use unique names for your items, e.g. "PluginName_ItemName". + + + + + Custom data container that can be used by plugins to store + own data in KeePass databases. + The data is stored in the *unencrypted* part of database files, + and it is not supported by all file formats (e.g. supported by KDBX, + unsupported by XML). + It is highly recommended to use CustomData instead, + if possible. + Use unique names for your items, e.g. "PluginName_ItemName". + + + + + Hash value of the primary file on disk (last read or last write). + A call to SaveAs without making the saved file primary will + not change this hash. May be null. + + + + + Detach binaries when opening a file. If this isn't null, + all binaries are saved to the specified path and are removed + from the database. + + + + + Localized application name. + + + + + Create a deep copy. + + + + + Unsupported. + + + + + Length of an encryption key in bytes. + The base ICipherEngine assumes 32. + + + + + Length of the initialization vector in bytes. + The base ICipherEngine assumes 16. + + + + + Represents a key. A key can be build up using several user key data sources + like a password, a key file, the currently logged on user credentials, + the current computer ID, etc. + + + + + Construct a new, empty key object. + + + + + Add a user key. + + User key to add. + + + + Remove a user key. + + User key to remove. + Returns true if the key was removed successfully. + + + + Test whether the composite key contains a specific type of + user keys (password, key file, ...). If at least one user + key of that type is present, the function returns true. + + User key type. + Returns true, if the composite key contains + a user key of the specified type. + + + + Get the first user key of a specified type. + + Type of the user key to get. + Returns the first user key of the specified type + or null if no key of that type is found. + + + + Creates the composite key from the supplied user key sources (password, + key file, user account, computer ID, etc.). + + + + + Generate a 32-byte (256-bit) key from the composite key. + + + + + List of all user keys contained in the current composite key. + + + + + A strongly-typed resource class, for looking up localized strings, etc. + + + + + Look up a localized string similar to + 'Test'. + + + + + Get the icon as an Image (original size). + + + + + Get the icon as an Image (with the specified size). + + Width of the returned image. + Height of the returned image. + + + + A class that offers static functions to estimate the quality of + passwords. + + + + + Estimate the quality of a password. + + Password to check. + Estimated bit-strength of the password. + + + + Estimate the quality of a password. + + Password to check, UTF-8 encoded. + Estimated bit-strength of the password. + + + + The KdbxFile class supports saving the data to various + formats. + + + + + The default, encrypted file format. + + + + + Use this flag when exporting data to a plain-text XML file. + + + + + If this property is set to a non-null stream, all data that + is read from the input stream is automatically written to + the copy stream (before returning the read data). + + + + + Represents an UUID of a password entry or group. Once created, + PwUuid objects aren't modifyable anymore (immutable). + + + + + Standard size in bytes of a UUID. + + + + + Zero UUID (all bytes are zero). + + + + + Construct a new UUID object. + + If this parameter is true, a new + UUID is generated. If it is false, the UUID is initialized + to zero. + + + + Construct a new UUID object. + + Initial value of the PwUuid object. + + + + Create a new, random UUID. + + Returns true if a random UUID has been generated, + otherwise it returns false. + + + + Convert the UUID to its string representation. + + String containing the UUID value. + + + + Get the 16 UUID bytes. + + + + + Name of the provider that generated the custom key. + + + + + Compression algorithm specifiers. + + + + + No compression. + + + + + GZip compression. + + + + + Virtual field: currently known number of algorithms. Should not be used + by plugins or libraries -- it's used internally only. + + + + + Tree traversal methods. + + + + + Don't traverse the tree. + + + + + Traverse the tree in pre-order mode, i.e. first visit all items + in the current node, then visit all subnodes. + + + + + Methods for merging databases/entries. + + + + + Icon identifiers for groups and password entries. + + + + + Virtual identifier -- represents the number of icons. + + + + + Use default user credentials (provided by the system). + + + + + Default or Manual, depending on whether + manual credentials are available. + This type exists for supporting upgrading from KeePass + 2.28 to 2.29; the user cannot select this type. + + + + + Comparison modes for in-memory protected objects. + + + + + Ignore the in-memory protection states. + + + + + Ignore the in-memory protection states of standard + objects; do compare in-memory protection states of + custom objects. + + + + + Compare in-memory protection states. + + + + + Empty standard string fields are considered to be the + same as non-existing standard string fields. + This doesn't affect custom string comparisons. + + + + + The I/O connection is being opened for reading. + + + + + The I/O connection is being opened for writing. + + + + + The I/O connection is being opened for testing + whether a file/object exists. + + + + + The I/O connection is being opened for deleting a file/object. + + + + + The I/O connection is being opened for renaming/moving a file/object. + + + + + This flag prevents any handles being garbage-collected + before the started process has terminated, without + blocking the current thread. + + + + + UIIcon indicates that the returned image is going + to be displayed as icon in the UI and that it is not + subject to future changes in size. + + + + + A class representing a password entry. A password entry consists of several + fields like title, user name, password, etc. Each password entry has a + unique ID (UUID). + + + + + Construct a new, empty password entry. Member variables will be initialized + to their default values. + + If true, a new UUID will be created + for this entry. If false, the UUID is zero and you must set it + manually later. + If true, the creation, last modification + and last access times will be set to the current system time. + + + + Clone the current entry. The returned entry is an exact value copy + of the current entry (including UUID and parent group reference). + All mutable members are cloned. + + Exact value clone. All references to mutable values changed. + + + + Assign properties to the current entry based on a template entry. + + Template entry. Must not be null. + Only set the properties of the template entry + if it is newer than the current one. + If true, the history will be + copied, too. + If true, the + LocationChanged property is copied, otherwise not. + + + + Touch the entry. This function updates the internal last access + time. If the parameter is true, + the last modification time gets updated, too. + + Modify last modification time. + + + + Touch the entry. This function updates the internal last access + time. If the parameter is true, + the last modification time gets updated, too. + + Modify last modification time. + If true, all parent objects + get touched, too. + + + + Create a backup of this entry. The backup item doesn't contain any + history items. + + + + + Create a backup of this entry. The backup item doesn't contain any + history items. + If this parameter isn't null, + the history list is maintained automatically (i.e. old backups are + deleted if there are too many or the history size is too large). + This parameter may be null (no maintenance then). + + + + + Restore an entry snapshot from backups. + + Index of the backup item, to which + should be reverted. + + + + Restore an entry snapshot from backups. + + Index of the backup item, to which + should be reverted. + If this parameter isn't null, + the history list is maintained automatically (i.e. old backups are + deleted if there are too many or the history size is too large). + This parameter may be null (no maintenance then). + + + + Delete old history entries if there are too many or the + history size is too large. + If one or more history entries have been deleted, + true is returned. Otherwise false. + + + + + Approximate the total size (in process memory) of this entry + in bytes (including strings, binaries and history entries). + + Size in bytes. + + + + UUID of this entry. + + + + + Reference to a group which contains the current entry. + + + + + The date/time when the location of the object was last changed. + + + + + Get or set all entry strings. + + + + + Get or set all entry binaries. + + + + + Get or set all auto-type window/keystroke sequence associations. + + + + + Get all previous versions of this entry (backups). + + + + + Image ID specifying the icon that will be used for this entry. + + + + + Get the custom icon ID. This value is 0, if no custom icon is + being used (i.e. the icon specified by the IconID property + should be displayed). + + + + + Get or set the foreground color of this entry. + + + + + Get or set the background color of this entry. + + + + + The date/time when this entry was created. + + + + + The date/time when this entry was last modified. + + + + + The date/time when this entry was last accessed (read). + + + + + The date/time when this entry expires. Use the Expires property + to specify if the entry does actually expire or not. + + + + + Specifies whether the entry expires or not. + + + + + Get or set the usage count of the entry. To increase the usage + count by one, use the Touch function. + + + + + Entry-specific override URL. + + + + + List of tags associated with this entry. + + + + + Custom data container that can be used by plugins to store + own data in KeePass entries. + The data is stored in the encrypted part of encrypted + database files. + Use unique names for your items, e.g. "PluginName_ItemName". + + + + + A string that is protected in process memory. + ProtectedString objects are immutable and thread-safe. + + + + + Construct a new protected string object. Protection is + disabled. + + + + + Construct a new protected string. The string is initialized + to the value supplied in the parameters. + + If this parameter is true, + the string will be protected in memory (encrypted). If it + is false, the string will be stored as plain-text. + The initial string value. + + + + Construct a new protected string. The string is initialized + to the value supplied in the parameters (UTF-8 encoded string). + + If this parameter is true, + the string will be protected in memory (encrypted). If it + is false, the string will be stored as plain-text. + The initial string value, encoded as + UTF-8 byte array. This parameter won't be modified; the caller + is responsible for clearing it. + + + + Construct a new protected string. The string is initialized + to the value passed in the XorredBuffer object. + + Enable protection or not. + XorredBuffer object containing the + string in UTF-8 representation. The UTF-8 string must not + be null-terminated. + + + + Convert the protected string to a standard string object. + Be careful with this function, as the returned string object + isn't protected anymore and stored in plain-text in the + process memory. + + Plain-text string. Is never null. + + + + Read out the string and return it as a char array. + The returned array is not protected and should be cleared by + the caller. + + Plain-text char array. + + + + Read out the string and return a byte array that contains the + string encoded using UTF-8. + The returned array is not protected and should be cleared by + the caller. + + Plain-text UTF-8 byte array. + + + + Get the string as an UTF-8 sequence xorred with bytes + from a CryptoRandomStream. + + + + + Get an empty ProtectedString object, without protection. + + + + + Get an empty ProtectedString object, with protection turned on. + + + + + A flag specifying whether the ProtectedString object + has turned on memory protection or not. + + + + + Length of the protected string, in characters. + + + + + A protected binary, i.e. a byte array that is encrypted in memory. + A ProtectedBinary object is immutable and thread-safe. + + + + + Construct a new, empty protected binary data object. + Protection is disabled. + + + + + Construct a new protected binary data object. + + If this paremeter is true, + the data will be encrypted in memory. If it is false, the + data is stored in plain-text in the process memory. + Value of the protected object. + The input parameter is not modified and + ProtectedBinary doesn't take ownership of the data, + i.e. the caller is responsible for clearing it. + + + + Construct a new protected binary data object. + + If this paremeter is true, + the data will be encrypted in memory. If it is false, the + data is stored in plain-text in the process memory. + Value of the protected object. + The input parameter is not modified and + ProtectedBinary doesn't take ownership of the data, + i.e. the caller is responsible for clearing it. + Offset for . + Size for . + + + + Construct a new protected binary data object. + Copy the data from a XorredBuffer object. + + Enable protection or not. + XorredBuffer object containing the data. + + + + Get a copy of the protected data as a byte array. + Please note that the returned byte array is not protected and + can therefore been read by any other application. + Make sure that your clear it properly after usage. + + Unprotected byte array. This is always a copy of the internal + protected data and can therefore be cleared safely. + + + + Get the data xorred with bytes from a CryptoRandomStream. + + + + + A plugin can provide a custom memory protection method + by assigning a non-null delegate to this property. + + + + + A flag specifying whether the ProtectedBinary object has + turned on memory protection or not. + + + + + Length of the stored data. + + + + + Class containing self-test methods. + + + + + Perform a self-test. + + + + + Application-wide logging services. + + + + + Represents an object that has been deleted. + + + + + Construct a new PwDeletedObject object. + + + + + Clone the object. + + Value copy of the current object. + + + + UUID of the entry that has been deleted. + + + + + The date/time when the entry has been deleted. + + + + + Master password/passphrase as provided by the user. + + + + + Get the password as protected string. This is null + unless remembering the password has been turned on. + + + + + Get key data. Querying this property is fast (it returns a + reference to a cached ProtectedBinary object). + If no key data is available, null is returned. + + + + + A list of ProtectedBinary objects (dictionary). + + + + + Construct a new list of protected binaries. + + + + + Clone the current ProtectedBinaryList object, including all + stored protected strings. + + New ProtectedBinaryList object. + + + + Get one of the stored binaries. + + Binary identifier. + Protected binary. If the binary identified by + cannot be found, the function + returns null. + Thrown if the input + parameter is null. + + + + Set a binary object. + + Identifier of the binary field to modify. + New value. This parameter must not be null. + Thrown if any of the input + parameters is null. + + + + Remove a binary object. + + Identifier of the binary field to remove. + Returns true if the object has been successfully + removed, otherwise false. + Thrown if the input parameter + is null. + + + + Get the number of binaries in this entry. + + + + diff --git a/src/Build/PrepMonoDev.sh b/src/Build/PrepMonoDev.sh new file mode 100644 index 0000000..af5ffcb --- /dev/null +++ b/src/Build/PrepMonoDev.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +kpBuild="$(pwd)" +kpRoot="${kpBuild}/.." + +# Mono's resource compiler/linker doesn't support ICO files +# containing high resolution images (in PNG format) +kpIco="${kpRoot}/Ext/Icons_15_VA/LowResIcons/KeePass_LR.ico" +kpIcoG="${kpRoot}/Ext/Icons_15_VA/LowResIcons/KeePass_LR_G.ico" +kpIcoR="${kpRoot}/Ext/Icons_15_VA/LowResIcons/KeePass_LR_R.ico" +kpIcoY="${kpRoot}/Ext/Icons_15_VA/LowResIcons/KeePass_LR_Y.ico" + +fnPrepSolution() +{ + cd "${kpRoot}" + local kpSln="KeePass.sln" + + # Update solution format to 11 (this targets Mono 4 rather than 3.5) + sed -i 's!Format Version 10\.00!Format Version 11\.00!g' "${kpSln}" +} + +fnPrepKeePass() +{ + cd "${kpRoot}/KeePass" + local kpCsProj="KeePass.csproj" + + sed -i 's! ToolsVersion="3\.5"!!g' "${kpCsProj}" + sed -i 's!true!false!g' "${kpCsProj}" + sed -i '/sgen\.exe/d' "${kpCsProj}" + + cp -f "${kpIco}" KeePass.ico + cp -f "${kpIco}" Resources/Icons/KeePass.ico + cp -f "${kpIcoG}" Resources/Icons/KeePass_G.ico + cp -f "${kpIcoR}" Resources/Icons/KeePass_R.ico + cp -f "${kpIcoY}" Resources/Icons/KeePass_Y.ico +} + +fnPrepKeePassLib() +{ + cd "${kpRoot}/KeePassLib" + local kpCsProj="KeePassLib.csproj" + local kpXmlUtilEx="Utility/XmlUtilEx.cs" + + sed -i 's! ToolsVersion="3\.5"!!g' "${kpCsProj}" + sed -i 's!true!false!g' "${kpCsProj}" + + sed -i -E 's!(xrs\.ProhibitDtd = true;)!// \1!g' "${kpXmlUtilEx}" + sed -i -E 's!// (xrs\.DtdProcessing = DtdProcessing\.Prohibit;)!\1!g' "${kpXmlUtilEx}" +} + +fnPrepTrlUtil() +{ + cd "${kpRoot}/Translation/TrlUtil" + local kpCsProj="TrlUtil.csproj" + + sed -i 's! ToolsVersion="3\.5"!!g' "${kpCsProj}" + + cp -f "${kpIco}" Resources/KeePass.ico +} + +fnPrepSolution +fnPrepKeePass +fnPrepKeePassLib +fnPrepTrlUtil + +cd "${kpBuild}" diff --git a/src/Docs/Chm/KeePass.hhp b/src/Docs/Chm/KeePass.hhp new file mode 100644 index 0000000..7f9e08a --- /dev/null +++ b/src/Docs/Chm/KeePass.hhp @@ -0,0 +1,61 @@ +[OPTIONS] +Compatibility=1.1 or later +Compiled file=KeePass.chm +Contents file=KeePassContents.hhc +Default topic=help\base\index.html +Display compile progress=No +Full-text search=Yes +Language=0x409 Englisch (USA) +Title=KeePass Help + + +[FILES] +help\index.html +help\base\autotype.html +help\base\autourl.html +help\base\cmdline.html +help\base\configuration.html +help\base\credits.html +help\base\faq.html +help\base\faq_tech.html +help\base\fieldrefs.html +help\base\firststeps.html +help\base\importexport.html +help\base\index.html +help\base\integration.html +help\base\keys.html +help\base\license_lgpl.html +help\base\multiuser.html +help\base\placeholders.html +help\base\pwgenerator.html +help\base\repair.html +help\base\search.html +help\base\secedits.html +help\base\security.html +help\base\tans.html +help\base\terms.html +help\base\usingpws.html +help\v2\autotype_obfuscation.html +help\v2\dbsettings.html +help\v2\entry.html +help\v2\guioptions.html +help\v2\index.html +help\v2\ioconnect.html +help\v2\license.html +help\v2\plugins.html +help\v2\policy.html +help\v2\setup.html +help\v2\sync.html +help\v2\translation.html +help\v2\triggers.html +help\v2\version.html +help\v2\xml_replace.html +help\v2_dev\customize.html +help\v2_dev\plg_index.html +help\v2_dev\scr_index.html +help\v2_dev\scr_kps_index.html +help\v2_dev\scr_sc_index.html +images\back.gif + +[INFOTYPES] + diff --git a/src/Docs/Chm/KeePassContents.hhc b/src/Docs/Chm/KeePassContents.hhc new file mode 100644 index 0000000..8601085 --- /dev/null +++ b/src/Docs/Chm/KeePassContents.hhc @@ -0,0 +1,198 @@ + + + + + + + + + + + diff --git a/src/Docs/Chm/default.css b/src/Docs/Chm/default.css new file mode 100644 index 0000000..5fdb13a --- /dev/null +++ b/src/Docs/Chm/default.css @@ -0,0 +1,524 @@ +/* + Copyright (C) 2003-2023 Dominik Reichl. +*/ + +body, kbd kbd { + font-family: Verdana, Arial, sans-serif; + font-size: 9.75pt; +} + +body { + color: #000000; + background-color: #FFFFFF; +} +@media not all and (forced-colors: active) { + body { + background-image: url("images/back.gif"); + background-repeat: repeat; + background-attachment: fixed; + } +} + +p { + margin-left: 0px; +} + +/* ul { + margin-left: 20px; + list-style: disc; +} */ + +h1 { + font-size: 15.00pt; + font-weight: bold; +} + +h2 { + font-size: 13.50pt; + font-weight: bold; +} + +h3 { + font-size: 11.25pt; + font-weight: bold; +} + +h4 { + font-size: 9.75pt; + font-weight: bold; +} + +h5 { + font-size: 9.00pt; + font-weight: bold; +} + +h6 { + font-size: 7.50pt; + font-weight: normal; +} + +hr { + display: block; + height: 0px; + border-style: none none solid none; + border-width: 0px 0px 1px 0px; + border-bottom-color: #7F7F7F; + margin: 0px auto 0px auto; + padding: 0px 0px 0px 0px; +} + +table { + empty-cells: show; +} + +th, td { + text-align: left; + vertical-align: top; +} + +pre { + display: block; + background-color: #EEEEEE; /* #E6E6E6 */ + white-space: pre-wrap; + overflow: auto; + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-all; + -moz-tab-size: 4; + tab-size: 4; +} + +kbd kbd { + padding: 0px 4px 1px 4px; + border: 1px solid #808080; + border-collapse: collapse; + border-radius: 2px; + box-shadow: 0.1em 0.15em 0.2em #C5C5C5; + color: #000000; + background-color: #EEEEEE; + background-image: -webkit-linear-gradient(top, #EEEEEE, #FAFAFA, #EEEEEE); + background-image: -moz-linear-gradient(top, #EEEEEE, #FAFAFA, #EEEEEE); + background-image: -ms-linear-gradient(top, #EEEEEE, #FAFAFA, #EEEEEE); + background-image: linear-gradient(to bottom, #EEEEEE, #FAFAFA, #EEEEEE); +} + +/* --------------------------------------------------------------------- */ + +a { + color: #0000DD; + text-decoration: none; +} + +a:hover, a:active { + color: #6699FF; + text-decoration: underline; +} + +/* --------------------------------------------------------------------- */ + +.menubox { + display: block; + border: 1px solid #C5C5C5; + margin: 0px 1px 0px 0px; + padding: 0px 0px 0px 0px; + color: #000000; + background-color: #FFFFFF; + font-size: 8.25pt; +} + +.menubox .menutitle { + padding: 1px 1px 1px 3px; + color: #005101; + background-color: #C5C5C5; + background-image: -webkit-linear-gradient(left, #C5C5C5, #E5E5E5); + background-image: -moz-linear-gradient(left, #C5C5C5, #E5E5E5); + background-image: -ms-linear-gradient(left, #C5C5C5, #E5E5E5); + background-image: linear-gradient(to right, #C5C5C5, #E5E5E5); + font-size: 7.50pt; + font-weight: bold; +} + +.menubox > img { /* Icon of a folder */ + margin: 2px 0px 2px 2px; /* See 'a' (border + padding) */ +} + +.menubox a { + display: block; + padding: 1px 1px 1px 1px; /* See also '> img' */ + border: 1px solid #FFFFFF; /* See also '> img' */ + border-radius: 2px; + color: #000000; + text-decoration: none; + hyphens: none; + white-space: nowrap; +} + +.menubox a:hover, .menubox a:active { + border: 1px solid #0A246A; + background-color: #B6BDD2; + background-image: -webkit-linear-gradient(top, #D9E5F9, #B8BED8); + background-image: -moz-linear-gradient(top, #D9E5F9, #B8BED8); + background-image: -ms-linear-gradient(top, #D9E5F9, #B8BED8); + background-image: linear-gradient(to bottom, #D9E5F9, #B8BED8); +} + +/* --------------------------------------------------------------------- */ + +table.laytable, table.laytablews { + width: 100%; + border: 0px none; +} + +table.laytable { + border-collapse: collapse; +} + +table.laytable > tr > th, table.laytable > tbody > tr > th, +table.laytable > tr > td, table.laytable > tbody > tr > td { + padding: 2px 2px 2px 2px; +} + +table.laytable > tr:first-of-type > th, table.laytable > tbody > tr:first-of-type > th, +table.laytable > tr:first-of-type > td, table.laytable > tbody > tr:first-of-type > td { + padding-top: 0px; +} + +table.laytable > tr > th:first-of-type, table.laytable > tbody > tr > th:first-of-type, +table.laytable > tr > td:first-of-type, table.laytable > tbody > tr > td:first-of-type { + padding-left: 0px; +} + +table.laytable > tr:last-of-type > th, table.laytable > tbody > tr:last-of-type > th, +table.laytable > tr:last-of-type > td, table.laytable > tbody > tr:last-of-type > td { + padding-bottom: 0px; +} + +table.laytable > tr > th:last-of-type, table.laytable > tbody > tr > th:last-of-type, +table.laytable > tr > td:last-of-type, table.laytable > tbody > tr > td:last-of-type { + padding-right: 0px; +} + +/* --------------------------------------------------------------------- */ + +table.tablebox, table.tablebox75 { + background-color: #EEEEEE; + padding: 0px 0px 0px 0px; +} + +table.tablebox { + width: 100%; + margin: 0px 0px 0px 0px; +} + +table.tablebox75 { + width: 75%; + margin: 0px auto 0px auto; +} + +table.tablebox, table.tablebox75, +table.tablebox tr th, table.tablebox75 tr th, +table.tablebox tr td, table.tablebox75 tr td { + border: 1px solid #AFB5CF; + border-collapse: collapse; +} + +table.tablebox tr th, table.tablebox75 tr th { + padding: 2px 5px 2px 5px; + background-color: #EEEEEE; + background-image: -webkit-linear-gradient(top, #C1C1C1, #EEEEEE); + background-image: -moz-linear-gradient(top, #C1C1C1, #EEEEEE); + background-image: -ms-linear-gradient(top, #C1C1C1, #EEEEEE); + background-image: linear-gradient(to bottom, #C1C1C1, #EEEEEE); + font-weight: bold; +} + +table.tablebox tr td, table.tablebox75 tr td { + padding: 5px 5px 5px 5px; + background-color: #F0F0F0; +} + +/* --------------------------------------------------------------------- */ + +img { + border: 0px none; + vertical-align: middle; +} + +img.textimg { + height: 1em; +} + +/* --------------------------------------------------------------------- */ + +.tooltipex { + position: absolute; + display: none; + background-color: #FFFFE0; + padding: 1px 2px 1px 2px; + opacity: 0.9; + border: 1px solid #000000; +} + +/* --------------------------------------------------------------------- */ + +div.specificbox { + border: 1px solid #808080; + border-radius: 5px; + display: block; + background-color: #EEF0FF; + padding: 1px 2px 2px 2px; +} + +div.specificbox div.specifictitle { + font-size: 7.50pt; + font-weight: bold; + border-left: 0px none; + border-right: 0px none; + border-bottom: thin dotted #808080; + border-top: 0px none; + text-align: left; + margin-bottom: 3px; +} + +/* --------------------------------------------------------------------- */ + +table.sectionheader { + width: 100%; + border: thin solid #808080; + -moz-box-shadow: 1px 1px 5px #808080; + -webkit-box-shadow: 1px 1px 5px #808080; + box-shadow: 1px 1px 5px #808080; + background-color: #F0F8FF; + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; +} + +table.sectionheader tr td { + border: 0px none; + border-collapse: collapse; + vertical-align: middle; + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; +} + +table.sectionheader tr td:nth-of-type(1) { + width: 68px; +} + +table.sectionheader tr td img { + display: block; /* Inline results in additional space at the bottom */ + width: 64px; + height: 64px; +} + +table.sectionheader tr td h1 { + font-weight: normal; + margin: 0px 0px 0px 0px; +} + +table.sectionheader tr td p { /* Tag is optional (e.g. in news) */ + font-size: smaller; + margin: 0px 0px 0px 0px; +} + +/* --------------------------------------------------------------------- */ + +h2.sectiontitle { + font-size: 9.75pt; + font-weight: bold; + color: #005101; + background-color: #D0D6E6; + background-image: -webkit-linear-gradient(top, #C5C9DB, #DBE3F2); + background-image: -moz-linear-gradient(top, #C5C9DB, #DBE3F2); + background-image: -ms-linear-gradient(top, #C5C9DB, #DBE3F2); + background-image: linear-gradient(to bottom, #C5C9DB, #DBE3F2); + border: 1px solid #AFB5CF; + margin: 0px 0px 0px 0px; + padding: 2px 2px 2px 6px; +} + +h2.sectiontitle img { + margin-right: 2px; +} + +/* --------------------------------------------------------------------- */ + +td.helptopheader { + background-color: #E7E7FF; + background-image: -webkit-linear-gradient(top, #CFCFFF, #FFFFFF); + background-image: -moz-linear-gradient(top, #CFCFFF, #FFFFFF); + background-image: -ms-linear-gradient(top, #CFCFFF, #FFFFFF); + background-image: linear-gradient(to bottom, #CFCFFF, #FFFFFF); +} + +/* --------------------------------------------------------------------- */ + +div.tipdiv { + background-color: #FFFFE0; + padding: 1px 1px 1px 1px; + border: 1px solid #000000; +} + +.box100 { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100%; +} + +.withspc > li + li { + margin-top: 0.75em; +} + +.floatrightws { + float: right; + margin: 0px 0px 0.5em 0.5em; +} + +.big { + font-size: larger; +} + +/* .nowrap { + word-break: keep-all; + overflow-wrap: normal; + word-wrap: normal; + hyphens: none; + white-space: nowrap; +} */ + +.codekw { color: #0000FF; } +.codetp { color: #008888; } +.codecm { color: #008800; } +.codest { color: #880000; } + +.codexml { } /* For automatic syntax highlighting */ +.codexmldecl { color: #008888; } +.codexmltag { color: #880088; } + +.uiex_w { + border: 1px solid #808080; + background-color: #FFFFFF; + color: #000000; +} + +.uiex_t_sel { + background-color: #99D1FF; + color: #000000; +} + +/* --------------------------------------------------------------------- */ + +.il-m { + background: transparent url("images/il_main_v02.png") no-repeat; + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + border: 0px none; + overflow: hidden; + display: inline-block; + vertical-align: middle; +} + +.spr-m-kp-h { background-position: -1px -1px; width: 75px; height: 75px; } +.spr-m-home-mh { background-position: -78px -1px; width: 31px; height: 21px; } +.spr-m-contact-mh { background-position: -78px -24px; width: 31px; height: 21px; } +.spr-m-news-mh { background-position: -78px -47px; width: 31px; height: 21px; } +.spr-m-scrsh-mh { background-position: -111px -1px; width: 31px; height: 21px; } +.spr-m-dl-mh { background-position: -111px -24px; width: 31px; height: 21px; } +.spr-m-lang-mh { background-position: -111px -47px; width: 31px; height: 21px; } +.spr-m-ext-mh { background-position: -144px -1px; width: 31px; height: 21px; } +.spr-m-write-mh { background-position: -144px -24px; width: 31px; height: 21px; } +.spr-m-write-s { background-position: -151px -26px; width: 16px; height: 16px; } +.spr-m-help-ml { background-position: -177px -1px; width: 31px; height: 18px; } +.spr-m-info-ml { background-position: -177px -21px; width: 31px; height: 18px; } +.spr-m-sec-ml { background-position: -177px -41px; width: 31px; height: 18px; } +.spr-m-donate-ml { background-position: -177px -61px; width: 31px; height: 18px; } +.spr-m-award-ml { background-position: -210px -1px; width: 31px; height: 18px; } +.spr-m-links-ml { background-position: -210px -21px; width: 31px; height: 18px; } +.spr-m-xmag-ml { background-position: -210px -41px; width: 31px; height: 18px; } +.spr-m-osi-h { background-position: -1px -96px; width: 72px; height: 60px; } +.spr-m-award-s { background-position: -1px -158px; width: 16px; height: 16px; } +.spr-m-feed-s { background-position: -19px -158px; width: 16px; height: 16px; } +.spr-m-w3valid-b { background-position: -1px -176px; width: 80px; height: 15px; } +.spr-m-kp-b { background-position: -83px -176px; width: 80px; height: 15px; } + +/* --------------------------------------------------------------------- */ + +#consent_c { + display: none; + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + border: 0px none; + position: fixed; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + z-index: 254; + overflow: auto; + background-color: rgba(0, 0, 0, 0.85); + transition: background 1.5s; /* Cf. JavaScript timeout */ +} + +#consent_dlg { + border: 1px solid #808080; + position: relative; + width: 33%; + margin: 96px auto 0px auto; + padding: 16px 16px 16px 16px; + background-color: #EEEEEE; +} +@media (max-height: 540px) { + #consent_dlg { + margin-top: 4px; + } +} + +#consent_dlg button { + display: block; + width: 50%; + margin: 8px auto 8px auto; + padding: 8px 2px 8px 2px; + cursor: pointer; + color: #000000; + background-color: #E0E0E0; + background-image: -webkit-linear-gradient(top, #F0F0F0, #D0D0D0); + background-image: -moz-linear-gradient(top, #F0F0F0, #D0D0D0); + background-image: -ms-linear-gradient(top, #F0F0F0, #D0D0D0); + background-image: linear-gradient(to bottom, #F0F0F0, #D0D0D0); + border: 1px solid #A0A0A0; + border-radius: 5px; +} + +#consent_dlg button:first-of-type { + margin-top: 1em; +} +#consent_dlg button:last-of-type { + margin-bottom: 1em; +} + +#consent_dlg button:hover { + background-color: #E0F0FF; + background-image: -webkit-linear-gradient(top, #E8F8FF, #D8E8F8); + background-image: -moz-linear-gradient(top, #E8F8FF, #D8E8F8); + background-image: -ms-linear-gradient(top, #E8F8FF, #D8E8F8); + background-image: linear-gradient(to bottom, #E8F8FF, #D8E8F8); + border-color: #0080FF; +} + +#consent_dlg button:active { + background-color: #C8E0F0; + background-image: -webkit-linear-gradient(top, #D0E8F8, #C0D8E8); + background-image: -moz-linear-gradient(top, #D0E8F8, #C0D8E8); + background-image: -ms-linear-gradient(top, #D0E8F8, #C0D8E8); + background-image: linear-gradient(to bottom, #D0E8F8, #C0D8E8); + border-color: #004080; +} + +#consent_dlg button:focus { + outline: none; +} +#consent_dlg button[data-focusvisible="true"]:focus { /* Focus with keyboard, see JS */ + outline: 2px dotted #000080; +} diff --git a/src/Docs/Chm/help/base/autotype.html b/src/Docs/Chm/help/base/autotype.html new file mode 100644 index 0000000..1e2fc84 --- /dev/null +++ b/src/Docs/Chm/help/base/autotype.html @@ -0,0 +1,641 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Auto-Type - KeePass + + + + + + + + + + + + + + + + +

Auto-Type

+

Powerful feature that sends simulated keypresses to other applications.

+ + + +
+ + +

+Basic Auto-Type Information

+ +

KeePass features an "Auto-Type" functionality. This feature allows you to define +a sequence of keypresses, which KeePass can automatically perform for you. The +simulated keypresses can be sent to any other currently open window of your choice (browser windows, +login dialogs, ...).

+ +

By default, the sent keystroke sequence is {USERNAME}{TAB}{PASSWORD}{ENTER}, +i.e. it first types the user name of the selected entry, then presses the Tab key, +then types the password of the entry and finally presses the Enter key.

+ +

For TAN entries, the default sequence is {PASSWORD}, +i.e. it just types the TAN into the target window, without pressing Enter.

+ + + + + + +Auto-Type can be configured individually for each entry using the +Auto-Type tab page on the entry dialog (select an entry → Edit Entry). +On this page you can specify a default sequence and customize specific +window/sequence associations.
+
+Two-Channel Auto-Type Obfuscation is supported (making +Auto-Type resistant against keyloggers). + + +

Additionally, you can create customized window/sequence associations, which override the +default sequence. You can specify different keystroke sequences for different windows for each entry. +For example, imagine a webpage, to which you want to login, that has multiple +pages where one can login. These pages could all look a bit different (on one +you could additionally need to check some checkbox – like often seen in forums). +Here creating customized window/sequence associations solves the problems: you simply +specify different auto-type sequences for each windows (identified by their window +titles).

+ +

Invoking Auto-Type:
+There are three different methods to invoke auto-type:

+ + + +

All methods are explained in detail below.

+ +

Input Focus:
+Note that auto-type starts typing into the control of the target window +that has the input focus. Thus, for example for the default +sequence you have to ensure that the input focus is set to the +user name control of the target window before invoking auto-type using any of +the above methods.

+ +
+ + +

+Requirements and Limitations

+ +

Rights:
+For auto-type to work, KeePass must be running with the same or higher +rights as the target application. Especially, if the target application +is running with administrative rights, KeePass must be running with +administrative rights, too. For details, see + +Windows Integrity Mechanism Design. +An example are certain instances of VMware Workstation that run on +a higher integrity level.

+ +

Remote Desktops and Virtual Machines:
+KeePass does not know the keyboard layout that has been selected in +a remote desktop or virtual machine window. +If you want to auto-type into such a window, you must ensure +that the local and the remote/virtual system are using the same +keyboard layout.

+ +

When performing auto-type into a remote desktop or virtual machine +window, the following characters may be problematic (depending on the +exact circumstances) and should therefore be avoided, if possible: +" (U+0022), +' (U+0027), +^ (U+005E), +` (U+0060), +~ (U+007E), +¨ (U+00A8), +¯ (U+00AF), +° (U+00B0), +´ (U+00B4), +¸ (U+00B8), +spacing modifier letters (U+02B0 to U+02FF), +and characters that cannot be realized with a direct key combination.

+ +

Wayland:
+On a Unix-like system with a Wayland compositor, there may be further +limitations; see the Auto-Type on Wayland page.

+ +
+ + +

+Context Menu: 'Perform Auto-Type' Command

+ +

This method is the one that requires the least amount of configuration and is +the simpler one, but it has the disadvantage that you need to select the entry +in KeePass which you want to auto-type.

+ +

The method is simple: right-click on an entry of your currently opened database +and click 'Perform Auto-Type' (or alternatively press the +Ctrl+V +shortcut for this command). The window that previously got the focus +(i.e. the one in which you worked before switching to KeePass) will be brought +to the foreground and KeePass auto-types into this window.

+ +

The sequence which is auto-typed depends on the window's title. If you didn't +specify any custom window/sequence associations, the default sequence is sent. If +you created associations, KeePass uses the sequence of the first matching +association. If none of the associations match, the default sequence is used.

+ +
+ + +

+Global Auto-Type Hot Key

+ +

This is the more powerful method, but it also requires a little bit more +work/knowledge, before it can be used.

+ +

Simple Global Auto-Type Example:

+ +
    +
  1. Create an entry in KeePass titled Notepad with values for user name and password.
  2. +
  3. Start Notepad (under 'Programs' → 'Accessories').
  4. +
  5. Press Ctrl+Alt+A within Notepad. +The user name and password will be typed into Notepad.
  6. +
+ +

The KeePass entry title Notepad is matched with the window title of +Notepad and the default Auto-Type sequence is typed.

+ +

How It Works - Details:

+ +

KeePass registers a system-wide hot key for auto-type. The advantage of +this hot key is that you don't need to switch to the KeePass window and +select the entry. You simply press the hot key while having the target window +open (i.e. the window which will receive the simulated keypresses).

+ +

By default, the global hot key is +Ctrl+Alt+A +(i.e. hold the Ctrl and Alt keys, +press A and release all keys). +You can change this hot key in the options dialog +(main menu 'Tools' → 'Options' → tab + + + +'Integration'): + +here, click into the global auto-type hot key textbox and press the hot key +that you wish to use. If the hot key is usable, it will appear in the textbox.

+ +

When you press the hot key, KeePass looks at the title of the currently opened window and +searches the currently opened database for usable entries. If KeePass finds multiple +entries that can be used, it displays a selection dialog. +An entry is considered to be usable for the current window title when +at least one of the following conditions is fulfilled:

+ + + +

The second condition has been mentioned already, but the first one +is new. By using entry titles as filters for window titles, the configuration amount +for auto-type is almost zero: you only need to make sure that the entry title +is contained in the window title of the window into which you want the entry to be +auto-typed. Of course, this is not always possible (for example, if a webpage has a +very generic title like "Welcome"), here you need to +use custom window/sequence associations.

+ + + + + + +Custom window/sequence associations can be specified on the 'Auto-Type' tab +page of each entry.
+
+The associations complement the KeePass entry title. +Any associations specified will be used in addition to the KeePass entry +title to determine a match. + + +

Auto-Type window definitions, entry titles and URLs are Spr-compiled, i.e. +placeholders, +environment variables, +field references, etc. can be used.

+ +
+ + +

+Auto-Type Keystroke Sequences

+ +

An auto-type keystroke sequence is a one-line string that can contain +placeholders and special key codes.

+ +

A complete list of all supported placeholders can be found on the page +Placeholders. The special key codes can +be found below.

+ +

Above you've seen already that the +default auto-type is {USERNAME}{TAB}{PASSWORD}{ENTER}. Here, +{USERNAME} and {PASSWORD} are placeholders: when auto-type +is performed, these are replaced by the appropriate field values of the entry. +{TAB} and {ENTER} are special key codes: these are replaced +by the appropriate keypresses. Special key codes are the only way to specify special +keys like Arrow-Down, Shift, Escape, etc.

+ +

Of course, keystroke sequences can also contain simple characters to be sent. +For example, the following string is perfectly valid as keystroke sequence string:
+{USERNAME}{TAB}Some text to be sent!{ENTER}.

+ + + + + + +Special key codes are case-insensitive. + + +

Special Keys:
+The following codes for special keys are supported:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Special KeyCode
Tab{TAB}
Enter{ENTER} or ~
Arrow Up{UP}
Arrow Down{DOWN}
Arrow Left{LEFT}
Arrow Right{RIGHT}
Insert{INSERT} or {INS}
Delete{DELETE} or {DEL}
Home{HOME}
End{END}
Page Up{PGUP}
Page Down{PGDN}
Space{SPACE}
Backspace{BACKSPACE}, +{BS} or {BKSP}
Break{BREAK}
Caps-Lock{CAPSLOCK}
Escape{ESC}
Windows Key{WIN} (equ. to {LWIN})
Windows Key: left, right{LWIN}, {RWIN}
Apps / Menu{APPS}
Help{HELP}
Numlock{NUMLOCK}
Print Screen{PRTSC}
Scroll Lock{SCROLLLOCK}
F1 - F16{F1} - {F16}
Numeric Keypad +{ADD}
Numeric Keypad -{SUBTRACT}
Numeric Keypad *{MULTIPLY}
Numeric Keypad /{DIVIDE}
Numeric Keypad 0 to 9{NUMPAD0} to {NUMPAD9}
Shift+
Ctrl^
Alt%
+ +
+ + + + + + + + + + + + + + + + +
Special KeyCode
+{+}
%{%}
^{^}
~{~}
(, ){(}, {)}
[, ]{[}, {]}
{, }{{}, {}}
+ + +

Additionally, some special commands are supported:

+ + + + + + + + + + +
Command SyntaxAction
{DELAY X}Delays X milliseconds.
{DELAY=X}Sets the default +delay to X milliseconds for all following keypresses.
{CLEARFIELD}Clears the contents of the +edit control that currently has the focus (only single-line edit controls).
{VKEY X}Sends the + +virtual key of value X.
{APPACTIVATE WindowTitle}Activates +the window "WindowTitle".
{BEEP X Y}Beeps with +a frequency of X hertz and a duration of Y milliseconds.
+ +
+ + + + + + + +
Command SyntaxAction
{VKEY X F}Sends the +virtual key of value X; see below.
+ + +
+ + + +{VKEY X F}:
+This command sends the +virtual key of value X. +The parameter F is optional and may be a combination of the following +values: + + +

The values E and N are mutually exclusive. +It is recommended to specify neither E nor N, +if possible; KeePass then determines automatically whether the virtual key +is typically realized using an extended key.

+ +

The values D and U are mutually exclusive. +If neither D nor U is specified, KeePass +sends a keypress (i.e. down and up).

+ +

On Linux systems, KeePass automatically converts most Windows virtual key codes +to Linux key codes (i.e. the {VKEY ...} command works on both +systems).

+ +Examples: + + +Do not use the {VKEY ...} command to change the state of the +Shift, Ctrl and +Alt modifiers. For this, use +, +^ and % instead (see above). + + +
+ + +Keys and special keys (not placeholders or commands) can be repeated by +appending a number within the code. For example, {TAB 5} +presses the Tab key 5 times. + + +

Examples:

+ +

{TITLE}{TAB}{USERNAME}{TAB}{PASSWORD}{ENTER}
+Types the entry's title, a Tab, the user name, +a Tab, the password of the +currently selected entry, and presses Enter.

+ +

{TAB}{PASSWORD}{ENTER}
+Presses the Tab key, enters the entry's password and +presses Enter.

+ +

{USERNAME}{TAB}^v{ENTER}
+Types the user name, presses Tab, presses +Ctrl+V (which pastes data from the Windows +clipboard in most applications), and presses Enter.

+ +

Toggling Checkboxes:
+A checkbox (e.g. "Stay logged in on this computer") can +usually be toggled by sending a space character (' '). +Example:
+{USERNAME}{TAB}{PASSWORD}{TAB} {TAB}{ENTER}
+If there is a form with a user name field, a password field and a checkbox, +this sequence would enter the user name, the password and toggle the checkbox +that follows the password control.

+ +

Pressing Non-Default Buttons:
+Pressing non-default buttons works the same as toggling checkboxes: send +a space character (' '). +Note that this should only be used for non-default buttons; for +default buttons, {ENTER} should be sent instead.

+ +

Higher ANSI Characters:
+The auto-type function supports sending of higher ANSI characters in range 126-255. This +means that you can send special characters like ©, @, etc. without any problems; +you can write them directly into the keystroke sequence definition.

+ +
+ + +

+Target Window Filters

+ +

When creating a custom window/sequence association, you need to tell +KeePass how the matching window titles look like. Here, KeePass supports +simple wildcards:

+ + + + + + + + +
String with WildcardMeaning
STRINGMatches all window titles that are named exactly "STRING".
STRING*Matches all window titles that start with "STRING".
*STRINGMatches all window titles that end with "STRING".
*STRING*Matches all window titles that have "STRING" somewhere in the window title. This includes the string being directly at the start or at the end of the window title.
+ +
+ + + + + + +Wildcards may also appear in the middle of patterns. +For example, *Windows*Explorer* would match +Windows Internet Explorer.
+
+Additionally, matching using + +regular expressions is supported. In order to +tell KeePass that the pattern is a regular expression, enclose it in +//. For example, //B.?g Window// would +match Big Window, Bug Window and Bg Window. + + +

By using wildcards, you can make your auto-type associations browser-independent. +See the usage examples for more information.

+ +
+ + +

+Change Default Auto-Type Sequence

+ +

The default auto-type sequence (i.e. the one which is used when you don't specify +a custom one) is {USERNAME}{TAB}{PASSWORD}{ENTER}. KeePass allows you +to change this default sequence. Normally you won't need to change it (use +custom window/sequence definitions instead!), but it is quite useful when some +other application is interfering with KeePass (for example a security software that +always asks you for permission before allowing KeePass to auto-type).

+ + + + + + +By default, entries inherit the auto-type sequence of their containing group. +Groups also inherit the auto-type sequence of their parent groups. There is +only one top group (the first group contains all other groups). Consequently, if +you change the auto-type sequence of this very first group, all other groups +and their entries will use this sequence. Practically, this is a global override. +To change it, right-click on the first group, choose 'Edit Group' and switch +to the 'Auto-Type' tab. +
+ + +

+ + +

+Usage Example

+ +

Now let's have a look at a real-world example: logging into a website. In this example, +will we use the global auto-type hot key to fill out the login webpage. +First open the test page, and afterwards create a new entry +in KeePass with title Test Form and a user name and password +of your choice.

+ +

Let's assume the global auto-type hot key is set to +Ctrl+Alt+A (the default). +KeePass is running in the background, you have opened your database and the workspace is unlocked.

+ +

When you now navigate to the test page and are being prompted for your user name and password, +just click into the user name field and press +Ctrl+Alt+A. +KeePass enters the user name and password for you!

+ +

Why did this work? The window title of your browser window was +"Test Form - KeePass - Internet Explorer" or +"Test Form - KeePass - Mozilla Firefox", depending on the browser +you are using. Because we gave the entry in KeePass the title Test Form, the +entry title is contained in the window title, therefore KeePass uses this entry.

+ +

Here you see the huge advantages of auto-type: it not only doesn't require +any additional browser software +(the browser knows nothing of KeePass – there are no helper browser plugins required), +it is also browser-independent: the one entry that you created within KeePass works +for Internet Explorer and Mozilla Firefox (and other browsers) without +requiring any modifications or definitions.

+ +

When you would use window/sequence associations +(instead of entry title matching), you can achieve the same +browser-independent effect using wildcards: you could for example have used +Test Form - KeePass - * as window filter. This filter matches both +the Internet Explorer and the Firefox window.

+ + + diff --git a/src/Docs/Chm/help/base/autourl.html b/src/Docs/Chm/help/base/autourl.html new file mode 100644 index 0000000..098681f --- /dev/null +++ b/src/Docs/Chm/help/base/autourl.html @@ -0,0 +1,302 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + URL Field - KeePass + + + + + + + + + + + + + +

URL Field

+

The URL field supports various special protocols and placeholders.

+ + + +Usage Tips & Tricks: + + +
+ + +

+Standard Capabilities

+ +

The URL field can execute any valid URL for which a protocol handler is defined. +On most systems at least the http://, https://, +ftp:// and mailto: protocols are defined. +KeePass supports all protocols that Windows supports.

+ +

For example, if you globally (i.e. using the Windows Explorer) register PuTTY for ssh:// URLs, +KeePass will automatically use PuTTY for ssh:// URLs, too.

+ +
+ + +

+Executing Command Lines

+ +

Instead of a URL, you can also execute command lines using the URL field. +To tell KeePass that the line you entered +is a command line, prefix it using cmd://. For example if you would like to execute +Notepad, your URL could look like this:

+ +
cmd://C:\Windows\Notepad.exe C:\Test\MyTestFile.txt
+ +

The virtual cmd:// protocol also supports parameters for executable +files, in contrast to +the file:// protocol. This was the main reason why cmd:// +was introduced; with file:// you +aren't able to pass any parameters to started applications. Use the cmd:// +protocol instead.

+ +

The paths for the cmd:// protocol don't need to be encoded. For example, +you do not have to replace space characters by %20, as it is normally +required for other URLs. KeePass just cuts away the cmd:// virtual +protocol prefix and passes the remaining command line to the system.

+ +

If the file path contains spaces, you must enclose it in quotes (").

+ +

Environment Variables:
+System environment variables are supported. +The name of the variable must be enclosed in '%' characters. +For example %TEMP% is replaced by the user's temporary path.

+ +

UNC Paths:
+Windows-style UNC paths (starting with \\) are directly +supported, i.e. do not need to be prefixed with cmd://.

+ +

Double Quotes (") and Backslashes (\):
+There are multiple rule sets for parsing command lines +(SHELLEXECUTEINFOW structure, +CommandLineToArgvW function, + +Microsoft C/C++ startup code, etc.). +These rule sets are contradictory; command lines are interpreted differently. +For example, in the SHELLEXECUTEINFOW structure documentation, +backslashes have no special meaning, whereas the +CommandLineToArgvW function sometimes interprets a backslash +as an escape character. +Another example: A"""B C"""D is +interpreted as one argument (namely A"B C"D) +by the Microsoft C/C++ startup code, whereas the CommandLineToArgvW +function returns two arguments +(namely A"B and C"D). +KeePass cannot know how the executed application will interpret its +command line, and there is no command line encoding that is +interpreted as intended by all applications. +Therefore, we recommend:

+ + +

Unix-like Systems:
+On Unix-like systems, KeePass assumes that double quotes (") +and backslashes (\) must be encoded. +Furthermore, KeePass assumes that single quotes (') +only occur in contexts where they must not be encoded (e.g. within +double quotes). So, if any of your arguments may contain a single quote, +you have to ensure that it occurs within such a context. +On Windows, this is irrelevant, as single quotes do not have a special meaning here.

+ +
+ + +

+Placeholders

+ +

In the URL field, you can use several placeholders that will get automatically replaced +when the URL is executed. For example:

+ +
https://www.example.com/default.php?user={USERNAME}&pass={PASSWORD}
+ +

For this entry, KeePass will replace {USERNAME} by the data of the username field and {PASSWORD} +by the data in the password field when you execute the link.

+ +

For a complete list of supported placeholders, see the page +Placeholders.

+ +

Also note that the special placeholders are supported, too. For example, +the {APPDIR} placeholder is replaced by the application +directory path of the currently running KeePass instance. It's the absolute path of the +directory containing the KeePass executable, without a trailing backslash. +If you would like to start a new KeePass instance, you could set the URL to:

+ +
cmd://"{APPDIR}\KeePass.exe"
+ +

To use different browsers for entries, you can use URLs like the following:
+cmd://{INTERNETEXPLORER} "https://www.example.com/"
+cmd://{FIREFOX} "https://www.example.com/"
+cmd://{OPERA} "https://www.example.com/"
+cmd://{GOOGLECHROME} "https://www.example.com/"
+cmd://{SAFARI} "https://www.example.com/"
+The browser placeholder will be replaced by the browser's executable path (if the +browser is installed).

+ +
+ + +

+Changing the URL Handler (URL Override)

+ +
+ + + + + + +

The URL field behavior can be overridden individually for each entry +using the field 'Override URL' (tab 'Properties' in the entry dialog). +This allows you to execute a specific URL, while still using the URL +field to (only) store data. +When double-clicking the URL field of the entry in the main window, the +specified command line (in the URL override field) will be run.

+ +

Using a different browser:
+If your default browser is Firefox and you want to open a specific site with +Internet Explorer, specify the following in the URL override field:

+ +

cmd://{INTERNETEXPLORER} "{URL}"

+ +

KeePass will open Internet Explorer and pass the data from the URL field +as the parameter. This uses a placeholder to find Internet +Explorer.

+ +

Globally changing the URL behavior:
+If you want to change the default URL action for a URL scheme +(e.g. http://, https:// or ftp://), +you can define a URL scheme override +in 'Tools' → 'Options' → tab 'Integration' → 'URL Overrides'. +This for example allows to specify a browser as default for websites +(in the dialog you can find several overrides for browsers like Internet Explorer, +Mozilla Firefox, Opera and Google Chrome).

+ +

URL scheme overrides can also be used to define new protocols. For example, +if you want to define a protocol kdbx:// that opens another KeePass database, +specify the following as override for the kdbx scheme (on Windows):
+cmd://"{APPDIR}\KeePass.exe" "{BASE:RMVSCM}" -pw-enc:"{PASSWORD_ENC}"
+or on Unix-like systems (Mono):
+cmd://mono "{APPDIR}/KeePass.exe" "{BASE:RMVSCM}" -pw-enc:"{PASSWORD_ENC}"
+If an entry now has a URL looking like kdbx://PathToYourDatabase.kdbx +and the master password for this database in the password field, +double-clicking the URL of the entry in the main window opens the other database. +The -pw-enc command line parameter and +the {PASSWORD_ENC} placeholder +allow passing the master password of the other database in encrypted form, +i.e. process monitors and similar utilities aren't be able to read the master password.

+ + +

+ + +

+Starting RDP/TS Sessions

+ +

You can use the URL field of entries and the virtual cmd:// +protocol to start remote desktop connections.

+ +

For this, enter the following in the URL field of an entry:

+ +
cmd://mstsc.exe
+ +

When you now double-click the URL field of the entry in the main window, a +Windows remote desktop connection is initiated.

+ +

MSTSC is the Windows terminal server connection program (remote desktop connection). +You can pass a path to an existing RDP file to the program to open it. For example, +the following URL opens the specified RDP file:

+ +
cmd://mstsc.exe "C:\My Files\Connection.rdp"
+ +

MSTSC also supports several command line options:

+ + + +
+ + +

+Executing Built-In Shell Commands

+ +

The URL field can be used to start applications/documents and URLs. +If you want to execute a built-in shell command, like COPY for +example, this however doesn't work directly, because there is no COPY.EXE +(in Windows 9x times there actually was one, but on all modern Windows operating +systems these commands are built-in to the command line window).

+ +

In order to execute built-in shell commands, you need to pass them to the +command line interpreter cmd.exe.

+ +

For the COPY command you would specify cmd.exe +as executable file and /C COPY from to as arguments (where +'from' and 'to' are paths). The /C +parameter tells cmd.exe to execute the command line that +follows.

+ +

In the URL field, your URL would look like the following:
+cmd://cmd.exe /C COPY from to
+In other locations, like command lines in the trigger system, +you can leave out the cmd:// URL prefix.

+ + + diff --git a/src/Docs/Chm/help/base/cmdline.html b/src/Docs/Chm/help/base/cmdline.html new file mode 100644 index 0000000..541098a --- /dev/null +++ b/src/Docs/Chm/help/base/cmdline.html @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Command Line Options - KeePass + + + + + + + + + + + + + +

Command Line Options

+

Command line options to automate KeePass tasks.

+ +

You can pass a file path in the command line in order to tell KeePass to open +this file immediately after startup.

+ +

Switches can be either prefixed using +a minus (-) or two minus characters (--). +On Windows, a slash (/) is another alternative. +The prefixes are equivalent; it doesn't matter which one you use.

+ +

Database file. +The database file location is passed as argument. Only one database file is allowed. +If the path contains a space, it must be enclosed in quotes (").

+ +

Password. +Passwords can be passed using the -pw: option. In order to +pass 'abc' as password, you would add the following argument to the command line: +-pw:abc. Note that there must be no space between the ':' and the +password. If your password contains a space, you must enclose it in quotes. For +example: -pw:"my secret password".

+ +

Using the -pw: option is not recommended, due to +security reasons (the operating system allows reading the command line +options of other applications).

+ +

When passing the -pw-stdin option, KeePass +reads the password from the StdIn stream. +This option is intended for programmatically passing the password to KeePass. +For entering the password by hand, it is recommended to use the +normal master key dialog instead (because in this dialog the password +is hidden by bullets/asterisks and it is encrypted by the process memory +protection).

+ +

Key file. +For supplying the key file location, the -keyfile: switch +exists. The same rules as above apply, just that you specify the key file location: +-keyfile:D:\pwsafe.key. You also need to quote the value, if it contains +a space, tab or other whitespace characters.

+ +

Preselection. +In order to just preselect a key file, use the -preselect: option. +For example, if you lock your database with a password and a key file, but +just want to type in the password (so, without selecting the key file manually), +your command line would look like this:

+ +
KeePass.exe "C:\My Documents\MyDatabase.kdbx" -preselect:C:\pwsafe.key
+ +

KeePass would then show a prompt for the password for the database, but in +the key file list, the C:\pwsafe.key file is selected already. When using the +-preselect: switch, KeePass by default activates the key file switch and +sets the focus to the password edit window.

+ +

Note the difference! The -preselect: switch just preselects the key file +for you and displays the login prompt. In contrast, the -keyfile: switch +doesn't prompt you for the (maybe missing) password.

+ +

Other. +The -minimize command line option makes KeePass start up minimized. +This option may not work when KeePass runs on Mono (due to a bug in Mono).

+ +

The -auto-type command line option makes other already opened +KeePass instances perform a global auto-type.

+ + + + + + +Additionally, the -useraccount switch is supported. If specified, the +current user account credentials will be used.
+
+The -iocredfromrecent switch makes KeePass load file +system credentials (not database key) from the most recently used files list. +Alternatively, the file system credentials can be specified using the +-iousername: and -iopassword: parameters. +The optional -ioiscomplete switch +tells KeePass that the path and file system credentials are complete +(the 'Open URL' dialog will not be displayed then).
+
+The -pw-enc: parameter is similar to -pw:, but +it requires the password to be encrypted. Encrypted passwords can be +generated using the {PASSWORD_ENC} +placeholder.
+
+The -entry-url-open option makes other already opened KeePass instances +search for an entry and open its URL. The entry is identified by its UUID, +which you can pass as -uuid: command line parameter.
+
+The -auto-type-password option is similar to -auto-type, +but auto-types only the password of a matching entry. +-auto-type-selected performs auto-type for the currently selected entry.
+
+The -cancel option causes all other KeePass instances to +cancel opening/saving a database file.
+
+The path of the local configuration file can be changed +using the -cfg-local: command line parameter. + + +

The order of the arguments is arbitrary.

+ +
+ +

+Usage Examples

+ +

Open the database file 'C:\My Documents\MyDatabase.kdbx' (KeePass will prompt you +for the password and/or key file location):

+ +
KeePass.exe "C:\My Documents\MyDatabase.kdbx"
+ +

If you got a database that is locked with a password 'abc', you could open it like this:

+ +
KeePass.exe "C:\My Documents\MyDatabaseWithPw.kdbx" -pw:abc
+ +

If your USB stick always mounts to drive F: and you've locked your database with a key file +on the USB stick, you could open your database as follows:

+ +
KeePass.exe "C:\My Documents\MyDatabaseWithFile.kdbx" -keyfile:F:\pwsafe.key
+ +

If you've locked your database using a password and a key file, you can combine +the two switches and open your database as follows:

+ +
KeePass.exe "C:\My Documents\MyDatabaseWithTwo.kdbx" -pw:abc -keyfile:F:\pwsafe.key
+ +

You have locked your database using a password and a key file, but only +want to have the key file preselected (i.e. you want to get prompted for the +password), your command line would look like this:

+ +
KeePass.exe "C:\My Documents\MyDatabaseWithTwo.kdbx" -preselect:F:\pwsafe.key
+ +
+ +

+Starting KeePass using a Batch File

+ +

Batch files can be used to start KeePass. Mostly you want to +specify some of the parameters listed above. You can theoretically +simply put the command line (i.e. application path and parameters) +into the batch file, but this is not recommended as the command +window will stay open until KeePass is closed. The following +method is recommended instead:

+ +
START "" KeePass.exe ..\MyDb.kdbx -pw:MySecretPw
+ +

This START command will run KeePass (which opens the +..\MyDb.kdbx file using +MySecretPw as password). KeePass is assumed to be in the same +directory (working directory) as the batch file, otherwise you need to +specify a different path.

+ +

START executes the given command line and immediately exits, +i.e. it doesn't wait until the application is terminated. Consequently, +the command window will disappear after KeePass has been started.

+ +

Please note the two quotes (") after the +START command. These quotes +are required if the application path contains quotes (in the example +above, the quotes could also be removed). +If you want to learn more about the START command syntax, type +START /? into the command window.

+ +
+ +

+Closing/Locking KeePass using a Batch File

+ +

To close all currently running KeePass instances, call +KeePass.exe with the '--exit-all' parameter:

+ +
KeePass.exe --exit-all
+ +

All KeePass windows will attempt to close. If a database has been modified, +KeePass will ask you whether you want to save or not. If you wish to save in +any case (i.e. a forced exit without any confirmation dialog), enable the +'Automatically save database on exit and workspace locking' option +in 'Tools' → 'Options' → tab 'Advanced'.

+ +

The KeePass instance that has been created by the command above is not visible (i.e. +it does not show a main window) and will immediately terminate after sending close +requests to the other instances.

+ +

The --lock-all and +--unlock-all command line options lock/unlock the workspaces +of all other KeePass instances.

+ + + diff --git a/src/Docs/Chm/help/base/configuration.html b/src/Docs/Chm/help/base/configuration.html new file mode 100644 index 0000000..dc679c9 --- /dev/null +++ b/src/Docs/Chm/help/base/configuration.html @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Configuration - KeePass + + + + + + + + + + + + + +

Configuration

+

Details about how and where KeePass stores its configuration.

+ +

KeePass supports multiple locations for storing configuration information: +the global configuration file in the KeePass application directory, +a local user-dependent one in the user's private configuration folder, and +an enforced configuration file in the KeePass application directory. +The first one is called global, +because everyone using this KeePass installation will +write to the same configuration file (and possibly overwriting settings of other +users). The second one is called local, because changes made to this configuration +file only affect the current user.

+ + + + + + +Configuration files are stored in XML format.

+ + + + + + + + + + + + + + + + + + + + + + +
ConfigurationLocationTypical File Path
GlobalApplication DirectoryC:\Program Files\KeePass Password Safe 2\KeePass.config.xml
Global (Virtualized)Windows Virtual StoreC:\Users\User Name\AppData\Local\VirtualStore\Program Files\KeePass Password Safe 2\KeePass.config.xml
LocalUser Application DataC:\Users\User Name\AppData\Roaming\KeePass\KeePass.config.xml
EnforcedApplication DirectoryC:\Program Files\KeePass Password Safe 2\KeePass.config.enforced.xml
+ + + + +

On Linux systems, the local configuration file is typically stored in +'$XDG_CONFIG_HOME/KeePass' (which often is '~/.config/KeePass', +where '~' is the user's home directory).

+ +
+ + +

+Installation by Administrator, Usage by User

+ +

If you use the KeePass installer and install the program with administrator rights, +the program directory will be write-protected when working +as a normal/limited user. KeePass will use local configuration files, i.e. save and load +the configuration from a file in your user directory.

+ +

Multiple users can use the locally installed KeePass. Configuration settings +will not be shared and can be configured individually by each user.

+ +
+ + +

+Portable Version

+ +

If you downloaded the portable version of KeePass (ZIP package), KeePass will +try to store its configuration in the application directory. No configuration +settings will be stored in the user directory (if the global configuration file is +writable).

+ +
+ + +

+Create Portable Version of Installed KeePass

+ +

If you are currently using a locally installed version of KeePass +(installed by the KeePass installer) and want to create a portable version of it, +first copy all files of KeePass to the portable device. Then get the configuration file +from your user directory (application data, see above) and copy it +over the configuration file on the portable device.

+ +
+ + +

+For Network Administrators: Enforced Configuration

+ +

Settings in an enforced configuration file +take precedence over settings in global and local +configuration files.

+ +

This feature is intended primarily for network administrators +who want to enforce certain settings for users of a shared +KeePass installation.

+ +

For details, please see the +Enforced Configuration +help page.

+ +
+ + +

+Technical Details

+ +

This section explains in detail how loading and saving the configuration works.

+ +

When KeePass starts up and finds both global and local configuration files, it must +decide the order in which KeePass tries to get the configuration items. +This is controlled by the +(Kee)PreferUserConfiguration flag in the global configuration +file. If it is not present, it defaults to false.

+ +

The flag is set to true in the global configuration file of the +KeePass installer package. The portable ZIP package does not contain a configuration file, +consequently the flag defaults to false.

+ + + + + + +Loading: + + +Saving: + + +The path of the local configuration file can be changed +using the '-cfg-local:' command line parameter. + + + + + + diff --git a/src/Docs/Chm/help/base/credits.html b/src/Docs/Chm/help/base/credits.html new file mode 100644 index 0000000..e854936 --- /dev/null +++ b/src/Docs/Chm/help/base/credits.html @@ -0,0 +1,887 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Acknowledgements / Credits - KeePass + + + + + + + + + + + + + +

Acknowledgements / Credits

+

Thanks to various people for contributions and/or work.

+ +

At this place I want to thank a lot of people very much for their help, +source code, suggestions and other contributions (in no particular order).

+ + + +
+ + +

+Donation Acknowledgements

+ +

Developing high-quality applications takes much time and resources. +Donations make it possible to keep up the current development standard. +Therefore, many thanks to all who donated to the project.

+ +

More information about donations and a list of people who donated +can be found here: +KeePass +Donations.

+ +
+ + +

+Source Code Acknowledgements

+ +

KeePass uses some classes and libraries written by different +people and given away for free. Here I want to thank them for writing +these classes and libraries.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AuthorClass / Library
Szymon StefanekC++ implementation +of the AES/Rijndael encryption algorithm.
Niels FergusonC implementation of the Twofish encryption algorithm.
Brian GladmanC implementation +of the SHA-2 (256/384/512) hashing algorithms.
Alvaro MendezMFC class for validating edit controls (CAMSEdit).
Brent CorkumMFC class for XP-style menu (BCMenu).
Davide CalabroMFC class for buttons with icons (CButtonST).
Zorglab, Chris Maunder, Alexander Bischofberger, James White, Descartes Systems Sciences Inc.MFC class for color pickers (CColourPickerXP).
Peter MaresMFC class for window side banners (CKCSideBannerWnd).
Chris MaunderMFC class for system tray icons (CSystemTray).
Hans Dietrich, Chris MaunderMFC class for hyperlinks in dialogs (XHyperLink).
LallousClass for sending simulated keystrokes to other applications + +(CSendKeys).
PJ NaughterMFC classes for checking for single instance +(CSingleInstance) +and version information +(CVersionInfo).
Bill RubinCommand line C++ classes.
Boost DevelopersBoost C++ libraries.
Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, Samuel Neves, +Thomas PorninC implementation +of the Argon2 password hashing function.
+ +
+ + + + + + + +
AuthorResource
Mark BurnettList of + + +10000 Top Passwords, which KeePass uses in its +password quality estimation algorithm.
+ +

+ + +

+Icon Acknowledgements

+ +

Many thanks to Christopher Bolin for creating the main KeePass icon +(see top left on this page) and its +variations. +Many thanks to Victor Andreyenkov for refining the application icons.

+ +

Many thanks to David Vignoni for creating the nice 'Nuvola' icon theme. +Most of the icons used in KeePass and on its website are icons of this theme. You can find the +original images on the website +of the author, and the license below.

+ +

Furthermore, thanks to the authors of the following icons that KeePass uses:

+ + +
+ + +

+Translation Acknowledgements

+ +

Many thanks to all people who created translations for KeePass.

+ +
+ + +

+Plugin Acknowledgements

+ +

Many thanks to all people who wrote plugins for KeePass. Without you, KeePass +would be a lot less powerful and useful!

+ +
+ + +

+Tools Acknowledgements

+ + + +

Thanks to Jordan Russell for creating Inno Setup. This +tool is used to create the KeePass installation program.

+ + +

Thanks to Dimitri van Heesch for the Doxygen utility, which is used to compile the source +code documentation.

+ +
+ + +

+Hosting/Distribution Acknowledgements

+ +
+ + ++ + + + + + + + + + + + + + +
+Thanks to SourceForge +for hosting the KeePass downloads / translations / plugins and for providing the +project support platform (forums, feature requests / bug trackers, ...) for free. +
+Thanks to domain)FACTORY +for hosting the KeePass website. +
+Thanks to datensysteme-lenk +for hosting the German KeePass support forum in the past. +
+ +

+ + +

+Suggestions and Forum Support Acknowledgements

+ +

Thanks to all the people answering questions of others in the KeePass +forums! A product is only as good as its support is, and I alone could +never provide such an excellent individual help platform.

+ +

A few persons should be mentioned here, because of an extraordinary amount +of suggestions (features, bug reports, ...) and helping others in the forums: +Paul Tannard, Wellread1 and Michael Scheer.

+ +
+ + +

+Special Acknowledgements

+ +

Thanks to Daniel Turini for suggesting "KeePass" +as the name of the project.

+ +

An especially big thanks to Bill Rubin. He not only contributed a lot of +source code to KeePass, he also had an enormous amount of feature and improvement suggestions, +helped people in the KeePass forums, and wrote a KeePass plugin for backing up +databases. He's also the reason why many of the sections in the KeePass Help +are very precise, helpful, clear and easy to understand. +In our countless hours long IM chats, we not only discussed much about the design +of KeePass, Bill also told me a lot about C++ and other stuff. Thanks!

+ +
+ + +

+Licenses of Components/Resources/etc.

+ + +

Nuvola Icon Theme

+ +

Usage of the icons is allowed under the terms of the LGPL license (which you can find +here: GNU Lesser General Public License), plus +an addition.

+ +
TITLE:  NUVOLA ICON THEME for KDE 3.x
+AUTHOR: David Vignoni | ICON KING
+SITE:   http://www.icon-king.com
+MAILING LIST: http://mail.icon-king.com/mailman/listinfo/nuvola_icon-king.com
+
+Copyright (c)  2003-2004  David Vignoni.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation,
+version 2.1 of the License.
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+You should have received a copy of the GNU Lesser General Public
+License along with this library (see the the license.txt file); if not, write
+to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+MA  02111-1307  USA
+#######**** NOTE THIS ADD-ON ****#######
+The GNU Lesser General Public License or LGPL is written for software libraries
+in the first place. The LGPL has to be considered valid for this artwork
+library too.
+Nuvola icon theme for KDE 3.x is a special kind of software library, it is an
+artwork library, it's elements can be used in a Graphical User Interface, or
+GUI.
+Source code, for this library means:
+ - raster png image* .
+The LGPL in some sections obliges you to make the files carry
+notices. With images this is in some cases impossible or hardly usefull.
+With this library a notice is placed at a prominent place in the directory
+containing the elements. You may follow this practice.
+The exception in section 6 of the GNU Lesser General Public License covers
+the use of elements of this art library in a GUI.
+dave [at] icon-king.com
+
+Date:       15 october 2004
+Version:    1.0
+
+DESCRIPTION:
+
+Icon theme for KDE 3.x.
+Icons where designed using Adobe Illustrator, and then exported to PNG format.
+Icons shadows and minor corrections were done using Adobe Photoshop.
+Kiconedit was used to correct some 16x16 and 22x22 icons.
+
+LICENSE
+
+Released under GNU Lesser General Public License (LGPL)
+Look at the license.txt file.
+
+CONTACT
+
+David Vignoni
+e-mail :        david [at] icon-king.com
+ICQ :           117761009
+http:           http://www.icon-king.com
+ +
+ + +

Boost

+ +
Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+ +
+ + +

Twofish Implementation

+ +
Fast, portable, and easy-to-use Twofish implementation,
+Version 0.3.
+Copyright (c) 2002 by Niels Ferguson.
+
+The author hereby grants a perpetual license to everybody to
+use this code for any purpose as long as the copyright message is included
+in the source code of this or any derived work.
+ +
+ + +

SHA-2 Implementation

+ +
Copyright (c) 2003, Dr Brian Gladman, Worcester, UK.   All rights reserved.
+
+LICENSE TERMS
+
+The free distribution and use of this software in both source and binary
+form is allowed (with or without changes) provided that:
+
+  1. distributions of this source code include the above copyright
+     notice, this list of conditions and the following disclaimer;
+
+  2. distributions in binary form include the above copyright
+     notice, this list of conditions and the following disclaimer
+     in the documentation and/or other associated materials;
+
+  3. the copyright holder's name is not used to endorse products
+     built using this software without specific written permission.
+
+ALTERNATIVELY, provided that this notice is retained in full, this product
+may be distributed under the terms of the GNU General Public License (GPL),
+in which case the provisions of the GPL apply INSTEAD OF those given above.
+
+DISCLAIMER
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its properties, including, but not limited to, correctness
+and/or fitness for purpose.
+---------------------------------------------------------------------------
+Issue 01/08/2005
+ +
+ + +

CSendKeys

+ +
Copyright (c) 2004 lallous <lallousx86@yahoo.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+---------------------------------------
+
+The Original SendKeys copyright info
+
+SendKeys (sndkeys32.pas) routine for 32-bit Delphi.
+Written by Ken Henderson
+Copyright (c) 1995 Ken Henderson <khen@compuserve.com>
+ +
+ + +

Command Line Classes

+ +
Copyright (c) 2006, Bill Rubin <rubin@contractor.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of Quality Object Software, Inc., nor the names of
+      its contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+ +
+ + +

Argon2 Implementation

+ +
Argon2 reference source code package - reference C implementations
+
+Copyright 2015
+Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+
+You may use this work under the terms of a Creative Commons CC0 1.0
+License/Waiver or the Apache Public License 2.0, at your option. The terms of
+these licenses can be found at:
+
+- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+- Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+
+The terms of the licenses are reproduced below.
+
+--------------------------------------------------------------------------------
+
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
+    this CC0 or use of the Work.
+
+--------------------------------------------------------------------------------
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+ +
+ + + diff --git a/src/Docs/Chm/help/base/faq.html b/src/Docs/Chm/help/base/faq.html new file mode 100644 index 0000000..5f25e6e --- /dev/null +++ b/src/Docs/Chm/help/base/faq.html @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Administrative FAQ - KeePass + + + + + + + + + + + + + +

Administrative FAQ

+

Frequently Asked Questions about the project, licensing, ...

+ + + +
+ + +

+How can I help you?

+ +

If you like KeePass and would like to help the developers in some way:

+ + + +
+ + +

+May KeePass be used in a company?

+ +

Yes. KeePass is free software and you don't have to pay any +fees. You may freely use KeePass under the terms of its + + + + +license. + + +

+ +

But of course, if you like KeePass, +donations +are always greatly appreciated.

+ + + + + + +You might be interested in this page: +Customization (2.x). + + +

+ + +

+What about a centralized KeePass Internet server?

+ +

The idea on the first glance sounds simple and useful: there should be a centralized +KeePass Internet server, on which all users can store their passwords. By having +Internet connection, you'd have access to all your passwords.

+ +

Note that this idea is different from simply providing webspace. KeePass 2.x already +supports storing databases on servers using HTTP/FTP. The point is +having one server for all users.

+ +

When creating such a server, there are several difficulties:

+ + + +

Summary: a centralized Internet server currently is out of range. If someone wants +to start a company providing such a service, feel free to use KeePass as base +application (of course respect the Open Source terms).

+ +

But what can and probably will be done later is a local intranet KeePass server (for +companies for example). +Employees could log in to the company's password server and use it. But a centralized Internet +server – no chance.

+ + + diff --git a/src/Docs/Chm/help/base/faq_tech.html b/src/Docs/Chm/help/base/faq_tech.html new file mode 100644 index 0000000..8790a05 --- /dev/null +++ b/src/Docs/Chm/help/base/faq_tech.html @@ -0,0 +1,766 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Technical FAQ - KeePass + + + + + + + + + + + + + +

Technical FAQ

+

Frequently Asked Questions about the usage of KeePass.

+ +
+Configuration: + + +Installation / Integration: + + +Security: + + +Usage: + + +
+ + +

+I've saved my options, but when I reopen KeePass I get the old options. What's wrong?

+ +

KeePass supports two different locations for storing configuration information: +the global configuration file in the KeePass directory and a local, user-dependent +one in the user's private configuration folder. Most likely you do not have write +access to your global configuration file.

+ +

For more details, see + +Configuration.

+ +
+ + + + +

+Why doesn't KeePass 2.x run on my computer?

+ +

Symptoms: When trying to run KeePass 2.x on Windows ≤ XP, +an error message like the following is displayed:
+"A required .DLL file, MSCOREE.DLL, was not found" or
+"The application failed to initialize properly (0xc0000135)".

+ +

Cause: KeePass 2.x requires Microsoft .NET Framework ≥ 2.0.

+ +

Resolution: Install Microsoft .NET Framework 2.0 or higher. +It is available as a free download from the Microsoft website: + +Microsoft .NET Framework. +Alternatively, you can install it through +Windows Update (the framework is an optional component).

+ +

KeePass 1.x does not require this framework.

+ +
+ + +

+Why does KeePass 2.x crash when starting it from a network drive/share?

+ +

Symptoms: When trying to run KeePass 2.x from a network drive/share, +you get an error message like the following:
+"Application has generated an exception that could not be +handled" or
+"KeePass has encountered a problem and needs to close".

+ +

Cause: The strict default security policy by the Microsoft .NET +Framework disallows running .NET applications from a network drive/share.

+ +

Recommended resolution: Copy/install KeePass 2.x onto a local hard +disk, and run the copy.

+ +

Alternative, not recommended resolution: +Configure the security policy to allow running .NET applications from +network drives/shares. Ask your administrator to do this (administrative +rights are required). If you have administrative rights and want to do +it yourself, you can use the + +Code Access Security Policy Tool (Caspol.exe) +that ships with the .NET framework (helpful instructions can be found + + +here and + + + +here).

+ +
+ + +

+Does KeePass 2.x use FIPS-validated algorithm implementations?

+ +

KeePass uses many algorithms. This FAQ answer focuses on the algorithms +used for encrypting/decrypting a database file. +Typically, KeePass primarily uses AES-256, SHA-256, HMAC-SHA-256 and SHA-512 +here (unless the user has specified a different +encryption algorithm or a different +key derivation function in the +database settings). +For these algorithms, the .NET Framework provides classes, and KeePass +uses these.

+ +

Since version 4.8, the .NET Framework supports using FIPS-validated +implementations of the algorithms above +(see 'What's new in .NET Framework 4.8').

+ +

For compatibility with older .NET Framework versions, KeePass ignores +the FIPS mode by default. If all your PCs have the .NET Framework 4.8 or higher +installed, you can enable the usage of FIPS-validated algorithm +implementations by opening the 'KeePass.exe.config' file using a text editor +and deleting the line +'<enforceFIPSPolicy enabled="false" />'.

+ +

Implementations of other algorithms (such as ChaCha20 and Argon2) are not +FIPS-validated. If Microsoft provides validated implementations of those +algorithms in the future, we will consider using them.

+ +
+ + + +

+Why doesn't the CHM help file work?

+ +

Symptoms: When trying to open the KeePass CHM help file from +a remote computer or shared network drive, it's not displayed correctly +(navigation aborted, ...).

+ +

Solution: See + + +Microsoft Security Bulletin MS05-026.

+ +
+ + +

+Where can I find more application icons for Windows shortcuts?

+ +
+ + +
+Application icons are icons in Windows ICO format. They can be used in +Windows shortcuts and/or as file association icons. The KeePass executable +contains various application icons which can be used for these purposes.
+
+Additional application icons are available from the "Ext/Icons_*" +directories of the KeePass source code package. +Most of them, shown at right, are slight variations of the main KeePass icon.
+
+Even more, contributed icons (by users) can be found on the +plugins page.
+
+If you have multiple KeePass databases, you can use differently colored KeePass +application icons in order to distinguish them.
+
+These icons are not included in the binary distribution because this would make +the application file too large.

+
+Application Icons +
+ +
+ + +

+How can I add more client icons for password entries?

+ +
+ + +
+Client icons are the icons used for password entries and groups within KeePass. +Each entry can be assigned its own icon.
+
+ + + +You can import your own icons into KeePass databases. For this, click the 'Add...' +button in the icon picker dialog.
+
+Supported formats are BMP, EMF, GIF, ICO, JPEG, PNG, TIFF and WMF. + +
+
+Client Icons +
+ +
+ + +

+Does KeePass support a mini mode?

+ +
+ + + + + + + +Functions can be blocked/enforced using an enforced configuration file. + + +

+ + +

+Why doesn't KeePass lock after Auto-Type?

+ +
+ + + + + + +This does not apply to KeePass 2.x. + + +

+ + +

+Why doesn't Auto-Type work correctly on Polish systems?

+ +

On Polish systems, the default auto-type hot key +Ctrl+Alt+A +conflicts with a system command and is frequently used in typing. +Therefore, auto-type is often executed accidentally.

+ +

The global auto-type hot key can be changed to a different key combination +in the KeePass options (see +Auto-Type for details).

+ +
+ + + +

+Why doesn't printing work in KeePass 1.x?

+ +

Symptoms: When trying to print a password list in KeePass 1.x, +nothing happens after clicking OK in the 'Print Options' dialog.

+ +

Cause: KeePass 1.x uses the application associated with .html +files to print the password list. If this application doesn't support the +"print" shell verb (like Mozilla Firefox), nothing happens.

+ +

Resolution: Associate .html files with a different +application that supports the "print" shell verb (like Internet Explorer).

+ +

Alternative Resolution / Workaround: +Click 'File' → 'Print Preview' in KeePass 1.x and +manually print the document in the application that just opened the file.

+ +
+ + + +

+Why does KeePass try to connect to the Internet?

+ +

KeePass has an option to automatically check for updates on each program start. +In order to check for updates, KeePass downloads a small version information +file and compares the available version with the installed version. +No personal information is sent to the KeePass web server.

+ +

Automatic update checks are performed unintrusively in the background. +A notification is only displayed when an update is available. Updates are not +downloaded or installed automatically.

+ +

The option is disabled by default. You can enable/disable it in +'Tools' → 'Options' → tab 'Advanced'.

+ +
+ + +

+Does the GUI support dark themes?

+ +

Yes. KeePass supports all system themes, including dark ones.

+ + + + +

Example (Windows 11, 'Dusk' theme):

+ +
+Dark Master Key Prompt Dialog +
+ +

Option 'Choose your (default app) mode' → 'Dark'.
+Windows 11 has an option 'Choose your mode' (on Windows 10, it is called +'Choose your default app mode'), which can be set to 'Dark'. +Note that this option applies to UWP apps only, not to regular Windows applications. +Windows allows the UWP option to contradict the system theme +(e.g. a light system theme may be active even when the UWP option is set to 'Dark'). +KeePass is a regular Windows application, not a UWP app, +thus it follows the system theme, not the UWP option. +This is the expected behavior; KeePass does not have anything to do +with UWP options.

+ +

Custom appearance.
+If you want to change KeePass' appearance independent of the active +system theme, you might be interested in the +KeeTheme plugin.

+ +
+ + +

+How to change the GUI font (size)?

+ +

KeePass uses the default graphical user interface (GUI) font that has +been specified in the operating system settings. +So, if you want to change the font (especially the size of the font) +that KeePass uses, change it globally.

+ + + +

In addition to supporting these system settings, KeePass allows +to customize the fonts that are used in lists and for passwords +(in the options dialog; these settings affect KeePass only, +no other applications).

+ + + +
+ + +

+Is Auto-Type keylogger-safe?

+ +

Is the Auto-Type feature resistant to keyloggers?

+ + + + + + +By default: no. The Auto-Type method in KeePass 2.x works the same as the one in +1.x and consequently is not keylogger-safe.
+
+However, KeePass features an alternative method called +Two-Channel Auto-Type Obfuscation (TCATO), +which renders keyloggers useless. This is an opt-in feature (because it +doesn't work with all windows) and must be enabled for entries manually. +See the TCATO documentation for details.
+ + +

+ + +

+Can Auto-Type locate child controls?

+ +

No. Auto-Type only checks whether the title of the currently active top level +window matches.

+ +

Browsers like Mozilla Firefox completely draw the window (all controls) +themselves, without using standard Windows controls. Consequently it is +technically impossible for KeePass to check whether a URL matches (methods +like creating a screenshot and using optical character recognition +are not reliable and secure). Also, it's impossible to check which child +control currently has the focus. These problems can only be avoided by using +browser integration plugins, i.e. not using auto-type at all.

+ +

The user must make sure that the focus +is placed in the correct control before starting auto-type.

+ +
+ + +

+Could you add the ... encryption algorithm to KeePass?

+ +
+ + + + + + +AES (Rijndael) and ChaCha20 are supported. +There exist various +plugins +that provide support for additional encryption algorithms, +including but not limited to Twofish, Serpent and GOST.
+
+If you'd like to implement an algorithm, have a look at the ArcFourCipher sample plugin. + + +

+ + +

+Why doesn't KeePass lock while a sub-dialog is open?

+ +

KeePass has various options to lock its workspace automatically +(after some time of inactivity, when the computer gets locked or the user +is switched, when the computer gets suspended, etc.). +However, the workspace is not locked automatically while a sub-dialog +(like the 'Edit Entry' dialog) is open.

+ +

To understand why this behavior makes sense, it is first important to know what happens +when the workspace gets locked. When locking, KeePass completely closes the database +and only remembers several view parameters, like the last selected group, the top visible +entry, selected entries, etc. From a security point of view, this achieves the best +security possible: breaking a locked workspace is equal to breaking the database itself.

+ +

Now back to the original question. Let's assume a sub-dialog is open and +one of the events occurs that should automatically lock the workspace. +What should KeePass do now? +In this situation, KeePass cannot ask the user what to do, +and must make an automatic decision. There are several possibilities:

+ + + +

Obviously, none of these alternatives is satisfactory. +Therefore, KeePass implements the following simple and easy to understand behavior:

+ +

KeePass doesn't lock while a sub-dialog is open.

+ +

This simple concept avoids the problems above. The user is responsible for the +state of the program.

+ + + +

Note that opening a sub-dialog is typically only required for +editing something; it is not required for using +entries, as the main window provides +various methods for this.

+ +

Locking when Windows locks. +On Windows XP and older, the Windows service 'Terminal Services' +should be enabled. If this service is disabled, locking KeePass +when Windows locks might not work. This service isn't required on newer +operating systems.

+ +
+ + +

+Printing creates a temporary file. Will it be erased securely?

+ +

KeePass creates a temporary HTML file when printing password lists and showing +print previews. This file is securely deleted when closing the database.

+ +

You must wait for the file being printed completely before closing KeePass +(and close the print preview before closing KeePass), otherwise it could happen +that the printing application blocks KeePass from deleting the file.

+ +

There is no way around the temporary file in the current printing system. +If you want to write a plugin that directly sends the data to the printer, you can +find a plugin development tutorial here: +KeePass 2.x Plugin Development.

+ +
+ + + + +

+Why the estimated quality of a password suddenly drops?

+ +

For estimating the quality/strength of a password, KeePass not only uses +statistical methods (like checking which character ranges are used, +repeating characters and differences), it also has a built-in list of +common passwords and checks for patterns. When completing a common password or a +repetition, the estimated quality can drop.

+ +

Details can be found on the +Password Quality Estimation help page.

+ +
+ + +

+How to store and work with large amounts of (formatted) text?

+ +
+ + + + + + + + +
+KeePass has a built-in editor that allows working conveniently with +large amounts of (formatted) texts.
+
+To add a large text to an entry, import the file as attachment +(or click 'Attach' → 'Create Empty Attachment'). +The built-in editor supports *.TXT (simple text) and *.RTF (formatted text) files.
+
+In order to edit an attachment, right-click onto the entry in the main window, +point on 'Attachments' and click 'YourFile.*'. Alternatively, +if the text file +is the only attachment, you can open it by just double-clicking onto +it in the main window (enable showing the attachment column in 'View' → +'Configure Columns' → 'Attachments'). Alternatively, it's also possible to click the name of +the attachment in the entry details view in the main window.
+
+For TXT files, the built-in editor supports standard operations like cut, +copy, paste, undo, word wrap, etc. For RTF files, additionally standard formatting +commands are available: choosing the font, font size, bold, italic, underline, +strikeout, text and background colors, align left/center/right, etc. +
+ +
+ + +

+ + +

+Can an e-mail address field be added?

+ +

A few times it has been requested that a standard entry field for e-mail addresses +is added (on the main tab page in the entry editing dialog). +The short answer: an e-mail address field will not be added +due to usability reasons. Now the long answer.

+ +

First of all, let's assume that most of the entries stored in KeePass +contain information for logging in to websites. +When you register an account for a website, you often have to specify a +user name as well as an e-mail address. When you regularly +log in later, you usually only need to provide either user name + password +or e-mail + password (never user name + e-mail + password). +Here the first part (which is either user name or e-mail) serves as +identification: you tell the website who you are. +The second part (password) provides authentication: you prove to the +website that you're really the one who you claim to be.

+ +

There are various methods how KeePass can transfer data to +other applications. All of these methods by default assume that the content +of the user name field is used for identification. For example, +the default auto-type sequence of +an entry is +{USERNAME}{TAB}{PASSWORD}{ENTER}, the default +KeeForm +configuration uses the user name, etc. +Now on the one hand some websites require an e-mail address instead +of a user name. On the other hand we want the default data transfer configuration +to work for most websites (such that the work that the user has to put +into the configuration is kept minimal and only needed for +websites using special login forms).

+ +

The solution is simple: instead of interpreting the 'User Name' field +strictly as a field containing a user name, users should rather interpret +it as a field in which the data required for identification is stored. +This data can consist of a user name, an e-mail address or something else +(e.g. an account number for an online banking website). +By handling it like this, the default data transfer configuration will work for most +websites, i.e. zero amount of work needs to be put into +the configuration. +If you had to provide both a user name and an e-mail address at +registration time, the other information (which isn't required +on a regular basis) can be stored e.g. in +the notes field or a custom string field of the KeePass entry.

+ +

Now assume a separate e-mail field would be added. +When users store both a user name and an e-mail address, +KeePass cannot know which of the two is required for identification. +So, in order to setup data transfer for the entry, users would be forced +to choose which of the two fields should be used.

+ +

So, adding an e-mail field would be a step back in usability, +because it forces users to put additional time into data transfer configuration. +The current system ('User Name' containing identification information, +without a separate e-mail field) doesn't require this, and thus is +the better solution.

+ +

For users that are willing to manually configure the data transfer for each +entry, there are multiple ways to get a separate e-mail address field. +After switching to the 'Advanced' tab in the entry editing dialog, +an e-mail address field can be added as custom string. +If the field should appear on the main tab page of the dialog, the +KPEntryTemplates plugin can be used.

+ + + diff --git a/src/Docs/Chm/help/base/fieldrefs.html b/src/Docs/Chm/help/base/fieldrefs.html new file mode 100644 index 0000000..24a9441 --- /dev/null +++ b/src/Docs/Chm/help/base/fieldrefs.html @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Field References - KeePass + + + + + + + + + + + + +

Field References

+

How to put references to data in fields of other entries.

+ + + +
+ + +

+Introduction

+ +

KeePass can insert data stored in different +entries into fields of an entry. +This means that multiple entries can share a common +field (user name, password, ...), and by changing the actual data entry, +all other entries will also use the new value.

+ +

To create a field reference, you can either use the +convenient field references wizard (in the entry editing window, +click the 'Tools' button at the bottom left and select +'Insert Field Reference'), or insert the placeholder manually +(see the syntax below).

+ +

Note that field references are intended for referencing data stored +in different entries. If you want to insert data from the +same/current entry, you should use local placeholders, like +{TITLE} and {S:FieldName}; +see Placeholders.

+ +
+ + +

+Placeholder Syntax

+ +

The placeholder syntax for field references is the following:

+ +

{REF:<WantedField>@<SearchIn>:<Text>}

+ +

The WantedField and SearchIn parts need to be replaced by +1-letter codes identifying the field:

+ + + + + + + + + + + +
CodeField
TTitle
UUser name
PPassword
AURL
NNotes
IUUID
OOther custom strings (KeePass 2.x only)
+ +

The Text part is the search string, which describes the text(s) +that must occur in the specified field of an entry to match.

+ +

If multiple entries match the specified search criterion, the first +entry will be used. +To avoid ambiguity, an entry can be identified by its UUID, which is unique. +Example: +{REF:P@I:46C9B1FFBD4ABC4BBB260C6190BAD20C} would insert the +password of the entry having 46C9B1FFBD4ABC4BBB260C6190BAD20C as UUID.

+ + +Referencing fields of other entries only works with standard fields, not +with custom user strings. +If you want to reference a custom user string, you need +to place a redirection in a standard field of the entry with the custom string, +using {S:<Name>}, +and reference the standard field.
+
+Custom strings can locally (i.e. within an entry) be referenced using +{S:<Name>}, +see the page Placeholders for details.
+
+You can use the O code to make KeePass search the database for +custom string fields (to identify the referenced source entry), +but O cannot be used to retrieve data from custom fields (i.e. the +code can't be used as WantedField). + + +
+ +
+ + +

+Example

+ +

Let's assume you have two entries: one with title "Example Website" +and one with "Example Forum", and you want to insert the user name +of the website account into the URL of the forum entry. Within the forum entry's +URL, you could reference the user name like this:
+https://forum.example.com/?user={REF:U@T:Example Website}

+ + + diff --git a/src/Docs/Chm/help/base/firststeps.html b/src/Docs/Chm/help/base/firststeps.html new file mode 100644 index 0000000..5fe16bc --- /dev/null +++ b/src/Docs/Chm/help/base/firststeps.html @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + First Steps Tutorial - KeePass + + + + + + + + + + + + + +

First Steps Tutorial

+

A short tutorial showing you the basic usage of KeePass.

+ +

This short tutorial will show you how to actually use KeePass. It describes +only the basic usage, advanced features are covered on separate pages.

+
+ +

Creating a new database

+ +

The very first step is creating a new password database. KeePass will store all +your passwords in such a database. To create one, click +'File' → 'New...' in the main menu or click the leftmost toolbar button. +A window will appear, which prompts you for a master password and/or key file. +The database will be encrypted with the password you enter here. The password +you enter here will be the only password you'll ever have to remember from on +now. It should be long and built up of mixed characters. Keep in mind that when +someone gets your database file and guesses the password, he could access all +passwords you stored in the database.

+ +

For this tutorial, we'll just use a password, not a key file. Click into the password edit +field and enter a password of your choice. The password edit control isn't limited in length, so +feel free to even enter a whole sentence (just keep in mind that you'll need to +remember it).

+ + + + + + +After clicking [OK], a second dialog appears. In this dialog you can configure +some generic database properties. For now, just leave everything as it is and +click [OK]. + + +

Now you see the main window. On the left, you see the entry groups. On the +right, you see the actual password entries. The password entries are +grouped together into the password groups you see on the left. So, depending +on which group on the left you selected, it'll show you the entries in this group +in the right view. KeePass has created a few default groups for you, but you're +totally free to delete them and create your own ones.

+
+ +

Adding an entry

+ +

Time to store your very first password in the KeePass database! Right-click +into the right password entry view and choose 'Add Entry...'. A window +will pop up. In this window you can now edit your entry: enter a title for +it, a user name, a URL, the password, etc. If you don't need some of the +fields, just leave them empty. When you're done, click [OK].

+
+ +

Using entries

+ +

Your new entry is displayed in the +main entry list now. +There are various ways how you can use it.

+ +

For example, you can copy the user name of the entry into the clipboard. +In order to invoke the 'Copy User Name' command, double-click onto the +user name cell in the main entry list. +Alternatively, the command can be invoked via the main menu, +the context menu, the toolbar button, or by pressing +Ctrl+B. +When the user name is in the clipboard, you can paste it into the +target window.

+ +

Copying passwords and other fields works analogously.

+ +

Alternatively, you can drag&drop fields into other windows. +For details, see Drag&Drop.

+
+ +

Saving the database

+ +

It's time to save your database. Click onto the 'Save' toolbar button +(which has a disk icon).

+
+ +

More

+ +

That's it! You've made the first steps in using KeePass! You can now have a look +at the more advanced features of KeePass.

+ +

Passwords and Key Files: In the tutorial above we've encrypted +the database using a password. But KeePass also supports key files, i.e. you can +lock your database using a file (which you can carry around on your USB stick +for example). It even supports combining those two methods for maximum security.

+ +

TAN Entries: TAN entries are one-time passwords. Many +banks are using TANs for better security. KeePass supports TAN entries, by +making them expire automatically when using them.

+ +

Auto-Type: The auto-typing functionality is a very +powerful feature. In the tutorial above you've copied the user name and password +of an entry to the clipboard. Wouldn't it be nice if KeePass would just type +those strings for you into other windows? Wouldn't it be nice if you could define +whole sequences of keypresses that KeePass should type for you? That's exactly +what the auto-type feature does: it sends simulated keypresses for you to +other windows!

+ +

URL Field: The URL field supports URLs +of course. In the tutorial, you've learned that you can enter simple URLs into +this field and KeePass will open the browser window for you. But the URL field +can do more! It actually supports many different protocols (not just http) +and supports executing +Windows command lines through the cmd:// virtual protocol. The +field also features a powerful substitution engine, replacing codes +by other fields (user name, password, ...) of this entry.

+ +

Command Line Parameters: You can open .kdb(x) files by +passing the file name to the KeePass executable file. But did you know that you can +also send the password for the database and key file location over the command line? +You can also use the command line to preselect a key file for you.

+ + + + +

Plugins: + + +KeePass features a powerful plugin architecture. +If you miss some functionality, have a look at the plugins page to see if there +are other people that have already written plugins for this. Many plugins exist +to import/export data from/to other file formats.

+ + + diff --git a/src/Docs/Chm/help/base/importexport.html b/src/Docs/Chm/help/base/importexport.html new file mode 100644 index 0000000..1b323d3 --- /dev/null +++ b/src/Docs/Chm/help/base/importexport.html @@ -0,0 +1,522 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Import / Export - KeePass + + + + + + + + + + + + + + + + +

Import / Export

+

KeePass supports importing/exporting data from/to various file formats.

+ +

KeePass 1.x supports importing data from CSV files (special form), +CodeWallet, Password Safe, and Personal Vault.

+ +

KeePass 2.x supports importing data from CSV files (all), +KeePass 1.x (KDB, XML and CSV), KeePass 2.x XML, +1Password, +1Password Pro, 1PW, Alle meine Passworte, +Any Password, Bitwarden, CodeWallet, Dashlane, +DataVault, DesktopKnox, Enpass, +FlexWallet, Google Chrome, Handy Safe, Handy Safe Pro, +Kaspersky Password Manager, KeePassX, Keeper, +Key Folder, LastPass, +Mozilla Bookmarks, mSecure, Network Password Manager, +Norton Identity Safe, nPassword, PassKeeper, +Passphrase Keeper, Password Agent, +Password Depot, Password Exporter, +Password Keeper, Password Memory, Password Prompter, +Password Safe, Password Saver, Passwords Plus, +Passwort.Tresor, Personal Vault, +PINs, Revelation, RoboForm, SafeWallet, +Security TXT, SplashID, Steganos Password Manager, +Sticky Password, True Key, TurboPasswords, VisKeeper, +Whisper 32, ZDNet's Password Pro, and Spamex.com.

+ +

For both KeePass 1.x and 2.x, there are plugins available that +add more import/export capabilities.

+ + + +
+ +

Unfortunately there isn't any standard password database format. Every password +manager uses its own file format. Anyway, almost all support exporting to CSV or XML +files. This sounds good at first glance, but CSV and XML files aren't specialized password +database formats, they only specify a low-level layout of the stored data (for CSV: data fields +are separated by commas; for XML: hierarchical form using tags). These formats do not +specify the high-level arrangement of the data (for CSV: order/meaning of the fields; for +XML: tag names and structure). Because of this, many users are confused when application #1 +exports data to CSV/XML and application #2 can't read the CSV/XML file, although it claims +that it can read those files.

+ +

This help page details the expected CSV and XML file formats. Knowing the formats which +KeePass expects, you can reformat CSV and XML files exported by other password managers to +match the KeePass formats. CSV files can be reformatted using e.g. LibreOffice Calc +(see below). +XML files can be reformatted using an XML editor.

+ +

KeePass can import many password database formats directly (see top of this page). +Additionally, there are specialized KeePass +plugins available +for importing more formats (like AnyPassword CSV, Oubliette files, PINs TXT, ZSafe files, +and many more). Using these plugins, you don't need to manually reformat the output of +other password managers; you can directly import the exported files.

+ +

If no import plugin exists for importing data from your previous password manager, +feel free to post a request for it in the +KeePass Feature Requests Tracker +or in the +Open +Discussion forum.

+ +
+ + +

+File Format: CSV (KeePass 1.x)

+ +

KeePass imports and exports data from/to CSV files in the following format:

+ +

"Account","Login Name","Password","Web Site","Comments"

+ +

The 'Account' field in a CSV file corresponds to the title field of +a KeePass entry, 'Login Name' corresponds to the user name, +'Web Site' corresponds to the URL, and 'Comments' correspond to the notes. +The CSV field names differ from the KeePass entry field names +in order to ensure the compatibility with certain other applications.

+ +

For a detailed example, download this file: +ZIP Package +FileSample_CSV.zip. +This file is zipped only in order to ensure correct encoding (if not zipped, browsers or +download managers could automatically convert the file to a different encoding). When importing +a CSV file, it must not be zipped!

+ +

Important notes about the format:

+ + + +

Microsoft Excel by default does not enclose fields in quotes ("). +It is recommended that you use +LibreOffice Calc +to create a correct CSV file (see below), or use the Generic CSV Importer +of KeePass 2.x (import your CSV file into KeePass 2.x, then export the data to a +KeePass 1.x KDB file), or fix the CSV file by manually adding the quotes using a text editor.

+ +

If you want to transfer data between KeePass 1.x databases, you must +not change the default export options of KeePass. +Do not export additional fields or uncheck any options, otherwise +KeePass will not be able to re-import the CSV file, because it does not comply to the +specification above any more.

+ +

Using LibreOffice Calc to create a CSV file:
+LibreOffice Calc +can be used to create CSV files that can be imported correctly into KeePass. Follow these steps:

+ + + +
+ + +

+File Format: XML (KeePass 1.x)

+ +

This section describes the KeePass 1.x XML format. Note that this format +is different from the XML format used by KeePass 2.x (anyway, KeePass 2.x +can import KeePass 1.x XML files).

+ +

You can download a detailed XML sample file here: +ZIP Package +FileSample_XML.zip. +This file is zipped only in order to ensure correct encoding (if not zipped, browsers or +download managers could automatically convert the file to a different encoding). When importing +a XML file, it of course must not be zipped!

+ +

Important notes about the format:

+ + + +
+ + +

+Generic CSV Importer

+ +

KeePass 2.x features a generic CSV importer. +This tool can import almost all CSV formats. The CSV +files are loaded and you can manually specify the encoding / character set, assign columns +to data fields, and specify how the low-level structure looks like (usage of quotes, etc.).

+ +

To start the generic CSV file importer, click 'File' → 'Import' and +choose 'Generic CSV Importer'.

+ +
+ +
+ +

Details about the generic CSV importer (with descriptions of the +options, examples, etc.) can be found on the +Generic CSV Importer help page.

+ +
+ + +

+How to Import CodeWallet TXT

+ +

CodeWallet is a password manager that supports different card types (fields). +KeePass cannot know which of the CodeWallet fields correspond to the KeePass +standard fields (title, user name, ...), because they don't have fixed names (language-dependent, +user-customizable, ...). +Therefore all fields from the CodeWallet file are imported into custom string fields +of KeePass entries. After importing the file, you can move some of the strings +to the correct standard fields (by clicking the 'Move' button on the second tab page +of the entries dialog.

+ +
+ + + + +

+How to Import PINs TXT

+ +

In order to successfully import a PINs TXT file, you need to do the following:

+ + + +

After exporting a TXT file using the settings above, import it using +'File → Import' in KeePass 2.x.

+ +
+ + +

+How to Import Data from RoboForm

+ +
    + +
  1. Export your logins to a HTML file. To do this, open +RoboForm's Passcard Editor ('Edit Passcards' or 'RoboForm Editor' +in the Windows start menu) +and in the editor's main menu go 'Passcard''Print List' +(in newer versions you have to click the 'RoboForm' button and go +'Print List''Logins'). In the +dialog that opens, click the 'Save' button. Choose a location and file name, +and click 'Save'.
  2. + +
  3. Open your KeePass 2.x database file and go 'File''Import'. +Choose 'RoboForm HTML' as format and select the HTML file you just exported, +then click 'OK'.
  4. +
+ +
+ + +

+How to Import Data from Steganos Password Manager 2007

+ +

Warning! It is possible that the transfer fails and that KeePass accidently +overwrites your existing passwords in Steganos Password Manager. Therefore, back up your +SEF file before starting the import! In any case you should restore your passwords by +restoring the backup you just created after the import process! Even if you think +KeePass hasn't changed anything, restore from the backup!

+ +

Unfortunately Steganos Password Manager (SPM) lacks any form of export functionality. As the +SEF file format (in which the data is stored) is proprietary and no specification +is available, KeePass needs to try to get all the data out of the windows of +SPM.

+ +

The import process works as follows. First you start SPM and open your password +database. The main password management window should be open (i.e. the one which lists +your items in the middle of the screen, and got toolbar-like buttons at the top). Make +sure that all your items are displayed in the list (select the correct filter in +the combobox above the item list).

+ +

Now switch to KeePass 2.x and open your KeePass database. Go File → Import and +choose Steganos Password Manager 2007. Click [OK]. Now read the rest before continuing.

+ +

After pressing the [Yes] button in the KeePass import confirmation dialog, you got +10 seconds to switch to the SPM window. Select the very first entry within the SPM window +(but do not open it, just select it). This is important! The first entry must have the +keyboard focus and must be selected.

+ +

When the 10 seconds are over, KeePass will start importing. You will see how +KeePass opens the SPM items, copies the data, closes the item's window, select the +next item, etc. Everything goes automatic now and you can just sit back and watch. +Sometimes Windows playes a ding sound, this is normal.

+ +

Note that it can take quite some time to import your items. Do not do +anything while KeePass is importing! One single mouse click or keypress can ruin the +complete import process.

+ +

The last item will be scanned twice. When completed, KeePass will +show a message "The import process has finished!".

+ +

It is possible that KeePass failed to import some items (mainly caused by SPM's +unpredictable slow response times). It is highly recommended that you compare each of +the entries.

+ +
+ + +

+How to Import Data from PassKeeper 1.2

+ +

The import process works visually, exactly like the import method for +Steganos Password Manager data. Please read all instructions in +How to Import Data from Steganos Password Manager 2007.

+ +
+ + +

+How to Import 1PW and 1Password Pro CSV

+ +

KeePass can import CSV files exported by 1PW and 1Password Pro. +When exporting the data, make sure:

+ + + +
+ + +

+Export: Option 'Additionally Export Parent Groups'

+ +

In KeePass 2.x, there is an option 'Additionally export parent groups' +in the export dialog. +If this option is turned on, the parent groups of the selected groups/entries +are exported, too (all up to the root group of the database). +Unselected groups/entries in parent groups are not exported.

+ +

If the selected file format does not support groups, the option +has no effect. +When exporting the whole database (via 'File' → 'Export') or the +root group, the option is disabled, because the root group has no parent +group.

+ +

Properties of the parent groups (icons, notes, auto-type settings, etc.) +are exported, if the selected file format supports them. +When importing a file, the properties of the groups in the current database +may be overwritten by the properties of the groups in the file +(depending on the import mode and the last modification times).

+ +

Example. +Assume that the user selects the entry 'Entry B' that is stored in +the groups 'Group 1' → 'Group 1.2' of a database.

+ +
+ + + + + + + + + + + +
Root Group
Group 1
Group 1.1
Group 1.2
Group 2
+  + + + + + + + + + + + + +
TitleUser NamePasswordURLNotes
Entry AMichael42********https://example.net/None.
Entry BMichael42********https://example.com/None.
Entry CMichael42********https://example.org/None.
+
+ +

Exporting the selected entry (via 'Entry' → 'Data Exchange' → +'Export Entry') to a KDBX database file without turning on the option results in:

+ +
+ + + +
Root Group
+  + + + + +
TitleUser NamePasswordURLNotes
Entry BMichael42********https://example.com/None.
+
+ +

In contrast, exporting the selected entry to a KDBX database file with +the option turned on results in:

+ +
+ + + + + + + +
Root Group
Group 1
Group 1.2
+  + + + + +
TitleUser NamePasswordURLNotes
Entry BMichael42********https://example.com/None.
+
+ + + diff --git a/src/Docs/Chm/help/base/index.html b/src/Docs/Chm/help/base/index.html new file mode 100644 index 0000000..78acee5 --- /dev/null +++ b/src/Docs/Chm/help/base/index.html @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Help Center - KeePass + + + + + + + + + + + + + + + + + + +
+ + +

+KeePass Password Safe

+
+ +
+ + +

KeePass: Copyright © 2003-2023 Dominik Reichl. +The program is OSI Certified Open Source Software. +OSI Certified is a certification mark of the Open Source Initiative. +For more information, see the + + + +License page. + +

+ +

Introduction

+ + + + +Main Window Screenshot + + + +

Today, you have to remember many passwords. You need a password for a lot of +websites, your e-mail account, your webserver, network logins, etc. +The list is endless. +Also, you should use a different password for each account, because +if you would use only one password everywhere and someone gets this password, +you would have a problem: the thief would have access to all of your +accounts.

+ +

KeePass is a free open source password manager, which helps you to manage +your passwords in a secure way. You can store all your passwords in one +database, which is locked with a +master key. So you only have to remember one +single master key to unlock the whole database. Database files are +encrypted +using the best and most secure encryption algorithms currently known +(AES-256, ChaCha20 and Twofish).

+ +

The database consists of only one file, so it can be transferred +easily from one computer to another. +Data can also be imported/exported +from/to various other formats +(import from more than 40 different formats of other password managers, + +generic CSV importer, + +...). Of course, printing entries is supported, too.

+ +

KeePass supports groups, which allow you to organize your entries +conveniently. For quickly locating specific entries, there are search +functions.

+ +

There are various methods for transferring entry data (like user names +and passwords) from KeePass to other applications +(clipboard, +drag&drop, etc.). The powerful +auto-type feature can simulate keypresses.

+ +

KeePass has a strong password generator +(you can define allowed characters, length, generation rules, ...).

+ +

The program features a plugin architecture. Plugins can add features +in many areas (integration, transfer, backup, network, even more +import/export formats, and much more).

+ +

As KeePass is open source, +you can have a look at its full source code and check whether the security +features are implemented correctly.

+ +

This documentation applies to + + + +KeePass 2.x. + +

+ + + diff --git a/src/Docs/Chm/help/base/integration.html b/src/Docs/Chm/help/base/integration.html new file mode 100644 index 0000000..b550cd1 --- /dev/null +++ b/src/Docs/Chm/help/base/integration.html @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Integration - KeePass + + + + + + + + + + + + +

Integration

+

How KeePass integrates into your operating system environment.

+ + + +
+ + +

+Global Hot Key to Restore KeePass Window

+ +

To quickly switch back from an application to KeePass, you can use the +global hot key that restores the KeePass main window.

+ +

If you have multiple instances of KeePass running, pressing the global hot +key will restore the first instance that has been started.

+ +

The global hot key is Ctrl+Alt+K.

+ + + + + + +The hot key can freely be changed to a different key combination +(or disabled) in the 'Options' dialog, tab page 'Integration'. + + +

+ + +

+Limit to Single Instance Option

+ +

If you enable the 'Limit to Single Instance' option, at most one KeePass instance can +be running at a time. If you try to start a second KeePass instance, it is +immediately terminated, and the first instance is brought to +the foreground.

+ + + + + + +KeePass 2.x can open multiple databases in one instance/window (a tab bar appears, +which allows you to conveniently switch between the databases).
+
+When multiple databases are opened in one instance and you press the +global auto-type hot key, auto-type searches in all opened databases for +matching entries. Note that only exactly one KeePass instance can register +the global hot key; so when you disable the single instance option and +open databases in different instances, only the first instance searches +for matching entries when global auto-type is invoked, not the others. + + + + diff --git a/src/Docs/Chm/help/base/keys.html b/src/Docs/Chm/help/base/keys.html new file mode 100644 index 0000000..af79f3e --- /dev/null +++ b/src/Docs/Chm/help/base/keys.html @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Master Key - KeePass + + + + + + + + + + + + + + + + +

Master Key

+

Details about components of a master key.

+ + + +
+ +

Your KeePass database file is encrypted using a master key. +This master key can consist of multiple components: +a master password, a key file and/or a key that is protected +using the current Windows user account.

+ +

For opening a database file, all components of the +master key are required.

+ +

If you forget/lose any of the master key components (or forget the +composition), all data stored in the database is lost. +There is no backdoor and no universal key that can open your database.

+ +
+ + +

+Master Password

+ +

If you use a master password, you only have to remember one password or +passphrase (which should be good!) to open your database.

+ +

KeePass features a protection against brute-force and dictionary attacks; +see the security help page +for details.

+ +
+ + +

+Key File

+ +

A key file is a file that contains a key (and possibly additional data, +e.g. a hash that allows to verify the integrity of the key). +The file extension typically is 'keyx' or 'key'.

+ +

A key file must not be modified, otherwise you cannot open your database +anymore. If you want to use a different key file, open the dialog for +changing the master key (via 'File' → 'Change Master Key') +and create/select the new key file.

+ +

Two-factor protection. +A key file is something that you must have in order to be able +to open the database +(in contrast to a master password, which you must know). +If you use both a key file and a master password, you have a two-factor +protection: possession and knowledge.

+ +

Location. +As mentioned above, the idea of a key file is that you have +something. If an attacker obtains both your database file and your +key file, then the key file provides no protection. +Therefore, the two files must be stored in different locations. +For example, you could store the key file on a separate USB stick.

+ +

Hiding the location. +The key file content must be kept secret, not its location +(file path/name). +Trying to hide the key file (e.g. by storing it among +a thousand other files, in the hope that an attacker does not know which +file is the correct one) typically does not increase the security, because +it is easy to find out the correct file (e.g. by inspecting the last access +times of files, lists of recently used files of the operating system, +file system auditing logs, anti-virus software logs, etc.). +KeePass has an option for remembering the paths of key files, +which is turned on by default; turning it off typically just decreases +the usability without increasing the security.

+ +

Backup. +You should create a backup of your key file (onto an independent data +storage device). +If your key file is an XML file (which is the default), you can also create +a backup on paper (KeePass 2.x provides a command for printing a key file +backup in the menu 'File' → 'Print'). +In any case, the backup should be stored in a secure location, where only +you and possibly a few other people that you trust have access to. +More details about backing up a key file can be found in the +ABP FAQ.

+ +

Formats. +KeePass supports the following key file formats:

+ + +

Reuse. +You can use one key file for multiple database files. +This can be convenient, but please keep in mind that when an +attacker obtains your key file, you have to change the master keys +of all database files protected with this key file.

+ + + + + + +In order to reuse an existing key file, click on the 'Browse' button +in the master key creation dialog. + + +

+ + +

+Windows User Account

+ +
+ + + + + + +KeePass can make the database dependent on the current Windows user +account. If you enable this option, you can only open the database when +you are logged in as the same Windows user when creating the database.
+
+Warning +Be very careful with using this option. If your Windows user account +gets deleted, you won't be able to open your KeePass database anymore. +Also, when using this option at home and your computer breaks (hard disk +damaged), it is not +enough to just create a new Windows account on the new installation with the +same name and password; +you need to copy the complete account (i.e. SID, ...). This is not +a simple task, so if you don't know how to do this, it is highly recommended +that you don't enable this option. +Detailed instructions how to recover a Windows user account can be found here: +Recover Windows User Account Credentials +(a short technical tutorial can be found in a Microsoft TechNet article: + +How to recover a Vault corrupted by lost DPAPI keys).
+
+You can change the password of the Windows user account freely; +this does not affect the KeePass database. +Note that changing the password (e.g. a user using the Control Panel +or pressing Ctrl+Alt+Del +and selecting 'Change Password') and +resetting it to a new one (e.g. an administrator using a +NET USER <User> <NewPassword> +command) are two different things. +After changing your password, you can still open your KeePass database. +When resetting the password to a new one, access usually is not possible +anymore (because the user's DPAPI keys are lost), but there are exceptions +(for example when the user is in a domain, Windows can retrieve the user's DPAPI keys +from a domain controller, or a home user can use a previously created +Password Reset Disk). +Details can be found in the MSDN article + +Windows Data Protection and in the support article + + +How to troubleshoot the Data Protection API (DPAPI).
+
+If you decide to use this option, it is highly recommended not to rely +on it exclusively, but to additionally use one of the other two options (password +or key file).
+
+Protection using user accounts is unsupported on Windows 98 / ME. + + +

+ + +

+For Administrators: Specifying Minimum Properties of Master Keys

+ +

Administrators can specify a minimum length +and/or the minimum estimated quality that master passwords must have in +order to be accepted. You can tell KeePass +to check these two minimum requirements by adding/editing +appropriate definitions in the +INI/XML configuration file.

+ + + + + + +The value of the +Security/MasterPassword/MinimumLength node specifies +the minimum master password length (in characters). For example, by setting +it to 10, KeePass will only accept +master passwords that consist of at least 10 characters.
+
+The value of the +Security/MasterPassword/MinimumQuality node specifies +the minimum estimated quality (in bits) that master passwords must have. +For example, by setting it to 80, only master passwords +with an estimated quality of at least 80 bits will be accepted.
+
+The Security/MasterKeyExpiryRec node can be set to an +XSD date or an XSD duration (see +XSD Date and Time Data Types). +If the master key has not been changed since the specified date or +if the time span between now and the last master key change exceeds +the specified duration, KeePass recommends to change it. +This setting applies to all databases that are opened with this +KeePass instance; a master key expiry can also be configured for +each database individually (in 'File' → 'Database Settings' → +tab 'Advanced').
+
+By specifying KeyCreationFlags and/or KeyPromptFlags +(in the UI node), you can force states (enabled, disabled, +checked, unchecked) of key source controls in the master key creation and +prompt dialogs. These values can be bitwise combinations of one or more of +the following flags:
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Flag (Hex)Flag (Dec)Description
0x00Don't force any states (default).
0x11Enable password.
0x22Enable key file.
0x44Enable user account.
0x88Enable 'hide password' button.
0x100256Disable password.
0x200512Disable key file.
0x4001024Disable user account.
0x8002048Disable 'hide password' button.
0x1000065536Check password.
0x20000131072Check key file.
0x40000262144Check user account.
0x80000524288Check 'hide password' option/button.
0x100000016777216Uncheck password.
0x200000033554432Uncheck key file.
0x400000067108864Uncheck user account.
0x8000000134217728Uncheck 'hide password' option/button.
+ +
+The values of KeyCreationFlags and KeyPromptFlags +must be specified in decimal notation.
+
+For example, if you want to enforce using the user account option, you could +check and disable the control (such that the user can't uncheck it anymore) +by specifying 263168 as value (0x40000 + 0x400 = 0x40400 = 263168). + + + + diff --git a/src/Docs/Chm/help/base/license_lgpl.html b/src/Docs/Chm/help/base/license_lgpl.html new file mode 100644 index 0000000..6a14c2d --- /dev/null +++ b/src/Docs/Chm/help/base/license_lgpl.html @@ -0,0 +1,551 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + LGPL License - KeePass + + + + + + + + + + + + + +

LGPL License

+

GNU Lesser General Public License.

+ +
+ +
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+ + + diff --git a/src/Docs/Chm/help/base/multiuser.html b/src/Docs/Chm/help/base/multiuser.html new file mode 100644 index 0000000..a9cc905 --- /dev/null +++ b/src/Docs/Chm/help/base/multiuser.html @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Multiple Users - KeePass + + + + + + + + + + + + +

Multiple Users

+

Details about multi-user features of KeePass.

+ + + +
+ + +

+General Information about Shared Databases

+ +

Both KeePass 1.x and 2.x allow multiple users working with one database, +which is typically stored on a shared network drive or a file server.

+ +

All users use the same master password and/or key file to open the +database. There are no per-group or per-entry access control lists (ACLs).

+ +

In order to restrict write access to the database file (i.e. only a select +set of users may change the stored data), use file system access rights.

+ +
+ + +

+KeePass 1.x: Office-Style Locking

+ +
+ + + +
+With KeePass 1.x, a database can be stored on a shared network drive and used by multiple +users. When a user tries to open a database that is already opened by +someone else, a prompt asks whether to open the database in read-only +or normal mode (see image on the right).
+
+By opening a database in normal mode, the current user takes ownership +of the file (i.e. subsequent opening attempts will show the current user +as owner).
+
+KeePass 1.x does not provide synchronization, i.e. by saving the database you +are saving your current data to disk. If another user has changed an entry +in the meanwhile (i.e. since you loaded the database), these changes are overwritten. +
+ +
+ +

If you want to use KeePass 1.x with a database on a shared network drive, it +is recommended to let an administrator write to the database and let +users only read it (ensure this using file system access rights). +By using the -readonly command line switch, +KeePass will automatically open +a given database in read-only mode (i.e. not show the mode prompt). Users +would open the database using a shortcut that contains this command line +switch.

+ +

If there is no central administrator managing the database, users need to +be careful to not overwrite each others changes.

+ +
+ + +

+KeePass 2.x: Synchronize or Overwrite

+ +
+ + + +
+With KeePass 2.x, a database can be stored on a shared network drive and used by multiple +users. When attempting to save, KeePass first checks whether the file on disk has been +modified since it was loaded. If yes, KeePass asks whether to synchronize or +overwrite the file (see image on the right).
+
+By synchronizing, changes made by other users (file on disk) +and changes made by the current user are merged. +After the synchronization process has finished, +the current user also sees the changes made by others (i.e. the data in the +current KeePass instance is up-to-date).
+
+If there is a conflict (multiple users edited the same +entry), KeePass uses the latest version of the entry based on the last +modification time. +
+ +
+ +

Note: the synchronize prompt is only triggered by the 'Save' command, +not by the 'Save As' command. When executing the 'Save As' command and +manually selecting a file, this file will always be overwritten.

+ + + diff --git a/src/Docs/Chm/help/base/placeholders.html b/src/Docs/Chm/help/base/placeholders.html new file mode 100644 index 0000000..ce83ef3 --- /dev/null +++ b/src/Docs/Chm/help/base/placeholders.html @@ -0,0 +1,785 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Placeholders - KeePass + + + + + + + + + + + + + +

Placeholders

+

KeePass supports various placeholders.

+ +

In many places in KeePass (auto-type, URL field, triggers, ...), +placeholders can be used.

+ + + + + + + + + + +Placeholders are case-insensitive. + + + +
+ +

KeePass uses the abbreviation "Spr" for "String placeholder replacement". +An Spr-compiled field is a field where placeholders are replaced +when performing an action with this field (like copying it to the +clipboard, sending it using auto-type, etc.).

+ +

References in a field to (parts of) the field itself are +unsupported. For example, the {URL:HOST} placeholder +cannot be used in the URL field (but it can be used in the +'Override URL' field).

+ +
+ + +

+Entry Field Placeholders

+ +
+ + + + + + + + + +
PlaceholderField
{TITLE}Title
{USERNAME}User name
{URL}URL
{PASSWORD}Password
{NOTES}Notes
+ +
+ + +Custom strings can be referenced using {S:Name}. +For example, if you have a custom string named "eMail", +you can use the placeholder {S:eMail}. + + +
+ +
+ + + + + + + + + + + + + + + +
PlaceholderIs Replaced By
{URL:RMVSCM}Entry URL without scheme name.
{URL:SCM}Scheme name of the entry URL.
{URL:HOST}Host component of the entry URL.
{URL:PORT}Port number of the entry URL.
{URL:PATH}Path component of the entry URL.
{URL:QUERY}Query information of the entry URL.
{URL:USERINFO}User information of the entry URL.
{URL:USERNAME}User name of the entry URL.
{URL:PASSWORD}Password of the entry URL.
{UUID}UUID of the entry (32 hexadecimal characters).
+
+An example for the {URL:...} placeholders can be found below. + + +

+ + +

+Entry Field References

+ +

Fields of other entries can be inserted using +Field References.

+ +
+ + +

+Paths and Date/Time Placeholders

+ +
+ + + + + + + + + + +
PlaceholderIs Replaced By
{EDGE}Path to Microsoft Edge, if installed.
{FIREFOX}Path to Mozilla Firefox, if installed.
{GOOGLECHROME}Path to Google Chrome (or Chromium +on Unix-like systems), if installed.
{INTERNETEXPLORER}Path to Internet Explorer, if installed.
{OPERA}Path to Opera, if installed.
{SAFARI}Path to Safari, if installed.
+ + + +
+ + + + + +
PlaceholderIs Replaced By
{APPDIR}KeePass application directory path.
+ +
+ + + + + + + + + + + + + + + + + + +
PlaceholderIs Replaced By
{GROUP}Name of the entry's parent group.
{GROUP_PATH}Full path of the entry's parent group.
{GROUP_NOTES}Notes of the entry's parent group.
{GROUP_SEL}Name of the group that is currently selected in the main window.
{GROUP_SEL_PATH}Full path of the group that is currently selected in the main window.
{GROUP_SEL_NOTES}Notes of the group that is currently selected in the main window.
{DB_PATH}Full path of the current database.
{DB_DIR}Directory of the current database.
{DB_NAME}File name (including extension) of the current database.
{DB_BASENAME}File name (excluding extension) of the current database.
{DB_EXT}File name extension of the current database.
{ENV_DIRSEP}Directory separator ('\' on Windows, '/' on Unix).
{ENV_PROGRAMFILES_X86}This is +%ProgramFiles(x86)%, if it exists, otherwise %ProgramFiles%.
+ + +
+ + + + + + + + + + + + + + + + + + +
PlaceholderIs Replaced By
{DT_SIMPLE}Current local date/time as a simple, +sortable string. For example, for 2012-07-25 17:05:34 the value is 20120725170534.
{DT_YEAR}Year component of the current local date/time.
{DT_MONTH}Month component of the current local date/time.
{DT_DAY}Day component of the current local date/time.
{DT_HOUR}Hour component of the current local date/time.
{DT_MINUTE}Minute component of the current local date/time.
{DT_SECOND}Second component of the current local date/time.
{DT_UTC_SIMPLE}Current UTC date/time as a simple, sortable string.
{DT_UTC_YEAR}Year component of the current UTC date/time.
{DT_UTC_MONTH}Month component of the current UTC date/time.
{DT_UTC_DAY}Day component of the current UTC date/time.
{DT_UTC_HOUR}Hour component of the current UTC date/time.
{DT_UTC_MINUTE}Minute component of the current UTC date/time.
{DT_UTC_SECOND}Second component of the current UTC date/time.
+ +

+ + +

+Environment Variables

+ +

System environment variables are supported. +The name of the variable must be enclosed in '%' characters. +For example %TEMP% is replaced by the user's temporary path.

+ +
+ + +

+Text Transformations

+ +
+ + + + + + + + + +
PlaceholderAction
{T-REPLACE-RX:/Text/Search/Replace/}Searches the regular expression Search in Text +and replaces all matches by Replace. +See below.
{T-CONV:/Text/Type/}Convert Text to Type. +See below.
+ + +

+ + + +{T-REPLACE-RX:/Text/Search/Replace/} – Replace +Using Regular Expression:
+This placeholder searches the + +regular expression Search in Text +and replaces all matches by Replace.
+
+All parameters are Spr-compiled, i.e. placeholders can be used within them.
+
+The first character after the first ':' specifies the +separator character. Any character except '}' can be used as separator +character. +It must not appear within the parameters. +For example, +{T-REPLACE-RX:/A/B/C/} and +{T-REPLACE-RX:!A!B!C!} are equivalent. +The last separator character (before the '}') is required.
+
+Usage example. +Let the user name field contain the e-mail address 'myname@example.com' and +the URL field '{T-REPLACE-RX:!{USERNAME}!.*@(.*)!https://$1!}'. +When running the URL field, KeePass opens +'https://example.com'. + + +

+ + + +{T-CONV:/Text/Type/} – Convert:
+This placeholder converts Text to Type.
+
+All parameters are Spr-compiled, i.e. placeholders can be used within them.
+
+Supported types are: + + + +

+ + +

+Other Placeholders

+ +
+ + + + + + + + + + + + + + + + + + + +
PlaceholderAction
{PICKCHARS}
+{PICKCHARS:Fld:Opt}
Shows a dialog to pick certain characters from an entry string. +See below.
{PICKFIELD}Shows a dialog to pick a field +whose value will be inserted.
{NEWPASSWORD}
+{NEWPASSWORD:/Profile/}
Generates a new password. +See below.
{PASSWORD_ENC}Password in encrypted form. +See below.
{HMACOTP}Generates an HMAC-based one-time password. +See below.
{TIMEOTP}Generates a time-based one-time password. +See below.
{C:Comment}Comment; is removed.
{BASE}
+{BASE:RMVSCM}
+{BASE:SCM}
+{BASE:HOST}
+{BASE:PORT}
+{BASE:PATH}
+{BASE:QUERY}
+{BASE:USERINFO}
+{BASE:USERNAME}
+{BASE:PASSWORD}
Within a URL override, +each of these placeholders is replaced by the specified part of the string that is +being overridden. +See below.
{CLIPBOARD}Gets the clipboard content (text).
{CLIPBOARD-SET:/Text/}Copies Text into the clipboard.
{CMD:/CommandLine/Options/}Runs a command line. See below.
+ + + + +

+ + + +{PICKCHARS} – Picking Characters:
+Character Picking Dialog +The {PICKCHARS} placeholder shows a dialog, in which you can +pick characters of an entry string (like the password) at certain positions.
+
+{PICKCHARS} without any parameters lets you pick an arbitrary +amount of characters from the password of the entry. +A different entry string can be specified by appending a ':' +and the name of the field; e.g. {PICKCHARS:UserName}. +The names of the standard fields are Title, UserName (without a space), +Password, URL and Notes. A custom entry string can +be referenced by its name (without an S: prefix).
+
+Additionally, the placeholder supports various (optional!) options. Options are appended +after the field name, separated by a ':'. If you want to specify +multiple options, separate them by a comma ','. Options are +key-value pairs, separated by a '='. The following options +are supported: + +If you want to show the character picking dialog multiple times within one sequence, +assign different IDs to the placeholders. +If an ID is specified multiple times (or no ID is specified +and the placeholders are the same), +KeePass shows the character picking dialog once and reuses the picked characters +in all following placeholders with the same ID.
+
+Usage examples:
+
+{USERNAME}{TAB}{PICKCHARS:Password:C=5}{ENTER}
+First a dialog is shown in which the user can pick exactly 5 characters +from the entry password. +Afterwards KeePass types the user name into the target window, presses +Tab, types the 5 picked characters and presses +Enter.
+
+ComboBox Form +{S:Memorable}{TAB}{PICKCHARS:Password:ID=1, C=1, Conv=D, +Conv-Offset=1}{TAB}{PICKCHARS:Password:ID=2, C=1, Conv=D, +Conv-Offset=1}{TAB}{PICKCHARS:Password:ID=3, C=1, Conv=D, +Conv-Offset=1}{ENTER}
+First the character picking dialog is shown three times and each time the user +can pick exactly one character from the entry password. +Afterwards the auto-type process starts: +KeePass types the contents of a custom entry string named "Memorable" +into the target window. +The focus is switched to the next control by pressing Tab, +and the first previously picked character is converted to +down arrow keypresses (with one additional keypress; e.g. a '1' is converted +to two down arrow keypresses). +This is repeated two more times with the other picked characters, +and finally Enter is pressed.
+
+Note this is not equivalent to picking three characters at once. +If you'd use {S:Memorable}{TAB}{PICKCHARS:Password:C=3, Conv=D, Conv-Offset=1}, +all the down arrow keypresses are sent to the same, currently active control.
+
+In some browsers (e.g. Opera), setting the focus to a combobox can +be slow. If you experience auto-type failures, consider slowing down +the focus changes, e.g. by adding {DELAY 250} after each {TAB}, +or slowing down the whole sequence, e.g. by prepending {DELAY=150}. + + +

+ + + +{NEWPASSWORD} and {NEWPASSWORD:/Profile/} +– Generating New Passwords:
+The {NEWPASSWORD} placeholder +generates a new password for the current entry, based on the 'Automatically +generated passwords for new entries' generator profile.
+
+This placeholder is evaluated only once in an auto-type process, i.e. +for a typical 'Old Password' - 'New Password' - 'Repeat New Password' +dialog you can use +{PASSWORD}{TAB}{NEWPASSWORD}{TAB}{NEWPASSWORD}{ENTER} +as auto-type sequence.
+
+In order to use a different password generator profile, use +{NEWPASSWORD:/Profile/}, where Profile +is the name of the profile. +If the specified profile cannot be found, the +'Automatically generated passwords for new entries' profile is used.
+
+When specifying '~' as name of the profile +(i.e. when using the placeholder {NEWPASSWORD:/~/}), KeePass derives +a profile from the current entry password. +Not recommended, as the quality can decay. + + +

+ + + +{PASSWORD_ENC} – Encrypting Passwords:
+The {PASSWORD_ENC} placeholder is replaced by the password +of the current entry in encrypted form. The password is encrypted using +credentials of the current Windows user. The encrypted password should +not be stored and only works for the current user.
+
+It is intended to be used in conjunction with the +-pw-enc command line parameter +(see the URL Field page for +an example how to define a URL to open an additional KeePass database). +The placeholder cannot be used to transfer passwords to other applications +(except KeePass), because the target applications don't know how to decrypt +encrypted passwords generated by {PASSWORD_ENC}. + + +

+ + + + +One-Time Passwords (OTPs):
+KeePass provides menu commands in the main window for generating one-time +passwords ('Copy HMAC-Based OTP', 'Show HMAC-Based OTP', 'Copy Time-Based OTP', +'Show Time-Based OTP'). +Furthermore, one-time passwords can be generated during +auto-type using the {HMACOTP} and +{TIMEOTP} placeholders. + +

The parameters for the OTP generation are stored as entry strings and +can be edited conveniently using the 'OTP Generator Settings' dialog +(which checks the entered values, shows a preview, etc.). +Alternatively, you can edit the entry strings directly, as documented below.

+ +

{HMACOTP} – Generating HMAC-Based One-Time Passwords:
+The {HMACOTP} placeholder generates an HMAC-based one-time +password (HOTP) according to RFC 4226.

+ +

The shared secret and other parameters can be specified using the +following entry string fields (which can be added/edited in the entry +dialog on the 'Advanced' tab page):

+ + +

{TIMEOTP} – Generating Time-Based One-Time Passwords:
+The {TIMEOTP} placeholder generates a time-based one-time +password (TOTP) according to RFC 6238.

+ +

The shared secret and other parameters can be specified using the +following entry string fields (which can be added/edited in the entry +dialog on the 'Advanced' tab page):

+ + +

The date and the time of your system must be correct, otherwise +the service/server may reject the generated OTP.

+ +

Usage example. +Create a new entry and change its default auto-type sequence to +{USERNAME}{TAB}{PASSWORD}{ENTER}{DELAY 3000}{HMACOTP}{ENTER}. +Open the 'OTP Generator Settings' dialog, set the shared secret +for HMAC-based OTPs to '12345678901234567890' and select the UTF-8 encoding. +When performing auto-type, KeePass sends the user name, presses +Tab, sends the password, presses Enter, +waits 3 seconds, generates and sends a HMAC-based OTP and finally presses +Enter again. +The counter value for the OTP generation is updated automatically. +With the shared secret above and initial counter value 0, the following +OTPs are generated: 755224, 287082, 359152, 969429, 338314, ... +(more generated OTPs can be found in the example in RFC 4226).

+ +Plugins. +There are plugins +that add support for non-standard OTPs (e.g. Steam) and +provide additional functions related to OTPs. + + +

+ + + +{URL:...} and {BASE:...}:
+The {URL:...} placeholder is replaced by the specified part +of the current entry's URL; this typically is useful in an +entry-specific URL override (defined on the 'Properties' tab of the entry dialog). +The {BASE:...} placeholder is replaced by the specified part +of the URL being overridden; this typically is useful in a +global URL override (defined in 'Tools' → 'Options' → tab 'Integration' → +button 'URL Overrides'), because there no entry context may be available.
+
+Usage example. For the entry URL +https://user:pw@keepass.info:80/path/example.php?q=e&s=t, +the placeholders return the following values:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
PlaceholderValue
{URL}https://user:pw@keepass.info:80/path/example.php?q=e&s=t
{URL:RMVSCM}user:pw@keepass.info:80/path/example.php?q=e&s=t
{URL:SCM}https
{URL:HOST}keepass.info
{URL:PORT}80
{URL:PATH}/path/example.php
{URL:QUERY}?q=e&s=t
{URL:USERINFO}user:pw
{URL:USERNAME}user
{URL:PASSWORD}pw
+
+{BASE} supports exactly the same parts as {URL}. + + +

+ + + +{CMD:/CommandLine/Options/} – Running a command line:
+The {CMD:/CommandLine/Options/} placeholder +runs the specified command line.
+
+A command line consists of a path to an executable file or a document +and command line parameters. +If the path contains spaces, it must be enclosed in quotes (").
+
+The character after the first ':' specifies the separator +character. It can be chosen freely (except '{' and '}'), +but it must not occur in the command line or any of the options. +For example, {CMD:/Notepad.exe/W=0/} and +{CMD:!Notepad.exe!W=0!} are equivalent. +The separator character at the end (before the '}') is mandatory.
+
+An option is a key-value pair, separated by '='. +Multiple options must be separated using commas ','.
+
+Options: + + +

New-line characters at the end of the output are removed (analogous to +'$(...)' and '`...`' shell command substitutions).

+ +Usage examples: + + + + + diff --git a/src/Docs/Chm/help/base/pwgenerator.html b/src/Docs/Chm/help/base/pwgenerator.html new file mode 100644 index 0000000..da35d3f --- /dev/null +++ b/src/Docs/Chm/help/base/pwgenerator.html @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Password Generator - KeePass + + + + + + + + + + + + + +

Password Generator

+

Details about the built-in password generator of KeePass.

+ + + +
+ + +

+Generation Based on Character Sets

+ +

This password generation method is the recommended way to generate random passwords. +Other methods (pattern-based generation, ...) should only be used if passwords must +follow special rules or fulfill certain conditions.

+ +

Generation based on a character set is very simple. You simply let KeePass know +which characters can be used (e.g. upper-case letters, digits, ...) and KeePass will +randomly pick characters out of the set.

+ +

Defining a character set:
+The character set can be defined directly in the password generator window. For convenience, +KeePass offers adding commonly used ranges of characters to the set. This is done by +ticking the appropriate check box. Additionally to these predefined character ranges, you +can specify characters manually: all characters that you enter in the 'Also include the +following characters' text box will be directly added to the character set.

+ +

The characters that you enter in the 'Also include the following characters' +text box are included in the character set from which the password generator randomly +chooses characters from. +This means that these additional characters are allowed to appear in the +generated passwords, but they are not forced to. +If you want to force that some characters appear in the generated passwords, +you have to use the pattern-based generation.

+ +

Character sets are sets:
+In mathematical terms, character sets are sets, not vectors. This means that characters +cannot be added twice to the set. Either a character is in the set or it is not.

+ +

For example, if you enter 'AAAAB' into the additional characters box, this is +exactly the same set as 'AB'. 'A' will not be 4 times as likely as 'B'! +If you need to follow rules like 'character A is more likely than B', you must +use pattern-based generation + permuting password characters.

+ +

KeePass will 'optimize' your character set by removing all duplicate characters. If +you'd enter the character set 'AAAAB' into the additional characters box, +close and reopen the password generator, it'll show the shorter character set 'AB'. +Similarly, if you tick the 'Digits' check box and enter '3' into the +additional box, the '3' will be ignored because it is already included in the +'Digits' character range.

+ +

Supported characters:
+All Unicode +characters in the ranges [U+0001, U+D7FF] and [U+E000, U+FFFF] +except { U+0009 / '\t', U+000A / '\n', U+000D / '\r' } are supported. +Characters in the range [U+010000, U+10FFFF] (which need to be encoded +in UTF-16 using surrogate pairs from [0xD800, 0xDFFF]) are not supported. +Subsequent processing of passwords may have further limitations +(for example, the character U+FFFF is forbidden in XML/KDBX files +and will be replaced or removed).

+ +
+ + +

+Generation Based on Patterns

+ +

The password generator can create passwords using patterns. A pattern is a +string defining the layout of the new password. The following placeholders +are supported:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PlaceholderTypeCharacter Set
aLower-Case Alphanumericabcdefghijklmnopqrstuvwxyz 0123456789
AMixed-Case AlphanumericABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789
UUpper-Case AlphanumericABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789
dDigit0123456789
hLower-Case Hex Character0123456789 abcdef
HUpper-Case Hex Character0123456789 ABCDEF
lLower-Case Letterabcdefghijklmnopqrstuvwxyz
LMixed-Case LetterABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz
uUpper-Case LetterABCDEFGHIJKLMNOPQRSTUVWXYZ
vLower-Case Vowelaeiou
VMixed-Case VowelAEIOU aeiou
ZUpper-Case VowelAEIOU
cLower-Case Consonantbcdfghjklmnpqrstvwxyz
CMixed-Case ConsonantBCDFGHJKLMNPQRSTVWXYZ bcdfghjklmnpqrstvwxyz
zUpper-Case ConsonantBCDFGHJKLMNPQRSTVWXYZ
pPunctuation,.;:
bBracket()[]{}<>
sPrintable 7-Bit Special Character!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
SPrintable 7-Bit ASCIIA-Z, a-z, 0-9, !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
xLatin-1 SupplementRange [U+00A1, U+00FF] except U+00AD:
+¡¢£¤¥¦§¨©ª«¬®¯ +°±²³´µ¶·¸¹º»¼½¾¿ +ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ +ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß +àáâãäåæçèéêëìíîï +ðñòóôõö÷øùúûüýþÿ
\Escape (Fixed Char)Use following character as is.
{n}Escape (Repeat)Repeat the previous placeholder n times.
[...]Custom Char SetDefine a custom character set.
+ +

The \ placeholder is special: it's an escape character. The next character that follows +the \ is written directly into the generated password. If you want a \ in your +password at a specific place, you have to write \\.

+ +

Using the {n} code you can define how many times the previous placeholder +should occur. The { } operator duplicates placeholders, not generated characters. Examples:
d{4} is equivalent to dddd,
dH{4}a is equivalent to dHHHHa and
Hda{1}dH is equivalent to HdadH.

+ +

The [...] notation can be used to define a custom character set, from which +the password generator will pick one character randomly. All characters between the '[' +and ']' brackets follow the same rules as the placeholders above. +The '^' character removes the next placeholders from the character set. +Examples:
[dp] generates exactly 1 random character out of the set +digits + punctuation,
[d\m\@^\3]{5} generates 5 characters out of the set "012456789m@",
[u\_][u\_] generates 2 characters out of the set upper-case + '_'.

+ +

More examples:

+ +

ddddd
+Generates for example: 41922, 12733, 43960, 07660, 12390, 74680, ...

+ +

\H\e\x\:\ HHHHHH
+Generates for example: 'Hex: 13567A', 'Hex: A6B99D', 'Hex: 02243C', ...

+ +

Common password patterns:

+ + + + + + + + + + + + + + + + + + + +
NamePattern
Hex Key - 40-BitH{10}
Hex Key - 128-BitH{32}
Hex Key - 256-BitH{64}
MAC AddressHH\-HH\-HH\-HH\-HH\-HH
+ +

+ + +

+Generating Passwords that Follow Rules

+ +

Below are a few examples how the pattern generation feature can be used to generate +passwords that follow certain rules.

+ +

Important! For all of the following examples you must enable the 'Randomly permute +characters of password' option!

+ + + + + + + + + + + + + + + + + + + + + +
RulePattern
Must consist of 2 upper-case letters, 2 lower-case letters and 2 digits.uulldd
Must consist of 9 digits and 1 letter.d{9}L
Must consist of 10 alphanumeric characters, where at least 1 is +a letter and at least 1 is a digit.LdA{8}
Must consist of 10 alphanumeric characters, where at least 2 are +upper-case letters and at least 2 are lower-case letters.uullA{6}
Must consist of 9 characters of the set "ABCDEF" and +an '@' symbol.\@[\A\B\C\D\E\F]{9}
+ +

+ + +

+Security-Reducing Options

+ +

The password generator supports several options like 'Each character must occur at most once', +'Exclude look-alike characters' (O0, Il1|) +and a field to explicitly specify characters that should not appear in generated passwords.

+ +

These options are reducing the security of generated passwords. You should +only enable them if you are forced to follow such rules by the website/application, +for which you are generating the password.

+ +

The options can be found in the 'Advanced' dialog / tab page.

+ + + + + + +Tab Control +If you enable a security-reducing option, an exclamation mark (!)
+is appended to the 'Advanced' tab. + + +

+ + +

+Creating and Using Password Generator Profiles

+ +

Password generator options (character set, length, pattern, ...) can be saved +as password generator profiles.

+ +

Creating/modifying a profile:

+ +
    +
  1. Open the Password Generator window.
  2. +
  3. Specify all options of the new profile.
  4. +
  5. Click the +'Save as Profile' button.
  6. +
  7. Enter the name of the new profile, or select an existing profile name from +the drop-down list to overwrite it. Close the dialog with OK.
  8. +
  9. If you want to immediately create a password using the new profile, +click OK/Accept. Otherwise click Cancel/Close (the profile is not lost; +profile management is independent of password generation).
  10. +
+ +

Using a profile:
+To use a profile, simply select it from the drop-down profiles list +in the password generator window. All settings of this profile will be +restored accordingly.

+ +

Meta-profile 'Derive from previous password':
+When this meta-profile is selected, a password is generated based on +a character set derived from the previous password. The new password +has the same length as the old one, and every character of the old +password turns on the character subset that contains this character. +For example, if the old password contains the letter 'R', then the character +set used for generating the new password contains the range 'A' to 'Z'.
+Warning! This meta-profile should not be used blindly +(i.e. without reviewing the used character set). +The new password does not necessarily contain at least one character +from each character subset (see 'Generation +Based on Character Sets'), thus blindly generating new passwords +with this meta-profile can result in a quality degradation of the +effectively used profile.

+ +
+ + +

+Configuring Settings of Automatically Generated Passwords for New Entries

+ +

When you create a new entry, KeePass will automatically generate a random +password for it. The properties of these generated passwords can be configured +in the password generator dialog.

+ +

To configure, specify the options of your choice and overwrite the +'(Automatically generated passwords for new entries)' profile (see +section above).

+ +

Disabling automatically generated passwords:
+To disable automatically generated passwords for new entries, select +'Generate using character set' and specify 0 as password length. +Overwrite the appropriate profile (see above).

+ + + diff --git a/src/Docs/Chm/help/base/repair.html b/src/Docs/Chm/help/base/repair.html new file mode 100644 index 0000000..837e227 --- /dev/null +++ b/src/Docs/Chm/help/base/repair.html @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Repairing Databases - KeePass + + + + + + + + + + + + +

Repairing Databases

+

KeePass can repair corrupted databases in some cases.

+ +
+ +

KeePass has quite some features to avoid database file corruption +(transacted database writing, device buffer flushing, ...). However, +data corruption can still be caused by other programs, the system or +broken storage devices (note that KeePass by default is verifying the integrity +of database files immediately after writing them, i.e. at this point of time, +KeePass guarantees file integrity; however, KeePass of course can't do anything +when the data becomes corrupted/unreadable at a later point of time).

+ +

In these cases, the database repair functionality might help you. +Here, KeePass tries to read as much data as possible from the corrupted file.

+ +

Warning +In repair mode, the integrity of the data is not checked +(in order to rescue as much data as possible). +When no integrity checks are performed, corrupted/malicious data might +be incorporated into the database. +Thus the repair functionality should only be used when there really is no other solution. +If you use it, afterwards you should thoroughly check your whole +database for corrupted/malicious data.

+ + + + + + +In order to use the repair functionality in KeePass 2.x, first +create a new database file. Then, go 'File''Import' and import +the corrupted database file, using 'KeePass KDBX (2.x) (Repair Mode)' +as format. + + +

Anyway, if you've lost the master key for the database, the repair functionality +cannot help you. Also, if the header of the database (first few bytes) is +corrupted, you're out of luck, too: the repair functionality won't be able +to restore any entries (because the header contains information required +to decrypt the database).

+ +

The repair functionality should be seen as last hope. Regularly making +backups of your databases is much better and has to be preferred. +Backups have no cryptographic security implications. +There are plugins that automate the backup process, see the +KeePass plugins page.

+ +
+ + +

+File Header/Signature

+ +

If your database file has been deleted and you want to try recovering +it using a tool that supports a file header/signature detection: +below you can find the first bytes (in hex notation) with which all +database files begin.

+ + + +

The file header does not contain a field that specifies the length +of the file. If the length cannot be determined from the file system, +try to recover sufficiently much data (i.e. the database file data and +maybe some subsequent, unnecessary data) and use the +repair functionality above, which will simply ignore any subsequent data.

+ + + diff --git a/src/Docs/Chm/help/base/search.html b/src/Docs/Chm/help/base/search.html new file mode 100644 index 0000000..11b59bf --- /dev/null +++ b/src/Docs/Chm/help/base/search.html @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Search - KeePass + + + + + + + + + + + + + + + + + +

Search

+

Details about the search functions of KeePass.

+ + + +
+ + +

+Search Mode 'Simple Expression'

+ +

In this mode, KeePass searches the specified terms in the selected fields. +For an entry to match, all terms must match.

+ + + +

An entry matches if the specified terms can be found as substrings. +If you want to find exact matches instead, use a +regular expression +(see the example 'Exact term').

+ +

Examples.

+ + + + + + + + +
Multiple terms
Find what:Michael Home
Options:☑ Title
Finds every entry whose title contains both the term +'Michael' and the term 'Home' (in any order).
+ +
+ + + + + + + + +
Terms with spaces
Find what:Michael "Web Server"
Options:☑ Title
Finds every entry whose title contains both the term +'Michael' and the term 'Web Server'.
+ +
+ + + + + + + + +
Exclusions (2.x)
Find what:Michael -Home
Options:☑ Title
Finds every entry whose title contains the term +'Michael', but not the term 'Home'.
+ +

+ + +

+Search Mode 'Regular Expression'

+ +

In this mode, KeePass searches for matches of a regular expression +in the selected fields.

+ +

Information about regular expressions and tools can be found here:

+ + +

Examples.

+ + + + + + + + +
Exact term
Find what:^Michael$
Options:☑ User name
Finds every entry whose user name is 'Michael' (exactly, +i.e. 'Michael' is not only a substring of the entry's user name).
+ +
+ + + + + + + + + +
Short passwords
Find what:^.{1,10}$
Options:☑ Password
Finds every entry whose password has a length +between 1 and 10 (inclusive).
If you want to find weak passwords instead, +use the 'Password Quality' command in the 'Find' menu.
+ +
+ + + + + + + + +
Multiple tags (OR, exact)
Find what:^(Home|Private)$
Options:☑ Tags
Finds every entry that has the tag 'Home' or the tag 'Private' +(or both).
+ +

+ + +

+Search Mode 'XPath Expression' (2.x)

+ +

In this mode, a KeePass 2.x XML DOM of the current database is +created in memory and the specified XPath expression is used to +find entries.

+ +

Information about XPath expressions can be found here:

+ + +

In order to see your database in the KeePass 2.x XML format, you can +export it (via 'File' → 'Export') to a 'KeePass XML (2.x)' file.

+ +

If you want to find and replace data using XPath and regular +expressions, see the XML Replace feature.

+ +

Examples.

+ + + + + + + + +
Icon
Find what://Entry[(IconID = '3') and not(CustomIconUUID)]
Finds every entry that has a +Server icon.
+ +
+ + + + + + + + +
Expired in specific year
Find what://Entry/Times[(Expires = 'True') and starts-with(ExpiryTime, '2022-')]/..
Finds every entry that has expired in 2022.
+ +
+ + + + + + + + + +
Custom string field
Find what://Entry/String[(Key = 'Telephone') and contains(Value, '12345')]/..
Options:☑ Other strings
Finds every entry that has a custom string field +named 'Telephone' whose value contains '12345'.
+ +
+ + + + + + + + + +
Attached PDF files
Find what://Entry/Binary/Key[(string-length(.) >= 4) and (substring(., string-length(.) - 3) = '.pdf')]/../..
Finds every entry that has a file attachment whose +name ends with '.pdf'.
If you want to find large entries instead, use the +'Large Entries' command in the 'Find' menu.
+ +
+ + + + + + + + + +
Background color
Find what://Entry[BackgroundColor = '#CCFFCC']
Finds every entry that has a +light green +background color.
The standard background colors are +light red (#FFCCCC), +light green (#CCFFCC), +light blue (#99CCFF) and +light yellow (#FFFF99).
+ +
+ + + + + + + + + + +
Multiple tags (AND, exact)
Find what://Entry[contains(concat(';', Tags, ';'), ';Home;') and +contains(concat(';', Tags, ';'), ';Private;')]
Options:☑ Tags
Finds every entry that has both the tag 'Home' +and the tag 'Private'.
In contrast to this, searching with the +simple expression 'Home Private' +also finds entries that have 'Home' and 'Private' as substrings in +the tags.
+ +
+ + + + + + + + + +
History entry count
Find what://Entry[count(History/Entry) >= 4]
Options:☑ History
Finds every entry that has at least 4 history entries.
+ +
+ + + + + + + + +
Group notes
Find what://Group[contains(Notes, 'Private')]/Entry
Finds every entry whose (direct) parent group +contains the word 'Private' in the notes (of the group, not of the entry). +If there are multiple such groups, the entries of all these groups are found.
+ +

+ + +

+Search Profiles (2.x)

+ +

KeePass can save search parameters as a search profile. +This can be useful when you are regularly performing similar searches.

+ +

Creating a profile.
+In order to save the current search parameters specified in the 'Find' dialog, +click the +profile creation button. KeePass then shows a dialog where you can enter +a name for the new profile.

+ +

Overwriting a profile.
+Overwriting an existing profile works the same as creating a profile, +except that you select an existing profile name in the name dialog.

+ +

Using a profile.
+There are two ways to load a profile and perform a search with it:

+ + +

Deleting a profile.
+In order to delete a profile, select it in the 'Find' dialog and +click the profile deletion button.

+ +
+ + +

+Quick Search Box

+ +

The quick search box in the toolbar of the main window supports +simple expression and +regular expression searches.

+ +

In order to indicate that the search string is a regular expression, +enclose it in '//'. +For example, '//A{6}//' finds all entries containing +the string 'AAAAAA'. +Note that this special syntax does not work in the 'Find' dialog; +in this dialog, you need to select the regular expression mode +and specify the regular expression as-is, i.e. without enclosing it +in '//'.

+ +

Options.
+The 'Find' dialog and the quick search box are independent; +options/parameters in the 'Find' dialog do not affect quick searches. +Options for quick searches can be found in the options dialog +(menu 'Tools' → 'Options' → tab 'Interface').

+ + + diff --git a/src/Docs/Chm/help/base/secedits.html b/src/Docs/Chm/help/base/secedits.html new file mode 100644 index 0000000..31f42da --- /dev/null +++ b/src/Docs/Chm/help/base/secedits.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Secure Edit Controls - KeePass + + + + + + + + + + + + +

Secure Edit Controls

+

KeePass supports security-enhanced edit controls.

+ +

KeePass was one of the first password managers featuring secure edit controls. The +edit controls used in KeePass are resistant to password revealers and password +control spies. Additionally, the entered passwords are protected against +memory dumping attacks: the passwords aren't even visible in the process memory space +of KeePass!

+ +

KeePass uses secure edit controls only when the hiding behind asterisks option +is turned on! If you show the passwords in plaintext, they won't be protected +(secure edit controls are just disabled then, replaced by standard Windows edit +controls).

+ + + + + + +There are no selection limitations. Secure edit controls behave exactly like +standard Windows edit controls. + + + + diff --git a/src/Docs/Chm/help/base/security.html b/src/Docs/Chm/help/base/security.html new file mode 100644 index 0000000..442a542 --- /dev/null +++ b/src/Docs/Chm/help/base/security.html @@ -0,0 +1,710 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Security - KeePass + + + + + + + + + + + + + +

Security

+

Detailed information on the security of KeePass.

+ + + +
+ + +

+Database Encryption

+ +

KeePass database files are encrypted. KeePass encrypts the whole +database, i.e. not only your passwords, but also your user names, URLs, +notes, etc.

+ +

The following encryption algorithms are supported:

+ +

KeePass 1.x:

+ + + + + + + + + + + + +
AlgorithmKey SizeStd. / Ref.
Advanced Encryption Standard (AES / Rijndael)256 bitsNIST FIPS 197
Twofish256 bitsInfo
+ +

KeePass 2.x:

+ + + + + + + + + + + + + + +
AlgorithmKey SizeStd. / Ref.
Advanced Encryption Standard (AES / Rijndael)256 bitsNIST FIPS 197
ChaCha20256 bitsRFC 7539
There exist various +plugins +that provide support for additional encryption algorithms, +including but not limited to Twofish, Serpent and GOST.
+ +

These well-known and thoroughly analyzed algorithms are +considered to be very secure. +AES (Rijndael) became effective as a U.S. federal government standard +and is approved by the National Security Agency (NSA) +for top secret information. +Twofish was one of the other four AES finalists. +ChaCha20 is the successor of the Salsa20 algorithm (which is included in the +eSTREAM portfolio).

+ +

The block ciphers are used in the Cipher Block Chaining (CBC) +block cipher mode. +In CBC mode, plaintext patterns are concealed.

+ +

An initialization vector (IV) is generated +randomly each time +a database is saved. Thus, multiple databases encrypted with the same +master key (e.g. backups) are no problem.

+ +

Data authenticity and integrity:

+ + + + + + +The authenticity and integrity of the data is ensured using +a HMAC-SHA-256 hash of the ciphertext (Encrypt-then-MAC scheme). + + + + +

KeePass 2.x supports the FIPS mode.

+ +
+ + +

+Key Hashing and Key Derivation

+ +

SHA-256 is used for compressing the components +of the master key +(consisting of a master password, a key file, a Windows user account key +and/or a key provided by a plugin) to a 256-bit key K.

+ +

SHA-256 is a cryptographic hash function that is considered to be +very secure. It has been standardized in +NIST FIPS 180-4. +The attack against SHA-1 discovered in 2005 does not affect +the security of SHA-256.

+ +

In order to generate the key for the encryption algorithm, +K is transformed using a key derivation function (with +a random salt). This prevents precomputation of keys and makes dictionary +and guessing attacks harder. For details, see the section +'Protection against Dictionary Attacks'.

+ +
+ + +

+Protection against Dictionary Attacks

+ +

KeePass features a protection against dictionary and guessing attacks.

+ +

Such attacks cannot be prevented, but they can be made harder. +For this, the key K derived from the user's master key +(see above) is transformed using a +key derivation function with a random salt. +This prevents a precomputation of keys and adds a work factor +that the user can make as large as desired +to increase the computational effort of a dictionary or guessing attack.

+ +

Multiple key derivation functions are supported. In the database +settings dialog, you can select one and specify certain parameters +for it.

+ +

By clicking the '1 Second Delay' button in the database settings +dialog, KeePass computes the number of iterations that results in a +1 second delay when loading/saving a database. +Furthermore, KeePass 2.x has a button 'Test' that performs a key +transformation with the specified parameters (which can be cancelled) +and reports the required time.

+ +

The key transformation may require more or less time on other +devices. If you are using KeePass or a port of it on other devices, +make sure that all devices are fast enough (and have sufficient memory) +to load the database with your parameters within an acceptable time.

+ +

Supported key derivation functions:

+ + + +

Argon2 on iOS. If you are using a KeePass-compatible app +on iOS, please note the following limitation of iOS. +If the app uses a lot of RAM (e.g. due to using Argon2 with a +large memory parameter), then AutoFill may not work. +In this case, we recommend to use a relatively low value for the +Argon2 memory parameter (64 MB or less, depending on the app and the +database size) and a relatively high number of iterations.

+ +

KeePassX. In contrast to KeePass, the Linux port KeePassX +only partially supports protection against dictionary and guessing attacks.

+ +
+ + +

+Random Number Generation

+ +

KeePass first creates an entropy pool using various entropy sources +(including random numbers generated by the system cryptographic provider, +current date/time and uptime, cursor position, operating system version, +processor count, environment variables, process and memory statistics, +current culture, a new random GUID, etc.).

+ +

The random bits for the high-level generation methods are generated +using a cryptographically secure pseudo-random number generator +(based on SHA-256/SHA-512 and ChaCha20) that is initialized using the entropy pool.

+ +
+ + +

+Process Memory Protection

+ +

While KeePass is running, sensitive data is stored encryptedly +in the process memory. +This means that even if you would dump the KeePass process memory to disk, +you could not find any sensitive data. +For performance reasons, the process memory protection only applies +to sensitive data; sensitive data here includes for instance the master key +and entry passwords, but not user names, notes and file attachments. +Note that this has nothing to do with the +encryption of database files; +in database files, all data (including user names, etc.) is encrypted.

+ +

Furthermore, KeePass erases all security-critical memory (if possible) +when it is not needed anymore, i.e. it overwrites these memory areas +before releasing them.

+ +

KeePass uses the Windows DPAPI for encrypting sensitive data in memory + +(via CryptProtectMemory / + +ProtectedMemory). +With DPAPI, the key for the memory encryption is stored in a +secure, non-swappable memory area managed by Windows. +DPAPI is available on Windows 2000 and higher. +KeePass 2.x always uses DPAPI when it is available; +in KeePass 1.x, this can be disabled (in the advanced options; by default +using DPAPI is enabled; if it is disabled, KeePass 1.x uses the ARC4 encryption +algorithm with a random key; note that this is less secure than DPAPI, mainly not +because ARC4 cryptographically is not that strong, but because the key for +the memory encryption is also stored in swappable process memory; +similarly, KeePass 2.x falls back to encrypting the process memory using +ChaCha20, if DPAPI is unavailable). +On Unix-like systems, KeePass 2.x uses ChaCha20, because Mono does not provide +any effective memory protection method.

+ +

For some operations, KeePass must make sensitive data available +unencryptedly in the process memory. For example, in order to show a password +in the standard list view control provided by Windows, KeePass must supply +the cell content (the password) as unencrypted string +(unless hiding using asterisks is enabled). +Operations that result in unencrypted data in the process memory include, +but are not limited to: displaying data (not asterisks) in standard controls, +searching data, replacing placeholders (during auto-type, drag&drop, +copying to clipboard, ...), importing/exporting files (except KDBX) +and loading/saving unencrypted files. +Windows and .NET may make copies of the data (in the process memory) +that cannot be erased by KeePass.

+ +
+ + +

+Enter Master Key on Secure Desktop (Protection against Keyloggers)

+ +

KeePass 2.x has an option (in 'Tools' → 'Options' → tab 'Security') +to show master key dialogs on a different/secure desktop +(supported on Windows 2000 and higher), similar to Windows' +User Account Control (UAC). Almost no keylogger works on a secure desktop.

+ +

The option is turned off by default for compatibility reasons.

+ +

More information can be found on the +Secure Desktop +help page.

+ + +Note that auto-type can be secured against keyloggers, too, by using +Two-Channel Auto-Type Obfuscation. + + +

Note: KeePass was one of the first password managers that allow +entering the master key on a different/secure desktop!

+ +
+ + +

+Locking the Workspace

+ +

When locking the workspace, KeePass closes the database file and +only remembers its path and certain view parameters.

+ +

This provides maximum security: unlocking the +workspace is as hard as opening the database file the normal way. Also, it prevents +data loss (the computer can crash while KeePass is locked, without doing any damage +to the database).

+ +

When a sub-dialog is open, the workspace may not be locked; +for details, see the FAQ.

+ +
+ + +

+Viewing/Editing Attachments

+ +

KeePass 2.x has an internal viewer/editor for attachments. +For details how to use it for working with texts, see +'How to store and work with large amounts of +(formatted) text?'.

+ +

The internal viewer/editor works with the data in main memory. +It does not extract/store the data onto disk.

+ +

When trying to open an attachment that the internal viewer/editor cannot handle +(e.g. a PDF file), KeePass extracts the attachment to a (EFS-encrypted) +temporary file and opens it using the default application associated with this file type. +After finishing viewing/editing, the user can choose between importing +or discarding any changes made to the temporary file. +In any case, KeePass afterwards securely deletes the temporary file +(including overwriting it).

+ +
+ + +

+Plugins

+ + + + +

A separate page exist about the security of plugins: +Plugin Security.

+ + +
+ + +

+Self-Tests

+ +

Each time you start KeePass, the program performs a quick self-test to see +whether the encryption and hash algorithms work correctly and pass +their test vectors. If one of the algorithms does not pass its test vectors, +KeePass shows a security exception dialog.

+ +
+ + +

+Specialized Spyware

+ +

This section gives answers to questions like the following:

+ + + +

The answer to all these questions is: no. Adding any of these features +would not increase security.

+ +

All security features in KeePass protect against generic threats like +keyloggers, clipboard monitors, password control monitors, etc. (and against +non-runtime attacks on the database, memory dump analyzers, ...). +However in all the questions above we are assuming that there is a spyware +program running on the system that is specialized on attacking KeePass.

+ +

In this situation, the best security features will fail. +This is law #1 of the + + +Ten Immutable Laws of Security +(Microsoft TechNet article; see also the +Microsoft TechNet article + +Revisiting the 10 Immutable Laws of Security, Part 1):
+"If a bad guy can persuade you to run his program on your +computer, it's not your computer anymore".

+ +

For example, consider the following very simple spyware specialized +for KeePass: an application that waits for KeePass to be started, then hides +the started application and imitates KeePass itself. All interactions +(like entering a password for decrypting the configuration, etc.) can be +simulated. +The only way to discover this spyware is to use a program that the spyware +does not know about or cannot manipulate (secure desktop); +in any case it cannot be KeePass.

+ +

For protecting your PC, we recommend using an anti-virus software. +Use a proper firewall, only run software from trusted sources, +do not open unknown e-mail attachments, etc.

+ +
+ + +

+Malicious Data

+ +

The user should check all data that he enters and/or runs.

+ +

If you enter/run data without checking it first, this can lead to +security problems (like for instance a disclosure of sensitive data +or an execution of malicious code). This is a general principle; +it applies to most applications, not only to KeePass.

+ +

Examples:

+ + +

If the user checks the data that he enters/runs, none of the +"attacks" above works. Entering data is a manual operation +(i.e. an attacker cannot do this himself), and only the user can +decide whether the resulting effect is intended or not. +Showing warning/confirmation dialogs all the time would not be reasonable.

+ +

When opening a database that has been created/modified by +someone else, you should carefully check all data that you want to use. +If you do not fully trust the creator of the database, do not +open any files attached to entries.

+ +
+ + +

+Options for Experts

+ +

Most security options can be configured in the options dialog of +KeePass (menu 'Tools' → 'Options') and in the database settings +dialog (menu 'File' → 'Database Settings').

+ +

However, in KeePass 2.x, there additionally are a few security options +for experts that cannot be configured in the user interface. +For example, KeePass can protect its process with a +discretionary access control list (DACL), and +its windows can be protected against certain screen capture operations.

+ +

Warning +Activating these options for experts may result in compatibility problems and +may make KeePass unusable. Therefore, these options can only be activated by +editing the configuration file manually (using an XML or text editor). +This ensures that users know how they can deactivate the problematic options +(by editing the configuration file once more) +in order to make KeePass usable again.

+ +

If you know how the configuration +system of KeePass works, then see the +customization +help page, on which these options are documented.

+ +
+ + +

+Options for Administrators

+ +

Administrators can enforce certain settings, disallow certain functions, +specify requirements for master passwords, and much more. +Details can be found on the following help pages:

+ + + +
+ + +

+Security Issues

+ +

For a list of security issues, their status and clarifications, please see the page +Security Issues.

+ + + diff --git a/src/Docs/Chm/help/base/tans.html b/src/Docs/Chm/help/base/tans.html new file mode 100644 index 0000000..4507a5f --- /dev/null +++ b/src/Docs/Chm/help/base/tans.html @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + TAN Support - KeePass + + + + + + + + + + + + +

TAN Support

+

KeePass supports Transaction Authentication Numbers (TANs).

+ + + +

KeePass supports TANs, i.e. passwords that can be used only +once. +These special passwords are used by some banks: you need to confirm +transactions using such TANs. This provides additional security, as +a spy cannot perform transactions, even if he knows the password of +your banking account.

+ +
+ + +

+Using the TAN Wizard to add TANs

+ +

You can use the KeePass TAN Wizard to add several TANs at once to your +database. Just open the TAN wizard dialog (menu Tools - TAN Wizard) and enter +all your TANs. The formatting doesn't really +matter, KeePass just uses all alphanumerical strings, i.e. characters like line breaks, +tabs, spaces, dots, etc. are interpreted as separators.

+ +

The wizard will then generate several TAN entries from the data you entered into the dialog. Each +TAN is a standard KeePass entry. The title of a TAN entry always is set to "<TAN>". +This tells KeePass that the entry is a TAN entry. You cannot change the title, user +name and URL of a TAN. But you can freely add notes to a TAN entry, if you wish.

+ +
+ + +

+Using TANs

+ +

When you use the TAN (e.g. execute the "Copy Password" command on +it), its expiration date will be set +to the current time, which expires the entry. It will get a red +X as icon. +If you later want to know when you used a specific TAN, +you can just have a look at its expiration date.

+ +

When copying a TAN to the clipboard, the database is marked as modified. You must save +the file in order to remember the usage of a TAN.

+ +

If you accidently used a TAN without needing it, you can reset it (i.e. remove the red +X and show it as valid TAN again). To do this, open the +TAN entry (right-click it and choose 'Edit/View Entry...'). Here, uncheck the +'Expires' checkbox. Click [OK] to close the dialog.

+ + + diff --git a/src/Docs/Chm/help/base/terms.html b/src/Docs/Chm/help/base/terms.html new file mode 100644 index 0000000..b02e90c --- /dev/null +++ b/src/Docs/Chm/help/base/terms.html @@ -0,0 +1,1311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Legal Documentation - KeePass + + + + + + + + + + + + + + + + + + +

Legal Documentation

+

Terms of use, disclaimer and privacy policy.

+ +

+English:

+ + +

+German (Deutsch):

+ + +

Only the German version is legally binding.

+ +
+ +

+English

+ + +

Content

+ +

The author reserves the right not to be responsible for the topicality, +correctness, completeness or quality of the information provided. +Liability claims against the author relating to material or non-material +damage caused by the use or non-use of the information provided or by the +use of incorrect or incomplete information are generally excluded, +unless it can be proven that the author acted intentionally or +with gross negligence.

+ +

All offers are subject to change and non-binding. +The author expressly reserves the right to change, extend or delete +parts of the pages or the entire publication or to cease the publication +temporarily or permanently without separate announcement.

+ +
+ + +

Referrals and Links

+ +

In the case of direct or indirect referrals and links to external +websites that lie outside the author's area of responsibility, +liability would only come into force if the author had knowledge of +the content and it were technically possible and reasonable for him +to prevent use in the case of illegal content.

+ +

The author hereby expressly declares that at the time of setting the +referral or link no illegal content was discernible on the referred/linked pages. +The author has no influence whatsoever on the current and future design, +content or authorship of the referred/linked pages. +Therefore, he hereby expressly dissociates himself from all contents of all +referred/linked pages which were changed after the referral or link setting. +This statement applies to all referrals and links within the author's own +Internet offer as well as to foreign entries in guest books, discussion +forums, link directories, mailing lists and all other forms of databases +set up by the author to whose content external write accesses are possible. +For illegal, incorrect or incomplete contents and in particular for damages +arising from the use or non-use of information presented in this way, +only the provider of the page to which the referral/link was made is liable, +not the person who merely refers/links to the respective publication.

+ +
+ + +

Copyright and Trademark Rights

+ +

The author endeavours to respect applicable copyrights in all publications. +However, if in spite of all efforts a copyright is violated, we will +remove the relevant item from the publication on notification or +will insert information on the copyright.

+ +

All brands and trademarks mentioned within the publication that are +subject to property rights of third parties are subject to the +provisions of the applicable trademark law and the property rights of the +registered owner without restriction. +The mere mention of a trademark does not imply that it is not protected +by third-party rights.

+ +

The copyright for any material (images, diagrams, sounds, videos, texts, etc.) +created by the author is reserved. +Any duplication or use of such material in other electronic or printed +publications is not permitted without the author's explicit consent.

+ +
+ + +

Privacy

+ +

Controller

+ +

See Imprint.

+ +
+ +

General Information on Data Processing

+ +

If the opportunity for the input of personal or business data (e-mail +addresses, name, addresses) is given, the input of this data takes place +voluntarily. The use and payment of all offered services is permitted – +if and so far technically possible and reasonable – without +specification of any personal data or under specification of anonymized data +or an alias.

+ +

The use of published postal addresses, telephone or fax numbers and +e-mail addresses for marketing purposes is prohibited. +We expressly reserve the right to take legal action against senders of +so-called spam mails who violate this prohibition.

+ +
Scope of Processing of Personal Data
+ +

We only process personal data of our users if this is necessary to +provide a functional website as well as our contents and services. +The processing of personal data of our users takes place regularly only +after consent of the user. +An exception applies in those cases where prior consent cannot be obtained +for real reasons and the processing of the data is permitted by law.

+ +
Legal Basis for the Processing of Personal Data
+ + + +
Data Erasure and Storage Time
+ +

The personal data of the data subject will be erased or blocked as soon +as the purpose of storage ceases to apply. +The data may be stored beyond that if the European or national legislator +has provided for this in EU regulations, laws or other provisions to which +the controller is subject. +The data will also be erased or blocked if a storage period prescribed by +the aforementioned standards expires, unless there is a need for further +storage of the data for the conclusion or performance of a contract.

+ +
+ +

Provision of the Website and Creation of Log Files

+ +

Every time you visit our website, our system automatically collects data +and information of the calling computer. +The following data is collected:

+ +
    +
  1. Information about the browser type and version used.
  2. +
  3. The user's operating system.
  4. +
  5. The user's Internet service provider.
  6. +
  7. The IP address of the user.
  8. +
  9. Date and time of access.
  10. +
  11. Websites from which the user's system reaches our website.
  12. +
  13. Websites that are accessed by the user's system via our website.
  14. +
+ +

The data is also stored in the log files of our system. +This data is not stored together with other personal data of the user.

+ +

The temporary storage of the IP address by the system is necessary to +enable the website to be delivered to the user's computer. +For this the IP address of the user must remain stored for the duration +of the session.

+ +

The data is stored in log files to ensure the functionality of the website. +In addition, the data serves us to optimize the website and to ensure +the security of our information technology systems. +An evaluation of the data for marketing purposes does not take place in +this context.

+ +

The legal basis for the temporary storage of the data and the log files +is Art. 6 para. 1 lit. f GDPR. +Our legitimate interests lie in the above-mentioned purposes.

+ +

The data will be deleted as soon as they are no longer necessary to +achieve the purpose for which they were collected:

+ + + +

The collection of the data for the provision of the website and the +storage of the data in log files is absolutely necessary for the +operation of the website. +Consequently, there is no possibility of objection on the part of the user.

+ +
+ +

Cookies

+ +

Our website uses cookies. +Cookies are text files that are stored in the browser or by the +browser on the user's computer system. +If a user visits a website, a cookie may be stored on the user's system. +This cookie may contain a characteristic string that uniquely identifies +the browser when you return to the website.

+ +

We use cookies to make our website more user-friendly. +Some elements of our website require that the calling browser can +be identified even after a page change.

+ +

The following data is stored and transmitted in the cookies:

+ + +

The purpose of using technically necessary cookies is to simplify +the use of websites for users. +Some functions of our website cannot be offered without the use of cookies. +For this it is necessary that the browser is recognized even after a page change.

+ +

We need cookies for the following applications:

+ + +

The user data collected via technically necessary cookies are not +used to create user profiles.

+ +

The legal basis for the processing of personal data using cookies +is Art. 6 para. 1 lit. f GDPR. +Our legitimate interests lie in the above-mentioned purposes.

+ +

The user's computer stores and transmits cookies. +Therefore, you as a user also have full control over the use of cookies. +You can deactivate or restrict the transmission of cookies by changing +the settings in your browser. +Cookies that have already been saved can be erased at any time. +This can also be done automatically. +Please consult the documentation of your browser. +Links to the cookie management documentations of some popular browsers:

+ + +

If cookies are deactivated for our website, it may no longer be possible +to use all functions of the website to the full extent.

+ +
+ +

Advertising

+ +

We use third-party advertising companies (Google) to serve ads when you visit our +website. These companies may use information (not including your name, address, +e-mail address or telephone number) about your visits to this and other websites +in order to provide advertisements about goods and services of interest to you. +For more information about the methods and how you can prevent this information +from being used by third parties, see:

+ + +

In the European Economic Area and California, +only non-personalized advertising is displayed on our website.

+ +

When you visit a page on our website, your browser contacts the +third party servers. +The third party provider obtains among other things your IP address, +the browser type and the address (URL) of the visited page.

+ +

The legal basis is Art. 6 para. 1 lit. f GDPR; +our website is financed by advertising.

+ +
+ +

Contact Form and E-Mail Contact

+ +

There is a contact form on our website, which can be used for +electronic contact. +When a user takes advantage of this possibility, the data entered in +the input mask is transmitted to us and stored. +At the time the message is sent, the current date and time are also stored.

+ +

Alternatively, it is possible to contact us via the e-mail address provided. +In this case, the user's personal data transmitted by e-mail is stored.

+ +

In this context, the data is not passed on to third parties.

+ +

The data is used only to process the contact or conversation.

+ +

The legal basis for the processing of the data is Art. 6 para. 1 lit. f GDPR. +Our legitimate interests lie in the above-mentioned purposes. +If the contact is aimed at the conclusion of a contract, +Art. 6 para. 1 lit. b GDPR is an additional legal basis.

+ +

If a legal archiving obligation applies, the data is stored for +the prescribed duration. +Otherwise, the data are erased as soon as they are no longer necessary +to achieve the purposes of their collection. +For the personal data sent via contact form or e-mail, this is the case +when the conversation with the user is finished. +The conversation is finished when the circumstances indicate that the +matter in question has been finally clarified.

+ +

You have the possibility to object to the storage of your personal data +at any time. To do this, send an appropriate e-mail to the controller. +In this case, all data stored in the course of the contact or conversation +will be erased without undue delay, and the conversation cannot be continued.

+ +
+ +

Rights of the Data Subject

+ +

If your personal data is processed, you are a data subject in terms of +the GDPR and have the following rights.

+ +
Right of Access
+ +

You can ask the controller to confirm whether personal data concerning +you is processed by us.

+ +

If such processing takes place, you can request the following information +from the controller:

+
    +
  1. the purposes of the processing;
  2. +
  3. the categories of personal data concerned;
  4. +
  5. the recipients or categories of recipient to whom the personal data +have been or will be disclosed;
  6. +
  7. the envisaged period for which the personal data will be stored, +if possible, or otherwise the criteria used to determine that period;
  8. +
  9. the existence of the right to request from the controller +rectification or erasure of personal data or restriction of processing of +personal data concerning the data subject or to object to such processing;
  10. +
  11. the right to lodge a complaint with a supervisory authority;
  12. +
  13. where the personal data are not collected from the data subject, +any available information as to their source;
  14. +
  15. the existence of automated decision-making, including profiling, +referred to in Art. 22 para. 1 and 4 GDPR and, at least in those cases, +meaningful information about the logic involved, as well as the significance +and the envisaged consequences of such processing for the data subject.
  16. +
+ +

You have the right to request information as to whether the personal +data concerning you is transferred to a third country or to an +international organization. +In this context, pursuant to Art. 46 GDPR you may request to be informed +of the appropriate safeguards relating to the transfer.

+ +
Right to Rectification
+ +

You have the right to rectification and/or completion if the personal +data processed concerning you is incorrect or incomplete. +The controller shall make the correction without undue delay.

+ +
Right to Restriction of Processing
+ +

Under the following conditions, you may request the restriction of the +processing of personal data concerning you:

+ +
    +
  1. if you contest the accuracy of the personal data, for a period +enabling the controller to verify the accuracy of the personal data;
  2. +
  3. the processing is unlawful and you oppose the erasure of the personal +data and request the restriction of their use instead;
  4. +
  5. the controller no longer needs the personal data for the purposes of +the processing, but they are required by you for the establishment, +exercise or defence of legal claims;
  6. +
  7. you object to processing pursuant to Art. 21 para. 1 GDPR pending the +verification whether the legitimate grounds of the controller override yours.
  8. +
+ +

Where processing has been restricted, your personal data shall, +with the exception of storage, only be processed with your consent or +for the establishment, exercise or defence of legal claims or for the +protection of the rights of another natural or legal person or for reasons +of important public interest of the Union or of a Member State.

+ +

If processing has been restricted pursuant to the above conditions, +you will be informed by the controller before the restriction is lifted.

+ +
Right to Erasure
+ +

Erasure Obligation. +You have the right to obtain from the controller the erasure of personal data +concerning you without undue delay. +The controller has the obligation to erase personal data without undue delay +where one of the following grounds applies:

+
    +
  1. The personal data are no longer necessary in relation to the purposes +for which they were collected or otherwise processed.
  2. +
  3. You withdraw your consent on which the processing is based (according to +Art. 6 para. 1 lit. a or Art. 9 para. 2 lit. a GDPR), and where there is no +other legal ground for the processing.
  4. +
  5. You object to the processing pursuant to Art. 21 para. 1 GDPR and +there are no overriding legitimate grounds for the processing, or you +object to the processing pursuant to Art. 21 para. 2 GDPR.
  6. +
  7. The personal data have been unlawfully processed.
  8. +
  9. The personal data have to be erased for compliance with a legal +obligation in Union or Member State law to which the controller is subject.
  10. +
  11. The personal data have been collected in relation to the offer of +information society services referred to in Art. 8 para. 1 GDPR.
  12. +
+ +

Information to Third Parties. +Where the controller has made the personal data public and is obliged +pursuant to Art. 17 para. 1 GDPR to erase the personal data, the controller, +taking account of available technology and the cost of implementation, +shall take reasonable steps, including technical measures, to inform +controllers which are processing the personal data that you have requested +the erasure by such controllers of any links to, or copy or replication of, +those personal data.

+ +

Exceptions. +The right to erasure does not apply where processing is necessary

+
    +
  1. for exercising the right of freedom of expression and information;
  2. +
  3. for compliance with a legal obligation which requires processing by +Union or Member State law to which the controller is subject or for +the performance of a task carried out in the public interest or in the +exercise of official authority vested in the controller;
  4. +
  5. for reasons of public interest in the area of public health in +accordance with Art. 9 para. 2 lit. h and i as well as Art. 9 para. 3 GDPR;
  6. +
  7. for archiving purposes in the public interest, scientific or +historical research purposes or statistical purposes in accordance with +Art. 89 para. 1 GDPR in so far as the right referred to in +Art. 17 para. 1 GDPR is likely to render impossible or seriously +impair the achievement of the objectives of that processing;
  8. +
  9. for the establishment, exercise or defence of legal claims.
  10. +
+ +
Right to Notification
+ +

The controller communicates any rectification or erasure of personal +data or restriction of processing carried out in accordance with +Art. 16, Art. 17 para. 1 and Art. 18 GDPR to each recipient to whom +the personal data have been disclosed, unless this proves impossible +or involves disproportionate effort.

+ +

You have the right to request to be informed about those recipients +by the controller.

+ +
Right to Data Portability
+ +

You have the right to receive the personal data concerning you, +which you have provided to the controller, in a structured, +commonly used and machine-readable format and have the right to +transmit those data to another controller without hindrance from +the controller to which the personal data have been provided, where

+
    +
  1. the processing is based on consent pursuant to Art. 6 para. 1 lit. a +or Art. 9 para. 2 lit. a GDPR or on a contract pursuant to +Art. 6 para. 1 lit. b GDPR, and
  2. +
  3. the processing is carried out by automated means.
  4. +
+ +

In exercising this right, you further have the right to have the +personal data transmitted directly from one controller to another, +where technically feasible. +Freedoms and rights of others must not be affected adversely.

+ +

The right to data portability does not apply to processing necessary +for the performance of a task carried out in the public interest or in +the exercise of official authority vested in the controller.

+ +
Right to Object
+ +

You have the right to object, on grounds relating to your particular +situation, at any time to processing of personal data concerning you +which is based on Art. 6 para. 1 lit. e or f GDPR, +including profiling based on those provisions.

+ +

The controller no longer processes your personal data unless the +controller demonstrates compelling legitimate grounds for the processing +which override your interests, rights and freedoms or for the +establishment, exercise or defence of legal claims.

+ +

Where personal data are processed for direct marketing purposes, +you have the right to object at any time to processing of personal data +concerning you for such marketing, which includes profiling to the +extent that it is related to such direct marketing.

+ +

If you object to processing for direct marketing purposes, your +personal data is no longer processed for such purposes.

+ +

In the context of the use of information society services, and +notwithstanding Directive 2002/58/EC, you may exercise your right +to object by automated means using technical specifications.

+ +
Right to Withdraw the Data Protection Declaration of Consent
+ +

You have the right to withdraw your consent at any time. +The withdrawal of consent does not affect the lawfulness of processing +based on consent before its withdrawal.

+ +
Automated Individual Decision-Making, Including Profiling
+ +

You have the right not to be subject to a decision based solely on +automated processing, including profiling, which produces legal effects +concerning you or similarly significantly affects you. +This does not apply if the decision

+
    +
  1. is necessary for entering into, or performance of, a contract between +you and the controller;
  2. +
  3. is authorised by Union or Member State law to which the controller +is subject and which also lays down suitable measures to safeguard your +rights and freedoms and legitimate interests; or
  4. +
  5. is based on your explicit consent.
  6. +
+ +

However, these decisions are not based on special categories of +personal data referred to in Art. 9 para. 1 GDPR, unless +Art. 9 para. 2 lit. a or g GDPR applies and suitable measures to +safeguard your rights and freedoms and legitimate interests are in place.

+ +

In the cases 1. and 3., the data controller implements suitable +measures to safeguard your rights and freedoms and legitimate interests, +at least the right to obtain human intervention on the part of the +controller, to express your point of view and to contest the decision.

+ +
Right to Lodge a Complaint With a Supervisory Authority
+ +

Without prejudice to any other administrative or judicial remedy, +you have the right to lodge a complaint with a supervisory authority, +in particular in the Member State of your habitual residence, place of +work or place of the alleged infringement if you consider that the +processing of personal data relating to you infringes the GDPR.

+ +

The supervisory authority with which the complaint has been lodged +informs the complainant on the progress and the outcome of the +complaint including the possibility of a judicial remedy pursuant to +Art. 78 GDPR.

+ +
+ + + +

KeePass License

+ +

The terms under which KeePass is distributed can be found on the +following pages: +KeePass 1.x License, +KeePass 2.x License.

+ +

See also the Acknowledgements/Credits page +(includes third-party licenses).

+ +
+ + + +

Legal Validity of this Documentation

+ +

This legal documentation is to be regarded as part of the Internet +publication from which you were referred to this page. +If sections or individual terms of this statement are not legal or +correct, the content or validity of the other parts remain uninfluenced +by this fact.

+ +

+ +

+German (Deutsch)

+ + +

Inhalt

+ +

Der Autor übernimmt keinerlei Gewähr für die Aktualität, Korrektheit, +Vollständigkeit oder Qualität der bereitgestellten Informationen. +Haftungsansprüche gegen den Autor, welche sich auf Schäden materieller +oder nicht-materieller Art beziehen, die durch die Nutzung oder Nichtnutzung +der dargebotenen Informationen bzw. durch die Nutzung fehlerhafter +oder unvollständiger Informationen verursacht wurden, sind +grundsätzlich ausgeschlossen, sofern seitens des Autors kein +nachweislich vorsätzliches oder grob fahrlässiges Verschulden vorliegt.

+ +

Alle Angebote sind freibleibend und unverbindlich. +Der Autor behält es sich ausdrücklich vor, Teile der Seiten oder das gesamte +Angebot ohne gesonderte Ankündigung zu verändern, zu ergänzen, zu +löschen oder die Veröffentlichung zeitweise oder endgültig einzustellen.

+ +
+ + +

Verweise und Links

+ +

Bei direkten oder indirekten Verweisen und Links auf fremde Webseiten, +die außerhalb des Verantwortungsbereiches des Autors liegen, +würde eine Haftungsverpflichtung ausschließlich in +dem Fall in Kraft treten, in dem der Autor von den Inhalten Kenntnis +hat und es ihm technisch möglich und zumutbar wäre, die Nutzung im +Falle rechtswidriger Inhalte zu verhindern.

+ +

Der Autor erklärt hiermit ausdrücklich, dass zum Zeitpunkt der +Verweis- bzw. Linksetzung keine illegalen Inhalte auf den verwiesenen/verlinkten +Seiten erkennbar waren. Auf die aktuelle und zukünftige Gestaltung, +die Inhalte oder die Urheberschaft der verwiesenen/verlinkten Seiten +hat der Autor keinerlei Einfluss. Deshalb distanziert er sich +hiermit ausdrücklich von allen Inhalten aller verwiesenen/verlinkten Seiten, +die nach der Verweis- bzw. Linksetzung verändert wurden. +Diese Feststellung gilt für alle innerhalb des eigenen Internetangebotes +gesetzten Verweise und Links sowie für Fremdeinträge in vom Autor +eingerichteten Gästebüchern, Diskussionsforen, Linkverzeichnissen, +Mailinglisten und in allen anderen Formen von Datenbanken, auf +deren Inhalt externe Schreibzugriffe möglich sind. Für illegale, +fehlerhafte oder unvollständige Inhalte und insbesondere für +Schäden, die aus der Nutzung oder Nichtnutzung solcherart +dargebotener Informationen entstehen, haftet allein der +Anbieter der Seite, auf welche verwiesen wurde, nicht derjenige, +der über Verweise oder Links auf die jeweilige Veröffentlichung +lediglich verweist.

+ +
+ + +

Urheber- und Kennzeichenrecht

+ +

Der Autor ist bestrebt, in allen Publikationen geltende Urheberrechte +zu beachten. Sollte es trotzdem zu einer Urheberrechtsverletzung kommen, +werden wir das entsprechende Objekt nach Benachrichtigung aus unserer +Publikation entfernen oder Informationen zum Urheberrecht hinzufügen.

+ +

Alle innerhalb des Internetangebots genannten und ggf. durch Dritte +geschützten Marken- und Warenzeichen unterliegen uneingeschränkt den +Bestimmungen des jeweils gültigen Kennzeichenrechts und den +Besitzrechten der jeweiligen eingetragenen Eigentümer. +Allein aufgrund der bloßen Nennung ist nicht der Schluss zu ziehen, +dass Markenzeichen nicht durch Rechte Dritter geschützt sind.

+ +

Das Copyright für veröffentlichte, vom Autor selbst erstellte +Objekte (Bilder, Grafiken, Tondokumente, Videosequenzen, Texte, usw.) +bleibt allein beim Autor der Seiten. +Eine Vervielfältigung oder Verwendung solcher Objekte in anderen +elektronischen oder gedruckten Publikationen ist ohne ausdrückliche +Zustimmung des Autors nicht gestattet.

+ +
+ + +

Datenschutz

+ +

Verantwortlicher

+ +

Siehe Impressum.

+ +
+ +

Allgemeines zur Datenverarbeitung

+ +

Sofern innerhalb des Internetangebotes die Möglichkeit zur +Eingabe persönlicher oder geschäftlicher Daten (E-Mail-Adressen, +Namen, Anschriften) besteht, so erfolgt die Preisgabe dieser Daten seitens +des Nutzers auf ausdrücklich freiwilliger Basis. Die Inanspruchnahme +und Bezahlung aller angebotenen Dienste ist – soweit technisch +möglich und zumutbar – auch ohne Angabe solcher Daten bzw. +unter Angabe anonymisierter Daten oder eines Pseudonyms gestattet.

+ +

Die Nutzung der im Rahmen des Impressums oder vergleichbarer +Angaben veröffentlichten Kontaktdaten wie Postanschriften, +Telefon- und Faxnummern sowie E-Mail-Adressen durch Dritte zur +Übersendung von nicht ausdrücklich angeforderten Informationen +zu Marketing-Zwecken ist nicht gestattet. +Rechtliche Schritte gegen die Versender von sogenannten Spam-Mails +bei Verstößen gegen dieses Verbot sind ausdrücklich vorbehalten.

+ +
Umfang der Verarbeitung personenbezogener Daten
+ +

Wir verarbeiten personenbezogene Daten unserer Nutzer grundsätzlich nur, +soweit dies zur Bereitstellung einer funktionsfähigen Website sowie +unserer Inhalte und Leistungen erforderlich ist. Die Verarbeitung +personenbezogener Daten unserer Nutzer erfolgt regelmäßig nur nach +Einwilligung des Nutzers. Eine Ausnahme gilt in solchen Fällen, +in denen eine vorherige Einholung einer Einwilligung aus tatsächlichen +Gründen nicht möglich ist und die Verarbeitung der Daten durch +gesetzliche Vorschriften gestattet ist.

+ +
Rechtsgrundlage für die Verarbeitung personenbezogener Daten
+ + + +
Datenlöschung und Speicherdauer
+ +

Die personenbezogenen Daten der betroffenen Person werden gelöscht +oder gesperrt, sobald der Zweck der Speicherung entfällt. +Eine Speicherung kann darüber hinaus erfolgen, wenn dies durch den +europäischen oder nationalen Gesetzgeber in unionsrechtlichen Verordnungen, +Gesetzen oder sonstigen Vorschriften, denen der Verantwortliche unterliegt, +vorgesehen wurde. Eine Löschung oder Sperrung der Daten erfolgt auch dann, +wenn eine durch die genannten Normen vorgeschriebene Speicherfrist abläuft, +es sei denn, dass eine Erforderlichkeit zur weiteren Speicherung der Daten +für einen Vertragsabschluss oder eine Vertragserfüllung besteht.

+ +
+ +

Bereitstellung der Website und Erstellung von Logfiles

+ +

Bei jedem Aufruf unserer Internetseite erfasst unser System automatisiert +Daten und Informationen des aufrufenden Rechners. +Folgende Daten werden hierbei erhoben:

+ +
    +
  1. Informationen über den Browsertyp und die verwendete Version.
  2. +
  3. Das Betriebssystem des Nutzers.
  4. +
  5. Den Internet-Service-Provider des Nutzers.
  6. +
  7. Die IP-Adresse des Nutzers.
  8. +
  9. Datum und Uhrzeit des Zugriffs.
  10. +
  11. Websites, von denen das System des Nutzers auf unsere Internetseite gelangt.
  12. +
  13. Websites, die vom System des Nutzers über unsere Website aufgerufen werden.
  14. +
+ +

Die Daten werden ebenfalls in den Logfiles unseres Systems gespeichert. +Eine Speicherung dieser Daten zusammen mit anderen personenbezogenen Daten +des Nutzers findet nicht statt.

+ +

Die vorübergehende Speicherung der IP-Adresse durch das System ist +notwendig, um eine Auslieferung der Website an den Rechner des Nutzers zu +ermöglichen. Hierfür muss die IP-Adresse des Nutzers für die Dauer der +Sitzung gespeichert bleiben.

+ +

Die Speicherung in Logfiles erfolgt, um die Funktionsfähigkeit der Website +sicherzustellen. Zudem dienen uns die Daten zur Optimierung der Website und +zur Sicherstellung der Sicherheit unserer informationstechnischen Systeme. +Eine Auswertung der Daten zu Marketingzwecken findet in diesem Zusammenhang +nicht statt.

+ +

Rechtsgrundlage für die vorübergehende Speicherung der Daten und der +Logfiles ist Art. 6 Abs. 1 lit. f DSGVO. +Unsere berechtigten Interessen liegen in den oben genannten Zwecken.

+ +

Die Daten werden gelöscht, sobald sie für die Erreichung des Zweckes +ihrer Erhebung nicht mehr erforderlich sind:

+ + + +

Die Erfassung der Daten zur Bereitstellung der Website und die Speicherung +der Daten in Logfiles ist für den Betrieb der Website zwingend erforderlich. +Es besteht folglich seitens des Nutzers keine Widerspruchsmöglichkeit.

+ +
+ +

Cookies

+ +

Unsere Website verwendet Cookies. Bei Cookies handelt es sich +um Textdateien, die im Browser bzw. vom Browser +auf dem Computersystem des Nutzers gespeichert werden. +Ruft ein Nutzer eine Website auf, so kann ein Cookie auf dem +System des Nutzers gespeichert werden. +Dieser Cookie kann eine charakteristische Zeichenfolge enthalten, +die eine eindeutige Identifizierung des Browsers beim +erneuten Aufrufen der Website ermöglicht.

+ +

Wir setzen Cookies ein, um unsere Website nutzerfreundlicher zu +gestalten. Einige Elemente unserer Internetseite erfordern es, +dass der aufrufende Browser auch nach einem Seitenwechsel +identifiziert werden kann.

+ +

In den Cookies werden dabei folgende Daten gespeichert und übermittelt:

+ + +

Der Zweck der Verwendung technisch notwendiger Cookies ist, +die Nutzung von Websites für die Nutzer zu vereinfachen. +Einige Funktionen unserer Internetseite können ohne den Einsatz +von Cookies nicht angeboten werden. Für diese ist es erforderlich, +dass der Browser auch nach einem Seitenwechsel wiedererkannt wird.

+ +

Für folgende Anwendungen benötigen wir Cookies:

+ + +

Die durch technisch notwendige Cookies erhobenen Nutzerdaten werden +nicht zur Erstellung von Nutzerprofilen verwendet.

+ +

Die Rechtsgrundlage für die Verarbeitung personenbezogener Daten +unter Verwendung von Cookies ist Art. 6 Abs. 1 lit. f DSGVO. +Unsere berechtigten Interessen liegen in den oben genannten Zwecken.

+ +

Cookies werden auf dem Rechner des Nutzers gespeichert und von diesem +übermittelt. Daher haben Sie als Nutzer auch die volle +Kontrolle über die Verwendung von Cookies. Durch eine Änderung der +Einstellungen in Ihrem Browser können Sie die Übertragung von +Cookies deaktivieren oder einschränken. Bereits gespeicherte Cookies +können jederzeit gelöscht werden. Dies kann auch automatisiert erfolgen. +Bitte konsultieren Sie die Dokumentation Ihres Browsers. +Links zu den Cookie-Management-Dokumentationen einiger gängiger Browser:

+ + +

Werden Cookies für unsere Website deaktiviert, können möglicherweise +nicht mehr alle Funktionen der Website vollumfänglich genutzt werden.

+ +
+ +

Werbung

+ +

Wir greifen auf Drittanbieter (Google) zurück, um Anzeigen zu schalten, +wenn Sie unsere Website besuchen. Diese Unternehmen nutzen möglicherweise +Informationen (dies schließt nicht Ihren Namen, Ihre Adresse, +E-Mail-Adresse oder Telefonnummer ein) zu Ihren Besuchen dieser und anderer +Websites, damit Anzeigen zu Produkten und Diensten geschaltet werden +können, die Sie interessieren. +Weitere Informationen über die Methoden und darüber, welche Möglichkeiten +Sie haben, damit diese Informationen nicht von den Drittanbietern +verwendet werden können, finden Sie hier:

+ + +

Im Europäischen Wirtschaftsraum und in Kalifornien +wird auf unserer Website nur nicht-personalisierte Werbung angezeigt.

+ +

Beim Aufruf einer Seite unserer Website kontaktiert Ihr Browser +die Server des Drittanbieters; hierbei erfährt der Drittanbieter unter anderem +Ihre IP-Adresse, den Browsertyp und die Adresse (URL) der aufgerufenen Seite.

+ +

Die Rechtsgrundlage ist Art. 6 Abs. 1 lit. f DSGVO; +unsere Website wird durch die Werbung finanziert.

+ +
+ +

Kontaktformular und E-Mail-Kontakt

+ +

Auf unserer Internetseite ist ein Kontaktformular vorhanden, +welches für die elektronische Kontaktaufnahme genutzt werden kann. +Nimmt ein Nutzer diese Möglichkeit wahr, so werden die in der +Eingabemaske eingegebenen Daten an uns übermittelt und gespeichert. +Zum Zeitpunkt der Absendung der Nachricht werden zudem das aktuelle +Datum und die aktuelle Uhrzeit gespeichert.

+ +

Alternativ ist eine Kontaktaufnahme über die bereitgestellte +E-Mail-Adresse möglich. In diesem Fall werden die mit der E-Mail +übermittelten personenbezogenen Daten des Nutzers gespeichert.

+ +

Es erfolgt in diesem Zusammenhang keine Weitergabe der Daten an Dritte.

+ +

Die Daten dienen allein zur Bearbeitung der Kontaktaufnahme bzw. +Konversation.

+ +

Die Rechtsgrundlage für die Verarbeitung der Daten ist +Art. 6 Abs. 1 lit. f DSGVO. +Unsere berechtigten Interessen liegen in den oben genannten Zwecken. +Zielt der Kontakt auf den Abschluss eines Vertrages ab, so ist +Art. 6 Abs. 1 lit. b DSGVO eine zusätzliche Rechtsgrundlage.

+ +

Falls eine gesetzliche Archivierungspflicht gilt, werden die Daten +für die vorgeschriebene Dauer gespeichert. +Anderenfalls werden die Daten gelöscht, sobald sie für die Erreichung der Zwecke +ihrer Erhebung nicht mehr erforderlich sind. Für die personenbezogenen Daten, +die per Kontaktformular oder E-Mail übersandt wurden, ist dies dann der Fall, +wenn die jeweilige Konversation mit dem Nutzer beendet ist. +Beendet ist die Konversation dann, wenn sich aus den Umständen entnehmen +lässt, dass der betroffene Sachverhalt abschließend geklärt ist.

+ +

Sie haben jederzeit die Möglichkeit, der Speicherung Ihrer +personenbezogenen Daten zu widersprechen. +Senden Sie dazu eine entsprechende E-Mail an den Verantwortlichen. +In diesem Fall werden alle Daten, die im Zuge der Kontaktaufnahme bzw. +Konversation gespeichert wurden, unverzüglich gelöscht, und +die Konversation kann nicht fortgeführt werden.

+ +
+ +

Rechte der betroffenen Person

+ +

Werden personenbezogene Daten von Ihnen verarbeitet, sind Sie Betroffener +im Sinne der DSGVO und es stehen Ihnen die folgenden Rechte zu.

+ +
Auskunftsrecht
+ +

Sie können von dem Verantwortlichen eine Bestätigung darüber verlangen, +ob personenbezogene Daten, die Sie betreffen, von uns verarbeitet werden.

+ +

Liegt eine solche Verarbeitung vor, können Sie von dem Verantwortlichen +über folgende Informationen Auskunft verlangen:

+
    +
  1. die Verarbeitungszwecke;
  2. +
  3. die Kategorien von personenbezogenen Daten, welche verarbeitet werden;
  4. +
  5. die Empfänger bzw. die Kategorien von Empfängern, gegenüber denen die Sie +betreffenden personenbezogenen Daten offengelegt wurden oder noch offengelegt werden;
  6. +
  7. die geplante Dauer der Speicherung der Sie betreffenden personenbezogenen Daten +oder, falls konkrete Angaben hierzu nicht möglich sind, Kriterien für die +Festlegung der Speicherdauer;
  8. +
  9. das Bestehen eines Rechts auf Berichtigung oder Löschung der Sie +betreffenden personenbezogenen Daten, eines Rechts auf Einschränkung der +Verarbeitung durch den Verantwortlichen oder eines Widerspruchsrechts +gegen diese Verarbeitung;
  10. +
  11. das Bestehen eines Beschwerderechts bei einer Aufsichtsbehörde;
  12. +
  13. alle verfügbaren Informationen über die Herkunft der Daten, wenn die +personenbezogenen Daten nicht bei der betroffenen Person erhoben werden;
  14. +
  15. das Bestehen einer automatisierten Entscheidungsfindung einschließlich +Profiling gemäß Art. 22 Abs. 1 und 4 DSGVO und – zumindest in diesen Fällen – +aussagekräftige Informationen über die involvierte Logik sowie die Tragweite +und die angestrebten Auswirkungen einer derartigen Verarbeitung für die +betroffene Person.
  16. +
+ +

Ihnen steht das Recht zu, Auskunft darüber zu verlangen, ob die Sie +betreffenden personenbezogenen Daten in ein Drittland oder an eine +internationale Organisation übermittelt werden. In diesem Zusammenhang können +Sie verlangen, gemäß Art. 46 DSGVO über die geeigneten Garantien im Zusammenhang +mit der Übermittlung unterrichtet zu werden.

+ +
Recht auf Berichtigung
+ +

Sie haben das Recht auf Berichtigung und/oder Vervollständigung, +sofern die verarbeiteten personenbezogenen Daten, die Sie betreffen, +unrichtig oder unvollständig sind. +Der Verantwortliche hat die Berichtigung unverzüglich vorzunehmen.

+ +
Recht auf Einschränkung der Verarbeitung
+ +

Unter den folgenden Voraussetzungen können Sie die Einschränkung der +Verarbeitung der Sie betreffenden personenbezogenen Daten verlangen:

+ +
    +
  1. wenn Sie die Richtigkeit der Sie betreffenden personenbezogenen Daten für +eine Dauer bestreiten, die es dem Verantwortlichen ermöglicht, die Richtigkeit +der personenbezogenen Daten zu überprüfen;
  2. +
  3. die Verarbeitung unrechtmäßig ist und Sie die Löschung der +personenbezogenen Daten ablehnen und stattdessen die Einschränkung der +Nutzung der personenbezogenen Daten verlangen;
  4. +
  5. der Verantwortliche die personenbezogenen Daten für die Zwecke der +Verarbeitung nicht länger benötigt, Sie diese jedoch zur Geltendmachung, +Ausübung oder Verteidigung von Rechtsansprüchen benötigen;
  6. +
  7. wenn Sie Widerspruch gegen die Verarbeitung gemäß Art. 21 Abs. 1 DSGVO +eingelegt haben und noch nicht feststeht, ob die berechtigten Gründe des +Verantwortlichen gegenüber Ihren Gründen überwiegen.
  8. +
+ +

Wurde die Verarbeitung der Sie betreffenden personenbezogenen Daten +eingeschränkt, dürfen diese Daten – von ihrer Speicherung abgesehen – nur +mit Ihrer Einwilligung oder zur Geltendmachung, Ausübung oder Verteidigung +von Rechtsansprüchen oder zum Schutz der Rechte einer anderen natürlichen +oder juristischen Person oder aus Gründen eines wichtigen öffentlichen +Interesses der Union oder eines Mitgliedstaats verarbeitet werden.

+ +

Wurde die Verarbeitung nach den o.g. Voraussetzungen eingeschränkt, +werden Sie von dem Verantwortlichen unterrichtet bevor die +Einschränkung aufgehoben wird.

+ +
Recht auf Löschung
+ +

Löschungspflicht. +Sie können von dem Verantwortlichen verlangen, dass die Sie betreffenden +personenbezogenen Daten unverzüglich gelöscht werden. +Der Verantwortliche ist verpflichtet, diese Daten unverzüglich zu löschen, +sofern einer der folgenden Gründe zutrifft:

+
    +
  1. Die Sie betreffenden personenbezogenen Daten sind für die Zwecke, für +die sie erhoben oder auf sonstige Weise verarbeitet wurden, nicht mehr notwendig.
  2. +
  3. Sie widerrufen Ihre Einwilligung, auf die sich die Verarbeitung (gemäß +Art. 6 Abs. 1 lit. a oder Art. 9 Abs. 2 lit. a DSGVO) stützte, und es fehlt +an einer anderweitigen Rechtsgrundlage für die Verarbeitung.
  4. +
  5. Sie legen gemäß Art. 21 Abs. 1 DSGVO Widerspruch gegen die Verarbeitung +ein und es liegen keine vorrangigen berechtigten Gründe für die Verarbeitung vor, +oder Sie legen gemäß Art. 21 Abs. 2 DSGVO Widerspruch gegen die Verarbeitung ein.
  6. +
  7. Die Sie betreffenden personenbezogenen Daten wurden unrechtmäßig verarbeitet.
  8. +
  9. Die Löschung der Sie betreffenden personenbezogenen Daten ist zur Erfüllung +einer rechtlichen Verpflichtung nach dem Unionsrecht oder dem Recht der +Mitgliedstaaten erforderlich, dem der Verantwortliche unterliegt.
  10. +
  11. Die Sie betreffenden personenbezogenen Daten wurden in Bezug auf angebotene +Dienste der Informationsgesellschaft gemäß Art. 8 Abs. 1 DSGVO erhoben.
  12. +
+ +

Information an Dritte. +Hat der Verantwortliche die Sie betreffenden personenbezogenen Daten +öffentlich gemacht und ist er gemäß Art. 17 Abs. 1 DSGVO zu deren Löschung +verpflichtet, so trifft er unter Berücksichtigung der verfügbaren Technologie +und der Implementierungskosten angemessene Maßnahmen, auch technischer Art, +um für die Datenverarbeitung Verantwortliche, die die personenbezogenen Daten +verarbeiten, darüber zu informieren, dass Sie als betroffene Person von ihnen +die Löschung aller Links zu diesen personenbezogenen Daten oder von Kopien +oder Replikationen dieser personenbezogenen Daten verlangt haben.

+ +

Ausnahmen. +Das Recht auf Löschung besteht nicht, soweit die Verarbeitung erforderlich ist

+
    +
  1. zur Ausübung des Rechts auf freie Meinungsäußerung und Information;
  2. +
  3. zur Erfüllung einer rechtlichen Verpflichtung, die die Verarbeitung +nach dem Recht der Union oder der Mitgliedstaaten, dem der Verantwortliche +unterliegt, erfordert, oder zur Wahrnehmung einer Aufgabe, die im öffentlichen +Interesse liegt oder in Ausübung öffentlicher Gewalt erfolgt, die dem +Verantwortlichen übertragen wurde;
  4. +
  5. aus Gründen des öffentlichen Interesses im Bereich der öffentlichen +Gesundheit gemäß Art. 9 Abs. 2 lit. h und i sowie Art. 9 Abs. 3 DSGVO;
  6. +
  7. für im öffentlichen Interesse liegende Archivzwecke, wissenschaftliche +oder historische Forschungszwecke oder für statistische Zwecke gemäß +Art. 89 Abs. 1 DSGVO, soweit das unter Art. 17 Abs. 1 DSGVO genannte Recht +voraussichtlich die Verwirklichung der Ziele dieser Verarbeitung unmöglich +macht oder ernsthaft beeinträchtigt;
  8. +
  9. zur Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen.
  10. +
+ +
Recht auf Unterrichtung
+ +

Haben Sie das Recht auf Berichtigung, Löschung oder Einschränkung der +Verarbeitung gegenüber dem Verantwortlichen geltend gemacht, ist dieser +verpflichtet, allen Empfängern, denen die Sie betreffenden personenbezogenen +Daten offengelegt wurden, diese Berichtigung oder Löschung der Daten oder +Einschränkung der Verarbeitung mitzuteilen, es sei denn, dies erweist sich +als unmöglich oder ist mit einem unverhältnismäßigen Aufwand verbunden.

+ +

Ihnen steht gegenüber dem Verantwortlichen das Recht zu, über diese +Empfänger unterrichtet zu werden.

+ +
Recht auf Datenübertragbarkeit
+ +

Sie haben das Recht, die Sie betreffenden personenbezogenen Daten, +die Sie dem Verantwortlichen bereitgestellt haben, in einem strukturierten, +gängigen und maschinenlesbaren Format zu erhalten. Außerdem haben Sie das +Recht diese Daten einem anderen Verantwortlichen ohne Behinderung durch den +Verantwortlichen, dem die personenbezogenen Daten bereitgestellt wurden, +zu übermitteln, sofern

+
    +
  1. die Verarbeitung auf einer Einwilligung gemäß Art. 6 Abs. 1 lit. a DSGVO +oder Art. 9 Abs. 2 lit. a DSGVO oder auf einem Vertrag gemäß +Art. 6 Abs. 1 lit. b DSGVO beruht und
  2. +
  3. die Verarbeitung mithilfe automatisierter Verfahren erfolgt.
  4. +
+ +

In Ausübung dieses Rechts haben Sie ferner das Recht, zu erwirken, +dass die Sie betreffenden personenbezogenen Daten direkt von einem +Verantwortlichen einem anderen Verantwortlichen übermittelt werden, +soweit dies technisch machbar ist. Freiheiten und Rechte anderer Personen +dürfen hierdurch nicht beeinträchtigt werden.

+ +

Das Recht auf Datenübertragbarkeit gilt nicht für eine Verarbeitung +personenbezogener Daten, die für die Wahrnehmung einer Aufgabe erforderlich +ist, die im öffentlichen Interesse liegt oder in Ausübung öffentlicher +Gewalt erfolgt, die dem Verantwortlichen übertragen wurde.

+ +
Widerspruchsrecht
+ +

Sie haben das Recht, aus Gründen, die sich aus Ihrer besonderen +Situation ergeben, jederzeit gegen die Verarbeitung der Sie betreffenden +personenbezogenen Daten, die aufgrund von Art. 6 Abs. 1 lit. e oder f DSGVO +erfolgt, Widerspruch einzulegen; dies gilt auch für ein auf diese +Bestimmungen gestütztes Profiling.

+ +

Der Verantwortliche verarbeitet die Sie betreffenden personenbezogenen Daten +nicht mehr, es sei denn, er kann zwingende schutzwürdige Gründe für die +Verarbeitung nachweisen, die Ihre Interessen, Rechte und Freiheiten +überwiegen, oder die Verarbeitung dient der Geltendmachung, Ausübung oder +Verteidigung von Rechtsansprüchen.

+ +

Werden die Sie betreffenden personenbezogenen Daten verarbeitet, +um Direktwerbung zu betreiben, haben Sie das Recht, jederzeit Widerspruch +gegen die Verarbeitung der Sie betreffenden personenbezogenen Daten zum +Zwecke derartiger Werbung einzulegen; dies gilt auch für das Profiling, +soweit es mit solcher Direktwerbung in Verbindung steht.

+ +

Widersprechen Sie der Verarbeitung für Zwecke der Direktwerbung, +so werden die Sie betreffenden personenbezogenen Daten nicht mehr für diese +Zwecke verarbeitet.

+ +

Sie haben die Möglichkeit, im Zusammenhang mit der Nutzung von +Diensten der Informationsgesellschaft – ungeachtet der Richtlinie +2002/58/EG – Ihr Widerspruchsrecht mittels automatisierter Verfahren +auszuüben, bei denen technische Spezifikationen verwendet werden.

+ +
Recht auf Widerruf der datenschutzrechtlichen Einwilligungserklärung
+ +

Sie haben das Recht, Ihre datenschutzrechtliche Einwilligungserklärung +jederzeit zu widerrufen. Durch den Widerruf der Einwilligung wird die +Rechtmäßigkeit der aufgrund der Einwilligung bis zum Widerruf erfolgten +Verarbeitung nicht berührt.

+ +
Automatisierte Entscheidung im Einzelfall einschließlich Profiling
+ +

Sie haben das Recht, nicht einer ausschließlich auf einer +automatisierten Verarbeitung – einschließlich Profiling – beruhenden +Entscheidung unterworfen zu werden, die Ihnen gegenüber rechtliche Wirkung +entfaltet oder Sie in ähnlicher Weise erheblich beeinträchtigt. +Dies gilt nicht, wenn die Entscheidung

+
    +
  1. für den Abschluss oder die Erfüllung eines Vertrags zwischen Ihnen +und dem Verantwortlichen erforderlich ist;
  2. +
  3. aufgrund von Rechtsvorschriften der Union oder der Mitgliedstaaten, +denen der Verantwortliche unterliegt, zulässig ist und diese Rechtsvorschriften +angemessene Maßnahmen zur Wahrung Ihrer Rechte und Freiheiten sowie Ihrer +berechtigten Interessen enthalten; oder
  4. +
  5. mit Ihrer ausdrücklichen Einwilligung erfolgt.
  6. +
+ +

Allerdings dürfen diese Entscheidungen nicht auf besonderen Kategorien +personenbezogener Daten nach Art. 9 Abs. 1 DSGVO beruhen, +sofern nicht Art. 9 Abs. 2 lit. a oder g DSGVO gilt und angemessene Maßnahmen +zum Schutz der Rechte und Freiheiten sowie Ihrer berechtigten Interessen getroffen wurden.

+ +

Hinsichtlich der in 1. und 3. genannten Fälle trifft der +Verantwortliche angemessene Maßnahmen, um die Rechte und Freiheiten sowie +Ihre berechtigten Interessen zu wahren, wozu mindestens das Recht auf +Erwirkung des Eingreifens einer Person seitens des Verantwortlichen, +auf Darlegung des eigenen Standpunkts und auf Anfechtung der Entscheidung gehört.

+ +
Recht auf Beschwerde bei einer Aufsichtsbehörde
+ +

Unbeschadet eines anderweitigen verwaltungsrechtlichen oder gerichtlichen +Rechtsbehelfs steht Ihnen das Recht auf Beschwerde bei einer Aufsichtsbehörde, +insbesondere in dem Mitgliedstaat ihres Aufenthaltsorts, ihres Arbeitsplatzes +oder des Orts des mutmaßlichen Verstoßes, zu, wenn Sie der Ansicht sind, +dass die Verarbeitung der Sie betreffenden personenbezogenen Daten gegen +die DSGVO verstößt.

+ +

Die Aufsichtsbehörde, bei der die Beschwerde eingereicht wurde, unterrichtet +den Beschwerdeführer über den Stand und die Ergebnisse der Beschwerde +einschließlich der Möglichkeit eines gerichtlichen Rechtsbehelfs nach Art. 78 DSGVO.

+ +
+ + + +

KeePass-Lizenz

+ +

Die Bestimmungen, unter denen KeePass vertrieben wird, sind auf den +folgenden Seiten zu finden: +KeePass 1.x Lizenz, +KeePass 2.x Lizenz.

+ +

Siehe auch die Danksagungen-Seite +(enthält Lizenzen von Dritten).

+ +
+ + + +

Rechtswirksamkeit dieser Bestimmungen

+ +

Diese rechtlichen Bestimmungen sind als Teil des Internetangebotes +zu betrachten, von dem aus auf diese Seite verwiesen wurde. +Sofern Teile oder einzelne Formulierungen dieses Textes der +geltenden Rechtslage nicht, nicht mehr oder nicht vollständig +entsprechen sollten, bleiben die übrigen Teile des Dokumentes +in ihrem Inhalt und ihrer Gültigkeit davon unberührt.

+ + + diff --git a/src/Docs/Chm/help/base/usingpws.html b/src/Docs/Chm/help/base/usingpws.html new file mode 100644 index 0000000..a8afec5 --- /dev/null +++ b/src/Docs/Chm/help/base/usingpws.html @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Using Stored Passwords - KeePass + + + + + + + + + + + + +

Using Stored Passwords

+

How to transfer passwords stored in KeePass to other applications.

+ +

There are many different methods to transfer passwords stored in KeePass +to other applications:

+ + + +
+ + +

+Main Entry List

+ +

Depending on which field you double-click in the entry list of the main window, +different actions are performed:

+ + + +
+ + +

+Drag&Drop

+ +

You can drag&drop all fields of KeePass entries into other windows:

+ +
+Drag&Drop +
+ +

+ + +

+Auto-Type

+ +

Auto-Type is a powerful feature that sends simulated keypresses to +other applications.

+ +

You can find more details about it here: +Auto-Type documentation page.

+ +
+ + +

+Plugins

+ +

There are a lot of plugins available that integrate KeePass with +other applications.

+ +

You can find these integration plugins on the +plugins page.

+ + + diff --git a/src/Docs/Chm/help/images/appicons.png b/src/Docs/Chm/help/images/appicons.png new file mode 100644 index 0000000..14c8c13 Binary files /dev/null and b/src/Docs/Chm/help/images/appicons.png differ diff --git a/src/Docs/Chm/help/images/b16x16_ascii.png b/src/Docs/Chm/help/images/b16x16_ascii.png new file mode 100644 index 0000000..7462fa2 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_ascii.png differ diff --git a/src/Docs/Chm/help/images/b16x16_binary.png b/src/Docs/Chm/help/images/b16x16_binary.png new file mode 100644 index 0000000..3f4def6 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_binary.png differ diff --git a/src/Docs/Chm/help/images/b16x16_blockdevice.png b/src/Docs/Chm/help/images/b16x16_blockdevice.png new file mode 100644 index 0000000..18e10cd Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_blockdevice.png differ diff --git a/src/Docs/Chm/help/images/b16x16_cancel.png b/src/Docs/Chm/help/images/b16x16_cancel.png new file mode 100644 index 0000000..a432b49 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_cancel.png differ diff --git a/src/Docs/Chm/help/images/b16x16_chardevice.png b/src/Docs/Chm/help/images/b16x16_chardevice.png new file mode 100644 index 0000000..96c49df Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_chardevice.png differ diff --git a/src/Docs/Chm/help/images/b16x16_dataexchange.png b/src/Docs/Chm/help/images/b16x16_dataexchange.png new file mode 100644 index 0000000..f107b12 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_dataexchange.png differ diff --git a/src/Docs/Chm/help/images/b16x16_desktop.png b/src/Docs/Chm/help/images/b16x16_desktop.png new file mode 100644 index 0000000..291f8a4 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_desktop.png differ diff --git a/src/Docs/Chm/help/images/b16x16_donate.png b/src/Docs/Chm/help/images/b16x16_donate.png new file mode 100644 index 0000000..9c7b46f Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_donate.png differ diff --git a/src/Docs/Chm/help/images/b16x16_enhanced_browsing.png b/src/Docs/Chm/help/images/b16x16_enhanced_browsing.png new file mode 100644 index 0000000..c6c9ec3 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_enhanced_browsing.png differ diff --git a/src/Docs/Chm/help/images/b16x16_file_locked.png b/src/Docs/Chm/help/images/b16x16_file_locked.png new file mode 100644 index 0000000..cab5794 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_file_locked.png differ diff --git a/src/Docs/Chm/help/images/b16x16_filesaveas.png b/src/Docs/Chm/help/images/b16x16_filesaveas.png new file mode 100644 index 0000000..71602bc Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_filesaveas.png differ diff --git a/src/Docs/Chm/help/images/b16x16_help.png b/src/Docs/Chm/help/images/b16x16_help.png new file mode 100644 index 0000000..d7f0f85 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_help.png differ diff --git a/src/Docs/Chm/help/images/b16x16_history.png b/src/Docs/Chm/help/images/b16x16_history.png new file mode 100644 index 0000000..8d658e0 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_history.png differ diff --git a/src/Docs/Chm/help/images/b16x16_kblackbox.png b/src/Docs/Chm/help/images/b16x16_kblackbox.png new file mode 100644 index 0000000..257b205 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_kblackbox.png differ diff --git a/src/Docs/Chm/help/images/b16x16_kcmdrkonqi.png b/src/Docs/Chm/help/images/b16x16_kcmdrkonqi.png new file mode 100644 index 0000000..f5fd2ca Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_kcmdrkonqi.png differ diff --git a/src/Docs/Chm/help/images/b16x16_kcmsystem.png b/src/Docs/Chm/help/images/b16x16_kcmsystem.png new file mode 100644 index 0000000..ecce34d Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_kcmsystem.png differ diff --git a/src/Docs/Chm/help/images/b16x16_kdmconfig.png b/src/Docs/Chm/help/images/b16x16_kdmconfig.png new file mode 100644 index 0000000..7ad2e0c Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_kdmconfig.png differ diff --git a/src/Docs/Chm/help/images/b16x16_keyboard_layout.png b/src/Docs/Chm/help/images/b16x16_keyboard_layout.png new file mode 100644 index 0000000..01d751b Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_keyboard_layout.png differ diff --git a/src/Docs/Chm/help/images/b16x16_kgpg.png b/src/Docs/Chm/help/images/b16x16_kgpg.png new file mode 100644 index 0000000..79b708b Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_kgpg.png differ diff --git a/src/Docs/Chm/help/images/b16x16_kgpg_key3.png b/src/Docs/Chm/help/images/b16x16_kgpg_key3.png new file mode 100644 index 0000000..e68afac Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_kgpg_key3.png differ diff --git a/src/Docs/Chm/help/images/b16x16_kmultiple.png b/src/Docs/Chm/help/images/b16x16_kmultiple.png new file mode 100644 index 0000000..20e9da7 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_kmultiple.png differ diff --git a/src/Docs/Chm/help/images/b16x16_konsole.png b/src/Docs/Chm/help/images/b16x16_konsole.png new file mode 100644 index 0000000..8607208 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_konsole.png differ diff --git a/src/Docs/Chm/help/images/b16x16_ktouch.png b/src/Docs/Chm/help/images/b16x16_ktouch.png new file mode 100644 index 0000000..21ca8b0 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_ktouch.png differ diff --git a/src/Docs/Chm/help/images/b16x16_make_kdevelop.png b/src/Docs/Chm/help/images/b16x16_make_kdevelop.png new file mode 100644 index 0000000..4db9743 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_make_kdevelop.png differ diff --git a/src/Docs/Chm/help/images/b16x16_message.png b/src/Docs/Chm/help/images/b16x16_message.png new file mode 100644 index 0000000..ae1ce24 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_message.png differ diff --git a/src/Docs/Chm/help/images/b16x16_ok.png b/src/Docs/Chm/help/images/b16x16_ok.png new file mode 100644 index 0000000..5b0f6a6 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_ok.png differ diff --git a/src/Docs/Chm/help/images/b16x16_openterm.png b/src/Docs/Chm/help/images/b16x16_openterm.png new file mode 100644 index 0000000..9715fea Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_openterm.png differ diff --git a/src/Docs/Chm/help/images/b16x16_package_system.png b/src/Docs/Chm/help/images/b16x16_package_system.png new file mode 100644 index 0000000..7a750b9 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_package_system.png differ diff --git a/src/Docs/Chm/help/images/b16x16_password.png b/src/Docs/Chm/help/images/b16x16_password.png new file mode 100644 index 0000000..5656824 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_password.png differ diff --git a/src/Docs/Chm/help/images/b16x16_rotate_cw.png b/src/Docs/Chm/help/images/b16x16_rotate_cw.png new file mode 100644 index 0000000..4753c10 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_rotate_cw.png differ diff --git a/src/Docs/Chm/help/images/b16x16_server.png b/src/Docs/Chm/help/images/b16x16_server.png new file mode 100644 index 0000000..bb8a316 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_server.png differ diff --git a/src/Docs/Chm/help/images/b16x16_tar.png b/src/Docs/Chm/help/images/b16x16_tar.png new file mode 100644 index 0000000..184f959 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_tar.png differ diff --git a/src/Docs/Chm/help/images/b16x16_usbpendrive_unmount.png b/src/Docs/Chm/help/images/b16x16_usbpendrive_unmount.png new file mode 100644 index 0000000..eaafc2b Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_usbpendrive_unmount.png differ diff --git a/src/Docs/Chm/help/images/b16x16_vcard.png b/src/Docs/Chm/help/images/b16x16_vcard.png new file mode 100644 index 0000000..f6905dd Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_vcard.png differ diff --git a/src/Docs/Chm/help/images/b16x16_warning.png b/src/Docs/Chm/help/images/b16x16_warning.png new file mode 100644 index 0000000..474f63f Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_warning.png differ diff --git a/src/Docs/Chm/help/images/b16x16_window_list.png b/src/Docs/Chm/help/images/b16x16_window_list.png new file mode 100644 index 0000000..085baff Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_window_list.png differ diff --git a/src/Docs/Chm/help/images/b16x16_xmag.png b/src/Docs/Chm/help/images/b16x16_xmag.png new file mode 100644 index 0000000..d4e71b5 Binary files /dev/null and b/src/Docs/Chm/help/images/b16x16_xmag.png differ diff --git a/src/Docs/Chm/help/images/b64x64_binary.png b/src/Docs/Chm/help/images/b64x64_binary.png new file mode 100644 index 0000000..005d8c0 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_binary.png differ diff --git a/src/Docs/Chm/help/images/b64x64_blockdevice.png b/src/Docs/Chm/help/images/b64x64_blockdevice.png new file mode 100644 index 0000000..f1aee77 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_blockdevice.png differ diff --git a/src/Docs/Chm/help/images/b64x64_chardevice.png b/src/Docs/Chm/help/images/b64x64_chardevice.png new file mode 100644 index 0000000..078f4cd Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_chardevice.png differ diff --git a/src/Docs/Chm/help/images/b64x64_dataexchange.png b/src/Docs/Chm/help/images/b64x64_dataexchange.png new file mode 100644 index 0000000..7238a4f Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_dataexchange.png differ diff --git a/src/Docs/Chm/help/images/b64x64_desktop.png b/src/Docs/Chm/help/images/b64x64_desktop.png new file mode 100644 index 0000000..fd2b4a7 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_desktop.png differ diff --git a/src/Docs/Chm/help/images/b64x64_doc.png b/src/Docs/Chm/help/images/b64x64_doc.png new file mode 100644 index 0000000..04c6547 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_doc.png differ diff --git a/src/Docs/Chm/help/images/b64x64_enhanced_browsing.png b/src/Docs/Chm/help/images/b64x64_enhanced_browsing.png new file mode 100644 index 0000000..91d9c62 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_enhanced_browsing.png differ diff --git a/src/Docs/Chm/help/images/b64x64_file_locked.png b/src/Docs/Chm/help/images/b64x64_file_locked.png new file mode 100644 index 0000000..2c3faec Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_file_locked.png differ diff --git a/src/Docs/Chm/help/images/b64x64_help.png b/src/Docs/Chm/help/images/b64x64_help.png new file mode 100644 index 0000000..7a6ee42 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_help.png differ diff --git a/src/Docs/Chm/help/images/b64x64_kcmdrkonqi.png b/src/Docs/Chm/help/images/b64x64_kcmdrkonqi.png new file mode 100644 index 0000000..996ddc6 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_kcmdrkonqi.png differ diff --git a/src/Docs/Chm/help/images/b64x64_kcmsystem.png b/src/Docs/Chm/help/images/b64x64_kcmsystem.png new file mode 100644 index 0000000..0dfe40b Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_kcmsystem.png differ diff --git a/src/Docs/Chm/help/images/b64x64_kdmconfig.png b/src/Docs/Chm/help/images/b64x64_kdmconfig.png new file mode 100644 index 0000000..0def963 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_kdmconfig.png differ diff --git a/src/Docs/Chm/help/images/b64x64_keyboard_layout.png b/src/Docs/Chm/help/images/b64x64_keyboard_layout.png new file mode 100644 index 0000000..4120260 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_keyboard_layout.png differ diff --git a/src/Docs/Chm/help/images/b64x64_kgpg.png b/src/Docs/Chm/help/images/b64x64_kgpg.png new file mode 100644 index 0000000..e3e83cd Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_kgpg.png differ diff --git a/src/Docs/Chm/help/images/b64x64_kmultiple.png b/src/Docs/Chm/help/images/b64x64_kmultiple.png new file mode 100644 index 0000000..bd347e0 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_kmultiple.png differ diff --git a/src/Docs/Chm/help/images/b64x64_konsole.png b/src/Docs/Chm/help/images/b64x64_konsole.png new file mode 100644 index 0000000..e7c961e Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_konsole.png differ diff --git a/src/Docs/Chm/help/images/b64x64_ktouch.png b/src/Docs/Chm/help/images/b64x64_ktouch.png new file mode 100644 index 0000000..aaf125c Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_ktouch.png differ diff --git a/src/Docs/Chm/help/images/b64x64_package_system.png b/src/Docs/Chm/help/images/b64x64_package_system.png new file mode 100644 index 0000000..ea8e84f Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_package_system.png differ diff --git a/src/Docs/Chm/help/images/b64x64_usb.png b/src/Docs/Chm/help/images/b64x64_usb.png new file mode 100644 index 0000000..6bdf1da Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_usb.png differ diff --git a/src/Docs/Chm/help/images/b64x64_vcard.png b/src/Docs/Chm/help/images/b64x64_vcard.png new file mode 100644 index 0000000..c3f8a68 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_vcard.png differ diff --git a/src/Docs/Chm/help/images/b64x64_winprops.png b/src/Docs/Chm/help/images/b64x64_winprops.png new file mode 100644 index 0000000..ad7be3b Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_winprops.png differ diff --git a/src/Docs/Chm/help/images/b64x64_xmag.png b/src/Docs/Chm/help/images/b64x64_xmag.png new file mode 100644 index 0000000..9165030 Binary files /dev/null and b/src/Docs/Chm/help/images/b64x64_xmag.png differ diff --git a/src/Docs/Chm/help/images/clienticons.gif b/src/Docs/Chm/help/images/clienticons.gif new file mode 100644 index 0000000..c24d714 Binary files /dev/null and b/src/Docs/Chm/help/images/clienticons.gif differ diff --git a/src/Docs/Chm/help/images/dlgbanner_bluecarbon.png b/src/Docs/Chm/help/images/dlgbanner_bluecarbon.png new file mode 100644 index 0000000..c7420b7 Binary files /dev/null and b/src/Docs/Chm/help/images/dlgbanner_bluecarbon.png differ diff --git a/src/Docs/Chm/help/images/dlgbanner_win32.png b/src/Docs/Chm/help/images/dlgbanner_win32.png new file mode 100644 index 0000000..e940348 Binary files /dev/null and b/src/Docs/Chm/help/images/dlgbanner_win32.png differ diff --git a/src/Docs/Chm/help/images/dlgbanner_winvistablack.png b/src/Docs/Chm/help/images/dlgbanner_winvistablack.png new file mode 100644 index 0000000..2021897 Binary files /dev/null and b/src/Docs/Chm/help/images/dlgbanner_winvistablack.png differ diff --git a/src/Docs/Chm/help/images/dlgbanner_winxplogin.png b/src/Docs/Chm/help/images/dlgbanner_winxplogin.png new file mode 100644 index 0000000..a6199b3 Binary files /dev/null and b/src/Docs/Chm/help/images/dlgbanner_winxplogin.png differ diff --git a/src/Docs/Chm/help/images/dragndrop.png b/src/Docs/Chm/help/images/dragndrop.png new file mode 100644 index 0000000..ed9b19b Binary files /dev/null and b/src/Docs/Chm/help/images/dragndrop.png differ diff --git a/src/Docs/Chm/help/images/flageng_small.gif b/src/Docs/Chm/help/images/flageng_small.gif new file mode 100644 index 0000000..43a5ff6 Binary files /dev/null and b/src/Docs/Chm/help/images/flageng_small.gif differ diff --git a/src/Docs/Chm/help/images/flagger_small.gif b/src/Docs/Chm/help/images/flagger_small.gif new file mode 100644 index 0000000..930c873 Binary files /dev/null and b/src/Docs/Chm/help/images/flagger_small.gif differ diff --git a/src/Docs/Chm/help/images/folder_closed.png b/src/Docs/Chm/help/images/folder_closed.png new file mode 100644 index 0000000..25f7a22 Binary files /dev/null and b/src/Docs/Chm/help/images/folder_closed.png differ diff --git a/src/Docs/Chm/help/images/getkey_dark.png b/src/Docs/Chm/help/images/getkey_dark.png new file mode 100644 index 0000000..0eccaee Binary files /dev/null and b/src/Docs/Chm/help/images/getkey_dark.png differ diff --git a/src/Docs/Chm/help/images/plockb_64.png b/src/Docs/Chm/help/images/plockb_64.png new file mode 100644 index 0000000..b995c6a Binary files /dev/null and b/src/Docs/Chm/help/images/plockb_64.png differ diff --git a/src/Docs/Chm/help/images/pwgen_adv_excltab.png b/src/Docs/Chm/help/images/pwgen_adv_excltab.png new file mode 100644 index 0000000..cc0169f Binary files /dev/null and b/src/Docs/Chm/help/images/pwgen_adv_excltab.png differ diff --git a/src/Docs/Chm/help/images/rtfeditor.png b/src/Docs/Chm/help/images/rtfeditor.png new file mode 100644 index 0000000..ffc01a1 Binary files /dev/null and b/src/Docs/Chm/help/images/rtfeditor.png differ diff --git a/src/Docs/Chm/help/images/rtfeditor_small.png b/src/Docs/Chm/help/images/rtfeditor_small.png new file mode 100644 index 0000000..5bc0429 Binary files /dev/null and b/src/Docs/Chm/help/images/rtfeditor_small.png differ diff --git a/src/Docs/Chm/help/index.html b/src/Docs/Chm/help/index.html new file mode 100644 index 0000000..26655e8 --- /dev/null +++ b/src/Docs/Chm/help/index.html @@ -0,0 +1,15 @@ + + + + + + + + Redirection - KeePass + + + +

Redirecting to +help start page...

+ + diff --git a/src/Docs/Chm/help/v2/autotype_obfuscation.html b/src/Docs/Chm/help/v2/autotype_obfuscation.html new file mode 100644 index 0000000..d066389 --- /dev/null +++ b/src/Docs/Chm/help/v2/autotype_obfuscation.html @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Two-Channel Auto-Type Obfuscation - KeePass + + + + + + + + + + + + + +

Two-Channel Auto-Type Obfuscation

+

Description of the Two-Channel Auto-Type Obfuscation feature in KeePass 2.x.

+ + + +
+ + +

+Introduction: What is Two-Channel Auto-Type Obfuscation?

+ +

The Auto-Type feature of KeePass +is very powerful: it sends simulated keypresses to other applications. +This works with all Windows applications and +for the target applications it's not possible to distinguish between +real keypresses and the ones simulated by Auto-Type. + +This at the same time is the main disadvantage of Auto-Type, because +keyloggers can eavesdrop the simulated keys. + +That's where Two-Channel Auto-Type Obfuscation (TCATO) comes into play.

+ +

TCATO makes standard keyloggers useless. It uses the +Windows clipboard to transfer parts of the auto-typed text into the +target application. Keyloggers can see the Ctrl+V +presses, but do not log the actual contents pasted from the clipboard.

+ +

Clipboard spies don't work either, because only parts of the sensitive +information is transferred on this way.

+ +

Anyway, it's not perfectly secure (and unfortunately cannot be made +by theory). None of the currently available keyloggers or clipboard spies +can eavesdrop an obfuscated auto-type process, but it is theoretically possible +to write a dedicated spy application that specializes on logging obfuscated +auto-type.

+ +
+ + +

+When can Two-Channel Auto-Type Obfuscation be used?

+ +

TCATO cannot be used with all windows. The target window(s) must +support clipboard operations and navigation within edit controls using arrow keys. +Additionally, the target user interface must not contain automation features like +jumping focus when maximum length of a text box is reached (as seen in registration +number dialogs for example).

+ +

Rules of thumb:

+ + + +

Because it doesn't work with all windows, it's an opt-in feature for each +entry. You have to enable it explicitly on the 'Auto-Type' tab page in the +'Edit Entry' dialog.

+ +
+ + +

+How to enable / configure Two-Channel Auto-Type Obfuscation?

+ +

All you need to do is to tick the checkbox "Two-channel auto-type obfuscation" +of an entry ('Auto-Type' tab page of the entry editing window); KeePass will do the rest.

+ +
+ + +

+Technical Overview

+ +

Instead of simply sending simulated keypresses to the target application (as normal +auto-type does), obfuscated auto-type does the following:

+ + + +

These steps are described in detail below.

+ +
+ + + + +

+Intelligently Splitting the Text

+ +

The text to be sent must first be split intelligently. Not all parts of the +string can be sent using the clipboard: special key codes and key modifiers must be passed +unchanged to the SendInput function. For an example, have a look at the following +string:

+ +
mymail@myprovider.com{TAB}MyTopSecretPassword{TAB} {TAB}{ENTER}
+ +

This is an example of a typical string sent by KeePass to another application. First +it types the user's email address, then a Tab, +then the password, a Tab, toggles a checkbox, +another Tab and finally presses the Enter key. +This sequence can be split into the following parts:

+ +
mymail@myprovider.com
+{TAB}
+MyTopSecretPassword
+{TAB}
+' ' (space)
+{TAB}
+{ENTER}
+ +

For each line, it is checked if the clipboard can be used. If the line contains a '{', '}', '(', ')', +'+', '^', '%' or whitespace (space), it can only be sent by the SendInput function +directly. For example, '+' presses the Shift key, +it should not be copy/pasted as '+' character. +Spaces cannot be copy/pasted either, because they are usually used to toggle checkboxes.

+ +

In the example above, "mymail@myprovider.com" and "MyTopSecretPassword" can +be sent using the clipboard.

+ +
+ + +

+Splitting the Secrets

+ +

Let's transfer "mymail@myprovider.com" to the target application using +TCATO.

+ +

First, the secret string "mymail@myprovider.com" is randomly split character-wise +into two parts like two flat intertwining combs:

+ +
 y  il m   o  d  .c
+m ma  @ ypr vi er  om
+ +

The first string "yilmod.c" is now copied to the clipboard. The string to be +sent by the SendInput function is now assembled as follows:

+ + + +

In our example above, the key sequence would be assembled to:

+ +
^v{LEFT 8}m{RIGHT}ma{RIGHT}{RIGHT}@{RIGHT}ypr{RIGHT}vi{RIGHT}er{RIGHT}{RIGHT}om
+ +

This will first paste the clipboard contents, go to its start and fill in the remaining characters, +building up the original string "mymail@myprovider.com".

+ +

The time in which the first string part remains in the clipboard is minimal. +It is copied to the clipboard, pasted into the target application and immediately +cleared. This process usually takes only a few milliseconds at maximum.

+ +

More about secret string splitting:
+In the above example, the string "mymail@myprovider.com" was +split and sent. If the string would be split differently each time, +a malicious application could reassemble the string by +capturing multiple auto-types and combining them. In order to prevent this, +KeePass initializes the random number generator for splitting based on a +hash of the string. This means that each string is split differently, +but the partitions of a string are uniquely determined. So, by invoking +auto-type multiple times, an attacker cannot reassemble the original string, +because he always captures the same half part.

+ + + diff --git a/src/Docs/Chm/help/v2/dbsettings.html b/src/Docs/Chm/help/v2/dbsettings.html new file mode 100644 index 0000000..9fc2d7d --- /dev/null +++ b/src/Docs/Chm/help/v2/dbsettings.html @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Database Settings - KeePass + + + + + + + + + + + + +

Database Settings

+

Describes the various database options.

+ +

On the database settings dialog, you can configure various database-related +settings.

+ + + +
+ + +

+General

+ +

On this tab page you can specify general things like the name of the database and +a description. Additionally, you can set various defaults like a default user +name for new entries (created in this database).

+ +
+ + +

+Security Options

+ +

On this tab page you can specify various settings related to encryption. +Only change these settings if you really know what you are doing.

+ +

Encryption Algorithm:
+You can choose the algorithm that is used to encrypt the database. +All encryption algorithms offered by KeePass are well-known, secure algorithms, +see Database Encryption.

+ +

Key Transformation:
+See Protection against +Dictionary Attacks.

+ +

KeePass has a button on this tab page to compute the number of key transformations +that your computer can do in 1 second. If you for instance only want to wait 0.5 seconds, +half the number resulted from the benchmark.

+ +
+ + + + +

+Compression Options

+ +

KeePass databases can be compressed before being encrypted. Compression +reduces the size of the database, but also slows down the database +saving/loading process a bit.

+ +

It is recommended to use the GZip compression option. This algorithm +is very fast (you won't notice any difference to saving the database without +compression) and its compression rate is acceptable.

+ +

It is not recommended to save databases without compression.

+ +

On modern PCs, saving files with compression can actually be faster than +saving without compression, because the compression process is performed by +the CPU (which is very fast) and fewer data has to be transferred from/to +the storage device. Especially when the device is slow (like saving to USB +stick), compression can reduce the saving/loading time significantly.

+ +
+ + +

+Templates

+ +

Templates are a great way to predefine often used user names or +additional fields, or combinations of each.

+ + + +

First create a normal group in the main window and then set it as the +templates group in 'File' → +'Database Settings' → tab 'Advanced'.

+ +

In order to create a new entry based on a template, +click the drop-down arrow of the 'Add Entry' toolbar button +and choose the template to be used.

+ + + diff --git a/src/Docs/Chm/help/v2/entry.html b/src/Docs/Chm/help/v2/entry.html new file mode 100644 index 0000000..77ba37c --- /dev/null +++ b/src/Docs/Chm/help/v2/entry.html @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Entry Dialog - KeePass + + + + + + + + + + + + + +

Entry Dialog

+

Edit new/existing entries.

+ + + +
+ + +

+General

+ +

On the tab page 'General', you can specify the main information +of an account.

+ +

Title.
+In the title field, the name of the system/service should be entered.

+ +

For certain systems/services, it can make sense to ensure that the +entry title occurs within the target window title, because this allows +auto-type to associate the entry +with the target window. +For details, see global auto-type. +However, if the target window title does not contain the system/service name +(e.g. 'Login - Browser Name'), it is recommended to create a +custom window/sequence association instead.

+ +

User name.
+In the user name field, you should specify the data that you are entering +during a login in order to identify yourself. This typically is a user name, +an e-mail address or a number.

+ +

There is no separate e-mail address field by default, because this +would decrease the usability. For details, see the section +'Can an e-mail address field be added?' +in the FAQ.

+ +

When typing into the user name field, KeePass may display a list of +suggestions for the user name. +This list is generated dynamically: when opening the entry dialog, +KeePass collects the user names of all entries stored in the currently +active database. +If you see an incorrect user name in the list, you need to search this +user name in your entries (using the search function) and fix it there.

+ +

In the database settings (menu 'File' → +'Database Settings'), you can define a default user name for new entries.

+ +

Password.
+By default, KeePass generates a password for a new entry (this can be +customized/disabled). +You can use this password or replace it.

+ +

There is a button (right of the password repetition field) that opens +the password generator.

+ +

Furthermore, there is a button for disabling/enabling the +password quality estimation for the current entry. +Disabling the password quality estimation for an entry also +excludes the entry from password quality reports (menu 'Find' → +'Password Quality').

+ +

URL.
+See the help page 'URL Field'.

+ + +

Expires.
+In the entry list of the main window, an expired entry is displayed +with a red X icon and a +strikeout font. +Expired entries are not deleted/moved automatically.

+ +

You can search for expired entries using the menu 'Find' → +'Expired'. +Expired entries can also be displayed automatically when opening +the database (menu 'Tools' → 'Options' → tab 'Advanced' → +option 'Show expired entries (if any)').

+ +
+ + +

+Advanced

+ + +

Custom string fields.
+Each entry may have an arbitrary number of custom string fields. +Such a field consists of a name and a value. +The name must be unique (within the entry).

+ +

In the main window, the value of a custom string field can be +copied into the clipboard by right-clicking on the entry, pointing +on 'Other Data' and clicking on the name of the custom string field +(this is also possible via the menu 'Entry').

+ +

The value of a custom string field can also be used in an +auto-type sequence; +see the placeholders help page. +For example, the value of a custom string field named 'BIC' +(acronym for Business Identifier Code) can be inserted using the +'{S:BIC}' placeholder.

+ +

In database files, custom string fields are stored in encrypted form +(see 'Database Encryption'). +The option 'Protect value in process memory' (in the custom string field dialog) +allows to activate/deactivate the +process memory protection +for the value of the custom string field. +Activating this protection induces certain limitations (e.g. the value must +be hidden using asterisks for the protection to be effective) and increases +the time required by various operations. Therefore, it should be activated +only for really sensitive data (e.g. a second password).

+ + +

File attachments.
+You can attach arbitrary files to an entry.

+ +

Attached files are stored within the database file in encrypted form +(see 'Database Encryption'). +When importing a file as attachment, KeePass does not delete the +source file; you need to delete it yourself, if desired.

+ +

This feature is intended to store few/small files (e.g. registration files, +public/private key pair files, etc.). +Encrypting many/large files is considered to be out of the scope of a +password manager and it is recommended to use a specialized file encryption +software (e.g. VeraCrypt) for this task instead (KeePass can be used +to store the password for the encrypted file container).

+ +
+ + +

+Properties

+ + +

Tags.
+You can assign arbitrary tags to an entry. +Multiple tags have to be separated by commas (or semicolons). +When clicking the button right of the tags input field, a menu is +displayed that allows to add tags found in other entries.

+ +

Tags can also be added/removed in the main window: right-click onto +one or more entries → 'Edit Entry (Quick)' → 'Add Tag' or +'Remove Tag'.

+ +

A common use case is to mark frequently used entries (tag 'Favorite').

+ +

In order to show all entries that have a specific tag, click the +three-keys button +[3 Keys] +in the toolbar of the main window (to the right of +the 'Find' toolbar button) and choose the tag. +Alternatively, this command is also accessible via the main menu: +'Find' → 'Tag' → choose the tag.

+ +

If you want to see all entries with a specific tag (e.g. 'Favorite') +when opening a database, you can create a trigger +for this: click 'Tools' → 'Triggers', add a new trigger, +enter a name (e.g. 'Show favorites when opening a database'), +add an event 'Opened database file', and add an action +'Show entries by tag' with the parameter 'Tag' set to the tag name +(e.g. 'Favorite').

+ +

Override URL.
+See 'Changing the URL Handler'.

+ + +

UUID.
+A UUID is a 128-bit number that uniquely identifies an object +(an entry in this case).

+ +

In some places (e.g. in field references), +a UUID needs to be specified in hexadecimal form. +In some other places (e.g. in KDBX XML files), a UUID is stored in +Base64 form.

+ +

The entry dialog shows both forms (hexadecimal and Base64), such that +you can directly copy the form that you currently need.

+ +
+ + +

+Auto-Type

+ +

On this tab page, you can configure the auto-type behavior for +the current entry. +See the auto-type help page.

+ +
+ + +

+History

+ +

Each entry has an own history. When modifying an entry, KeePass +automatically creates a history entry, which contains the previous data. +The history entries are listed on the 'History' tab page of the entry dialog.

+ +

By default, the number of history entries per entry and the +history size per entry are limited to reasonable values. +You can change these limitations in the database settings dialog +(menu 'File' → 'Database Settings').

+ +

If you want to delete certain history entries manually, +there are two possibilities:

+ + +
+ + +

+Tools

+ +

When clicking the 'Tools' button (bottom left in the entry dialog), +a menu is displayed that provides some useful commands.

+ +

Copy initial password.
+Copies (to the clipboard) the password that was current when the dialog +was opened. +This command can be useful for instance when you try to change the password +and the website/service requests the previous password as confirmation +after specifying the new password.

+ +

URL field commands.
+These commands edit the URL field.

+ +

Insert field reference.
+When clicking one of the commands in this submenu, a dialog is displayed +that allows to conveniently create a +field reference in the chosen field.

+ +

OTP generator settings.
+Displays a dialog for conveniently editing the +one-time password +generator settings of the entry.

+ +
+ + +

+Editing Multiple Entries At Once

+ +

The entry dialog supports editing multiple entries at once. +For this, select multiple entries in the entry list of the main window +and invoke the 'Edit Entries' command.

+ + + +

Controls for data that cannot be modified in multiple entries at once +(e.g. file attachments) are disabled. Such data will not be modified.

+ + + diff --git a/src/Docs/Chm/help/v2/guioptions.html b/src/Docs/Chm/help/v2/guioptions.html new file mode 100644 index 0000000..94e4b75 --- /dev/null +++ b/src/Docs/Chm/help/v2/guioptions.html @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + GUI Options - KeePass + + + + + + + + + + + + +

GUI Options

+

Explains various Graphical User Interface (GUI) options.

+ + + +
+ + +

+Dialog Banner Styles

+ +

KeePass supports various different dialog banner styles. These styles are +independent from the operating system and can freely be used on all systems.

+ +

WinXP Login:
+WinXP Login Style

+ +

WinVista Black:
+WinVista Black Style

+ +

KeePass Win32:
+KeePass Win32 Style

+ +

Blue Carbon:
+Blue Carbon Style

+ + + diff --git a/src/Docs/Chm/help/v2/index.html b/src/Docs/Chm/help/v2/index.html new file mode 100644 index 0000000..7452cf0 --- /dev/null +++ b/src/Docs/Chm/help/v2/index.html @@ -0,0 +1,15 @@ + + + + + + Redirection - KeePass + + + +Redirecting to +KeePass Help Center...
+ + + + diff --git a/src/Docs/Chm/help/v2/ioconnect.html b/src/Docs/Chm/help/v2/ioconnect.html new file mode 100644 index 0000000..3d4e635 --- /dev/null +++ b/src/Docs/Chm/help/v2/ioconnect.html @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Load/Save From/To URL - KeePass + + + + + + + + + + + + +

Load/Save From/To URL

+

KeePass can load/save databases from/to URLs.

+ +

In this dialog you can specify a URL, from/to which data is read/written.

+ +

By default, KeePass supports FTP, HTTP, HTTPS +and WebDAV. More protocols may be available on your system +(if specific providers are installed).

+ +

The IOProtocolExt plugin adds support for +SCP, SFTP and FTPS.

+ +

Cloud storage:
+If you want to store your database file in a cloud storage: +for most cloud storages, there is an integration with the local file system +available (i.e. you can access your stored files using Windows Explorer). +For example, Dropbox, Microsoft OneDrive and Google Drive provide such +an integration. +If such an integration is available, it is recommended that you access +your database file this way; this often works better than accessing it +via a protocol like FTP or WebDAV. +If no such integration is available and your cloud storage also is not +accessible via a standard protocol, a specialized KeePass +plugin +for this cloud storage might be available.

+ +
+ + +

+Example: Using FTP Server

+ +

In order to load/save your database from/to an FTP server, you first need to +upload the database file to the server manually. This only needs to be done once.

+ +

Then start KeePass and go 'File''Open''Open URL...'. +Enter the full database path on the server and don't forget the ftp:// prefix! +This prefix is required, otherwise KeePass doesn't know which protocol to use. +Enter the FTP credentials and click [OK]. KeePass will download the file and open it.

+ +

KeePass can remember the FTP credentials, if you wish. You can choose between remembering +everything (user name and password), partially (user name only) and not remembering +the credentials at all.

+ +

When you press the 'Save' button, KeePass will automatically upload the new +database file to the server (same location as before, i.e. overwriting the previous +one).

+ + + diff --git a/src/Docs/Chm/help/v2/license.html b/src/Docs/Chm/help/v2/license.html new file mode 100644 index 0000000..5cd5fca --- /dev/null +++ b/src/Docs/Chm/help/v2/license.html @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + License (2.x) - KeePass + + + + + + + + + + + + + +

License (2.x)

+

License terms of KeePass 2.x.

+ +

KeePass: Copyright © 2003-2023 Dominik Reichl.

+ +

The program is distributed under the +terms of the GNU General Public License version 2 or later.

+ +

For acknowledgements and licenses of components/resources/etc., see the +Acknowledgements page.

+ +
+ +
+ +

GNU GENERAL PUBLIC LICENSE

+

+Version 2, June 1991 +

+ +
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+ +

Preamble

+ +

+ The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. +

+ +

+ When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. +

+ +

+ To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. +

+ +

+ For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. +

+ +

+ We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. +

+ +

+ Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. +

+ +

+ Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. +

+ +

+ The precise terms and conditions for copying, distribution and +modification follow. +

+ + +

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+ + +

+0. + This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". +

+ +

+Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. +

+ +

+1. + You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. +

+ +

+You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. +

+ +

+2. + You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: +

+ +
+
+
+ a) + You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. +
+
+
+ b) + You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. +
+
+
+ c) + If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) +
+
+ +

+These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. +

+ +

+Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. +

+ +

+In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. +

+ +

+3. + You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: +

+ + + + +
+
+
+ a) + Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, +
+
+
+ b) + Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, +
+
+
+ c) + Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) +
+
+ +

+The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. +

+ +

+If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. +

+ +

+4. + You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. +

+ +

+5. + You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. +

+ +

+6. + Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. +

+ +

+7. + If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. +

+ +

+If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. +

+ +

+It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. +

+ +

+This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. +

+ +

+8. + If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. +

+ +

+9. + The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. +

+ +

+Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. +

+ +

+10. + If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. +

+ +

NO WARRANTY

+ +

+11. + BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. +

+ +

+12. + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. +

+ +

END OF TERMS AND CONDITIONS

+ +

How to Apply These Terms to Your New Programs

+ +

+ If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. +

+ +

+ To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. +

+ +
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy  name of author
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ +

+Also add information on how to contact you by electronic and paper mail. +

+ +

+If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: +

+ +
+Gnomovision version 69, Copyright (C) year name of author
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'.  This is free software, and you are welcome
+to redistribute it under certain conditions; type `show c' 
+for details.
+
+ +

+The hypothetical commands `show w' and `show c' should show +the appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and +`show c'; they could even be mouse-clicks or menu items--whatever +suits your program. +

+ +

+You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: +

+ + +
+Yoyodyne, Inc., hereby disclaims all copyright
+interest in the program `Gnomovision'
+(which makes passes at compilers) written 
+by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+ +

+This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the +GNU Lesser General Public License +instead of this License. +

+ +
+End GNU General Public License +
+ +
+ + + diff --git a/src/Docs/Chm/help/v2/plugins.html b/src/Docs/Chm/help/v2/plugins.html new file mode 100644 index 0000000..1b27511 --- /dev/null +++ b/src/Docs/Chm/help/v2/plugins.html @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Plugins (2.x) - KeePass + + + + + + + + + + + + +

Plugins (2.x)

+

Installation, uninstallation and security of KeePass 2.x plugins.

+ +
+ +

+Introduction

+ +

KeePass features a plugin framework. Plugins can provide additional +functionality, like support of more file formats for import/export, +network functionalities, backup features, etc.

+ +
+ +

+Online Resources

+ +

Plugins can be found on the +Plugins page.

+ +
+ +

+Plugin Installation and Uninstallation

+ +

If there are no explicit instructions how to install the plugin, +follow these steps:

+ +
    +
  1. Download the plugin from the page above and unpack the ZIP file to a +new folder.
  2. +
  3. In KeePass, click 'Tools' → 'Plugins' → button +'Open Folder'; KeePass now opens a folder called 'Plugins'. +Move the new folder (containing the plugin files) into the 'Plugins' folder.
  4. +
  5. Restart KeePass in order to load the new plugin.
  6. +
+ + + +

To uninstall a plugin, delete the plugin files.

+ +

Linux:
+On some Linux systems, the mono-complete package may be +required for plugins to work properly.

+ +

Portability:
+PLGX plugins are compiled by KeePass and the generated files are stored +in a plugin cache, which by default is located in the +user's application data directory (so, running a PLGX plugin by default +creates files outside the KeePass application directory). +These plugin cache files do not need to be copied to other systems though, +because they are generated on each system and do not contain any user data.

+ +
+ +

+Security

+ +

What about the security of plugins? Can't malicious plugins +'inject' themselves into KeePass?

+ +

If plugins can register themselves +(i.e. have write access to the KeePass directory), they could also just +replace the whole 'KeePass.exe' file. It's a problem of file access +rights, not the plugin system.

+ +

If you worry about this, +install KeePass as administrator into the program files directory +(which is the default, typically in a folder in 'C:\Program Files'). +Afterwards, run KeePass and other applications only as normal user +(without administrator privileges).

+ +

This solves the problem above. As the KeePass directory is write-protected +for normal users, no other program can copy files into it. KeePass requires the plugins to +be in the application directory. Therefore, plugins cannot inject themselves anymore.

+ +

If you use the portable package of KeePass or installed it into a different +directory, you need to adjust the directory permissions yourself.

+ +

KeePass supports two plugin file formats: DLL and +PLGX. +A DLL plugin can be loaded directly, whereas KeePass needs to compile a PLGX +plugin to a DLL plugin first, which is then stored in a +plugin cache (see the section below). +By default, the user has write access in the plugin cache directory +(without administrator privileges). +If you want to use a PLGX plugin, consider to adjust the access rights of the +plugin cache directory to require administrator privileges for write access.

+ +
+ + +

+Plugin Cache

+ +

PLGX plugins are compiled and stored in a plugin cache directory on the +user's system. This cache highly improves the startup performance of KeePass. +Old files are normally deleted from the cache +automatically (this can be disabled in the plugins dialog). +The cache does not contain any user data.

+ +

By default, the plugin cache is located in the user's application data +directory. However, this can be overridden using the +Application/PluginCachePath setting in the configuration file +(this setting supports placeholders and environment variables). +So, if you're for example using KeePass on a portable device and don't want +the cache to be on the system, you could set the path to {APPDIR}\PluginCache.

+ +

Warning +Do not relocate the plugin cache into the 'Plugins' folder of the +KeePass application directory, because this can result in a severe +performance degradation.

+ + + diff --git a/src/Docs/Chm/help/v2/policy.html b/src/Docs/Chm/help/v2/policy.html new file mode 100644 index 0000000..c36ae89 --- /dev/null +++ b/src/Docs/Chm/help/v2/policy.html @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Application Policy - KeePass + + + + + + + + + + + + +

Application Policy

+

Details about the application policy system within KeePass.

+ + + +
+ + +

+Help for Users

+ +

Application policy is a KeePass feature that enables administrators +to prevent you from accidently compromising the security +system of your company.

+ +

Operations like exporting entries to non-encrypted +files or printing for example can be prevented effectively +using the application policy.

+ +

If you are using KeePass at home, you can ignore the +application policy (everything allowed anyway) or reduce +your rights using the policy yourself, in order to avoid +accidental leakage of sensitive information.

+ +

In order to prevent changing the policy after it has +been specified, it is recommended to use an +enforced +configuration file.

+ +
+ + +

+Help for Administrators

+ +

KeePass can be installed on a network drive and a policy +can be enforced (like not permitting users to print the +entry list).

+ +

The application policy enforcement is based on +the mechanism how KeePass stores configuration settings. You +first need to understand this method before you can continue +creating a policy; see the +configuration help page.

+ +

A policy-enforcing KeePass installation looks like +the following: the KeePass application files are stored +on the network drive and all users are starting KeePass from +this drive (i.e. they only have links to the executable on +the network drive). By using an enforced configuration file +on the network drive +(remember that this file overrides all others), +a policy can be enforced.

+ +

In order to create such an installation, follow these steps:

+ +
    +
  1. Copy KeePass to a shared network drive that supports file +access rights (like NTFS).
  2. + +
  3. Create an enforced configuration file that enforces the +application policy settings that you wish.
  4. + +
  5. Adjust the file access rights: allow users only to read and +execute all KeePass files, no write access.
  6. +
+ + + +
+ + +

+Policy Security

+ +

Recall what the policy mechanism looks like: KeePass and the +configuration file are stored on the network drive. If you +grant your users free access to the Internet or allow them +to insert CD-ROMs/DVDs/USB-sticks, nothing prevents +a user to download a separate copy of KeePass and run it. In +this case the policy isn't enforced, as the downloaded KeePass +doesn't know anything of the enforced configuration file on the network +drive.

+ +

Policy enforcement therefore only is effective if your users +really use the KeePass version installed on the network drive.

+ + + diff --git a/src/Docs/Chm/help/v2/setup.html b/src/Docs/Chm/help/v2/setup.html new file mode 100644 index 0000000..d101667 --- /dev/null +++ b/src/Docs/Chm/help/v2/setup.html @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Installation / Portability - KeePass + + + + + + + + + + + + + +

Installation / Portability

+

KeePass 2.x installation, uninstallation, portability and updates.

+ + + +
+ +

+General information

+ +

When downloading KeePass, you have the choice between 3 different packages:

+ + + +

The installer and the portable version are described in detail below.

+ +

The source code package contains everything you need to compile KeePass. +It includes the C#/C++ source code and header files, resource files, +sources for building the installer, etc.

+ + + +

Updating KeePass:
+When a new KeePass version has been released, you can update your existing KeePass +installation, without losing any configuration settings. The steps are +depending on which package you are using (installer or portable), see below.

+ +

Translations should also be updated when you install a new KeePass version. +You can find the latest translation files here: +KeePass Translations.

+ +
+ +

+Installer program (KeePass-2.xx-Setup.exe file)

+ +

The KeePass development team provides an installer, which copies KeePass +to your hard disk, creates shortcuts in the start menu and associates +KDBX files with KeePass, if desired.

+ +

Additionally, KeePass is automatically configured to store its settings in +the application data directory of the current user. +This way multiple users can use one KeePass +installation without overwriting each other's settings (each user has his +own configuration file). +The setup program must run with administrative +rights, however KeePass runs fine without administrative rights once it +is installed.

+ +

Installation:
+To install KeePass, run the KeePass-2.xx-Setup.exe file +and follow the wizard.

+ +

Updating:
+Run the KeePass-2.xx-Setup.exe file. +You do not need to uninstall the old version first. +Your configuration options will not be lost.

+ +

Uninstallation:
+In order to uninstall KeePass, run the uninstallation program, which is +accessible by a shortcut in the start menu folder of KeePass, or in +the program section of the system control panel. If you also want +to remove your configuration settings, you need to delete the configuration +file in the application data directory of your user profile, see +Configuration.

+ +

Silent Installation:
+The KeePass installer KeePass-2.xx-Setup.exe supports command line +switches for silent installation, i.e. the program gets installed without +asking the user for target directory or association options. The default settings +of the installer are used.

+ +

The /SILENT command line switch performs a silent +installation and shows a status dialog during the setup process. No questions +will be asked though.

+ +

The /VERYSILENT command line switch performs a silent +installation and does not show a status dialog during the setup process.

+ +

Destination Path:
+The installer allows to choose the destination path to which KeePass is +installed. +However, when the installer detects an existing KeePass installation, it +assumes that the user wants to perform an upgrade and thus doesn't +display the destination path selection page; the old version will be overwritten +by the new version. +If you want to move an existing KeePass installation to a different path, +first uninstall the old version; the installer of the new version will then +display the destination path selection page again.

+ +

Options/Components:
+The installation options/components are explained in detail here: +What +do the 2.x installation options/components mean in detail?.

+ +
+ + +

+Portable version (KeePass-2.xx.zip file)

+ +

The portable version can be carried around on portable devices (like USB +sticks) and runs on any computer directly from the device, without any +installation. +It doesn't store anything on your system (in contrast to +the setup package, see above). KeePass doesn't create any new +registry keys and it doesn't create any configuration files in your Windows +or application data directory of your user profile.

+ +

Make sure that KeePass has write access to +its application directory. Otherwise, if it doesn't have, it'll attempt +to store the configuration options (nothing security-relevant though) into the +application data directory of the currently logged on user. +For more about that, see this page: +Configuration.

+ +

Installation:
+KeePass does not need to be installed. Just download the ZIP package, unpack +it with your favorite ZIP program and KeePass is ready to be used. Copy it to +a location of your choice (for example onto your USB stick); no +additional configuration or installation is needed.

+ +

Updating:
+Download the latest portable package of KeePass, unpack it +and copy all new files over the old ones. Your configuration settings will not +be lost (the settings are stored in the KeePass.config.xml file, +which won't be overwritten, because KeePass ZIP packages don't +include a KeePass.config.xml file).

+ +

Uninstallation:
+Simply delete the KeePass folder.

+ +
+ + +

+Running KeePass under Mono (Linux, MacOS, BSD, ...)

+ +

In addition to Windows, KeePass 2.x runs under Mono, +i.e. Linux, MacOS, BSD, etc.

+ +

Links to all supported packages can be found on the +Downloads page.

+ + + +
+ + +

+Running KeePass under Wine (Linux, MacOS, BSD, ...)

+ +

Although you can run KeePass 2.x more or less natively on Unix-like systems +using Mono (see above), the user interface does not always look pretty. +Some users therefore prefer running KeePass 2.x under Wine.

+ +

In order to run KeePass 2.x under Wine, follow these steps:

+ +
    +
  1. Make sure that Wine is installed. +Typically the package to install is called wine.
  2. +
  3. Make sure that .NET Framework 4.5 or higher is installed in Wine, see +WineHQ AppDB: .NET Framework.
    +For installing .NET Framework 4.5, winetricks can be used, see +WineHQ AppDB: .NET Framework 4.5.
  4. +
  5. Download the latest portable package of KeePass 2.x (ZIP file) and unpack it +into some directory of your choice.
  6. +
  7. Run wine KeePass.exe.
  8. +
+ +

Theme. +By default, Wine uses the classic Windows theme. If you prefer some other +theme, you can install it in 'Applications' → 'Wine' → 'Configure Wine' → +tab 'Desktop Integration'. +Links to themes can for instance be found on +Wikipedia: Windows XP visual styles.

+ +

Auto-Type. +Wine currently does not implement all Windows API functions required for +auto-type, i.e. auto-type does not work when running KeePass under Wine.

+ + + + + +
+ + +

+Migrating from KeePass 1.x to 2.x

+ +

In order to migrate from KeePass 1.x to 2.x, follow these steps:

+ +
    +
  1. Install KeePass 2.x.
    +If you're using the installer, make sure that the component +'Native Support Library' is being installed +(by default this component is enabled).
  2. +
  3. Run KeePass 2.x and create a new KDBX database file (via 'File' → +'New').
  4. +
  5. Import your old KDB database file into your new KDBX database file +(via 'File' → 'Import', file format 'KeePass KDB (1.x)').
  6. +
+ +

If everything works fine, you can delete your old KeePass 1.x +installation. The old KDB database file also isn't required anymore, +but you may want to keep it as a backup.

+ + + diff --git a/src/Docs/Chm/help/v2/sync.html b/src/Docs/Chm/help/v2/sync.html new file mode 100644 index 0000000..0ad8c38 --- /dev/null +++ b/src/Docs/Chm/help/v2/sync.html @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Synchronization - KeePass + + + + + + + + + + + + +

Synchronization

+

Merge changes made in multiple copies of a database.

+ + + +
+ + +

+Introduction and Requirements

+ +

KeePass 2.x features a powerful, built-in synchronization mechanism. +Changes made in multiple copies of a database file can be merged safely.

+ +

After synchronizing two files A and B, both A and B are up-to-date +(i.e. KeePass saves the merged data to both locations when performing +a synchronization).

+ +

Requirements.

+ + +
+ + +

+Invoking a Synchronization

+ +

There are multiple ways how a synchronization can be invoked:

+ + + +
+ + +

+Technical Details

+ +

The synchronization algorithm is rather complex and it would take +many pages to describe in detail how it is working. +Developers interested in this can have a look into the KeePass source code. +Here are the most important properties of the synchronization algorithm:

+ + + +
+ + +

+Advanced Synchronization Schemes

+ + + + + diff --git a/src/Docs/Chm/help/v2/translation.html b/src/Docs/Chm/help/v2/translation.html new file mode 100644 index 0000000..0ed2a03 --- /dev/null +++ b/src/Docs/Chm/help/v2/translation.html @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Translations - KeePass + + + + + + + + + + + + +

Translations

+

How to install translations of KeePass 2.x.

+ + + + + +
+ + +

+Installing User Interface Translations

+ +

To install a user interface translation, follow these steps:

+ +
    +
  1. Download the translation ZIP file from the +Translations page +and unpack it (to the current directory).
  2. +
  3. In KeePass, click 'View' → 'Change Language' → button +'Open Folder'; KeePass now opens a folder called 'Languages'. +Move the unpacked file(s) into the 'Languages' folder.
  4. +
  5. Switch to KeePass, click 'View' → 'Change Language', +and select your language. Restart KeePass.
  6. +
+ + + +

Note. +For moving the unpacked file(s) (in step 2), we recommend to use Windows Explorer. +Other file managers may have problems with access rights.

+ +
+ + +

+Additional Localized Content

+ +

For some languages (not for all) there is additional localized content available, +like translated help files, tutorials, etc. All this content is available +from the same page where the user interface translations are downloadable: +Translations page.

+ +

If you'd like to create some translated content yourself, please first ask +the KeePass team if the thing you're planning to create isn't in work already by +someone else. If not, you'll make a lot of people very happy by creating translated content!

+ + + diff --git a/src/Docs/Chm/help/v2/triggers.html b/src/Docs/Chm/help/v2/triggers.html new file mode 100644 index 0000000..10147ea --- /dev/null +++ b/src/Docs/Chm/help/v2/triggers.html @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Triggers - KeePass + + + + + + + + + + + + + +

Triggers

+

Automate workflows using the trigger system.

+ + + +
+ + +

+Trigger System Introduction

+ +

KeePass features a powerful event-condition-action trigger system. +With this system, workflows can be automated. For example, you could define +a trigger that automatically uploads your database to a backup server after +saving the file locally.

+ +

A trigger starts to run when any of the specified events matches. +When this happens, the conditions are checked. If all conditions +are fulfilled, the actions of the trigger are performed. +Actions are performed consecutively; if one action fails, typically the execution +of the event is aborted (i.e. all following actions aren't performed).

+ +

A trigger must be both enabled and on in order to get executed. +The enabled state is set by the user; a disabled trigger has no +function. The on state is dependent on the state of the program. By +enabling the 'Initially On' option, a trigger is on by default. +If you enable the option 'Turn off after executing actions', the trigger +will be off after running once. There are actions to turn triggers on and off, +i.e. triggers can turn themselves and other triggers on and off, which allows +to define a complex state-dependent system of triggers.

+ +

Most strings in the trigger system are Spr-compiled, i.e. +placeholders +(except state-changing ones), environment variables, etc. can be used.

+ +

Sensitive Data.
+Some trigger events/conditions/actions support fields for potentially +sensitive data (for instance the password field of the 'Open database file' +action). As triggers are saved in a plain text +configuration file, +it is generally not recommended to directly enter sensitive data in trigger fields. +If a database is open when the trigger runs, the sensitive data can be +stored in the database and the trigger field can point to the data using +a field reference +(which KeePass resolves when evaluating the field). +In this way, only the field reference appears in the configuration file +and the actual sensitive data is stored in the encrypted database file.

+ +

I/O Connection Properties.
+Most trigger actions having a file path/URL parameter only allow +specifying the path/URL and possibly credentials (user name and password) +for accessing the file; advanced connection properties (like +timeout, user agent, passive mode, etc.) cannot be specified here. +If advanced connection properties are required, open the file once +(using 'File' → 'Open') with the desired connection properties. +This will create an item in the 'Open Recent' file list +(which remembers connection properties). +When a trigger action is executed, KeePass loads the connection properties +from the corresponding item (same path/URL) in the 'Open Recent' file list.

+ +
+ + +

+Events

+ + + +
+ + +

+Conditions

+ + + +
+ + +

+Actions

+ + + +
+ + +

+Examples

+ +

See the Trigger Examples page.

+ + + diff --git a/src/Docs/Chm/help/v2/version.html b/src/Docs/Chm/help/v2/version.html new file mode 100644 index 0000000..263283f --- /dev/null +++ b/src/Docs/Chm/help/v2/version.html @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Compatibility - KeePass + + + + + + + + + + + + +

Compatibility

+

Compatibility of KeePass editions.

+ +

KDBX files (created by KeePass 2.x) and KDB files (created by +KeePass 1.x) are not compatible. KeePass 2.x supports +a lot of features, which 1.x doesn't support, therefore these formats +are incompatible.

+ +

But KeePass 2.x can import KDB files created by KeePass 1.x. For +this, you first need to create a new database in KeePass 2.x +and then import the 1.x database using 'File' → 'Import'.

+ +

By 'File' → 'Export', KeePass 2.x can also export data to +1.x KDB files. However note that not all 2.x fields +are supported by 1.x (i.e. the export is lossy).

+ + + diff --git a/src/Docs/Chm/help/v2/xml_replace.html b/src/Docs/Chm/help/v2/xml_replace.html new file mode 100644 index 0000000..2cc7830 --- /dev/null +++ b/src/Docs/Chm/help/v2/xml_replace.html @@ -0,0 +1,395 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + XML Replace - KeePass + + + + + + + + + + + + + + +

XML Replace

+

About the XML replacement functionality.

+ + + +
+ + +

+General Information

+ +

XML Replace is a powerful feature that modifies a database by manipulating +its XML representation.

+ +

It creates a KeePass 2.x XML DOM of the current database +in memory, performs the operation specified by the user +(e.g. remove nodes or replace text), loads the modified XML tree, +and merges the current database with the modified database.

+ +

Warning +This is a feature for experts. Use with caution!

+ +

XML Replace can be invoked via 'Tools' → 'Database Tools' → +'XML Replace'.

+ +

Information about XPath and regular expressions can be found on the +Search help page.

+ +

KeePass protects history entries; XML Replace cannot be used to modify +these. Furthermore, any changes to database properties +(database name/description, etc.) may be ignored.

+ +
+ + +

+Examples

+ +
+ + + + + + + + + + + + +
Replace text in all entry titles and notes
Select nodes://Entry/String[(Key = 'Title') or (Key = 'Notes')]/Value
Action:Replace data
Data:Inner text
Find what:TheTextToFind
Replace with:TheReplacement
Within all entry titles and notes, this +replaces all occurences of TheTextToFind by +TheReplacement.
+ +
+ + + + + + + + + + + + + +
Replace all HTTP URLs by HTTPS URLs
Select nodes://Entry/String[Key = 'URL']/Value
Action:Replace data
Data:Inner text
Find what:^http:
Replace with:https:
Options:☑ Regular expressions
Within all entry URL fields, this replaces all +HTTP URLs by HTTPS URLs.
+ +
+ + + + + + + + + + + + + +
Replace group icons
Select nodes://Group/IconID
Action:Replace data
Data:Inner text
Find what:^48$
Replace with:36
Options:☑ Regular expressions
This assigns the ZIP package icon to all groups that +currently have a closed folder as icon.
+
+All icon IDs can be found in the icon picker dialog.
+ +
+ + + + + + + + + + +
Delete entry strings by name
Select nodes://Entry/String[Key = 'TheName']
Action:Remove nodes
Removes all entry strings named +TheName.
+ +
+ + + + + + + + + +
Delete entry attachments by name extension
Select nodes://Entry/Binary/Key[(string-length(.) >= 4) and (substring(., string-length(.) - 3) = '.jpg')]/..
Action:Remove nodes
Removes all entry attachments that have a name +ending in '.jpg'.
+ +
+ + + + + + + + + +
Reset background colors
Select nodes://Entry/BackgroundColor
Action:Remove nodes
Sets the background color of all entries to the +default (transparent/alternating).
+ +
+ + + + + + + + + + + + +
Disable auto-type for entries with empty fields
Select nodes://Entry/String[((Key = 'UserName') or (Key = 'Password')) and (Value = '')]/../AutoType/Enabled
Action:Replace data
Data:Inner text
Find what:True
Replace with:False
Disables auto-type for all entries that have an empty +user name field or an empty password field.
+ +
+ + + + + + + + + + + + +
Convert {DELAY= to upper-case
Select nodes://DefaultSequence | //KeystrokeSequence
Action:Replace data
Data:Inner text
Find what:{DELAY=
Replace with:{DELAY=
Converts all {DELAY= codes +within auto-type sequence overrides and associations to upper-case +(by default the case sensitivity option is turned off, thus the 'Find what' +text matches all cases).
+
+In KeePass 2.x, placeholders are case-insensitive. However, this XML Replace operation +may be useful as preparation for the following example (which matches +{DELAY= in a case-sensitive way).
+ +
+ + + + + + + + + + + + + +
Prepend {DELAY=50} to all sequences without a {DELAY=
Select nodes:(//DefaultSequence | //KeystrokeSequence)[not(contains(., '{DELAY=')) +and (. != '')]
Action:Replace data
Data:Inner text
Find what:^(.*)$
Replace with:{DELAY=50}$1
Options:☑ Regular expressions
Prepends a {DELAY=50} to all auto-type +sequence overrides and associations that do not contain any +{DELAY= already and are not empty.
+
+Note that the node selection is case-sensitive (independent of the data +case sensitivity option), thus you need to ensure that all +{DELAY= codes are upper-case before performing this operation. +This can e.g. be done using the XML Replace operation mentioned +above.
+ +
+ + + + + + + + + + + + + +
Change {DELAY= values
Select nodes://DefaultSequence | //KeystrokeSequence
Action:Replace data
Data:Inner text
Find what:\{DELAY=[\d\s]*\}
Replace with:{DELAY=50}
Options:☑ Regular expressions
Sets the values of all {DELAY= codes +within auto-type sequence overrides and associations to 50.
+ +
+ + + + + + + + + + + + + +
Remove {DELAY=x} from all sequences
Select nodes://DefaultSequence | //KeystrokeSequence
Action:Replace data
Data:Inner text
Find what:\{DELAY=[\d\s]*\}
Replace with:(Leave empty)
Options:☑ Regular expressions
Removes all {DELAY=x} codes from +all auto-type sequences.
+ +
+ + + + + + + + + +
Reset default sequences that contain {DELAY=
Select nodes://DefaultSequence[contains(., '{DELAY=')]
Action:Remove nodes
If a sequence has been specified in the field +'Override default sequence' (in the entry dialog) and it contains +{DELAY=, the sequence is reset, +i.e. the option 'Inherit default auto-type sequence from group' is activated.
+ +
+ + + + + + + + + + + + + +
Add an auto-type association to all entries
Select nodes://Entry/AutoType
Action:Replace data
Data:Outer XML
Find what:</AutoType>\Z
Replace with:<Association><Window>* - Notepad</Window><KeystrokeSequence>{PASSWORD}</KeystrokeSequence></Association></AutoType>
Options:☑ Regular expressions
Adds an auto-type association to all entries: the window title +'* - Notepad' is associated with the sequence '{PASSWORD}'.
+ +
+ + + + + + + + + + + + + +
Copy entry URLs into title fields
Select nodes://Entry
Action:Replace data
Data:Inner XML
Find what:(?s)(<Key>Title</Key>\s*)(<Value>.*?</Value>|<Value\s*/>)(.*?<Key>URL</Key>\s*)(<Value>.*?</Value>|<Value\s*/>)
Replace with:$1$4$3$4
Options:☑ Case-sensitive
+☑ Regular expressions
Copies the entry URL into the title field of the +entry (overwriting any existing data in the title field).
+
+If you want the entry URL to be copied only if the title field is empty, +use the following for 'Select nodes':
+//Entry/String[(Key = 'Title') and (Value = '')]/..
+ +
+ + + + + + + + + + + + + +
Copy entry titles into empty user name fields
Select nodes://Entry/String[(Key = 'UserName') and (Value = '')]/..
Action:Replace data
Data:Inner XML
Find what:(?s)(<Key>Title</Key>\s*<Value>)(.*?)(</Value>.*?<Key>UserName</Key>\s*)(<Value></Value>|<Value\s*/>)
Replace with:$1$2$3<Value>$2</Value>
Options:☑ Case-sensitive
+☑ Regular expressions
Copies the entry title into the user name field of the +entry, if this field is empty.
+ +
+ + + + + + + + + + + + + +
Ensure first line is not empty
Select nodes://Entry/String/Value
Action:Replace data
Data:Inner text
Find what:(?s)^(\r?\n)
Replace with:--$1
Options:☑ Regular expressions
For all multi-line fields, +this inserts '--' into the first line of the field value, +if this line is empty and the value has at least two lines. +Example:
+
+

+
+Sample data
+
+is replaced by
+
+
--
+
+Sample data
+ + + diff --git a/src/Docs/Chm/help/v2_dev/customize.html b/src/Docs/Chm/help/v2_dev/customize.html new file mode 100644 index 0000000..c8a194a --- /dev/null +++ b/src/Docs/Chm/help/v2_dev/customize.html @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Customization (2.x) - KeePass + + + + + + + + + + + + + + + + +

Customization (2.x)

+

KeePass 2.x features various options for network administrators to +customize the program's appearance and behavior.

+ + + +
+ + +

+Preliminaries

+ +

Most options below are configured by directly editing the +KeePass.config.xml configuration file. If you're planning to +deploy a customized KeePass version, you should fully understand the +KeePass configuration system, +especially how to enforce some settings and leave others up to users.

+ +

Note that KeePass features a rich plugin framework. If there's no +item in the XML file to configure what you're thinking about, you might +want to write a plugin.

+ +
+ + +

+Minimum Master Password Requirements

+ +

You can specify several properties that master passwords must have +in order to be accepted (length, estimated quality, ...). +See Specifying Minimum Master Password +Properties.

+ +
+ + +

+Specifying UI Element States

+ +

The state (enabled, disabled, visible, hidden) of several user interface +(UI) elements can be specified using the UIFlags value +of the UI node in the configuration file. +This can be a bitwise combination of one or more of +the following flags:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Flag (Hex)Flag (Dec)Description
0x00Don't force any states (default).
0x11Disable 'Tools' → 'Options' menu item.
0x22Disable 'Tools' → 'Plugins' menu item.
0x44Disable 'Tools' → 'Triggers' menu item.
0x88Disable controls to specify after how many +days the master key should/must be changed.
0x1016Hide password quality progress bars and information labels.
0x2032Disable 'Help' → 'Check for Updates' menu item.
0x4064Disable 'Tools' → 'Database Tools' → 'XML Replace' menu item.
0x80128Disable 'File' → 'Database Settings' menu item.
0x1000065536Hide built-in profiles in the +password generator context menu of the entry editing dialog.
0x20000131072Show UI elements related to last access times.
+Note: Databases are not marked as modified when a last access time +changes. Thus, when only last access times are changed and the user closes the +database (without saving manually first and without a save forced e.g. by a trigger or plugin), +the changes to the last access times are lost.
0x40000262144Do not display information dialogs when creating a new database.
0x80000524288Do not display auto-type obfuscation compatibility information dialogs.
0x1000001048576Do not clear the quick search terms list when closing/locking a database.
+Note: Even if this flag is set, the list is cleared when exiting +KeePass. If you frequently perform the same searches, consider using +tags or +search profiles.
0x2000002097152Enable the Input Method Editor (IME) on +secure desktops.
+Warning +This can result in problems (black screen, IME/CTF process with +high CPU usage, ...). See +'Why +does the Input Method Editor (IME) not work?'.
+ +

The value of UIFlags must be specified in decimal notation.

+ +

For example, if you want to disable the 'Options' and 'Check for Updates' +menu items, you'd specify 33 as value for the UIFlags node +(0x1 + 0x20 = 1 + 32 = 33).

+ +
+ + +

+More Options

+ + + + + diff --git a/src/Docs/Chm/help/v2_dev/plg_index.html b/src/Docs/Chm/help/v2_dev/plg_index.html new file mode 100644 index 0000000..ae16989 --- /dev/null +++ b/src/Docs/Chm/help/v2_dev/plg_index.html @@ -0,0 +1,661 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Plugin Development (2.x) - KeePass + + + + + + + + + + + + + +

Plugin Development (2.x)

+

How to develop plugins for KeePass 2.x.

+ +

This documentation applies to KeePass 2.x plugins. 2.x plugins are fundamentally +different from 1.x plugins. 1.x plugins cannot be loaded by KeePass 2.x.

+ + + +
+ + +

+Requirements

+ +

Before you can start developing a KeePass plugin, you need the following +prerequisites:

+ + + +
+ + +

+Step-by-Step Tutorial

+ +

Start your favorite IDE and create a new C# Class Library project +(for the .NET Framework, not .NET Standard/Core). +In this tutorial, the example plugin we're developing is called SimplePlugin. +The first thing you need to do now is to add a reference to KeePass: +go to the references dialog and select the KeePass.exe file +(from the portable ZIP package). +After you added the reference, the namespaces KeePass and +KeePassLib should be available.

+ +

It is important that you reference an official KeePass.exe, +not a development snapshot or own build, because otherwise your +plugin will be incompatible with official KeePass builds.

+ +

All KeePass plugins need to derive from a base KeePass plugin class +(Plugin in the KeePass.Plugins namespace). +By overriding methods and properties of this class, you can customize +the behavior of your plugin.

+ +

A minimal plugin looks like this:

+ +
using System;
+using System.Collections.Generic;
+
+using KeePass.Plugins;
+
+namespace SimplePlugin
+{
+	public sealed class SimplePluginExt : Plugin
+	{
+		private IPluginHost m_host = null;
+
+		public override bool Initialize(IPluginHost host)
+		{
+			if(host == null) return false;
+			m_host = host;
+			return true;
+		}
+	}
+}
+ +

You can find a fully documented and extended version of this simple +plugin on the KeePass plugins web page.

+ +

This plugin does exactly nothing, but it shows some important conventions +already, which must be followed by all plugins:

+ + + +

The Initialize function is the most important one and you +probably will always override it. In this function, you get an interface +to the KeePass internals: an IPluginHost interface reference. +Through this interface you can access the KeePass main menu, the currently +opened database, etc. The Initialize function is called immediately +after KeePass loads your plugin. All initialization should be done in this +method (not in the constructor of your plugin class!). If you +successfully initialized everything, you must return true. If +you return false, KeePass will immediately unload your plugin.

+ +

A second function that you will need very often is the Terminate +method:

+ +
public override void Terminate()
+{
+}
+ +

This function is called shortly before KeePass unloads your plugin. You cannot +abort this process (it's just a notification and your last chance to clean up +all used resources, etc.). Immediately after you return from this method, KeePass +can unload your plugin. It is highly recommended to free all resources in this +method (not in the destructor of your plugin class!).

+ +

We're almost done! We now need to tell KeePass that +our file is a KeePass plugin. This is done by editing the Version Information Block +of the file. Open the file version editing dialog (in Visual Studio 2005: right-click +onto the project name → 'Properties' → button 'Assembly Information'). +All fields can be assigned freely except the Product Name field (for more information +see Plugin Conventions). This field must be set to +"KeePass Plugin" (without the quotes).

+ + + +

That's it! Now try to compile your plugin and copy the resulting DLL +file into the KeePass directory. If you start KeePass and go to the plugins +dialog, you should see your plugin in the list of loaded plugins.

+ +
+ + +

+Providing Menu Items

+ +

Many plugins provide menu items (with subitems, if necessary) +in prominent locations like the 'Tools' menu, the entry context menu, etc. +Such a menu item can be supplied to KeePass by overriding the +GetMenuItem method of your plugin class +(which derives from the Plugin base class). +In this method, the plugin can construct and return a ToolStripMenuItem, +which KeePass will then show in the appropriate location.

+ +

Users should be able to associate the menu item with your plugin. +Typically, plugins set the text of the menu item to the name of the plugin or +a string that starts with the name of the plugin. For example, a plugin 'Abcd' +that wants to provide one menu item only (for accessing the plugin options) +could set the text of the menu item to 'Abcd Options'. +If the plugin supports multiple commands, set the menu item's text to +the plugin name (e.g. 'Abcd') and add a subitem for each command.

+ +

The GetMenuItem method should always construct and return +a new ToolStripMenuItem. Do not cache the menu item +or any of its subitems for +later purposes (KeePass may invoke the GetMenuItem method +multiple times and show the menu items in multiple places; if your plugin +would cache a menu item, trying to show it in multiple places would +result in problems, because a ToolStripMenuItem can have +only one parent item). +If you want to update the state of subitems (like disabling certain items +or showing checkmarks), you can do this for instance +in an anonymous method that handles the DropDownOpening +event of the returned menu item (this way you do not need to remember +menu item references manually); see +SamplePlugin +for an example.

+ +

KeePass takes ownership of the returned menu item (and its subitems). +The plugin should not add or remove the item to/from any menu itself; +KeePass will do this.

+ +

If your plugin does not provide a menu item in the location specified +by the PluginMenuType parameter t, +return null.

+ +

Example:

+ +
public override ToolStripMenuItem GetMenuItem(PluginMenuType t)
+{
+	// Provide a menu item for the main location(s)
+	if(t == PluginMenuType.Main)
+	{
+		ToolStripMenuItem tsmi = new ToolStripMenuItem();
+		tsmi.Text = "Abcd Options";
+		tsmi.Click += this.OnOptionsClicked;
+		return tsmi;
+	}
+
+	return null; // No menu items in other locations
+}
+
+private void OnOptionsClicked(object sender, EventArgs e)
+{
+	// Called when the menu item is clicked
+}
+ + + +

For an example how to create a menu item with subitems (and +update their states dynamically), see the +SamplePlugin +example plugin.

+ + + +
+ + +

+Plugin Conventions

+ +

File version information block:

+ +

KeePass uses the file version information block to detect if a DLL file is a +KeePass plugin and retrieves information from it to show in the plugins dialog. +The fields are used as follows:

+ + + +

Name, namespace and class name:

+ +

If you want to use the name "KeePass" as part of the name of +your plugin, directly prepend/append a non-numeric prefix/suffix. +For example, "KeePassSync" is ok, but "KeePass Sync" is not.

+ +

The namespace must be named like the DLL file without +extension. For example, if the DLL file is named SecretImporter.dll, +you must call the namespace SecretImporter.

+ +

The plugin class must be named like the namespace plus "Ext". +For the SecretImporter plugin, this would be SecretImporterExt.

+ +
+ + +

+Update Checking

+ +

The update check of KeePass ≥ 2.18 can also check for plugin updates. +Update check support is optional; plugins don't have to support update +checks.

+ +

In order to support update checks, plugin developers need to do the following:

+ + + +

Plugin developers have to update their version information file each time +they release new versions of their plugins.

+ +

Version information file format.

+ + +

Example. Let's assume you're developing two plugins: MyPlugin1 +(version 1.5) and MyPlugin2 (version 1.13.2.17). Then your version +information file could look as follows:

+
:
+MyPlugin1:1.5
+MyPlugin2:1.13.2.17
+:
+ +

If you've developed multiple plugins, it is recommended to create one +version information file, list all your plugins in this file and specify +the URL of the file in all your plugins. When KeePass checks for updates, +it'll download your version information file only once. +This reduces network traffic and is faster than downloading a version information +file for every plugin separately.

+ +

Signing. Since KeePass 2.34, +you can optionally digitally sign your version information file using RSA / SHA-512.

+ + +
+ + +

+Can KeePass 2.x Plugins be Written in Unmanaged C++?

+ +

Yes and no. You can write the logic of your plugin in unmanaged C++ (native +Win32 APIs can be used). However, you must provide a managed interface to your plugin, +i.e. you must export a managed class derived from the Plugin base class +as described in the tutorial. +Also, managed C++ is required to modify the KeePass internals (entries, +groups, main window, ...).

+ +

For an example how to use unmanaged APIs in a managed C++ plugin assembly, +see the +SamplePluginCpp +example plugin.

+ +

It is highly recommended to develop plugins in C#, not in C++, due to +compatibility reasons (in the case of native plugins, separate 32- and +64-bit builds are necessary; native plugins do not run on Unix-like +systems; etc.).

+ +
+ + +

+PLGX Files

+ +

PLGX is an optional plugin file format for KeePass ≥ 2.09. +Instead of compiling your plugin to a DLL file, the plugin source code +files can be packed into a PLGX file and KeePass will compile the plugin +itself when loading it.

+ +

One advantage of the PLGX approach is a strong compatibility detection. +In the case of a DLL plugin, an incompatibility (caused by an API +change within KeePass) is detected by the runtime when the plugin tries +to call/access the method/class, not at loading time. +So, an incompatibility is detected late and might crash KeePass. +In contrast, when using the PLGX format, an incompatibility is +detected immediately at loading time: if there is a problem, the +compile process fails and KeePass can show an informative +plugin incompatibility message to the user. +For DLL plugins, KeePass performs an own compatibility check, +which does not detect all incompatibilities though; +PLGX is far superior here.

+ +

Another advantage of the PLGX approach is compatibility with +custom KeePass builds. +A DLL plugin references an official KeePass build, and unless there +is a change within KeePass that breaks the plugin, the plugin is +also compatible with all future KeePass builds that are compiled +with the same assembly signing key (strong name). +This applies to all operating systems. +Especially, a DLL plugin that does not use any Windows-specific +function works fine on Linux with a KeePass build from the +official portable ZIP package. +However, some Linux packages compile KeePass from the source code; +such builds are not signed at all or are signed with a different +assembly signing key and are thus incompatible with DLL plugins. +In contrast, PLGX plugins are compatible with custom KeePass builds, +because KeePass can adjust the KeePass reference of the plugin +before compiling it.

+ +

For users, the procedure to install a DLL plugin is exactly the +same as for a PLGX plugin; both need to be copied into the 'Plugins' +folder.

+ +

Comparison.

+ + + + + + + + + + + + + + + + + + + + + +
 DLLPLGX
Compatibility checkNo Weak only.Yes Strong.
Compatibility with custom builds (Linux)No +Partial, see above.Yes
Authenticode signing supportYesNo
No compilation on the user's systemYesNo
No plugin cacheYesNo
+ +

So, both formats have unique advantages and disadvantages; +there is no "best" format.

+ +

Dual package. +You can ship a plugin both as a DLL and as a PLGX in one package +(e.g. 'SecretImporter.dll' and 'SecretImporter.plgx' within one folder). +KeePass will load the most appropriate file +(if KeePass has been signed with the official assembly signing key, +it will load the DLL, otherwise the PLGX). +If KeePass loads the DLL, the PLGX is ignored, which especially means +that only a weak compatibility check is performed (i.e. the strong +compatibility detection ensured by the PLGX is lost). +So, a dual package inherits the DLL disadvantages and is not +the "best" solution either.

+ +

Recommendation. +In any case, create a PLGX file (in order to ensure +compatibility with all KeePass builds). +If you think that the advantages of a DLL outweigh the risk +of an undetected compatibility problem, additionally provide +the plugin in DLL form.

+ +

Creating PLGX files. +PLGX files can be created from plugin sources by calling KeePass.exe +with the --plgx-create command line option. If you additionally +pass a path to the plugin sources directory (without terminating separator), +KeePass will use this one; otherwise +it'll show a folder browser dialog to allow you selecting the directory. If +you want to pass the directory location using the command line, make sure that +you're specifying a full, absolute path; relative paths will not work.

+ +

In order to keep the size of the PLGX file small, it is recommended +that you clean up the plugin sources directory before compiling the PLGX. +Remove all unnecessary binary files (files in the bin +and obj directory); especially, delete any plugin assembly DLL +that you compiled yourself. Temporary files by the IDE +(like .suo and .user files) +can also be deleted.

+ +

PLGX features.

+ + +

PLGX limitations.

+ + +

Defining prerequisites. You can optionally specify a minimum +KeePass version, a minimum installed .NET Framework, an operating system and +the minimum size of a pointer (x86 vs. x64) using the +--plgx-prereq-kp:, --plgx-prereq-net:, +--plgx-prereq-os: and --plgx-prereq-ptr: +command line options. If one of the plugin prerequisites isn't met, KeePass shows a detailed +error message to the end-user (instead of a generic plugin incompatibility +message). Build example:
+KeePass.exe --plgx-create C:\YourPluginDir --plgx-prereq-kp:2.09 +--plgx-prereq-net:3.5

+ +

Valid operating system values are Windows and Unix. +When running on an unknown operating system, KeePass defaults to Windows. +Pointer sizes (checking for x86 vs. x64) are specified in bytes; for example, +to only allow running on x64, you specify --plgx-prereq-ptr:8.

+ +

Build commands. Optionally you can specify pre-build +and post-build commands using --plgx-build-pre: and +--plgx-build-post:. These commands are embedded in the PLGX file +and executed when compiling the plugin on the end-user's system.

+ +

In the build commands, the placeholder {PLGX_TEMP_DIR} +specifies the temporary directory (including a terminating separator), +to which the files were extracted. In the post-build command, {PLGX_CACHE_DIR} +is replaced by the cache directory of the plugin (including a terminating +separator), into which the generated assembly was stored.

+ +

These build commands can for example be used to copy additional files into +the cache directory. Example:
+KeePass.exe --plgx-create C:\YourPluginDir +--plgx-build-post:"cmd /c COPY """{PLGX_TEMP_DIR}MyFile.txt""" +"""{PLGX_CACHE_DIR}MyFile.txt""""

+ +

In order to specify a quote character on the command line, it has +to be encoded using three quotes (this is Windows standard, see + +MSDN: SHELLEXECUTEINFOW). So, the command +line above will actually embed the post-build command +cmd /c COPY "{PLGX_TEMP_DIR}MyFile.txt" +"{PLGX_CACHE_DIR}MyFile.txt" +into the PLGX, which is correct. +It is highly recommended to surround paths including PLGX placeholders +using quotes, otherwise the command will not run correctly if the +path contains a space character (which happens very often).

+ +

If you need to run multiple commands, write them into a batch file and +execute it (with cmd). If you need to perform more complex +build tasks, write an own building executable and run it using the build +commands (typically it is useful to pass the directory locations as arguments +to your building executable), for example:
+KeePass.exe --plgx-create C:\YourPluginDir +--plgx-build-post:"{PLGX_TEMP_DIR}MyBuild.exe {PLGX_TEMP_DIR} {PLGX_CACHE_DIR}"

+ +

PLGX debugging. +When the command line option --debug is +passed and a PLGX plugin fails to compile, the output of all +tried compilers is saved to a temporary file.

+ + + diff --git a/src/Docs/Chm/help/v2_dev/scr_index.html b/src/Docs/Chm/help/v2_dev/scr_index.html new file mode 100644 index 0000000..4424d2b --- /dev/null +++ b/src/Docs/Chm/help/v2_dev/scr_index.html @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Scripting KeePass (2.x) - KeePass + + + + + + + + + + + + +

Scripting KeePass (2.x)

+

How to automate database operations in KeePass 2.x.

+ +

Prerequisites:

+ +

In order to automate KeePass, you need the KPScript plugin/extension. +You can find the latest version of KPScript on the KeePass plugins +web page. +The KPScript.exe file needs to be copied into the directory +where KeePass is installed (where the KeePass.exe file is).

+ +
+ +

There are two ways to automate KeePass: single command operations +and KPS script files.

+ + + + + diff --git a/src/Docs/Chm/help/v2_dev/scr_kps_index.html b/src/Docs/Chm/help/v2_dev/scr_kps_index.html new file mode 100644 index 0000000..6677f1f --- /dev/null +++ b/src/Docs/Chm/help/v2_dev/scr_kps_index.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + KPS Script Files - KeePass + + + + + + + + + + + + +

KPS Script Files

+

How to use KPS script files to automate KeePass 2.x.

+ +

KPS script files are a lot more powerful than single command operations, +but are also more complicated. You need +to have heavy experience in C# programming and the KeePass 2.x internals. +Within KPS files you can do everything that KeePass does.

+ +

What are KPS files?

+ +

KPS files are C# files that are loaded, +compiled and executed by the KPScript.exe program. +Within the script file, you got full access to the KeePass internals.

+ +

The main differences to "normal" C# files are:

+ + + +

Here's the famous Hello World program as KPS script:

+ +
public static void Main()
+{
+	MessageService.ShowInfo("Hello World!");
+}
+ +

For the most important namespaces, KPScript automatically adds +using directives at the start of the file before compiling it. +MessageService for example is located in KeePassLib.Utility, +but as it's included automatically by KPScript, you can use it directly.

+ +
+ +

Executing a KPS file:

+ +

To run a KPS file, you simply pass it to KPScript:

+ +
KPScript.exe C:\KeePass\MyScriptFile.kps
+ +

It is important that the file extension is .kps, otherwise KPScript won't +recognize the file and will interpret it as database for single command operations.

+ + + diff --git a/src/Docs/Chm/help/v2_dev/scr_sc_index.html b/src/Docs/Chm/help/v2_dev/scr_sc_index.html new file mode 100644 index 0000000..5615a44 --- /dev/null +++ b/src/Docs/Chm/help/v2_dev/scr_sc_index.html @@ -0,0 +1,493 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Single Command Operations - KeePass + + + + + + + + + + + + + +

Single Command Operations

+

How to use KPScript with single command operations to perform simple +database operations.

+ +

KPScript can be invoked using single commands. By passing the database location, +its key, a command and eventually some parameters, simple operations like adding +an entry can be performed. The syntax is very simple, no scripting knowledge is +required. This method is ideal when you quickly want to do some small changes to +the database. It is not recommended when you need to perform many operations, because +for each command the database needs to be loaded from file, decrypted, modified, +encrypted and written back to file.

+ +

Commands are specified by passing -c:COMMAND to KPScript, where COMMAND +is the command to execute (see below for a list of available commands).

+ +

The database location is passed to KPScript by just passing it as a parameter, +without any option prefix.

+ +
+ + +

+Master Key

+ +

The master key for the database can be passed to KPScript +using one of the following ways:

+ + + +
+ + +

+Available Commands

+ +

Please note that commands are added incrementally based on user requests. If you are +missing a command, please let the KeePass team know and it will be added to the +next release of KPScript.

+ +

Currently, the following commands are available:

+ + +
+
+ +

Command: ListGroups

+ +

This command lists all groups in a format that easily machine-readable. The output +is not intended to be printed/used directly. Usage example:

+ +

KPScript -c:ListGroups "C:\KeePass\MyDb.kdbx" -pw:MyPassword
+This will list all groups contained in the MyDb.kdbx database file.

+ +
+
+ +

Command: ListEntries

+ +

This command lists all entries in a format that easily machine-readable. The output +is not intended to be printed/used directly. The entry identification +syntax is exactly the same as in the EditEntry command. +Usage example:

+ +

KPScript -c:ListEntries "C:\KeePass\MyDb.kdbx" -pw:MyPassword +-keyfile:"C:\KeePass\MyDb.key"
+Opens the MyDb.kdbx database using 'MyPassword' as password and the MyDb.key file as key file. +It will output a list of all entries contained in the MyDb.kdbx database file.

+ +
+
+ +

Command: GetEntryString

+ +

Retrieves the value of an entry string field. The entry identification syntax +is exactly the same as in the EditEntry command. +Additional command line parameters:

+ + +

Usage example:

+ +

KPScript -c:GetEntryString "C:\KeePass\MyDb.kdbx" -pw:MyPassword +-Field:UserName -ref-Title:"Demo Account"
+Opens the MyDb.kdbx database using 'MyPassword' as password. +It outputs the user names of all entries that have the title +"Demo Account".

+ +
+
+ +

Command: AddEntry

+ +

This command adds an entry to the database. To specify the entry details, use the +standard string field identifiers as parameter names and their values for the contents. +Supported standard string fields are: Title, UserName, Password, URL, and Notes. +Usage examples:

+ +

KPScript -c:AddEntry "C:\KeePass\MyDb.kdbx" -pw:MyPw -Title:"New entry title"

+ +

KPScript -c:AddEntry "C:\KeePass\MyDb.kdbx" -pw:MyPw -Title:SomeWebsite +-UserName:Don -Password:pao5j3eg -URL:https://example.com/

+ +

Additional command line parameters:

+ + +

Usage example:

+ +

KPScript -c:AddEntry "C:\KeePass\MyDb.kdbx" -pw:MyPw -Title:"My Provider" +-GroupName:"Internet Sites"

+ +
+
+ +

Command: EditEntry

+ +

This command edits existing entries.

+ +

Use one or more of the following parameters to identify the entries +to be edited; all of the specified conditions must match:

+ + +

Use one or more of the following parameters to specify how the +entry should be edited:

+ + +

Usage examples:

+ +

KPScript -c:EditEntry "C:\KeePass\MyDb.kdbx" -pw:MyPw -ref-Title:"Existing +entry title" -set-UserName:"New user name"

+ +

KPScript -c:EditEntry "C:\KeePass\MyDb.kdbx" -pw:MyPw -ref-UserName:MyName +-set-UserName:NewName -set-Password:"Top Secret"

+ +

If you additionally pass -CreateBackup, KPScript will +first create backups of entries before modifying them.

+ +
+
+ +

Command: MoveEntry

+ +

This command moves one or more existing entries. The entry identification +syntax is exactly the same as in the EditEntry command.

+ + + +
+
+ +

Command: DeleteEntry

+ +

This command deletes one or more existing entries. The entry identification +syntax is exactly the same as in the EditEntry command.

+ +
+
+ +

Command: DeleteAllEntries

+ +

This command deletes all entries (in all subgroups).

+ +
+
+ +

Command: Import

+ +

This command imports a file into the database.

+ + + +

Usage example:

+ +

KPScript -c:Import "C:\KeePass\MyDb.kdbx" -pw:MyPw -Format:"KeePass XML (2.x)" -File:SourceFile.xml

+ +
+
+ +

Command: Export

+ +

This command exports (parts of) the database.

+ + + +

Usage example:

+ +

KPScript -c:Export "C:\KeePass\MyDb.kdbx" -pw:MyPw -Format:"KeePass XML (2.x)" -OutFile:TargetFile.xml

+ +
+
+ +

Command: Sync

+ +

This command synchronizes the database with another one. +The other database path has to be specified using the +"-File" command line parameter. Usage example:

+ +

KPScript -c:Sync -guikeyprompt "C:\Path\A.kdbx" -File:"C:\Path\B.kdbx"

+ +
+
+ +

Command: ChangeMasterKey

+ +

This command changes the master key of the database. +The new key values are specified using the standard +options prefixed with 'new', i.e. -newpw:, -newkeyfile: +and -newuseraccount (all are optional). Usage example:

+ +

KPScript -c:ChangeMasterKey "C:\KeePass\MyDb.kdbx" -pw:MyPw -newpw:MyNewPw

+ +
+
+ +

Command: DetachBins

+ +

This command saves all entry attachments (into the directory of the database) +and removes them from the database. + +Usage example:

+ +

KPScript -c:DetachBins -guikeyprompt "C:\KeePass\MyDb.kdbx"

+ +
+
+ +

Command: GenPw

+ +

Generates passwords.

+ + + +

Usage examples:

+ +

KPScript -c:GenPw
+Generates one password using the default generator profile.

+ +

KPScript -c:GenPw -count:5 -profile:"Hex Key - 128-Bit (built-in)"
+Generates five 128-bit hex passwords (when no translation is used).

+ +
+
+ +

Command: EstimateQuality

+ +

Estimates the quality (in bits) of the password specified via the +-text: parameter. +Usage example:

+ +

KPScript -c:EstimateQuality -text:MyTopSecretPassword

+ +
+ + +

+Console Character Encoding

+ +

If you observe garbled special characters in the output, please read the page +Console +Character Encoding.

+ + + diff --git a/src/Docs/Chm/images/back.gif b/src/Docs/Chm/images/back.gif new file mode 100644 index 0000000..1a86442 Binary files /dev/null and b/src/Docs/Chm/images/back.gif differ diff --git a/src/Docs/Chm/images/osi_certified_72x60.gif b/src/Docs/Chm/images/osi_certified_72x60.gif new file mode 100644 index 0000000..aacec25 Binary files /dev/null and b/src/Docs/Chm/images/osi_certified_72x60.gif differ diff --git a/src/Docs/Chm/screenshots/keepass_2x/gencsvimp.png b/src/Docs/Chm/screenshots/keepass_2x/gencsvimp.png new file mode 100644 index 0000000..fbe4dc6 Binary files /dev/null and b/src/Docs/Chm/screenshots/keepass_2x/gencsvimp.png differ diff --git a/src/Docs/Chm/screenshots/keepass_2x/main.jpg b/src/Docs/Chm/screenshots/keepass_2x/main.jpg new file mode 100644 index 0000000..8b4a664 Binary files /dev/null and b/src/Docs/Chm/screenshots/keepass_2x/main.jpg differ diff --git a/src/Docs/Chm/screenshots/windows_vista/comboboxform.png b/src/Docs/Chm/screenshots/windows_vista/comboboxform.png new file mode 100644 index 0000000..6d49bdf Binary files /dev/null and b/src/Docs/Chm/screenshots/windows_vista/comboboxform.png differ diff --git a/src/Docs/Chm/screenshots/windows_vista/pickchars.png b/src/Docs/Chm/screenshots/windows_vista/pickchars.png new file mode 100644 index 0000000..b6bee2a Binary files /dev/null and b/src/Docs/Chm/screenshots/windows_vista/pickchars.png differ diff --git a/src/Docs/Chm/screenshots/windows_vista/readonlymode.png b/src/Docs/Chm/screenshots/windows_vista/readonlymode.png new file mode 100644 index 0000000..652b629 Binary files /dev/null and b/src/Docs/Chm/screenshots/windows_vista/readonlymode.png differ diff --git a/src/Docs/Chm/screenshots/windows_vista/syncorsave.png b/src/Docs/Chm/screenshots/windows_vista/syncorsave.png new file mode 100644 index 0000000..669d23c Binary files /dev/null and b/src/Docs/Chm/screenshots/windows_vista/syncorsave.png differ diff --git a/src/Docs/History.txt b/src/Docs/History.txt new file mode 100644 index 0000000..18fef01 --- /dev/null +++ b/src/Docs/History.txt @@ -0,0 +1,4674 @@ +2023-01-09: 2.53 +- For each entry listed on the 'History' tab page of the entry + dialog, the fields modified with respect to the previous + entry are displayed +- Added 'Compare' button on the 'History' tab page of the entry + dialog; when two (not necessarily consecutive) history + entries are selected, clicking the button shows a detailed + comparison (with values, etc.) +- When editing an entry, the history entry list of the entry + dialog now contains an entry called 'Dialog (unsaved)', which + represents all data entered in the current dialog (other tab + pages) +- When editing an entry, the history entry list of the entry + dialog now contains an entry called 'Current (TIME)', which + is the entry that is currently stored in the database + (without any changes made in the current dialog) +- Added 'History' command in the 'Find' main menu; it lists all + entry modifications (sorted by time) +- Added filter box in most report dialogs (last modified + entries, history, large entries, similar password clusters, + password quality, history entry comparison, database file + search, ...) +- Added 'Print' button in most report dialogs +- Added 'Export' button in most report dialogs; supported + formats are CSV and HTML +- Added {EDGE} placeholder, which is replaced by the executable + path of the new (Chromium-based) Microsoft Edge, if installed +- Added URL override suggestion for Microsoft Edge in private + mode in the URL override suggestions drop-down list of the + entry dialog +- Added optional built-in global URL overrides for opening + HTTP/HTTPS URLs with Microsoft Edge in private mode +- When trying to rearrange entries while automatic sorting is + activated, KeePass now asks whether to deactivate automatic + sorting +- Added access keys in the tags button drop-down menu of the + entry/group dialogs +- Added access keys in the 'View' -> 'Sort By' menu +- Added access keys in the entry templates menu +- Added access keys in the 'Perform Auto-Type' menu (which is + displayed if the 'Show additional auto-type menu commands' + option is turned on) +- Added {HMACOTP} and {TIMEOTP} in the 'Perform Auto-Type' menu +- Added keyboard shortcut Ctrl+T for the 'Copy Time-Based OTP' + entry data command +- Added keyboard shortcut Ctrl+Shift+T for the 'Show Time-Based + OTP' entry data command +- Enhanced Password Depot XML import module to support the new + format (added support for the new node names, group icons, + recycle bin, tags, favorites, auto-type delay conversion, + history, enhanced icon mapping, enhanced date/time parsing, + ...) +- Added border for headings in HTML exports/printouts +- Added support for running KeePass in FIPS mode + +- History entries listed on the 'History' tab page of the entry + dialog are now sorted from newest to oldest +- The icons in the list on the 'History' tab page of the entry + dialog now indicate the type of the entry +- History entry controls of the entry dialog are now disabled + when creating a new entry +- The history entry 'Restore' button is now disabled when any + change has been made in the current dialog +- The 'Password modified' time is now updated immediately when + deleting a history entry +- Improved URL override suggestion for Microsoft Edge in the + URL override suggestions drop-down list of the entry dialog + (changed from 'microsoft-edge:{URL}' to 'cmd://{EDGE} + "{URL}"') +- Improved optional built-in global URL overrides for opening + HTTP/HTTPS URLs with Microsoft Edge (changed from + 'microsoft-edge:{BASE}' to 'cmd://{EDGE} "{BASE}"') +- Reordered web browser URL overrides alphabetically +- Improved dynamic menu item access key assignment +- Improved item separation in the entry details view +- In most places, groups in a group path are now separated by + right arrows instead of hyphens +- Improved last modification time comparison for plugin data + dictionaries +- Unified generation of common HTML parts +- The 'Copy Initial Password' command in the 'Tools' menu of + the entry dialog now requires the 'Copy' application policy + flag +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- The history entry 'Restore' button now always works as + expected + +2022-09-09: 2.52 +- Added 'Copy Initial Password' command in the tools menu of + the entry dialog; it copies (to the clipboard) the password + that was current when the dialog was opened +- When multiple entries are selected (containing at least one + attachment), the number of attachments is now displayed in + the 'Attachments' submenu of the entry menu +- Added option 'Alt. item background color' (supporting the + states 'Off', 'On, default color' and 'On, custom color'); + this combines the previous two options 'Use alternating item + background colors' and 'Custom alt. item color' +- Comment placeholders ({C:...}) may now contain balanced + braces +- In the auto-type entry selection dialog, values in the + 'Sequence - Comments' column are dereferenced now +- The time when the password of an entry was last changed is + now displayed in the entry dialog on the 'History' tab page +- The {FIREFOX} placeholder and the 'URL(s)' menu ('Open with + ...' commands) now support detecting the Microsoft Store + version of Firefox (in addition to the regular versions) +- Added support for importing 1Password 8.7 1PUX files +- Added support for importing Key Folder 1.22 XML files +- Sticky Password XML import: added support for importing + groups and expiry dates +- Steganos Password Manager CSV import: added support for the + new encoding of double quotes +- Bitwarden JSON import: time-based one-time password generator + settings are converted automatically now +- KeePass now checks the 'KeePass.exe.config' file and shows a + warning message when finding a problem +- For development builds: added command for showing GC + information +- Plugins can now load the header of a database file more + easily +- Plugins can now subscribe to a master key change event +- TrlUtil: added workaround for .NET tab control focus bug + +- Moved the command 'Save Attached File(s) To' into the + 'Attachments' submenu of the entry menu and renamed it to + 'Save File(s) To' +- The command for saving attached files is now available only + if at least one of the selected entries has at least one + attachment +- The {APPACTIVATE ...} auto-type command now ignores the + options 'Cancel auto-type when the target window changes' and + 'Cancel auto-type when the target window title changes' +- {APPACTIVATE ...} auto-type command: if the specified window + does not exist or cannot be focused, auto-type is aborted now +- Unified creation of fields with indices +- Improved database modification state and UI updating after + imports/synchronizations +- In the master key creation/prompt dialogs, the [OK] button is + now disabled when checking the 'Key file/provider' check box + and selecting '(None)' in the combo box +- Improved drop-down menu width adjustment for certain combo + boxes in the options dialog +- Improved hashing performance of protected binaries, UUIDs, + ... +- Performance improvements related to empty arrays +- Improved Mono framework version detection +- TrlUtil: improved preview dialog update performance +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- Fixed a bug that caused a minimized main window to be + restored to a normal window instead of a maximized window in + certain situations +- The 'Help' menu item in the entry dialog and the 'Help' + button in the entry string field dialog now open the correct + help sections + +2022-05-09: 2.51.1 +- The option 'Use alternating item background colors' is now + compatible with automatic sorting again +- Improved entry list update performance when duplicating + entries +- Fixed an entry list scrolling bug +- Minor other improvements + +2022-05-06: 2.51 +- Most dialogs with fixed size now detect whether they fit onto + the current screen, and when a dialog does not fit (e.g. due + to a very high DPI factor), its size is reduced and scroll + bars are displayed +- Added plural entry command names in the main window (e.g. the + command for editing the currently selected entry/entries is + now called either 'Edit Entry' or 'Edit Entries', depending + on the number of selected entries) +- Added tooltip for the main part of the status bar of the main + window +- Enhanced color buttons (tooltips, accessible names, ...) in + the entry dialog, in the database settings dialog and in the + options dialog +- Added 'Interface (2)' tab page in the options dialog, renamed + the existing 'Interface' tab page to 'Interface (1)', moved + some controls from 'Interface (1)' to 'Interface (2)' +- Enhanced font selection controls (with a checkbox that allows + to return to the default, the button shows the currently + selected font, tooltip, improved accessibility, ...) in the + options dialog +- Added help links 'Dark theme' and 'Main font (size)' in the + options dialog +- The options 'Custom alt. item color' and 'Esc keypress in + main window' are now disabled if they are enforced (by an + enforced configuration file) +- Added support for opening URLs with Waterfox in private mode +- Added dialog for editing (HMAC-based and time-based) one-time + password generator settings (can be opened using the 'OTP + Generator Settings' commands in the entry dialog or in the + 'Edit Entry (Quick)' menu of the main window) +- Added entry commands 'Copy HMAC-Based OTP', 'Show HMAC-Based + OTP', 'Copy Time-Based OTP' and 'Show Time-Based OTP' (in the + 'Other Data' menu) +- Added entry commands 'Copy Title' and 'Copy Notes' (in the + 'Other Data' menu) +- When switching to the 'Generate' tab page of the password + generator dialog (no database open), the entropy collection + dialog is displayed now, if the option 'Show dialog for + collecting user input as additional entropy' is turned on +- Added option 'Colorize password characters' in the HTML + export/print dialog; the colors are customizable +- Added options 'Custom main font' and 'Custom password font' + in the HTML export/print dialog +- Added horizontal entry separator lines in tabular HTML + exports/printouts +- In the plugins dialog, the 'Delete old files from cache + automatically' option and the 'Clear' button are now disabled + if they are enforced (by an enforced configuration file) +- Plugins can now change the expiry date of an entry more + easily +- Added workaround for Wine bug 52457 + +- Improved main window initialization performance +- Improved initial emergence of a minimized or maximized main + window (less flickering, improved performance, ...) +- Improved names/tooltips of the database toolbar buttons in + the main window +- Improved handling of bold/italic list fonts +- Improved entry list update performance in certain situations +- Improved dynamic menu deconstruction performance +- Fields starting with 'HmacOtp-' or 'TimeOtp-' are not shown + in the entry string copy menu anymore +- Improved tooltips and accessibility of password repetition + text boxes +- When a dark theme is active, the error background color of + text boxes is darker now +- Improved accessibility of expiry control groups +- The title of the master key creation/change dialog is now + adjusted to the context +- Improved 'Compression' tab page of the database settings + dialog (extended 'None' option description, improved + accessibility, ...) +- If no color has been specified, the 'Custom alt. item color' + button in the options dialog now shows the default color +- Improved HTML generation for HTML exports/printouts +- Improved default fonts used when printing or exporting to + HTML +- In block HTML exports/printouts, field names are not italic + anymore (unless the user has selected an italic main font) +- In HTML exports/printouts, all field values except passwords + are trimmed now +- HTML exports/printouts: improved encoding of white-space + characters in passwords +- Improved horizontal entry separator lines in block HTML + exports/printouts +- TrlUtil: improved control classification +- Increased Authenticode certificate key length +- Various CHM/help improvements +- Upgraded installer +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- The command line parameter '-preselect:' now works as + expected when the option 'Clear master key command line + parameters after using them once' is turned on +- Font selections in the options dialog are now applied only + when closing the dialog with [OK] + +2022-01-09: 2.50 +- On most Windows systems, AES-KDF is now about twice as fast + as before +- On most Linux systems, AES-KDF is now about 4 times as fast + as before, if the 'libgcrypt' library is installed +- On most Windows systems, Argon2d and Argon2id are now about + twice as fast as before (for default parameters) +- On most Linux systems, Argon2d and Argon2id are now about 3 + times as fast as before (for default parameters), if the + 'libargon2' library is installed +- The option 'Enter master key on secure desktop' is now also + supported by master key prompt dialogs shown during imports, + confirmations (before exporting, printing, changing the + master key, ...) and trigger actions +- The option 'Enter master key on secure desktop' is now also + supported by master key creation/change dialogs +- The key file/provider combo boxes in the master key dialogs + now have a tooltip that shows the current value, if the value + is very long +- When running on .NET 4.7.2 or higher, GZip decompression is + faster now (i.e. most databases are opened a bit faster, + pasting entries from the clipboard is a bit faster, ...) +- Added password generation button in the entry string field + dialog +- When double-clicking the title cell of an entry in the main + entry list while holding down the Shift key, the title is now + copied to the clipboard +- Added support for opening URLs with Pale Moon, Epiphany and + Midori in private mode +- Enhanced application detection on Unix-like systems (support + for certain Snap packages, ...) +- Added support for detecting the latest versions of Chromium + on Unix-like systems (for 'Open with ...' commands in the + 'URL(s)' menu, for the {GOOGLECHROME} placeholder, ...) +- In the 'URL(s)' menu, there now are separate commands for + Google Chrome and Chromium, if both are installed +- Enhanced support for detecting Vivaldi, Brave, Pale Moon and + Epiphany +- Added support for importing Kaspersky Password Manager 9.0.2 + TXT files +- Bitwarden import module: added support for importing + subfolders, and collection names are now imported as tags +- In the 'About KeePass' dialog, each item in the components + list now has a tooltip that shows the file/folder path of the + component, if it is installed +- In the 'About KeePass' dialog, a double-click onto a + component now shows the component file/folder with the file + manager +- In the 'About KeePass' dialog, the components list now has a + context menu that provides the following new commands: 'Show + with File Manager', 'Copy Version/Status' and 'Copy Path' + +- If the option 'An entry matches if one of its tags is + contained in the target window title' is turned on, auto-type + now additionally considers tags inherited from groups +- The built-in password generation patterns 'Hex Key - *-Bit' + now use upper-case hexadecimal symbols +- Improved Spr variance check of the password generator (custom + string references, ...) +- All commands in the password generator menu (shown by the + password generator buttons in entry/string dialogs) support + the option 'Show dialog for collecting user input as + additional entropy' now +- Improved entropy collection dialog +- Improved control state updating in the master key prompt + dialog and in the master key creation/change dialog +- Improved key file existence check in the master key + creation/change dialog +- Improved master key construction +- Improved handling of exclusive key providers +- Improved compatibility of some dialogs with plugins that can + cancel closing the dialog +- Improved automatic entry selections in the main entry list +- Access key improvements +- Improved entry equality test in order to prevent the creation + of unnecessary history entries during certain operations +- XML Replace: improved entry modification detection +- Improved initial input focus in the single edit dialog +- In the import/export dialog, the icon of an import/export + module now matches the file/procedure type +- DataVault CSV import module: improved importing of notes +- Improved native buffer handling +- When opening/copying the URL of an entry, the last access + time of the entry is updated now +- TrlUtil: added DPI awareness mode declaration +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- Column header context menus are not shown for non-report list + views anymore +- When copying a URL to the clipboard fails, the main entry + list is updated now +- Toggling the password generator option 'Show dialog for + collecting user input as additional entropy' now causes a + switch to the '(Custom)' profile +- In the TAN wizard dialog, group names containing ampersands + are displayed correctly now + +2021-09-10: 2.49 +- Added dedicated context menu for custom string fields in the + entry dialog, which provides the following new commands: + 'Copy Name(s)', 'Copy Value(s)', 'Copy Item(s)', 'Paste + Item(s)', 'Select All' and 'Move To' +- Added button 'More' to the right of the custom string fields + list in the entry dialog, which shows the context menu +- Added dedicated context menu for auto-type associations in + the entry dialog, which provides the following new commands: + 'Copy Target Window(s)', 'Copy Sequence(s)', 'Copy Item(s)', + 'Paste Item(s)', 'Duplicate Item(s)' and 'Select All' +- Added button 'More' to the right of the auto-type + associations list in the entry dialog, which shows the + context menu +- Added optional 'Auto-Type - Enabled' main entry list column + (turned off by default, can be turned on in 'View' -> + 'Configure Columns') +- Added optional 'Auto-Type - Sequences' main entry list column + (turned off by default, can be turned on in 'View' -> + 'Configure Columns') +- Added support for importing Keeper 16.0.0 JSON files +- Added option 'Show confirmation dialog when opening a + database file whose minor format version is unknown' (in + 'Tools' -> 'Options' -> tab 'Interface', turned on by + default) +- Added tooltips for some controls +- Dialog banners can now be read by screen readers (if the + option 'Optimize for screen reader' is turned on) +- Added accessibility names for some controls (text boxes after + check boxes, image/color buttons, warning icons, ...; if the + option 'Optimize for screen reader' is turned on) +- Controls in the accessibility/automation control tree are now + ordered by their visual locations (if the option 'Optimize + for screen reader' is turned on) +- Added automatic screen reader detection based on the + operating system's screen reader parameter (this does not + make the option 'Optimize for screen reader' obsolete though, + because not all screen readers set the parameter) +- Various accessibility enhancements (when running on .NET + 4.7.1 or higher) +- Added UIFlags bit for not clearing the quick search terms + list when closing/locking a database +- Added UIFlags bit for enabling the Input Method Editor (IME) + on secure desktops +- Added customization option to override the URL that is opened + for a help page + +- In most list views, tooltips are now displayed for a longer + time +- The entry string move commands can now move multiple strings + at once +- Removed the entry string button 'Move' in the entry dialog + (the move commands are available in the context menu) +- Reordered fields/columns in the entry details view and in the + 'Configure Columns' dialog for improved consistency with the + entry dialog +- When running on .NET 4.7 or higher, rich text boxes now + instantiate Rich Edit 4.1 (or higher) controls, which support + various new features (e.g. Tamil characters are now displayed + correctly even when the 'Latha' font is not installed) +- Improved linkification in the entry details view of the main + window (URLs, attachments, ...) and in the internal data + viewer (URLs) +- URLs in the hex view of the internal data viewer are not + linkified anymore +- Improved tab order in various dialogs +- Improved accessibility control name provision +- Improved temporary file/directory deletion performance +- Improved hashing of protected binaries, UUIDs, popular + passwords, images, ... +- Improved quality of some icons +- In the HTML export/printing dialog, the option 'Group name' + is now disabled when group names are unavailable +- Reduced space between tables and group headings in HTML + exports/printouts +- In the help source selection dialog, controls are now + disabled if a help source is enforced (by an enforced + configuration file) or if a help URL override is specified +- Improved keyboard shortcut check +- TrlUtil: improved string table handling +- Various CHM file improvements +- Upgraded installer +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- The save confirmation dialog of the entry dialog does not + create unnecessary history entries anymore +- The tags button drop-down menu in the entry/group dialogs now + uses the correct font +- TrlUtil: fixed a string table association bug + +2021-05-10: 2.48.1 +- Improved compatibility with certain plugins/ports +- In the main entry list, new-line characters in text inserted + by a placeholder are now filtered +- Minor other improvements + +2021-05-07: 2.48 +- New KDBX 4.1 file format, which supports various new features + (listed below) +- Added support for group tags (KDBX 4.1) +- In the entry/group dialogs, there now is a button to show a + menu for adding/removing existing tags +- If an entry/group inherits a tag from a parent group, a link + is displayed in the entry/group dialog to show the parent + groups and their tags +- Added option in the entry dialog for disabling/enabling the + password quality estimation for the current entry (KDBX 4.1) +- If the password quality estimation is disabled for an entry, + the entry is now excluded from password quality reports (menu + 'Find' -> 'Password Quality') +- When moving an entry/group into a different group (e.g. into + the recycle bin), the previous parent group is remembered now + (KDBX 4.1, not enforcing) +- Added command 'Move to Previous Parent Group' (in the + 'Rearrange' popup menu; if the command will move all selected + entries/groups out of the recycle bin, a '(Restore)' suffix + is appended to the command name; if at least one entry/group + will be moved into/within the recycle bin, a confirmation + dialog is displayed) +- Renaming a list view item (if supported, e.g. a file attached + to an entry) can now be initiated by pressing the F2 key +- Each custom icon may now have a name, and its last + modification time is remembered (KDBX 4.1) +- In the icon picker dialog, a custom icon can now be renamed + (click on an already selected name or press the F2 key) +- In the icon picker dialog, the dimensions and the size of a + custom icon are now displayed in a tooltip +- The UUID and the deletion time of a deleted custom icon are + remembered now, and this information is used in order to + delete the custom icon during a synchronization (if the last + modification time is older than the deletion time) +- Added built-in URL override for associating the 'ssh' URL + scheme with 'SSH.exe' (OpenSSH, included in Windows 10; + activatable/deactivatable in 'Tools' -> 'Options' -> tab + 'Integration' -> button 'URL Overrides') +- Added support for loading images with Exif orientation tags +- Enhanced the LastPass import module to support CSV files + created by the latest versions +- Enhanced the nPassword import module to import group tags +- The last modification time of a database-specific custom data + item (by a plugin/port) is now saved (KDBX 4.1) +- When synchronizing databases, database-specific custom data + items (by plugins/ports) are now merged based on their last + modification times +- Added support for loading KDBX 4 files created by other + applications that do not perform a binary content + deduplication +- Added workaround for .NET/Windows TopMost/WS_EX_TOPMOST + desynchronization bug + +- Various user interface improvements in the group dialog + (moved the notes box to the first tab page, moved the auto- + type behavior option to the auto-type tab, ...) +- Tags are sorted naturally now +- Improved tag handling performance +- Various user interface improvements in the icon picker dialog +- The temporary icon that represents multiple icons (when + editing multiple entries at once) is now named '(Multiple + values)' +- Improved custom icon handling performance +- The placeholders {HMACOTP} and {TIMEOTP} now automatically + add padding to shared secrets in Base32 encoding, if + necessary +- Improved error handling of the placeholders {HMACOTP} and + {TIMEOTP} +- Internal data viewer/editor: '*.asc', '*.tab' and '*.tsv' + files are now treated as text files by default +- The internal data viewer now does not try to display non-HTML + files using the web browser control anymore +- Improved error handling of the Bitwarden JSON and nPassword + NPW import modules +- Improved merging of custom data items (by plugins/ports) in + the KDBX file header +- Improved image hashing +- Improved version display in the 'About' dialog +- Installer: improved file overwriting +- On 64-bit operating systems, the registry value for the setup + option 'Optimize KeePass start-up performance' is now created + in the 64-bit view of the registry +- ShInstUtil now fully supports Unicode +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- The command 'Delete Unused Custom Icons' does not delete + icons anymore that are still used by history entries + +2021-01-09: 2.47 +- In the 'Find' dialog, search parameters can now be saved as + profiles; the profiles can be accessed quickly via the main + menu ('Find' -> 'Search Profiles') and the group context menu +- Added search mode 'XPath expression' in the 'Find' dialog, + which creates a KeePass 2.x XML DOM of the current database + in memory and finds entries using the specified XPath + expression +- Added option 'History' in the 'Find' dialog, which includes + history entries in searches +- Added 'Help' button in the 'Find' dialog +- Added auto-type matching option 'Consider similar dashes as + identical' (in 'Tools' -> 'Options' -> tab 'Advanced', turned + on by default) +- Added commands 'Copy Group (Encrypted)', 'Copy Group + (Unencrypted)' and 'Paste Group' (in the menu 'Group' -> + 'Data Exchange') +- When loading/saving a configuration file fails, an error + message is displayed now, and in certain cases a backup of + the configuration file is created (the path is mentioned in + the error message) +- Added configuration option for saving the configuration + (turned on by default) +- On the 'Security' tab page of the options dialog, two links + have been added, which open help pages for experts and + administrators +- Added {TIMEOTP} placeholder, which generates a time-based + one-time password (as specified in RFC 6238) +- Enhanced XML key file format (added hash that allows to + verify the integrity of the key; values are now encoded using + hexadecimal characters in order to improve the readability) +- Added command 'Print Key File Backup' (in 'File' -> 'Print') +- In the dialog that asks whether to print an emergency sheet, + there is now an option 'Also print a key file backup' (on + Windows), if the master key contains a key file +- Added command 'Create Key File' (in 'Tools' -> 'Advanced + Tools'), which shows a dialog for creating a new key file + (random key) or for recreating a key file from a printed + backup +- Added Argon2id key derivation function +- Added support for importing Dashlane 6.2039.0 JSON files +- Dashlane and RoboForm import: domains are now mapped to HTTPS + URLs (instead of HTTP URLs) +- Added option 'Use a different master key' in the + import/export dialog (tab page 'Options') +- Added option 'Additionally export parent groups' in the + import/export dialog (tab page 'Options') +- Added options 'Open exported file (with associated + application)' and 'Show exported file (with file manager)' in + the import/export dialog (tab page 'Options') +- The 'About' dialog now shows whether KeePass is currently + running as 32- or 64-bit application +- Plugins can now disable/enable specific Mono workarounds +- Added workaround for Mono URL opening bug +- Added workaround for Mono HTML document opening bug + +- Improved performance of certain searches +- Various user interface improvements in the search dialog +- Improved keyboard shortcut handling (e.g. Ctrl+Tab and Ctrl+ + Shift+Tab now also work when the quick search box is focused) +- The local configuration file is now loaded only if necessary +- Improved performance of configuration saving +- Changed default key file extension from 'key' to 'keyx' +- Most key file dialogs now only show '*.keyx' and '*.key' + files by default +- When clicking the key file 'Browse' button in the master key + creation dialog and selecting a file that is not an XML key + file, KeePass now asks whether to use the file as key file + anyway +- Improved key file loading/saving error messages +- Various user interface improvements in the import/export + dialog +- The import/export dialog does not accept relative file paths + anymore +- The import/export dialog now shows an error message when + trying to export to multiple files +- Removed indeterminate progress indicators while displaying + the import/export dialog +- Improved field to standard field mapping function +- Moved command 'Empty Recycle Bin' directly below the 'Delete + Group' command +- Moved commands 'Print Group' and 'Export Group' into the + 'Data Exchange' popup menu +- Improved quality of some icons +- Improved dialog banner caching +- Improved performance of certain object collection operations +- History entry UUIDs are now fixed automatically +- Increased default value of Argon2 memory parameter +- Improved task dialog parent determination +- The setup program now installs KeePass into a folder in + 'C:\Program Files' by default (i.e. without '(x86)' suffix; + this is reasonable, because on a 64-bit operating system, + KeePass runs as 64-bit application) +- Upgraded installer +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- Search: regular expressions starting with a '-' are not + treated as exclusions anymore +- Fixed a bug that caused KeePass to hang when trying to read a + configuration file that contains certain unsupported nodes + +2020-09-10: 2.46 +- The entry editing dialog can now edit all currently selected + entries at once +- As entry attachment icons, the icons associated with the + respective file types (in the system settings) are used now +- When running on .NET 4.8 or higher, secure connections (e.g. + for WebDAV) now support TLS 1.3 +- Added keyboard shortcut Ctrl+* (numeric keypad) for the + 'Expand Recursively' group command +- Added keyboard shortcut Ctrl+/ (numeric keypad) for the + 'Collapse Recursively' group command +- Right-clicking on the header of the main entry list now shows + the 'Configure Columns' command +- The {VKEY ...} command now supports some flags (for + specifying whether to send a key down or up event only and/or + whether to send an extended key) +- Added configuration option for protecting KeePass windows + against certain screen capture operations +- Added command line parameter '-wa-enable:' for enabling + specific Mono workarounds +- On Unix-like systems with a Wayland compositor, KeePass (with + the KPUInput plugin) can now auto-type the default sequence + and manually selected sequences of the currently selected + entry + +- Improved quality of the icons in the entry 'URL(s)' menu +- Improved quality of the icons in the drop-down list of the + 'Override URL' field in the entry editing dialog +- Improved control state updating in the entry editing dialog +- The file selection dialog for the Generic CSV Importer now + shows only CSV, TSV, TAB, TXT and ASC files by default +- Improved user interface of the Generic CSV Importer +- For large texts containing probably invalid characters, the + internal data viewer now shortens the text and provides a + 'Show more' link for expanding the text; this ensures a + responsive user interface in this case +- Improved caching of dialog banners +- Moved the help source selection from the 'Help' main menu to + the options dialog (tab 'Integration') +- If the application policy option 'Export - No Key Repeat' is + turned off, the master key must now be entered directly + before the export is performed, i.e. after choosing the + format and the target +- The application policy option 'Export - No Key Repeat' now + also applies to the trigger action 'Export active database' +- When running on Mono, the options 'Focus quick search box + when restoring from taskbar' and 'Focus quick search box when + restoring from tray' are disabled now (because they do not + work reliably due to a bug in Mono) +- Various code optimizations +- Minor other improvements + +- The attachment button drop-down menus in the entry editing + dialog now use the correct font +- The 'Tools' button in the entry editing dialog is not + disabled for TAN entries anymore + +2020-05-07: 2.45 +- Added support for opening URLs with the new (Chromium-based) + Microsoft Edge in private mode +- Added support for opening URLs with Vivaldi in private mode +- Added automatic assignment of mnemonics for 'Open with ...' + commands in the 'URL(s)' menu +- The entry templates menu now supports showing templates that + are stored in subgroups of the templates group; each subgroup + is displayed as a submenu +- When adding a new entry based on a template that has an empty + user name, the user name is now set to the default user name + of the database, unless the new entry is stored in the + templates group +- When adding a new entry based on a template that has an empty + password, a random password is generated now (based on the + password generator profile 'Automatically generated passwords + for new entries'), unless the new entry is stored in the + templates group +- When adding a new entry based on a template that does not + expire, the expiry date is now set based on the option 'By + default, new entries expire in the following number of days' + (in 'Tools' -> 'Options' -> tab 'Security'), unless the new + entry is stored in the templates group +- New icon recoloring (with high DPI support, by deconstructing + an ICO, modifying BMP palettes and data, and assembling a new + ICO); there are 24 database colors now +- Added {UUID} placeholder, which is replaced by the UUID of + the current entry +- The UUID of a group is now displayed in the group editing + dialog (tab 'General') +- When specifying a weak master password in the master key + creation dialog, KeePass now shows a warning +- Triggers: added string comparison mode 'Matches regular + expression' +- Enforced configuration: added support for attributes that + allow to specify the desired merge behavior +- Enforced configuration: for most lists, node keys are now + used to find corresponding list items +- Plugins: added I/O connection event for customizing web + requests +- Added workaround for Mono pre-authenticated anonymous web + request bug + +- Auto-Type: improved compatibility with VMware Horizon Client + and Kaseya Live Connect +- Enhanced detection of Microsoft Edge +- The 'Open with ...' commands in the 'URL(s)' menu are sorted + now +- Improved performance of the entry templates menu; removed + limitation to 30 templates +- Database descriptions are now displayed in file tab tooltips +- When editing an attachment directly from the main window, a + history entry is created now +- UUIDs in the group and entry editing dialogs are now + displayed both in hexadecimal and base 64 form +- Improved Bitwarden import module to support JSON files + without groups +- If the trigger system is disabled using an enforced + configuration file, most controls in the triggers dialog are + disabled now, too +- Plugins: an I/O access event is now raised when checking the + existence of a local database file +- In texts that are about to be displayed in a rich text box, + U+FFFC characters are now replaced by question marks (in + order to avoid the text being cut off at this point) +- When running on Mono 5.10 or higher, a monospaced font is + used in password text boxes by default again, as the Mono bug + 5795 has been fixed +- Various code optimizations +- Minor other improvements + +- Fixed a default value type problem in the hot key + configuration settings +- Database file tab colors are now rounded to the nearest + supported colors + +2020-01-20: 2.44 +- Added option 'Use file transactions for writing configuration + settings' (turned on by default) +- If the option 'Do not store data in the Windows clipboard + history and the cloud clipboard' is turned on (which it is by + default), KeePass now additionally excludes its clipboard + contents from processing by Windows' internal + ClipboardMonitor component +- Added commands to find database files ('File' -> 'Open' -> + 'Find Files' and 'Find Files (In Folder)') +- Added 'Edit' menu in the internal text editor (including new + 'Select All' and 'Find' commands with keyboard shortcuts) +- Added keyboard shortcuts for formatting commands in the + internal text editor +- Added 'Cancel' button in the save confirmation dialog of the + internal text editor +- Added {CLIPBOARD} and {CLIPBOARD-SET:/T/} placeholders, which + get/set the clipboard content +- Added support for importing True Key 4 CSV files +- Added command line options for adding/removing scheme- + specific URL overrides +- Added an auto-type event for plugins +- When loading a plugin on a Unix-like system fails, the error + message now includes a hint that the 'mono-complete' package + may be required +- In order to avoid a Windows Input Method Editor (IME) bug + (resulting in a black screen and/or an IME/CTF process with + high CPU usage), KeePass now disables the IME on secure + desktops + +- Auto-Type: improved compatibility with VMware Workstation +- Auto-Type into virtual machines: improved compatibility with + certain guest systems +- The option to use the 'Clipboard Viewer Ignore' clipboard + format is now turned on by default +- Improved menu/toolbar item state updating in the internal + text editor +- Improved performance of Spr compilations +- Before writing a local configuration file whose path has been + specified using the '-cfg-local:' command line parameter, + KeePass now tries to create the parent directory, if it does + not exist yet +- Improved conversion of file URIs to local file paths +- Improved compatibility of the list view dialog with plugins +- If ChaCha20 is selected as file encryption algorithm, the + database is now saved in the KDBX 4 format (thanks to + AMOSSYS) +- Minor process memory protection improvements +- HTML export/printing: KeePass now generates HTML 5 documents + (instead of XHTML 1.0 documents) +- HTML export/printing: improved internal CSS +- HTML exports do not contain temporary content identifiers + anymore +- XSL files: HTML output now conforms to HTML 5 instead of + XHTML 1.0 +- XSL files: improved internal CSS +- CHM pages are now rendered in the highest standards mode + supported by Internet Explorer (EdgeHTML mode) +- Migrated most of the documentation from XHTML 1.0 to HTML 5 +- Various code optimizations +- Minor other improvements + +- In the internal text editor, the 'Delete' command does not + reset RTF text formattings anymore +- The KeyCreationFlags bit 2^19 (for hiding the passwords) now + works as intended + +2019-09-10: 2.43 +- Added tooltips for certain character set options in the + password generator dialog +- Added option 'Remember password hiding setting in the main + window' (in 'Tools' -> 'Options' -> tab 'Advanced'; the + option is turned on by default) +- Added yellow intermediate step in password quality progress + bars +- When the URL override field in the entry editing dialog is + not empty, but the URL field is empty, a warning is displayed + now +- When an explicit request to generate a password fails (for + instance due to an invalid pattern), an error message is + displayed now +- Added trigger events 'Synchronizing database file' and + 'Synchronized database file' +- Enhanced the Password Agent import module to support XML + files created by version 3 +- The 'MasterKeyExpiryRec' configuration setting can now also + be set to an XSD duration instead of an XSD date (for + periodic master key change recommendations) +- KeePass now excludes itself from Windows Error Reporting +- On Unix-like systems, file transactions now preserve the Unix + file access permissions, the user ID and the group ID +- Added workaround for .NET initial focus bug + +- Auto-Type: improved sending of modifier keys +- Auto-Type: improved sending of characters that are realized + with Ctrl+Alt/AltGr +- Auto-Type: improved compatibility with VMware Remote Console + and Dameware Mini Remote Control +- Improved main window state handling +- Improved construction and updates of the main menu and the + group/entry context menus +- Main menu items can now be deselected by pressing the Esc key +- Top-level nodes in tree views cannot be collapsed anymore if + no root lines are displayed +- New entries in a group with the e-mail folder icon now have + the e-mail icon by default +- Improved performance of automatic scrolling in the main entry + list +- If user names are hidden in the main window, no user name + suggestions are displayed in the entry editing dialog anymore +- Function keys without modifiers can be registered as system- + wide hot keys now +- For file rename/move web requests, a canonical representation + of the destination name/path is used now +- URL override base placeholders can now be used within + {CMD:...} placeholders +- Directly after an import, the deleted object information is + now applied/removed (depending on the last modification time + and the deletion time) +- Improved compatibility of the 'Delete Duplicate Entries' + command with the process memory protection +- Improved handling of command lines containing quotes or + backslashes +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +2019-05-04: 2.42.1 +- Improved menu item state updating +- Improved backward compatibility with certain plugins +- Minor other improvements + +2019-05-01: 2.42 +- Added main menu items 'Group', 'Entry' and 'Find', which + contain all commands related to groups and entries (supersets + of context menus); removed 'Edit' main menu item, because all + of its commands are included in the three new main menu items +- Added support for a system-wide hot key to auto-type only the + password of a matching entry; by default, the hot key is + Ctrl+Alt+Shift+A, changeable in the options dialog +- When double-clicking the URL cell of an entry in the main + entry list while holding down the Shift key, KeePass now + copies the URL to the clipboard (a double-click without Shift + continues to open the URL; the option 'Copy URLs to clipboard + instead of opening them' reverses this behavior) +- Added quick edit commands 'Expires: Now' and 'Expires: Never' +- There now are two commands for copying a whole entry to the + clipboard: 'Copy Entry (Encrypted)' and 'Copy Entry + (Unencrypted)'; the first one encrypts the data for the + current user using the Windows DPAPI +- Added Ctrl+Shift+P shortcut for printing the currently + selected group +- The creation time and the last modification time of an entry + are now displayed on the 'History' tab of the entry editing + dialog +- Added support for importing Steganos Password Manager 20 CSV + files +- Added support for importing Bitwarden 1.12 JSON files +- Mozilla Bookmarks JSON import: added support for importing + tags (new format, in addition to the old format) and keywords +- Enhanced the Enpass import module to support TXT files + created by version 6.0.4 +- The language selection dialog now also lists KeePass 1.x LNG + files; when trying to select such a file, an informative + error message is displayed +- Added 'Cancel' command in the context menu of KeePass' system + tray icon, which can be used to abort opening and saving a + database file +- Added '-cancel' command line option, which causes all other + KeePass instances to cancel opening/saving a database file +- Added '-auto-type-password' command line option (other + running KeePass instances auto-type only the password of a + matching entry) +- Added '-e1:' command line parameter, which works like '-e:', + but is handled by only one other instance; '-e:' is handled + by all other instances +- When compiling a PLGX plugin, KeePass now defines a + 'KP_V_*_*_*' symbol, where the asterisks specify the KeePass + version (for example, 'KP_V_2_42_0' for version 2.42) +- Added workarounds for .NET Caps Lock warning tooltip bug +- Added workaround for Mono grid view default color bug +- Added workaround for OneDrive bug on Windows 1809 + +- Auto-Type: improved sending of characters that are realized + with the AltGr key +- Auto-Type: improved compatibility with VirtualBox 6 and + VMware Player +- Improved user interface behavior while opening a database + file +- Accelerator key improvements +- Replaced 4 and 8 weeks expiry date search commands by 1 and 2 + months (taking the number of days in the months into account) +- Improved hot key controls (better key combination handling + and display) +- The hot key controls in the options dialog now support + entering hot keys that are already registered by KeePass +- Improved field to standard field mapping function +- Improved new-line handling of several import modules +- When a file import fails, KeePass now shows a more detailed + error message +- After changing the color of an entry using a quick edit + command, the entries are deselected now, such that the new + color is visible immediately +- Moved 'Print Emergency Sheet' command into 'File' -> 'Print' +- The pattern-based password generator now supports repeating + escaped characters using '{...}' +- The pattern-based password generator now refuses to generate + a password if the pattern is (partially) invalid +- Turning off the 'Unhide Passwords' policy now enforces hiding + passwords in a few more places/situations +- New-line characters at the end of the output of a {CMD:...} + placeholder are now removed (analogous to $(...) and `...` + shell command substitutions) +- The {URL:SCM} and {BASE:SCM} placeholders now work with + arbitrary data having a ':'-terminated prefix +- Improved {URL:RMVSCM} and {BASE:RMVSCM} placeholders ('//' + authority prefix is removed, but not '/') +- The '-entry-url-open' command line option is now handled by + all other KeePass instances (instead of only one) +- Path traversal with attachment names is not possible anymore +- Removed the option 'Show tray icon only if main window has + been sent to tray' from the options dialog (due to possible + denial-of-service problems); if you want to hide the icon, it + is recommended to configure this in the system settings + instead +- Improved reading of KDBX XML documents with unknown elements +- Improved JSON parser +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- Fixed a crash that could occur when trying to import certain + Mozilla Bookmarks JSON files +- Fixed a crash that could occur when trying to import certain + files with very deeply nested groups +- Fixed handling of paths with folder/file names containing + quotes (which can occur on Unix-like systems only) + +2019-01-09: 2.41 +- Added option 'Do not store data in the Windows clipboard + history and the cloud clipboard' (the option is turned on by + default; for entry clipboard commands in the main window) +- Added option 'Esc keypress in main window' (in 'Tools' -> + 'Options' -> tab 'Interface'), which allows to specify the + action of the Esc key (ignore, lock workspace, minimize, + minimize to tray, exit) +- Added option 'Ignore search settings of groups' in the 'Find' + dialog +- Internal data viewer: added support for zooming images using + the OEM + and - keys with Ctrl +- Added accelerator keys (especially for labels) in various + dialogs +- Added UIFlags bit for disabling the 'Database Settings' menu + item +- Added workarounds for Windows RTF character encoding bug +- Added workaround for Mono input focus restoration problem + that occurs when a form gets activated +- Plugins: added method to provide menu items +- Plugins: added property to get the edit mode of an entry + dialog +- TrlUtil: added tab 'Validation', which shows the results of + all checks that TrlUtil performs +- TrlUtil: the tab in the preview form that contains the + currently selected control is now selected automatically +- TrlUtil: the preview form now shows accelerator keys + permanently +- TrlUtil: enhanced support for derived control classes +- TrlUtil: the current file name is now displayed in the title + bar +- Enhanced installer (added user directory checks, added option + to open the plugins web page, component/option names can be + translated now, updated NGen size estimation, improved file + associations update, ...) + +- In order to avoid selection/Ctrl+A problems, the user name + auto-completion now does not append suggestions anymore; it + only shows a list of suggestions (in which a suggestion can + be selected manually) +- Improved accelerator keys in the 'Find' dialog +- The history list in the entry dialog now supports showing + custom icons +- Mass entry modifications (colors/icons) now create history + entries, if necessary +- Improved text rendering in dialog banners +- In the database settings dialog, the path of the database + file is now shown in the dialog banner +- Improved selection/view preservation of the entry view +- While importing/synchronizing, a status dialog is displayed + now if and only if the main window is not constructed + completely yet (otherwise the status is displayed in the main + window) +- Improved reliability of clipboard operations +- Improved error reporting for the 'Paste Entries' command +- Renamed the automatic clipboard clearing option and added a + tooltip in order to clarify the behavior of the option +- The commands 'Find Similar Passwords (Pairs)', 'Find Similar + Passwords (Clusters)' and 'Password Quality Report' now + ignore TAN entries +- The report of clusters of similar passwords now shows more + clusters in certain cases +- In the 'Plugins' dialog, the plugins are now sorted + alphabetically +- KeePass does not try to load satellite assemblies as plugins + anymore +- Improved configuration saving when an enforced configuration + file exists, but no global one +- Improved reading of KDBX XML documents with unknown elements +- The export module 'Customizable HTML File' now works fine on + Unix-like systems, too +- On Unix-like systems: improved support for executing KeePass + while no X server is running +- ShInstUtil: improved NGen detection on 64-bit systems +- TrlUtil: the preview form does not steal the input focus + anymore +- TrlUtil: improved accelerator key check +- Various code optimizations +- Minor other improvements + +- Fixed a bug that caused KeePass to crash when trying to view + certain password generator profiles +- The option 'Use monospace font for passwords' in the 'Print' + / HTML export dialog now works for all translations + +2018-09-10: 2.40 +- Added automatic completion support for the user name box in + the entry editing dialog and the auto-type sequence boxes in + the entry/group editing dialogs (suggesting user names and + auto-type sequences that are used in other entries/groups) +- Added automatic completion support for the URL and user name + boxes in the 'Open From URL' dialog (suggesting URLs and user + names of items in the list of most recently used database + files) +- Added option 'Group path' in the 'Find' dialog (enabled by + default for quick searches) +- Added read-only mode for the entry string dialog, which is + used by the entry dialog when viewing a history entry +- The internal data viewer now supports zooming images using + Ctrl+Add, Ctrl+Subtract and the mouse wheel with Ctrl; + furthermore, there are now '+' and '-' buttons right of the + zoom selection box in the toolbar +- Added option 'Remember master password (in encrypted form) of + a database while it is open' (which is the default; turning + off this option prevents the usage of certain features) +- Enhanced compatibility check for DLL plugins +- Added URL opening event for plugins +- On Unix-like systems: added support for opening the local + help file with KChmViewer +- Added workaround for initial input focus problem in the + master key prompt dialog +- Added workaround for Mono not always raising the FormClosed + event properly +- TrlUtil now remembers the last translation file directory + +- The 'Configure Columns' dialog now computes a display order + for the new columns, taking the previous display order into + account +- While importing/synchronizing, no status dialog is displayed + anymore (the status is displayed in the main window) +- Improved UI responsiveness during long operations +- When hiding/restoring the main window via the system tray + icon fails, KeePass now shows a notification +- Improved Return key handling in text boxes +- Improved initial input focus in some dialogs +- Enhanced database file path unification +- The configuration system does not create a KeePass folder in + the user's application data folder anymore when the target + configuration file location is outside this folder +- Improved window text query method +- Improved Unicode environment detection +- Various improvements for right-to-left writing systems +- Improved support for case-sensitive command line parameter + names (for plugins and KPScript) +- If a plugin is available both as a DLL and as a PLGX (in the + same folder), KeePass now loads either the DLL or the PLGX +- For plugins: most public definitions are now static +- KPScript: improved parsing of escape sequences +- Renamed native support library item in the installer +- Upgraded installer +- Various code optimizations +- Minor other improvements + +2018-05-12: 2.39.1 +- File transactions: improved access control list (ACL) + restoration +- File transactions are not used anymore when attempting to + write to a local file that does not exist yet (to ensure a + correct default ACL) +- The option to minimize the main window after performing + auto-type is now ignored while displaying a subdialog +- Plugins can now implement classes derived from KeePass' + custom rich text boxes + +2018-05-06: 2.39 +- KeePass now uses Transactional NTFS (TxF) for writing + database and configuration files, if possible; this improves + the compatibility with other programs that are watching these + files (e.g. file synchronization services) +- Added command 'Edit' -> 'Show Entries' -> 'Large Entries' +- Added command 'Edit' -> 'Show Entries' -> 'Last Modified + Entries' +- Added option 'Automatically save after modifying an entry + using the entry editing dialog' (turned off by default) +- Added option 'Minimize main window after performing + auto-type' (turned off by default) +- Added option 'Show lines between nodes in tree views' (turned + off by default) +- Added support for importing Google Chrome 66 password CSV + files +- Added trigger event 'Time - Periodic', which is raised at + user-defined intervals +- Links in the entry string editing dialog are clickable now +- Added UIFlags bit for disabling the 'XML Replace' menu item +- Added UIFlags bit for hiding auto-type obfuscation + compatibility information dialogs +- Added workaround for .NET 'urtf' RTF round-trip bug +- Secure edit controls are now extensible by plugins +- KPScript: the 'AddEntry' command now supports the + '-setx-Expires' and '-setx-ExpiryTime' parameters + +- In printouts and HTML exports, expired entries now have a red + 'X' icon (if the option 'Icon' is turned on) +- Improved string normalization in the entry and string editing + dialogs +- Improved and optimized process memory protection, especially + in the entry editing dialog +- Secure edit control improvements +- Improved behavior when moving a custom string to a standard + field +- Improved entry size calculation +- URL overrides are now used also for application URLs +- Improved input focus restoration +- When trying to toggle the auto-start option and + creating/deleting the registry value fails, KeePass now shows + a detailed error message +- Improved XML serialization +- Stream disposal improvements in exceptional situations +- Process object disposal improvements +- Extended inter-process communication (IPC) messages are + compressed and encrypted now +- New IPC mechanism on Unix-like systems +- Enhanced desktop type detection on Unix-like systems +- On the Cinnamon desktop, the 'Always on Top' option is now + disabled (because it is not supported properly by the + environment) +- KeePass now ignores hidden Git and Visual Studio directories + when building a PLGX file +- The trigger system now ignores state-changing placeholders in + most places +- Removed trigger event 'User interface state updated' + (consider using the new event 'Time - Periodic' instead) +- Various code optimizations +- Minor other improvements + +- The 'View' button on the 'History' tab of the entry editing + dialog is now disabled when multiple items are selected +- The main window state is now updated after closing an entry + report dialog + +2018-01-09: 2.38 +- The installers (regular and MSI) now create an empty + 'Languages' folder in the application directory, and the + portable package now also contains such a folder; language + files should now be stored in this folder +- Added button 'Open Folder' in the language selection dialog, + which opens the 'Languages' folder +- Added button 'Open Folder' in the plugins dialog, which opens + the 'Plugins' folder +- Added a runtime activation policy setting (to improve + compatibility with Microsoft User Experience Virtualization) +- Added option 'Icon' and an option for specifying the + placeholder behavior (replace or not, or both forms) in the + 'Print' / HTML export dialog +- Printing / HTML export: the notes of a group are now + displayed below the group name +- Enhanced the Password Exporter import module to support XML + files created by version 1.3.4 +- Added workaround for Microsoft Office breaking the 'Print' + shell verb for HTML files +- Added workaround for Mono list view item deletion bug +- Added workaround for Mono command line argument encoding bug +- KPScript: the 'AddEntry' and 'EditEntry' commands now support + the '-setx-Icon' and '-setx-CustomIcon' parameters, which set + the icon of the entry +- KPScript: the 'ChangeMasterKey' command now supports the + '-newpw-enc' parameter (for specifying the new master + password in encrypted form, compatible with the + {PASSWORD_ENC} placeholder) +- KPScript: the 'ListEntries' command now supports all '-ref-*' + and '-refx-*' parameters + +- Password quality estimation: improved compatibility with + process memory protection +- Improved UI scaling when using KeePass on multiple systems + with different DPI values +- Printing / HTML export: improved embedding of CSS +- Printing / HTML export: spaces in passwords are now encoded + as non-breaking spaces +- Improved UI updating in the 'Print' / HTML export dialog +- Enhanced KDE system font detection +- Improved fatal error handling +- Various improvements in the language selection dialog +- KPScript: improved behavior of '-ref-*' parameters when + combined with the '-refx-All' option +- Various code optimizations +- Minor other improvements + +- Fixed HTML generation bug: when the option 'Use monospace + font for passwords' was turned off, a generated HTML file in + 'Details' mode could contain invalid end tags + +2017-10-12: 2.37 +- When creating a new database, KeePass now offers to print a + KeePass emergency sheet (which can then be filled out and + stored in a secure location, where only the user and possibly + a few other people that the user trusts have access to); an + emergency sheet can also be created via 'Tools' -> 'Database + Tools' -> 'Print Emergency Sheet' +- Added database file information dialog that is displayed when + creating a new database +- Added function to search similar password clusters ('Edit' -> + 'Show Entries' -> 'Find Similar Passwords (Clusters)') +- On Unix-like systems: if the library 'libgcrypt.so.20' is + available, KeePass uses it for AES-KDF transformations +- Enhanced PrepMonoDev.sh script to upgrade a DTD processing + definition +- Added workaround for .NET/Windows column header drawing bug + when switching to TAN-only entry list mode +- Added workaround for Mono tab switching bug +- Added workaround for Mono '}' character RTF encoding bug +- TrlUtil: added support for .NET 4.* + +- Improved dialog for changing the master key (key file and + user account are now expert options, added more information + and links to help page sections) +- KeePass now directly offers to save the database after + changing the master key, and it asks whether to print a new + emergency sheet +- Various improvements in the translation selection dialog (the + selected translation can now be activated by pressing Return, + the list view now uses the Explorer style, ...) +- KeePass now refuses to attach files that are larger than 512 + MB (as larger files can result in serialization problems) +- Increased default number of AES-KDF rounds +- On Unix-like systems, KeePass now uses the CSP implementation + of the AES algorithm for encrypting data, which is a bit + faster +- Improved tool strip checkmark rendering on Unix-like systems +- Updated links (to the website, help pages, etc.) +- The MSI file is now built using Visual Studio 2017 +- Various code optimizations +- Minor other improvements + +2017-06-09: 2.36 +- Added commands 'Find Duplicate Passwords' and 'Find Similar + Passwords' (in 'Edit' -> 'Show Entries'), which show entries + that are using the same or similar passwords +- Added command 'Password Quality Report' (in 'Edit' -> 'Show + Entries'), which shows all entries and the estimated quality + of their passwords +- Added option 'String name' in the 'Edit' -> 'Find' dialog + (for searching entries that have a specific custom string + field) +- Added option for using a gray tray icon +- Added {CMD:/.../} placeholder, which runs a command line +- Added {T-CONV:/.../Raw/} placeholder, which inserts a text + without encoding it for the current context +- Added optional 'Last Password Modification Time (Based on + History)' entry list column +- The internal text editor now supports editing PS1 files +- The position and size of the internal data viewer is now + remembered and restored +- For various dialogs, the maximized state is now remembered + and restored +- Added configuration option for specifying an expiry date for + master keys +- Added configuration option for specifying disallowed + auto-type target windows +- Added workaround for Edge throwing away all keyboard input + for a short time after its activation +- Added workaround for Mono not properly rendering bold and + italic text in rich text boxes +- TrlUtil now performs a case-sensitive word validation + +- The password input controls in the I/O connection dialog and + the proxy dialog now are secure edit controls +- The icon of the 'Save' command in the main menu is now grayed + out when there are no database changes (like the toolbar + button) +- Auto-Type: improved support for target applications that + redirect the focus immediately +- Auto-Type: improved compatibility with VMware vSphere client +- When an error occurs during auto-type, KeePass is now brought + to the foreground before showing an error message box +- Entries in groups where searching is disabled (e.g. the + recycle bin group) are now ignored by the commands that show + expired entries +- Improved scrolling when moving entries while grouping in the + entry list is on +- Improved support for right-to-left writing systems +- Improved application and system tray icon handling +- Updated low resolution ICO files (for Mono development) +- Moved single-click tray icon action option from the + 'Integration' tab to the 'Interface' tab of the options + dialog +- Synchronization file path comparisons are case-insensitive + now +- Improved workaround for Mono clipboard bug (improved + performance and window detection; the workaround is now + applied only if 'xsel' and 'xdotool' are installed) +- Enhanced PrepMonoDev.sh script +- KPScript: times in group and entry lists now contain a time + zone identifier (typically 'Z' for UTC) +- Various code optimizations +- Minor other improvements + +- The drop-down menu commands in the entry editing dialog for + setting the expiry date now work as expected + +2017-01-09: 2.35 +- New KDBX 4 file format, which supports various new features + (listed below; e.g. Argon2) +- Added Argon2 key derivation function (it can be activated in + the database settings dialog) +- Improved header and data authentication in KDBX 4 files + (using HMAC-SHA-256, Encrypt-then-MAC scheme) +- Added ChaCha20 (RFC 7539) encryption algorithm (it can be + activated as KDBX file encryption algorithm in the database + settings dialog; furthermore, it supersedes Salsa20 as + default for generating the inner random stream of KDBX 4 + files) +- Added support for opening entry URLs with Firefox or Opera in + private mode via the context menu -> 'URL(s)' -> 'Open with + ... (Private)' +- Added URL override suggestions for Firefox and Opera in + private mode in the URL override suggestions drop-down list + in the entry dialog +- Added optional built-in global URL overrides for opening + HTTP/HTTPS URLs with Firefox or Opera in private mode +- Added {PICKFIELD} placeholder, which shows a dialog to pick a + field whose value will be inserted +- Added option 'Hide "Close Database" toolbar button when at + most one database is opened' (turned on by default) +- Added option 'Show additional auto-type menu commands', which + can be turned on to show menu commands for performing entry + auto-type with some specific sequences +- Added menu command 'Selected Entry's Group' (with keyboard + shortcut Ctrl+G) in 'Edit' -> 'Show Entries' (and a context + menu equivalent 'Show Parent Group' in 'Selected Entries'), + which opens the parent group of the currently selected entry + and selects the entry again +- Added menu commands in 'Edit' -> 'Show Entries' to show + entries that expire in a specific number of days (1, 2, 3) or + weeks (1, 2, 4, 8) or in the future +- Added configuration option that specifies the number of days + within which entries are considered to expire 'soon' (the + default is 7) +- Added option for changing the alternate item background color +- When the option 'Remember key sources' is enabled, KeePass + now also remembers whether a master password has been used +- Added option 'Force changing the master key the next time + (once)' (in 'File' -> 'Database Settings' -> tab 'Advanced') +- Added parameters 'Window style' and 'Verb' for the 'Execute + command line / URL' trigger action +- Added support for importing mSecure 3.5.5 CSV files +- Added support for importing Password Saver 4.1.2 XML files +- Added support for importing Enpass 5.3.0.1 TXT files +- Enhanced SplashID CSV import (added support for the old + version 3.4, added mappings for types of the latest version, + groups are now created only for categories, and types are + imported as tags) +- LastPass import: added support for CSV files exported by the + LastPass Chrome extension, which encodes some special + characters as XML entities +- Added 'KeePass KDBX (2.34, Old Format)' export module +- Export using XSL transformation: added support for the + 'xsl:output' element in XSL files +- If the global auto-type hot key is Ctrl+Alt+A and the current + input locale is Polish, KeePass now shows a warning dialog + (telling the user that Ctrl+Alt+A is in conflict with a + system key combination producing a character) +- Added Alt+X Unicode character conversion support in rich text + boxes on Unix-like systems +- For development snapshots, the 'About' dialog now shows the + snapshot version (in the form 'YYMMDD') +- Plugins can provide other key derivation functions now +- The header of KDBX 4 files is extensible by plugins +- Enhanced support for developing encryption algorithm plugins +- Plugins can now store custom data in groups and entries +- Plugin data stored in the database, a group or an entry can + now be inspected (and deleted) in the database maintenance + dialog, the group dialog and the entry dialog, respectively +- For plugins: file closing events now contain information + about whether KeePass is exiting, locking or performing a + trigger action +- Added workaround for .NET handle cast overflow bug in + InputLanguage.Culture +- Added workaround for Mono ignoring the Ctrl+I shortcut +- Added workaround for Mono clipboard bug +- Added workaround for Mono not focusing the default control in + the entry editing dialog +- Added workaround for a Mono timer bug that caused high CPU + load while showing a file save confirmation dialog +- Added Mono workaround: when running on MacOS, KeePass now + does not try to instantiate a tray icon anymore +- Added workaround for XDoTool sending diacritic characters in + incorrect case +- TrlUtil now recommends to clear the 'Unused Text' tab + +- Improved behavior when searching entries with exclusions + (terms prefixed with '-') +- Improved support for auto-typing into target windows using + different keyboard layouts +- Auto-Type: improved support for keyboard layouts with keys + where Shift, Caps Lock and no modifier result in 3 different + characters +- Auto-Type: improved support for spacing modifier letters + (U+02B0 to U+02FF) +- Global auto-type now works with target windows having empty + titles +- When copying entries to the clipboard, the data package now + includes custom icons used by the entries +- Unified behavior when drag&dropping a field containing a + placeholder +- Improved entry edit confirmation dialog +- If the screen height is insufficient to display a dialog, the + dialog's banner (if the dialog has one) is now removed to + save some space +- Some tooltips are now displayed for a longer time +- A new entry created using a template now does not include the + history of the template anymore +- For empty RTF attachments, the internal data editor now by + default uses the font that is specified for TXT files +- Internal data editor: added support for changing the format + of mixed-format selections +- Internal data viewer and editor: null characters ('\0', not + '0') in texts are now automatically replaced by spaces (like + Notepad on Windows 10) +- Improved encoding signature handling for conversions during + text attachment imports (via the 'Text Encoding' dialog) +- File transactions are not used anymore for files that have a + reparse point (e.g. symbolic links) +- Improved XSL stylesheets for KDBX XML files +- The internal window manager is now thread-safe +- Improved date/time handling +- Improved button image disposal +- When synchronizing two databases, custom data (by plugins) is + now merged +- When opening a database file, corrupted icon indices are now + automatically replaced by default values +- Added some more entropy sources for the seed of the + cryptographically secure pseudo-random number generator + (environment variables, command line, full operating system + version, current culture) +- ChaCha20 is now used during password generation (instead of + Salsa20) +- ChaCha20 is now used as fallback process memory encryption + algorithm (instead of Salsa20) +- When the encryption algorithm for a database file is unknown, + the error message now shows the UUID of the algorithm +- In KDBX 4, header field lengths are now 4 bytes wide +- In KDBX 4, entry attachments are now stored in an inner, + binary header (encrypted, possibly compressed), before the + XML part; this reduces the database file size and improves + the loading/saving performance +- In KDBX 4, the inner random stream cipher ID and key (to + support process memory protection) are now stored in the + inner header instead of in the outer header +- KPScript: the 'ChangeMasterKey' command now also updates the + master key change date +- TrlUtil: improved validation warning dialogs +- The MSI file now requires any .NET Framework version, not a + specific one +- The MSI file is now built using Visual Studio 2015 +- Various code optimizations +- Minor other improvements + +- When executing a {HMACOTP} placeholder, the last modification + time of the corresponding entry is now updated +- Key files containing exactly 64 alphanumeric characters are + now loaded as intended + +2016-06-11: 2.34 +- The version information file (which the optional update check + downloads to see if there exists a newer version) is now + digitally signed (using RSA-4096 / SHA-512); furthermore, it + is downloaded over HTTPS +- Added option 'Lock workspace when minimizing main window to + tray' +- Added option 'Esc minimizes to tray instead of locking the + workspace' +- Added Ctrl+Q shortcut for closing KeePass (as alternative to + Alt+F4) +- Added UIFlags bit for disabling the 'Check for Updates' menu + item +- The installers (regular and MSI) now create an empty + 'Plugins' folder in the application directory, and the + portable package now also contains such a folder +- Plugins: added support for digitally signed version + information files + +- Plugins are now loaded only directly from the application + directory and from any subdirectory of the 'Plugins' folder + in the application directory +- Improved startup performance (by filtering plugin candidates) +- When closing a database, KeePass now searches and deletes any + temporary files that may have been created and forgotten by + MSHTML when printing failed +- CHM help file: improved high DPI support +- Various code optimizations +- Minor other improvements + +2016-05-07: 2.33 +- Added commands in the group context menu (under 'Rearrange'): + 'Expand Recursively' and 'Collapse Recursively' +- Added option 'When selecting an entry, automatically select + its parent group, too' (turned on by default) +- Added placeholders for data of the group that is currently + selected in the main window: {GROUP_SEL}, {GROUP_SEL_PATH} + and {GROUP_SEL_NOTES} +- While importing/synchronizing, indeterminate progress is now + displayed on the taskbar button (on Windows 7 and higher) +- Added optional parameters 'Filter - Group' and 'Filter - Tag' + for the 'Export active database' trigger action +- Pressing the Escape key in the main window now locks the + workspace (independent of the current database locking state, + in contrast to Ctrl+L) +- Added option 'Extra-safe file transactions' in 'Tools' -> + 'Options' -> tab 'Advanced' +- Added customization option to specify how often the master + key dialog appears when entering incorrect master keys +- Plugins: added event 'FormLoadPost' for the main window +- KPScript: the 'GetEntryString' command now supports the + '-Spr' option, which causes KPScript to Spr-compile the field + value (i.e. placeholders are replaced, field references are + resolved, environment variables are inserted, etc.) + +- Improved database synchronization performance +- Improved object reordering during a database synchronization + for new and relocated groups/entries +- Improved synchronization of deleted objects information +- Improved database synchronization to prevent implicit object + deletions +- HTML export/printing: the notes column now is twice as wide + as the other columns +- When entering a Spr-variant password in the entry dialog, the + quality estimation is now disabled +- Group tooltips are now displayed for about 30 seconds +- The root group is now always expanded when opening a database +- Improved private mode browser detection +- Improved DPI awareness declaration (on Windows 10 and higher) +- Improved regular expression searching performance in usual + use cases +- Improved natural string comparison performance (on Unix-like + systems) +- Improved mnemonic characters in the 'Rearrange' menus +- Upgraded installer +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +2016-03-09: 2.32 +- The quick search box (in the toolbar of the main window) now + supports searching using a regular expression; in order to + indicate that the search text is a regular expression, + enclose it in '//'; for example, performing a quick search + for '//Michael|Adam//' shows all entries containing 'Michael' + or 'Adam' +- Added 'Advanced' tab in the 'Open From URL' dialog (easily + extensible by plugins); added options: timeout, pre- + authenticate, HTTP/HTTPS/WebDAV user agent and 100-Continue + behavior, FTP passive mode +- Added per-user Start Menu Internet Application detection +- When selecting an entry in the main entry list, its parent + group is now selected automatically in the group tree view +- Auto-Type matching: added option 'Expired entries can match' + (turned off by default, i.e. expired entries are ignored) +- Added option 'Always show global auto-type entry selection + dialog' (to show the dialog even when no or one entry is + found for the currently active target window; turned off by + default) +- Added {GROUP_NOTES} placeholder +- Added support for importing nPassword 1.0.2.41 NPW files +- In triggers and KPScript, an import/export module can now be + specified both using its display name and its format name +- When running under .NET 4.5 or higher, secure connections + (e.g. for WebDAV) now support TLS 1.1 and TLS 1.2 (in + addition to SSL 3 and TLS 1.0) +- Added Mono workaround: when running on the Unity or Pantheon + desktop, KeePass now does not try to instantiate a tray icon + anymore; if you want a tray icon on Unity/Pantheon, use the + application indicator plugin +- Added workaround for Mono not implementing the property + SystemInformation.SmallIconSize for MacOS systems +- Added command line parameter '-wa-disable:' for disabling + specific Mono workarounds (IDs separated by commas) +- KPScript: if the value of a '-ref-*:' parameter is enclosed + in '//', it is now treated as a regular expression, which + must occur in the entry field for an entry to match +- KPScript: .NET 4.0/4.5 is now preferred, if installed +- KPScript: enhanced high DPI support + +- Auto-Type: improved compatibility with target windows that + handle activation slowly and ignore any input until being + ready (like Microsoft Edge) +- Auto-Type: improved sending of characters that are typically + realized with the AltGr key +- When editing a custom entry string, the value text box now + has the initial focus +- Improved image/icon shrinking +- Improved icon recoloring on high DPI resolutions +- Changed some ICO files such that higher resolution images are + used +- Changed some PNG files to workaround the image DPI scaling + behavior on Windows XP +- Improved new-line filtering in the main entry view +- When trying to use the Windows user account as part of a + composite master key fails, a more detailed error message is + displayed now +- The 'About' dialog now indicates whether the current build is + a development snapshot +- Changed code signing certificate +- Upgraded installer +- Various code optimizations +- Minor other improvements + +- After an incomplete drag&drop operation over the group tree + view, the previous group selection is now restored + +2016-01-09: 2.31 +- Added menu/toolbar styles, freely selectable in 'Tools' -> + 'Options' -> tab 'Interface'; available styles are 'Windows + 10', 'Windows 8.1', 'KeePass - Gradient', '.NET/Office - + Professional' and 'System - Classic'; by default KeePass uses + the style most similar to the one of the current operating + system +- Refined application icons (thanks to Victor Andreyenkov) +- Auto-Type: new target window classification method, which + improves compatibility with target windows hosted within + other windows (e.g. a PuTTY window within SuperPuTTY/MTPuTTY) +- Auto-Type: added workaround for the default Ctrl+Alt behavior + of KiTTY variants (which differs from Windows' behavior) +- Before clearing the clipboard, KeePass now first copies a + non-sensitive text into it; this ensures that no sensitive + information remains in the clipboard even when clearing is + prevented by the environment (e.g. when running in a virtual + machine, when using a clipboard extension utility, ...) +- Added support for opening entry URLs with Internet Explorer + or Google Chrome in private mode via the context menu -> + 'URL(s)' -> 'Open with ... (Private)' +- Added URL override suggestions for Internet Explorer and + Google Chrome in private mode in the URL override suggestions + drop-down list in the entry dialog +- Added optional built-in global URL overrides for opening + HTTP/HTTPS URLs with Internet Explorer or Google Chrome in + private mode +- Added Ctrl+K shortcut for the 'Duplicate Entry' command +- Mozilla Bookmarks HTML import: added support for importing + tags +- Added support for exporting to Mozilla Bookmarks HTML files +- Windows/IE favorites export: entry fields are Spr-compiled + now, and entries with cmd:// URLs are now exported as LNK + files +- HTML export/printing: added support for UUIDs, added + horizontal lines between entries in details mode, added + background color for group headings, long field names are + hyphenated now, and long field data now breaks and wraps onto + the next line +- Plugins: added possibility to configure file transactions for + each URI scheme +- Plugins: added possibility to provide custom 'Save As' + dialogs more easily +- Converted some PNG images as a workaround for a problem in + Cairo/LibPNG on Unix-like systems +- As a workaround for a weakness in Mono's FileDialog, before + showing such a dialog on Unix-like systems KeePass now tries + to load the file '~/.recently-used' and deletes it, if it is + not a valid XML file +- KPScript: added support for specifying the master password in + encrypted form using the '-pw-enc:' command line parameter + (exactly like in KeePass, compatible with the {PASSWORD_ENC} + placeholder) +- KPScript: the 'Export' command now supports the optional + '-GroupPath:' parameter (to export a specific group instead + of the whole database) +- KPScript: the 'GetEntryString' command now supports the + '-FailIfNoEntry' option +- KPScript: added '-refx-Expires' and '-refx-Expired' entry + identification parameters +- KPScript: the 'Import' command now prints more specific error + messages +- All KeePass program binaries are now dual signed using SHA-1 + and SHA-256 + +- Auto-Type: improved keyboard layout handling when the target + window changes during an auto-type process +- Auto-Type: improved compatibility with Remote Desktop + Connection client and VirtualBox +- Improved icon recoloring +- Improved printing of dates/times and tags +- The password generator based on a character set now ensures + that the generated password is Spr-invariant +- Password generator based on a pattern or a custom algorithm: + when a Spr-variant password is generated, a confirmation + dialog for accepting this password is displayed +- If the 'Save Database' policy prevents saving, the auto-save + option is now ignored +- Improved .NET Framework version detection +- PLGX debugging: when the command line option '-debug' is + passed and a PLGX plugin fails to compile, the output of all + tried compilers is saved to a temporary file +- Improved file transaction creation time handling on Unix-like + systems +- Improved compatibility with Mono on BSD systems +- Enhanced PrepMonoDev.sh script for compatibility with Mono + 4.x +- Removed KeePassLibSD sub-project (a KeePass library for + Pocket PC / Windows Mobile) from the main solution +- Upgraded installer +- Various code optimizations +- Minor other improvements + +- When running under Mono (Linux, MacOS, ...), two options + related to window minimization are disabled now (because they + do not work properly due to a Mono bug) + +2015-08-09: 2.30 +- When opening a database via a URL fails, the error message + dialog now has a button 'Specify different server + credentials' (on Windows Vista and higher) +- Added support for opening entry URLs with Microsoft Edge via + the context menu -> 'URL(s)' -> 'Open with Edge' +- Added URL override suggestion for Microsoft Edge in the URL + override suggestions drop-down list in the entry dialog +- Added optional built-in global URL overrides for opening + HTTP/HTTPS URLs with Microsoft Edge +- When clicking on a group link in the entry view, KeePass now + ensures that the group is visible in the group tree +- The main window is now moved onto the primary screen when it + is restored outside all screens +- KDBX loader: added support for non-empty protected binary + value reference elements +- Plugins: added two auto-type sequence query events +- Added workaround for Mono drawing bug when scrolling a rich + text box +- When running under Mono, some automatic locking options are + now disabled (because Mono doesn't implement the required + events) +- The installer now prevents running the installer while it is + already running +- KPScript: added '-GroupPath:' parameter (for specifying the + full path of a group) +- KPScript: the 'MoveEntry' command now also supports the + '-GroupName:' parameter (as alternative to '-GroupPath:') +- KPScript: added support for specifying the path of an XSL + stylesheet file using the command line parameter '-XslFile:' +- KPScript: the 'ListGroups' command now also outputs the + parent group UUID for each group +- KPScript: the parameters for specifying new field data (for + the 'AddEntry' and the 'EditEntry' command) now support + escape sequences (e.g. '\n' is replaced by a new-line + character) + +- The 'Synchronize' file dialog now shows only KDBX files by + default +- In the 'Attachments (Count)' column, only non-zero counts are + shown now +- Improved MRU item refreshes +- The entry string dialog now supports changing the case of a + string name +- The entry string dialog now does not allow adding a string + whose name differs from another existing string name in this + entry only by case +- The entry view in the main window is now updated immediately + after pressing Ctrl+H or Ctrl+J +- The KDB import module now tries to round any invalid + date/time to the nearest valid date/time +- XML serializers are now loaded/created at KeePass startup in + order to avoid a problem when shutting down Windows and + KeePass.XmlSerializers.dll not being present +- Changed tab bar behavior in the options dialog to avoid a tab + content cropping issue caused by plugins +- Improved workaround for Mono splitter bug +- Upgraded installer +- Various performance improvements +- Various code optimizations +- Minor other improvements + +2015-04-10: 2.29 +- Added high resolution icons +- Added support for high resolution custom icons +- Added option in the proxy configuration dialog to use the + user's default credentials (provided by the system) +- {FIREFOX} placeholder: if no regular Firefox is installed, + KeePass now looks for Firefox ESR +- {PICKCHARS} placeholder: the Conv-Fmt option now supports all + combinations of '0', 'A', 'a' and '?'; '?' skips a combobox + item +- Added {BEEP X Y} auto-type command (where X is the frequency + in hertz and Y the duration in milliseconds) +- Added optional 'Attachments (Count)' entry list column +- Added Ctrl+Insert shortcut as alternative for Ctrl+C in the + entry list of the main window +- Added shortcut keys for 'Copy Entries' (Ctrl+Shift+C) and + 'Paste Entries' (Ctrl+Shift+V) +- Added some access keys in various dialogs +- In the field reference dialog, the field in which the + reference will be inserted is now selected as source field by + default +- Added UUID uniqueness check +- Added support for importing Passphrase Keeper 2.60 HTML files + (in addition to the already supported 2.50 and 2.70 formats) +- The path of the local configuration file can now be changed + using the '-cfg-local:' command line parameter +- Plugins can now access the KeePass resources (images, icons, + etc.) through the IPluginHost interface +- Added a few workarounds for external window manipulations + before the main window has been fully constructed +- Added workaround for .NET gradient drawing bug; 'Blue Carbon' + dialog banners are now drawn correctly on high DPI +- Added workaround for Mono file version information block + generation bug +- KPScript: added 'EstimateQuality' command (to estimate the + quality of a specified password) +- All KeePass program binaries are now digitally signed (thanks + to Certum/Unizeto) + +- In the master key creation dialog, the 'Create' and 'Browse' + buttons are now disabled when a key provider is selected +- Changed behavior of the 'Use system proxy settings' option + (KeePass now directly gets the system proxy settings, not the + .NET default proxy settings) +- Improved focus restoration after closing the character + picking dialog +- Removed 'O' and 'C' access keys from 'OK' and 'Cancel' + buttons (instead, press Enter for 'OK' and Esc for 'Cancel') +- Improved remembering of splitter positions +- Improved assignments of check mark images to menu items +- Improved behavior when synchronizing a local EFS-encrypted + database file with a local database file +- On Unix-like systems, hot key boxes now show 'External' + instead of 'None' +- Various code optimizations +- Minor other improvements + +- AltGr+E (i.e. Ctrl+Alt+E) does not focus the quick search box + anymore + +2014-10-08: 2.28 +- Enhanced high DPI support +- Added trigger action 'Show message box' (which can abort the + current trigger execution or execute a command line / URL) +- The 'Database has unsaved changes' trigger condition now + supports choosing between the active database and the + database that triggered the event +- Added parameter for the trigger action 'Activate database + (select tab)' that allows activating the database that + triggered the event +- Auto-Type: added workaround for KiTTY's default Ctrl+Alt + behavior (which differs from Windows' behavior) +- Auto-Type: added workaround for PuTTYjp's default Ctrl+Alt + behavior (which differs from Windows' behavior) +- Added up/down arrow buttons for reordering auto-type + associations in the entry editing dialog +- While entering the master key on a secure desktop, dimmed + screenshots are now also displayed on all non-primary screens +- Added support for importing VisKeeper 3.3.0 TXT files +- The group tree view is now saved and restored during most + group tree updates +- In the main entry list, multiple entries can now be moved by + one step up/down at once +- If Caps Lock is on, a balloon tip indicating this is now also + displayed for password text boxes immediately after opening a + dialog (where the password text box is the initially focused + control) +- In the cases where Windows would display outdated thumbnail + and peek preview images for the main window, KeePass now + requests Windows to use a static bitmap instead (showing only + the KeePass logo) +- Added fallback method for parsing dates/times (the default + parser fails for some custom formats specified in the Control + Panel) +- Added workaround for .NET ToolStrip height bug +- Added own process memory protection for Unix-like systems (as + Mono doesn't provide any effective memory protection method) +- On Unix-like systems, Shift+F10 (and Ctrl+Alt+5 and + Ctrl+NumPad5 on MacOS) now shows the context menu in most + list/tree view controls and rich text boxes (like on Windows) +- KPScript: for the 'Import' command, a different master key + can now be specified using the standard master key command + line parameters with the prefix 'imp_' (e.g. -imp_pw:Secret) +- KPScript: added option '-FailIfNotExists' for the + 'GetEntryString' command +- KPScript: added '-refx-Group' and '-refx-GroupPath' entry + identification parameters + +- Improved compatibility with ClearType +- Improved support for high contrast themes +- When duplicating a group/entry, the creation time and the + last access time of the copy are now set to the current time +- Character picker dialog: initially the text box is now + focused, improved tab order, and picked characters are now + inserted at the current insertion point (instead of the end) +- Ctrl+Tab is now handled only once when the database tab bar + has the focus +- When exporting to a KeePass 1.x KDB file, a warning/error is + now shown if the master key contains/is a Windows User + Account +- Unknown trigger events/conditions/actions are now ignored by + the trigger dialog +- Reduced group tree view flickering +- Improved default value for the entry history size limit +- Improved menu check mark and radio images +- Improved list view column resizing +- Improved list view scrolling +- Secure edit control performance improvements +- In some cases, double-clicking the tray icon now brings + KeePass to the foreground +- Improved concurrent UI behavior during auto-type +- Auto-Type: improved compatibility with keyboard layouts with + combining apostrophes, quotation marks and tildes +- Auto-Type: improved virtual key translation on Unix-like + systems +- KPScript: the 'EditEntry' command now also updates the time + fields of all affected entries +- KPScript: the 'DeleteEntry' and 'DeleteAllEntries' commands + now create deleted object information (improving + synchronization behavior) +- Upgraded installer +- Various code optimizations +- Minor other improvements + +- When auto-typing a sequence containing a {NEWPASSWORD} + placeholder, the raw new password is now stored (in the + password field of the entry), not its corresponding auto-type + sequence +- Synchronizing two unrelated databases now always works as + expected + +2014-07-06: 2.27 +- The estimated password quality (in bits) is now displayed on + the quality progress bar, and right of the quality progress + bar the length of the password is displayed +- Auto-Type: before sending a character using a key combination + involving at least two modifiers, KeePass now first tests + whether this key combination is a registered system-wide hot + key, and, if so, tries to send the character as a Unicode + packet instead +- Auto-Type: added workaround for Cygwin's default Ctrl+Alt + behavior (which differs from Windows' behavior) +- Auto-Type: added {APPACTIVATE ...} command +- {HMACOTP} placeholder: added support for specifying the + shared secret using the entry strings 'HmacOtp-Secret-Hex' + (secret as hex string), 'HmacOtp-Secret-Base32' (secret as + Base32 string) and 'HmacOtp-Secret-Base64' (secret as Base64 + string) +- {T-CONV:...} placeholder: added 'Uri-Dec' type (for + converting the string to its URI-unescaped representation) +- Added placeholders: {URL:USERINFO}, {URL:USERNAME} and + {URL:PASSWORD} +- Added placeholders: {BASE}, {BASE:RMVSCM}, {BASE:SCM}, + {BASE:HOST}, {BASE:PORT}, {BASE:PATH}, {BASE:QUERY}, + {BASE:USERINFO}, {BASE:USERNAME}, {BASE:PASSWORD} (within a + URL override, each of these placeholders is replaced by the + specified part of the string that is being overridden) +- Added {NEWPASSWORD:/Profile/} placeholder, which generates a + new password for the current entry using the specified + password generator profile +- Pattern-based password generator: the '^' character now + removes the next character from the current custom character + set (for example, [a^y] contains all lower-case alphanumeric + characters except 'y') +- Enhanced syntax highlighting in the sequence field of the + 'Edit Auto-Type Item' dialog +- Added option 'Do not ask whether to synchronize or overwrite; + force synchronization' +- Added synchronization support for the group behavior + properties 'Auto-Type for entries in this group' and + 'Searching entries in this group' +- Root group properties are now synchronized based on the last + modification time +- While saving a database, a shutdown block reason is now + specified +- Added 'Move to Group' menu in the 'Selected Entries' popup of + the main entry list context menu +- Items of dynamic menus (tags, strings, attachments, password + generator profiles, ...) now have auto-assigned accelerator + keys +- As alternative to Ctrl+F, pressing F3 in the main window now + displays the 'Find' dialog +- Added UIFlags bit for hiding password quality progress bars + and information labels +- Enhanced system font detection on Unix-like systems +- When using 'xsel' for clipboard operations on Unix-like + systems, text is now copied into both the primary selection + and the clipboard +- Added '--version' command line option (for Unix-like systems) +- Plugins can now subscribe to an IPC event that is raised when + running KeePass with the '-e:' command line parameter +- Added workaround for .NET AutoWordSelection bug +- Added workaround for Mono bug 10163; saving files using + WebDAV now also works under Mono 2.11 and higher +- Added workaround for Mono image tabs bug +- Added workaround for Mono NumericUpDown drawing bug + +- Merged the URL scheme overrides and the 'Override all URLs' + option into a new dialog 'URL Overrides' +- Improved autocompletion of I/O connection parameters using + the MRU list (now treating the user name as filter) +- Improved interaction of I/O connection trigger parameters and + the MRU list +- The master key prompt dialog now validates key files only + when clicking [OK], and invalid ones are not removed + automatically from the list anymore +- Improved support for managing columns leftover from + uninstalled plugins in the 'Configure Columns' dialog +- If the 'Unhide Passwords' policy is turned off, the passwords + column in the auto-type entry selection dialog is now + unavailable +- The entry list in the main window is now updated immediately + after performing auto-type or copying data to the clipboard +- Various list view performance improvements +- The 'Searching entries in this group' group behavior + properties are now ignored during resolving field references +- Improved behavior in case of syntax errors in placeholders + with parameters +- Two-channel auto-type obfuscation: improved realization of + clipboard paste commands +- General main window keyboard shortcuts now also work within + the quick search box and the database tab bar +- Pressing Ctrl+Shift+Tab in the main window now always selects + the previous database tab (independent of which control has + the focus) +- Changed shortcut keys for moving entries/groups on Unix-like + systems, due to Mono's incorrect handling of Alt (preventing + key events) and navigation keys (selection updated at the + wrong time) +- Auto-Type: improved modifier key releasing on Unix-like + systems +- Various code optimizations +- Minor other improvements + +- A key-up event to the groups tree in the main window without + a corresponding key-down event does not change the entry list + anymore + +2014-04-13: 2.26 +- Added option to show a confirmation dialog when moving + entries/groups to the recycle bin +- Auto-Type: added workaround for applications with broken + time-dependent message processing +- Auto-Type: added workaround for PuTTY's default Ctrl+Alt + behavior (which differs from Windows' behavior) +- Auto-Type: added configuration option to specify the default + delay between two keypresses +- Added optional sequence comments column in the auto-type + entry selection dialog (in this column, only {C:...} comments + in the sequence are displayed; if a comment starts with '!', + only this comment is shown) +- If the option 'Automatically search key files' is activated, + all drives are now scanned in parallel and any key files are + added asynchronously (this avoids issues caused by slow + network drives) +- Added trigger action 'Show entries by tag' +- {OPERA} placeholder: updated detection code to also support + the latest versions of Opera +- {T-CONV:...} placeholder: added 'Uri' type (for converting + the string to its URI-escaped representation) +- Synchronization functions are now available for remote + databases, too +- Enhanced RoboForm importer to additionally support the new + file format +- Summary lists are now also available in delete confirmation + dialogs on Unix-like systems and Windows XP and earlier +- Added workaround for Mono Process StdIn BOM bug +- KPScript: added 'refx-All' option (matches all entries) +- KPScript: added optional parameters 'setx-Expires' and + 'setx-ExpiryTime' for the 'EditEntry' command + +- Improved database tab selection after closing an inactive + database +- New just-in-time MRU files list +- Improved selection of entries created by the password + generator +- The internal text editor now determines the newline sequence + that the data is using the most when opening it, and converts + all newline sequences to the initial sequence when saving the + data +- Improved realization of the {CLEARFIELD} command (now using + Bksp instead of Del, in order to avoid Ctrl+Alt+Del issues on + newer Windows systems) +- The note that deleting a group will also delete all subgroups + and entries within this group is now only displayed if the + group is not empty +- Improved GUI thread safety of the update check dialog +- Improved HTML generation +- Improved version formatting +- On Unix-like systems, window state automations are now + disabled during initial auto-type target window switches +- On Unix-like systems, the button to choose a password font is + disabled now (because this is unsupported due to Mono bug + 5795) +- Various files (e.g. 'History.txt') are now encoded using + UTF-8 +- Improved build system +- Various code optimizations +- Minor other improvements + +- In the 'Configure Columns' dialog, the activation states of + plugin-provided columns are now preset correctly + +2014-02-03: 2.25 +- New auto-type key sending engine (improved support for + sending Unicode characters and for sending keypresses into + virtual machine/emulator windows; now largely compatible with + the Neo keyboard layout; sequence parsing is faster, more + flexible and optimizes the sequence; improved behavior for + invalid sequences; differential delays, making the auto-type + process less susceptible to externally caused delays; + automatic cancelling is now more precise up to at most one + keypress and also works on Unix-like systems; improved + message processing during auto-type) +- When trying to open an entry attachment that the built-in + editor/viewer cannot handle, KeePass now extracts the + attachment to a (EFS-encrypted) temporary file and opens it + using the default application associated with this file; + afterwards the user can choose between importing/discarding + changes and KeePass deletes the temporary file securely +- On Windows Vista and higher, the button in the entry editing + dialog to open attachments is now a split button; the drop- + down menu allows to choose between the built-in viewer, the + built-in editor and an external application +- Added 'XML Replace' functionality +- Generic CSV importer: added option to merge imported groups + with groups already existing in the database +- Added support for importing Dashlane 2.3.2 CSV files +- On Windows 8 and higher, some running Metro apps are now + listed in the 'Edit Auto-Type Item' dialog +- Added {T-CONV:/T/C/} placeholder (to convert text to upper- + case, lower-case, or its UTF-8 representation to Base64 or + Hex) +- Added {SPACE} special key code (as alternative for the ' ' + character, for improved readability of auto-type sequences) +- XML merge (used e.g. when an enforced configuration file is + present): added support for comments in inner nodes +- Added UIFlags bit for showing last access times + +- In the history entry viewing dialog, the 'Open' and 'Save' + commands are now available for attachments +- When replacing the {PASSWORD_ENC} placeholder, KeePass now + first Spr-compiles the entry password (i.e. placeholders, + environment variables, etc. can be used) +- Improved configuration loading performance +- Improved displaying of fatal exceptions +- Various code optimizations +- Minor other improvements + +- Data inserted by entry URL component placeholders is now + encoded correctly + +2013-11-03: 2.24 +- The URL override field in the entry editing dialog is now an + editable combo box, where the drop-down list contains + suggestions for browser overrides +- Password quality estimations are now computed in separate + threads to improve the UI responsiveness +- The password generator profile 'Automatically generated + passwords for new entries' is now available in the password + generator context menu of the entry editing dialog +- Added UIFlags bit for hiding built-in profiles in the + password generator context menu of the entry editing dialog +- Tags can be included in printouts now +- Generic CSV importer: added support for importing tags +- Added support for importing Norton Identity Safe 2013 CSV + files +- Mozilla Bookmarks JSON import: added support for importing + tags +- RoboForm import: URLs are now terminated using a '/', added + support for the new file format and for the new note fields +- Added support for showing modern task dialogs even when no + form exists (requiring a theming activation context) +- KeePass now terminates CtfMon child processes started by + .NET/Windows, if they are not terminated automatically +- Added workarounds for '#', '{', '}', '[', ']', '~' and + diaeresis .NET SendKeys issues +- Added workaround for 'xsel' hanging on Unix-like systems +- Converted some PNG images as a workaround for a problem in + Cairo/LibPNG on Unix-like systems +- Installer: the version is now shown in the 'Version' field of + the item in the Windows 'Programs and Features' dialog +- TrlUtil: added 'Go to Next Untranslated' command +- TrlUtil: added shortcut keys + +- The 'Open From URL' dialog is now brought to the foreground + when trying to perform global auto-type while the database is + locked and the main window is minimized to tray +- Profiles are now shown directly in the password generator + context menu of the entry editing dialog +- After duplicating entries, KeePass now ensures that the + copies are visible +- User names of TAN entries are now dereferenced, if the option + for showing dereferenced data in the main window is enabled +- When creating an entry from a template, the new entry is now + selected and focused +- Empty fields are not included in detailed printouts anymore +- Enhanced Internet Explorer detection +- The '-preselect' command line option now works together with + relative database file paths +- Improved quoted app paths parsing +- Extended culture invariance +- Improved synchronization performance +- Improved internal keypress routing +- Last access times by default are not shown in the UI anymore +- TrlUtil: improved dialog focusing when showing message boxes +- KeePassLib/KPScript: improved support for running on systems + without any GUI +- Various code optimizations +- Minor other improvements + +- Fixed a crash that could occur if the option 'Show expired + entries (if any)' is enabled and a trigger switches to a + different locked database when unlocking a database +- The tab bar is now updated correctly after closing an + inactive database by middle-clicking its tab +- Column display orders that are unstable with respect to + linear auto-adjusting assignment are now restored correctly + +2013-07-20: 2.23 +- New password quality estimation algorithm +- Added toolbar buttons: 'Open URL(s)', 'Copy URL(s) to + Clipboard' and 'Perform Auto-Type' +- Added 'Generate Password' command in the context menu of the + KeePass system tray icon +- Added 'Copy history' option in the entry duplication dialog + (enabled by default) +- Added 'Duplicate Group' context menu command +- In the MRU list, currently opened files now have an + '[Opened]' suffix and are blue +- When a dialog is displayed, (double) clicking the KeePass + system tray icon now activates the dialog +- Added {T-REPLACE-RX:...} placeholder, which replaces text + using a regular expression +- Added {VKEY-NX X} and {VKEY-EX X} special key codes +- Added 'Perform auto-type with selected entry' trigger action +- Added 'Import into active database' trigger action +- Mozilla Bookmarks HTML import: added support for groups, + bookmark descriptions and icons +- Mozilla Bookmarks JSON import: bookmark descriptions are now + imported into the note fields of entries +- RoboForm import: added support for the new file format +- Added support for importing Network Password Manager 4.0 CSV + files +- Enhanced SafeWallet XML importer to additionally support + importing web entries and groups from very old export file + versions (for newer versions this was already supported) +- Added database repair mode warning +- Added option to accept invalid SSL certificates (turned off + by default) +- Added user activity notification event for plugins +- File transactions for FTP URLs are now always disabled when + running under .NET 4.0 in order to workaround .NET bug 621450 +- Added workaround for Mono list view item selection bug +- Added workaround for Mono bug 649266; minimizing to tray now + removes the task bar item and restoring does not result in a + broken window anymore +- Added workaround for Mono bug 5795; text and selections in + password boxes are now drawn properly (a monospace font can + only be used on Windows due to the bug) +- Added workaround for Mono bug 12525; dialog banners are now + drawn correctly again +- Added workaround for Mono form loading bug +- KPScript: added 'Import' command +- KPScript: the 'ListEntries' command now also outputs + date/time fields of entries + +- When the option for remembering the last used database is + enabled, KeePass now remembers the last active database + (instead of the last opened or saved database) +- The 'Add Group' command and the F2 key in the groups tree + view now open the group editing dialog; in-place tree node + label editing is disabled +- Custom string and plugin-provided columns in the 'Configure + Columns' dialog are sorted alphabetically now +- Improved behavior when closing inactive databases +- Improved support for trigger actions during database closing +- The 'Special' GUI character set now includes '|' and '~' +- The 'High ANSI' character set now consists of the range + [U+0080, U+00FF] except control and non-printable characters +- The options dialog is now listed in the task bar when it is + opened while KeePass is minimized to the system tray +- A remembered user account usage state can now be preset even + when the user account option is disabled using key prompt + configuration flags +- Improved initial input focus in key creation/prompt dialogs + when key creation/prompt configuration flags are specified +- During synchronization, the status dialog is now closed after + all files have been saved +- Improved behavior of the global KeePass activation hot key + when a dialog is displayed +- Changed auto-type command icon +- Shortened product name in main window title +- Improved data URI validation +- Custom clipboard data is now encoded as data URI (with a + vendor-specific MIME type) +- Improved configuration loading performance +- Enhanced I/O connection problem diagnostics +- Improved single instance checking on Unix-like systems +- KeePassLibC DLLs and ShInstUtil are now explicitly marked as + DEP- and ASLR-compatible (like the executable file) +- Various UI improvements +- Various code optimizations +- Minor other improvements + +- The suffixes to the 'Inherit setting from parent' options on + the 'Behavior' tab of the group editing dialog now correctly + show the inherited settings of the current group's parent +- When locked, the main window's title doesn't show the full + path of the database anymore when the option 'Show full path + in title bar (instead of file name only)' is turned off +- The status bar is now updated correctly after sorting by a + column + +2013-04-05: 2.22 +- When the option for remembering key sources is enabled, + KeePass now also remembers whether the user account is + required +- Added 'View' -> 'Grouping in Entry List' menu +- Added 'Close active database' trigger action +- Added '-ioiscomplete' command line option, which tells + KeePass that the path and file system credentials are + complete (the 'Open URL' dialog will not be displayed then) +- Added support for importing SafeWallet XML files (3.0.4 and + 3.0.5) +- Added support for importing TurboPasswords 5.0.1 CSV files +- LastPass CSV importer: added support for group trees +- Alle meine Passworte XML importer: added support for custom + fields and group names with special characters +- Password Safe XML importer: added support for the e-mail + field +- Added 'Help' button in the generic CSV importer dialog +- Added workaround for .NET bug 642188; top visible list view + items are now remembered in details view with groups enabled +- Added workaround for Mono form title bar text update bug + (which e.g. caused bug 801414) + +- After closing a character picking dialog, KeePass now + explicitly activates the previous window +- Improved behavior when cancelling the icon picker dialog +- Main window activation redirection now works with all KeePass + dialogs automatically +- The window state of the current database is now remembered + before opening another database +- Previous parameters are now discarded when switching between + different trigger event/condition/action types +- Unified separators in group paths +- The UI state is now updated after adding an entry and + clicking an entry reference link in the entry view +- The '-entry-url-open' command line option now searches for + matching entries in all open databases +- Improved database context determination when opening a URL +- Added support for special values in date/time fields imported + from KeePass 1.x +- Improved HTML entity decoding (support for more entities and + CDATA sections, improved performance, ...) +- RoboForm HTML importer: URLs are converted to lower-case now + and support for a special order rotation of attributes has + been added +- Removed Password Gorilla CSV importer; users should use the + generic CSV importer (which can import more data than the old + specialized CSV importer) +- Improved file discoveries +- Improved test form entry auto-type window definition +- In the MSI package, the version is now included in the + product name +- Native key transformation library: replaced Boost threads by + Windows API threads (because Boost threads can result in + crashes on restricted Windows 7 x64 systems) +- Various UI improvements +- Various code optimizations +- Minor other improvements + +2013-02-03: 2.21 +- Generic CSV importer: a group separator can be specified now + (for importing group trees) +- Internal data viewer: added hex viewer mode (which is now the + default for unknown data types) +- In the 'Show Entries by Tag' menu, the number of entries + having a specific tag is now shown right of the tag +- In the 'Add Tag' menu, a tag is now disabled if all selected + entries already have this tag +- Auto-Type: added support for right modifier keys +- Added special key codes: {WIN}, {LWIN}, {RWIN}, {APPS}, + {NUMPAD0} to {NUMPAD9} +- Interleaved sending of keys is now prevented by default (if + you e.g. have an auto-type sequence that triggers another + auto-type, enable the new option 'Allow interleaved sending + of keys' in 'Tools' -> 'Options' -> tab 'Advanced') +- Added '-auto-type-selected' command line option (other + running KeePass instances perform auto-type for the currently + selected entry) +- Added option to additionally show references when showing + dereferenced data (enabled by default) +- The selection in a secure edit control is now preserved when + unhiding and hiding the content +- The auto-type association editing dialog now does not hang + anymore when a window of any other application hangs +- When an application switches from the secure desktop to a + different desktop, KeePass now shows a warning message box; + clicking [OK] switches back to the secure desktop +- Added 'OK'/'Cancel' buttons in the icon picker dialog +- Added support for importing LastPass 2.0.2 CSV files +- KeePass now shows an error message when the user accidentally + attempts to use a database file as key file +- Added support for UTF-16 surrogate pairs +- Added UTF-8 BOM support for version information files +- The KeePass version is now also shown in the components list + in the 'About' dialog +- File operations are now context-independent (this e.g. makes + it possible to use the 'Activate database' trigger action + during locking) +- Plugins can now register their placeholders to be shown in + the auto-type item editing dialog +- Plugins can now subscribe to I/O access events +- Added workaround for .NET bug 694242; status dialogs now + scale properly with the DPI resolution +- Added workaround for Mono DataGridView.EditMode bug +- Added workaround for Mono bug 586901; high Unicode characters + in rich text boxes are displayed properly now + +- When the main window UI is being unblocked, the focus is not + reset anymore, if a primary control has the focus +- When opening the icon picker dialog, KeePass now ensures that + the currently selected icon is visible +- Internal data viewer: improved visibility updating +- The e-mail box icon by default is not inherited by new + entries anymore +- The database is now marked as modified when auto-typing a TAN + entry +- Enhanced AnyPassword importer to additionally support CSV + files exported by AnyPassword Pro 1.07 +- Enhanced Password Safe XML importer (KeePass tries to fix the + broken XML files exported by Password Safe 3.29 + automatically) +- I/O credentials can be loaded over IPC now +- Enhanced user switch detection +- Even when an exception occurs, temporary files created during + KDB exports are now deleted immediately +- Improved behavior on Unix-like systems when the operating + system does not grant KeePass access to the temporary + directory +- Improved critical sections that are not supposed to be re- + entered by the same thread +- Improved secure desktop name generation +- When a dialog is closed, references within the global client + image list to controls (event handlers) are removed now +- .NET 4.5 is now preferred, if installed +- PLGX plugins are now preferably compiled using the .NET 4.5 + compiler, if KeePass is currently running under the 4.5 CLR +- Updated KB links +- Changed naming of translation files +- The installer now always overwrites the KeePassLibC 1.x + support libraries +- Upgraded installer +- Various code optimizations +- Minor other improvements + +- When locking multiple databases and cancelling a 'Save + Changes?' dialog, the UI is now updated correctly +- '&' characters in dynamic menu texts, in dialog banner texts, + in image combobox texts, in text box prompts and in tooltips + are now displayed properly + +2012-10-04: 2.20.1 +- Improved support for images with DPI resolutions different + from the DPI resolution of the display device +- {GOOGLECHROME} placeholder: updated detection code to also + support the latest versions of Chrome +- The option to lock on remote control mode changes now + additionally watches for remote connects and disconnects +- Improved Windows registry accesses +- Improved behavior when the user deletes the system temporary + directory +- On Unix-like systems, KeePass now stores most of its + temporary files in a private temporary directory (preferably + in $XDG_RUNTIME_DIR) +- Added detection support for the following web browsers on + Unix-like systems: Rekonq, Midori and Dooble +- KeePass does not try to set the WM_CLASS property on MacOS + systems anymore +- Modified some icons to work around unsupported PNG + transparency keys in Mono +- Various code optimizations +- Minor other improvements + +2012-09-08: 2.20 +- Header data in KDBX files is now authenticated (to prevent + silent data corruption attacks; thanks to P. Gasti and K. B. + Rasmussen) +- Added management of working directories (a separate working + directory is remembered for each file dialog context; working + directories are remembered relatively to KeePass.exe; the + management can be deactivated by turning off the new option + 'Remember working directories') +- Added option to cancel auto-type when the target window title + changes +- Added quick search box in the toolbar of the internal text + editor +- Files can now be attached to entries by using drag&drop from + Windows Explorer to the attachments list in the entry editing + dialog +- Added '-pw-stdin' command line option to make KeePass read + the master password from the StdIn stream +- Added placeholders to get parts of the entry URL: {URL:SCM}, + {URL:HOST}, {URL:PORT}, {URL:PATH} and {URL:QUERY} +- Added a 'Details' button in the plugin load failure message + box (when clicked, detailed error information for developers + is shown) +- Added warning icon left of the Windows user account option + description in the master key creation dialog +- Added support for more image file formats (e.g. when + importing custom client icons) +- Added support for importing DesktopKnox 3.2 XML files +- The generic CSV importer now guesses whether the option to + ignore the first row should be enabled or not (the user of + course can still specify it manually, too) +- Added support for exporting to KeePass 1.x CSV files +- Added support for moving the PLGX cache to a different remote + drive +- The Spr engine is now extensible, i.e. plugins can provide + additional transformations/placeholders +- On Unix-like systems, KeePass now uses the 'xsel' utility for + clipboard operations, if 'xsel' is installed (in order to + work around Mono clipboard bugs) +- Added Mono workaround to set the WM_CLASS property +- Added workaround for Mono splitter bug +- The 'PrepMonoDev.sh' script now removes the serialization + assembly generating post build event +- TrlUtil: added support for importing PO files + +- Improved FTP file existence checking +- High DPI UI improvements +- The database is not marked as modified anymore when using in- + place label editing to fake-edit a group's name (i.e. when + the final new name is the same as the previous one) +- Password is not auto-repeated anymore when trying to unhide + it fails due to the policy 'Unhide Passwords' being disabled +- Improved menu accelerator and shortcut keys +- Changed I/O connection name display format +- Improved browser detection on MacOS +- Task dialog thread safety improvements +- Added UI check during import for KPScript +- Upgraded and improved installer (now uses Unicode, LZMA2 + compression, ...) +- Various UI improvements +- Various code optimizations +- Minor other improvements + +- On Windows systems, new line sequences in text to be shown in + a standard multiline text box are now converted to Windows + format + +2012-05-01: 2.19 +- New generic CSV importer (now supports multi-line fields, '\' + as escape character, field & record separators and the text + qualifier can be specified, white space characters can be + removed from the beginning/end of fields, the fields and + their order can be defined, supported fields now are group + name & standard fields like e.g. title & custom strings & + times & ignore column, the first row can be ignored, KeePass + initially tries to guess the fields and their order based on + the first row) +- Native master key transformations are now computed in two + threads on 64-bit systems, too; on dual/multi core processors + this results in almost twice the performance as before (by + doubling the amount of rounds you'll get the same waiting + time as in 2.18, but the protection against dictionary and + guessing attacks is doubled) +- New XML configuration and translation deserializer to improve + the startup performance +- Added option to require a password repetition only when + hiding using asterisks is enabled (enabled by default) +- Entry attachments can now be renamed using in-place label + editing (click on an already selected item to show an edit + box) +- Empty entry attachments can now be created using 'Attach' -> + 'Create Empty Attachment' +- Sizes of entry attachments are now shown in a column of the + attachments list in the entry editing dialog +- Added {ENV_PROGRAMFILES_X86} placeholder (this is + %ProgramFiles(x86)%, if it exists, otherwise %ProgramFiles%) +- Added auto-type option 'An entry matches if one of its tags + is contained in the target window title' +- URLs in HTML exports are now linkified +- Import modules may now specify multiple default/equivalent + file extensions (like e.g. 'htm' and 'html') +- Added support for reading texts encoded using UTF-32 Big + Endian +- Enhanced text encoding detection (now detects UTF-32 LE/BE + and UTF-16 LE/BE by zeros, improved UTF-8 detection, ...) +- Added zoom function for images in internal data viewer +- Drop-down image buttons in the entry editing dialog are now + marked using small black triangle overlays +- Added support for loading key files from URLs +- Controls in the options dialog are now disabled when the + options are enforced (using an enforced configuration file) +- If KeePass is started with the '-debug' command line option, + KeePass now shows a developer-friendly error message when + opening a database file fails +- Added 'Wait for exit' property in the 'Execute command line / + URL' trigger action +- The 'File exists' trigger condition now also supports URLs +- Added two file closing trigger events (one raised before and + one after saving the database file) +- Plugins: added file closing events +- Plugins: added events (AutoType.Sequence*) that allow plugins + to provide auto-type sequence suggestions +- Added workaround to support loading data from version + information files even when they have incorrectly been + decompressed by a web filter +- Added workarounds for '°', '|' and '£' .NET SendKeys issues +- Added workaround for topmost window .NET/Windows issue (the + 'Always on Top' option now works even when switching to a + different window while KeePass is starting up) +- Added workaround for Mono dialog event ordering bug +- Added workaround for Mono clipboard bugs on MacOS +- KPScript: added 'MoveEntry', 'GetEntryString' and 'GenPw' + commands +- KPScript: added '-refx-UUID' and '-refx-Tags' entry + identification parameters + +- When only deleting history entries (without changing any data + field of an entry), no backup entry is created anymore +- Unified text encoding handling for internal data viewer and + editor, generic CSV importer and text encoding selection + dialog +- Improved font sizing in HTML exports/printouts +- Improved encoding of group names in HTML exports/printouts +- If an entry doesn't expire, 'Never expires' is now shown in + the 'Expiry Time' column in HTML exports/printouts +- The expiry edit control now accepts incomplete edits and the + 'Expires' checkbox is checked immediately +- The time component of the default expiry suggestion is now + 00:00:00 +- The last selected/focused item in the attachments list of the + entry editing dialog is now selected/focused after editing an + attachment +- Improved field to standard field mapping function +- Enhanced RoboForm importer to concatenate values of fields + with conflicting names +- Updated Spamex.com importer +- Removed KeePass 1.x CSV importer; users should use the new + generic CSV importer (which can import more data than the old + specialized 1.x CSV importer) +- When trying to open another database while a dialog is + displayed, KeePass now just brings itself to the foreground + without attempting to open the second database +- More list views use the Vista Explorer style +- Modifier keys without another key aren't registered as global + hot key anymore +- Improved default suggestions for custom sequences in the + auto-type sequence editing dialog +- Improved default focus in the auto-type sequence editing + dialog +- Added {C:Comment} placeholder in the auto-type sequence + editing dialog +- On Unix-like systems, the {GOOGLECHROME} placeholder now + first searches for Google Chrome and then (if not found) for + Chromium +- Versions displayed in the update checking dialog now consist + of at least two components +- Added '@' and '`' to the printable 7-bit ASCII character set +- Merged simple and extended special character spaces to one + special character space +- Reduced control character space from 60 to 32 +- The first sample entry's URL now points to the KeePass + website +- Improved key transformation delay calculation +- Improved key file loading performance +- The main menu now isn't a tab stop anymore +- Some configuration nodes are now allocated only on demand +- Improved UI update when moving/copying entries to the + currently active group or a subgroup of it using drag&drop +- Improved behavior when closing an inactive database having + unsaved changes +- Changed versioning scheme in file version information blocks + from digit- to component-based +- Development snapshots don't ask anymore whether to enable the + automatic update check (only stable releases do) +- Improved PLGX cache directory naming +- The PLGX cache directory by default is now located in the + local application data folder instead of the roaming one +- Improved support for PLGX plugins that are using LINQ +- Various UI improvements +- Various code optimizations +- Minor other improvements + +- Fixed sorting of items in the most recently used files list +- Fixed tab order in the 'Advanced' tab of the entry editing + dialog + +2012-01-05: 2.18 +- The update check now also checks for plugin updates (if + plugin developers provide version information files) +- When starting KeePass 2.18 for the first time, it asks + whether to enable the automatic update check or not (if not + enabled already) +- When closing the entry editing dialog by closing the window + (using [X], Esc, ...) and there are unsaved changes, KeePass + now asks whether to save or discard the changes; only when + explicitly clicking the 'Cancel' button, KeePass doesn't + prompt +- When not hiding passwords using asterisks, they don't need to + be repeated anymore +- Password repetition boxes now provide instant visual feedback + whether the password has been repeated correctly (if + incorrect, the background color is changed to light red) +- When clicking an '***' button to change the visibility of the + entered password, KeePass now automatically transfers the + input focus into the password box +- Visibility of columns in the auto-type entry selection dialog + can now be customized using the new 'Options' button +- Added auto-type option 'An entry matches if the host + component of its URL is contained in the target window title' +- Added shortcut keys: Ctrl+Shift+O for 'Open URL', + Ctrl+Shift+U for copying URLs to the clipboard, Ctrl+I for + 'Add Entry', Ctrl+R for synchronizing with a file, + Ctrl+Shift+R for synchronizing with a URL +- Ensuring same keyboard layouts during auto-type is now + optional (option enabled by default) +- Plain text KDB4 XML exports now store the memory protection + flag of strings in an attribute 'ProtectInMemory' +- Added option to use database lock files (intended for storage + providers that don't lock files while writing to them, like + e.g. some FTP servers); the option is turned off by default + (and especially for local files and files on a network share + it's recommended to leave it turned off) +- Added UIFlags bit for disabling the controls to specify after + how many days the master key should/must be changed +- Added support for in-memory protecting strings that are + longer than 65536 characters +- Added workaround for '@' .NET SendKeys issue + +- .NET 4.0 is now preferred, if installed +- PLGX plugins are now preferably compiled using the .NET 4.0 + compiler, if KeePass is currently running under the 4.0 CLR +- Automatic update checks are now performed at maximum once per + day (you can still check manually as often as you wish) +- Auto-Type: entry titles and URLs are now Spr-compiled before + being compared with the target window title +- Decoupled the options 'Show expired entries' and 'Show + entries that will expire soon' +- Specifying the data hiding setting (using asterisks) in the + column configuration dialog is now done using a checkbox +- The entry view now preferably uses the hiding settings + (asterisks) of the entry list columns +- Improved entry expiry date calculation +- Enhanced Password Agent importer to support version 2.6.2 +- Enhanced SplashID importer to import last modification dates +- Improved locating of system executables +- Password generator profiles are now sorted by name +- Separated built-in and user-defined password generator + profiles (built-in profiles aren't stored in the + configuration file anymore) +- Improved naming of shortcut keys, and shortcut keys are now + displayed in tooltips +- Internal window manager can now close windows opened in other + threads +- Improved entry touching when closing the entry editing dialog + by closing the window (using [X], Esc, ...) +- Improved behavior when entering an invalid URL in the 'Open + URL' dialog +- Improved workaround for Mono tab bar height bug +- ShInstUtil: improved Native Image Generator version detection +- Unified in-memory protection +- In-memory protection performance improvements +- Developers: in-memory protected objects are now immutable and + thread-safe +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- The cached/temporary custom icons image list is now updated + correctly after running the 'Delete unused custom icons' + command + +2011-10-19: 2.17 +- Multiple auto-type sequences can now be defined for a window + in one entry +- The auto-type entry selection dialog now displays the + sequence that will be typed +- The auto-type entry selection dialog is now resizable; + KeePass remembers the dialog's position, size and the list + view column widths +- Added auto-type option 'An entry matches if its URL is + contained in the target window title' +- Added two options to show dereferenced data in the main entry + list (synchronously or asynchronously) +- Dereferenced data fields are now shown in the entry view of + the main window and the auto-type entry selection dialog + (additionally to the references) +- Field references in the entry view are now clickable; when + clicking one, KeePass jumps to the data source entry +- Added option in the 'Find' dialog to search in dereferenced + data fields +- Added option to search in dereferenced data fields when + performing a quick search (toolbar in main window) +- The 'Find' dialog now shows a status dialog while searching + for entries +- The main window now shows a status bar and the UI is disabled + while performing a quick search +- Added context menu commands to open the URL of an entry in a + specific browser +- Added {SAFARI} browser path placeholder +- Added {C:...} comment placeholder +- Added entry duplication options dialog (appending "- Copy" to + entry titles, and/or replacing user names and passwords by + field references to the original entries) +- Added option to focus the quick search box when restoring + from taskbar (disabled by default) +- Added tray context menu command to show the options dialog +- Source fields are now compiled before using them in a + {PICKCHARS} dialog +- Added 'Copy Link' rich text box context menu command +- Before printing, the data/format dialog now shows a print + dialog, in which the printer can be selected +- Added application policy to ask for the current master key + before printing +- Added support for importing Passphrase Keeper 2.50 HTML files + (in addition to the already supported 2.70 format) +- KeePass now removes zone identifiers from itself, ShInstUtil + and the CHM help file +- Listing currently opened windows works under Unix-like + systems now, too +- Alternating item background colors are now also supported in + list views with item groups +- IOConnection now supports reading from data URIs (RFC 2397) +- Group headers are now skipped when navigating in single + selection list views using the arrow keys +- Added detection support for the following web browsers on + Unix-like systems: Firefox, Opera, Chromium, Epiphany, Arora, + Galeon and Konqueror +- Added documentation of the synchronization feature +- Key provider plugins can now declare that they're compatible + with the secure desktop mode, and a new property in the query + context specifies whether the user currently is on the secure + desktop +- Added workaround for a list view sorting bug under Windows XP +- Added workaround for a .NET bug where a cached window state + gets out of sync with the real window state +- Added workaround for a Mono WebRequest bug affecting WebDAV + support + +- Items in the auto-type entry selection dialog can now be + selected using a single click +- When performing global auto-type, the Spr engine now uses the + entry container database instead of the current database as + data source +- The generated passwords list in the password generator dialog + now uses the password font (monospace by default) +- The last modification time of an entry is now updated when a + new password is generated using the {NEWPASSWORD} placeholder +- The overlay icon for the taskbar button (on Windows 7) is now + restored when Windows Explorer crashes and when starting in + minimized and locked mode +- Improved opening of CHM help file +- The buttons in file save dialogs now have accelerator keys +- Separated URL scheme overrides into built-in and custom ones +- Improved tray command state updating +- The default tray command is now rendered using a bold font +- The main window is now disabled while searching and removing + duplicate entries +- Improved banner handling/updating in resizable dialogs +- The 'Ctrl+U' shortcut hint is now moved either to the open or + to the copy command, depending on whether the option 'Copy + URLs to clipboard instead of opening them' is enabled or not +- Improved command availability updating of rich text context + menus +- Quick searches are now invoked asynchronously +- Improved quick search performance +- The option to minimize the main window after locking the + KeePass workspace is now enabled by default +- When performing auto-type, newline characters are now + converted to Enter keypresses +- Auto-type on Unix-like systems: improved sending of backslash + characters +- On Unix-like systems, the default delay between auto-typed + keystrokes is now 3 ms +- Spr engine performance improvements +- Changing the in-memory protection state of a custom entry + string is now treated as a database change +- Some options in the options dialog are now linked (e.g. the + option 'Automatically search key files also on removable + media' can only be enabled when 'Automatically search key + files' is enabled) +- Most items with default values aren't written to the + configuration file anymore (resulting in a smaller file and + making it possible to change defaults in future versions) +- Path separators in the configuration file are now updated for + the current operating system +- Improved 'xdotool' version detection +- Improved I/O response handling when deleting/renaming files +- Various UI text improvements +- Various code optimizations +- Minor other improvements + +- Status bar text is now correctly updated to 'Ready' after an + unsuccessful/cancelled database opening attempt +- Password generation based on patterns: escaped curly brackets + are now parsed correctly + +2011-07-12: 2.16 +- When searching for a string containing a whitespace + character, KeePass now splits the terms and reports all + entries containing all of the terms (e.g. when you search for + "Forum KeePass" without the quotes, all entries containing + both "Forum" and "KeePass" are reported); the order of the + terms is arbitrary; if you want to search for a term + containing whitespace, enclose the term in quotes +- When searching for a term starting with a minus ('-'), all + entries that do not contain the term are reported (e.g. when + you search for "Forum -KeePass" without the quotes, all + entries containing "Forum" but not "KeePass" are reported) +- Added dialog in the options to specify a web proxy (none, + system or manual) and user name and password for it +- Added option to always exit instead of locking the workspace +- Added option to play the UAC sound when switching to a secure + desktop (enabled by default) +- Added filter box in the field references creation dialog +- Added command to delete duplicate entries (entries are + considered to be equal when their strings and attachments are + the same, all other data is ignored; if one of two equal + entries is in the recycle bin, it is deleted preferably; + otherwise the decision is based on the last modification + time) +- Added command to delete empty groups +- Added command to delete unused custom icons +- For Unix-like systems: new file-based IPC broadcast mechanism + (supporting multiple endpoints) +- For Unix-like systems: added file-based global mutex + mechanism +- Auto-type on Unix-like systems: added support for sending + square brackets and apostrophes +- Two-channel auto-type obfuscation is now supported on + Unix-like systems, too +- Web access on Unix-like systems: added workarounds for non- + implemented cache policy and credentials requirement +- Added context menu command to empty the recycle bin (without + deleting the recycle bin group) +- On Windows Vista and higher, when trying to delete a group, + the confirmation dialog now shows a short summary of the + subgroups and entries that will be deleted, too +- In the auto-type target window drop-down combobox, icons are + now shown left of the window names +- Added {CLEARFIELD} auto-type command (to clear the contents + of single-line edit controls) +- Added support for importing Sticky Password 5.0 XML files + (formatted memos are imported as RTF file attachments, which + you can edit using the internal KeePass editor; e.g. right- + click on the entry in the main window and go 'Attachments' -> + 'Edit Notes.rtf' or click on the attachment in the entry view + at the bottom of the main window; see 'How to store and work + with large amounts of formatted text?' in the FAQ) +- Added support for importing Kaspersky Password Manager 5.0 + XML files (formatted memos are imported the same as by the + Sticky Password importer, see above) +- Password Depot importer: added support for more fields (new + time fields and usage count), time fields can be imported + using the stored format specifier, vertical tabulators are + removed, improved import of information cards, and auto-type + sequences are converted now +- Added ability to export links into the root directory of + Windows/IE favorites +- Windows/IE favorites export: added configuration items to + specify a prefix and a suffix for exported links/files +- In the entry editing dialog, KeePass now opens an attachment + either in the internal editor or in the internal viewer, + depending on whether the format is supported by the editor +- When creating a new database, KeePass now automatically + creates a second sample entry, which is configured for the + test form in the online help center +- Added configuration option to disable the 'Options', + 'Plugins' and/or 'Triggers' menu items +- Added workaround for Mono tab bar height bug +- Added workaround for Mono FTP bug +- Added workaround for Mono CryptoStream bug +- Added workaround for a Mono bug related to focusing list view + items +- Added shell script to prepare the sources for MonoDevelop +- Translations can now also be loaded from the KeePass + application data directory +- TrlUtil: added support for ellipses as alternative to 3 dots +- KPScript: added 'DetachBins' command to save all entry + attachments (into the directory of the database) and remove + them from the database + +- After performing a quick-find, the search text is now + selected +- Improved quick-find deselection performance +- On Unix-like systems, command line parameters prefixed with a + '/' are now treated as absolute file paths instead of options +- Improved IPC support on Unix-like systems +- Locked databases can now be dismissed using the close command +- Invalid target windows (like the taskbar, own KeePass + windows, etc.) are not shown in the auto-type target window + drop-down combobox anymore +- Newly created entries are now selected and focused +- The entry list is now focused when duplicating and selecting + all entries +- If KeePass is blocked from showing a dialog on the secure + desktop, KeePass now shows the dialog on the normal desktop +- Improved dialog initialization on the secure desktop +- The current status is now shown while exporting Windows/IE + favorites +- Windows/IE favorites export: improved naming of containing + folder when exporting selected entries only +- Windows/IE favorites export: if a group doesn't contain any + exportable entry, no directory is created for this group + anymore +- Improved data editor window position/size remembering +- Key modifiers of shortcut key strings are translated now +- Shortcut keys of group and entry commands are now also shown + in the main menu +- When no template entries are specified/found, this is now + indicated in the 'Add Entry' toolbar drop-down menu +- When deleting a group, its subgroups and entries are now + added correctly to the list of deleted objects +- Font handling improvements +- Improved lock timeout updating when a dialog is displayed +- Improved export error handling +- Improved FIPS compliance problems self-test (error message + immediately at start), and specified configuration option to + prevent .NET from enforcing FIPS policy +- Various code optimizations +- Minor other improvements + +- Last modification time is now updated when restoring an older + version of an entry +- When duplicating an entry, the UUIDs of history items are now + changed, too + +2011-04-10: 2.15 +- Added option to show the master key dialog on a secure + desktop (similar to Windows' UAC; almost no keylogger works + on a secure desktop; the option is disabled by default for + compatibility reasons) +- Added option to limit the number of history items per entry + (the default is 10) +- Added option to limit the history size per entry (the default + is 6 MB) +- Added {PICKCHARS} placeholder, which shows a dialog to pick + certain characters from an entry string; various options like + specifying the number of characters to pick and conversion to + down arrow keypresses are supported; see the one page long + documentation on the auto-type help page; the less powerful + {PICKPASSWORDCHARS} is now obsolete (but still supported for + backward compatibility) +- The character picking dialog now remembers and restores its + last position and size +- KDBX file format: attachments are now stored in a pool within + the file and entries reference these items; this reduces the + file size a lot when there are history items of entries + having attachments +- KDBX file format: attachments are now compressed (if the + compression option is enabled) before being Base64-encoded, + compressed and encrypted; this results in a smaller file, + because the compression algorithm works better on the raw + data than on its encoded form +- PLGX plugins can now be loaded on Unix-like systems, too +- Added option to specify a database color; by specifying a + color, the main window icon and the tray icon are recolored + and the database tab (shown when multiple databases are + opened in one window) gets a colored rectangle icon +- New rich text builder, which supports using multiple + languages in one text (e.g. different Chinese variants) +- Added 'Sort By' popup menu in the 'View' menu +- Added context menu commands to sort subgroups of a group +- Added option to clear master key command line parameters + after using them once (enabled by default) +- Added application policies to ask for the current master key + before changing the master key and/or exporting +- Added option to also unhide source characters when unhiding + the selected characters in the character picking dialog +- Added ability to export custom icons +- Added 'String' trigger condition +- Added support for importing DataViz Passwords Plus 1.007 CSV + files +- Enhanced 1Password Pro importer to also support 1PW CSV files +- Enhanced FlexWallet importer to also support version 2006 XML + files (in addition to version 1.7 XML files) +- Enabled auto-suggest for editable drop-down combo boxes (and + auto-append where it makes sense) +- Pressing Ctrl+Enter in the rich text boxes of the entry + dialog and the custom string dialog now closes with OK (if + possible) +- Added option to cancel auto-type when the target window + changes +- Auto-type on Unix-like systems: added support for key + modifiers +- Added '--saveplgxcr' command line option to save compiler + results in case the compilation of a PLGX plugin fails +- Added workaround for % .NET SendKeys issue +- Added workaround for Mono bug 620618 in the main entry list + +- Improved key file suggestion performance +- When the master key change application policy is disabled and + the master key expires (forced change), KeePass now shows the + two information dialogs only once per opening +- After removing the password column, hiding behind asterisks + is suggested by default now when showing the column again +- TAN entries now expire on auto-type, if the option for + expiring TANs on use is enabled +- Auto-type now sends acute and grave accents as separate + characters +- Auto-type now explicitly skips the taskbar window when + searching for the target window +- Multiple lines are now separated in the entry list and in the + custom string list of the entry dialog by a space +- RoboForm importer: improved multiline value support +- Improved UNC path support +- Improved entry list refresh performance +- Improved UI state update performance +- Entry list context menus are now configured instantly +- Inapplicable group commands are now disabled +- Improved control focusing +- Improved clipboard handling +- Copying and pasting whole entries is now also supported on + Windows 98 and ME +- Improved releasing of dialog resources +- Improved keys/placeholders box in auto-type editing dialog +- Improved user-friendliness in UAC dialogs +- Tooltips of the tab close button and the password repeat box + can be translated now +- Improved help (moved placeholders to separate page, ...) +- KeePassLibSD now uses the SHA-256 implementation of Bouncy + Castle +- Upgraded installer +- Various code optimizations +- Minor other improvements + +- Window titles are now trimmed, such that auto-type also works + with windows whose titles have leading or trailing whitespace + characters +- Detection of XSL files works under Linux/MacOS now, too + +2011-01-02: 2.14 +- Added option to lock after some time of global user + inactivity +- Added option to lock when the remote control status changes +- Auto-type on Unix-like systems: added special key code + support (translation to X KeySyms) and support for {DELAY X} + and {DELAY=X} +- Added window activation support on Unix-like systems +- Auto-type on Windows: added {VKEY X} special key code (sends + virtual key X) +- Added support for importing DataVault 4.7 CSV files +- Added support for importing Revelation 0.4 XML files +- Added 'Auto-Type - Without Context' application policy to + disable the 'Perform Auto-Type' command (Ctrl+V), but still + leave global auto-type available +- Added option to collapse newly-created recycle bin tree nodes +- Added 'Size' column in the history list of the entry dialog +- Added trigger action to remove custom toolbar buttons +- Added kdbx:// URL scheme overrides (for Windows and Unix-like + systems; disabled by default) +- Added KeePass.exe.config file to redirect old assemblies to + the latest one, and explicitly declare .NET 4.0 runtime + support +- Added documentation for the '-pw-enc' command line parameter, + the {PASSWORD_ENC} placeholder and URL overrides +- Added workaround for ^/& .NET SendKeys issue + +- New locking timer (using a timeout instead of a countdown) +- Improved locking when the Windows session is being ended or + switched +- Improved multi-database locking +- Separated the options for locking when the computer is locked + and the computer is about to be suspended +- {FIREFOX} placeholder: added support for registry-redirected + 32-bit Firefox installations on 64-bit Windows systems +- File transactions: the NTFS/EFS encryption flag is now also + preserved when the containing directory isn't encrypted +- The IPC channel name on Unix-like systems is now dependent on + the current user and machine name +- KeePass now selects the parent group after deleting a group +- Entries are now marked as modified when mass-changing their + colors or icons +- Key states are now queried on interrupt level +- A {DELAY=X} global delay now affects all characters of a + keystroke sequence when TCATO is enabled, too +- Improved dialog closing when exiting automatically +- Plugin-provided entry list columns can now be right-aligned + at KeePass startup already +- Removed KDBX DOM code +- Installer: the KeePass start menu shortcut is now created + directly in the programs folder; the other shortcuts have + been removed (use the Control Panel for uninstalling and the + 'Help' menu in KeePass to access the help) +- Various code optimizations +- Minor other improvements + +- Quotes in parameters for the 'Execute command line / URL' + trigger action are now escaped correctly +- Auto-type on Unix-like systems: window filters without + wildcards now match correctly + +2010-09-06: 2.13 +- Password quality estimation algorithm: added check for about + 1500 most common passwords (these are rated down to 1/8th of + their statistical rating; Bloom filter-based implementation) +- Global auto-type (using a system-wide hot key) is now + possible on Unix-like systems (see the documentation for + setup instructions, section 'Installation / Portability' in + the 'KeePass 2.x' group; thanks to Jordan Sissel for + enhancing 'xdotool') +- Added IPC functionality for Unix-like systems +- Added possibility to write export plugins that don't require + an output file +- Tag lists are sorted alphabetically now +- Password text boxes now use a monospace font by default +- Added option to select a different font for password text + boxes (menu 'Tools' -> 'Options' -> tab 'Interface') +- Added support for importing Password Prompter 1.2 DAT files +- Added ability to export to Windows/IE favorites +- Added ability to specify I/O credentials in the 'Synchronize' + trigger action +- Added ability to specify I/O credentials and a master key in + the 'Open database file' trigger action +- If I/O credentials are stored, they are now obfuscated +- Custom colors in the Windows color selection dialog are now + remembered +- Added high resolution version of the KeePass application icon +- Improved lock overlay icon (higher resolution) +- PLGX loader: added support for unversioned KeePass assembly + references + +- Added workaround to avoid alpha transparency corruption when + adding images to an image list +- Improved image list generation performance +- Added workaround to display the lock overlay icon when having + enabled the option to start minimized and locked +- Improved group and entries deletion confirmation dialogs + (with preview; only Windows Vista and higher) +- The password character picking dialog now offers the raw + password characters instead of an auto-type encoded sequence +- PINs importer: improved importing of expiry dates +- Some button icons are now resized to 16x15 when the 16x16 + icon is too large +- Renamed character repetition option in the password generator + for improved clarity +- Improved workspace locking +- Locking timer is now thread-safe +- Added code to prevent loading libraries from the current + working directory (to avoid binary planting attacks) +- Removed Tomboy references (on Unix-like systems) +- Various code optimizations +- Minor other improvements + +- {NEWPASSWORD} placeholder: special characters in generated + passwords are now transformed correctly based on context + (auto-type, command line, etc.) + +2010-07-09: 2.12 +- Auto-type window definitions in custom window-sequence pairs + are now Spr-compiled (i.e. placeholders, environment + variables, etc. can be used) +- Global auto-type delay: added support for multi-modified keys + and special keys +- Added 'New Database' application policy flag +- Added 'Copy Whole Entries' application policy flag +- Multi-monitor support: at startup, KeePass now ensures that + the main window's normal area at least partially overlaps the + virtual screen rectangle of at least one monitor +- RoboForm importer: URLs without protocol prefix are now + prefixed automatically (HTTP) +- Entry-dependent placeholders can now be used in most trigger + events, conditions and actions (the currently focused entry + is used) +- Auto-type on Unix-like systems: KeePass now shows an + informative error message when trying to invoke auto-type + without having installed the 'xdotool' package + +- New column engine: drag&dropping hidden fields works as + expected again (the field data is transferred, not asterisks) +- Improved restoration of a maximized main window +- Improved error message when trying to import/export data + from/to a KDB file on a non-Windows operating system +- Minor other improvements + +2010-07-03: 2.11 +- Added entry tags (you can assign tags to entries in the entry + editing window or by using the 'Selected Entries' context + menu; to list all entries having a specific tag, choose the + tag either in the 'Edit' main menu or in the 'Show Entries' + toolbar drop-down button) +- Completely new entry list column engine; the columns are + dynamic now, custom entry strings can be shown in the list, + to configure go 'View' -> 'Configure Columns...'; the column + engine is also extensible now, i.e. plugins can provide new + columns +- Added 'Size' entry list column (shows the approximate memory + required for the entry) +- Added 'History (Count)' entry list column (double-clicking a + cell of this column opens the entry editing window and + automatically switches to the 'History' tab) +- Added 'Expiry Time (Date Only)' entry list column +- Added options to specify the number of days until the master + key of a database is recommended to and/or must be changed +- Added support for exporting selected entries to KDB +- Added 'FileSaveAsDirectory' configuration key to specify the + default directory for 'Save As' database file dialogs +- Double-clicking a history entry in the entry editing dialog + now opens/views the entry +- It's now possible to tab from menus and toolbars to dialog + controls +- Added option to turn off hiding in-memory protected custom + strings using asterisks in the entry view +- Added workaround for FTP servers sending a 550 error after + opening and closing a file without downloading data +- Added 'Unhide Passwords' application policy flag +- Password Depot importer: some icons are converted now +- {GOOGLECHROME} placeholder: updated detection code to also + support the latest versions of Chrome +- The main window now uses the shell font by default +- On Windows Vista and higher, Explorer-themed tree and list + views are now used in the main window +- On Windows 7 and higher, the main window peek preview is now + disabled when the KeePass workspace is locked +- Installer: added option to optimize the on-demand start-up + performance of KeePass +- TrlUtil: added 3 dots string validation + +- Improved entry list item selection performance (defer UI + state update on selection change burst) +- Improved special key code conversion in KDB importer +- Icon picker dialog now has a 'Close' button +- When sorting is enabled, the entry list view now doesn't get + destroyed anymore when trying to move entries +- Main window is now brought to the foreground when untraying +- Removed grid lines option +- Reduced size of MSI file +- Various performance improvements +- Various code optimizations +- Minor other improvements + +- No file path is requested anymore when double-clicking an + import source that doesn't require a file + +2010-03-05: 2.10 +- Translation system: added support for right-to-left scripts +- Added {HMACOTP} placeholder to generate HMAC-based one-time + passwords as specified in RFC 4226 (the shared secret is the + UTF-8 representation of the value of the 'HmacOtp-Secret' + custom entry string field, and the counter is stored in + decimal form in the 'HmacOtp-Counter' field) +- On Windows 7, KeePass now shows a 'locked' overlay icon on + the taskbar button when the database is locked +- On Windows 7, the database loading/saving progress is now + shown on the taskbar button +- Added option to disable automatic searching for key files +- Added KDBX database repair functionality (in File -> Import) +- Added support for expired root groups +- Added global delay support for shifted special keys +- Added 'Change Master Key' application policy flag +- Added 'Edit Triggers' application policy flag +- Added trigger action to activate a database (select tab) +- Added configuration options to allow enforcing states + (enabled, disabled, checked, unchecked) of key source + controls in the master key creation and prompt dialogs + (see 'Composite Master Key' documentation page) +- Added option to disable the 'Save' command (instead of + graying it out) if the database hasn't been modified +- Added support for importing KeePassX 0.4.1 XML files +- Added support for importing Handy Safe 5.12 TXT files +- Added support for importing Handy Safe Pro 1.2 XML files +- Added support for importing ZDNet's Password Pro 3.1.4 TXT + files +- Added dialog for selecting the encoding of text files to be + attached to an entry +- Added option to search for passwords in quick finds (disabled + by default) +- Added Ctrl+S shortcut in the internal data editor +- Internal data editor window can now be maximized +- Document tabs can now be closed by middle-clicking on them +- Most strings in the trigger system are now Spr-compiled (i.e. + placeholders, environment variables, etc. can be used) +- Added '--lock-all' and '--unlock-all' command line options to + lock/unlock the workspaces of all other KeePass instances +- Added 'pw-enc' command line option and {PASSWORD_ENC} + placeholder +- Added preliminary auto-type support for Linux (right-click on + an entry and select 'Perform Auto-Type'; the 'xdotool' + package is required) +- Added option to enforce using the system font when running + under KDE and Gnome (option enabled by default) +- HTML exports are now XHTML 1.0 compliant +- Printing: added option to sort entries +- Printing: group names are now shown as headings +- KPScript: added '-CreateBackup' option for the EditEntry + command (to create backups of entries before modifying them) +- The PLGX plugin cache root path can now be specified in the + configuration file (Application/PluginCachePath) +- Plugin developers: added ability to write entropy providers + that can update the internal pool of the cryptographically + strong random number generator +- Plugin developers: added some public PwEntryForm properties, + events and methods +- Plugin developers: added entry template events +- Plugin developers: added group and entry touching events +- Plugin developers: added main window focus changing event +- Plugin developers: added support for writing format providers + for the internal attachments viewer + +- Expired icons of groups are non-permanent now +- Improved search performance and in-memory protection + compatibility +- The SendKeys class now always uses the SendInput method (not + JournalHook anymore) +- Improved auto-type delay handling +- Two-channel auto-type obfuscation: added support for default + delays +- The default auto-type delay is now 10 ms +- Improved top-most window auto-type support +- Improved high DPI support (text rendering, banners, ...) +- Temporary file transaction files are now deleted before + writing to them +- Broadcasted file IPC notification messages do not wait + infinitely for hanging applications anymore +- On Windows XP and higher, KeePass now uses alpha-transparent + icons in the main entry list +- In the entry editing dialog, when moving a custom string to a + standard field, the string is now appended to the field + (instead of overwriting the previous contents of the field) +- Improved UTF-8 encoding (don't emit byte order marks) +- Improved field to standard field mapping function +- HTML exports do not contain byte-order marks anymore +- For improved clarity, some controls are now renamed/changed + dynamically when using the password generator without having + a database open +- Improved auto-type definition conversion for KDB exports +- Standard field placeholders are now correctly removed when + auto-typing, if the standard field doesn't exist +- Improved icon picker cancel blocking when removing an icon +- The default workspace locking time is now 300 seconds (but + the option is still disabled by default) +- Modern task dialogs are now displayed on 64-bit Windows + systems, too +- Improved file corruption error messages +- Improved entry attachments renaming method +- Double-clicking an attachment in the entry editing dialog now + opens it in the internal viewer (the internal editor can only + be invoked in the main window) +- When attachments are edited using the internal editor, the + entry's last modification time is now updated +- Improved plugin loading (detect PLGX cache files) +- If the application policy disallows clipboard operations, + KeePass doesn't unnecessarily decrypt sensitive data anymore +- Added tooltip for the 'View' toolbar drop-down button +- Improved menu accelerator and shortcut keys +- Upgraded installer +- Installer: various minor improvements +- Various performance improvements +- Various code optimizations +- Minor other improvements + +- No exception is thrown anymore when lowering the clipboard + auto-clear time in the options below the value of a currently + running clearing countdown +- The 'Show expired entries' functionality now also works when + there's exactly one matching entry + +2009-09-12: 2.09 +- Added option to use file transactions when writing databases + (enabled by default; writing to a temporary file and + replacing the actual file afterwards avoids data loss when + KeePass is prevented from saving the database completely) +- Added PLGX plugin file format +- Enhanced database synchronization by structure merging + (relocation/moving and reordering groups and entries) +- Added synchronization 'Recent Files' list (in 'File' menu) +- Synchronization / import: added merging of entry histories +- Synchronization / import: backups of current entries are + created automatically, if their data would be lost in the + merging process +- Database name, description, default user name, entry + templates group and the recycle bin settings are now + synchronized +- Added {NEWPASSWORD} placeholder, which generates a new + password for the current entry, based on the "Automatically + generated passwords for new entries" generator profile; this + placeholder is replaced once in an auto-type process, i.e. + for a typical 'Old Password'-'New Password'-'Repeat New + Password' dialog you can use + {PASSWORD}{TAB}{NEWPASSWORD}{TAB}{NEWPASSWORD}{ENTER} +- Added scheme-specific URL overrides (this way you can for + example tell KeePass to open all http- and https-URLs with + Firefox or Opera instead of the system default browser; PuTTY + is set as handler for ssh-URLs by default; see Options -> + Integration) +- Added option to drop to the background when copying data to + the clipboard +- Added option to use alternating item background colors in the + main entry list (option enabled by default) +- The Ctrl+E shortcut key now jumps to the quick search box +- Added auto-type sequence conversion routine to convert key + codes between 1.x and 2.x format +- Added workaround for internal queue issue in SendKeys.Flush +- Added more simple clipboard backup routine to workaround + clipboard issues when special formats are present +- Added native clipboard clearing method to avoid empty data + objects being left in the clipboard +- Added import support for custom icons +- Added {GOOGLECHROME} placeholder, which is replaced by the + executable path of Google Chrome, if installed +- Added {URL:RMVSCM} placeholder, which inserts the URL of the + current entry without the scheme specifier +- Added ability to search for UUIDs and group names +- Toolbar searches now also search in UUIDs and group names +- Added {DELAY=X} placeholder to specify a default delay of X + milliseconds between standard keypresses in this sequence +- Added option to disable verifying written database files +- Attachment names in the entry view are now clickable (to open + the attachments in the internal editor or viewer) +- Added Unicode support in entry details view +- Added option to render menus and toolbars with gradient + backgrounds (enabled by default) +- MRU lists now have numeric access keys +- Added '--entry-url-open' command line option (specify the + UUID of the entry as '--uuid:' command line parameter) +- Added 'Application initialized' trigger event +- Added 'User interface state updated' trigger event +- Added host reachability trigger condition +- Added 'Active database has unsaved changes' trigger condition +- Added 'Save active database' trigger action +- Added database file synchronization trigger action +- Added database file export trigger action +- KeePass now restores the last view when opening databases +- Added system-wide hot key to execute auto-type for the + currently selected entry (configurable in the options) +- Added option to disable auto-type entry matching based on + title (by default an entry matches if its title is contained + in the target window title) +- Added option to disable marking TAN entries as expired when + using them +- Added option to focus the quick search box when restoring + from tray (disabled by default) +- Added entry context menu commands to sort by UUID and + file attachments +- Custom string fields are now appended to the notes when + exporting to KeePass 1.x KDB files +- Enforced configuration files are now item-based (items not + defined in the enforced configuration file are now loaded + from the global/local configuration files instead of being + set to defaults) +- File transactions are used when writing configuration files +- KPScript: added 'ChangeMasterKey' command +- ShInstUtil: added check for the presence of .NET +- TrlUtil: added command under 'Import' that loads 2.x LNGX + files without checking base hashes +- TrlUtil: added control docking support +- Plugin developers: added static window addition and removal + events to the GlobalWindowManager class +- Plugin developers: added ability to write custom dialog + banner generators (CustomGenerator of BannerFactory) +- Plugin developers: the IOConnectionInfo of the database is + now accessible through the key provider query context +- Plugin developers: added static auto-type filter events + (plugins can provide own placeholders, do sequence + customizations like inserting delays, and provide alternative + key sending methods) +- Plugin developers: added UIStateUpdated main window event + +- Simple text boxes now convert rich text immediately +- Improved entry change detection (avoid unnecessary backups + when closing the entry dialog with [OK] but without any + changes; detect by content instead of change events) +- Header in entry selection dialog is now non-clickable +- Entry list header now uses native sorting icons +- Key providers are now remembered separately from key files +- The main window is now the owner of the import method dialog +- The global URL override is now also applied for main entry + URLs in the entry details view +- Improved grouping behavior when disabling entry sorting +- Improved field mapping in RoboForm import +- Root groups now support custom icons +- In the entry dialog, string values are now copied to the + clipboard instead of asterisks +- Improved import/synchronization status dialog +- Improved import/synchronization error message dialogs +- Entry history items are now identified by the last + modification time instead of last access time +- The trigger system can now be accessed directly through + 'Tools' -> 'Triggers...', not the options anymore +- Changed order of commands in the 'Tools' menu +- Improved auto-type target window validity checking +- Ctrl-V does not make the main window lose the focus anymore + if auto-type is disabled for the currently selected entry +- When restoring from tray, the main window is now brought to + the foreground +- Double-clicking an icon in the icon picker dialog now chooses + the icon and closes the dialog +- When adding a custom icon to the database, the new icon is + selected automatically +- When opening a database by running KeePass.exe with the + database file path as parameter (and single instance option + enabled), the existing KeePass instance will not prompt for + keys of previously locked databases anymore when restoring + (they are just left in locked state) +- Unlocking routine doesn't display multiple dialogs anymore +- Improved shortcut key handling in main window +- Master key change success message now has a distinguishable + window title +- Improved start position and focus of the URL dialog +- Improved layout in options dialog +- Improved UUID and UI updates when removing custom icons +- Improved window deconstruction when closing with [X] +- Improved user activity detection +- Improved state updating of sorting context menu commands +- Improved sorting by UUIDs +- Improved naming of options to clarify their meaning +- Converted ShInstUtil to a native application (in order to be + able to show a warning in case .NET is not installed) +- Plugins: improved IOConnection to allow using registered + custom WebRequest descendants (WebRequest.RegisterPrefix) +- TrlUtil: improved XML comments generation +- Various code optimizations +- Minor other improvements + +- Password profile derivation function doesn't incorrectly + always add standard character ranges anymore +- In-memory protection for the title field of new entries can + be enabled now + +2009-07-05: 2.08 +- Key transformation library: KeePass can now use Windows' + CNG/BCrypt API for key transformations (about 50% faster than + the KeePass built-in key transformation code; by increasing + the amount of rounds by 50%, you'll get the same waiting time + as in 2.07, but the protection against dictionary and + guessing attacks is raised by a factor of 1.5; only Windows + Vista and higher) +- Added support for sending keystrokes (auto-type) to windows + that are using different keyboard layouts +- Added option to remember key file paths (enabled by default) +- Added internal editor for text files (text only and RTF + formatted text; editor can edit entry attachments) +- Internal data viewer: added support for showing rich text + (text with formatting) +- Added inheritable group settings for disabling auto-type and + searching for all entries in this group (see tab 'Behavior'); + for new recycle bins, both properties are set to disabled +- Added new placeholders: {DB_PATH}, {DB_DIR}, {DB_NAME}, + {DB_BASENAME}, {DB_EXT}, {ENV_DIRSEP}, {DT_SIMPLE}, + {DT_YEAR}, {DT_MONTH}, {DT_DAY}, {DT_HOUR}, {DT_MINUTE}, + {DT_SECOND}, {DT_UTC_SIMPLE}, {DT_UTC_YEAR}, {DT_UTC_MONTH}, + {DT_UTC_DAY}, {DT_UTC_HOUR}, {DT_UTC_MINUTE}, {DT_UTC_SECOND} +- The password character picking dialog now supports pre- + defining the number of characters to pick; append :k in the + placeholder to specify a length of k (for example, + {PICKPASSWORDCHARS3:5} would be a placeholder with ID 3 and + would pick 5 characters from the password); advantage: when + having picked k characters, the dialog closes automatically, + i.e. saves you to click [OK] +- IDs in {PICKPASSWORDCHARSn} do not need to be consecutive + anymore +- The password character picking dialog now first dereferences + passwords (i.e. placeholders can be used here, too) +- Added '-minimize' command line option +- Added '-iousername', '-iopassword' and '-iocredfromrecent' + command line options +- Added '--auto-type' command line option +- Added support for importing FlexWallet 1.7 XML files +- Added option to disable protecting the clipboard using the + CF_CLIPBOARD_VIEWER_IGNORE clipboard format +- Added support for WebDAV URLs (thanks to Ryan Press) +- Added shortcut keys in master key prompt dialog +- Added entry templates functionality (first specify an entry + templates group in the database settings dialog, then use the + 'Add Entry' toolbar drop-down button) +- Added AceCustomConfig class (accessible through host + interface), that allows plugins to store their configuration + data in the KeePass configuration file +- Added ability for plugins to store custom data in KDBX + database files (PwDatabase.CustomData) +- Added interface for custom password generation algorithm + plugins +- URLs in the entry preview window are now always clickable + (especially including cmd:// URLs) +- Added option to copy URLs to the clipboard instead of opening + them (Options -> Interface, turned off by default) +- Added option to automatically resize entry list columns when + resizing the main window (turned off by default) +- Added 'Sync' command in KPScript scripting tool +- Added FIPS compliance problems self-test (see FAQ for details + about FIPS compliance) +- Added Rijndael/AES block size validation and configuration +- Added NotifyIcon workaround for Mono under MacOS +- Added confirmation box for empty master passwords +- Added radio buttons in auto-type sequence editing dialog to + choose between the default entry sequence and a custom one +- Added hint that group notes are shown in group tooltips +- Added test for KeePass 1.x plugins and an appropriate error + message +- Added interface for writing master password requirements + validation plugins +- Key provider plugin API: enhanced key query method by a + context information object +- Key provider plugin API: added 'DirectKey' property to key + provider base class that allows returning keys that are + directly written to the user key data stream +- Key provider plugin API: added support for exclusive plugins +- The '-keyfile' command line option now supports selecting key + providers (plugins) +- Auto-Type: added option to send an Alt keypress when only the + Alt modifier is active (option enabled by default) +- Added warning when trying to use only Alt or Alt-Shift as + global hot key modifier +- TrlUtil: added search functionality and toolbar +- TrlUtil: version is now shown in the window title + +- Improved database file versioning and changed KDBX file + signature in order to prevent older versions from corrupting + newer files +- ShInstUtil now first tries to uninstall a previous native + image before creating a new one +- Improved file corruption error messages (instead of index out + of array bounds exception text, ...) +- The 'Open in Browser' command now opens all selected entries + instead of just the focused one +- Data-editing commands in the 'Tools' menu in the entry dialog + are now disabled when being in history viewing mode +- Right arrow key now works correctly in group tree view +- Entry list is now updated when selecting a group by pressing + a A-Z, 0-9 or numpad key +- Improved entry list performance and sorting behavior +- Improved splitter distance remembering +- Improved self-tests (KeePass now correctly terminates when a + self-test fails) +- The attachment column in the main window now shows the names + of the attached files instead of the attachments count +- Double-clicking an attachment field in the main window now + edits (if possible) or shows the first attachment of the + entry +- Group modification times are now updated after editing groups +- Improved scrolling of the entry list in item grouping mode +- Changed history view to show last modification times, titles + and user names of history entries +- KeePass now also automatically prompts to unlock when + restoring to a maximized window +- Improved file system root directory support +- Improved generic CSV importer preview performance +- When saving a file, its path is not remembered anymore, if + the option for opening the recently used file at startup is + disabled +- Improved auto-type input blocking +- Instead of a blank text, the entry dialog now shows + "(Default)" if the default auto-type sequence is used in a + window-sequence association +- Most broadcasted Windows messages do not wait for hanging + applications anymore +- Improved main window hiding at startup when the options to + minimize after opening a database and to tray are enabled +- Default tray action is now dependent on mouse button +- New entries can now inherit custom icons from their parent + groups +- Improved maximized state handling when exiting while the main + window is minimized +- Improved state updating in key creation form +- Improved MRU list updating performance +- Improved plugin incompatibility error message +- Deprecated {DOCDIR}, use {DB_DIR} instead ({DOCDIR} is still + supported for backward compatibility though) +- Last modification times of TAN entries are now updated +- F12 cannot be registered as global hot key anymore, because + it is reserved for kernel-mode / JIT debuggers +- Improved auto-type statement conversion routine in KeePass + 1.x KDB file importer +- Improved column width calculation in file/data format dialog +- Improved synchronization status bar messages +- TrlUtil: base hash for forms is now computed using the form's + client rectangle instead of its window size +- Various code optimizations +- Minor other improvements + +- Recycle bin is now cleared correctly when clearing the + database + +2009-03-14: 2.07 Beta +- Added powerful trigger system (when events occur, check some + conditions and execute a list of actions; see options dialog + in 'Advanced'; more events / conditions / actions can be + added later based on user requests, and can also be provided + by plugins) +- Native master key transformations (rounds) are now computed + by the native KeePassLibC support library (which contains the + new, highly optimized transformation code used by KeePass + 1.15, in two threads); on dual/multi core processors this + results in almost triple the performance as before (by + tripling the amount of rounds you'll get the same waiting + time as in 2.06, but the protection against dictionary and + guessing attacks is tripled) +- Added recycle bin (enabled by default, it can be disabled in + the database settings dialog) +- Added Salsa20 stream cipher for CryptoRandomStream (this + algorithm is not only more secure than ArcFour, but also + achieves a higher performance; CryptoRandomStream defaults to + Salsa20 now; port developers: KeePass uses Salsa20 for the + inner random stream in KDBX files) +- KeePass is now storing file paths (last used file, MRU list) + in relative form in the configuration file +- Added support for importing 1Password Pro CSV files +- Added support for importing KeePass 1.x XML files +- Windows XP and higher: added support for double-buffering in + all list views (including entry lists) +- Windows Vista and higher: added support for alpha-blended + marquee selection in all list views (including entry lists) +- Added 'EditEntry', 'DeleteEntry', 'AddEntries' and + 'DeleteAllEntries' commands in KPScript scripting tool +- Added support for importing special ICO files +- Added option to exit instead of locking the workspace after + the specified time of inactivity +- Added option to minimize the main window after locking the + KeePass workspace +- Added option to minimize the main window after opening a + database +- Added support for exporting to KDBX files +- Added command to remove deleted objects information +- TrlUtil now checks for duplicate accelerator keys in dialogs +- Added controls in the entry editing dialog to specify a + custom text foreground color for entries +- KeePass now retrieves the default auto-type sequence from + parent groups when adding new entries +- The password character picking dialog can now be invoked + multiple times when auto-typing (use {PICKPASSWORDCHARS}, + {PICKPASSWORDCHARS2}, {PICKPASSWORDCHARS3}, etc.) +- Added '-set-urloverride', '-clear-urloverride' and + '-get-urloverride' command line options +- Added '-set-translation' command line option +- Added option to print custom string fields in details mode +- Various entry listings now support custom foreground and + background colors for entry items +- Added 'click through' behavior for menus and toolbars +- File association methods are now UAC aware + +- User interface is now blocked while saving to a file (in + order to prevent accidental user actions that might interfere + with the saving process) +- Improved native modifier keys handling on 64-bit systems +- Improved application startup performance +- Added image list processing workaround for Windows 7 +- OK button is now reenabled after manually activating the key + file checkbox and selecting a file in the master key dialog +- The master key dialog now appears in the task bar +- When KeePass is minimized to tray and locked, pressing the + global auto-type hot key doesn't restore the main window + anymore +- The installer now by default installs KeePass 1.x and 2.x + into separate directories in the program files folder +- The optional autorun registry keys of KeePass 1.x and 2.x do + not collide anymore +- File type association identifiers of KeePass 1.x and 2.x do + not collide anymore +- File MRU list now uses case-insensitive comparisons +- Improved preview updates in Print and Data Viewer dialogs +- Message service provider is thread safe now +- Threading safety improvements in KPScript scripting plugin +- Improved control state updates in password generator dialog +- Improved master password validation in 'New Database' dialog +- Times are now stored as UTC in KDBX files (ISO 8601 format) +- Last access time fields are now updated when auto-typing, + copying fields to the clipboard and drag&drop operations +- KPScript scripting tool now supports in-memory protection +- Database is not marked as modified anymore when closing the + import dialog with Cancel +- Added asterisks in application policy editing dialog to make + clearer that changing the policy requires a KeePass restart +- Double-clicking a format in the import/export dialog now + automatically shows the file browsing dialog +- Improved permanent entry deletion confirmation prompt +- Improved font objects handling +- Expired groups are now rendered using a striked out font +- Improved auto-type statement conversion routine in KeePass + 1.x KDB file importer +- Clipboard clearing countdown is not started anymore when + copying data fails (e.g. policy disabled) +- Improved synchronization with URLs +- The database maintenance dialog now only marks the database + as modified when it actually has removed something +- KeePass now broadcasts a shell notification after changing + the KDBX file association +- Improved warning message when trying to directly open KeePass + 1.x KDB files +- Improved Linux/MacOS compatibility +- Improved MSI package (removed unnecessary dependency) +- TrlUtil: improved NumericUpDown and RichTextBox handling +- Installer now checks for minimum operating system version +- Installer: file association is now a task, not a component +- Installer: various other improvements +- Various code optimizations +- Minor other improvements + +- When cloning a group tree using drag&drop, KeePass now + assigns correct parent group references to cloned groups and + entries +- Fixed crash when clicking 'Cancel' in the settings dialog + when creating a new database + +2008-11-01: 2.06 Beta +- Translation system is now complete (translations to various + languages will be published on the KeePass translations page + when translators finish them) +- When saving the database, KeePass now first checks whether + the file on disk/server has been modified since it was loaded + and if so, asks the user whether to synchronize with the + changed file instead of overwriting it (i.e. multiple users + can now use a shared database on a network drive) +- Database files are now verified (read and hashed) after + writing them to disk (in order to prevent data loss caused by + damaged/broken devices and/or file systems) +- Completely new auto-type/URL placeholder replacement and + field reference engine +- On Windows Vista, some of the message boxes are now displayed + as modern task dialogs +- KeePass is now also available as MSI package +- Accessibility: added advanced option to optimize the user + interface for screen readers (only enable this option if + you're really using a screen reader) +- Added standard client icons: Tux, feather, apple, generic + Wiki icon, '$', certificate and BlackBerry +- Secure edit controls in the master key and entry dialogs now + accept text drops +- Added ability to store notes for each group (see 'Notes' tab + in the group editing window), these notes are shown in the + tooltip of the group in the group tree of the main window +- Group names in the entry details view are now clickable; + click it to jump to the group of the entry (especially useful + for jumping from search results to the real group of an + entry) +- Added 'GROUPPATH', 'DELAY' and 'PICKPASSWORDCHARS' special + placeholders to auto-type sequence editing dialog +- Wildcards (*) may now also appear in the middle of auto-type + target window filters +- For auto-type target window filters, regular expressions are + now supported (enclose in //) +- KeePass now shows an explicit file corruption warning message + when saving to a file fails +- Added option to prepend a special auto-type initialization + sequence for Internet Explorer and Maxthon windows to fix a + focus issue (option enabled by default) +- Added ability to specify a minimum length and minimum + estimated quality that master passwords must have (see help + file -> Features -> Composite Master Key; for admins) +- Added field reference creation dialog (accessible through + the 'Tools' menu in the entry editing dialog) +- Field references are dereferenced when copying data to the + clipboard +- Entry field references are now dereferenced in drag&drop + operations +- KeePass now follows field references in indirect auto-type + sequence paths +- Added internal field reference cache (highly improves + performance of multiple-cyclic/recursive field references) +- Added managed system power mode change handler +- Added "Lock Workspace" tray context menu command +- Moved all export commands into a new export dialog +- Added context menu command to export the selected group only +- Added context menu command to export selected entries only +- Added support for importing Password Memory 2008 XML files +- Added support for importing Password Keeper 7.0 CSV files +- Added support for importing Passphrase Keeper 2.70 HTML files +- Added support for importing data from PassKeeper 1.2 +- Added support for importing Mozilla bookmarks JSON files + (Firefox 3 bookmark files) +- Added support for exporting to KeePass 1.x CSV files +- Added XSL transformation file to export passwords only + (useful for generating and exporting password lists) +- Added support for writing databases to hidden files +- When passing '/?', '--help' or similar on the command line, + KeePass will now open the command line help +- When single instance mode is enabled and a second instance is + started with command line parameters, these parameters are + now sent to the already open KeePass instance +- KeePass now ships with a compiled XML serializer library, + which highly improves startup performance +- Added support for Uniform Naming Convention (UNC) paths + (Windows) in the URL field (without cmd:// prefix) +- Added option to exclude expired entries in the 'Find' dialog +- Added option to exclude expired entries in quick searches + (toolbar; disabled by default) +- The box to enter the name of a custom string field is now a + combobox that suggests previously-used names in its drop-down + list +- Added Shift, Control and Alt key modifiers to placeholder + overview in the auto-type sequence editing dialog +- Added support for 64 byte key files which don't contain hex + keys +- Added Ctrl-Shift-F accelerator for the 'Find in this Group' + context menu command (group tree must have the focus) +- Added export ability to KPScript plugin +- Ctrl-Tab now also works in the password list, groups tree and + entry details view +- Added multi-user documentation +- Plugin developers: DocumentManagerEx now has an + ActiveDocumentSelected event +- Plugin developers: instead of manually setting the parent + group property and adding an object to a group, use the new + AddEntry / AddGroup methods of PwGroup (can take ownership) +- Plugins can now add new export file formats (in addition to + import formats) +- Plugins: added static message service event + +- When using the installation package and Windows Vista, + settings are now stored in the user's profile directory + (instead of Virtual Store; like on Windows XP and earlier) +- Accessibility: multi-line edit controls do not accept tabs + anymore (i.e. tab jumps to the next dialog control), and + inserting a new line doesn't require pressing Ctrl anymore +- When moving entries, KeePass doesn't switch to the target + group anymore +- When deleting entries from the search results, the entry list + is not cleared anymore +- Improved entry duplication method (now also works correctly + in search results list and grouped list views) +- A more useful error message is shown when checking for + updates fails +- Improved formats sorting in the import dialog +- The 'Limit to single instance' option is now turned on by + default (multiple databases are opened in tabs) +- Removed 'sort up', 'sort down' and empty client icons +- Improved program termination code (common clean-up) +- Improved error message that is shown when reading/writing the + protected user key fails +- The key file selection dialog now by default shows all files +- Plugins: improved event handlers (now using generic delegate) +- Implemented several workarounds for Mono (1.9.1+) +- Added conformance level specification for XSL transformations + (in order to improve non-XML text exports using XSLT) +- Improved key state toggling for auto-type on 64-bit systems +- Removed several unnecessary .NET assembly dependencies +- Threading safety improvements +- Highly improved entry context menu performance when many + entries are selected +- Entry selection performance improvements in main window +- Improved entries list view performance (state caching) +- List view group assignment improvements (to avoid splitting) +- Removed tab stops from quality progress bars +- After moving entries to a different group, the original group + is selected instead of the target group +- Layout and text improvements in the master key creation form +- Text in the URL field is now shown in blue (if it's black in + the standard theme) +- Improved auto-type tab in entry dialog (default sequence) +- Improved AES/Rijndael cipher engine initialization +- Improved build scripts +- Various code optimizations +- Minor other improvements +- Installer: changed AppId to allow parallel installation of + KeePass 1.x and 2.x +- Minor other installer improvements + +- The 'View' -> 'Show Columns' -> 'Last Access Time' menu + command now works correctly +- The 'Clipboard' -> 'Paste Entries' menu command now assigns + correct group references to pasted entries + +2008-04-08: 2.05 Alpha +- Added placeholders for referencing fields of other entries + (dereferenced when starting URLs and performing auto-type, + see the auto-type placeholders documentation) +- Added natural sorting (when sorting the entry list, KeePass + now performs a human-like comparison instead of a simple + lexicographical one; this sorts entries with numbers more + logically) +- Added support for importing RoboForm passcards (HTML) +- Added {DELAY X} auto-type command (to delay X milliseconds) +- Added {GROUPPATH} placeholder (will be replaced by the group + hierarchy path to the entry; groups are separated by dots) +- When saving databases to removable media, KeePass now tries + to lock and unlock the volume, which effectively flushes all + system caches related to this drive (this prevents data loss + caused by removing USB sticks without correctly unmounting in + Windows first; but it only works when no other program is + using the drive) +- Added pattern placeholder 's' to generate special characters + of the printable 7-bit ASCII character set +- A " - Copy" suffix is now appended to duplicated entries +- After duplicating entries, the new entries are selected +- The list view item sorter now supports dates/times, i.e. + sorting based on entry times is logically now, not + lexicographically +- Added GUI option to focus the entry list after a successful + quick search (toolbar; disabled by default) +- Several entry context menu commands are now only enabled if + applicable (if the user name field of an entry is empty, the + 'Copy User Name' command is disabled, etc.) +- Added a 'Tools' button menu in the entry editing dialog +- Tools button menu: Added command to select an application for + the URL field (will be prefixed with cmd://) +- Tools button menu: Added command to select a document for the + URL field (will be prefixed with cmd://) +- Added password generator option to exclude/omit + user-specified characters in generated passwords +- Added clearification paragraph in master key creation dialog + about using the Windows user account as source (backup, ...) +- Added menu command to synchronize with a URL (database stored + on a server) +- KeePass is now checking the network connection immediately + when trying to close the URL dialog +- Added file closed event arguments (I/O connection info) +- Added "file created" event for plugins + +- The document manager is now accessible by plugins +- Improved field to standard field mapping function +- KeePass now locks when the system is suspending (if the + option for locking on locking Windows or switching user is + enabled) +- All documents are now locked when the session is ended or the + user is switched (if the option for this is enabled) +- Moving a group into one of its child groups does not make the + group vanish anymore +- Auto-type validator now supports "{{}" and "{}}" sequences + (i.e. auto-type can send '{' and '}' characters) +- Undo buffers of secure edit controls are now cleared + correctly +- Disabling sorting does not clear search results anymore +- Entry editing dialog: Return and Esc work correctly now +- Column sort order indicators are now rendered using text + instead of images (improves Windows Vista compatibility) +- Splitter positions are now saved correctly when exiting after + minimizing the main window to tray +- Added handler code for some more unsupported image file + format features (when importing special ICO files) +- Translation system is now about 75% complete +- KeePass is now developed using Visual Studio 2008 +- Minor UI improvements +- Minor Windows installer improvements + +- The CSV importer does not crash anymore when clicking Cancel + while trying to import entries into an empty folder +- I/O connection credentials saving works correctly now +- Fixed duplicate accelerator keys in the entry context menu +- Help button in master key creation dialog now works correctly + +2008-01-06: 2.04 Alpha +- Added key provider API (it now is very easy to write a plugin + that provides additional key methods, like locking to USB + device ID, certificates, smart cards, ... see the developers + section in the online KeePass help center) +- Added option to show entries of sub-groups in the entry list + of a group (see 'View' -> 'Show Entries of Sub-Groups') +- Added XML valid characters filter (to prevent XML document + corruption by ASCII/DOS control characters) +- Added context menu command to print selected entries only +- Added option to disallow repeating characters in generated + passwords (both character set-based and pattern-based) +- Moved security-reducing / dangerous password generator + options to a separate 'Advanced' tab page (if you enable a + security-reducing option, an exclamation mark (!) is + appended to the 'Advanced' tab text) +- Added 'Get more languages' button to the translations dialog +- Added textual cue for the quick-search edit control +- The TAN wizard now shows the name of the group into which the + TANs will be imported +- Improved random number generator (it now additionally + collects system entropy manually and hashes it with random + numbers provided by the system's default CSP and a counter) +- For determining the default text in the 'Override default + sequence' edit box in the 'Edit Entry' window, KeePass now + recursively traverses up the group tree +- Last entry list sorting mode (column, ascending / descending) + is now remembered and restored +- First item in the auto-type entry selection window is now + focused (allowing to immediately navigate using the keyboard) +- Text in secure edit controls is now selected when the control + gets the focus the first time +- For TAN entries, only a command 'Copy TAN' is now shown in + the context menu, others (that don't apply) are invisible +- Regular expressions are validated before they are matched +- KeePass now checks the auto-type string for invalid entry + field references before sending it +- The clipboard auto-clear information message is now shown in + the status bar instead of the tray balloon tooltip +- Matching entries are shown only once in the search results + list, even when multiple fields match the search text +- First item of search results is selected automatically, if no + other item is already selected (selection restoration) +- Entries with empty titles do not match all windows any more +- Improved high DPI support in entry window +- When having enabled the option to automatically lock the + workspace after some time and saving a file fails, KeePass + will prompt again after the specified amount of time instead + of 1 second +- KeePass now suggests the current file name as name for new + files (save as, save as copy) +- The password generator profile combo box can now show more + profiles in the list without scrolling +- Improved native methods exception handling (Mono) +- Updated CHM documentation file +- TAN wizard now assigns correct indices to TANs after new line + characters +- Copying KeePass entries to the clipboard now works together + with the CF_CLIPBOARD_VIEWER_IGNORE clipboard format +- KeePass now uses the correct client icons image list + immediately after adding a custom icon to the database +- Fixed 'generic error in GDI+' when trying to import a 16x16 + icon (thanks to 'stroebele' for the patch) +- File close button in the toolbar (multiple files) works now +- Fixed minor bug in provider registration of cipher pool + +2007-10-11: 2.03 Alpha +- Added multi-document support (tabbed interface when multiple + files are opened) +- KeePass 2.x now runs on Windows 98 / ME, too! (with .NET 2.0) +- Added option to permute passwords generated using a pattern + (this allows generating passwords that follow complex rules) +- Added option to start minimized and locked +- Added support for importing Passwort.Tresor XML files +- Added support for importing SplashID CSV files +- Added '--exit-all' command line parameter; call KeePass.exe + with this parameter to close all other open KeePass instances + (if you do not wish to see the 'Save?' confirmation dialog, + enable the 'Automatically save database on exit' option) +- Added support for CF_CLIPBOARD_VIEWER_IGNORE clipboard format + (clipboard viewers/extenders compliant with this format + ignore data copied by KeePass) +- Added support for synchronizing with multiple other databases + (select multiple files in the file selection dialog) +- Added ability to specify custom character sets in password + generation patterns +- Added pattern placeholder 'S' to generate printable 7-bit + ASCII characters +- Added pattern placeholder 'b' to generate brackets +- Added support for starting very long command lines +- Entry UUID is now shown on the 'Properties' tab page +- Added Spanish language for installer +- KeePass now creates a mutex in the global name space +- Added menu command to save a copy of the current database +- The database name is now shown in the title of the 'Enter + Password' window +- Added "Exit" command to tray icon context menu +- Pressing the 'Enter' key in the password list now opens the + currently selected entry for editing +- Added '-GroupName:' parameter for 'AddEntry' command in the + KPScript KeePass scripting tool (see plugins web page) +- Added URL example in 'Open URL' dialog +- Added support for plugin namespaces with dots (nested) +- Added ability to specify the characters a TAN can consist of +- '-' is now treated as TAN character by default, not as + separator any more +- Added ability to search using a regular expression +- Notes in the entry list are now CR/LF-filtered +- Added {PICKPASSWORDCHARS} placeholder, KeePass will show a + dialog which allows you to pick certain characters +- The password generator dialog is now shown in the Windows + taskbar if the main window is minimized to tray +- Caps lock is now disabled before auto-typing +- Improved installer (added start menu link to the CHM help + file, mutex checking at uninstallation, version information + block, ...) +- Plugin architecture: added cancellable default entry action + event handler +- Added support for subitem infotips in various list controls +- Group name is now shown in the 'Find' dialog (if not root) +- Pressing the 'Insert' key in the password list now opens the + 'Add Entry' dialog +- Last search settings are now remembered (except search text) +- The column order in the main window is now remembered +- Pressing F2 in the groups tree now initiates editing the name + of the currently selected group +- Pressing F2 in the password list now opens the editing dialog +- The 'About' dialog is now automatically closed when clicking + an hyperlink +- Entries generated by 'Tools' - 'Password Generator' are now + highlighted in the main window (visible and selected) +- Extended auto-close functionality to some more dialogs +- Protected user key is now stored in the application data + directory instead of the registry (when upgrading from 2.02, + first change the master key so it doesn't use the user + account credentials option!) +- Improved configuration file format (now using XML + serialization, allowing serialization of complex structures) +- Improved configuration saving/loading (avoid file system + virtualization on Windows Vista when using the installer, + improved out of the box support for installation by admin / + usage by user, better limited user account handling, ...) +- Improved password generator profile management (UI) +- Improved password generator character set definition +- Custom icons can be deleted from the database now +- Changed password pattern placeholders to support ANSI +- Removed plugin projects from core distribution (plugin source + codes will be available separately, like in 1.x) +- Window position and size is saved now when exiting KeePass + while minimized +- Splitter positions are restored correctly now when the main + window is maximized +- Password list refreshes now restore the previous view + (including selected and focused items, ...) +- Improved session ending handler +- Improved help menu +- Added more JPEG extensions in the icon dialog (JFIF/JFI/JIF) +- Navigation through the group tree using the keyboard is now + possible (entries list is updated) +- Options dialog now remembers the last opened tab page +- Synchronization: deletion information is merged correctly now +- Improved importing status dialog +- Improved search results presentation +- Title field is now the first control in the focus cycle of + the entry dialog +- The auto-type entry selection dialog now also shows custom / + imported icons +- The quick-find box now has the focus after opening a database +- The main window title now shows 'File - KeePass Password + Safe' instead of 'KeePass Password Safe [File]'; improved + tooltip text for tray icon +- The 'Save Attachments' context menu command is disabled now + if the currently selected entry doesn't have any attachments +- A more useful error message is shown when trying to import an + unsupported image format +- Replaced 'Search All Fields' by an additional 'Other' option +- Expired/used TAN entries are not shown in the expired entries + dialog any more +- UI now mostly follows the Windows Vista UI text guidelines +- Improved UI behavior in options dialog +- Improved text in password generator preview window +- After activating a language, the restart dialog is only shown + if the selected language is different from the current one +- Online help browser is now started in a separate thread +- Value field in 'Edit String' window now accepts 'Return' key +- The name prompt in the 'Edit String' window now initially + shows a prompt instead of an invalid field name warning +- Expired entries are now also shown when unlocking the + database +- Expired entries are not shown any more in the auto-type entry + selection dialog +- Various dialogs: Return and Esc work correctly now +- Improved key handling in password list +- Updated SharpZipLib component in KeePassLibSD +- Updated CHM documentation file +- Deleting custom string fields of entries works correctly now +- Fixed a small bug in the password list view restoration + routines (the item above the previous top one was visible) +- KeePass doesn't prevent Windows from shutting down any more + when the 'Close button minimizes window' option is enabled +- The "Application Policy Help" link in the options dialog + works now +- KeePass doesn't crash any more when viewing an history entry + that has a custom/imported icon +- Icon in group editing dialog is now initialized correctly +- Last TAN is not ignored any more by the TAN wizard +- Other minor features and bugfixes + +2007-04-11: 2.02 Alpha +- Added "Two-Channel Auto-Type Obfuscation" feature, which + makes auto-type resistant against keyloggers; this is an opt- + in feature, see the documentation +- Added KDBX data integrity verification (partial content + hashes); note: this is a breaking change to the KDBX format +- Added internal data viewer to display attachments (text + files, images, and web documents); see the new 'View' button + in the 'Edit Entry' window and the new dynamic entry context + menu popup 'Show In Internal Viewer' +- External images can now be imported and used as entry icons +- Added KeePassLibC and KeePassNtv 64-bit compatibility +- Added Spamex.com import support +- Added KeePass CSV 1.x import support +- When adding a group, users are immediately prompted for a + name (like Windows Explorer does when creating new folders) +- Added prompts for various text boxes +- The installer's version is now set to the KeePass version +- The key prompt dialog now shows an 'Exit' button when + unlocking a database +- Added F1 menu shortcut for opening the help file/page +- URL override is now displayed in the entry view +- Added ability to check if the composite key is valid + immdiately after starting to decrypt the file +- Added ability to move groups on the same level (up / down), + use either the context menu or the Alt+... shortcuts +- The database isn't marked as modified any more when closing + the 'Edit Entry' dialog with OK but without modifying + anything +- Added version information for native transformations library +- Local file name isn't displayed any more in URL dialog +- Improved path clipping (tray text, ...) +- Improved data field retrieval in SPM 2007 import module +- Improved attachments display/handling in 'Edit Entry' dialog +- Improved entry context menu (added some keyboard shortcut + indicators, updated icons, ...) +- Improved performance of secure password edit controls +- Clearified auto-type documentation +- Installer uses best compression now +- Improved auto-type state handling +- In-memory protected custom strings are hidden by asterisks + in the entry details window now +- Improved entropy collection dialog +- Updated import/export documentation +- Added delete shortcut key for deleting groups +- Instead of showing the number of attachments in the entry + view, the actual attachment names are shown now +- Improved asterisks hiding behavior in entry view +- New entries now by default inherit the icon of their parent + groups, except if it's a folder-like icon +- Updated AES code in native library +- Improved native library detection and configuration +- Improved entry/group dragging behavior (window updates, ...) +- A more useful error message is shown when you try to export + to a KDB3 file without having KeePassLibC installed +- Configuration class supports DLL assemblies +- KeePass doesn't create an empty directory in the application + data path any more, if the global config file is writable +- Clipboard isn't cleared any more at exit if it doesn't + contain data copied by KeePass +- Empty auto-type sequences in custom window-sequence pairs now + map to the inherited ones or default overrides, if specified +- Cleaned up notify tray resources +- Improved help menu +- A *lot* code quality improvements +- ShInstUtil doesn't crash any more when called without any + parameter +- Auto-type now sends modifier keys (+ for Shift, % for Alt, + ...) and character groups correctly +- Fixed alpha transparency multi-shadow bug in groups list +- Overwrite confirmation now isn't displayed twice any more + when saving an attachment from the 'Edit Entry' window +- User interface state is updated after 'Select All' command +- Auto-Type warnings are now shown correctly +- Fixed auto-type definition in sample entry (when creating a + new database) +- The global auto-type hot key now also works when KeePass is + locked and minimized to tray +- Fixed bug in initialization of Random class (KeePass could + have crashed 1 time in 2^32 starts) + +2007-03-23: 2.01 Alpha +- Improved auto-type engine (releases and restores modifier + keys, improved focusing, etc.) +- Implemented update-checking functionality +- Added KPScript plugin (see source code package) for scripting + (details about it can be found in the online help center) +- Added Whisper 32 1.16 import support +- Added Steganos Password Manager 2007 import support +- Search results now show the full path of the container group +- Entry windows (main password list, auto-type entry selection + dialog, etc.) now show item tooltips when hovering over them +- Added window box drop-down hint in the auto-type item dialog +- Database maintenance history days setting is now remembered +- Improved main window update after importing a file +- Improved command line handling +- If opening/starting external files fails, helpful messages + are displayed now +- Completely new exception handling mechanism in the Kdb4File + class (allows to show more detailed messages) +- New message service class (KeePassLib.Utility.MessageService) +- Added option to disable remembering the password hiding + setting in the 'Edit Entry' window +- Added menu shortcuts for opening the current entry URL + (Ctrl+U) and performing current entry auto-type (Ctrl+V) +- Changed file extension to KDBX +- Password generation profiles are now saved when the dialog is + closed with 'Close'/'Cancel' +- Entry URL overrides now precede the global URL override +- Standard password generation profiles are now included in the + executable file +- Restructured plugin architecture, it's much clearer now + (abstract base class, assembly-internal manager class, ...) +- Only non-empty strings are now displayed in the entry view +- Current working directory is set to the KeePass application + directory before executing external files/URLs +- Changed fields shown in the auto-type entry selection dialog: + title, user name and URL are displayed instead of title, user + name and password +- Clearified clipboard commands in context menus +- Help buttons now open the correct topics in the CHM +- Fixed name in the installer script +- Workspace is not locked any more if a window is open (this + prevents data loss) +- The 'Find' toolbar button works now +- The OK button in the Import dialog is now enabled when you + manually enter a path into the file text box +- Fixed entry list focus bug +- Fixed menu focus bug +- The 'Copy Custom String' menu item doesn't disappear any more +- Fixed enabled/disabled state of auto-type menu command + +2007-03-17: 2.00 Alpha +- Strings containing quotes are now passed correctly over the + command-line +- Created small help file with links to online resources +- Rewrote cipher engines pool +- Restructured KeePassLib +- Added dialog for browser selection +- Added option to disable searching for key files on removable + media +- Improved KDB3 support (especially added support for empty + times as created by the KeePass Toolbar for example) +- Added confirmations for deleting entries and groups +- Fixed a lot of bugs and inconsistencies; added features +- Fixed a bug in the 'Start KeePass at Windows startup' + registration method +- Added custom split container control to avoid focus problems +- Clipboard is only cleared if it contains KeePass data +- New system for configuration defaults +- A LOT of other features, bugfixes, ... + +... (a lot of versions here) ... + +2006-10-07: 2.00 Pre-Alpha 29 +- Various small additions and bugfixes + +2006-10-06: 2.00 Pre-Alpha 28 +- Implemented entry data drag-n-drop for main entry list +- Implemented URL overriding +- Added {} repeat operator in password generator +- Added database maintenance dialog (deleting history entries) +- Custom entry strings are now shown in the entry preview +- Added alternative window layout: side by side +- A lot of other features and bugfixes + +... (some versions here) ... + +2006-09-17: 2.00 Pre-Alpha 25 +- Fixed exception that occured when WTS notifications are + unavailable + +2006-09-16: 2.00 Pre-Alpha 24 +- Implemented quality progress bars (gradient bars) +- Added special key codes into placeholder insertion field in + the 'Edit AutoType' dialog +- Currently opened windows are listed in the 'Edit AutoType' + dialog +- Entries can be copied/pasted to/from Windows clipboard +- Added {APPDIR}, {DOCDIR} and {GROUP} codes +- Foreground and background colors can be assigned to entries +- Expired entries are displayed using a striked-out font +- Password generator supports profiles now +- Password generator supports patterns now +- VariousImport: Added support for Password Exporter XML files +- A _lot_ of other features and bugfixes + +2006-09-07: 2.00 Pre-Alpha 23 +- Internal release + +2006-09-07: 2.00 Pre-Alpha 22 +- Improved password quality estimation +- Implemented secure edit controls (in key creation dialog, key + prompt dialog and entry editing dialog) + +2006-09-05: 2.00 Pre-Alpha 21 +- Removed BZip2 compression +- Added font selection for main window lists +- Added file association creation/removal buttons in the + options dialog +- Installer supports associating KDB files with KeePass +- Added option to run KeePass at Windows startup (for current + user; see Options dialog, Integration page) +- Added default tray action (sending/restoring to/from tray) +- Added single-click option for default tray action +- Added option to automatically open last used database on + KeePass startup (see Options dialog, Advanced page) +- Added option to automatically save the current database on + exit and workspace locking (Options dialog, Advanced page) +- Implemented system-wide KeePass application messages +- Added 'Limit to single instance' option +- Added option to check for update at KeePass startup +- Added options to show expired entries and entries that will + expire soon after opening a database +- Added option to generate random passwords for new entries +- Links in the entry view are clickable now +- Links in the notes field of the entry dialog are clickable + now +- Fixed context menu auto-type command (inheriting defaults) +- Improved entry list state updating performance +- Classic databases are listed in the main MRU list, prefixed + with '[Classic]' +- Other features and bugfixes + +2006-09-03: 2.00 Pre-Alpha 20 +- First testing release + +... (a lot of versions here) ... + +2006-03-21: 2.00 Pre-Alpha 0 +- Project started diff --git a/src/Docs/License.txt b/src/Docs/License.txt new file mode 100644 index 0000000..4a09f45 --- /dev/null +++ b/src/Docs/License.txt @@ -0,0 +1,347 @@ +KeePass: Copyright (C) 2003-2023 Dominik Reichl . + +The software is distributed under the terms of the GNU General Public License +version 2 or later. + +For acknowledgements and licenses of components/resources/etc., see the file +'KeePass.chm'. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/src/Ext/Icons_04_CB/Finals/Untitled.ico b/src/Ext/Icons_04_CB/Finals/Untitled.ico new file mode 100644 index 0000000..d22bede Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/Untitled.ico differ diff --git a/src/Ext/Icons_04_CB/Finals/key-blu.png b/src/Ext/Icons_04_CB/Finals/key-blu.png new file mode 100644 index 0000000..d38e01b Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/key-blu.png differ diff --git a/src/Ext/Icons_04_CB/Finals/key-bw.png b/src/Ext/Icons_04_CB/Finals/key-bw.png new file mode 100644 index 0000000..85bc1fe Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/key-bw.png differ diff --git a/src/Ext/Icons_04_CB/Finals/key-grn.ico b/src/Ext/Icons_04_CB/Finals/key-grn.ico new file mode 100644 index 0000000..5c30b16 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/key-grn.ico differ diff --git a/src/Ext/Icons_04_CB/Finals/key-grn.png b/src/Ext/Icons_04_CB/Finals/key-grn.png new file mode 100644 index 0000000..b904b5b Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/key-grn.png differ diff --git a/src/Ext/Icons_04_CB/Finals/plock-blu.ico b/src/Ext/Icons_04_CB/Finals/plock-blu.ico new file mode 100644 index 0000000..d213a44 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plock-blu.ico differ diff --git a/src/Ext/Icons_04_CB/Finals/plock-blu.png b/src/Ext/Icons_04_CB/Finals/plock-blu.png new file mode 100644 index 0000000..64c2d10 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plock-blu.png differ diff --git a/src/Ext/Icons_04_CB/Finals/plock-bw.png b/src/Ext/Icons_04_CB/Finals/plock-bw.png new file mode 100644 index 0000000..7abaae5 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plock-bw.png differ diff --git a/src/Ext/Icons_04_CB/Finals/plock-dis.ico b/src/Ext/Icons_04_CB/Finals/plock-dis.ico new file mode 100644 index 0000000..2e12566 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plock-dis.ico differ diff --git a/src/Ext/Icons_04_CB/Finals/plock-grn.ico b/src/Ext/Icons_04_CB/Finals/plock-grn.ico new file mode 100644 index 0000000..0e06752 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plock-grn.ico differ diff --git a/src/Ext/Icons_04_CB/Finals/plock-grn.png b/src/Ext/Icons_04_CB/Finals/plock-grn.png new file mode 100644 index 0000000..abcbb09 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plock-grn.png differ diff --git a/src/Ext/Icons_04_CB/Finals/plock.ico b/src/Ext/Icons_04_CB/Finals/plock.ico new file mode 100644 index 0000000..8e711cf Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plock.ico differ diff --git a/src/Ext/Icons_04_CB/Finals/plock.png b/src/Ext/Icons_04_CB/Finals/plock.png new file mode 100644 index 0000000..06390bc Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plock.png differ diff --git a/src/Ext/Icons_04_CB/Finals/plockb.png b/src/Ext/Icons_04_CB/Finals/plockb.png new file mode 100644 index 0000000..35e7a21 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plockb.png differ diff --git a/src/Ext/Icons_04_CB/Finals/plockbw-r.png b/src/Ext/Icons_04_CB/Finals/plockbw-r.png new file mode 100644 index 0000000..0f8060a Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plockbw-r.png differ diff --git a/src/Ext/Icons_04_CB/Finals/plockbw.png b/src/Ext/Icons_04_CB/Finals/plockbw.png new file mode 100644 index 0000000..520e69a Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals/plockbw.png differ diff --git a/src/Ext/Icons_04_CB/Finals2/plock-blu.ico b/src/Ext/Icons_04_CB/Finals2/plock-blu.ico new file mode 100644 index 0000000..d213a44 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals2/plock-blu.ico differ diff --git a/src/Ext/Icons_04_CB/Finals2/plock-dis.ico b/src/Ext/Icons_04_CB/Finals2/plock-dis.ico new file mode 100644 index 0000000..2e12566 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals2/plock-dis.ico differ diff --git a/src/Ext/Icons_04_CB/Finals2/plock.ico b/src/Ext/Icons_04_CB/Finals2/plock.ico new file mode 100644 index 0000000..8e711cf Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals2/plock.ico differ diff --git a/src/Ext/Icons_04_CB/Finals2/plockb.ico b/src/Ext/Icons_04_CB/Finals2/plockb.ico new file mode 100644 index 0000000..79ff999 Binary files /dev/null and b/src/Ext/Icons_04_CB/Finals2/plockb.ico differ diff --git a/src/Ext/Icons_04_CB/ReadMe.txt b/src/Ext/Icons_04_CB/ReadMe.txt new file mode 100644 index 0000000..36947f9 --- /dev/null +++ b/src/Ext/Icons_04_CB/ReadMe.txt @@ -0,0 +1,2 @@ +Christopher Bolin has made these nice icons for KeePass. +Many thanks to him! diff --git a/src/Ext/Icons_04_CB/key-org.ico b/src/Ext/Icons_04_CB/key-org.ico new file mode 100644 index 0000000..9041481 Binary files /dev/null and b/src/Ext/Icons_04_CB/key-org.ico differ diff --git a/src/Ext/Icons_04_CB/keyhole-grn.ico b/src/Ext/Icons_04_CB/keyhole-grn.ico new file mode 100644 index 0000000..9945a24 Binary files /dev/null and b/src/Ext/Icons_04_CB/keyhole-grn.ico differ diff --git a/src/Ext/Icons_04_CB/lockblue.ico b/src/Ext/Icons_04_CB/lockblue.ico new file mode 100644 index 0000000..eee458b Binary files /dev/null and b/src/Ext/Icons_04_CB/lockblue.ico differ diff --git a/src/Ext/Icons_04_CB/lockgreen.ico b/src/Ext/Icons_04_CB/lockgreen.ico new file mode 100644 index 0000000..5bad9dd Binary files /dev/null and b/src/Ext/Icons_04_CB/lockgreen.ico differ diff --git a/src/Ext/Icons_04_CB/lockred.ico b/src/Ext/Icons_04_CB/lockred.ico new file mode 100644 index 0000000..fc4033a Binary files /dev/null and b/src/Ext/Icons_04_CB/lockred.ico differ diff --git a/src/Ext/Icons_04_CB/lockyellow.ico b/src/Ext/Icons_04_CB/lockyellow.ico new file mode 100644 index 0000000..edaa5b6 Binary files /dev/null and b/src/Ext/Icons_04_CB/lockyellow.ico differ diff --git a/src/Ext/Icons_04_CB/plockb.ico b/src/Ext/Icons_04_CB/plockb.ico new file mode 100644 index 0000000..13c34fa Binary files /dev/null and b/src/Ext/Icons_04_CB/plockb.ico differ diff --git a/src/Ext/Icons_04_CB/plockb2.ico b/src/Ext/Icons_04_CB/plockb2.ico new file mode 100644 index 0000000..e181b01 Binary files /dev/null and b/src/Ext/Icons_04_CB/plockb2.ico differ diff --git a/src/Ext/Icons_04_CB/plockbw.ico b/src/Ext/Icons_04_CB/plockbw.ico new file mode 100644 index 0000000..46702c4 Binary files /dev/null and b/src/Ext/Icons_04_CB/plockbw.ico differ diff --git a/src/Ext/Icons_04_CB/plockg.ico b/src/Ext/Icons_04_CB/plockg.ico new file mode 100644 index 0000000..d4335b4 Binary files /dev/null and b/src/Ext/Icons_04_CB/plockg.ico differ diff --git a/src/Ext/Icons_04_CB/plocko.ico b/src/Ext/Icons_04_CB/plocko.ico new file mode 100644 index 0000000..fbbaca0 Binary files /dev/null and b/src/Ext/Icons_04_CB/plocko.ico differ diff --git a/src/Ext/Icons_04_CB/plockr.ico b/src/Ext/Icons_04_CB/plockr.ico new file mode 100644 index 0000000..89fda78 Binary files /dev/null and b/src/Ext/Icons_04_CB/plockr.ico differ diff --git a/src/Ext/Icons_04_CB/plocky.ico b/src/Ext/Icons_04_CB/plocky.ico new file mode 100644 index 0000000..42ead12 Binary files /dev/null and b/src/Ext/Icons_04_CB/plocky.ico differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_1024.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_1024.png new file mode 100644 index 0000000..cbe660a Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_1024.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_128.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_128.png new file mode 100644 index 0000000..c9f93b4 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_128.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_16.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_16.png new file mode 100644 index 0000000..48ea86a Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_16.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_20.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_20.png new file mode 100644 index 0000000..d2567df Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_20.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_24.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_24.png new file mode 100644 index 0000000..baf5f5c Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_24.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_256.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_256.png new file mode 100644 index 0000000..a2cb4ba Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_256.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_32.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_32.png new file mode 100644 index 0000000..9967860 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_32.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_48.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_48.png new file mode 100644 index 0000000..6845cd9 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_48.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_512.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_512.png new file mode 100644 index 0000000..e8318f9 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_512.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_64.png b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_64.png new file mode 100644 index 0000000..b995c6a Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round/KeePass_Round_64.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_128.png b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_128.png new file mode 100644 index 0000000..d3d554d Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_128.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_16.png b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_16.png new file mode 100644 index 0000000..2598341 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_16.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_256.png b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_256.png new file mode 100644 index 0000000..6fae175 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_256.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_32.png b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_32.png new file mode 100644 index 0000000..8bf6861 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_32.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_48.png b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_48.png new file mode 100644 index 0000000..9b667d1 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_48.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_64.png b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_64.png new file mode 100644 index 0000000..0a03118 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Keyhole/KeePass_Round_Keyhole_64.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_128.png b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_128.png new file mode 100644 index 0000000..7e7df47 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_128.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_16.png b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_16.png new file mode 100644 index 0000000..39574b2 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_16.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_256.png b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_256.png new file mode 100644 index 0000000..82b398d Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_256.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_32.png b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_32.png new file mode 100644 index 0000000..d2c18ba Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_32.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_48.png b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_48.png new file mode 100644 index 0000000..9e213fd Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_48.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_64.png b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_64.png new file mode 100644 index 0000000..b3c413a Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Round_Locked/KeePass_Round_Locked_64.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_128.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_128.png new file mode 100644 index 0000000..6013449 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_128.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_16.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_16.png new file mode 100644 index 0000000..0618cc2 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_16.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_24.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_24.png new file mode 100644 index 0000000..17ddfee Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_24.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_256.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_256.png new file mode 100644 index 0000000..e579fdf Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_256.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_32.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_32.png new file mode 100644 index 0000000..0b6f0f8 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_32.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_48.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_48.png new file mode 100644 index 0000000..6bbcdc0 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_48.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_64.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_64.png new file mode 100644 index 0000000..ba16ce7 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue/KeePass_Square_Blue_64.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_128.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_128.png new file mode 100644 index 0000000..aac5978 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_128.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_16.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_16.png new file mode 100644 index 0000000..708ca92 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_16.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_24.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_24.png new file mode 100644 index 0000000..fd99a40 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_24.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_256.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_256.png new file mode 100644 index 0000000..d920dbd Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_256.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_32.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_32.png new file mode 100644 index 0000000..ed907ed Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_32.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_48.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_48.png new file mode 100644 index 0000000..10b4a81 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_48.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_64.png b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_64.png new file mode 100644 index 0000000..817eae2 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Blue_Locked/KeePass_Square_Blue_Locked_64.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_128.png b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_128.png new file mode 100644 index 0000000..e5b43b8 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_128.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_16.png b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_16.png new file mode 100644 index 0000000..c30a8ab Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_16.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_256.png b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_256.png new file mode 100644 index 0000000..b4fedf1 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_256.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_32.png b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_32.png new file mode 100644 index 0000000..cc367d2 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_32.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_48.png b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_48.png new file mode 100644 index 0000000..90598d2 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_48.png differ diff --git a/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_64.png b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_64.png new file mode 100644 index 0000000..b6273c8 Binary files /dev/null and b/src/Ext/Icons_15_VA/KeePass_Square_Yellow/KeePass_Square_Yellow_64.png differ diff --git a/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR.ico b/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR.ico new file mode 100644 index 0000000..098e917 Binary files /dev/null and b/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR.ico differ diff --git a/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR_G.ico b/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR_G.ico new file mode 100644 index 0000000..d35f877 Binary files /dev/null and b/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR_G.ico differ diff --git a/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR_R.ico b/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR_R.ico new file mode 100644 index 0000000..c150c04 Binary files /dev/null and b/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR_R.ico differ diff --git a/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR_Y.ico b/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR_Y.ico new file mode 100644 index 0000000..20e0701 Binary files /dev/null and b/src/Ext/Icons_15_VA/LowResIcons/KeePass_LR_Y.ico differ diff --git a/src/Ext/Icons_15_VA/ReadMe.txt b/src/Ext/Icons_15_VA/ReadMe.txt new file mode 100644 index 0000000..c93bb95 --- /dev/null +++ b/src/Ext/Icons_15_VA/ReadMe.txt @@ -0,0 +1,2 @@ +Many thanks to Victor Andreyenkov for creating these +refined versions of Christopher Bolin's icons! diff --git a/src/Ext/Icons_Nuvola/License.txt b/src/Ext/Icons_Nuvola/License.txt new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/src/Ext/Icons_Nuvola/License.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/src/Ext/Icons_Nuvola/ReadMe.txt b/src/Ext/Icons_Nuvola/ReadMe.txt new file mode 100644 index 0000000..590166e --- /dev/null +++ b/src/Ext/Icons_Nuvola/ReadMe.txt @@ -0,0 +1,60 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +This copyright and license notice covers the images in this directory. +Note the license notice contains an add-on. +************************************************************************ + +TITLE: NUVOLA ICON THEME for KDE 3.x +AUTHOR: David Vignoni | ICON KING +SITE: http://www.icon-king.com +MAILING LIST: http://mail.icon-king.com/mailman/listinfo/nuvola_icon-king.com + +Copyright (c) 2003-2004 David Vignoni. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation, +version 2.1 of the License. +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +You should have received a copy of the GNU Lesser General Public +License along with this library (see the the license.txt file); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#######**** NOTE THIS ADD-ON ****####### +The GNU Lesser General Public License or LGPL is written for software libraries +in the first place. The LGPL has to be considered valid for this artwork +library too. +Nuvola icon theme for KDE 3.x is a special kind of software library, it is an +artwork library, it's elements can be used in a Graphical User Interface, or +GUI. +Source code, for this library means: + - raster png image* . +The LGPL in some sections obliges you to make the files carry +notices. With images this is in some cases impossible or hardly usefull. +With this library a notice is placed at a prominent place in the directory +containing the elements. You may follow this practice. +The exception in section 6 of the GNU Lesser General Public License covers +the use of elements of this art library in a GUI. +dave [at] icon-king.com + +Date: 15 october 2004 +Version: 1.0 + +DESCRIPTION: + +Icon theme for KDE 3.x. +Icons where designed using Adobe Illustrator, and then exported to PNG format. +Icons shadows and minor corrections were done using Adobe Photoshop. +Kiconedit was used to correct some 16x16 and 22x22 icons. + +LICENSE + +Released under GNU Lesser General Public License (LGPL) +Look at the license.txt file. + +CONTACT + +David Vignoni +e-mail : david [at] icon-king.com +ICQ : 117761009 +http: http://www.icon-king.com diff --git a/src/Ext/Images_App_HighRes/Images/B48x48_FontBold.png b/src/Ext/Images_App_HighRes/Images/B48x48_FontBold.png new file mode 100644 index 0000000..8cd5dd0 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Images/B48x48_FontBold.png differ diff --git a/src/Ext/Images_App_HighRes/Images/B48x48_FontItalic.png b/src/Ext/Images_App_HighRes/Images/B48x48_FontItalic.png new file mode 100644 index 0000000..db52876 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Images/B48x48_FontItalic.png differ diff --git a/src/Ext/Images_App_HighRes/Images/B48x48_FontStrikeout.png b/src/Ext/Images_App_HighRes/Images/B48x48_FontStrikeout.png new file mode 100644 index 0000000..a9cc424 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Images/B48x48_FontStrikeout.png differ diff --git a/src/Ext/Images_App_HighRes/Images/B48x48_FontUnderline.png b/src/Ext/Images_App_HighRes/Images/B48x48_FontUnderline.png new file mode 100644 index 0000000..91b365e Binary files /dev/null and b/src/Ext/Images_App_HighRes/Images/B48x48_FontUnderline.png differ diff --git a/src/Ext/Images_App_HighRes/Images/B48x48_KeePass.png b/src/Ext/Images_App_HighRes/Images/B48x48_KeePass.png new file mode 100644 index 0000000..ce89144 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Images/B48x48_KeePass.png differ diff --git a/src/Ext/Images_App_HighRes/Images/B48x48_LockWorkspace.png b/src/Ext/Images_App_HighRes/Images/B48x48_LockWorkspace.png new file mode 100644 index 0000000..f46ae74 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Images/B48x48_LockWorkspace.png differ diff --git a/src/Ext/Images_App_HighRes/Images/B48x48_Transparent.png b/src/Ext/Images_App_HighRes/Images/B48x48_Transparent.png new file mode 100644 index 0000000..63077ca Binary files /dev/null and b/src/Ext/Images_App_HighRes/Images/B48x48_Transparent.png differ diff --git a/src/Ext/Images_App_HighRes/Images/B57x21_3BlackDots.png b/src/Ext/Images_App_HighRes/Images/B57x21_3BlackDots.png new file mode 100644 index 0000000..5a7ef33 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Images/B57x21_3BlackDots.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B32x32_KRec_Record.png b/src/Ext/Images_App_HighRes/Nuvola/B32x32_KRec_Record.png new file mode 100644 index 0000000..42d017c Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B32x32_KRec_Record.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_1DownArrow.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_1DownArrow.png new file mode 100644 index 0000000..ee52113 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_1DownArrow.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_1UpArrow.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_1UpArrow.png new file mode 100644 index 0000000..95fd80d Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_1UpArrow.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_2DownArrow.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_2DownArrow.png new file mode 100644 index 0000000..64fc927 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_2DownArrow.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_2UpArrow.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_2UpArrow.png new file mode 100644 index 0000000..f10cb39 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_2UpArrow.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_ASCII.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_ASCII.png new file mode 100644 index 0000000..884c362 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_ASCII.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Apply.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Apply.png new file mode 100644 index 0000000..3b7a690 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Apply.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Attach.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Attach.png new file mode 100644 index 0000000..449b247 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Attach.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Binary.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Binary.png new file mode 100644 index 0000000..a898930 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Binary.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_BlockDevice.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_BlockDevice.png new file mode 100644 index 0000000..a3b93ff Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_BlockDevice.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Browser.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Browser.png new file mode 100644 index 0000000..b5f28c4 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Browser.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Color_Fill.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Color_Fill.png new file mode 100644 index 0000000..21458cd Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Color_Fill.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Colorize.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Colorize.png new file mode 100644 index 0000000..61a6f63 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Colorize.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_CompFile.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_CompFile.png new file mode 100644 index 0000000..5ea4818 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_CompFile.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Configure.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Configure.png new file mode 100644 index 0000000..2bf463b Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Configure.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Cut.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Cut.png new file mode 100644 index 0000000..57c4711 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Cut.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Edit.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Edit.png new file mode 100644 index 0000000..bee2645 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Edit.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditCopy.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditCopy.png new file mode 100644 index 0000000..a04d2f7 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditCopy.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditDelete.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditDelete.png new file mode 100644 index 0000000..f748cbe Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditDelete.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditPaste.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditPaste.png new file mode 100644 index 0000000..099c51f Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditPaste.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditShred.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditShred.png new file mode 100644 index 0000000..c7d5726 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_EditShred.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Error.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Error.png new file mode 100644 index 0000000..e1841e4 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Error.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Exit.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Exit.png new file mode 100644 index 0000000..e0ae1d9 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Exit.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_FTP.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FTP.png new file mode 100644 index 0000000..5ed1f07 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FTP.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileNew.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileNew.png new file mode 100644 index 0000000..bc10ac0 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileNew.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_FilePrint.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FilePrint.png new file mode 100644 index 0000000..05e1598 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FilePrint.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileQuickPrint.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileQuickPrint.png new file mode 100644 index 0000000..d8d9c3b Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileQuickPrint.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileSave.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileSave.png new file mode 100644 index 0000000..0006ad4 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileSave.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileSaveAs.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileSaveAs.png new file mode 100644 index 0000000..2be6df2 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_FileSaveAs.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_File_Locked.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_File_Locked.png new file mode 100644 index 0000000..9a0e37e Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_File_Locked.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder.png new file mode 100644 index 0000000..31c8a7e Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Blue_Open.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Blue_Open.png new file mode 100644 index 0000000..f7314b3 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Blue_Open.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Home.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Home.png new file mode 100644 index 0000000..74f8aea Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Home.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Locked.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Locked.png new file mode 100644 index 0000000..f165846 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Locked.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Txt.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Txt.png new file mode 100644 index 0000000..e02294a Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Txt.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Yellow_Open.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Yellow_Open.png new file mode 100644 index 0000000..a423319 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Folder_Yellow_Open.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_HTML.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_HTML.png new file mode 100644 index 0000000..017f9d3 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_HTML.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Help.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Help.png new file mode 100644 index 0000000..915f9fd Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Help.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_History.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_History.png new file mode 100644 index 0000000..7907787 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_History.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_History_Clear.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_History_Clear.png new file mode 100644 index 0000000..c475c95 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_History_Clear.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_HwInfo.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_HwInfo.png new file mode 100644 index 0000000..2c7b760 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_HwInfo.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Identity.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Identity.png new file mode 100644 index 0000000..e21451f Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Identity.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Gen.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Gen.png new file mode 100644 index 0000000..78a644b Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Gen.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Import.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Import.png new file mode 100644 index 0000000..0d1e238 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Import.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Info.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Info.png new file mode 100644 index 0000000..4fa7e01 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Info.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Key1.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Key1.png new file mode 100644 index 0000000..eade0c6 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Key1.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Key2.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Key2.png new file mode 100644 index 0000000..01b0054 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Key2.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Key3.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Key3.png new file mode 100644 index 0000000..99b3b7f Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Key3.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Sign.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Sign.png new file mode 100644 index 0000000..1e76bf6 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KGPG_Sign.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KNotes.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KNotes.png new file mode 100644 index 0000000..d0d7cba Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KNotes.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KOrganizer.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KOrganizer.png new file mode 100644 index 0000000..3aa37ad Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KOrganizer.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KTouch.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KTouch.png new file mode 100644 index 0000000..5eb702c Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KTouch.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_KaboodleLoop.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KaboodleLoop.png new file mode 100644 index 0000000..389efac Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_KaboodleLoop.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Keyboard_Layout.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Keyboard_Layout.png new file mode 100644 index 0000000..c17c9f1 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Keyboard_Layout.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Laptop_Charge.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Laptop_Charge.png new file mode 100644 index 0000000..ed869f6 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Laptop_Charge.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Make_KDevelop.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Make_KDevelop.png new file mode 100644 index 0000000..19c2f23 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Make_KDevelop.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_MessageBox_Critical.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_MessageBox_Critical.png new file mode 100644 index 0000000..3f0a657 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_MessageBox_Critical.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_MessageBox_Info.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_MessageBox_Info.png new file mode 100644 index 0000000..079f8fc Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_MessageBox_Info.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_MessageBox_Warning.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_MessageBox_Warning.png new file mode 100644 index 0000000..b11a7b6 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_MessageBox_Warning.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Misc.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Misc.png new file mode 100644 index 0000000..0c17cd9 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Misc.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_No.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_No.png new file mode 100644 index 0000000..b7e2f90 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_No.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Package_Development.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Package_Development.png new file mode 100644 index 0000000..22a9248 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Package_Development.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Package_Settings.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Package_Settings.png new file mode 100644 index 0000000..34dc628 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Package_Settings.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Personal.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Personal.png new file mode 100644 index 0000000..5c111cd Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Personal.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Redo.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Redo.png new file mode 100644 index 0000000..3da735b Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Redo.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Reload_Page.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Reload_Page.png new file mode 100644 index 0000000..c525960 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Reload_Page.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Services.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Services.png new file mode 100644 index 0000000..e4e1243 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Services.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Spreadsheet.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Spreadsheet.png new file mode 100644 index 0000000..05f4aff Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Spreadsheet.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Toggle_Log.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Toggle_Log.png new file mode 100644 index 0000000..16f440d Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Toggle_Log.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Trashcan_Full.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Trashcan_Full.png new file mode 100644 index 0000000..37b1486 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Trashcan_Full.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Undo.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Undo.png new file mode 100644 index 0000000..5cbf37d Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Undo.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_View_Detailed.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_View_Detailed.png new file mode 100644 index 0000000..6b682db Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_View_Detailed.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_WWW.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_WWW.png new file mode 100644 index 0000000..cccc91c Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_WWW.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_Wizard.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Wizard.png new file mode 100644 index 0000000..c117bea Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_Wizard.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola/B48x48_XMag.png b/src/Ext/Images_App_HighRes/Nuvola/B48x48_XMag.png new file mode 100644 index 0000000..538d656 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola/B48x48_XMag.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Assembled/B48x48_Folder_Inbox.png b/src/Ext/Images_App_HighRes/Nuvola_Assembled/B48x48_Folder_Inbox.png new file mode 100644 index 0000000..e26dc7c Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Assembled/B48x48_Folder_Inbox.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Assembled/B48x48_Folder_Outbox.png b/src/Ext/Images_App_HighRes/Nuvola_Assembled/B48x48_Folder_Outbox.png new file mode 100644 index 0000000..dc50d21 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Assembled/B48x48_Folder_Outbox.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_DeleteEntry.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_DeleteEntry.png new file mode 100644 index 0000000..3a18800 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_DeleteEntry.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_EditCopyLink.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_EditCopyLink.png new file mode 100644 index 0000000..9face9b Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_EditCopyLink.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_EditCopyUrl.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_EditCopyUrl.png new file mode 100644 index 0000000..c71176b Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_EditCopyUrl.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_FileSave_Disabled.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_FileSave_Disabled.png new file mode 100644 index 0000000..d733ade Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_FileSave_Disabled.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_File_Close.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_File_Close.png new file mode 100644 index 0000000..b7e2f90 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_File_Close.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_File_SaveAll.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_File_SaveAll.png new file mode 100644 index 0000000..80f19ad Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_File_SaveAll.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_File_SaveAll_Disabled.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_File_SaveAll_Disabled.png new file mode 100644 index 0000000..3469af9 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_File_SaveAll_Disabled.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Folder_2.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Folder_2.png new file mode 100644 index 0000000..2b6dc26 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Folder_2.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Folder_New_Ex.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Folder_New_Ex.png new file mode 100644 index 0000000..8c0113a Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Folder_New_Ex.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Key_New.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Key_New.png new file mode 100644 index 0000000..cc47a91 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Key_New.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_TextAlignCenter.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_TextAlignCenter.png new file mode 100644 index 0000000..1ef88d4 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_TextAlignCenter.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_TextAlignLeft.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_TextAlignLeft.png new file mode 100644 index 0000000..5257ddd Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_TextAlignLeft.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_TextAlignRight.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_TextAlignRight.png new file mode 100644 index 0000000..d7f0799 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_TextAlignRight.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Window_2Horz1Vert.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Window_2Horz1Vert.png new file mode 100644 index 0000000..904eb92 Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Window_2Horz1Vert.png differ diff --git a/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Window_3Horz.png b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Window_3Horz.png new file mode 100644 index 0000000..c22a2af Binary files /dev/null and b/src/Ext/Images_App_HighRes/Nuvola_Derived/B48x48_Window_3Horz.png differ diff --git a/src/Ext/Images_Client_16/C00_Password.png b/src/Ext/Images_Client_16/C00_Password.png new file mode 100644 index 0000000..5656824 Binary files /dev/null and b/src/Ext/Images_Client_16/C00_Password.png differ diff --git a/src/Ext/Images_Client_16/C01_Package_Network.png b/src/Ext/Images_Client_16/C01_Package_Network.png new file mode 100644 index 0000000..03ef9a5 Binary files /dev/null and b/src/Ext/Images_Client_16/C01_Package_Network.png differ diff --git a/src/Ext/Images_Client_16/C02_MessageBox_Warning.png b/src/Ext/Images_Client_16/C02_MessageBox_Warning.png new file mode 100644 index 0000000..474f63f Binary files /dev/null and b/src/Ext/Images_Client_16/C02_MessageBox_Warning.png differ diff --git a/src/Ext/Images_Client_16/C03_Server.png b/src/Ext/Images_Client_16/C03_Server.png new file mode 100644 index 0000000..bb8a316 Binary files /dev/null and b/src/Ext/Images_Client_16/C03_Server.png differ diff --git a/src/Ext/Images_Client_16/C04_Klipper.png b/src/Ext/Images_Client_16/C04_Klipper.png new file mode 100644 index 0000000..ff668d5 Binary files /dev/null and b/src/Ext/Images_Client_16/C04_Klipper.png differ diff --git a/src/Ext/Images_Client_16/C05_Edu_Languages.png b/src/Ext/Images_Client_16/C05_Edu_Languages.png new file mode 100644 index 0000000..8aa2004 Binary files /dev/null and b/src/Ext/Images_Client_16/C05_Edu_Languages.png differ diff --git a/src/Ext/Images_Client_16/C06_KCMDF.png b/src/Ext/Images_Client_16/C06_KCMDF.png new file mode 100644 index 0000000..604c3d5 Binary files /dev/null and b/src/Ext/Images_Client_16/C06_KCMDF.png differ diff --git a/src/Ext/Images_Client_16/C07_Kate.png b/src/Ext/Images_Client_16/C07_Kate.png new file mode 100644 index 0000000..4a52bb1 Binary files /dev/null and b/src/Ext/Images_Client_16/C07_Kate.png differ diff --git a/src/Ext/Images_Client_16/C08_Socket.png b/src/Ext/Images_Client_16/C08_Socket.png new file mode 100644 index 0000000..3125ef8 Binary files /dev/null and b/src/Ext/Images_Client_16/C08_Socket.png differ diff --git a/src/Ext/Images_Client_16/C09_Identity.png b/src/Ext/Images_Client_16/C09_Identity.png new file mode 100644 index 0000000..5e51272 Binary files /dev/null and b/src/Ext/Images_Client_16/C09_Identity.png differ diff --git a/src/Ext/Images_Client_16/C10_Kontact.png b/src/Ext/Images_Client_16/C10_Kontact.png new file mode 100644 index 0000000..e4c5cdc Binary files /dev/null and b/src/Ext/Images_Client_16/C10_Kontact.png differ diff --git a/src/Ext/Images_Client_16/C11_Camera.png b/src/Ext/Images_Client_16/C11_Camera.png new file mode 100644 index 0000000..45d1436 Binary files /dev/null and b/src/Ext/Images_Client_16/C11_Camera.png differ diff --git a/src/Ext/Images_Client_16/C12_IRKickFlash.png b/src/Ext/Images_Client_16/C12_IRKickFlash.png new file mode 100644 index 0000000..89e7a97 Binary files /dev/null and b/src/Ext/Images_Client_16/C12_IRKickFlash.png differ diff --git a/src/Ext/Images_Client_16/C13_KGPG_Key3.png b/src/Ext/Images_Client_16/C13_KGPG_Key3.png new file mode 100644 index 0000000..e68afac Binary files /dev/null and b/src/Ext/Images_Client_16/C13_KGPG_Key3.png differ diff --git a/src/Ext/Images_Client_16/C14_Laptop_Power.png b/src/Ext/Images_Client_16/C14_Laptop_Power.png new file mode 100644 index 0000000..69c89a5 Binary files /dev/null and b/src/Ext/Images_Client_16/C14_Laptop_Power.png differ diff --git a/src/Ext/Images_Client_16/C15_Scanner.png b/src/Ext/Images_Client_16/C15_Scanner.png new file mode 100644 index 0000000..fa0f83d Binary files /dev/null and b/src/Ext/Images_Client_16/C15_Scanner.png differ diff --git a/src/Ext/Images_Client_16/C16_Mozilla_Firebird.png b/src/Ext/Images_Client_16/C16_Mozilla_Firebird.png new file mode 100644 index 0000000..7c2e661 Binary files /dev/null and b/src/Ext/Images_Client_16/C16_Mozilla_Firebird.png differ diff --git a/src/Ext/Images_Client_16/C17_CDROM_Unmount.png b/src/Ext/Images_Client_16/C17_CDROM_Unmount.png new file mode 100644 index 0000000..e2e3f67 Binary files /dev/null and b/src/Ext/Images_Client_16/C17_CDROM_Unmount.png differ diff --git a/src/Ext/Images_Client_16/C18_Display.png b/src/Ext/Images_Client_16/C18_Display.png new file mode 100644 index 0000000..ededc0b Binary files /dev/null and b/src/Ext/Images_Client_16/C18_Display.png differ diff --git a/src/Ext/Images_Client_16/C19_Mail_Generic.png b/src/Ext/Images_Client_16/C19_Mail_Generic.png new file mode 100644 index 0000000..2de442b Binary files /dev/null and b/src/Ext/Images_Client_16/C19_Mail_Generic.png differ diff --git a/src/Ext/Images_Client_16/C20_Misc.png b/src/Ext/Images_Client_16/C20_Misc.png new file mode 100644 index 0000000..98d4b99 Binary files /dev/null and b/src/Ext/Images_Client_16/C20_Misc.png differ diff --git a/src/Ext/Images_Client_16/C21_KOrganizer.png b/src/Ext/Images_Client_16/C21_KOrganizer.png new file mode 100644 index 0000000..6c86544 Binary files /dev/null and b/src/Ext/Images_Client_16/C21_KOrganizer.png differ diff --git a/src/Ext/Images_Client_16/C22_ASCII.png b/src/Ext/Images_Client_16/C22_ASCII.png new file mode 100644 index 0000000..8e771b7 Binary files /dev/null and b/src/Ext/Images_Client_16/C22_ASCII.png differ diff --git a/src/Ext/Images_Client_16/C23_Icons.png b/src/Ext/Images_Client_16/C23_Icons.png new file mode 100644 index 0000000..df51f18 Binary files /dev/null and b/src/Ext/Images_Client_16/C23_Icons.png differ diff --git a/src/Ext/Images_Client_16/C24_Connect_Established.png b/src/Ext/Images_Client_16/C24_Connect_Established.png new file mode 100644 index 0000000..0f6b9f9 Binary files /dev/null and b/src/Ext/Images_Client_16/C24_Connect_Established.png differ diff --git a/src/Ext/Images_Client_16/C25_Folder_Mail.png b/src/Ext/Images_Client_16/C25_Folder_Mail.png new file mode 100644 index 0000000..90cf487 Binary files /dev/null and b/src/Ext/Images_Client_16/C25_Folder_Mail.png differ diff --git a/src/Ext/Images_Client_16/C26_FileSave.png b/src/Ext/Images_Client_16/C26_FileSave.png new file mode 100644 index 0000000..fd0048d Binary files /dev/null and b/src/Ext/Images_Client_16/C26_FileSave.png differ diff --git a/src/Ext/Images_Client_16/C27_NFS_Unmount.png b/src/Ext/Images_Client_16/C27_NFS_Unmount.png new file mode 100644 index 0000000..f6a8dd5 Binary files /dev/null and b/src/Ext/Images_Client_16/C27_NFS_Unmount.png differ diff --git a/src/Ext/Images_Client_16/C28_Message.png b/src/Ext/Images_Client_16/C28_Message.png new file mode 100644 index 0000000..ae1ce24 Binary files /dev/null and b/src/Ext/Images_Client_16/C28_Message.png differ diff --git a/src/Ext/Images_Client_16/C29_KGPG_Term.png b/src/Ext/Images_Client_16/C29_KGPG_Term.png new file mode 100644 index 0000000..e77ff5b Binary files /dev/null and b/src/Ext/Images_Client_16/C29_KGPG_Term.png differ diff --git a/src/Ext/Images_Client_16/C30_Konsole.png b/src/Ext/Images_Client_16/C30_Konsole.png new file mode 100644 index 0000000..b1366b1 Binary files /dev/null and b/src/Ext/Images_Client_16/C30_Konsole.png differ diff --git a/src/Ext/Images_Client_16/C31_FilePrint.png b/src/Ext/Images_Client_16/C31_FilePrint.png new file mode 100644 index 0000000..3a87543 Binary files /dev/null and b/src/Ext/Images_Client_16/C31_FilePrint.png differ diff --git a/src/Ext/Images_Client_16/C32_FSView.png b/src/Ext/Images_Client_16/C32_FSView.png new file mode 100644 index 0000000..e167acf Binary files /dev/null and b/src/Ext/Images_Client_16/C32_FSView.png differ diff --git a/src/Ext/Images_Client_16/C33_Run.png b/src/Ext/Images_Client_16/C33_Run.png new file mode 100644 index 0000000..7514245 Binary files /dev/null and b/src/Ext/Images_Client_16/C33_Run.png differ diff --git a/src/Ext/Images_Client_16/C34_Configure.png b/src/Ext/Images_Client_16/C34_Configure.png new file mode 100644 index 0000000..a4a3834 Binary files /dev/null and b/src/Ext/Images_Client_16/C34_Configure.png differ diff --git a/src/Ext/Images_Client_16/C35_KRFB.png b/src/Ext/Images_Client_16/C35_KRFB.png new file mode 100644 index 0000000..6f02e87 Binary files /dev/null and b/src/Ext/Images_Client_16/C35_KRFB.png differ diff --git a/src/Ext/Images_Client_16/C36_Ark.png b/src/Ext/Images_Client_16/C36_Ark.png new file mode 100644 index 0000000..e2b67dc Binary files /dev/null and b/src/Ext/Images_Client_16/C36_Ark.png differ diff --git a/src/Ext/Images_Client_16/C37_KPercentage.png b/src/Ext/Images_Client_16/C37_KPercentage.png new file mode 100644 index 0000000..2a15a07 Binary files /dev/null and b/src/Ext/Images_Client_16/C37_KPercentage.png differ diff --git a/src/Ext/Images_Client_16/C38_Samba_Unmount.png b/src/Ext/Images_Client_16/C38_Samba_Unmount.png new file mode 100644 index 0000000..3f3b8ff Binary files /dev/null and b/src/Ext/Images_Client_16/C38_Samba_Unmount.png differ diff --git a/src/Ext/Images_Client_16/C39_History.png b/src/Ext/Images_Client_16/C39_History.png new file mode 100644 index 0000000..8d658e0 Binary files /dev/null and b/src/Ext/Images_Client_16/C39_History.png differ diff --git a/src/Ext/Images_Client_16/C40_Mail_Find.png b/src/Ext/Images_Client_16/C40_Mail_Find.png new file mode 100644 index 0000000..1e230e2 Binary files /dev/null and b/src/Ext/Images_Client_16/C40_Mail_Find.png differ diff --git a/src/Ext/Images_Client_16/C41_VectorGfx.png b/src/Ext/Images_Client_16/C41_VectorGfx.png new file mode 100644 index 0000000..5b51008 Binary files /dev/null and b/src/Ext/Images_Client_16/C41_VectorGfx.png differ diff --git a/src/Ext/Images_Client_16/C42_KCMMemory.png b/src/Ext/Images_Client_16/C42_KCMMemory.png new file mode 100644 index 0000000..c749034 Binary files /dev/null and b/src/Ext/Images_Client_16/C42_KCMMemory.png differ diff --git a/src/Ext/Images_Client_16/C43_Trashcan_Full.png b/src/Ext/Images_Client_16/C43_Trashcan_Full.png new file mode 100644 index 0000000..aa9d732 Binary files /dev/null and b/src/Ext/Images_Client_16/C43_Trashcan_Full.png differ diff --git a/src/Ext/Images_Client_16/C44_KNotes.png b/src/Ext/Images_Client_16/C44_KNotes.png new file mode 100644 index 0000000..1e27e9c Binary files /dev/null and b/src/Ext/Images_Client_16/C44_KNotes.png differ diff --git a/src/Ext/Images_Client_16/C45_Cancel.png b/src/Ext/Images_Client_16/C45_Cancel.png new file mode 100644 index 0000000..a432b49 Binary files /dev/null and b/src/Ext/Images_Client_16/C45_Cancel.png differ diff --git a/src/Ext/Images_Client_16/C46_Help.png b/src/Ext/Images_Client_16/C46_Help.png new file mode 100644 index 0000000..28a0f9e Binary files /dev/null and b/src/Ext/Images_Client_16/C46_Help.png differ diff --git a/src/Ext/Images_Client_16/C47_KPackage.png b/src/Ext/Images_Client_16/C47_KPackage.png new file mode 100644 index 0000000..fdb3644 Binary files /dev/null and b/src/Ext/Images_Client_16/C47_KPackage.png differ diff --git a/src/Ext/Images_Client_16/C48_Folder.png b/src/Ext/Images_Client_16/C48_Folder.png new file mode 100644 index 0000000..1972448 Binary files /dev/null and b/src/Ext/Images_Client_16/C48_Folder.png differ diff --git a/src/Ext/Images_Client_16/C49_Folder_Blue_Open.png b/src/Ext/Images_Client_16/C49_Folder_Blue_Open.png new file mode 100644 index 0000000..2c55c56 Binary files /dev/null and b/src/Ext/Images_Client_16/C49_Folder_Blue_Open.png differ diff --git a/src/Ext/Images_Client_16/C50_Folder_Tar.png b/src/Ext/Images_Client_16/C50_Folder_Tar.png new file mode 100644 index 0000000..2effa39 Binary files /dev/null and b/src/Ext/Images_Client_16/C50_Folder_Tar.png differ diff --git a/src/Ext/Images_Client_16/C51_Decrypted.png b/src/Ext/Images_Client_16/C51_Decrypted.png new file mode 100644 index 0000000..42dd93e Binary files /dev/null and b/src/Ext/Images_Client_16/C51_Decrypted.png differ diff --git a/src/Ext/Images_Client_16/C52_Encrypted.png b/src/Ext/Images_Client_16/C52_Encrypted.png new file mode 100644 index 0000000..8035712 Binary files /dev/null and b/src/Ext/Images_Client_16/C52_Encrypted.png differ diff --git a/src/Ext/Images_Client_16/C53_Apply.png b/src/Ext/Images_Client_16/C53_Apply.png new file mode 100644 index 0000000..5b0f6a6 Binary files /dev/null and b/src/Ext/Images_Client_16/C53_Apply.png differ diff --git a/src/Ext/Images_Client_16/C54_Signature.png b/src/Ext/Images_Client_16/C54_Signature.png new file mode 100644 index 0000000..8834f3f Binary files /dev/null and b/src/Ext/Images_Client_16/C54_Signature.png differ diff --git a/src/Ext/Images_Client_16/C55_Thumbnail.png b/src/Ext/Images_Client_16/C55_Thumbnail.png new file mode 100644 index 0000000..91adff8 Binary files /dev/null and b/src/Ext/Images_Client_16/C55_Thumbnail.png differ diff --git a/src/Ext/Images_Client_16/C56_KAddressBook.png b/src/Ext/Images_Client_16/C56_KAddressBook.png new file mode 100644 index 0000000..7f879f8 Binary files /dev/null and b/src/Ext/Images_Client_16/C56_KAddressBook.png differ diff --git a/src/Ext/Images_Client_16/C57_View_Text.png b/src/Ext/Images_Client_16/C57_View_Text.png new file mode 100644 index 0000000..c688d5f Binary files /dev/null and b/src/Ext/Images_Client_16/C57_View_Text.png differ diff --git a/src/Ext/Images_Client_16/C58_KGPG.png b/src/Ext/Images_Client_16/C58_KGPG.png new file mode 100644 index 0000000..a6ed9b4 Binary files /dev/null and b/src/Ext/Images_Client_16/C58_KGPG.png differ diff --git a/src/Ext/Images_Client_16/C59_Package_Development.png b/src/Ext/Images_Client_16/C59_Package_Development.png new file mode 100644 index 0000000..df1fb74 Binary files /dev/null and b/src/Ext/Images_Client_16/C59_Package_Development.png differ diff --git a/src/Ext/Images_Client_16/C60_KFM_Home.png b/src/Ext/Images_Client_16/C60_KFM_Home.png new file mode 100644 index 0000000..3525b0b Binary files /dev/null and b/src/Ext/Images_Client_16/C60_KFM_Home.png differ diff --git a/src/Ext/Images_Client_16/C61_Services.png b/src/Ext/Images_Client_16/C61_Services.png new file mode 100644 index 0000000..2a24b7e Binary files /dev/null and b/src/Ext/Images_Client_16/C61_Services.png differ diff --git a/src/Ext/Images_Client_16/C62_Tux.png b/src/Ext/Images_Client_16/C62_Tux.png new file mode 100644 index 0000000..437b418 Binary files /dev/null and b/src/Ext/Images_Client_16/C62_Tux.png differ diff --git a/src/Ext/Images_Client_16/C63_Feather.png b/src/Ext/Images_Client_16/C63_Feather.png new file mode 100644 index 0000000..1e58370 Binary files /dev/null and b/src/Ext/Images_Client_16/C63_Feather.png differ diff --git a/src/Ext/Images_Client_16/C64_Apple.png b/src/Ext/Images_Client_16/C64_Apple.png new file mode 100644 index 0000000..b35f728 Binary files /dev/null and b/src/Ext/Images_Client_16/C64_Apple.png differ diff --git a/src/Ext/Images_Client_16/C65_W.png b/src/Ext/Images_Client_16/C65_W.png new file mode 100644 index 0000000..69dc825 Binary files /dev/null and b/src/Ext/Images_Client_16/C65_W.png differ diff --git a/src/Ext/Images_Client_16/C66_Money.png b/src/Ext/Images_Client_16/C66_Money.png new file mode 100644 index 0000000..e32ed5a Binary files /dev/null and b/src/Ext/Images_Client_16/C66_Money.png differ diff --git a/src/Ext/Images_Client_16/C67_Certificate.png b/src/Ext/Images_Client_16/C67_Certificate.png new file mode 100644 index 0000000..5494fb9 Binary files /dev/null and b/src/Ext/Images_Client_16/C67_Certificate.png differ diff --git a/src/Ext/Images_Client_16/C68_Smartphone.png b/src/Ext/Images_Client_16/C68_Smartphone.png new file mode 100644 index 0000000..af53ab2 Binary files /dev/null and b/src/Ext/Images_Client_16/C68_Smartphone.png differ diff --git a/src/Ext/Images_Client_HighRes/C00_Password.png b/src/Ext/Images_Client_HighRes/C00_Password.png new file mode 100644 index 0000000..98d7607 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C00_Password.png differ diff --git a/src/Ext/Images_Client_HighRes/C01_Package_Network.png b/src/Ext/Images_Client_HighRes/C01_Package_Network.png new file mode 100644 index 0000000..b5f28c4 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C01_Package_Network.png differ diff --git a/src/Ext/Images_Client_HighRes/C02_MessageBox_Warning.png b/src/Ext/Images_Client_HighRes/C02_MessageBox_Warning.png new file mode 100644 index 0000000..b11a7b6 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C02_MessageBox_Warning.png differ diff --git a/src/Ext/Images_Client_HighRes/C03_Server.png b/src/Ext/Images_Client_HighRes/C03_Server.png new file mode 100644 index 0000000..eb337b4 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C03_Server.png differ diff --git a/src/Ext/Images_Client_HighRes/C04_Klipper.png b/src/Ext/Images_Client_HighRes/C04_Klipper.png new file mode 100644 index 0000000..87ff9a1 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C04_Klipper.png differ diff --git a/src/Ext/Images_Client_HighRes/C05_Edu_Languages.png b/src/Ext/Images_Client_HighRes/C05_Edu_Languages.png new file mode 100644 index 0000000..5eae512 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C05_Edu_Languages.png differ diff --git a/src/Ext/Images_Client_HighRes/C06_KCMDF.png b/src/Ext/Images_Client_HighRes/C06_KCMDF.png new file mode 100644 index 0000000..ed1c867 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C06_KCMDF.png differ diff --git a/src/Ext/Images_Client_HighRes/C07_Kate.png b/src/Ext/Images_Client_HighRes/C07_Kate.png new file mode 100644 index 0000000..36459cf Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C07_Kate.png differ diff --git a/src/Ext/Images_Client_HighRes/C08_Socket.png b/src/Ext/Images_Client_HighRes/C08_Socket.png new file mode 100644 index 0000000..1bacbaa Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C08_Socket.png differ diff --git a/src/Ext/Images_Client_HighRes/C09_Identity.png b/src/Ext/Images_Client_HighRes/C09_Identity.png new file mode 100644 index 0000000..e21451f Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C09_Identity.png differ diff --git a/src/Ext/Images_Client_HighRes/C10_Kontact.png b/src/Ext/Images_Client_HighRes/C10_Kontact.png new file mode 100644 index 0000000..75619bc Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C10_Kontact.png differ diff --git a/src/Ext/Images_Client_HighRes/C11_Camera.png b/src/Ext/Images_Client_HighRes/C11_Camera.png new file mode 100644 index 0000000..68046fa Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C11_Camera.png differ diff --git a/src/Ext/Images_Client_HighRes/C12_IRKickFlash.png b/src/Ext/Images_Client_HighRes/C12_IRKickFlash.png new file mode 100644 index 0000000..bc7e2ae Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C12_IRKickFlash.png differ diff --git a/src/Ext/Images_Client_HighRes/C13_KGPG_Key3.png b/src/Ext/Images_Client_HighRes/C13_KGPG_Key3.png new file mode 100644 index 0000000..99b3b7f Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C13_KGPG_Key3.png differ diff --git a/src/Ext/Images_Client_HighRes/C14_Laptop_Power.png b/src/Ext/Images_Client_HighRes/C14_Laptop_Power.png new file mode 100644 index 0000000..4a37878 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C14_Laptop_Power.png differ diff --git a/src/Ext/Images_Client_HighRes/C15_Scanner.png b/src/Ext/Images_Client_HighRes/C15_Scanner.png new file mode 100644 index 0000000..71aed18 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C15_Scanner.png differ diff --git a/src/Ext/Images_Client_HighRes/C16_Mozilla_Firebird.png b/src/Ext/Images_Client_HighRes/C16_Mozilla_Firebird.png new file mode 100644 index 0000000..1fae5e7 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C16_Mozilla_Firebird.png differ diff --git a/src/Ext/Images_Client_HighRes/C17_CDROM_Unmount.png b/src/Ext/Images_Client_HighRes/C17_CDROM_Unmount.png new file mode 100644 index 0000000..1b0a503 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C17_CDROM_Unmount.png differ diff --git a/src/Ext/Images_Client_HighRes/C18_Display.png b/src/Ext/Images_Client_HighRes/C18_Display.png new file mode 100644 index 0000000..6b9ab9e Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C18_Display.png differ diff --git a/src/Ext/Images_Client_HighRes/C19_Mail_Generic.png b/src/Ext/Images_Client_HighRes/C19_Mail_Generic.png new file mode 100644 index 0000000..79699c8 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C19_Mail_Generic.png differ diff --git a/src/Ext/Images_Client_HighRes/C20_Misc.png b/src/Ext/Images_Client_HighRes/C20_Misc.png new file mode 100644 index 0000000..0c17cd9 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C20_Misc.png differ diff --git a/src/Ext/Images_Client_HighRes/C21_KOrganizer.png b/src/Ext/Images_Client_HighRes/C21_KOrganizer.png new file mode 100644 index 0000000..3aa37ad Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C21_KOrganizer.png differ diff --git a/src/Ext/Images_Client_HighRes/C22_ASCII.png b/src/Ext/Images_Client_HighRes/C22_ASCII.png new file mode 100644 index 0000000..884c362 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C22_ASCII.png differ diff --git a/src/Ext/Images_Client_HighRes/C23_Icons.png b/src/Ext/Images_Client_HighRes/C23_Icons.png new file mode 100644 index 0000000..5aaece3 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C23_Icons.png differ diff --git a/src/Ext/Images_Client_HighRes/C24_Connect_Established.png b/src/Ext/Images_Client_HighRes/C24_Connect_Established.png new file mode 100644 index 0000000..4a2de8c Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C24_Connect_Established.png differ diff --git a/src/Ext/Images_Client_HighRes/C25_Folder_Mail.png b/src/Ext/Images_Client_HighRes/C25_Folder_Mail.png new file mode 100644 index 0000000..23365a1 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C25_Folder_Mail.png differ diff --git a/src/Ext/Images_Client_HighRes/C26_FileSave.png b/src/Ext/Images_Client_HighRes/C26_FileSave.png new file mode 100644 index 0000000..0006ad4 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C26_FileSave.png differ diff --git a/src/Ext/Images_Client_HighRes/C27_NFS_Unmount.png b/src/Ext/Images_Client_HighRes/C27_NFS_Unmount.png new file mode 100644 index 0000000..20cd06b Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C27_NFS_Unmount.png differ diff --git a/src/Ext/Images_Client_HighRes/C28_Message.png b/src/Ext/Images_Client_HighRes/C28_Message.png new file mode 100644 index 0000000..746e915 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C28_Message.png differ diff --git a/src/Ext/Images_Client_HighRes/C29_KGPG_Term.png b/src/Ext/Images_Client_HighRes/C29_KGPG_Term.png new file mode 100644 index 0000000..3e2421f Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C29_KGPG_Term.png differ diff --git a/src/Ext/Images_Client_HighRes/C30_Konsole.png b/src/Ext/Images_Client_HighRes/C30_Konsole.png new file mode 100644 index 0000000..aad1041 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C30_Konsole.png differ diff --git a/src/Ext/Images_Client_HighRes/C31_FilePrint.png b/src/Ext/Images_Client_HighRes/C31_FilePrint.png new file mode 100644 index 0000000..05e1598 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C31_FilePrint.png differ diff --git a/src/Ext/Images_Client_HighRes/C32_FSView.png b/src/Ext/Images_Client_HighRes/C32_FSView.png new file mode 100644 index 0000000..299e137 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C32_FSView.png differ diff --git a/src/Ext/Images_Client_HighRes/C33_Run.png b/src/Ext/Images_Client_HighRes/C33_Run.png new file mode 100644 index 0000000..d741485 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C33_Run.png differ diff --git a/src/Ext/Images_Client_HighRes/C34_Configure.png b/src/Ext/Images_Client_HighRes/C34_Configure.png new file mode 100644 index 0000000..2bf463b Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C34_Configure.png differ diff --git a/src/Ext/Images_Client_HighRes/C35_KRFB.png b/src/Ext/Images_Client_HighRes/C35_KRFB.png new file mode 100644 index 0000000..f83e3dc Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C35_KRFB.png differ diff --git a/src/Ext/Images_Client_HighRes/C36_Ark.png b/src/Ext/Images_Client_HighRes/C36_Ark.png new file mode 100644 index 0000000..3393d26 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C36_Ark.png differ diff --git a/src/Ext/Images_Client_HighRes/C37_KPercentage.png b/src/Ext/Images_Client_HighRes/C37_KPercentage.png new file mode 100644 index 0000000..3ba9bf2 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C37_KPercentage.png differ diff --git a/src/Ext/Images_Client_HighRes/C38_Samba_Unmount.png b/src/Ext/Images_Client_HighRes/C38_Samba_Unmount.png new file mode 100644 index 0000000..83d8e7e Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C38_Samba_Unmount.png differ diff --git a/src/Ext/Images_Client_HighRes/C39_History.png b/src/Ext/Images_Client_HighRes/C39_History.png new file mode 100644 index 0000000..7907787 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C39_History.png differ diff --git a/src/Ext/Images_Client_HighRes/C40_Mail_Find.png b/src/Ext/Images_Client_HighRes/C40_Mail_Find.png new file mode 100644 index 0000000..56b68ee Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C40_Mail_Find.png differ diff --git a/src/Ext/Images_Client_HighRes/C41_VectorGfx.png b/src/Ext/Images_Client_HighRes/C41_VectorGfx.png new file mode 100644 index 0000000..9a35223 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C41_VectorGfx.png differ diff --git a/src/Ext/Images_Client_HighRes/C42_KCMMemory.png b/src/Ext/Images_Client_HighRes/C42_KCMMemory.png new file mode 100644 index 0000000..ecd8072 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C42_KCMMemory.png differ diff --git a/src/Ext/Images_Client_HighRes/C43_Trashcan_Full.png b/src/Ext/Images_Client_HighRes/C43_Trashcan_Full.png new file mode 100644 index 0000000..37b1486 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C43_Trashcan_Full.png differ diff --git a/src/Ext/Images_Client_HighRes/C44_KNotes.png b/src/Ext/Images_Client_HighRes/C44_KNotes.png new file mode 100644 index 0000000..d0d7cba Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C44_KNotes.png differ diff --git a/src/Ext/Images_Client_HighRes/C45_Cancel.png b/src/Ext/Images_Client_HighRes/C45_Cancel.png new file mode 100644 index 0000000..6b4497d Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C45_Cancel.png differ diff --git a/src/Ext/Images_Client_HighRes/C46_Help.png b/src/Ext/Images_Client_HighRes/C46_Help.png new file mode 100644 index 0000000..915f9fd Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C46_Help.png differ diff --git a/src/Ext/Images_Client_HighRes/C47_KPackage.png b/src/Ext/Images_Client_HighRes/C47_KPackage.png new file mode 100644 index 0000000..c8a65a7 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C47_KPackage.png differ diff --git a/src/Ext/Images_Client_HighRes/C48_Folder.png b/src/Ext/Images_Client_HighRes/C48_Folder.png new file mode 100644 index 0000000..31c8a7e Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C48_Folder.png differ diff --git a/src/Ext/Images_Client_HighRes/C49_Folder_Blue_Open.png b/src/Ext/Images_Client_HighRes/C49_Folder_Blue_Open.png new file mode 100644 index 0000000..f7314b3 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C49_Folder_Blue_Open.png differ diff --git a/src/Ext/Images_Client_HighRes/C50_Folder_Tar.png b/src/Ext/Images_Client_HighRes/C50_Folder_Tar.png new file mode 100644 index 0000000..bf10afc Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C50_Folder_Tar.png differ diff --git a/src/Ext/Images_Client_HighRes/C51_Decrypted.png b/src/Ext/Images_Client_HighRes/C51_Decrypted.png new file mode 100644 index 0000000..c532f17 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C51_Decrypted.png differ diff --git a/src/Ext/Images_Client_HighRes/C52_Encrypted.png b/src/Ext/Images_Client_HighRes/C52_Encrypted.png new file mode 100644 index 0000000..4d42a7e Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C52_Encrypted.png differ diff --git a/src/Ext/Images_Client_HighRes/C53_Apply.png b/src/Ext/Images_Client_HighRes/C53_Apply.png new file mode 100644 index 0000000..3b7a690 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C53_Apply.png differ diff --git a/src/Ext/Images_Client_HighRes/C54_Signature.png b/src/Ext/Images_Client_HighRes/C54_Signature.png new file mode 100644 index 0000000..3df00d2 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C54_Signature.png differ diff --git a/src/Ext/Images_Client_HighRes/C55_Thumbnail.png b/src/Ext/Images_Client_HighRes/C55_Thumbnail.png new file mode 100644 index 0000000..bcc1681 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C55_Thumbnail.png differ diff --git a/src/Ext/Images_Client_HighRes/C56_KAddressBook.png b/src/Ext/Images_Client_HighRes/C56_KAddressBook.png new file mode 100644 index 0000000..16f440d Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C56_KAddressBook.png differ diff --git a/src/Ext/Images_Client_HighRes/C57_View_Text.png b/src/Ext/Images_Client_HighRes/C57_View_Text.png new file mode 100644 index 0000000..c0f2b0f Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C57_View_Text.png differ diff --git a/src/Ext/Images_Client_HighRes/C58_KGPG.png b/src/Ext/Images_Client_HighRes/C58_KGPG.png new file mode 100644 index 0000000..108d62e Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C58_KGPG.png differ diff --git a/src/Ext/Images_Client_HighRes/C59_Package_Development.png b/src/Ext/Images_Client_HighRes/C59_Package_Development.png new file mode 100644 index 0000000..22a9248 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C59_Package_Development.png differ diff --git a/src/Ext/Images_Client_HighRes/C60_KFM_Home.png b/src/Ext/Images_Client_HighRes/C60_KFM_Home.png new file mode 100644 index 0000000..74f8aea Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C60_KFM_Home.png differ diff --git a/src/Ext/Images_Client_HighRes/C61_Services.png b/src/Ext/Images_Client_HighRes/C61_Services.png new file mode 100644 index 0000000..e4e1243 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C61_Services.png differ diff --git a/src/Ext/Images_Client_HighRes/C62_Tux.png b/src/Ext/Images_Client_HighRes/C62_Tux.png new file mode 100644 index 0000000..5a0f74e Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C62_Tux.png differ diff --git a/src/Ext/Images_Client_HighRes/C63_Feather.png b/src/Ext/Images_Client_HighRes/C63_Feather.png new file mode 100644 index 0000000..dcdef2e Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C63_Feather.png differ diff --git a/src/Ext/Images_Client_HighRes/C64_Apple.png b/src/Ext/Images_Client_HighRes/C64_Apple.png new file mode 100644 index 0000000..cacbb06 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C64_Apple.png differ diff --git a/src/Ext/Images_Client_HighRes/C65_W.png b/src/Ext/Images_Client_HighRes/C65_W.png new file mode 100644 index 0000000..311953d Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C65_W.png differ diff --git a/src/Ext/Images_Client_HighRes/C66_Money.png b/src/Ext/Images_Client_HighRes/C66_Money.png new file mode 100644 index 0000000..db9dc7e Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C66_Money.png differ diff --git a/src/Ext/Images_Client_HighRes/C67_Certificate.png b/src/Ext/Images_Client_HighRes/C67_Certificate.png new file mode 100644 index 0000000..54da0f3 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C67_Certificate.png differ diff --git a/src/Ext/Images_Client_HighRes/C68_Smartphone.png b/src/Ext/Images_Client_HighRes/C68_Smartphone.png new file mode 100644 index 0000000..d4b95b9 Binary files /dev/null and b/src/Ext/Images_Client_HighRes/C68_Smartphone.png differ diff --git a/src/Ext/KPDummyKey.pfx b/src/Ext/KPDummyKey.pfx new file mode 100644 index 0000000..19b0155 Binary files /dev/null and b/src/Ext/KPDummyKey.pfx differ diff --git a/src/Ext/KeePass.config.xml b/src/Ext/KeePass.config.xml new file mode 100644 index 0000000..6cbbd51 --- /dev/null +++ b/src/Ext/KeePass.config.xml @@ -0,0 +1,6 @@ + + + + true + + diff --git a/src/Ext/KeePass.exe.config b/src/Ext/KeePass.exe.config new file mode 100644 index 0000000..1ab98a4 --- /dev/null +++ b/src/Ext/KeePass.exe.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ext/KeePass.iss b/src/Ext/KeePass.iss new file mode 100644 index 0000000..c8ae128 --- /dev/null +++ b/src/Ext/KeePass.iss @@ -0,0 +1,363 @@ +; KeePass Password Safe Installation Script +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! +; Thanks to Hilbrand Edskes for installer improvements. + +#define MyAppNameShort "KeePass" +#define MyAppNameShortEx "KeePass 2" +#define MyAppName "KeePass Password Safe" +#define MyAppNameEx "KeePass Password Safe 2" +#define MyAppPublisher "Dominik Reichl" +#define MyAppURL "https://keepass.info/" +#define MyAppExeName "KeePass.exe" +#define MyAppUrlName "KeePass.url" +#define MyAppHelpName "KeePass.chm" +#define MyAppId "KeePassPasswordSafe2" + +#define KeeVersionStr "2.53" +#define KeeVersionStrWithMinor "2.53" +#define KeeVersionStrWithMinorPath "2.53" +#define KeeVersionWin "2.53.0.0" +#define KeeVersionWinShort "2.53" + +#define KeeDevPeriod "2003-2023" + +[Setup] +AppName={#MyAppName} +AppVersion={#KeeVersionWinShort} +AppVerName={#MyAppName} {#KeeVersionStrWithMinor} +AppId={#MyAppId} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +AppCopyright=Copyright © {#KeeDevPeriod} {#MyAppPublisher} +MinVersion=6.1sp1 + +; When specifying ArchitecturesInstallIn64BitMode=x64, Inno Setup performs +; a side-by-side installation instead of updating a previous installation +; (32-bit installation on a 64-bit system). +; In order to avoid this, we only change DefaultDirName. +; ArchitecturesInstallIn64BitMode=x64 +DefaultDirName={code:MyGetProgramFiles}\{#MyAppNameEx} + +DefaultGroupName={#MyAppNameEx} +AllowNoIcons=yes +LicenseFile=..\Docs\License.txt +OutputDir=..\Build\KeePass_Distrib +OutputBaseFilename={#MyAppNameShort}-{#KeeVersionStrWithMinorPath}-Setup +Compression=lzma2/ultra +SolidCompression=yes +InternalCompressLevel=ultra +UninstallDisplayIcon={app}\{#MyAppExeName} +AppMutex=KeePassAppMutex,Global\KeePassAppMutexEx +SetupMutex=KeePassSetupMutex2 +ChangesAssociations=yes +VersionInfoVersion={#KeeVersionWin} +VersionInfoCompany={#MyAppPublisher} +VersionInfoDescription={#MyAppName} {#KeeVersionStr} Setup +VersionInfoCopyright=Copyright © {#KeeDevPeriod} {#MyAppPublisher} +SetupIconFile=compiler:SetupClassicIcon.ico +; WizardImageFile=compiler:WizClassicImage-IS.bmp +; WizardSmallImageFile=compiler:WizClassicSmallImage-IS.bmp +WizardStyle=classic +DisableDirPage=auto +AlwaysShowDirOnReadyPage=yes +DisableProgramGroupPage=yes +AlwaysShowGroupOnReadyPage=no + +[Languages] +Name: en; MessagesFile: "compiler:Default.isl" +Name: ca; MessagesFile: "compiler:Languages\Catalan.isl" +Name: cs; MessagesFile: "compiler:Languages\Czech.isl" +Name: da; MessagesFile: "compiler:Languages\Danish.isl" +Name: de; MessagesFile: "compiler:Languages\German.isl" +Name: es; MessagesFile: "compiler:Languages\Spanish.isl" +Name: fi; MessagesFile: "compiler:Languages\Finnish.isl" +Name: fr; MessagesFile: "compiler:Languages\French.isl" +; Name: hu; MessagesFile: "compiler:Languages\Hungarian.isl" +Name: it; MessagesFile: "compiler:Languages\Italian.isl" +Name: ja; MessagesFile: "compiler:Languages\Japanese.isl" +Name: nb; MessagesFile: "compiler:Languages\Norwegian.isl" +Name: nl; MessagesFile: "compiler:Languages\Dutch.isl" +Name: pl; MessagesFile: "compiler:Languages\Polish.isl" +Name: ptBR; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl" +Name: ptPT; MessagesFile: "compiler:Languages\Portuguese.isl" +Name: ru; MessagesFile: "compiler:Languages\Russian.isl" +; Name: sk; MessagesFile: "compiler:Languages\Slovak.isl" +Name: sl; MessagesFile: "compiler:Languages\Slovenian.isl" + +[CustomMessages] +MyCompCore=KeePass core files +MyCompHelp=User manual +MyCompNtvLib=Native support library +MyCompXSL=XSL stylesheets for KDBX XML files +; "KeePass performance optimization" could falsely be interpreted as +; operating system performance optimization carried out by KeePass +MyCompNGen=Optimize KeePass performance +MyCompPreLoad=Optimize KeePass start-up performance +MyStatusNGen=Optimizing KeePass performance... +MyStatusPreLoad=Optimizing KeePass start-up performance... +MyOptPlgPage=Open the plugins web page + +ca.MyCompCore=Fitxers del nucli del KeePass +ca.MyCompHelp=Manual d'usuari +ca.MyCompNtvLib=Biblioteca de suport nativa +ca.MyCompXSL=Fulls d'estil XSL pels fitxers XML del KeePass +ca.MyCompNGen=Optimitza el rendiment del KeePass +ca.MyCompPreLoad=Optimitza l'inici del KeePass +ca.MyStatusNGen=Optimitzant el rendiment del KeePass... +ca.MyStatusPreLoad=Optimitzant l'inici del KeePass... +ca.MyOptPlgPage=Obre el web dels connectors + +da.MyCompCore=KeePass kernefiler +da.MyCompHelp=Brugermanual +da.MyCompNtvLib=Oprindeligt understøttelsesbibliotek +da.MyCompXSL=XSL-stylesheets til KDBX XML-filer +da.MyCompNGen=Optimer KeePass ydeevne +da.MyCompPreLoad=Optimer KeePass opstarts ydeevne +da.MyStatusNGen=Optimerer KeePass ydeevne... +da.MyStatusPreLoad=Optimerer KeePass opstarts ydeevne... +da.MyOptPlgPage=Åbn websiden med plugins + +de.MyCompCore=KeePass-Hauptdateien +de.MyCompHelp=Benutzerhandbuch +de.MyCompNtvLib=Native Unterstützungsbibliothek +de.MyCompXSL=XSL-Stylesheets für KDBX-XML-Dateien +de.MyCompNGen=KeePass-Leistung optimieren +de.MyCompPreLoad=KeePass-Start-Leistung optimieren +de.MyStatusNGen=Optimiere KeePass-Leistung... +de.MyStatusPreLoad=Optimiere KeePass-Start-Leistung... +de.MyOptPlgPage=Die Plugins-Webseite öffnen + +es.MyCompCore=Archivos de instalación de KeePass +es.MyCompHelp=Manual del usuario +es.MyCompNtvLib=Biblioteca para soporte nativo +es.MyCompXSL=Hojas de estilo XSL para los archivos XML de KDBX +es.MyCompNGen=Optimizar el rendimiento de KeePass +es.MyCompPreLoad=Optimizar el rendimiento de inicio de KeePass +es.MyStatusNGen=Optimizando el rendimiento de KeePass... +es.MyStatusPreLoad=Optimizando el rendimiento de inicio de KeePass... +es.MyOptPlgPage=Abrir la página web de los complementos + +fi.MyCompCore=KeePassin ydintiedostot +fi.MyCompHelp=Käyttäjän opas +fi.MyCompNtvLib=Natiivitukikirjasto +fi.MyCompXSL=XSL-tyylarkit KDBX XML-tiedostoja varten +fi.MyCompNGen=KeePassin suorituksen optimointi +fi.MyCompPreLoad=KeePassin käynnistyksen optimointi +fi.MyStatusNGen=Optimoidaan KeePassin suoritusta... +fi.MyStatusPreLoad=Optimoidaan KeePassin käynnistystä... +fi.MyOptPlgPage=Avaa liitännäiset ja laajennukset sisältävä sivusto + +fr.MyCompCore=Fichiers de base KeePass +fr.MyCompHelp=Manuel de l'utilisateur +fr.MyCompNtvLib=Bibliothèque de support native +fr.MyCompXSL=Feuilles de style XSL pour les fichiers KDBX XML +fr.MyCompNGen=Optimiser les performances de KeePass +fr.MyCompPreLoad=Optimiser les performances de démarrage de KeePass +fr.MyStatusNGen=En cours d'optimisation des performances de KeePass... +fr.MyStatusPreLoad=En cours d'optimisation des performances de démarrage de KeePass... +fr.MyOptPlgPage=Ouvre la page des greffons (plugins) sur la toile + +; hu.MyCompCore=KeePass nélkülözhetetlen fájlok +; hu.MyCompHelp=Használati utasítás +; hu.MyCompNtvLib=Natív támogatási könyvtár +; hu.MyCompXSL=XSL stíluslapok a KDBX XML fájlokhoz +; hu.MyCompNGen=Optimalizálja a KeePass teljesítményét +; hu.MyCompPreLoad=Optimalizálja a KeePass indítási teljesítményét +; hu.MyStatusNGen=A KeePass teljesítményének optimalizálása... +; hu.MyStatusPreLoad=A KeePass indítási teljesítményének optimalizálása... +; hu.MyOptPlgPage=Nyissa meg a bővítmények weboldalát + +it.MyCompCore=File core di KeePass +it.MyCompHelp=Manuale utente +it.MyCompNtvLib=Libreria di supporto nativa +it.MyCompXSL=Fogli di stile XSL per i file KDBX XML +it.MyCompNGen=Ottimizza le prestazioni di KeePass +it.MyCompPreLoad=Ottimizza le prestazioni di avvio di KeePass +it.MyStatusNGen=Ottimizzazione delle prestazioni di KeePass... +it.MyStatusPreLoad=Ottimizzazione delle prestazioni di avvio di KeePass... +it.MyOptPlgPage=Apri la pagina web dei plug-in + +ja.MyCompCore=KeePassのコアファイル +ja.MyCompHelp=ユーザーマニュアル +ja.MyCompNtvLib=ネイティブサポートライブラリ +ja.MyCompXSL=KDBXのXMLファイル用XSLスタイルシート +ja.MyCompNGen=KeePassのパフォーマンスを最適化 +ja.MyCompPreLoad=KeePassの起動パフォーマンスを最適化 +ja.MyStatusNGen=KeePassのパフォーマンスを最適化中... +ja.MyStatusPreLoad=KeePassの起動パフォーマンスを最適化中... +ja.MyOptPlgPage=プラグインのWebページを開きます。 + +nl.MyCompCore=KeePass basisbestanden +nl.MyCompHelp=Handleiding +nl.MyCompNtvLib=Standaard bestandsondersteuning +nl.MyCompXSL=XSL stylesheets voor KDBX XML bestanden +nl.MyCompNGen=Optimaliseer KeePass prestaties +nl.MyCompPreLoad=Optimaliseer KeePass opstartprestaties +nl.MyStatusNGen=KeePass prestaties optimaliseren... +nl.MyStatusPreLoad=KeePass opstartprestaties optimaliseren... +nl.MyOptPlgPage=Open de plugins webpagina + +pl.MyCompCore=Główne pliki KeePassa +pl.MyCompHelp=Przewodnik użytkownika +pl.MyCompNtvLib=Wbudowana obsługa dodatkowych funkcji +pl.MyCompXSL=Arkusze stylów XSL dla plików KDBX XML +pl.MyCompNGen=Optymalizuj wydajność KeePassa +pl.MyCompPreLoad=Optymalizuj czas uruchamiania KeePassa +pl.MyStatusNGen=Optymalizowanie wydajności KeePassa... +pl.MyStatusPreLoad=Optymalizowanie czasu uruchamiania KeePassa... +pl.MyOptPlgPage=Otwórz stronę internetową z wtyczkami + +ptBR.MyCompCore=Arquivos principais do KeePass +ptBR.MyCompHelp=Manual do usuário +ptBR.MyCompNtvLib=Biblioteca de suporte nativo +ptBR.MyCompXSL=Folhas de estilo XSL para arquivos XML KDBX +ptBR.MyCompNGen=Otimizar desempenho do KeePass +ptBR.MyCompPreLoad=Otimizar desempenho da inicialização do KeePass +ptBR.MyStatusNGen=Otimizando desempenho do KeePass... +ptBR.MyStatusPreLoad=Otimizando desempenho da inicialização do KeePass... +ptBR.MyOptPlgPage=Abrir página web dos plugins + +ptPT.MyCompCore=Ficheiros principais do KeePass +ptPT.MyCompHelp=Manual do utilizador +ptPT.MyCompNtvLib=Biblioteca de suporte nativo +ptPT.MyCompXSL=Folhas de estilo XSL para ficheiros XML KDBX +ptPT.MyCompNGen=Otimize o desempenho do KeePass +ptPT.MyCompPreLoad=Otimize o desempenho do arranque do KeePass +ptPT.MyStatusNGen=Otimizando o desempenho do KeePass... +ptPT.MyStatusPreLoad=Otimizando o desempenho do arranque do KeePass... +ptPT.MyOptPlgPage=Abrir a página web dos miniaplicativos + +ru.MyCompCore=Основные файлы KeePass +ru.MyCompHelp=Руководство пользователя +ru.MyCompNtvLib=Встроенная библиотека поддержки +ru.MyCompXSL=Таблицы стилей XSL для XML-файлов KDBX +ru.MyCompNGen=Оптимизировать производительность KeePass +ru.MyCompPreLoad=Оптимизировать скорость запуска KeePass +ru.MyStatusNGen=Оптимизация производительности KeePass... +ru.MyStatusPreLoad=Оптимизация скорости запуска KeePass... +ru.MyOptPlgPage=Открыть веб-страницу плагинов + +[Tasks] +Name: FileAssoc; Description: {cm:AssocFileExtension,{#MyAppNameShort},.kdbx} +Name: DesktopIcon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked +Name: QuickLaunchIcon; Description: {cm:CreateQuickLaunchIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked + +[Components] +Name: Core; Description: "{cm:MyCompCore}"; Flags: fixed; Types: full compact custom +Name: UserDoc; Description: "{cm:MyCompHelp}"; Types: full custom +Name: KeePassLibC; Description: "{cm:MyCompNtvLib}"; Types: full custom +; Name: NativeLib; Description: Native Crypto Library (Fast Key Transformations); Types: full custom +Name: XSL; Description: "{cm:MyCompXSL}"; Types: full custom +Name: NGen; Description: "{cm:MyCompNGen}"; Types: full custom; ExtraDiskSpaceRequired: 8388608 +Name: PreLoad; Description: "{cm:MyCompPreLoad}"; Types: full custom; ExtraDiskSpaceRequired: 2048 +; Name: FileAssoc; Description: {cm:AssocFileExtension,{#MyAppNameShort},.kdbx}; Types: full custom + +[Dirs] +Name: "{app}\Languages"; Flags: uninsalwaysuninstall +Name: "{app}\Plugins"; Flags: uninsalwaysuninstall + +[Files] +Source: ..\Build\KeePass_Distrib\KeePass.exe; DestDir: {app}; Flags: ignoreversion; Components: Core +Source: ..\Build\KeePass_Distrib\KeePass.XmlSerializers.dll; DestDir: {app}; Flags: ignoreversion; Components: Core +Source: ..\Build\KeePass_Distrib\KeePass.exe.config; DestDir: {app}; Flags: ignoreversion; Components: Core +Source: ..\Build\KeePass_Distrib\KeePass.config.xml; DestDir: {app}; Flags: ignoreversion; Components: Core +Source: ..\Build\KeePass_Distrib\License.txt; DestDir: {app}; Flags: ignoreversion; Components: Core +Source: ..\Build\KeePass_Distrib\ShInstUtil.exe; DestDir: {app}; Flags: ignoreversion; Components: Core +Source: ..\Build\KeePass_Distrib\KeePass.chm; DestDir: {app}; Flags: ignoreversion; Components: UserDoc +Source: ..\Build\KeePass_Distrib\KeePassLibC32.dll; DestDir: {app}; Flags: ignoreversion; Components: KeePassLibC +Source: ..\Build\KeePass_Distrib\KeePassLibC64.dll; DestDir: {app}; Flags: ignoreversion; Components: KeePassLibC +; Source: ..\Build\KeePass_Distrib\KeePassNtv32.dll; DestDir: {app}; Flags: ignoreversion; Components: NativeLib +; Source: ..\Build\KeePass_Distrib\KeePassNtv64.dll; DestDir: {app}; Flags: ignoreversion; Components: NativeLib +Source: ..\Build\KeePass_Distrib\XSL\KDBX_Common.xsl; DestDir: {app}\XSL; Flags: ignoreversion; Components: XSL +Source: ..\Build\KeePass_Distrib\XSL\KDBX_DetailsFull_HTML.xsl; DestDir: {app}\XSL; Flags: ignoreversion; Components: XSL +Source: ..\Build\KeePass_Distrib\XSL\KDBX_DetailsLight_HTML.xsl; DestDir: {app}\XSL; Flags: ignoreversion; Components: XSL +Source: ..\Build\KeePass_Distrib\XSL\KDBX_PasswordsOnly_TXT.xsl; DestDir: {app}\XSL; Flags: ignoreversion; Components: XSL +Source: ..\Build\KeePass_Distrib\XSL\KDBX_Tabular_HTML.xsl; DestDir: {app}\XSL; Flags: ignoreversion; Components: XSL + +[Registry] +; Always unregister .kdbx association at uninstall +Root: HKCR; Subkey: .kdbx; Flags: uninsdeletekey; Tasks: not FileAssoc +Root: HKCR; Subkey: kdbxfile; Flags: uninsdeletekey; Tasks: not FileAssoc +; Register .kdbx association at install, and unregister at uninstall +Root: HKCR; Subkey: .kdbx; ValueType: string; ValueData: kdbxfile; Flags: uninsdeletekey; Tasks: FileAssoc +Root: HKCR; Subkey: kdbxfile; ValueType: string; ValueData: KeePass Database; Flags: uninsdeletekey; Tasks: FileAssoc +Root: HKCR; Subkey: kdbxfile; ValueType: string; ValueName: AlwaysShowExt; Flags: uninsdeletekey; Tasks: FileAssoc +Root: HKCR; Subkey: kdbxfile\DefaultIcon; ValueType: string; ValueData: """{app}\{#MyAppExeName}"",0"; Flags: uninsdeletekey; Tasks: FileAssoc +Root: HKCR; Subkey: kdbxfile\shell\open; ValueType: string; ValueData: &Open with {#MyAppName}; Flags: uninsdeletekey; Tasks: FileAssoc +Root: HKCR; Subkey: kdbxfile\shell\open\command; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: FileAssoc + +; [INI] +; Filename: {app}\{#MyAppUrlName}; Section: InternetShortcut; Key: URL; String: {#MyAppURL} + +[Icons] +; Name: {group}\{#MyAppName}; Filename: {app}\{#MyAppExeName} +; Name: {group}\{cm:ProgramOnTheWeb,{#MyAppName}}; Filename: {app}\{#MyAppUrlName} +; Name: {group}\Help; Filename: {app}\{#MyAppHelpName}; Components: UserDoc +; Name: {group}\{cm:UninstallProgram,{#MyAppName}}; Filename: {uninstallexe} +Name: {autoprograms}\{#MyAppNameShortEx}; Filename: {app}\{#MyAppExeName} +Name: {userdesktop}\{#MyAppNameShortEx}; Filename: {app}\{#MyAppExeName}; Tasks: DesktopIcon; Check: MyDesktopCheck +Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppNameShortEx}; Filename: {app}\{#MyAppExeName}; Tasks: QuickLaunchIcon; Check: MyAppDataCheck + +[Run] +; Filename: {app}\KeePass.exe; Parameters: -RegisterFileExt; Components: FileAssoc +Filename: {app}\ShInstUtil.exe; Parameters: net_check; WorkingDir: {app}; Flags: skipifdoesntexist skipifsilent +Filename: {app}\ShInstUtil.exe; Parameters: preload_register; WorkingDir: {app}; StatusMsg: "{cm:MyStatusPreLoad}"; Flags: skipifdoesntexist; Components: PreLoad +Filename: {app}\ShInstUtil.exe; Parameters: ngen_install; WorkingDir: {app}; StatusMsg: "{cm:MyStatusNGen}"; Flags: skipifdoesntexist; Components: NGen +Filename: {app}\{#MyAppExeName}; Description: "{cm:LaunchProgram,{#MyAppNameShort}}"; Flags: postinstall nowait skipifsilent +Filename: "https://keepass.info/plugins.html"; Description: "{cm:MyOptPlgPage}"; Flags: postinstall shellexec skipifsilent unchecked + +[UninstallRun] +; Filename: {app}\KeePass.exe; Parameters: -UnregisterFileExt +Filename: {app}\ShInstUtil.exe; Parameters: preload_unregister; WorkingDir: {app}; Flags: skipifdoesntexist; RunOnceId: "PreLoad"; Components: PreLoad +Filename: {app}\ShInstUtil.exe; Parameters: ngen_uninstall; WorkingDir: {app}; Flags: skipifdoesntexist; RunOnceId: "NGen"; Components: NGen + +; Delete old files when upgrading +[InstallDelete] +Name: {app}\{#MyAppUrlName}; Type: files +Name: {app}\XSL\KDBX_DetailsFull.xsl; Type: files +Name: {app}\XSL\KDBX_DetailsLite.xsl; Type: files +Name: {app}\XSL\KDBX_PasswordsOnly.xsl; Type: files +Name: {app}\XSL\KDBX_Styles.css; Type: files +Name: {app}\XSL\KDBX_Tabular.xsl; Type: files +Name: {app}\XSL\TableHeader.gif; Type: files +Name: {group}\{#MyAppName}.lnk; Type: files +Name: {group}\{cm:ProgramOnTheWeb,{#MyAppName}}.lnk; Type: files +Name: {group}\Help.lnk; Type: files +Name: {group}\{cm:UninstallProgram,{#MyAppName}}.lnk; Type: files +Name: {group}; Type: dirifempty +Name: {userdesktop}\{#MyAppName}.lnk; Type: files; Check: MyDesktopCheck +Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}.lnk; Type: files; Check: MyAppDataCheck + +; [UninstallDelete] +; Type: files; Name: {app}\{#MyAppUrlName} + +[Code] +function MyDesktopCheck(): Boolean; +begin + try + ExpandConstant('{userdesktop}'); + Result := True; + except + Result := False; + end; +end; + +function MyAppDataCheck(): Boolean; +begin + try + ExpandConstant('{userappdata}'); + Result := True; + except + Result := False; + end; +end; + +function MyGetProgramFiles(Param: String): String; +begin + if IsWin64() then + Result := ExpandConstant('{autopf64}') + else + Result := ExpandConstant('{autopf}'); +end; diff --git a/src/Ext/KeePassMsi/KeePassMsi.sln b/src/Ext/KeePassMsi/KeePassMsi.sln new file mode 100644 index 0000000..f20a9e2 --- /dev/null +++ b/src/Ext/KeePassMsi/KeePassMsi.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "KeePassMsi", "KeePassMsi.vdproj", "{C4135368-4A84-4924-B5CE-82B18FAADFD4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Default = Debug|Default + Release|Default = Release|Default + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C4135368-4A84-4924-B5CE-82B18FAADFD4}.Debug|Default.ActiveCfg = Debug + {C4135368-4A84-4924-B5CE-82B18FAADFD4}.Debug|Default.Build.0 = Debug + {C4135368-4A84-4924-B5CE-82B18FAADFD4}.Release|Default.ActiveCfg = Release + {C4135368-4A84-4924-B5CE-82B18FAADFD4}.Release|Default.Build.0 = Release + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Ext/KeePassMsi/KeePassMsi.vdproj b/src/Ext/KeePassMsi/KeePassMsi.vdproj new file mode 100644 index 0000000..1be1a38 --- /dev/null +++ b/src/Ext/KeePassMsi/KeePassMsi.vdproj @@ -0,0 +1,1250 @@ +"DeployProject" +{ +"VSVersion" = "3:800" +"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" +"IsWebType" = "8:FALSE" +"ProjectName" = "8:KeePassMsi" +"LanguageId" = "3:1033" +"CodePage" = "3:1252" +"UILanguageId" = "3:1033" +"SccProjectName" = "8:" +"SccLocalPath" = "8:" +"SccAuxPath" = "8:" +"SccProvider" = "8:" + "Hierarchy" + { + "Entry" + { + "MsmKey" = "8:_092CBAA0A0914855A6FDE86CD482FD39" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_1FC6DBE255BB4666BC86F87988C881A0" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_22BA2527C1AC43E5B61F88AA217DF2E2" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_2A0C1DA9803A47F5842BC63F7CC0FEBC" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_442863E39B69D2D0EE0DFF0823AF5611" + "OwnerKey" = "8:_8C05ADB649434D7892E36709EBDED4CC" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_46CD3E3687454981A64BCF41FB207030" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_4F601F0D55964BDF9EF93A6D6B3FFD4F" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_71B4B6B66D7B48478B4C9A237064F77A" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_8C05ADB649434D7892E36709EBDED4CC" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_9473A3E101A1441894F0176A3A583551" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_9BCEB0D341714092A0374B47DA8238DD" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_A13624F7FFFD46FFA9EA3509BBB398FD" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_A2213A2E9D2B46D9ABB41BDE043EB6B1" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_B354F7D87A064AA0BBC71E3926639333" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_C34738027450488E935C153E9FD57296" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_C4F8814F844C43EE8C9F5B662182B11A" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_UNDEFINED" + "OwnerKey" = "8:_8C05ADB649434D7892E36709EBDED4CC" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_UNDEFINED" + "OwnerKey" = "8:_442863E39B69D2D0EE0DFF0823AF5611" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_UNDEFINED" + "OwnerKey" = "8:_C4F8814F844C43EE8C9F5B662182B11A" + "MsmSig" = "8:_UNDEFINED" + } + } + "Configurations" + { + "Debug" + { + "DisplayName" = "8:Debug" + "IsDebugOnly" = "11:TRUE" + "IsReleaseOnly" = "11:FALSE" + "OutputFilename" = "8:..\\..\\Build\\KeePassMsi\\Debug\\KeePass.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:3" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:2" + "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" + { + "Enabled" = "11:FALSE" + "PromptEnabled" = "11:TRUE" + "PrerequisitesLocation" = "2:1" + "Url" = "8:" + "ComponentsUrl" = "8:" + "Items" + { + } + } + } + "Release" + { + "DisplayName" = "8:Release" + "IsDebugOnly" = "11:FALSE" + "IsReleaseOnly" = "11:TRUE" + "OutputFilename" = "8:..\\..\\Build\\KeePassMsi\\Release\\KeePass.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:3" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:2" + "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" + { + "Enabled" = "11:FALSE" + "PromptEnabled" = "11:TRUE" + "PrerequisitesLocation" = "2:1" + "Url" = "8:" + "ComponentsUrl" = "8:" + "Items" + { + } + } + } + } + "Deployable" + { + "CustomAction" + { + } + "DefaultFeature" + { + "Name" = "8:DefaultFeature" + "Title" = "8:" + "Description" = "8:" + } + "ExternalPersistence" + { + "LaunchCondition" + { + "{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_B360A87AC4E743ADA53B9FFAAF1F5346" + { + "Name" = "8:.NET Framework" + "Message" = "8:[VSDNETMSG]" + "FrameworkVersion" = "8:ANY" + "AllowLaterVersions" = "11:FALSE" + "InstallUrl" = "8:http://go.microsoft.com/fwlink/?LinkId=76617" + } + } + } + "File" + { + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_092CBAA0A0914855A6FDE86CD482FD39" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\XSL\\KDBX_Tabular_HTML.xsl" + "TargetName" = "8:KDBX_Tabular_HTML.xsl" + "Tag" = "8:" + "Folder" = "8:_76A04227854C4619BBADCC3E5C2829AE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1FC6DBE255BB4666BC86F87988C881A0" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\XSL\\KDBX_DetailsLight_HTML.xsl" + "TargetName" = "8:KDBX_DetailsLight_HTML.xsl" + "Tag" = "8:" + "Folder" = "8:_76A04227854C4619BBADCC3E5C2829AE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_22BA2527C1AC43E5B61F88AA217DF2E2" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\KeePassLibC32.dll" + "TargetName" = "8:KeePassLibC32.dll" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2A0C1DA9803A47F5842BC63F7CC0FEBC" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\KeePass.chm" + "TargetName" = "8:KeePass.chm" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_442863E39B69D2D0EE0DFF0823AF5611" + { + "AssemblyRegister" = "3:1" + "AssemblyIsInGAC" = "11:FALSE" + "AssemblyAsmDisplayName" = "8:KeePass, Version=2.53.0.18479, Culture=neutral, PublicKeyToken=fed2ed7716aecf5c, processorArchitecture=MSIL" + "ScatterAssemblies" + { + } + "SourcePath" = "8:KeePass.EXE" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:TRUE" + "IsDependency" = "11:TRUE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_46CD3E3687454981A64BCF41FB207030" + { + "SourcePath" = "8:..\\..\\KeePass\\KeePass.ico" + "TargetName" = "8:KeePassIcon.ico" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4F601F0D55964BDF9EF93A6D6B3FFD4F" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\XSL\\KDBX_DetailsFull_HTML.xsl" + "TargetName" = "8:KDBX_DetailsFull_HTML.xsl" + "Tag" = "8:" + "Folder" = "8:_76A04227854C4619BBADCC3E5C2829AE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_71B4B6B66D7B48478B4C9A237064F77A" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\KeePass.exe.config" + "TargetName" = "8:KeePass.exe.config" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_8C05ADB649434D7892E36709EBDED4CC" + { + "AssemblyRegister" = "3:1" + "AssemblyIsInGAC" = "11:FALSE" + "AssemblyAsmDisplayName" = "8:KeePass.XmlSerializers, Version=2.53.0.18479, Culture=neutral, PublicKeyToken=fed2ed7716aecf5c, processorArchitecture=MSIL" + "ScatterAssemblies" + { + "_8C05ADB649434D7892E36709EBDED4CC" + { + "Name" = "8:KeePass.XmlSerializers.dll" + "Attributes" = "3:512" + } + } + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\KeePass.XmlSerializers.dll" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9473A3E101A1441894F0176A3A583551" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\XSL\\KDBX_Common.xsl" + "TargetName" = "8:KDBX_Common.xsl" + "Tag" = "8:" + "Folder" = "8:_76A04227854C4619BBADCC3E5C2829AE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9BCEB0D341714092A0374B47DA8238DD" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\KeePassLibC64.dll" + "TargetName" = "8:KeePassLibC64.dll" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A13624F7FFFD46FFA9EA3509BBB398FD" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\KeePass.config.xml" + "TargetName" = "8:KeePass.config.xml" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A2213A2E9D2B46D9ABB41BDE043EB6B1" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\XSL\\KDBX_PasswordsOnly_TXT.xsl" + "TargetName" = "8:KDBX_PasswordsOnly_TXT.xsl" + "Tag" = "8:" + "Folder" = "8:_76A04227854C4619BBADCC3E5C2829AE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B354F7D87A064AA0BBC71E3926639333" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\ShInstUtil.exe" + "TargetName" = "8:ShInstUtil.exe" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C34738027450488E935C153E9FD57296" + { + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\License.txt" + "TargetName" = "8:License.txt" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_C4F8814F844C43EE8C9F5B662182B11A" + { + "AssemblyRegister" = "3:1" + "AssemblyIsInGAC" = "11:FALSE" + "AssemblyAsmDisplayName" = "8:KeePass, Version=2.53.0.18479, Culture=neutral, PublicKeyToken=fed2ed7716aecf5c, processorArchitecture=MSIL" + "ScatterAssemblies" + { + "_C4F8814F844C43EE8C9F5B662182B11A" + { + "Name" = "8:KeePass.exe" + "Attributes" = "3:512" + } + } + "SourcePath" = "8:..\\..\\Build\\KeePass_Distrib\\KeePass.exe" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + } + "FileType" + { + "{5EB83D71-FA18-4901-BE56-DE22E13CC478}:_7BABCD00223047B785A71DFBB11D9B48" + { + "Name" = "8:KeePass Database" + "Description" = "8:" + "Extensions" = "8:kdbx" + "MIME" = "8:" + "Icon" = "8:_46CD3E3687454981A64BCF41FB207030" + "IconIndex" = "3:0" + "Command" + { + "Command" = "8:_C4F8814F844C43EE8C9F5B662182B11A" + } + "Verbs" + { + "{95C0C507-CBF0-42B8-B119-07219E384A4A}:_33B042E70FCE442EB6C1AD610694DFD5" + { + "Command" = "8:&Open" + "Verb" = "8:open" + "Arguments" = "8:\"%1\"" + "Order" = "3:0" + } + } + } + } + "Folder" + { + "{3C67513D-01DD-4637-8A68-80971EB9504F}:_02F929C52C1D41D29CB593270C6D1DC6" + { + "DefaultLocation" = "8:[ProgramFilesFolder]KeePass2x" + "Name" = "8:#1925" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:TARGETDIR" + "Folders" + { + "{9EF0B969-E518-4E46-987F-47570745A589}:_650CFBE3ACEC49F281DA5C781D164F2B" + { + "Name" = "8:Languages" + "AlwaysCreate" = "11:TRUE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:_A866B7F9250C42C49D83E0C115F4E016" + "Folders" + { + } + } + "{9EF0B969-E518-4E46-987F-47570745A589}:_76A04227854C4619BBADCC3E5C2829AE" + { + "Name" = "8:XSL" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:_04DFBD4168EF4BFD8825BA692441B287" + "Folders" + { + } + } + "{9EF0B969-E518-4E46-987F-47570745A589}:_F7FA774F4B0E4A3FB0F1FA4743CF06C8" + { + "Name" = "8:Plugins" + "AlwaysCreate" = "11:TRUE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:_83A2FA647E5D4F68A9F210FC7878D245" + "Folders" + { + } + } + } + } + "{1525181F-901A-416C-8A58-119130FE478E}:_8285FAA6D5774714AB190FF7FA5604FB" + { + "Name" = "8:#1919" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:ProgramMenuFolder" + "Folders" + { + "{9EF0B969-E518-4E46-987F-47570745A589}:_C5518630440D4460BD3C92160ACB1712" + { + "Name" = "8:KeePass" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:_71CA578B76DC40C6A8B7FBD159CDBC1A" + "Folders" + { + } + } + } + } + "{1525181F-901A-416C-8A58-119130FE478E}:_CD17966DB7404B60877D38C1EE806E5B" + { + "Name" = "8:#1916" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:DesktopFolder" + "Folders" + { + } + } + } + "LaunchCondition" + { + } + "Locator" + { + } + "MsiBootstrapper" + { + "LangId" = "3:1033" + "RequiresElevation" = "11:FALSE" + } + "Product" + { + "Name" = "8:Microsoft Visual Studio" + "ProductName" = "8:KeePass 2.53" + "ProductCode" = "8:{0C1CDCE1-3866-493B-A57F-0183D9BFDD04}" + "PackageCode" = "8:{F3BAC6F8-2A77-49F5-994D-D1CB4E970595}" + "UpgradeCode" = "8:{F2F19898-4F86-4940-9BFA-426574CE03E1}" + "AspNetVersion" = "8:4.0.30319.0" + "RestartWWWService" = "11:FALSE" + "RemovePreviousVersions" = "11:TRUE" + "DetectNewerInstalledVersion" = "11:TRUE" + "InstallAllUsers" = "11:TRUE" + "ProductVersion" = "8:2.53.0" + "Manufacturer" = "8:Dominik Reichl" + "ARPHELPTELEPHONE" = "8:" + "ARPHELPLINK" = "8:https://keepass.info/" + "Title" = "8:KeePass Setup" + "Subject" = "8:KeePass Password Safe" + "ARPCONTACT" = "8:Dominik Reichl" + "Keywords" = "8:" + "ARPCOMMENTS" = "8:" + "ARPURLINFOABOUT" = "8:https://keepass.info/" + "ARPPRODUCTICON" = "8:_46CD3E3687454981A64BCF41FB207030" + "ARPIconIndex" = "3:0" + "SearchPath" = "8:" + "UseSystemSearchPath" = "11:TRUE" + "TargetPlatform" = "3:0" + "PreBuildEvent" = "8:" + "PostBuildEvent" = "8:" + "RunPostBuildEvent" = "3:0" + } + "Registry" + { + "HKLM" + { + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_C5EBC4EA7F4A4F02BD195E1047CD2D03" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_8408784FC07F4908A396060A977864FA" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCU" + { + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_262C9049A6B143369D448CE3C70D8EE5" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_22DFF8BEC1B745DF969ABE72FF0B968A" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCR" + { + "Keys" + { + } + } + "HKU" + { + "Keys" + { + } + } + "HKPU" + { + "Keys" + { + } + } + } + "Sequences" + { + } + "Shortcut" + { + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_B9061F34EC304CA08E34DD695F741D2D" + { + "Name" = "8:KeePass User Manual" + "Arguments" = "8:" + "Description" = "8:" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_2A0C1DA9803A47F5842BC63F7CC0FEBC" + "Folder" = "8:_C5518630440D4460BD3C92160ACB1712" + "WorkingFolder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Icon" = "8:" + "Feature" = "8:" + } + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_D4CD5274BA6C4E25937C7C422285FBCB" + { + "Name" = "8:KeePass" + "Arguments" = "8:" + "Description" = "8:" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_C4F8814F844C43EE8C9F5B662182B11A" + "Folder" = "8:_CD17966DB7404B60877D38C1EE806E5B" + "WorkingFolder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Icon" = "8:_46CD3E3687454981A64BCF41FB207030" + "Feature" = "8:" + } + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_E64C38ED6AED4249B632955704092C33" + { + "Name" = "8:KeePass" + "Arguments" = "8:" + "Description" = "8:" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_C4F8814F844C43EE8C9F5B662182B11A" + "Folder" = "8:_C5518630440D4460BD3C92160ACB1712" + "WorkingFolder" = "8:_02F929C52C1D41D29CB593270C6D1DC6" + "Icon" = "8:_46CD3E3687454981A64BCF41FB207030" + "Feature" = "8:" + } + } + "UserInterface" + { + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_0AEBAAEF47704E8B9A01C6CB1E62FDBD" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdUserInterface.wim" + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_0CDFE41F4D01459286E7AFC52A7A9277" + { + "Name" = "8:#1900" + "Sequence" = "3:1" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_5861FDDB998C4FD1B1873B4342542B84" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "InstallAllUsersVisible" + { + "Name" = "8:InstallAllUsersVisible" + "DisplayName" = "8:#1059" + "Description" = "8:#1159" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_7FC84AF39FDF4EC4BC98AB5AA8A2C381" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8:KeePass: Copyright 2003-2023 Dominik Reichl. The software is distributed under the terms of the GNU General Public License version 2 or later." + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_E3C24FFA9AD74248A8825644371FB17D" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_1F185A5B22D443A8A99D2A777A370EF7" + { + "Name" = "8:#1902" + "Sequence" = "3:1" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_D035303469A14DEB8F3431B84D01CC88" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "UpdateText" + { + "Name" = "8:UpdateText" + "DisplayName" = "8:#1058" + "Description" = "8:#1158" + "Type" = "3:15" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1258" + "DefaultValue" = "8:#1258" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_5BB2AB842E494718822EA43B48741CFF" + { + "Name" = "8:#1900" + "Sequence" = "3:2" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_267559472A6540C0ABEB216DE61BC2ED" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8:KeePass: Copyright 2003-2023 Dominik Reichl. The software is distributed under the terms of the GNU General Public License version 2 or later." + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_60D4F895DECE471F8ED4CDF61AA25B54" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_EDDAA1C6104A4A66917AC39A88839596" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_614D264D47264F6DBD8EB6EA348B4547" + { + "Name" = "8:#1901" + "Sequence" = "3:1" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_0F1ACBA89BC94B0C976878701159E964" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_7FB322B6256147D2948431F3FC326234" + { + "Name" = "8:#1901" + "Sequence" = "3:2" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_92F56F1C382B496EB552FC1054921EA6" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_8033517407B24C178237C0535336BD6A" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdBasicDialogs.wim" + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_867192A49F194B79BD5113B27E970F8F" + { + "Name" = "8:#1902" + "Sequence" = "3:2" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_07EF6E21553142618A6718FD92103A1C" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + } + "MergeModule" + { + } + "ProjectOutput" + { + } + } +} diff --git a/src/Ext/KeePass_NoVer.exe.config b/src/Ext/KeePass_NoVer.exe.config new file mode 100644 index 0000000..cc90b1b --- /dev/null +++ b/src/Ext/KeePass_NoVer.exe.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/Ext/PublicKeys/ArcFourCipher.pk b/src/Ext/PublicKeys/ArcFourCipher.pk new file mode 100644 index 0000000..179dd73 Binary files /dev/null and b/src/Ext/PublicKeys/ArcFourCipher.pk differ diff --git a/src/Ext/PublicKeys/KPScript.pk b/src/Ext/PublicKeys/KPScript.pk new file mode 100644 index 0000000..c67a204 Binary files /dev/null and b/src/Ext/PublicKeys/KPScript.pk differ diff --git a/src/Ext/PublicKeys/KeePass.pk b/src/Ext/PublicKeys/KeePass.pk new file mode 100644 index 0000000..1d25e33 Binary files /dev/null and b/src/Ext/PublicKeys/KeePass.pk differ diff --git a/src/Ext/PublicKeys/KeePassLib.pk b/src/Ext/PublicKeys/KeePassLib.pk new file mode 100644 index 0000000..da07d6c Binary files /dev/null and b/src/Ext/PublicKeys/KeePassLib.pk differ diff --git a/src/Ext/PublicKeys/KeePassLibSD.pk b/src/Ext/PublicKeys/KeePassLibSD.pk new file mode 100644 index 0000000..9c204d4 Binary files /dev/null and b/src/Ext/PublicKeys/KeePassLibSD.pk differ diff --git a/src/Ext/PublicKeys/SamplePlugin.pk b/src/Ext/PublicKeys/SamplePlugin.pk new file mode 100644 index 0000000..9b30be4 Binary files /dev/null and b/src/Ext/PublicKeys/SamplePlugin.pk differ diff --git a/src/Ext/Resources/LockOverlay16.png b/src/Ext/Resources/LockOverlay16.png new file mode 100644 index 0000000..8e6e81b Binary files /dev/null and b/src/Ext/Resources/LockOverlay16.png differ diff --git a/src/Ext/Resources/LockOverlay32.png b/src/Ext/Resources/LockOverlay32.png new file mode 100644 index 0000000..91ce0af Binary files /dev/null and b/src/Ext/Resources/LockOverlay32.png differ diff --git a/src/Ext/TrlUtil.exe.config b/src/Ext/TrlUtil.exe.config new file mode 100644 index 0000000..cc90b1b --- /dev/null +++ b/src/Ext/TrlUtil.exe.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/Ext/XSL/KDBX_Common.xsl b/src/Ext/XSL/KDBX_Common.xsl new file mode 100644 index 0000000..19d87b0 --- /dev/null +++ b/src/Ext/XSL/KDBX_Common.xsl @@ -0,0 +1,111 @@ + + + + + + + + +
+
+ + + ]]> + + ]]> + + + + + ]]> + + + + + + +/* <]]> */ + +]]> + + + + + + + KDBX Common + + +

The KDBX_Common.xsl stylesheet is not supposed to be used directly.

+ + +
+ +
diff --git a/src/Ext/XSL/KDBX_DetailsFull_HTML.xsl b/src/Ext/XSL/KDBX_DetailsFull_HTML.xsl new file mode 100644 index 0000000..f833aaf --- /dev/null +++ b/src/Ext/XSL/KDBX_DetailsFull_HTML.xsl @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:if test="DatabaseName != ''"> + <xsl:value-of select="DatabaseName" /> + </xsl:if> + <xsl:if test="DatabaseName = ''"> + <xsl:text>Database</xsl:text> + </xsl:if> + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + User Name: + + + + Password: + + + + + URL: + + + + + + + + + + + Notes: + + + + + + + + + + : + + + + + + + + + +Creation Time: + + +Last Modification Time: + + + +Expires: + + + + + Never expires + + + +
+ + +
+ +
diff --git a/src/Ext/XSL/KDBX_DetailsLight_HTML.xsl b/src/Ext/XSL/KDBX_DetailsLight_HTML.xsl new file mode 100644 index 0000000..937ba3c --- /dev/null +++ b/src/Ext/XSL/KDBX_DetailsLight_HTML.xsl @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:if test="DatabaseName != ''"> + <xsl:value-of select="DatabaseName" /> + </xsl:if> + <xsl:if test="DatabaseName = ''"> + <xsl:text>Database</xsl:text> + </xsl:if> + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + User Name: + + + + Password: + + + + + URL: + + + + + + + + + + + Notes: + + + + + + + + + + : + + + + + + + + + +
+ + +
+ +
diff --git a/src/Ext/XSL/KDBX_PasswordsOnly_TXT.xsl b/src/Ext/XSL/KDBX_PasswordsOnly_TXT.xsl new file mode 100644 index 0000000..82ec1d7 --- /dev/null +++ b/src/Ext/XSL/KDBX_PasswordsOnly_TXT.xsl @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ext/XSL/KDBX_Tabular_HTML.xsl b/src/Ext/XSL/KDBX_Tabular_HTML.xsl new file mode 100644 index 0000000..b59c233 --- /dev/null +++ b/src/Ext/XSL/KDBX_Tabular_HTML.xsl @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + <xsl:if test="DatabaseName != ''"> + <xsl:value-of select="DatabaseName" /> + </xsl:if> + <xsl:if test="DatabaseName = ''"> + <xsl:text>Database</xsl:text> + </xsl:if> + + + + + + + + +

+ + + + + + + + + + + + +
TitleUser NamePasswordURLNotes
+ + +  

]]>
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/KeePass.sln b/src/KeePass.sln new file mode 100644 index 0000000..c4c0c52 --- /dev/null +++ b/src/KeePass.sln @@ -0,0 +1,61 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib", "KeePassLib\KeePassLib.csproj", "{53573E4E-33CB-4FDB-8698-C95F5E40E7F3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePass", "KeePass\KeePass.csproj", "{10938016-DEE2-4A25-9A5A-8FD3444379CA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrlUtil", "Translation\TrlUtil\TrlUtil.csproj", "{B7E890E7-BF50-4450-9A52-C105BD98651C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Debug|Win32.ActiveCfg = Debug|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Debug|x64.ActiveCfg = Debug|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Release|Any CPU.Build.0 = Release|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Release|Win32.ActiveCfg = Release|Any CPU + {53573E4E-33CB-4FDB-8698-C95F5E40E7F3}.Release|x64.ActiveCfg = Release|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Debug|Win32.ActiveCfg = Debug|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Debug|x64.ActiveCfg = Debug|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Release|Any CPU.Build.0 = Release|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Release|Win32.ActiveCfg = Release|Any CPU + {10938016-DEE2-4A25-9A5A-8FD3444379CA}.Release|x64.ActiveCfg = Release|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Debug|Win32.ActiveCfg = Debug|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Debug|x64.ActiveCfg = Debug|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Release|Any CPU.Build.0 = Release|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Release|Win32.ActiveCfg = Release|Any CPU + {B7E890E7-BF50-4450-9A52-C105BD98651C}.Release|x64.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/KeePass/App/AppDefs.cs b/src/KeePass/App/AppDefs.cs new file mode 100644 index 0000000..4386507 --- /dev/null +++ b/src/KeePass/App/AppDefs.cs @@ -0,0 +1,374 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Windows.Forms; + +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Utility; + +namespace KeePass.App +{ + public static class AppDefs + { + public static readonly Color ColorControlNormal = SystemColors.Window; + public static readonly Color ColorControlDisabled = SystemColors.Control; + public static readonly Color ColorEditError = (UIUtil.IsDarkTheme ? + Color.FromArgb(128, 0, 0) : Color.FromArgb(255, 192, 192)); + + public static readonly Color ColorQualityLow = Color.FromArgb(255, 128, 0); + public static readonly Color ColorQualityHigh = Color.FromArgb(0, 255, 0); + public static readonly Color ColorQualityMid = Color.FromArgb(255, 255, 0); + + public static readonly string LanguagesDir = "Languages"; + + public static readonly string PluginsDir = "Plugins"; + public static readonly string PluginProductName = "KeePass Plugin"; + + public static readonly string XslFilesDir = "XSL"; + public static readonly string XslFileHtmlFull = "KDBX_DetailsFull_HTML.xsl"; + public static readonly string XslFileHtmlLight = "KDBX_DetailsLight_HTML.xsl"; + public static readonly string XslFileHtmlTabular = "KDBX_Tabular_HTML.xsl"; + + public static class FileNames + { + public static readonly string Program = "KeePass.exe"; + public static readonly string XmlSerializers = "KeePass.XmlSerializers.dll"; + + public static readonly string NativeLib32 = "KeePassLibC32.dll"; + public static readonly string NativeLib64 = "KeePassLibC64.dll"; + + public static readonly string ShInstUtil = "ShInstUtil.exe"; + } + + // internal const string MruNameValueSplitter = @"/::/"; + + /// + /// Hot key IDs (used in WM_HOTKEY window messages). + /// + public static class GlobalHotKeyId + { + public static readonly int AutoType = 195; + public static readonly int AutoTypePassword = 197; + public static readonly int AutoTypeSelected = 196; + public static readonly int ShowWindow = 226; + public static readonly int EntryMenu = 227; + + internal const int TempRegTest = 225; + } + + public static class HelpTopics + { + internal const string Default = "index"; + + public static readonly string Acknowledgements = "base/credits"; + public static readonly string License = "v2/license"; + + public static readonly string DatabaseSettings = "v2/dbsettings"; + public static readonly string DbSettingsGeneral = "general"; + public static readonly string DbSettingsSecurity = "security"; + // public static readonly string DbSettingsProtection = "protection"; + public static readonly string DbSettingsCompression = "compression"; + + public static readonly string AutoType = "base/autotype"; + public static readonly string AutoTypeObfuscation = "v2/autotype_obfuscation"; + public static readonly string AutoTypeWindowFilters = "autowindows"; + + public static readonly string Entry = "v2/entry"; + public static readonly string EntryGeneral = "gen"; + public static readonly string EntryStrings = "str"; + public static readonly string EntryAutoType = "at"; + public static readonly string EntryHistory = "hst"; + internal const string EntryAdvanced = "adv"; + internal const string EntryProperties = "prp"; + + public static readonly string KeySources = "base/keys"; + public static readonly string KeySourcesKeyFile = "keyfiles"; + public static readonly string KeySourcesUserAccount = "winuser"; + + public static readonly string PwGenerator = "base/pwgenerator"; + public static readonly string Search = "base/search"; + public static readonly string IOConnections = "v2/ioconnect"; + public static readonly string UrlField = "base/autourl"; + public static readonly string CommandLine = "base/cmdline"; + public static readonly string FieldRefs = "base/fieldrefs"; + + internal const string Placeholders = "base/placeholders"; + internal const string PlaceholdersOtp = "otp"; + + public static readonly string ImportExport = "base/importexport"; + public static readonly string ImportExportGenericCsv = "genericcsv"; + public static readonly string ImportExportSteganos = "imp_steganos"; + public static readonly string ImportExportPassKeeper = "imp_passkeeper"; + internal const string ImportExportParents = "exp_parents"; + + public static readonly string Security = "base/security"; + internal const string SecurityOptEx = "secoptex"; + internal const string SecurityOptAdm = "secoptadm"; + + public static readonly string AppPolicy = "v2/policy"; + + public static readonly string Triggers = "v2/triggers"; + public static readonly string TriggersEvents = "events"; + public static readonly string TriggersConditions = "conditions"; + public static readonly string TriggersActions = "actions"; + + public static readonly string TriggerUIStateUpd = "kb/trigger_uistateupd"; + + public static readonly string Setup = "v2/setup"; + public static readonly string SetupMono = "mono"; + + internal const string FaqTech = "base/faq_tech"; + internal const string FaqTechGuiDark = "guidark"; + internal const string FaqTechGuiFont = "guifont"; + + public static readonly string XmlReplace = "v2/xml_replace"; + + public static readonly string KbFaq = "kb/faq"; + public static readonly string KbFaqURtf = "urtf"; + } + + public static class CommandLineOptions + { + public static readonly string Password = "pw"; + public static readonly string KeyFile = "keyfile"; + public static readonly string UserAccount = "useraccount"; + + public static readonly string PasswordEncrypted = "pw-enc"; + public static readonly string PasswordStdIn = "pw-stdin"; + + public static readonly string PreSelect = "preselect"; + + public static readonly string IoCredUserName = "iousername"; + public static readonly string IoCredPassword = "iopassword"; + public static readonly string IoCredFromRecent = "iocredfromrecent"; + public static readonly string IoCredIsComplete = "ioiscomplete"; + + // User-friendly Pascal-case (shown in UAC dialog) + public static readonly string FileExtRegister = "RegisterFileExt"; + public static readonly string FileExtUnregister = "UnregisterFileExt"; + + public static readonly string PreLoad = "preload"; + // public static readonly string PreLoadRegister = "registerpreload"; + // public static readonly string PreLoadUnregister = "unregisterpreload"; + + public static readonly string ExitAll = "exit-all"; + public static readonly string Minimize = "minimize"; + public static readonly string AutoType = "auto-type"; + public static readonly string AutoTypePassword = "auto-type-password"; + public static readonly string AutoTypeSelected = "auto-type-selected"; + public static readonly string OpenEntryUrl = "entry-url-open"; + public static readonly string LockAll = "lock-all"; + public static readonly string UnlockAll = "unlock-all"; + public static readonly string Cancel = "cancel"; + public static readonly string IpcEvent = "e"; + public static readonly string IpcEvent1 = "e1"; + + public static readonly string Uuid = "uuid"; + public static readonly string Scheme = "scheme"; + public static readonly string Value = "value"; + public static readonly string Activate = "activate"; + + public static readonly string Help = "?"; + public static readonly string HelpLong = "help"; + + public static readonly string WorkaroundDisable = "wa-disable"; + public static readonly string WorkaroundEnable = "wa-enable"; + + public static readonly string ConfigPathLocal = "cfg-local"; + + public static readonly string ConfigSetUrlOverride = "set-urloverride"; + public static readonly string ConfigClearUrlOverride = "clear-urloverride"; + public static readonly string ConfigGetUrlOverride = "get-urloverride"; + public static readonly string ConfigAddUrlOverride = "add-urloverride"; + public static readonly string ConfigRemoveUrlOverride = "remove-urloverride"; + + public static readonly string ConfigSetLanguageFile = "set-languagefile"; + + public static readonly string PlgxCreate = "plgx-create"; + public static readonly string PlgxCreateInfo = "plgx-create-info"; + public static readonly string PlgxPrereqKP = "plgx-prereq-kp"; + public static readonly string PlgxPrereqNet = "plgx-prereq-net"; + public static readonly string PlgxPrereqOS = "plgx-prereq-os"; + public static readonly string PlgxPrereqPtr = "plgx-prereq-ptr"; + public static readonly string PlgxBuildPre = "plgx-build-pre"; + public static readonly string PlgxBuildPost = "plgx-build-post"; + + public static readonly string Debug = "debug"; + public static readonly string DebugThrowException = "debug-throwexcp"; + // public static readonly string SavePluginCompileRes = "saveplgxcr"; // Now: Debug + public static readonly string ShowAssemblyInfo = "showasminfo"; + public static readonly string MakeXmlSerializerEx = "makexmlserializerex"; + public static readonly string MakeXspFile = "makexspfile"; + +#if DEBUG + public static readonly string TestGfx = "testgfx"; +#endif + + public static readonly string Version = "version"; // For Unix + + // #if (DEBUG && !KeePassLibSD) + // public static readonly string MakePopularPasswordTable = "makepopularpasswordtable"; + // #endif + } + + public static class FileExtension + { + public static readonly string FileExt = "kdbx"; + public static readonly string FileExtId = "kdbxfile"; + + public static readonly string KeyFile = "keyx"; + internal const string KeyFileAlt = "key"; + } + + public static readonly string AutoRunName = "KeePass Password Safe 2"; + public static readonly string PreLoadName = "KeePass 2 PreLoad"; + + public static readonly string MutexName = "KeePassAppMutex"; + public static readonly string MutexNameGlobal = "KeePassAppMutexEx"; + + // public static readonly string ScriptExtension = "kps"; + + public static readonly int InvalidWindowValue = -16381; + + public static class NamedEntryColor + { + public static readonly Color LightRed = Color.FromArgb(255, 204, 204); + public static readonly Color LightGreen = Color.FromArgb(204, 255, 204); + public static readonly Color LightBlue = Color.FromArgb(153, 204, 255); + public static readonly Color LightYellow = Color.FromArgb(255, 255, 153); + } + + public static class FileDialogContext + { + // Values must not contain '@' + + public static readonly string Database = "Database"; + public static readonly string Sync = "Sync"; + public static readonly string KeyFile = "KeyFile"; + public static readonly string Import = "Import"; + public static readonly string Export = "Export"; + public static readonly string Attachments = "Attachments"; + public static readonly string Xsl = "Xsl"; + } + + public static readonly string DefaultTrlAuthor = "Dominik Reichl"; + public static readonly string DefaultTrlContact = "https://www.dominik-reichl.de/"; + + // public static readonly string LanguageInfoFileName = "LanguageInfo.xml"; + + internal const string Rsa4096PublicKeyXml = + @"9Oa8Bb9if4rSYBxczLVQ3Yyae95dWQrNJ1FlqS7DoF" + + @"RF80tD2hq84vxDE8slVeSHs68KMFnJhPsXFD6nM9oTRBaUlU/alnRTUU+X/cUXbr" + + @"mhYN9DkJhM0OcWk5Vsl9Qxl613sA+hqIwmPc+el/fCM/1vP6JkHo/JTJ2OxQvDKN" + + @"4cC55pHYMZt+HX6AhemsPe7ejTG7l9nN5tHGmD+GrlwuxBTddzFBARmoknFzDPWd" + + @"QHddjuK1mXDs6lWeu73ODlSLSHMc5n0R2xMwGHN4eaiIMGzEbt0lv1aMWz+Iy1H3" + + @"XgFgWGDHX9kx8yefmfcgFIK4Y/xHU5EyGAV68ZHPatv6i4pT4ZuecIb5GSoFzVXq" + + @"8BZjbe+zDI+Wr1u8jLcBH0mySTWkF2gooQLvE1vgZXP1blsA7UFZSVFzYjBt36HQ" + + @"SJLpQ9AjjB5MKpMSlvdb5SnvjzREiFVLoBsY7KH2TMz+IG1Rh3OZTGwjQKXkgRVj" + + @"5XrEMTFRmT1zo2BHWhx8vrY6agVzqsCVqxYRbjeAhgOi6hLDMHSNAVuNg6ZHOKS8" + + @"6x6kmBcBhGJriwY017H3Oxuhfz33ehRFX/C05egCvmR2TAXbqm+CUgrq1bZ96T/y" + + @"s+O5uvKpe7H+EZuWb655Y9WuQSby+q0Vqqny7T6Z2NbEnI8nYHg5ZZP+TijSxeH0" + + @"8=AQAB"; + + public static readonly string ColumnIdnGroup = "Group"; + public static readonly string ColumnIdnCreationTime = "CreationTime"; + public static readonly string ColumnIdnLastModificationTime = "LastModificationTime"; + public static readonly string ColumnIdnLastAccessTime = "LastAccessTime"; + public static readonly string ColumnIdnExpiryTime = "ExpiryTime"; + public static readonly string ColumnIdnUuid = "UUID"; + public static readonly string ColumnIdnAttachment = "Attachment"; + + public static string GetEntryField(PwEntry pe, string strFieldId) + { + if(pe == null) throw new ArgumentNullException("pe"); + if(strFieldId == null) throw new ArgumentNullException("strFieldId"); + + if(strFieldId == AppDefs.ColumnIdnGroup) + return ((pe.ParentGroup != null) ? pe.ParentGroup.Name : string.Empty); + else if(strFieldId == AppDefs.ColumnIdnCreationTime) + return TimeUtil.ToDisplayString(pe.CreationTime); + else if(strFieldId == AppDefs.ColumnIdnLastModificationTime) + return TimeUtil.ToDisplayString(pe.LastModificationTime); + else if(strFieldId == AppDefs.ColumnIdnLastAccessTime) + return TimeUtil.ToDisplayString(pe.LastAccessTime); + else if(strFieldId == AppDefs.ColumnIdnExpiryTime) + { + if(!pe.Expires) return KPRes.NeverExpires; + return TimeUtil.ToDisplayString(pe.ExpiryTime); + } + else if(strFieldId == AppDefs.ColumnIdnUuid) + return pe.Uuid.ToHexString(); + else if(strFieldId == AppDefs.ColumnIdnAttachment) + return pe.Binaries.UCount.ToString(); + + return pe.Strings.ReadSafe(strFieldId); + } + + internal static Color GetQualityColor(float fQ, bool bToControlBack) + { + if(fQ < 0.0f) { Debug.Assert(false); fQ = 0.0f; } + if(fQ > 1.0f) { Debug.Assert(false); fQ = 1.0f; } + + Color clrL = AppDefs.ColorQualityLow; + Color clrH = AppDefs.ColorQualityHigh; + Color clrM = AppDefs.ColorQualityMid; + + int iR, iG, iB; + if(fQ <= 0.5f) + { + fQ *= 2.0f; + iR = clrL.R + (int)(fQ * ((int)clrM.R - (int)clrL.R)); + iG = clrL.G + (int)(fQ * ((int)clrM.G - (int)clrL.G)); + iB = clrL.B + (int)(fQ * ((int)clrM.B - (int)clrL.B)); + } + else + { + fQ = (fQ - 0.5f) * 2.0f; + iR = clrM.R + (int)(fQ * ((int)clrH.R - (int)clrM.R)); + iG = clrM.G + (int)(fQ * ((int)clrH.G - (int)clrM.G)); + iB = clrM.B + (int)(fQ * ((int)clrH.B - (int)clrM.B)); + } + + if(iR < 0) { Debug.Assert(false); iR = 0; } + if(iR > 255) { Debug.Assert(false); iR = 255; } + if(iG < 0) { Debug.Assert(false); iG = 0; } + if(iG > 255) { Debug.Assert(false); iG = 255; } + if(iB < 0) { Debug.Assert(false); iB = 0; } + if(iB > 255) { Debug.Assert(false); iB = 255; } + + Color clrQ = Color.FromArgb(iR, iG, iB); + if(bToControlBack) + return UIUtil.ColorTowards(clrQ, AppDefs.ColorControlNormal, 0.5); + return clrQ; + } + + internal static string GetKeyFileFilter() + { + return UIUtil.CreateFileTypeFilter(AppDefs.FileExtension.KeyFile + + "|" + AppDefs.FileExtension.KeyFileAlt, KPRes.KeyFiles, true); + } + } +} diff --git a/src/KeePass/App/AppHelp.cs b/src/KeePass/App/AppHelp.cs new file mode 100644 index 0000000..ed34a0a --- /dev/null +++ b/src/KeePass/App/AppHelp.cs @@ -0,0 +1,257 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Util; +using KeePass.Util.Spr; + +using KeePassLib; +using KeePassLib.Native; +using KeePassLib.Utility; + +namespace KeePass.App +{ + public enum AppHelpSource + { + Local, + Online + } + + /// + /// Application help provider. Starts an external application that + /// shows help on a specified topic. + /// + public static class AppHelp + { + private static string g_strLocalHelpFile = null; + + /// + /// Get the path of the local help file. + /// + public static string LocalHelpFile + { + get + { + if(g_strLocalHelpFile == null) + g_strLocalHelpFile = UrlUtil.StripExtension( + WinUtil.GetExecutable()) + ".chm"; + + return g_strLocalHelpFile; + } + } + + public static bool LocalHelpAvailable + { + get + { + try + { + string strFile = AppHelp.LocalHelpFile; + if(!string.IsNullOrEmpty(strFile)) + return File.Exists(strFile); + } + catch(Exception) { Debug.Assert(false); } + + return false; + } + } + + public static AppHelpSource PreferredHelpSource + { + get + { + return (Program.Config.Application.HelpUseLocal ? + AppHelpSource.Local : AppHelpSource.Online); + } + + set + { + Program.Config.Application.HelpUseLocal = + (value == AppHelpSource.Local); + } + } + + /// + /// Show a help page. + /// + /// Topic name. May be null. + /// Section name. May be null. Must not start + /// with the '#' character. + public static void ShowHelp(string strTopic, string strSection) + { + AppHelp.ShowHelp(strTopic, strSection, false); + } + + /// + /// Show a help page. + /// + /// Topic name. May be null. + /// Section name. May be null. + /// Must not start with the '#' character. + /// Specify if the local help file should be + /// preferred. If no local help file is available, the online help + /// system will be used, independent of the bPreferLocal flag. + public static void ShowHelp(string strTopic, string strSection, bool bPreferLocal) + { + if(ShowHelpOverride(strTopic, strSection)) return; + + if(AppHelp.LocalHelpAvailable) + { + if(bPreferLocal || (AppHelp.PreferredHelpSource == AppHelpSource.Local)) + ShowHelpLocal(strTopic, strSection); + else + ShowHelpOnline(strTopic, strSection); + } + else ShowHelpOnline(strTopic, strSection); + } + + private static void ShowHelpLocal(string strTopic, string strSection) + { + string strFile = AppHelp.LocalHelpFile; + if(string.IsNullOrEmpty(strFile)) { Debug.Assert(false); return; } + + // Unblock CHM file for proper display of help contents + WinUtil.RemoveZoneIdentifier(strFile); + + string strCmd = "\"ms-its:" + strFile; + if(!string.IsNullOrEmpty(strTopic)) + { + strCmd += "::/help/" + strTopic + ".html"; + + if(!string.IsNullOrEmpty(strSection)) + strCmd += "#" + strSection; + } + strCmd += "\""; + + if(ShowHelpLocalKcv(strCmd)) return; + + string strDisp = strCmd; + try + { + if(NativeLib.IsUnix()) + NativeLib.StartProcess(strCmd.Trim('\"')); + else // Windows + { + strDisp = "HH.exe " + strDisp; + NativeLib.StartProcess(WinUtil.LocateSystemApp( + "hh.exe"), strCmd); + } + } + catch(Exception ex) + { + MessageService.ShowWarning(strDisp, ex); + } + } + + private static bool ShowHelpLocalKcv(string strQuotedMsIts) + { + try + { + if(!NativeLib.IsUnix()) return false; + + string strApp = AppLocator.FindAppUnix("kchmviewer"); + if(string.IsNullOrEmpty(strApp)) return false; + + string strFile = StrUtil.GetStringBetween(strQuotedMsIts, 0, ":", "::"); + if(string.IsNullOrEmpty(strFile)) + strFile = StrUtil.GetStringBetween(strQuotedMsIts, 0, ":", "\""); + if(string.IsNullOrEmpty(strFile)) + { + Debug.Assert(false); + return false; + } + + string strUrl = StrUtil.GetStringBetween(strQuotedMsIts, 0, "::", "\""); + + // https://www.ulduzsoft.com/linux/kchmviewer/kchmviewer-integration-reference/ + string strArgs = "\"" + SprEncoding.EncodeForCommandLine(strFile) + "\""; + if(!string.IsNullOrEmpty(strUrl)) + strArgs = "-showPage \"" + SprEncoding.EncodeForCommandLine( + strUrl) + "\" " + strArgs; + + NativeLib.StartProcess(strApp, strArgs); + return true; + } + catch(Exception) { Debug.Assert(false); } + + return false; + } + + private static void ShowHelpOnline(string strTopic, string strSection) + { + string strUrl = GetOnlineUrl(strTopic, strSection); + WinUtil.OpenUrl(strUrl, null); + } + + private static bool ShowHelpOverride(string strTopic, string strSection) + { + string strUrl = Program.Config.Application.HelpUrl; + if(string.IsNullOrEmpty(strUrl)) return false; + + string strRel = GetRelativeUrl(strTopic, strSection); + + WinUtil.OpenUrl(strUrl, null, true, strRel); + return true; + } + + private static string GetRelativeUrl(string strTopic, string strSection) + { + StringBuilder sb = new StringBuilder(); + + const string strDefault = AppDefs.HelpTopics.Default; + sb.Append(string.IsNullOrEmpty(strTopic) ? strDefault : strTopic); + sb.Append(".html"); + + if(!string.IsNullOrEmpty(strSection)) + { + sb.Append('#'); + sb.Append(strSection); + } + + return sb.ToString(); + } + + internal static string GetOnlineUrl(string strTopic, string strSection) + { + return (PwDefs.HelpUrl + GetRelativeUrl(strTopic, strSection)); + } + + // internal static void SetHelp(Form f, string strTopic, string strSection) + // { + // if(f == null) { Debug.Assert(false); return; } + // Debug.Assert(!f.HelpButton); + // f.HelpButton = true; + // SetHelp((Control)f, strTopic, strSection); + // } + // internal static void SetHelp(Control c, string strTopic, string strSection) + // { + // if(c == null) { Debug.Assert(false); return; } + // c.HelpRequested += delegate(object sender, HelpEventArgs e) + // { + // if(e == null) { Debug.Assert(false); return; } + // e.Handled = true; + // AppHelp.ShowHelp(strTopic, strSection); + // }; + // } + } +} diff --git a/src/KeePass/App/AppIcons.cs b/src/KeePass/App/AppIcons.cs new file mode 100644 index 0000000..5c0bd02 --- /dev/null +++ b/src/KeePass/App/AppIcons.cs @@ -0,0 +1,166 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.Text; + +using KeePass.UI; + +namespace KeePass.App +{ + public enum AppIconType + { + None = 0, + Main, + QuadNormal, + QuadLocked + } + + public static class AppIcons + { + private static Dictionary g_dCache = new Dictionary(); + private static readonly object g_oCacheSync = new object(); + + private const int g_hMain = 225; // Average hue of the main icon in degrees + private static readonly Color g_clrMain = UIUtil.ColorFromHsv(g_hMain, 1, 1); + + private static Color[] g_vColors = null; + internal static Color[] Colors + { + get + { + if(g_vColors == null) + { + List l = new List(); + + for(int h = 0; h < 360; h += 15) + l.Add(UIUtil.ColorFromHsv((h + g_hMain) % 360, 1, 1)); + + g_vColors = l.ToArray(); + +#if DEBUG + Color[] vInvariant = new Color[] { g_clrMain, + Color.Red, Color.Lime, Color.Blue, Color.Yellow }; + foreach(Color clr in vInvariant) + { + Debug.Assert(UIUtil.ColorsEqual(RoundColor(clr), clr)); + } +#endif + } + + return g_vColors; + } + } + + public static Icon Default + { + get { return Get(AppIconType.Main, Size.Empty, Color.Empty); } + } + + public static Icon Get(AppIconType t, Size sz, Color clr) + { + int w = Math.Min(Math.Max(sz.Width, 0), 256); + int h = Math.Min(Math.Max(sz.Height, 0), 256); + if((w == 0) || (h == 0)) + { + Size szDefault = UIUtil.GetIconSize(); + w = szDefault.Width; + h = szDefault.Height; + } + + Color c = clr; + if(!UIUtil.ColorsEqual(c, Color.Empty)) c = RoundColor(c); + + NumberFormatInfo nf = NumberFormatInfo.InvariantInfo; + string strID = ((long)t).ToString(nf) + ":" + w.ToString(nf) + ":" + + h.ToString(nf) + ":" + c.ToArgb().ToString(nf); + + Icon ico = null; + lock(g_oCacheSync) + { + if(g_dCache.TryGetValue(strID, out ico)) return ico; + } + + if(t == AppIconType.Main) + ico = Properties.Resources.KeePass; + else if(t == AppIconType.QuadNormal) + ico = Properties.Resources.QuadNormal; + else if(t == AppIconType.QuadLocked) + { + ico = Properties.Resources.QuadLocked; + + Debug.Assert(UIUtil.ColorsEqual(c, Color.Empty)); + c = Color.Empty; // This icon should not be recolored + } + else { Debug.Assert(false); } + + if((ico != null) && !UIUtil.ColorsEqual(c, Color.Empty)) + ico = IconColorizer.Recolor(ico, c); + + // Select requested resolution + if(ico != null) ico = new Icon(ico, w, h); // Preserves icon data + + Debug.Assert(ico != null); + lock(g_oCacheSync) { g_dCache[strID] = ico; } + return ico; + } + + private static int ColorDist(Color c1, Color c2) + { + int dR = (int)c1.R - (int)c2.R; + int dG = (int)c1.G - (int)c2.G; + int dB = (int)c1.B - (int)c2.B; + return ((dR * dR) + (dG * dG) + (dB * dB)); + } + + /// + /// Round to the nearest supported color. + /// + public static Color RoundColor(Color clr) + { + Debug.Assert(!UIUtil.ColorsEqual(clr, Color.Empty)); + if((clr.R == clr.B) && (clr.G == clr.B)) + return g_clrMain; // Gray => default + + Color[] v = AppIcons.Colors; + + int c = clr.ToArgb(); + for(int i = 0; i < v.Length; ++i) + { + if(v[i].ToArgb() == c) return clr; + } + + int iMin = 0, dMin = int.MaxValue; + for(int i = 0; i < v.Length; ++i) + { + int d = ColorDist(clr, v[i]); + if(d < dMin) + { + iMin = i; + dMin = d; + } + } + return v[iMin]; + } + } +} diff --git a/src/KeePass/App/AppPolicy.cs b/src/KeePass/App/AppPolicy.cs new file mode 100644 index 0000000..2e28c07 --- /dev/null +++ b/src/KeePass/App/AppPolicy.cs @@ -0,0 +1,429 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Text; +using System.Windows.Forms; + +using KeePass.App.Configuration; +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Utility; + +namespace KeePass.App +{ + /// + /// Application policy IDs. + /// + public enum AppPolicyId + { + Plugins = 0, + Export, + ExportNoKey, // Don't require the current key to be repeated + Import, + Print, + PrintNoKey, // Don't require the current key to be repeated + NewFile, + SaveFile, + AutoType, + AutoTypeWithoutContext, + CopyToClipboard, + CopyWholeEntries, + DragDrop, + UnhidePasswords, + ChangeMasterKey, + ChangeMasterKeyNoKey, // Don't require the current key to be repeated + EditTriggers + } + + /// + /// Application policy flags. + /// + public sealed class AppPolicyFlags + { + private bool m_bPlugins = true; + [DefaultValue(true)] + public bool Plugins + { + get { return m_bPlugins; } + set { m_bPlugins = value; } + } + + private bool m_bExport = true; + [DefaultValue(true)] + public bool Export + { + get { return m_bExport; } + set { m_bExport = value; } + } + + private bool m_bExportNoKey = true; + [DefaultValue(true)] + public bool ExportNoKey + { + get { return m_bExportNoKey; } + set { m_bExportNoKey = value; } + } + + private bool m_bImport = true; + [DefaultValue(true)] + public bool Import + { + get { return m_bImport; } + set { m_bImport = value; } + } + + private bool m_bPrint = true; + [DefaultValue(true)] + public bool Print + { + get { return m_bPrint; } + set { m_bPrint = value; } + } + + private bool m_bPrintNoKey = true; + [DefaultValue(true)] + public bool PrintNoKey + { + get { return m_bPrintNoKey; } + set { m_bPrintNoKey = value; } + } + + private bool m_bNewFile = true; + [DefaultValue(true)] + public bool NewFile + { + get { return m_bNewFile; } + set { m_bNewFile = value; } + } + + private bool m_bSave = true; + [DefaultValue(true)] + public bool SaveFile + { + get { return m_bSave; } + set { m_bSave = value; } + } + + private bool m_bAutoType = true; + [DefaultValue(true)] + public bool AutoType + { + get { return m_bAutoType; } + set { m_bAutoType = value; } + } + + private bool m_bAutoTypeWithoutContext = true; + [DefaultValue(true)] + public bool AutoTypeWithoutContext + { + get { return m_bAutoTypeWithoutContext; } + set { m_bAutoTypeWithoutContext = value; } + } + + private bool m_bClipboard = true; + [DefaultValue(true)] + public bool CopyToClipboard + { + get { return m_bClipboard; } + set { m_bClipboard = value; } + } + + private bool m_bCopyWholeEntries = true; + [DefaultValue(true)] + public bool CopyWholeEntries + { + get { return m_bCopyWholeEntries; } + set { m_bCopyWholeEntries = value; } + } + + private bool m_bDragDrop = true; + [DefaultValue(true)] + public bool DragDrop + { + get { return m_bDragDrop; } + set { m_bDragDrop = value; } + } + + private bool m_bUnhidePasswords = true; + [DefaultValue(true)] + public bool UnhidePasswords + { + get { return m_bUnhidePasswords; } + set { m_bUnhidePasswords = value; } + } + + private bool m_bChangeMasterKey = true; + [DefaultValue(true)] + public bool ChangeMasterKey + { + get { return m_bChangeMasterKey; } + set { m_bChangeMasterKey = value; } + } + + private bool m_bChangeMasterKeyNoKey = true; + [DefaultValue(true)] + public bool ChangeMasterKeyNoKey + { + get { return m_bChangeMasterKeyNoKey; } + set { m_bChangeMasterKeyNoKey = value; } + } + + private bool m_bTriggersEdit = true; + [DefaultValue(true)] + public bool EditTriggers + { + get { return m_bTriggersEdit; } + set { m_bTriggersEdit = value; } + } + + public AppPolicyFlags CloneDeep() + { + return (AppPolicyFlags)this.MemberwiseClone(); + } + } + + /// + /// Application policy settings. + /// + public static class AppPolicy + { + private static AppPolicyFlags m_apfCurrent = new AppPolicyFlags(); + // private static AppPolicyFlags m_apfNew = new AppPolicyFlags(); + + public static AppPolicyFlags Current + { + get { return m_apfCurrent; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_apfCurrent = value; + } + } + + /* public static AppPolicyFlags New + { + get { return m_apfNew; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_apfNew = value; + } + } */ + + internal static string GetName(AppPolicyId p) + { + string str; + + switch(p) + { + case AppPolicyId.Plugins: + str = KPRes.Plugins; + break; + case AppPolicyId.Export: + str = KPRes.Export; + break; + case AppPolicyId.ExportNoKey: + str = KPRes.Export + " - " + KPRes.NoKeyRepeat; + break; + case AppPolicyId.Import: + str = KPRes.Import; + break; + case AppPolicyId.Print: + str = KPRes.Print; + break; + case AppPolicyId.PrintNoKey: + str = KPRes.Print + " - " + KPRes.NoKeyRepeat; + break; + case AppPolicyId.NewFile: + str = KPRes.NewDatabase; + break; + case AppPolicyId.SaveFile: + str = KPRes.SaveDatabase; + break; + case AppPolicyId.AutoType: + str = KPRes.AutoType; + break; + case AppPolicyId.AutoTypeWithoutContext: + str = KPRes.AutoType + " - " + KPRes.WithoutContext; + break; + case AppPolicyId.CopyToClipboard: + str = KPRes.Copy; + break; + case AppPolicyId.CopyWholeEntries: + str = KPRes.CopyWholeEntries; + break; + case AppPolicyId.DragDrop: + str = KPRes.DragDrop; + break; + case AppPolicyId.UnhidePasswords: + str = KPRes.UnhidePasswords; + break; + case AppPolicyId.ChangeMasterKey: + str = KPRes.ChangeMasterKey; + break; + case AppPolicyId.ChangeMasterKeyNoKey: + str = KPRes.ChangeMasterKey + " - " + KPRes.NoKeyRepeat; + break; + case AppPolicyId.EditTriggers: + str = KPRes.TriggersEdit; + break; + default: + Debug.Assert(false); + str = KPRes.Unknown; + break; + } + + return str; + } + + internal static string GetDesc(AppPolicyId p) + { + string str; + + switch(p) + { + case AppPolicyId.Plugins: + str = KPRes.PolicyPluginsDesc; + break; + case AppPolicyId.Export: + str = KPRes.PolicyExportDesc2; + break; + case AppPolicyId.ExportNoKey: + str = KPRes.PolicyExportNoKeyDesc; + break; + case AppPolicyId.Import: + str = KPRes.PolicyImportDesc; + break; + case AppPolicyId.Print: + str = KPRes.PolicyPrintDesc; + break; + case AppPolicyId.PrintNoKey: + str = KPRes.PolicyPrintNoKeyDesc; + break; + case AppPolicyId.NewFile: + str = KPRes.PolicyNewDatabaseDesc; + break; + case AppPolicyId.SaveFile: + str = KPRes.PolicySaveDatabaseDesc; + break; + case AppPolicyId.AutoType: + str = KPRes.PolicyAutoTypeDesc; + break; + case AppPolicyId.AutoTypeWithoutContext: + str = KPRes.PolicyAutoTypeWithoutContextDesc; + break; + case AppPolicyId.CopyToClipboard: + str = KPRes.PolicyClipboardDesc; + break; + case AppPolicyId.CopyWholeEntries: + str = KPRes.PolicyCopyWholeEntriesDesc; + break; + case AppPolicyId.DragDrop: + str = KPRes.PolicyDragDropDesc; + break; + case AppPolicyId.UnhidePasswords: + str = KPRes.UnhidePasswordsDesc; + break; + case AppPolicyId.ChangeMasterKey: + str = KPRes.PolicyChangeMasterKey; + break; + case AppPolicyId.ChangeMasterKeyNoKey: + str = KPRes.PolicyChangeMasterKeyNoKeyDesc; + break; + case AppPolicyId.EditTriggers: + str = KPRes.PolicyTriggersEditDesc; + break; + default: + Debug.Assert(false); + str = KPRes.Unknown + "."; + break; + } + + return str; + } + + public static string RequiredPolicyMessage(AppPolicyId p) + { + return (KPRes.PolicyDisallowed + MessageService.NewParagraph + + KPRes.PolicyRequiredFlag + ":" + MessageService.NewLine + + AppPolicy.GetName(p) + "."); + } + + public static bool Try(AppPolicyId p) + { + bool b = true; + + switch(p) + { + case AppPolicyId.Plugins: b = m_apfCurrent.Plugins; break; + case AppPolicyId.Export: b = m_apfCurrent.Export; break; + case AppPolicyId.ExportNoKey: b = m_apfCurrent.ExportNoKey; break; + case AppPolicyId.Import: b = m_apfCurrent.Import; break; + case AppPolicyId.Print: b = m_apfCurrent.Print; break; + case AppPolicyId.PrintNoKey: b = m_apfCurrent.PrintNoKey; break; + case AppPolicyId.NewFile: b = m_apfCurrent.NewFile; break; + case AppPolicyId.SaveFile: b = m_apfCurrent.SaveFile; break; + case AppPolicyId.AutoType: b = m_apfCurrent.AutoType; break; + case AppPolicyId.AutoTypeWithoutContext: b = m_apfCurrent.AutoTypeWithoutContext; break; + case AppPolicyId.CopyToClipboard: b = m_apfCurrent.CopyToClipboard; break; + case AppPolicyId.CopyWholeEntries: b = m_apfCurrent.CopyWholeEntries; break; + case AppPolicyId.DragDrop: b = m_apfCurrent.DragDrop; break; + case AppPolicyId.UnhidePasswords: b = m_apfCurrent.UnhidePasswords; break; + case AppPolicyId.ChangeMasterKey: b = m_apfCurrent.ChangeMasterKey; break; + case AppPolicyId.ChangeMasterKeyNoKey: b = m_apfCurrent.ChangeMasterKeyNoKey; break; + case AppPolicyId.EditTriggers: b = m_apfCurrent.EditTriggers; break; + default: Debug.Assert(false); break; + } + + if(!b) + { + string strMsg = RequiredPolicyMessage(p); + MessageService.ShowWarning(strMsg); + } + + return b; + } + + internal static void ApplyToConfig() + { + try + { + AppConfigEx cfg = Program.Config; + + if(!AppPolicy.Current.UnhidePasswords) + { + List l = cfg.MainWindow.EntryListColumns; + foreach(AceColumn c in l) + { + if(c == null) { Debug.Assert(false); continue; } + + if(c.Type == AceColumnType.Password) + c.HideWithAsterisks = true; + } + } + } + catch(Exception) { Debug.Assert(false); } + } + } +} diff --git a/src/KeePass/App/Configuration/AceApplication.cs b/src/KeePass/App/Configuration/AceApplication.cs new file mode 100644 index 0000000..2dde40a --- /dev/null +++ b/src/KeePass/App/Configuration/AceApplication.cs @@ -0,0 +1,564 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Text; +using System.Xml.Serialization; + +using KeePass.Ecas; +using KeePass.Util; + +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.App.Configuration +{ + public sealed class AceApplication + { + public AceApplication() + { + } + + private bool m_bConfigSave = true; + [DefaultValue(true)] + public bool ConfigSave + { + get { return m_bConfigSave; } + set { m_bConfigSave = value; } + } + + private string m_strLanguageFile = string.Empty; // = English + [DefaultValue("")] + public string LanguageFile + { + get { return m_strLanguageFile; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strLanguageFile = value; + } + } + + private bool m_bHelpUseLocal = false; + [DefaultValue(false)] + public bool HelpUseLocal + { + get { return m_bHelpUseLocal; } + set { m_bHelpUseLocal = value; } + } + + private string m_strHelpUrl = string.Empty; + [DefaultValue("")] + public string HelpUrl + { + get { return m_strHelpUrl; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strHelpUrl = value; + } + } + + // Serialize DateTime with TimeUtil + private string m_strLastUpdChk = string.Empty; + [DefaultValue("")] + public string LastUpdateCheck + { + get { return m_strLastUpdChk; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strLastUpdChk = value; + } + } + + private IOConnectionInfo m_ioLastDb = null; + public IOConnectionInfo LastUsedFile + { + get + { + if(m_ioLastDb == null) m_ioLastDb = new IOConnectionInfo(); + return m_ioLastDb; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_ioLastDb = value; + } + } + + private AceMru m_mru = null; + public AceMru MostRecentlyUsed + { + get + { + if(m_mru == null) m_mru = new AceMru(); + return m_mru; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_mru = value; + } + } + + private bool m_bRememberWorkDirs = true; + [DefaultValue(true)] + public bool RememberWorkingDirectories + { + get { return m_bRememberWorkDirs; } + set { m_bRememberWorkDirs = value; } + } + + private Dictionary m_dictWorkingDirs = + new Dictionary(); + + /// + /// For serialization only; use the *WorkingDirectory + /// methods instead. + /// + [XmlArray("WorkingDirectories")] + [XmlArrayItem("Item")] + public string[] WorkingDirectoriesSerialized + { + get { return SerializeWorkingDirectories(); } + set + { + if(value == null) throw new ArgumentNullException("value"); + DeserializeWorkingDirectories(value); + } + } + + private AceStartUp m_su = null; + public AceStartUp Start + { + get + { + if(m_su == null) m_su = new AceStartUp(); + return m_su; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_su = value; + } + } + + private AceOpenDb m_fo = null; + public AceOpenDb FileOpening + { + get + { + if(m_fo == null) m_fo = new AceOpenDb(); + return m_fo; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_fo = value; + } + } + + private bool m_bVerifyFile = true; + [DefaultValue(true)] + public bool VerifyWrittenFileAfterSaving + { + get { return m_bVerifyFile; } + set { m_bVerifyFile = value; } + } + + private bool m_bTransactedFileWrites = true; + [DefaultValue(true)] + public bool UseTransactedFileWrites + { + get { return m_bTransactedFileWrites; } + set { m_bTransactedFileWrites = value; } + } + + private bool m_bTransactedConfigWrites = true; + [DefaultValue(true)] + public bool UseTransactedConfigWrites + { + get { return m_bTransactedConfigWrites; } + set { m_bTransactedConfigWrites = value; } + } + + private bool m_bFileTxExtra = false; + [DefaultValue(false)] + public bool FileTxExtra + { + get { return m_bFileTxExtra; } + set { m_bFileTxExtra = value; } + } + + private bool m_bFileLocks = false; + [DefaultValue(false)] + public bool UseFileLocks + { + get { return m_bFileLocks; } + set { m_bFileLocks = value; } + } + + private bool m_bSaveForceSync = false; + [DefaultValue(false)] + public bool SaveForceSync + { + get { return m_bSaveForceSync; } + set { m_bSaveForceSync = value; } + } + + private bool m_bAutoSaveAfterEntryEdit = false; + [DefaultValue(false)] + public bool AutoSaveAfterEntryEdit + { + get { return m_bAutoSaveAfterEntryEdit; } + set { m_bAutoSaveAfterEntryEdit = value; } + } + + private AceCloseDb m_fc = new AceCloseDb(); + public AceCloseDb FileClosing + { + get { return m_fc; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_fc = value; + } + } + + private EcasTriggerSystem m_triggers = new EcasTriggerSystem(); + public EcasTriggerSystem TriggerSystem + { + get { return m_triggers; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_triggers = value; + } + } + + private string m_strPluginCachePath = string.Empty; + [DefaultValue("")] + public string PluginCachePath + { + get { return m_strPluginCachePath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strPluginCachePath = value; + } + } + + private List m_lPluginCompat = new List(); + [XmlArrayItem("Item")] + public List PluginCompatibility + { + get { return m_lPluginCompat; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_lPluginCompat = value; + } + } + + private int m_iExpirySoonDays = 7; + [DefaultValue(7)] + public int ExpirySoonDays + { + get { return m_iExpirySoonDays; } + set { m_iExpirySoonDays = value; } + } + + internal static string GetLanguagesDir(AceDir d, bool bTermSep) + { + string str; + + if(d == AceDir.App) + str = UrlUtil.GetFileDirectory(WinUtil.GetExecutable(), + true, false) + AppDefs.LanguagesDir; + else if(d == AceDir.User) + str = UrlUtil.EnsureTerminatingSeparator( + AppConfigSerializer.AppDataDirectory, false) + + AppDefs.LanguagesDir; + else { Debug.Assert(false); return string.Empty; } + + if(bTermSep) str = UrlUtil.EnsureTerminatingSeparator(str, false); + + return str; + } + + private const string LngPrefixUser = "UL::"; + + internal string GetLanguageFilePath() + { + string str = m_strLanguageFile; + if(str.Length == 0) return string.Empty; + + string strDir, strName; + if(str.StartsWith(LngPrefixUser, StrUtil.CaseIgnoreCmp)) + { + strDir = GetLanguagesDir(AceDir.User, true); + strName = str.Substring(LngPrefixUser.Length); + } + else + { + strDir = GetLanguagesDir(AceDir.App, true); + strName = str; + } + + // File name must not contain a directory separator + // (language files must be directly in the directory, + // not any subdirectory of it or somewhere else) + if(UrlUtil.GetFileName(strName) != strName) + { + Debug.Assert(false); + return string.Empty; + } + + return (strDir + strName); + } + + internal void SetLanguageFilePath(string strPath) + { + m_strLanguageFile = string.Empty; + if(string.IsNullOrEmpty(strPath)) return; + + string str = GetLanguagesDir(AceDir.App, true); + if(strPath.StartsWith(str, StrUtil.CaseIgnoreCmp)) + { + m_strLanguageFile = strPath.Substring(str.Length); + return; + } + + str = GetLanguagesDir(AceDir.User, true); + if(strPath.StartsWith(str, StrUtil.CaseIgnoreCmp)) + { + m_strLanguageFile = LngPrefixUser + strPath.Substring(str.Length); + return; + } + + Debug.Assert(false); + } + + public string GetWorkingDirectory(string strContext) + { + // strContext may be null + + if(!m_bRememberWorkDirs) return null; + + string str; + m_dictWorkingDirs.TryGetValue(strContext ?? string.Empty, out str); + return str; + } + + public void SetWorkingDirectory(string strContext, string strDir) + { + // Both parameters may be null + + // if(!m_bRememberWorkDirs) return; + + if(string.IsNullOrEmpty(strContext)) return; + m_dictWorkingDirs[strContext] = (strDir ?? string.Empty); + } + + internal List GetWorkingDirectoryContexts() + { + if(!m_bRememberWorkDirs) return new List(); + + return new List(m_dictWorkingDirs.Keys); + } + + private string[] SerializeWorkingDirectories() + { + if(!m_bRememberWorkDirs) return MemUtil.EmptyArray(); + + List l = new List(); + foreach(KeyValuePair kvp in m_dictWorkingDirs) + l.Add(kvp.Key + @"@" + kvp.Value); + return l.ToArray(); + } + + private void DeserializeWorkingDirectories(string[] v) + { + // Do not check m_bRememberWorkDirs, because it might not + // have been deserialized yet + + m_dictWorkingDirs.Clear(); + + foreach(string str in v) + { + if(str == null) { Debug.Assert(false); continue; } + + int iSep = str.IndexOf('@'); + if(iSep <= 0) { Debug.Assert(false); continue; } + + m_dictWorkingDirs[str.Substring(0, iSep)] = str.Substring(iSep + 1); + } + } + + internal bool IsPluginCompat(string strHash) + { + if(string.IsNullOrEmpty(strHash)) { Debug.Assert(false); return false; } + + string str = "@" + strHash + "@" + WinUtil.GetAssemblyVersion() + "@1"; + + return m_lPluginCompat.Contains(str); + } + + internal void SetPluginCompat(string strHash) + { + if(string.IsNullOrEmpty(strHash)) { Debug.Assert(false); return; } + + string str = "@" + strHash + "@" + WinUtil.GetAssemblyVersion() + "@1"; + + if(m_lPluginCompat.Contains(str)) { Debug.Assert(false); return; } + m_lPluginCompat.Insert(0, str); // See auto. maintenance + } + } + + internal enum AceDir + { + App = 0, + User + } + + public sealed class AceStartUp + { + public AceStartUp() + { + } + + private bool m_bOpenLastDb = true; + [DefaultValue(true)] + public bool OpenLastFile + { + get { return m_bOpenLastDb; } + set { m_bOpenLastDb = value; } + } + + private bool m_bCheckForUpdate = false; + // [DefaultValue(false)] // Avoid user confusion with 'Configured' setting + public bool CheckForUpdate + { + get { return m_bCheckForUpdate; } + set { m_bCheckForUpdate = value; } + } + + private bool m_bCheckForUpdateCfg = false; + [DefaultValue(false)] + public bool CheckForUpdateConfigured + { + get { return m_bCheckForUpdateCfg; } + set { m_bCheckForUpdateCfg = value; } + } + + private bool m_bMinimizedAndLocked = false; + [DefaultValue(false)] + public bool MinimizedAndLocked + { + get { return m_bMinimizedAndLocked; } + set { m_bMinimizedAndLocked = value; } + } + + private bool m_bPlgDeleteOld = true; + [DefaultValue(true)] + public bool PluginCacheDeleteOld + { + get { return m_bPlgDeleteOld; } + set { m_bPlgDeleteOld = value; } + } + + private bool m_bClearPlgCache = false; + [DefaultValue(false)] + public bool PluginCacheClearOnce + { + get { return m_bClearPlgCache; } + set { m_bClearPlgCache = value; } + } + } + + public sealed class AceOpenDb + { + public AceOpenDb() + { + } + + private bool m_bShowExpiredEntries = false; + [DefaultValue(false)] + public bool ShowExpiredEntries + { + get { return m_bShowExpiredEntries; } + set { m_bShowExpiredEntries = value; } + } + + private bool m_bShowSoonToExpireEntries = false; + [DefaultValue(false)] + public bool ShowSoonToExpireEntries + { + get { return m_bShowSoonToExpireEntries; } + set { m_bShowSoonToExpireEntries = value; } + } + } + + public sealed class AceCloseDb + { + public AceCloseDb() + { + } + + private bool m_bAutoSave = false; + [DefaultValue(false)] + public bool AutoSave + { + get { return m_bAutoSave; } + set { m_bAutoSave = value; } + } + } + + public sealed class AceMru + { + public static readonly uint DefaultMaxItemCount = 12; + + public AceMru() + { + } + + private uint m_uMaxItems = DefaultMaxItemCount; + public uint MaxItemCount + { + get { return m_uMaxItems; } + set { m_uMaxItems = value; } + } + + private List m_lItems = new List(); + [XmlArrayItem("ConnectionInfo")] + public List Items + { + get { return m_lItems; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_lItems = value; + } + } + } +} diff --git a/src/KeePass/App/Configuration/AceCustomConfig.cs b/src/KeePass/App/Configuration/AceCustomConfig.cs new file mode 100644 index 0000000..afa15ca --- /dev/null +++ b/src/KeePass/App/Configuration/AceCustomConfig.cs @@ -0,0 +1,199 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; +using System.Globalization; + +using KeePassLib.Utility; + +namespace KeePass.App.Configuration +{ + public sealed class AceKvp + { + private string m_strKey = null; + public string Key + { + get { return m_strKey; } + set { m_strKey = value; } + } + + private string m_strValue = null; + public string Value + { + get { return m_strValue; } + set { m_strValue = value; } + } + + public AceKvp() + { + } + + public AceKvp(string strKey, string strValue) + { + m_strKey = strKey; + m_strValue = strValue; + } + } + + public sealed class AceCustomConfig + { + private Dictionary m_vItems = new Dictionary(); + + public AceCustomConfig() + { + } + + internal AceKvp[] Serialize() + { + List v = new List(); + + foreach(KeyValuePair kvp in m_vItems) + v.Add(new AceKvp(kvp.Key, kvp.Value)); + + return v.ToArray(); + } + + internal void Deserialize(AceKvp[] v) + { + if(v == null) throw new ArgumentNullException("v"); + + m_vItems.Clear(); + foreach(AceKvp kvp in v) + m_vItems[kvp.Key] = kvp.Value; + } + + /// + /// Set a configuration item's value. + /// + /// ID of the configuration item. This identifier + /// should consist only of English characters (a-z, A-Z, 0-9, '.', + /// ',', '-', '_') and should be unique -- for example (without quotes): + /// "PluginName.YourConfigGroupName.ItemName". Use upper camel + /// case as naming convention. + /// New value of the configuration item. + public void SetString(string strID, string strValue) + { + if(strID == null) throw new ArgumentNullException("strID"); + if(strID.Length == 0) throw new ArgumentException(); + + if(strValue == null) m_vItems.Remove(strID); + else m_vItems[strID] = strValue; + } + + /// + /// Set a configuration item's value. + /// + /// ID of the configuration item. This identifier + /// should consist only of English characters (a-z, A-Z, 0-9, '.', + /// ',', '-', '_') and should be unique -- for example (without quotes): + /// "PluginName.YourConfigGroupName.ItemName". Use upper camel + /// case as naming convention. + /// New value of the configuration item. + public void SetBool(string strID, bool bValue) + { + SetString(strID, StrUtil.BoolToString(bValue)); + } + + /// + /// Set a configuration item's value. + /// + /// ID of the configuration item. This identifier + /// should consist only of English characters (a-z, A-Z, 0-9, '.', + /// ',', '-', '_') and should be unique -- for example (without quotes): + /// "PluginName.YourConfigGroupName.ItemName". Use upper camel + /// case as naming convention. + /// New value of the configuration item. + public void SetLong(string strID, long lValue) + { + SetString(strID, lValue.ToString(NumberFormatInfo.InvariantInfo)); + } + + /// + /// Set a configuration item's value. + /// + /// ID of the configuration item. This identifier + /// should consist only of English characters (a-z, A-Z, 0-9, '.', + /// ',', '-', '_') and should be unique -- for example (without quotes): + /// "PluginName.YourConfigGroupName.ItemName". Use upper camel + /// case as naming convention. + /// New value of the configuration item. + public void SetULong(string strID, ulong uValue) + { + SetString(strID, uValue.ToString(NumberFormatInfo.InvariantInfo)); + } + + public string GetString(string strID) + { + return GetString(strID, null); + } + + /// + /// Get the current value of a custom configuration string. + /// + /// ID of the configuration item. + /// Default value that is returned if + /// the specified configuration does not exist. + /// Value of the configuration item. + public string GetString(string strID, string strDefault) + { + if(strID == null) throw new ArgumentNullException("strID"); + if(strID.Length == 0) throw new ArgumentException(); + + string strValue; + if(m_vItems.TryGetValue(strID, out strValue)) return strValue; + + return strDefault; + } + + public bool GetBool(string strID, bool bDefault) + { + string strValue = GetString(strID, null); + if(string.IsNullOrEmpty(strValue)) return bDefault; + + return StrUtil.StringToBool(strValue); + } + + public long GetLong(string strID, long lDefault) + { + string strValue = GetString(strID, null); + if(string.IsNullOrEmpty(strValue)) return lDefault; + + long lValue; + if(StrUtil.TryParseLongInvariant(strValue, out lValue)) + return lValue; + + return lDefault; + } + + public ulong GetULong(string strID, ulong uDefault) + { + string strValue = GetString(strID, null); + if(string.IsNullOrEmpty(strValue)) return uDefault; + + ulong uValue; + if(StrUtil.TryParseULongInvariant(strValue, out uValue)) + return uValue; + + return uDefault; + } + } +} diff --git a/src/KeePass/App/Configuration/AceDefaults.cs b/src/KeePass/App/Configuration/AceDefaults.cs new file mode 100644 index 0000000..46803cc --- /dev/null +++ b/src/KeePass/App/Configuration/AceDefaults.cs @@ -0,0 +1,335 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Xml.Serialization; + +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Keys; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.App.Configuration +{ + public sealed class AceKeyAssoc + { + private string m_strDb = string.Empty; + public string DatabasePath + { + get { return m_strDb; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strDb = value; + } + } + + private bool m_bPassword = false; + [DefaultValue(false)] + public bool Password + { + get { return m_bPassword; } + set { m_bPassword = value; } + } + + private string m_strKey = string.Empty; + [DefaultValue("")] + public string KeyFilePath + { + get { return m_strKey; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strKey = value; + } + } + + private string m_strProv = string.Empty; + [DefaultValue("")] + public string KeyProvider + { + get { return m_strProv; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strProv = value; + } + } + + private bool m_bUserAcc = false; + [DefaultValue(false)] + public bool UserAccount + { + get { return m_bUserAcc; } + set { m_bUserAcc = value; } + } + + public AceKeyAssoc() { } + } + + public sealed class AceDefaults + { + public AceDefaults() + { + } + + private int m_nNewEntryExpireDays = -1; + [DefaultValue(-1)] + public int NewEntryExpiresInDays + { + get { return m_nNewEntryExpireDays; } + set { m_nNewEntryExpireDays = value; } + } + + private uint m_uDefaultOptionsTab = 0; + public uint OptionsTabIndex + { + get { return m_uDefaultOptionsTab; } + set { m_uDefaultOptionsTab = value; } + } + + private const string DefaultTanChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"; + private string m_strTanChars = DefaultTanChars; + [DefaultValue(DefaultTanChars)] + public string TanCharacters + { + get { return m_strTanChars; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strTanChars = value; + } + } + + private bool m_bExpireTansOnUse = true; + [DefaultValue(true)] + public bool TanExpiresOnUse + { + get { return m_bExpireTansOnUse; } + set { m_bExpireTansOnUse = value; } + } + + private string m_strDbSaveAsPath = string.Empty; + [DefaultValue("")] + public string FileSaveAsDirectory + { + get { return m_strDbSaveAsPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strDbSaveAsPath = value; + } + } + + private bool m_bRememberKeySources = true; + [DefaultValue(true)] + public bool RememberKeySources + { + get { return m_bRememberKeySources; } + set { m_bRememberKeySources = value; } + } + + private List m_vKeySources = new List(); + [XmlArrayItem("Association")] + public List KeySources + { + get { return m_vKeySources; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_vKeySources = value; + } + } + + private string m_strCustomColors = string.Empty; + [DefaultValue("")] + public string CustomColors + { + get { return m_strCustomColors; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strCustomColors = value; + } + } + + private bool m_bExportMasterKeySpec = false; + [DefaultValue(false)] + public bool ExportMasterKeySpec + { + get { return m_bExportMasterKeySpec; } + set { m_bExportMasterKeySpec = value; } + } + + private bool m_bExportParentGroups = false; + [DefaultValue(false)] + public bool ExportParentGroups + { + get { return m_bExportParentGroups; } + set { m_bExportParentGroups = value; } + } + + private bool m_bExportPostOpen = false; + [DefaultValue(false)] + public bool ExportPostOpen + { + get { return m_bExportPostOpen; } + set { m_bExportPostOpen = value; } + } + + private bool m_bExportPostShow = false; + [DefaultValue(false)] + public bool ExportPostShow + { + get { return m_bExportPostShow; } + set { m_bExportPostShow = value; } + } + + private string m_strWinFavsBaseName = string.Empty; + [DefaultValue("")] + public string WinFavsBaseFolderName + { + get { return m_strWinFavsBaseName; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strWinFavsBaseName = value; + } + } + + private string m_strWinFavsFilePrefix = string.Empty; + [DefaultValue("")] + public string WinFavsFileNamePrefix + { + get { return m_strWinFavsFilePrefix; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strWinFavsFilePrefix = value; + } + } + + private string m_strWinFavsFileSuffix = string.Empty; + [DefaultValue("")] + public string WinFavsFileNameSuffix + { + get { return m_strWinFavsFileSuffix; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strWinFavsFileSuffix = value; + } + } + + private bool m_bCollapseRecycleBin = false; + [DefaultValue(false)] + public bool RecycleBinCollapse + { + get { return m_bCollapseRecycleBin; } + set { m_bCollapseRecycleBin = value; } + } + + private static string GetKeyAssocID(IOConnectionInfo iocDb) + { + if(iocDb == null) throw new ArgumentNullException("iocDb"); + + string strDb = iocDb.Path; + if((strDb.Length > 0) && iocDb.IsLocalFile() && + !UrlUtil.IsAbsolutePath(strDb)) + strDb = UrlUtil.MakeAbsolutePath(WinUtil.GetExecutable(), strDb); + + return strDb; + } + + private int GetKeyAssocIndex(string strID) + { + for(int i = 0; i < m_vKeySources.Count; ++i) + { + if(strID.Equals(m_vKeySources[i].DatabasePath, StrUtil.CaseIgnoreCmp)) + return i; + } + + return -1; + } + + public void SetKeySources(IOConnectionInfo iocDb, CompositeKey cmpKey) + { + string strID = GetKeyAssocID(iocDb); + int idx = GetKeyAssocIndex(strID); + + if((cmpKey == null) || !m_bRememberKeySources) + { + if(idx >= 0) m_vKeySources.RemoveAt(idx); + return; + } + + AceKeyAssoc a = new AceKeyAssoc(); + a.DatabasePath = strID; + + IUserKey kcpPassword = cmpKey.GetUserKey(typeof(KcpPassword)); + a.Password = (kcpPassword != null); + + IUserKey kcpFile = cmpKey.GetUserKey(typeof(KcpKeyFile)); + if(kcpFile != null) + { + string strKeyFile = ((KcpKeyFile)kcpFile).Path; + if(!string.IsNullOrEmpty(strKeyFile) && !StrUtil.IsDataUri(strKeyFile)) + { + if(!UrlUtil.IsAbsolutePath(strKeyFile)) + strKeyFile = UrlUtil.MakeAbsolutePath(WinUtil.GetExecutable(), + strKeyFile); + + a.KeyFilePath = strKeyFile; + } + } + + IUserKey kcpCustom = cmpKey.GetUserKey(typeof(KcpCustomKey)); + if(kcpCustom != null) + a.KeyProvider = ((KcpCustomKey)kcpCustom).Name; + + IUserKey kcpUser = cmpKey.GetUserKey(typeof(KcpUserAccount)); + a.UserAccount = (kcpUser != null); + + bool bAtLeastOne = (a.Password || (a.KeyFilePath.Length > 0) || + (a.KeyProvider.Length > 0) || a.UserAccount); + if(bAtLeastOne) + { + if(idx >= 0) m_vKeySources[idx] = a; + else m_vKeySources.Add(a); + } + else if(idx >= 0) m_vKeySources.RemoveAt(idx); + } + + public AceKeyAssoc GetKeySources(IOConnectionInfo iocDb) + { + string strID = GetKeyAssocID(iocDb); + int idx = GetKeyAssocIndex(strID); + + if(!m_bRememberKeySources) return null; + + if(idx >= 0) return m_vKeySources[idx]; + return null; + } + } +} diff --git a/src/KeePass/App/Configuration/AceIntegration.cs b/src/KeePass/App/Configuration/AceIntegration.cs new file mode 100644 index 0000000..760ec4b --- /dev/null +++ b/src/KeePass/App/Configuration/AceIntegration.cs @@ -0,0 +1,617 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Text; +using System.Windows.Forms; +using System.Xml.Serialization; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.App.Configuration +{ + public sealed class AceIntegration + { + private long m_hkAutoType = (long)(Keys.Control | Keys.Alt | Keys.A); + [DefaultValue((long)(Keys.Control | Keys.Alt | Keys.A))] + public long HotKeyGlobalAutoType + { + get { return m_hkAutoType; } + set { m_hkAutoType = value; } + } + + private long m_hkAutoTypePw = (long)(Keys.Control | Keys.Alt | Keys.Shift | Keys.A); + [DefaultValue((long)(Keys.Control | Keys.Alt | Keys.Shift | Keys.A))] + public long HotKeyGlobalAutoTypePassword + { + get { return m_hkAutoTypePw; } + set { m_hkAutoTypePw = value; } + } + + private long m_hkAutoTypeSel = (long)Keys.None; + [DefaultValue((long)Keys.None)] + public long HotKeySelectedAutoType + { + get { return m_hkAutoTypeSel; } + set { m_hkAutoTypeSel = value; } + } + + private long m_hkShowWindow = (long)(Keys.Control | Keys.Alt | Keys.K); + [DefaultValue((long)(Keys.Control | Keys.Alt | Keys.K))] + public long HotKeyShowWindow + { + get { return m_hkShowWindow; } + set { m_hkShowWindow = value; } + } + + private long m_hkEntryMenu = (long)Keys.None; + [DefaultValue((long)Keys.None)] + public long HotKeyEntryMenu + { + get { return m_hkEntryMenu; } + set { m_hkEntryMenu = value; } + } + + private bool m_bCheckHotKeys = true; + [DefaultValue(true)] + public bool CheckHotKeys + { + get { return m_bCheckHotKeys; } + set { m_bCheckHotKeys = value; } + } + + private string m_strUrlOverride = string.Empty; + [DefaultValue("")] + public string UrlOverride + { + get { return m_strUrlOverride; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strUrlOverride = value; + } + } + + private AceUrlSchemeOverrides m_vSchemeOverrides = new AceUrlSchemeOverrides(); + public AceUrlSchemeOverrides UrlSchemeOverrides + { + get { return m_vSchemeOverrides; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_vSchemeOverrides = value; + } + } + + private bool m_bSearchKeyFiles = true; + [DefaultValue(true)] + public bool SearchKeyFiles + { + get { return m_bSearchKeyFiles; } + set { m_bSearchKeyFiles = value; } + } + + private bool m_bSearchKeyFilesOnRemovable = false; + [DefaultValue(false)] + public bool SearchKeyFilesOnRemovableMedia + { + get { return m_bSearchKeyFilesOnRemovable; } + set { m_bSearchKeyFilesOnRemovable = value; } + } + + private bool m_bSingleInstance = true; + [DefaultValue(true)] + public bool LimitToSingleInstance + { + get { return m_bSingleInstance; } + set { m_bSingleInstance = value; } + } + + private bool m_bMatchByTitle = true; + [DefaultValue(true)] + public bool AutoTypeMatchByTitle + { + get { return m_bMatchByTitle; } + set { m_bMatchByTitle = value; } + } + + private bool m_bMatchByUrlInTitle = false; + [DefaultValue(false)] + public bool AutoTypeMatchByUrlInTitle + { + get { return m_bMatchByUrlInTitle; } + set { m_bMatchByUrlInTitle = value; } + } + + private bool m_bMatchByUrlHostInTitle = false; + [DefaultValue(false)] + public bool AutoTypeMatchByUrlHostInTitle + { + get { return m_bMatchByUrlHostInTitle; } + set { m_bMatchByUrlHostInTitle = value; } + } + + private bool m_bMatchByTagInTitle = false; + [DefaultValue(false)] + public bool AutoTypeMatchByTagInTitle + { + get { return m_bMatchByTagInTitle; } + set { m_bMatchByTagInTitle = value; } + } + + private bool m_bMatchNormDashes = true; + [DefaultValue(true)] + public bool AutoTypeMatchNormDashes + { + get { return m_bMatchNormDashes; } + set { m_bMatchNormDashes = value; } + } + + private bool m_bExpiredCanMatch = false; + [DefaultValue(false)] + public bool AutoTypeExpiredCanMatch + { + get { return m_bExpiredCanMatch; } + set { m_bExpiredCanMatch = value; } + } + + private bool m_bAutoTypeAlwaysShowSelDlg = false; + [DefaultValue(false)] + public bool AutoTypeAlwaysShowSelDialog + { + get { return m_bAutoTypeAlwaysShowSelDlg; } + set { m_bAutoTypeAlwaysShowSelDlg = value; } + } + + private bool m_bPrependInitSeqIE = true; + [DefaultValue(true)] + public bool AutoTypePrependInitSequenceForIE + { + get { return m_bPrependInitSeqIE; } + set { m_bPrependInitSeqIE = value; } + } + + private bool m_bSpecialReleaseAlt = true; + [DefaultValue(true)] + public bool AutoTypeReleaseAltWithKeyPress + { + get { return m_bSpecialReleaseAlt; } + set { m_bSpecialReleaseAlt = value; } + } + + private bool m_bAdjustKeybLayout = true; + [DefaultValue(true)] + public bool AutoTypeAdjustKeyboardLayout + { + get { return m_bAdjustKeybLayout; } + set { m_bAdjustKeybLayout = value; } + } + + private bool m_bAllowInterleaved = false; + [DefaultValue(false)] + public bool AutoTypeAllowInterleaved + { + get { return m_bAllowInterleaved; } + set { m_bAllowInterleaved = value; } + } + + private bool m_bCancelOnWindowChange = false; + [DefaultValue(false)] + public bool AutoTypeCancelOnWindowChange + { + get { return m_bCancelOnWindowChange; } + set { m_bCancelOnWindowChange = value; } + } + + private bool m_bCancelOnTitleChange = false; + [DefaultValue(false)] + public bool AutoTypeCancelOnTitleChange + { + get { return m_bCancelOnTitleChange; } + set { m_bCancelOnTitleChange = value; } + } + + private int m_iInterKeyDelay = -1; + [DefaultValue(-1)] + public int AutoTypeInterKeyDelay + { + get { return m_iInterKeyDelay; } + set { m_iInterKeyDelay = value; } + } + + private List m_lAbortWindows = new List(); + [XmlArrayItem("Window")] + public List AutoTypeAbortOnWindows + { + get { return m_lAbortWindows; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_lAbortWindows = value; + } + } + + private ProxyServerType m_pstProxyType = ProxyServerType.System; + [DefaultValue(ProxyServerType.System)] + public ProxyServerType ProxyType + { + get { return m_pstProxyType; } + set { m_pstProxyType = value; } + } + + private string m_strProxyAddr = string.Empty; + [DefaultValue("")] + public string ProxyAddress + { + get { return m_strProxyAddr; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strProxyAddr = value; + } + } + + private string m_strProxyPort = string.Empty; + [DefaultValue("")] + public string ProxyPort + { + get { return m_strProxyPort; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strProxyPort = value; + } + } + + private ProxyAuthType m_pstProxyAuthType = ProxyAuthType.Auto; + [DefaultValue(ProxyAuthType.Auto)] + public ProxyAuthType ProxyAuthType + { + get { return m_pstProxyAuthType; } + set { m_pstProxyAuthType = value; } + } + + private string m_strProxyUser = string.Empty; + [DefaultValue("")] + public string ProxyUserName + { + get { return m_strProxyUser; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strProxyUser = value; + } + } + + private string m_strProxyPassword = string.Empty; + [DefaultValue("")] + public string ProxyPassword + { + get { return m_strProxyPassword; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strProxyPassword = value; + } + } + + public AceIntegration() + { + } + } + + public sealed class AceUrlSchemeOverrides : IDeepCloneable + { + private List m_lBuiltInOverrides = + new List(); + [XmlIgnore] + public List BuiltInOverrides + { + get { return m_lBuiltInOverrides; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_lBuiltInOverrides = value; + } + } + + public ulong BuiltInOverridesEnabled + { + get { return GetEnabledBuiltInOverrides(); } + set { SetEnabledBuiltInOverrides(value); } + } + + private List m_lCustomOverrides = + new List(); + [XmlArrayItem("Override")] + public List CustomOverrides + { + get { return m_lCustomOverrides; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_lCustomOverrides = value; + } + } + + public AceUrlSchemeOverrides() + { + MakeBuiltInList(); + } + + private void MakeBuiltInList() + { + m_lBuiltInOverrides.Clear(); + + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(true, "ssh", + "cmd://SSH.exe -l \"{USERNAME}\" {BASE:RMVSCM}", 0x1000000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "ssh", + "cmd://PuTTY.exe -ssh {USERNAME}@{BASE:RMVSCM}", 0x1)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{EDGE} \"{BASE}\"", 0x4000)); // "microsoft-edge:{BASE}" + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{EDGE} \"{BASE}\"", 0x8000)); // "microsoft-edge:{BASE}" + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{EDGE} --inprivate \"{BASE}\"", 0x2000000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{EDGE} --inprivate \"{BASE}\"", 0x4000000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{FIREFOX} \"{BASE}\"", 0x8)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{FIREFOX} \"{BASE}\"", 0x10)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{FIREFOX} -private-window \"{BASE}\"", 0x100000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{FIREFOX} -private-window \"{BASE}\"", 0x200000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "chrome", + "cmd://{FIREFOX} -chrome \"{BASE}\"", 0x20)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{GOOGLECHROME} \"{BASE}\"", 0x100)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{GOOGLECHROME} \"{BASE}\"", 0x200)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{GOOGLECHROME} --incognito \"{BASE}\"", 0x40000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{GOOGLECHROME} --incognito \"{BASE}\"", 0x80000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{INTERNETEXPLORER} \"{BASE}\"", 0x2)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{INTERNETEXPLORER} \"{BASE}\"", 0x4)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{INTERNETEXPLORER} -private \"{BASE}\"", 0x10000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{INTERNETEXPLORER} -private \"{BASE}\"", 0x20000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{OPERA} \"{BASE}\"", 0x40)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{OPERA} \"{BASE}\"", 0x80)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{OPERA} --private \"{BASE}\"", 0x400000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{OPERA} --private \"{BASE}\"", 0x800000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "http", + "cmd://{SAFARI} \"{BASE}\"", 0x400)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "https", + "cmd://{SAFARI} \"{BASE}\"", 0x800)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "kdbx", + "cmd://\"{APPDIR}\\KeePass.exe\" \"{BASE:RMVSCM}\" -pw-enc:\"{PASSWORD_ENC}\"", 0x1000)); + m_lBuiltInOverrides.Add(new AceUrlSchemeOverride(false, "kdbx", + "cmd://mono \"{APPDIR}/KeePass.exe\" \"{BASE:RMVSCM}\" -pw-enc:\"{PASSWORD_ENC}\"", 0x2000)); + // Free: 0x8000000 + +#if DEBUG + ulong u = 0; + foreach(AceUrlSchemeOverride o in m_lBuiltInOverrides) + { + Debug.Assert(o.IsBuiltIn); + ulong f = o.BuiltInFlagID; + Debug.Assert((f != 0) && ((f & (f - 1)) == 0)); // Check power of 2 + u += f; + } + Debug.Assert(u == ((1UL << m_lBuiltInOverrides.Count) - 1UL)); +#endif + } + + public string GetOverrideForUrl(string strUrl) + { + if(string.IsNullOrEmpty(strUrl)) return null; + + for(int i = 0; i < 2; ++i) + { + List l = ((i == 0) ? m_lBuiltInOverrides : + m_lCustomOverrides); + + foreach(AceUrlSchemeOverride ovr in l) + { + if(!ovr.Enabled) continue; + + if(strUrl.StartsWith(ovr.Scheme + ":", StrUtil.CaseIgnoreCmp)) + return ovr.UrlOverride; + } + } + + return null; + } + + public AceUrlSchemeOverrides CloneDeep() + { + AceUrlSchemeOverrides ovr = new AceUrlSchemeOverrides(); + CopyTo(ovr); + return ovr; + } + + public void CopyTo(AceUrlSchemeOverrides ovrTarget) + { + ovrTarget.m_lBuiltInOverrides.Clear(); + foreach(AceUrlSchemeOverride shB in m_lBuiltInOverrides) + { + ovrTarget.m_lBuiltInOverrides.Add(shB.CloneDeep()); + } + + ovrTarget.m_lCustomOverrides.Clear(); + foreach(AceUrlSchemeOverride shC in m_lCustomOverrides) + { + ovrTarget.m_lCustomOverrides.Add(shC.CloneDeep()); + } + } + + private ulong GetEnabledBuiltInOverrides() + { + ulong u = 0; + for(int i = 0; i < m_lBuiltInOverrides.Count; ++i) + { + if(m_lBuiltInOverrides[i].Enabled) + u |= m_lBuiltInOverrides[i].BuiltInFlagID; + } + + return u; + } + + private void SetEnabledBuiltInOverrides(ulong uFlags) + { + for(int i = 0; i < m_lBuiltInOverrides.Count; ++i) + m_lBuiltInOverrides[i].Enabled = ((uFlags & + m_lBuiltInOverrides[i].BuiltInFlagID) != 0UL); + } + + internal void AddCustomOverride(string strScheme, string strOverride, + bool bEnable, bool bDisableOthers) + { + if(string.IsNullOrEmpty(strScheme)) return; // No assert + if(strOverride == null) return; // No assert + + if(bDisableOthers) + { + List l = new List(); + l.AddRange(m_lBuiltInOverrides); + l.AddRange(m_lCustomOverrides); + + foreach(AceUrlSchemeOverride o in l) + { + if(o.Scheme.Equals(strScheme, StrUtil.CaseIgnoreCmp)) + o.Enabled = false; + } + } + + m_lCustomOverrides.Add(new AceUrlSchemeOverride(bEnable, + strScheme, strOverride)); + } + + internal void RemoveCustomOverride(string strScheme, string strOverride) + { + if(string.IsNullOrEmpty(strScheme)) return; // No assert + if(strOverride == null) return; // No assert + + for(int i = m_lCustomOverrides.Count - 1; i >= 0; --i) + { + AceUrlSchemeOverride o = m_lCustomOverrides[i]; + if(o.Scheme.Equals(strScheme, StrUtil.CaseIgnoreCmp) && + (o.UrlOverride == strOverride)) + { + m_lCustomOverrides.RemoveAt(i); + return; // Remove one item only + } + } + } + } + + public sealed class AceUrlSchemeOverride : IDeepCloneable + { + private bool m_bEnabled = true; + public bool Enabled + { + get { return m_bEnabled; } + set { m_bEnabled = value; } + } + + private string m_strScheme = string.Empty; + public string Scheme + { + get { return m_strScheme; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strScheme = value; + } + } + + private string m_strOvr = string.Empty; + public string UrlOverride + { + get { return m_strOvr; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strOvr = value; + } + } + + private ulong m_uBuiltInFlagID = 0; + [XmlIgnore] + internal ulong BuiltInFlagID + { + get { return m_uBuiltInFlagID; } + } + + [XmlIgnore] + public bool IsBuiltIn + { + get { return (m_uBuiltInFlagID != 0UL); } + } + + public AceUrlSchemeOverride() + { + } + + public AceUrlSchemeOverride(bool bEnable, string strScheme, + string strUrlOverride) + { + Init(bEnable, strScheme, strUrlOverride, 0); + } + + internal AceUrlSchemeOverride(bool bEnable, string strScheme, + string strUrlOverride, ulong uBuiltInFlagID) + { + Init(bEnable, strScheme, strUrlOverride, uBuiltInFlagID); + } + + private void Init(bool bEnable, string strScheme, string strUrlOverride, + ulong uBuiltInFlagID) + { + if(strScheme == null) throw new ArgumentNullException("strScheme"); + if(strUrlOverride == null) throw new ArgumentNullException("strUrlOverride"); + + m_bEnabled = bEnable; + m_strScheme = strScheme; + m_strOvr = strUrlOverride; + m_uBuiltInFlagID = uBuiltInFlagID; + } + + public AceUrlSchemeOverride CloneDeep() + { + return new AceUrlSchemeOverride(m_bEnabled, m_strScheme, + m_strOvr, m_uBuiltInFlagID); + } + } +} diff --git a/src/KeePass/App/Configuration/AceLogging.cs b/src/KeePass/App/Configuration/AceLogging.cs new file mode 100644 index 0000000..230dbd2 --- /dev/null +++ b/src/KeePass/App/Configuration/AceLogging.cs @@ -0,0 +1,41 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; + +namespace KeePass.App.Configuration +{ + public sealed class AceLogging + { + public AceLogging() + { + } + + private bool m_bEnabled = false; + [DefaultValue(false)] + public bool Enabled + { + get { return m_bEnabled; } + set { m_bEnabled = value; } + } + } +} diff --git a/src/KeePass/App/Configuration/AceMainWindow.cs b/src/KeePass/App/Configuration/AceMainWindow.cs new file mode 100644 index 0000000..c46ab14 --- /dev/null +++ b/src/KeePass/App/Configuration/AceMainWindow.cs @@ -0,0 +1,758 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using System.Xml.Serialization; + +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Security; + +namespace KeePass.App.Configuration +{ + public enum AceMainWindowLayout + { + Default = 0, + SideBySide = 1 + } + + [Flags] + public enum AceListGrouping + { + Auto = 0, + On = 1, + Off = 2, + + // Additional flags: use value > Primary + + Primary = 0x0F // Auto/On/Off are primary states + } + + public enum AceEscAction + { + None = 0, + Lock = 1, + Minimize = 2, + MinimizeToTray = 3, + Exit = 4 + } + + public sealed class AceMainWindow + { + public AceMainWindow() + { + } + + private int m_posX = AppDefs.InvalidWindowValue; + public int X + { + get { return m_posX; } + set { m_posX = value; } + } + + private int m_posY = AppDefs.InvalidWindowValue; + public int Y + { + get { return m_posY; } + set { m_posY = value; } + } + + private int m_sizeW = AppDefs.InvalidWindowValue; + public int Width + { + get { return m_sizeW; } + set { m_sizeW = value; } + } + + private int m_sizeH = AppDefs.InvalidWindowValue; + public int Height + { + get { return m_sizeH; } + set { m_sizeH = value; } + } + + private bool m_bMax = false; + [DefaultValue(false)] + public bool Maximized + { + get { return m_bMax; } + set { m_bMax = value; } + } + + private double m_dSplitterHorz = double.Epsilon; + public double SplitterHorizontalFrac + { + get { return m_dSplitterHorz; } + set { m_dSplitterHorz = value; } + } + + private double m_dSplitterVert = double.Epsilon; + public double SplitterVerticalFrac + { + get { return m_dSplitterVert; } + set { m_dSplitterVert = value; } + } + + private AceMainWindowLayout m_layout = AceMainWindowLayout.Default; + [DefaultValue(AceMainWindowLayout.Default)] + public AceMainWindowLayout Layout + { + get { return m_layout; } + set { m_layout = value; } + } + + private bool m_bTop = false; + [DefaultValue(false)] + public bool AlwaysOnTop + { + get { return m_bTop; } + set { m_bTop = value; } + } + + private bool m_bCloseMin = false; + [DefaultValue(false)] + public bool CloseButtonMinimizesWindow + { + get { return m_bCloseMin; } + set { m_bCloseMin = value; } + } + + // For backward compatibility only; use EscAction instead + private bool m_bEscMin = false; + [DefaultValue(false)] + public bool EscMinimizesToTray + { + get { return m_bEscMin; } + set { m_bEscMin = value; } + } + + private AceEscAction m_aEsc = AceEscAction.Lock; + [DefaultValue(AceEscAction.Lock)] + public AceEscAction EscAction + { + get { return m_aEsc; } + set { m_aEsc = value; } + } + + private bool m_bMinToTray = false; + [DefaultValue(false)] + public bool MinimizeToTray + { + get { return m_bMinToTray; } + set { m_bMinToTray = value; } + } + + private bool m_bFullPath = false; + [DefaultValue(false)] + public bool ShowFullPathInTitle + { + get { return m_bFullPath; } + set { m_bFullPath = value; } + } + + // private bool m_bFullPathOnTab = false; + // [DefaultValue(false)] + // public bool ShowFullPathOnTab + // { + // get { return m_bFullPathOnTab; } + // set { m_bFullPathOnTab = value; } + // } + + // private bool m_bDbNameOnTab = false; + // [DefaultValue(false)] + // public bool ShowDatabaseNameOnTab + // { + // get { return m_bDbNameOnTab; } + // set { m_bDbNameOnTab = value; } + // } + + private bool m_bDropToBackAfterCopy = false; + [DefaultValue(false)] + public bool DropToBackAfterClipboardCopy + { + get { return m_bDropToBackAfterCopy; } + set { m_bDropToBackAfterCopy = value; } + } + + private bool m_bMinAfterCopy = false; + [DefaultValue(false)] + public bool MinimizeAfterClipboardCopy + { + get { return m_bMinAfterCopy; } + set { m_bMinAfterCopy = value; } + } + + private bool m_bMinAfterAutoType = false; + [DefaultValue(false)] + public bool MinimizeAfterAutoType + { + get { return m_bMinAfterAutoType; } + set { m_bMinAfterAutoType = value; } + } + + private bool m_bMinAfterLocking = true; + [DefaultValue(true)] + public bool MinimizeAfterLocking + { + get { return m_bMinAfterLocking; } + set { m_bMinAfterLocking = value; } + } + + private bool m_bMinAfterOpeningDb = false; + [DefaultValue(false)] + public bool MinimizeAfterOpeningDatabase + { + get { return m_bMinAfterOpeningDb; } + set { m_bMinAfterOpeningDb = value; } + } + + private bool m_bQuickFindSearchInPasswords = false; + [DefaultValue(false)] + public bool QuickFindSearchInPasswords + { + get { return m_bQuickFindSearchInPasswords; } + set { m_bQuickFindSearchInPasswords = value; } + } + + private bool m_bQuickFindExcludeExpired = false; + [DefaultValue(false)] + public bool QuickFindExcludeExpired + { + get { return m_bQuickFindExcludeExpired; } + set { m_bQuickFindExcludeExpired = value; } + } + + private bool m_bQuickFindDerefData = false; + [DefaultValue(false)] + public bool QuickFindDerefData + { + get { return m_bQuickFindDerefData; } + set { m_bQuickFindDerefData = value; } + } + + private bool m_bFocusResAfterQuickFind = false; + [DefaultValue(false)] + public bool FocusResultsAfterQuickFind + { + get { return m_bFocusResAfterQuickFind; } + set { m_bFocusResAfterQuickFind = value; } + } + + private bool m_bFocusQuickFindOnRestore = false; + /// + /// Focus the quick search box when restoring the main + /// window. Here 'restoring' actually means unminimizing, + /// i.e. restoring or maximizing the window. + /// + [DefaultValue(false)] + public bool FocusQuickFindOnRestore + { + get { return m_bFocusQuickFindOnRestore; } + set { m_bFocusQuickFindOnRestore = value; } + } + + private bool m_bFocusQuickFindOnUntray = false; + [DefaultValue(false)] + public bool FocusQuickFindOnUntray + { + get { return m_bFocusQuickFindOnUntray; } + set { m_bFocusQuickFindOnUntray = value; } + } + + private bool m_bCopyUrls = false; + [DefaultValue(false)] + public bool CopyUrlsInsteadOfOpening + { + get { return m_bCopyUrls; } + set { m_bCopyUrls = value; } + } + + private bool m_bEntrySelGroupSel = true; + [DefaultValue(true)] + public bool EntrySelGroupSel + { + get { return m_bEntrySelGroupSel; } + set { m_bEntrySelGroupSel = value; } + } + + private bool m_bDisableSaveIfNotModified = false; + /// + /// Disable 'Save' button (instead of graying it out) if the database + /// hasn't been modified. + /// + [DefaultValue(false)] + public bool DisableSaveIfNotModified + { + get { return m_bDisableSaveIfNotModified; } + set { m_bDisableSaveIfNotModified = value; } + } + + private bool m_bHideCloseDbTb = true; + [DefaultValue(true)] + public bool HideCloseDatabaseButton + { + get { return m_bHideCloseDbTb; } + set { m_bHideCloseDbTb = value; } + } + + private AceToolBar m_tb = new AceToolBar(); + public AceToolBar ToolBar + { + get { return m_tb; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_tb = value; + } + } + + private AceEntryView m_ev = new AceEntryView(); + public AceEntryView EntryView + { + get { return m_ev; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_ev = value; + } + } + + private AceTanView m_tan = new AceTanView(); + public AceTanView TanView + { + get { return m_tan; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_tan = value; + } + } + + private List m_lColumns = new List(); + [XmlArray("EntryListColumnCollection")] + [XmlArrayItem("Column")] + public List EntryListColumns + { + get { return m_lColumns; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_lColumns = value; + } + } + + private string m_strDisplayIndices = string.Empty; + [DefaultValue("")] + public string EntryListColumnDisplayOrder + { + get { return m_strDisplayIndices; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strDisplayIndices = value; + } + } + + private bool m_bAutoResizeColumns = false; + [DefaultValue(false)] + public bool EntryListAutoResizeColumns + { + get { return m_bAutoResizeColumns; } + set { m_bAutoResizeColumns = value; } + } + + private bool m_bAlternatingBgColor = true; + [DefaultValue(true)] + public bool EntryListAlternatingBgColors + { + get { return m_bAlternatingBgColor; } + set { m_bAlternatingBgColor = value; } + } + + private int m_argbAltBgColor = 0; + [DefaultValue(0)] + public int EntryListAlternatingBgColor + { + get { return m_argbAltBgColor; } + set { m_argbAltBgColor = value; } + } + + private bool m_bResolveFieldRefs = false; + [DefaultValue(false)] + public bool EntryListShowDerefData + { + get { return m_bResolveFieldRefs; } + set { m_bResolveFieldRefs = value; } + } + + private bool m_bResolveFieldRefsAsync = false; + [DefaultValue(false)] + public bool EntryListShowDerefDataAsync + { + get { return m_bResolveFieldRefsAsync; } + set { m_bResolveFieldRefsAsync = value; } + } + + private bool m_bDerefDataWithRefs = true; + [DefaultValue(true)] + public bool EntryListShowDerefDataAndRefs + { + get { return m_bDerefDataWithRefs; } + set { m_bDerefDataWithRefs = value; } + } + + // private bool m_bGridLines = false; + // public bool ShowGridLines + // { + // get { return m_bGridLines; } + // set { m_bGridLines = value; } + // } + + private ListSorter m_pListSorter = null; + public ListSorter ListSorting + { + get + { + if(m_pListSorter == null) m_pListSorter = new ListSorter(); + return m_pListSorter; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_pListSorter = value; + } + } + + private int m_iLgMain = (int)AceListGrouping.Auto; + [DefaultValue((int)AceListGrouping.Auto)] + public int ListGrouping // AceListGrouping + { + get { return m_iLgMain; } + set { m_iLgMain = value; } + } + + private bool m_bShowEntriesOfSubGroups = false; + [DefaultValue(false)] + public bool ShowEntriesOfSubGroups + { + get { return m_bShowEntriesOfSubGroups; } + set { m_bShowEntriesOfSubGroups = value; } + } + + public AceColumn FindColumn(AceColumnType t) + { + foreach(AceColumn c in m_lColumns) + { + if(c.Type == t) return c; + } + + return null; + } + + internal List FindColumns(AceColumnType t) + { + List l = new List(); + + foreach(AceColumn c in m_lColumns) + { + if(c.Type == t) l.Add(c); + } + + return l; + } + + public bool IsColumnHidden(AceColumnType t) + { + return IsColumnHidden(t, (t == AceColumnType.Password)); + } + + public bool IsColumnHidden(AceColumnType t, bool bDefault) + { + foreach(AceColumn c in m_lColumns) + { + if(c.Type == t) return c.HideWithAsterisks; + } + + return bDefault; + } + + public bool ShouldHideCustomString(string strCustomName, + ProtectedString psValue) + { + foreach(AceColumn c in m_lColumns) + { + if((c.Type == AceColumnType.CustomString) && + (c.CustomName == strCustomName)) + return c.HideWithAsterisks; + } + if(psValue != null) return psValue.IsProtected; + return false; + } + } + + public sealed class AceEntryView + { + public AceEntryView() + { + } + + private bool m_bShow = true; + [DefaultValue(true)] + public bool Show + { + get { return m_bShow; } + set { m_bShow = value; } + } + + // private bool m_bHideProtectedCustomStrings = true; + // [DefaultValue(true)] + // public bool HideProtectedCustomStrings + // { + // get { return m_bHideProtectedCustomStrings; } + // set { m_bHideProtectedCustomStrings = value; } + // } + } + + public sealed class AceTanView + { + public AceTanView() + { + } + + private bool m_bSimple = true; + [DefaultValue(true)] + public bool UseSimpleView + { + get { return m_bSimple; } + set { m_bSimple = value; } + } + + private bool m_bIndices = true; + [DefaultValue(true)] + public bool ShowIndices + { + get { return m_bIndices; } + set { m_bIndices = value; } + } + } + + public enum AceColumnType + { + Title = 0, + UserName, + Password, + Url, + Notes, + CreationTime, + LastModificationTime, + LastAccessTime, + ExpiryTime, + Uuid, + Attachment, + + CustomString, + + PluginExt, // Column data provided by a plugin + + OverrideUrl, + Tags, + ExpiryTimeDateOnly, + Size, + HistoryCount, + AttachmentCount, + LastPasswordModTime, + AutoTypeEnabled, + AutoTypeSequences, + + Count // Virtual identifier representing the number of types + } + + public sealed class AceColumn + { + private AceColumnType m_type = AceColumnType.Count; + public AceColumnType Type + { + get { return m_type; } + set + { + if(((int)value >= 0) && ((int)value < (int)AceColumnType.Count)) + m_type = value; + else { Debug.Assert(false); } + } + } + + private string m_strCustomName = string.Empty; + [DefaultValue("")] + public string CustomName + { + get { return m_strCustomName; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strCustomName = value; + } + } + + private int m_nWidth = -1; + public int Width + { + get { return m_nWidth; } + set { m_nWidth = value; } + } + + private bool m_bHide = false; + [DefaultValue(false)] + public bool HideWithAsterisks + { + get { return m_bHide; } + set { m_bHide = value; } + } + + public AceColumn() + { + } + + public AceColumn(AceColumnType t) + { + m_type = t; + } + + public AceColumn(AceColumnType t, string strCustomName, bool bHide, + int nWidth) + { + m_type = t; + m_strCustomName = strCustomName; + m_bHide = bHide; + m_nWidth = nWidth; + } + + public string GetDisplayName() + { + string str = string.Empty; + + switch(m_type) + { + case AceColumnType.Title: str = KPRes.Title; break; + case AceColumnType.UserName: str = KPRes.UserName; break; + case AceColumnType.Password: str = KPRes.Password; break; + case AceColumnType.Url: str = KPRes.Url; break; + case AceColumnType.Notes: str = KPRes.Notes; break; + case AceColumnType.CreationTime: str = KPRes.CreationTime; break; + case AceColumnType.LastModificationTime: str = KPRes.LastModificationTime; break; + case AceColumnType.LastAccessTime: str = KPRes.LastAccessTime; break; + case AceColumnType.ExpiryTime: str = KPRes.ExpiryTime; break; + case AceColumnType.Uuid: str = KPRes.Uuid; break; + case AceColumnType.Attachment: str = KPRes.Attachments; break; + case AceColumnType.CustomString: str = m_strCustomName; break; + case AceColumnType.PluginExt: str = m_strCustomName; break; + case AceColumnType.OverrideUrl: str = KPRes.UrlOverride; break; + case AceColumnType.Tags: str = KPRes.Tags; break; + case AceColumnType.ExpiryTimeDateOnly: str = KPRes.ExpiryTimeDateOnly; break; + case AceColumnType.Size: str = KPRes.Size; break; + case AceColumnType.HistoryCount: + str = KPRes.History + " (" + KPRes.Count + ")"; break; + case AceColumnType.AttachmentCount: + str = KPRes.Attachments + " (" + KPRes.Count + ")"; break; + case AceColumnType.LastPasswordModTime: str = KPRes.LastModTimePwHist; break; + case AceColumnType.AutoTypeEnabled: + str = KPRes.AutoType + " - " + KPRes.Enabled; break; + case AceColumnType.AutoTypeSequences: + str = KPRes.AutoType + " - " + KPRes.Sequences; break; + default: Debug.Assert(false); break; + }; + + return str; + } + + public int SafeGetWidth(int nDefaultWidth) + { + if(m_nWidth >= 0) return m_nWidth; + return nDefaultWidth; + } + + internal string GetTypeNameEx() + { + try + { + string str = m_type.ToString(); + + if(!string.IsNullOrEmpty(m_strCustomName)) + str += " - " + m_strCustomName; + + return str; + } + catch(Exception) { Debug.Assert(false); } + + return ((long)m_type).ToString(NumberFormatInfo.InvariantInfo); + } + +#if DEBUG + public override string ToString() + { + return (GetTypeNameEx() + ", Width: " + m_nWidth.ToString() + + ", Hide: " + m_bHide.ToString()); + } +#endif + + public static bool IsTimeColumn(AceColumnType t) + { + return ((t == AceColumnType.CreationTime) || + (t == AceColumnType.LastModificationTime) || + (t == AceColumnType.LastAccessTime) || + (t == AceColumnType.ExpiryTime) || + (t == AceColumnType.ExpiryTimeDateOnly) || + (t == AceColumnType.LastPasswordModTime)); + + /* bool bTime = false; + switch(t) + { + case AceColumnType.CreationTime: + case AceColumnType.LastModificationTime: + case AceColumnType.LastAccessTime: + case AceColumnType.ExpiryTime: + case AceColumnType.ExpiryTimeDateOnly: + case AceColumnType.LastPasswordModTime: + bTime = true; + break; + default: + break; + } + + return bTime; */ + } + + public static HorizontalAlignment GetTextAlign(AceColumnType t) + { + if((t == AceColumnType.Size) || (t == AceColumnType.HistoryCount) || + (t == AceColumnType.AttachmentCount)) + return HorizontalAlignment.Right; + + return HorizontalAlignment.Left; + } + } +} diff --git a/src/KeePass/App/Configuration/AceNative.cs b/src/KeePass/App/Configuration/AceNative.cs new file mode 100644 index 0000000..c137491 --- /dev/null +++ b/src/KeePass/App/Configuration/AceNative.cs @@ -0,0 +1,41 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; + +namespace KeePass.App.Configuration +{ + public sealed class AceNative + { + public AceNative() + { + } + + private bool m_bNativeKeyTrans = true; + [DefaultValue(true)] + public bool NativeKeyTransformations + { + get { return m_bNativeKeyTrans; } + set { m_bNativeKeyTrans = value; } + } + } +} diff --git a/src/KeePass/App/Configuration/AcePasswordGenerator.cs b/src/KeePass/App/Configuration/AcePasswordGenerator.cs new file mode 100644 index 0000000..70b1b04 --- /dev/null +++ b/src/KeePass/App/Configuration/AcePasswordGenerator.cs @@ -0,0 +1,69 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; + +using KeePassLib.Cryptography.PasswordGenerator; + +namespace KeePass.App.Configuration +{ + public sealed class AcePasswordGenerator + { + public AcePasswordGenerator() + { + } + + private PwProfile m_pwgoAutoProfile = new PwProfile(); + public PwProfile AutoGeneratedPasswordsProfile + { + get { return m_pwgoAutoProfile; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_pwgoAutoProfile = value; + } + } + + private PwProfile m_pwgoLastProfile = new PwProfile(); + public PwProfile LastUsedProfile + { + get { return m_pwgoLastProfile; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_pwgoLastProfile = value; + } + } + + private List m_vUserProfiles = new List(); + [XmlArrayItem("Profile")] + public List UserProfiles + { + get { return m_vUserProfiles; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_vUserProfiles = value; + } + } + } +} diff --git a/src/KeePass/App/Configuration/AceSearch.cs b/src/KeePass/App/Configuration/AceSearch.cs new file mode 100644 index 0000000..d08ecd7 --- /dev/null +++ b/src/KeePass/App/Configuration/AceSearch.cs @@ -0,0 +1,89 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Xml.Serialization; + +using KeePassLib; +using KeePassLib.Utility; + +namespace KeePass.App.Configuration +{ + public sealed class AceSearch + { + public AceSearch() + { + } + + private SearchParameters m_spLast = new SearchParameters(); + public SearchParameters LastUsedProfile + { + get { return m_spLast; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_spLast = value; + } + } + + private List m_lUserProfiles = new List(); + [XmlArrayItem("Profile")] + public List UserProfiles + { + get { return m_lUserProfiles; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_lUserProfiles = value; + } + } + + internal int FindProfileIndex(string strName) + { + for(int i = 0; i < m_lUserProfiles.Count; ++i) + { + if(m_lUserProfiles[i].Name == strName) return i; + } + + return -1; + } + + internal SearchParameters FindProfile(string strName) + { + int i = FindProfileIndex(strName); + return ((i >= 0) ? m_lUserProfiles[i] : null); + } + + internal void SortProfiles() + { + m_lUserProfiles.Sort(AceSearch.CompareProfilesByName); + } + + private static int CompareProfilesByName(SearchParameters spA, SearchParameters spB) + { + if(spA == null) { Debug.Assert(false); return ((spB == null) ? 0 : -1); } + if(spB == null) { Debug.Assert(false); return 1; } + + return StrUtil.CompareNaturally(spA.Name, spB.Name); + } + } +} diff --git a/src/KeePass/App/Configuration/AceSecurity.cs b/src/KeePass/App/Configuration/AceSecurity.cs new file mode 100644 index 0000000..2ebc85b --- /dev/null +++ b/src/KeePass/App/Configuration/AceSecurity.cs @@ -0,0 +1,274 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace KeePass.App.Configuration +{ + public sealed class AceSecurity + { + public AceSecurity() + { + } + + private AceWorkspaceLocking m_wsl = new AceWorkspaceLocking(); + public AceWorkspaceLocking WorkspaceLocking + { + get { return m_wsl; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_wsl = value; + } + } + + private AppPolicyFlags m_appPolicy = new AppPolicyFlags(); + public AppPolicyFlags Policy + { + get { return m_appPolicy; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_appPolicy = value; + } + } + + private AceMasterPassword m_mp = new AceMasterPassword(); + public AceMasterPassword MasterPassword + { + get { return m_mp; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_mp = value; + } + } + + private int m_nMasterKeyTries = 3; + [DefaultValue(3)] + public int MasterKeyTries + { + get { return m_nMasterKeyTries; } + set { m_nMasterKeyTries = value; } + } + + private bool m_bSecureDesktop = false; + [DefaultValue(false)] + public bool MasterKeyOnSecureDesktop + { + get { return m_bSecureDesktop; } + set { m_bSecureDesktop = value; } + } + + private string m_strMasterKeyExpiryRec = string.Empty; + [DefaultValue("")] + public string MasterKeyExpiryRec + { + get { return m_strMasterKeyExpiryRec; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strMasterKeyExpiryRec = value; + } + } + + private bool m_bClipClearOnExit = true; + [DefaultValue(true)] + public bool ClipboardClearOnExit + { + get { return m_bClipClearOnExit; } + set { m_bClipClearOnExit = value; } + } + + private int m_nClipClearSeconds = 12; + [DefaultValue(12)] + public int ClipboardClearAfterSeconds + { + get { return m_nClipClearSeconds; } + set { m_nClipClearSeconds = value; } + } + + private bool m_bClipNoPersist = true; + [DefaultValue(true)] + public bool ClipboardNoPersist + { + get { return m_bClipNoPersist; } + set { m_bClipNoPersist = value; } + } + + // The clipboard tools of old Office versions crash when + // storing the 'Clipboard Viewer Ignore' format using the + // OleSetClipboard function. + // Therefore, the default value of the option to use this + // format should be true if and only if KeePass uses the + // SetClipboardData function only (i.e. no OLE). + // Note that the .NET Framework and the UWP seem to use + // OLE internally. + private bool m_bUseClipboardViewerIgnoreFmt = true; + [DefaultValue(true)] + public bool UseClipboardViewerIgnoreFormat + { + get { return m_bUseClipboardViewerIgnoreFmt; } + set { m_bUseClipboardViewerIgnoreFmt = value; } + } + + private bool m_bClearKeyCmdLineOpt = true; + [DefaultValue(true)] + public bool ClearKeyCommandLineParams + { + get { return m_bClearKeyCmdLineOpt; } + set { m_bClearKeyCmdLineOpt = value; } + } + + private bool m_bSslCertsAcceptInvalid = false; + [DefaultValue(false)] + public bool SslCertsAcceptInvalid + { + get { return m_bSslCertsAcceptInvalid; } + set { m_bSslCertsAcceptInvalid = value; } + } + + // https://keepass.info/help/v2_dev/customize.html#opt + private bool m_bPreventScreenCapture = false; + [DefaultValue(false)] + public bool PreventScreenCapture + { + get { return m_bPreventScreenCapture; } + set { m_bPreventScreenCapture = value; } + } + + // https://keepass.info/help/v2_dev/customize.html#opt + private bool m_bProtectProcessWithDacl = false; + [DefaultValue(false)] + public bool ProtectProcessWithDacl + { + get { return m_bProtectProcessWithDacl; } + set { m_bProtectProcessWithDacl = value; } + } + } + + public sealed class AceWorkspaceLocking + { + public AceWorkspaceLocking() + { + } + + private bool m_bOnMinimize = false; + [DefaultValue(false)] + public bool LockOnWindowMinimize + { + get { return m_bOnMinimize; } + set { m_bOnMinimize = value; } + } + + private bool m_bOnMinimizeToTray = false; + [DefaultValue(false)] + public bool LockOnWindowMinimizeToTray + { + get { return m_bOnMinimizeToTray; } + set { m_bOnMinimizeToTray = value; } + } + + private bool m_bOnSessionSwitch = false; + [DefaultValue(false)] + public bool LockOnSessionSwitch + { + get { return m_bOnSessionSwitch; } + set { m_bOnSessionSwitch = value; } + } + + private bool m_bOnSuspend = false; + [DefaultValue(false)] + public bool LockOnSuspend + { + get { return m_bOnSuspend; } + set { m_bOnSuspend = value; } + } + + private bool m_bOnRemoteControlChange = false; + [DefaultValue(false)] + public bool LockOnRemoteControlChange + { + get { return m_bOnRemoteControlChange; } + set { m_bOnRemoteControlChange = value; } + } + + private uint m_uLockAfterTime = 0; + public uint LockAfterTime + { + get { return m_uLockAfterTime; } + set { m_uLockAfterTime = value; } + } + + private uint m_uLockAfterGlobalTime = 0; + public uint LockAfterGlobalTime + { + get { return m_uLockAfterGlobalTime; } + set { m_uLockAfterGlobalTime = value; } + } + + private bool m_bExitInsteadOfLockingAfterTime = false; + [DefaultValue(false)] + public bool ExitInsteadOfLockingAfterTime + { + get { return m_bExitInsteadOfLockingAfterTime; } + set { m_bExitInsteadOfLockingAfterTime = value; } + } + + private bool m_bAlwaysExitInsteadOfLocking = false; + [DefaultValue(false)] + public bool AlwaysExitInsteadOfLocking + { + get { return m_bAlwaysExitInsteadOfLocking; } + set { m_bAlwaysExitInsteadOfLocking = value; } + } + } + + public sealed class AceMasterPassword + { + public AceMasterPassword() + { + } + + private uint m_uMinLength = 0; + public uint MinimumLength + { + get { return m_uMinLength; } + set { m_uMinLength = value; } + } + + private uint m_uMinQuality = 0; + public uint MinimumQuality + { + get { return m_uMinQuality; } + set { m_uMinQuality = value; } + } + + private bool m_bRememberWhileOpen = true; + [DefaultValue(true)] + public bool RememberWhileOpen + { + get { return m_bRememberWhileOpen; } + set { m_bRememberWhileOpen = value; } + } + } +} diff --git a/src/KeePass/App/Configuration/AceToolBar.cs b/src/KeePass/App/Configuration/AceToolBar.cs new file mode 100644 index 0000000..1fe09a6 --- /dev/null +++ b/src/KeePass/App/Configuration/AceToolBar.cs @@ -0,0 +1,41 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; + +namespace KeePass.App.Configuration +{ + public sealed class AceToolBar + { + public AceToolBar() + { + } + + private bool m_bShow = true; + [DefaultValue(true)] + public bool Show + { + get { return m_bShow; } + set { m_bShow = value; } + } + } +} diff --git a/src/KeePass/App/Configuration/AceTrayIcon.cs b/src/KeePass/App/Configuration/AceTrayIcon.cs new file mode 100644 index 0000000..ba1c5c0 --- /dev/null +++ b/src/KeePass/App/Configuration/AceTrayIcon.cs @@ -0,0 +1,70 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Xml.Serialization; + +namespace KeePass.App.Configuration +{ + public sealed class AceTrayIcon + { + public AceTrayIcon() + { + } + + [Obsolete] // For backward compatibility with plugins only + [XmlIgnore] + public bool ShowOnlyIfTrayed + { + get { return this.ShowOnlyIfTrayedEx; } + // Old setting should not affect 'ShowOnlyIfTrayedEx'; + // a reset of this option is intended + set { } + } + + // Not available through the options dialog, see documentation; + // 'ShowOnlyIfTrayed' was used by KeePass <= 2.41 + private bool m_bOnlyIfTrayedEx = false; + [DefaultValue(false)] + public bool ShowOnlyIfTrayedEx + { + get { return m_bOnlyIfTrayedEx; } + set { m_bOnlyIfTrayedEx = value; } + } + + private bool m_bGrayIcon = false; + [DefaultValue(false)] + public bool GrayIcon + { + get { return m_bGrayIcon; } + set { m_bGrayIcon = value; } + } + + private bool m_bSingleClickDefault = false; + [DefaultValue(false)] + public bool SingleClickDefault + { + get { return m_bSingleClickDefault; } + set { m_bSingleClickDefault = value; } + } + } +} diff --git a/src/KeePass/App/Configuration/AceUI.cs b/src/KeePass/App/Configuration/AceUI.cs new file mode 100644 index 0000000..8d908bc --- /dev/null +++ b/src/KeePass/App/Configuration/AceUI.cs @@ -0,0 +1,584 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.Text; + +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib.Utility; + +namespace KeePass.App.Configuration +{ + [Flags] + public enum AceKeyUIFlags : ulong + { + None = 0, + EnablePassword = 0x1, + EnableKeyFile = 0x2, + EnableUserAccount = 0x4, + EnableHidePassword = 0x8, + DisablePassword = 0x100, + DisableKeyFile = 0x200, + DisableUserAccount = 0x400, + DisableHidePassword = 0x800, + CheckPassword = 0x10000, + CheckKeyFile = 0x20000, + CheckUserAccount = 0x40000, + CheckHidePassword = 0x80000, + UncheckPassword = 0x1000000, + UncheckKeyFile = 0x2000000, + UncheckUserAccount = 0x4000000, + UncheckHidePassword = 0x8000000 + } + + [Flags] + public enum AceUIFlags : ulong + { + None = 0, + + DisableOptions = 0x1, + DisablePlugins = 0x2, + DisableTriggers = 0x4, + DisableKeyChangeDays = 0x8, + HidePwQuality = 0x10, + DisableUpdateCheck = 0x20, + DisableXmlReplace = 0x40, + DisableDbSettings = 0x80, + + HideBuiltInPwGenPrfInEntryDlg = 0x10000, + ShowLastAccessTime = 0x20000, + HideNewDbInfoDialogs = 0x40000, + HideAutoTypeObfInfo = 0x80000, + NoQuickSearchClear = 0x100000, + SecureDesktopIme = 0x200000 + } + + [Flags] + public enum AceAutoTypeCtxFlags : long + { + None = 0, + + ColTitle = 0x1, + ColUserName = 0x2, + ColPassword = 0x4, + ColUrl = 0x8, + ColNotes = 0x10, + ColSequence = 0x20, + ColSequenceComments = 0x40, + + Default = (ColTitle | ColUserName | ColUrl | ColSequence) + } + + public sealed class AceUI + { + public AceUI() + { + } + + private AceTrayIcon m_tray = new AceTrayIcon(); + public AceTrayIcon TrayIcon + { + get { return m_tray; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_tray = value; + } + } + + private AceHiding m_uiHiding = new AceHiding(); + public AceHiding Hiding + { + get { return m_uiHiding; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_uiHiding = value; + } + } + + private bool m_bRepeatPwOnlyWhenHidden = true; + [DefaultValue(true)] + public bool RepeatPasswordOnlyWhenHidden + { + get { return m_bRepeatPwOnlyWhenHidden; } + set { m_bRepeatPwOnlyWhenHidden = value; } + } + + private AceFont m_font = new AceFont(); + public AceFont StandardFont + { + get { return m_font; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_font = value; + } + } + + private AceFont m_fontPasswords = new AceFont(true); + public AceFont PasswordFont + { + get { return m_fontPasswords; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_fontPasswords = value; + } + } + + private bool m_bForceSysFont = true; + [DefaultValue(true)] + public bool ForceSystemFontUnix + { + get { return m_bForceSysFont; } + set { m_bForceSysFont = value; } + } + + private BannerStyle m_bannerStyle = BannerStyle.WinVistaBlack; + public BannerStyle BannerStyle + { + get { return m_bannerStyle; } + set { m_bannerStyle = value; } + } + + private bool m_bShowImportStatusDlg = false; + [DefaultValue(false)] + public bool ShowImportStatusDialog + { + get { return m_bShowImportStatusDlg; } + set { m_bShowImportStatusDlg = value; } + } + + private bool m_bShowRecycleDlg = true; + [DefaultValue(true)] + public bool ShowRecycleConfirmDialog + { + get { return m_bShowRecycleDlg; } + set { m_bShowRecycleDlg = value; } + } + + private bool m_bShowDbMntncResDlg = true; + [DefaultValue(true)] + public bool ShowDbMntncResultsDialog + { + get { return m_bShowDbMntncResDlg; } + set { m_bShowDbMntncResDlg = value; } + } + + private bool m_bShowEmSheetDlg = true; + [DefaultValue(true)] + public bool ShowEmSheetDialog + { + get { return m_bShowEmSheetDlg; } + set { m_bShowEmSheetDlg = value; } + } + + private bool m_bShowDbOpenUnkVerDlg = true; + [DefaultValue(true)] + public bool ShowDbOpenUnkVerDialog + { + get { return m_bShowDbOpenUnkVerDlg; } + set { m_bShowDbOpenUnkVerDlg = value; } + } + + // private bool m_bUseCustomTsRenderer = true; + // [DefaultValue(true)] + // public bool UseCustomToolStripRenderer + // { + // get { return m_bUseCustomTsRenderer; } + // set { m_bUseCustomTsRenderer = value; } + // } + + private string m_strToolStripRenderer = string.Empty; + [DefaultValue("")] + public string ToolStripRenderer + { + get { return m_strToolStripRenderer; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strToolStripRenderer = value; + } + } + + private bool m_bTreeViewShowLines = false; + [DefaultValue(false)] + public bool TreeViewShowLines + { + get { return m_bTreeViewShowLines; } + set { m_bTreeViewShowLines = value; } + } + + private bool m_bOptScreenReader = false; + [DefaultValue(false)] + public bool OptimizeForScreenReader + { + get { return m_bOptScreenReader; } + set { m_bOptScreenReader = value; } + } + + private string m_strDataViewerRect = string.Empty; + [DefaultValue("")] + public string DataViewerRect + { + get { return m_strDataViewerRect; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strDataViewerRect = value; + } + } + + private string m_strDataEditorRect = string.Empty; + [DefaultValue("")] + public string DataEditorRect + { + get { return m_strDataEditorRect; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strDataEditorRect = value; + } + } + + private AceFont m_deFont = new AceFont(); + public AceFont DataEditorFont + { + get { return m_deFont; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_deFont = value; + } + } + + private bool m_bDeWordWrap = true; + [DefaultValue(true)] + public bool DataEditorWordWrap + { + get { return m_bDeWordWrap; } + set { m_bDeWordWrap = value; } + } + + private string m_strCharPickerRect = string.Empty; + [DefaultValue("")] + public string CharPickerRect + { + get { return m_strCharPickerRect; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strCharPickerRect = value; + } + } + + private string m_strAutoTypeCtxRect = string.Empty; + [DefaultValue("")] + public string AutoTypeCtxRect + { + get { return m_strAutoTypeCtxRect; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strAutoTypeCtxRect = value; + } + } + + private long m_lAutoTypeCtxFlags = (long)AceAutoTypeCtxFlags.Default; + [DefaultValue((long)AceAutoTypeCtxFlags.Default)] + public long AutoTypeCtxFlags + { + get { return m_lAutoTypeCtxFlags; } + set { m_lAutoTypeCtxFlags = value; } + } + + private string m_strAutoTypeCtxColWidths = string.Empty; + [DefaultValue("")] + public string AutoTypeCtxColumnWidths + { + get { return m_strAutoTypeCtxColWidths; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strAutoTypeCtxColWidths = value; + } + } + + private ulong m_uUIFlags = (ulong)AceUIFlags.None; + public ulong UIFlags + { + get { return m_uUIFlags; } + set { m_uUIFlags = value; } + } + + private ulong m_uKeyCreationFlags = (ulong)AceKeyUIFlags.None; + public ulong KeyCreationFlags + { + get { return m_uKeyCreationFlags; } + set { m_uKeyCreationFlags = value; } + } + + private ulong m_uKeyPromptFlags = (ulong)AceKeyUIFlags.None; + public ulong KeyPromptFlags + { + get { return m_uKeyPromptFlags; } + set { m_uKeyPromptFlags = value; } + } + + // private bool m_bEditCancelConfirmation = true; + // public bool EntryEditCancelConfirmation + // { + // get { return m_bEditCancelConfirmation; } + // set { m_bEditCancelConfirmation = value; } + // } + + private bool m_bAdvATCmds = false; + [DefaultValue(false)] + public bool ShowAdvAutoTypeCommands + { + get { return m_bAdvATCmds; } + set { m_bAdvATCmds = value; } + } + + private bool m_bSecDeskSound = true; + [DefaultValue(true)] + public bool SecureDesktopPlaySound + { + get { return m_bSecDeskSound; } + set { m_bSecDeskSound = value; } + } + } + + public sealed class AceHiding + { + public AceHiding() + { + } + + private bool m_bRememberHidePwsMain = true; + [DefaultValue(true)] + public bool RememberHidingPasswordsMain + { + get { return m_bRememberHidePwsMain; } + set { m_bRememberHidePwsMain = value; } + } + + private bool m_bSepHiding = false; + [DefaultValue(false)] + public bool SeparateHidingSettings + { + get { return m_bSepHiding; } + set { m_bSepHiding = value; } + } + + private bool m_bHideInEntryDialog = true; + [DefaultValue(true)] + public bool HideInEntryWindow + { + get { return m_bHideInEntryDialog; } + set { m_bHideInEntryDialog = value; } + } + + private bool m_bUnhideBtnAlsoUnhidesSec = false; + [DefaultValue(false)] + public bool UnhideButtonAlsoUnhidesSource + { + get { return m_bUnhideBtnAlsoUnhidesSec; } + set { m_bUnhideBtnAlsoUnhidesSec = value; } + } + } + + public sealed class AceFont + { + private Font m_fCached = null; + private bool m_bCacheValid = false; + + private string m_strFamily = "Microsoft Sans Serif"; + public string Family + { + get { return m_strFamily; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strFamily = value; + m_bCacheValid = false; + } + } + + private float m_fSize = 8.25f; + public float Size + { + get { return m_fSize; } + set { m_fSize = value; m_bCacheValid = false; } + } + + private GraphicsUnit m_gu = GraphicsUnit.Point; + public GraphicsUnit GraphicsUnit + { + get { return m_gu; } + set { m_gu = value; m_bCacheValid = false; } + } + + private FontStyle m_fs = FontStyle.Regular; + [DefaultValue(FontStyle.Regular)] + public FontStyle Style + { + get { return m_fs; } + set { m_fs = value; m_bCacheValid = false; } + } + + private bool m_bOverrideUIDefault = false; + public bool OverrideUIDefault + { + get { return m_bOverrideUIDefault; } + set { m_bOverrideUIDefault = value; } + } + + public AceFont() + { + } + + public AceFont(Font f) : this(f, false) + { + } + + internal AceFont(Font f, bool bOverrideUIDefault) + { + if(f == null) throw new ArgumentNullException("f"); + + this.Family = f.FontFamily.Name; + m_fSize = f.Size; + m_gu = f.Unit; + m_fs = f.Style; + + m_bOverrideUIDefault = bOverrideUIDefault; + } + + public AceFont(bool bMonospace) + { + if(bMonospace) m_strFamily = "Courier New"; + } + + internal AceFont CloneDeep() + { + return (AceFont)MemberwiseClone(); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + if(string.IsNullOrEmpty(m_strFamily)) + { + sb.Append('('); + sb.Append(KPRes.None); + sb.Append(')'); + } + else sb.Append(m_strFamily); + + sb.Append(", "); + sb.Append(Math.Round(m_fSize)); // 8.25, 9, 9.75, 11.25, 12, ... + sb.Append(' '); + sb.Append(GfxUtil.GraphicsUnitToString(m_gu)); + + string strStyle = FontUtil.FontStyleToString(m_fs); + if(!string.IsNullOrEmpty(strStyle)) + { + sb.Append(", "); + sb.Append(strStyle); + } + + return sb.ToString(); + } + + public Font ToFont() + { + if(m_bCacheValid) return m_fCached; + + m_fCached = FontUtil.CreateFont(m_strFamily, m_fSize, m_fs, m_gu); + m_bCacheValid = true; + return m_fCached; + } + + private static void AppendCss(StringBuilder sb, string strIndent, + string strProperty, params string[] vValueParts) + { + sb.Append(strIndent); + sb.Append(strProperty); + sb.Append(": "); + + for(int i = 0; i < vValueParts.Length; ++i) + sb.Append(vValueParts[i]); // Without separator space + + sb.AppendLine(";"); + } + + internal string ToCss(string strIndent, string strFamilyFallback, + bool bWithDefaults) + { + if(strIndent == null) { Debug.Assert(false); strIndent = string.Empty; } + + StringBuilder sb = new StringBuilder(); + NumberFormatInfo nfi = NumberFormatInfo.InvariantInfo; + + string strFamily = string.Empty; + if(!string.IsNullOrEmpty(m_strFamily)) + strFamily = "\"" + StrUtil.CssEscapeString(m_strFamily) + "\""; + else { Debug.Assert(false); } + if(!string.IsNullOrEmpty(strFamilyFallback)) + strFamily += ((strFamily.Length != 0) ? ", " : string.Empty) + + strFamilyFallback; + if(strFamily.Length != 0) + AppendCss(sb, strIndent, "font-family", strFamily); + + AppendCss(sb, strIndent, "font-size", m_fSize.ToString(nfi), + GfxUtil.GraphicsUnitToString(m_gu)); + + if((m_fs & FontStyle.Bold) != FontStyle.Regular) + AppendCss(sb, strIndent, "font-weight", "bold"); + else if(bWithDefaults) + AppendCss(sb, strIndent, "font-weight", "normal"); + + if((m_fs & FontStyle.Italic) != FontStyle.Regular) + AppendCss(sb, strIndent, "font-style", "italic"); + else if(bWithDefaults) + AppendCss(sb, strIndent, "font-style", "normal"); + + const FontStyle fsUS = FontStyle.Underline | FontStyle.Strikeout; + if((m_fs & fsUS) == fsUS) + AppendCss(sb, strIndent, "text-decoration", "underline line-through"); + else if((m_fs & FontStyle.Underline) != FontStyle.Regular) + AppendCss(sb, strIndent, "text-decoration", "underline"); + else if((m_fs & FontStyle.Strikeout) != FontStyle.Regular) + AppendCss(sb, strIndent, "text-decoration", "line-through"); + else if(bWithDefaults) + AppendCss(sb, strIndent, "text-decoration", "none"); + + return sb.ToString(); + } + } +} diff --git a/src/KeePass/App/Configuration/AppConfigEx.cs b/src/KeePass/App/Configuration/AppConfigEx.cs new file mode 100644 index 0000000..85a8ad7 --- /dev/null +++ b/src/KeePass/App/Configuration/AppConfigEx.cs @@ -0,0 +1,797 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Reflection; +using System.Text; +using System.Windows.Forms; +using System.Xml; +using System.Xml.Serialization; + +using KeePass.UI; +using KeePass.Util; +using KeePass.Util.XmlSerialization; + +using KeePassLib; +using KeePassLib.Delegates; +using KeePassLib.Native; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.App.Configuration +{ + [XmlType(AppConfigEx.StrXmlTypeName)] + public sealed class AppConfigEx + { + internal const string StrXmlTypeName = "Configuration"; + + private string m_strSearchString = null; + + public AppConfigEx() + { + } + +#if DEBUG + ~AppConfigEx() + { + Debug.Assert(m_strSearchString == null); + } +#endif + + private AceMeta m_meta = null; + public AceMeta Meta + { + get + { + if(m_meta == null) m_meta = new AceMeta(); + return m_meta; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_meta = value; + } + } + + private AceApplication m_aceApp = null; + public AceApplication Application + { + get + { + if(m_aceApp == null) m_aceApp = new AceApplication(); + return m_aceApp; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_aceApp = value; + } + } + + private AceLogging m_aceLogging = null; + public AceLogging Logging + { + get + { + if(m_aceLogging == null) m_aceLogging = new AceLogging(); + return m_aceLogging; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_aceLogging = value; + } + } + + private AceMainWindow m_uiMainWindow = null; + public AceMainWindow MainWindow + { + get + { + if(m_uiMainWindow == null) m_uiMainWindow = new AceMainWindow(); + return m_uiMainWindow; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_uiMainWindow = value; + } + } + + private AceUI m_aceUI = null; + public AceUI UI + { + get + { + if(m_aceUI == null) m_aceUI = new AceUI(); + return m_aceUI; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_aceUI = value; + } + } + + private AceSecurity m_sec = null; + public AceSecurity Security + { + get + { + if(m_sec == null) m_sec = new AceSecurity(); + return m_sec; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_sec = value; + } + } + + private AceNative m_native = null; + public AceNative Native + { + get + { + if(m_native == null) m_native = new AceNative(); + return m_native; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_native = value; + } + } + + private AcePasswordGenerator m_pwGen = null; + public AcePasswordGenerator PasswordGenerator + { + get + { + if(m_pwGen == null) m_pwGen = new AcePasswordGenerator(); + return m_pwGen; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_pwGen = value; + } + } + + private AceSearch m_aceSearch = null; + public AceSearch Search + { + get + { + if(m_aceSearch == null) m_aceSearch = new AceSearch(); + return m_aceSearch; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_aceSearch = value; + } + } + + private AceDefaults m_def = null; + public AceDefaults Defaults + { + get + { + if(m_def == null) m_def = new AceDefaults(); + return m_def; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_def = value; + } + } + + private AceIntegration m_int = null; + public AceIntegration Integration + { + get + { + if(m_int == null) m_int = new AceIntegration(); + return m_int; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_int = value; + } + } + + private AceCustomConfig m_cc = null; + [XmlIgnore] + public AceCustomConfig CustomConfig + { + get + { + if(m_cc == null) m_cc = new AceCustomConfig(); + return m_cc; + } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_cc = value; + } + } + + [XmlArray("Custom")] + [XmlArrayItem("Item")] + public AceKvp[] CustomSerialized + { + get + { + return this.CustomConfig.Serialize(); // m_cc might be null + } + set + { + if(value == null) throw new ArgumentNullException("value"); + this.CustomConfig.Deserialize(value); // m_cc might be null + } + } + + /// + /// Prepare for saving the configuration to disk. None of the + /// modifications in this method need to be rolled back + /// (for rollback, use OnSavePre / OnSavePost). + /// + private void PrepareSave() + { + AceMeta aceMeta = this.Meta; // m_meta might be null + AceApplication aceApp = this.Application; // m_aceApp might be null + AceSearch aceSearch = this.Search; // m_aceSearch might be null + AceDefaults aceDef = this.Defaults; // m_def might be null + + aceMeta.OmitItemsWithDefaultValues = true; + aceMeta.DpiFactorX = DpiUtil.FactorX; // For new (not loaded) cfgs. + aceMeta.DpiFactorY = DpiUtil.FactorY; + + aceApp.LastUsedFile.ClearCredentials(true); + + foreach(IOConnectionInfo iocMru in aceApp.MostRecentlyUsed.Items) + iocMru.ClearCredentials(true); + + if(!aceDef.RememberKeySources) aceDef.KeySources.Clear(); + + aceApp.TriggerSystem = Program.TriggerSystem; + + SearchUtil.PrepareForSerialize(aceSearch.LastUsedProfile); + foreach(SearchParameters sp in aceSearch.UserProfiles) + SearchUtil.PrepareForSerialize(sp); + + const int m = 64; // Maximum number of compatibility items + List l = aceApp.PluginCompatibility; + if(l.Count > m) l.RemoveRange(m, l.Count - m); // See reg. + } + + internal void OnLoad() + { + AceMainWindow aceMW = this.MainWindow; // m_uiMainWindow might be null + AceSearch aceSearch = this.Search; // m_aceSearch might be null + AceDefaults aceDef = this.Defaults; // m_def might be null + + // aceInt.UrlSchemeOverrides.SetDefaultsIfEmpty(); + + ObfuscateCred(false); + ChangePathsRelAbs(true); + + // Remove invalid columns + List lColumns = aceMW.EntryListColumns; + int i = 0; + while(i < lColumns.Count) + { + if(((int)lColumns[i].Type < 0) || ((int)lColumns[i].Type >= + (int)AceColumnType.Count)) + lColumns.RemoveAt(i); + else ++i; + } + + SearchUtil.FinishDeserialize(aceSearch.LastUsedProfile); + foreach(SearchParameters sp in aceSearch.UserProfiles) + SearchUtil.FinishDeserialize(sp); + + DpiScale(); + + if(aceMW.EscMinimizesToTray) // For backward compatibility + { + aceMW.EscMinimizesToTray = false; // Default value + aceMW.EscAction = AceEscAction.MinimizeToTray; + } + + if(NativeLib.IsUnix()) + { + this.Security.MasterKeyOnSecureDesktop = false; + + AceIntegration aceInt = this.Integration; + aceInt.HotKeyGlobalAutoType = (long)Keys.None; + aceInt.HotKeyGlobalAutoTypePassword = (long)Keys.None; + aceInt.HotKeySelectedAutoType = (long)Keys.None; + aceInt.HotKeyShowWindow = (long)Keys.None; + aceInt.HotKeyEntryMenu = (long)Keys.None; + } + + if(MonoWorkarounds.IsRequired(1378)) + { + AceWorkspaceLocking aceWL = this.Security.WorkspaceLocking; + aceWL.LockOnSessionSwitch = false; + aceWL.LockOnSuspend = false; + aceWL.LockOnRemoteControlChange = false; + } + + if(MonoWorkarounds.IsRequired(1418)) + { + aceMW.MinimizeAfterOpeningDatabase = false; + this.Application.Start.MinimizedAndLocked = false; + } + + if(MonoWorkarounds.IsRequired(1976)) + { + aceMW.FocusQuickFindOnRestore = false; + aceMW.FocusQuickFindOnUntray = false; + } + } + + internal void OnSavePre() + { + PrepareSave(); + + ChangePathsRelAbs(false); + ObfuscateCred(true); + RemoveSensitiveInfo(true); + } + + internal void OnSavePost() + { + RemoveSensitiveInfo(false); + ObfuscateCred(false); + ChangePathsRelAbs(true); + } + + private void ChangePathsRelAbs(bool bMakeAbsolute) + { + AceApplication aceApp = this.Application; // m_aceApp might be null + AceDefaults aceDef = this.Defaults; // m_def might be null + + ChangePathRelAbs(aceApp.LastUsedFile, bMakeAbsolute); + + foreach(IOConnectionInfo iocMru in aceApp.MostRecentlyUsed.Items) + ChangePathRelAbs(iocMru, bMakeAbsolute); + + List lWDKeys = aceApp.GetWorkingDirectoryContexts(); + foreach(string strWDKey in lWDKeys) + aceApp.SetWorkingDirectory(strWDKey, ChangePathRelAbsStr( + aceApp.GetWorkingDirectory(strWDKey), bMakeAbsolute)); + + foreach(AceKeyAssoc kfp in aceDef.KeySources) + { + kfp.DatabasePath = ChangePathRelAbsStr(kfp.DatabasePath, bMakeAbsolute); + kfp.KeyFilePath = ChangePathRelAbsStr(kfp.KeyFilePath, bMakeAbsolute); + } + } + + private static void ChangePathRelAbs(IOConnectionInfo ioc, bool bMakeAbsolute) + { + if(ioc == null) { Debug.Assert(false); return; } + + if(!ioc.IsLocalFile()) return; + + // Update path separators for current system + ioc.Path = UrlUtil.ConvertSeparators(ioc.Path); + + string strBase = WinUtil.GetExecutable(); + bool bIsAbs = UrlUtil.IsAbsolutePath(ioc.Path); + + if(bMakeAbsolute && !bIsAbs) + ioc.Path = UrlUtil.MakeAbsolutePath(strBase, ioc.Path); + else if(!bMakeAbsolute && bIsAbs) + ioc.Path = UrlUtil.MakeRelativePath(strBase, ioc.Path); + } + + private static string ChangePathRelAbsStr(string strPath, bool bMakeAbsolute) + { + if(strPath == null) { Debug.Assert(false); return string.Empty; } + if(strPath.Length == 0) return strPath; + + IOConnectionInfo ioc = IOConnectionInfo.FromPath(strPath); + ChangePathRelAbs(ioc, bMakeAbsolute); + return ioc.Path; + } + + private void ObfuscateCred(bool bObf) + { + AceApplication aceApp = this.Application; // m_aceApp might be null + AceIntegration aceInt = this.Integration; // m_int might be null + + if(aceApp.LastUsedFile == null) { Debug.Assert(false); } + else aceApp.LastUsedFile.Obfuscate(bObf); + + foreach(IOConnectionInfo iocMru in aceApp.MostRecentlyUsed.Items) + { + if(iocMru == null) { Debug.Assert(false); } + else iocMru.Obfuscate(bObf); + } + + if(bObf) aceInt.ProxyUserName = StrUtil.Obfuscate(aceInt.ProxyUserName); + else aceInt.ProxyUserName = StrUtil.Deobfuscate(aceInt.ProxyUserName); + + if(bObf) aceInt.ProxyPassword = StrUtil.Obfuscate(aceInt.ProxyPassword); + else aceInt.ProxyPassword = StrUtil.Deobfuscate(aceInt.ProxyPassword); + } + + private void RemoveSensitiveInfo(bool bRemove) + { + SearchParameters sp = this.Search.LastUsedProfile; + + if(bRemove) + { + Debug.Assert(m_strSearchString == null); + m_strSearchString = sp.SearchString; + sp.SearchString = string.Empty; + } + else + { + if(m_strSearchString != null) + { + sp.SearchString = m_strSearchString; + m_strSearchString = null; + } + else { Debug.Assert(false); } + } + } + + private void DpiScale() + { + AceMeta aceMeta = this.Meta; // m_meta might be null + double dCfgX = aceMeta.DpiFactorX, dCfgY = aceMeta.DpiFactorY; + double dScrX = DpiUtil.FactorX, dScrY = DpiUtil.FactorY; + + if((dScrX == dCfgX) && (dScrY == dCfgY)) return; + + // When this method returns, all positions and sizes are in pixels + // for the current screen DPI + aceMeta.DpiFactorX = dScrX; + aceMeta.DpiFactorY = dScrY; + + // Backward compatibility; configuration files created by KeePass + // 2.37 and earlier do not contain DpiFactor* values, they default + // to 0.0 and all positions and sizes are in pixels for the current + // screen DPI; so, do not perform any DPI scaling in this case + if((dCfgX == 0.0) || (dCfgY == 0.0)) return; + + double sX = dScrX / dCfgX, sY = dScrY / dCfgY; + GFunc fX = delegate(int x) + { + return (int)Math.Round((double)x * sX); + }; + GFunc fY = delegate(int y) + { + return (int)Math.Round((double)y * sY); + }; + GFunc fWsr = delegate(string strRect) + { + return UIUtil.ScaleWindowScreenRect(strRect, sX, sY); + }; + GFunc fVX = delegate(string strArray) + { + if(string.IsNullOrEmpty(strArray)) return strArray; + + try + { + int[] v = StrUtil.DeserializeIntArray(strArray); + if(v == null) { Debug.Assert(false); return strArray; } + + for(int i = 0; i < v.Length; ++i) + v[i] = (int)Math.Round((double)v[i] * sX); + + return StrUtil.SerializeIntArray(v); + } + catch(Exception) { Debug.Assert(false); } + + return strArray; + }; + Action fFont = delegate(AceFont f) + { + if(f == null) { Debug.Assert(false); return; } + + if(f.GraphicsUnit == GraphicsUnit.Pixel) + f.Size = (float)(f.Size * sY); + }; + + AceMainWindow mw = this.MainWindow; + AceUI ui = this.UI; + + if(mw.X != AppDefs.InvalidWindowValue) mw.X = fX(mw.X); + if(mw.Y != AppDefs.InvalidWindowValue) mw.Y = fY(mw.Y); + if(mw.Width != AppDefs.InvalidWindowValue) mw.Width = fX(mw.Width); + if(mw.Height != AppDefs.InvalidWindowValue) mw.Height = fY(mw.Height); + + foreach(AceColumn c in mw.EntryListColumns) + { + if(c.Width >= 0) c.Width = fX(c.Width); + } + + ui.DataViewerRect = fWsr(ui.DataViewerRect); + ui.DataEditorRect = fWsr(ui.DataEditorRect); + ui.CharPickerRect = fWsr(ui.CharPickerRect); + ui.AutoTypeCtxRect = fWsr(ui.AutoTypeCtxRect); + ui.AutoTypeCtxColumnWidths = fVX(ui.AutoTypeCtxColumnWidths); + + fFont(ui.StandardFont); + fFont(ui.PasswordFont); + fFont(ui.DataEditorFont); + } + + private static Dictionary m_dictXmlPathCache = + new Dictionary(); + public static bool IsOptionEnforced(object pContainer, PropertyInfo pi) + { + if(pContainer == null) { Debug.Assert(false); return false; } + if(pi == null) { Debug.Assert(false); return false; } + + XmlDocument xdEnforced = AppConfigSerializer.EnforcedConfigXml; + if(xdEnforced == null) return false; + + string strObjPath; + if(!m_dictXmlPathCache.TryGetValue(pContainer, out strObjPath)) + { + strObjPath = XmlUtil.GetObjectXmlPath(Program.Config, pContainer); + if(string.IsNullOrEmpty(strObjPath)) { Debug.Assert(false); return false; } + + m_dictXmlPathCache[pContainer] = strObjPath; + } + + string strProp = XmlSerializerEx.GetXmlName(pi); + if(string.IsNullOrEmpty(strProp)) { Debug.Assert(false); return false; } + + string strPre = strObjPath; + if(!strPre.EndsWith("/")) strPre += "/"; + string strXPath = strPre + strProp; + + XmlNode xn = xdEnforced.SelectSingleNode(strXPath); + if(xn == null) return false; + + XmContext ctx = new XmContext(null, AppConfigEx.GetNodeOptions, + AppConfigEx.GetNodeKey); + return XmlUtil.IsAlwaysEnforced(xn, strXPath, ctx); + } + + public static bool IsOptionEnforced(object pContainer, string strPropertyName) + { + if(pContainer == null) { Debug.Assert(false); return false; } + if(string.IsNullOrEmpty(strPropertyName)) { Debug.Assert(false); return false; } + + // To improve performance (avoid type queries), check here, too + XmlDocument xdEnforced = AppConfigSerializer.EnforcedConfigXml; + if(xdEnforced == null) return false; + + Type tContainer = pContainer.GetType(); + PropertyInfo pi = tContainer.GetProperty(strPropertyName); + return IsOptionEnforced(pContainer, pi); + } + + public static void ClearXmlPathCache() + { + m_dictXmlPathCache.Clear(); + } + + public void Apply(AceApplyFlags f) + { + AceApplication aceApp = this.Application; // m_aceApp might be null + AceSecurity aceSec = this.Security; // m_sec might be null + AceIntegration aceInt = this.Integration; // m_int might be null + + if((f & AceApplyFlags.Proxy) != AceApplyFlags.None) + IOConnection.SetProxy(aceInt.ProxyType, aceInt.ProxyAddress, + aceInt.ProxyPort, aceInt.ProxyAuthType, aceInt.ProxyUserName, + aceInt.ProxyPassword); + + if((f & AceApplyFlags.Ssl) != AceApplyFlags.None) + IOConnection.SslCertsAcceptInvalid = aceSec.SslCertsAcceptInvalid; + + if((f & AceApplyFlags.FileTransactions) != AceApplyFlags.None) + FileTransactionEx.ExtraSafe = aceApp.FileTxExtra; + } + + internal static void GetNodeOptions(XmNodeOptions o, string strXPath) + { + if(o == null) { Debug.Assert(false); return; } + if(string.IsNullOrEmpty(strXPath)) { Debug.Assert(false); return; } + Debug.Assert(strXPath.IndexOf('[') < 0); + + switch(strXPath) + { + // Sync. with documentation + + case "/Configuration/Application/PluginCompatibility": + case "/Configuration/Meta/DpiFactorX": + case "/Configuration/Meta/DpiFactorY": + o.NodeMode = XmNodeMode.None; + break; + + case "/Configuration/Application/TriggerSystem/Triggers/Trigger": + case "/Configuration/Defaults/KeySources/Association": + case "/Configuration/PasswordGenerator/AutoGeneratedPasswordsProfile": + case "/Configuration/PasswordGenerator/LastUsedProfile": + case "/Configuration/PasswordGenerator/UserProfiles/Profile": + case "/Configuration/Search/LastUsedProfile": + case "/Configuration/Search/UserProfiles/Profile": + o.ContentMode = XmContentMode.Replace; + break; + + // Nodes that do not have child elements: + // case "/Configuration/Application/WorkingDirectories/Item": + // case "/Configuration/Integration/AutoTypeAbortOnWindows/Window": + + // Nodes where the mode 'Merge' may be more useful: + // case "/Configuration/Application/MostRecentlyUsed/Items/ConnectionInfo": + // (allow users to save credentials) + // case "/Configuration/Custom/Item": + // (empty Value explicitly only) + // case "/Configuration/Defaults/SearchParameters": + // (admin might only want to turn off case-sensitivity) + // case "/Configuration/Integration/UrlSchemeOverrides/CustomOverrides/Override": + // (allow users to enable/disable the item) + // case "/Configuration/MainWindow/EntryListColumnCollection/Column": + // (allow users to change the width) + + default: break; + } + } + + internal static string GetNodeKey(XmlNode xn, string strXPath) + { + if(xn == null) { Debug.Assert(false); return null; } + if(string.IsNullOrEmpty(strXPath)) { Debug.Assert(false); return null; } + + Debug.Assert(xn is XmlElement); + Debug.Assert((strXPath == xn.Name) || strXPath.EndsWith("/" + xn.Name)); + Debug.Assert(strXPath.IndexOf('[') < 0); + + string strA = null, strB = null; + switch(strXPath) + { + // Sync. with documentation + + case "/Configuration/Application/PluginCompatibility/Item": + case "/Configuration/Application/WorkingDirectories/Item": + case "/Configuration/Integration/AutoTypeAbortOnWindows/Window": + strA = XmlUtil.SafeInnerXml(xn); + break; + + case "/Configuration/Application/MostRecentlyUsed/Items/ConnectionInfo": + strA = XmlUtil.SafeInnerXml(xn, "Path"); + strB = XmlUtil.SafeInnerXml(xn, "UserName"); // Cf. MRU display name + break; + + case "/Configuration/Application/TriggerSystem/Triggers/Trigger": + strA = XmlUtil.SafeInnerXml(xn, "Guid"); + break; + + case "/Configuration/Custom/Item": + strA = XmlUtil.SafeInnerXml(xn, "Key"); + break; + + case "/Configuration/Defaults/KeySources/Association": + strA = XmlUtil.SafeInnerXml(xn, "DatabasePath"); + break; + + case "/Configuration/Integration/UrlSchemeOverrides/CustomOverrides/Override": + strA = XmlUtil.SafeInnerXml(xn, "Scheme"); + strB = XmlUtil.SafeInnerXml(xn, "UrlOverride"); + break; + + case "/Configuration/MainWindow/EntryListColumnCollection/Column": + strA = XmlUtil.SafeInnerXml(xn, "Type"); + strB = XmlUtil.SafeInnerXml(xn, "CustomName"); + break; + + case "/Configuration/PasswordGenerator/UserProfiles/Profile": + case "/Configuration/Search/UserProfiles/Profile": + strA = XmlUtil.SafeInnerXml(xn, "Name"); + break; + + default: break; + } + + Debug.Assert((strA == null) || (strA.IndexOf('<') < 0)); + Debug.Assert((strB == null) || (strB.IndexOf('<') < 0)); + Debug.Assert((strB == null) || (strA != null)); // B => A + Debug.Assert((strA == null) || (strA.Length != 0)); + + if(strB != null) return ((strA ?? string.Empty) + " <> " + strB); + return strA; + } + + internal static string GetEmptyConfigXml() + { + return ("\r\n" + + "<" + StrXmlTypeName + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\r\n" + + "\t\r\n" + + ""); + } + } + + [Flags] + public enum AceApplyFlags + { + None = 0, + Proxy = 0x1, + Ssl = 0x2, + FileTransactions = 0x4, + + All = 0x7FFF + } + + public sealed class AceMeta + { + public AceMeta() + { + } + + private bool m_bPrefLocalCfg = false; + public bool PreferUserConfiguration + { + get { return m_bPrefLocalCfg; } + set { m_bPrefLocalCfg = value; } + } + + // private bool m_bIsEnforced = false; + // [XmlIgnore] + // public bool IsEnforcedConfiguration + // { + // get { return m_bIsEnforced; } + // set { m_bIsEnforced = value; } + // } + + private bool m_bOmitDefaultValues = true; + // Informational property only (like an XML comment); + // currently doesn't have any effect (the XmlSerializer + // always omits default values, independent of this + // property) + public bool OmitItemsWithDefaultValues + { + get { return m_bOmitDefaultValues; } + set { m_bOmitDefaultValues = value; } + } + + private double m_dDpiFactorX = 0.0; // See AppConfigEx.DpiScale() + [DefaultValue(0.0)] + public double DpiFactorX + { + get { return m_dDpiFactorX; } + set { m_dDpiFactorX = value; } + } + + private double m_dDpiFactorY = 0.0; // See AppConfigEx.DpiScale() + [DefaultValue(0.0)] + public double DpiFactorY + { + get { return m_dDpiFactorY; } + set { m_dDpiFactorY = value; } + } + } +} diff --git a/src/KeePass/App/Configuration/AppConfigSerializer.cs b/src/KeePass/App/Configuration/AppConfigSerializer.cs new file mode 100644 index 0000000..be195cc --- /dev/null +++ b/src/KeePass/App/Configuration/AppConfigSerializer.cs @@ -0,0 +1,415 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; +using KeePass.Util.XmlSerialization; + +using KeePassLib; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.App.Configuration +{ + public static class AppConfigSerializer + { + private static string g_strBaseName = null; // Null allowed + + private static string g_strAppDataDir = null; + private static string g_strAppDataLocalDir = null; + private static string g_strEnforcedConfigFile = null; + private static string g_strGlobalConfigFile = null; + private static string g_strUserConfigFile = null; + + private const string g_strFileSuffix = ".config.xml"; + private const string g_strFileEnfSuffix = ".config.enforced.xml"; + + /// + /// Get our folder in the application data directory. + /// + public static string AppDataDirectory + { + get + { + GetConfigPaths(); + return g_strAppDataDir; + } + } + + /// + /// Get our folder in the local application data directory. + /// + public static string LocalAppDataDirectory + { + get + { + GetConfigPaths(); + return g_strAppDataLocalDir; + } + } + + /// + /// Get/set the base name for the configuration. If this property is + /// null, the class constructs names based on the current + /// assembly and the product name. + /// + public static string BaseName + { + get { return g_strBaseName; } + + set + { + g_strBaseName = value; + + // Invalidate paths + g_strAppDataDir = null; + g_strAppDataLocalDir = null; + g_strEnforcedConfigFile = null; + g_strGlobalConfigFile = null; + g_strUserConfigFile = null; + } + } + + private static XmlDocument g_xdEnforced = null; + public static XmlDocument EnforcedConfigXml + { + get { return g_xdEnforced; } + } + + private static void GetConfigPaths() + { + if(g_strGlobalConfigFile == null) + { + Assembly asm = Assembly.GetExecutingAssembly(); + if(asm == null) { Debug.Assert(false); return; } + +#if !KeePassLibSD + string strFile = null; + + try { strFile = asm.Location; } + catch(Exception) { } + + if(string.IsNullOrEmpty(strFile)) + strFile = UrlUtil.FileUrlToPath(asm.GetName().CodeBase); +#else + string strFile = UrlUtil.FileUrlToPath(asm.GetName().CodeBase); +#endif + if(string.IsNullOrEmpty(strFile)) { Debug.Assert(false); strFile = string.Empty; } + + if(!string.IsNullOrEmpty(g_strBaseName)) + strFile = UrlUtil.GetFileDirectory(strFile, true, false) + g_strBaseName; + else + { + if(strFile.EndsWith(".exe", StrUtil.CaseIgnoreCmp) || + strFile.EndsWith(".dll", StrUtil.CaseIgnoreCmp)) + strFile = strFile.Substring(0, strFile.Length - 4); + } + + g_strGlobalConfigFile = strFile + g_strFileSuffix; + g_strEnforcedConfigFile = strFile + g_strFileEnfSuffix; + } + + if(g_strUserConfigFile == null) + { + string strBaseName = (!string.IsNullOrEmpty(g_strBaseName) ? + g_strBaseName : PwDefs.ShortProductName); + + string strUserDir; + try + { + strUserDir = Environment.GetFolderPath( + Environment.SpecialFolder.ApplicationData); + } + catch(Exception) + { + strUserDir = UrlUtil.GetFileDirectory(UrlUtil.FileUrlToPath( + Assembly.GetExecutingAssembly().GetName().CodeBase), true, false); + } + strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false); + + string strUserDirLocal; + try + { + strUserDirLocal = Environment.GetFolderPath( + Environment.SpecialFolder.LocalApplicationData); + } + catch(Exception) { strUserDirLocal = strUserDir; } + strUserDirLocal = UrlUtil.EnsureTerminatingSeparator(strUserDirLocal, false); + + g_strAppDataDir = strUserDir + strBaseName; + g_strAppDataLocalDir = strUserDirLocal + strBaseName; + g_strUserConfigFile = UrlUtil.EnsureTerminatingSeparator( + g_strAppDataDir, false) + strBaseName + g_strFileSuffix; + + string strLocalOvr = Program.CommandLineArgs[ + AppDefs.CommandLineOptions.ConfigPathLocal]; + if(!string.IsNullOrEmpty(strLocalOvr)) + { + string strWD = UrlUtil.EnsureTerminatingSeparator( + WinUtil.GetWorkingDirectory(), false); + g_strUserConfigFile = UrlUtil.MakeAbsolutePath(strWD + + "Sentinel.txt", strLocalOvr); + // Do not change g_strAppDataDir, as it's returned from + // the AppDataDirectory property + } + + Debug.Assert(!string.IsNullOrEmpty(g_strAppDataDir)); + } + } + + private static void EnsureDirOfFileExists(string strFile) + { + if(string.IsNullOrEmpty(strFile)) { Debug.Assert(false); return; } + + try + { + string strDir = UrlUtil.GetFileDirectory(strFile, false, true); + if(!Directory.Exists(strDir)) + Directory.CreateDirectory(strDir); + } + catch(Exception) { Debug.Assert(false); } + } + + private static XmlDocument LoadEnforcedConfigFile() + { +#if DEBUG + Stopwatch sw = Stopwatch.StartNew(); +#endif + + g_xdEnforced = null; + try + { + if(!File.Exists(g_strEnforcedConfigFile)) return null; + + XmlDocument xd = XmlUtilEx.CreateXmlDocument(); + xd.Load(g_strEnforcedConfigFile); + + g_xdEnforced = xd; + return xd; + } + catch(Exception ex) + { + FileDialogsEx.ShowConfigError(g_strEnforcedConfigFile, + ex.Message, false, false); + } +#if DEBUG + finally + { + sw.Stop(); + } +#endif + + return null; + } + + private static AppConfigEx LoadConfigFileEx(string strFilePath, + XmlDocument xdEnforced) + { + if(string.IsNullOrEmpty(strFilePath)) { Debug.Assert(false); return null; } + + AppConfigEx tConfig = null; + try + { + if(!File.Exists(strFilePath)) return null; + + XmlSerializerEx xs = new XmlSerializerEx(typeof(AppConfigEx)); + + if(xdEnforced == null) + { + using(FileStream fs = new FileStream(strFilePath, + FileMode.Open, FileAccess.Read, FileShare.Read)) + { + tConfig = (AppConfigEx)xs.Deserialize(fs); + } + } + else // Enforced configuration + { + XmlDocument xd = XmlUtilEx.CreateXmlDocument(); + xd.Load(strFilePath); + + XmContext ctx = new XmContext(xd, AppConfigEx.GetNodeOptions, + AppConfigEx.GetNodeKey); + XmlUtil.MergeElements(xd.DocumentElement, xdEnforced.DocumentElement, + "/" + xd.DocumentElement.Name, null, ctx); + + using(MemoryStream msW = new MemoryStream()) + { + xd.Save(msW); + + using(MemoryStream msR = new MemoryStream(msW.ToArray(), false)) + { + tConfig = (AppConfigEx)xs.Deserialize(msR); + } + } + } + } + catch(Exception ex) + { + FileDialogsEx.ShowConfigError(strFilePath, ex.Message, false, true); + } + + if(tConfig != null) tConfig.OnLoad(); + return tConfig; + } + + public static AppConfigEx Load() + { + GetConfigPaths(); + + // AppConfigEx cfgEnf = LoadConfigFileEx(g_strEnforcedConfigFile); + // if(cfgEnf != null) + // { + // cfgEnf.Meta.IsEnforcedConfiguration = true; + // return cfgEnf; + // } + XmlDocument xdEnforced = LoadEnforcedConfigFile(); + + AppConfigEx cfgGlobal = LoadConfigFileEx(g_strGlobalConfigFile, xdEnforced); + if((cfgGlobal != null) && !cfgGlobal.Meta.PreferUserConfiguration) + return cfgGlobal; // Do not show error for corrupted local configuration + + AppConfigEx cfgUser = LoadConfigFileEx(g_strUserConfigFile, xdEnforced); + + if((cfgGlobal == null) && (cfgUser == null)) + { + if(xdEnforced != null) + { + // Create an empty configuration file and merge it with + // the enforced configuration; this ensures that merge + // behaviors (like the node mode 'Remove') work as intended + try + { + string strFile = Program.TempFilesPool.GetTempFileName("xml"); + File.WriteAllText(strFile, AppConfigEx.GetEmptyConfigXml(), + StrUtil.Utf8); + + AppConfigEx cfg = LoadConfigFileEx(strFile, xdEnforced); + if(cfg != null) return cfg; + Debug.Assert(false); + } + catch(Exception) { Debug.Assert(false); } + } + + AppConfigEx cfgNew = new AppConfigEx(); + cfgNew.OnLoad(); // Create defaults + return cfgNew; + } + if((cfgGlobal != null) && (cfgUser == null)) return cfgGlobal; + if((cfgGlobal == null) && (cfgUser != null)) return cfgUser; + + cfgUser.Meta.PreferUserConfiguration = cfgGlobal.Meta.PreferUserConfiguration; + return (cfgGlobal.Meta.PreferUserConfiguration ? cfgUser : cfgGlobal); + } + + private static bool SaveConfigFileEx(AppConfigEx tConfig, string strFilePath) + { + if(string.IsNullOrEmpty(strFilePath)) { Debug.Assert(false); return false; } + + tConfig.OnSavePre(); + + // Temporarily remove user file preference (restore after saving) + bool bPref = tConfig.Meta.PreferUserConfiguration; + tConfig.Meta.PreferUserConfiguration = false; + + bool bResult = true; + try + { + IOConnectionInfo iocPath = IOConnectionInfo.FromPath(strFilePath); + + using(FileTransactionEx ft = new FileTransactionEx(iocPath, + Program.Config.Application.UseTransactedConfigWrites)) + { + using(Stream s = ft.OpenWrite()) + { + using(XmlWriter xw = XmlUtilEx.CreateXmlWriter(s)) + { + XmlSerializerEx xs = new XmlSerializerEx(typeof(AppConfigEx)); + xs.Serialize(xw, tConfig); + } + } + + ft.CommitWrite(); + } + } + catch(Exception ex) + { + FileDialogsEx.ShowConfigError(strFilePath, ex.Message, true, false); + bResult = false; + } + + tConfig.Meta.PreferUserConfiguration = bPref; + + tConfig.OnSavePost(); + return bResult; + } + + public static bool Save(AppConfigEx tConfig) + { + if(tConfig == null) { Debug.Assert(false); return false; } + if(!tConfig.Application.ConfigSave) return false; + + GetConfigPaths(); + + if(tConfig.Meta.PreferUserConfiguration) + { + EnsureDirOfFileExists(g_strUserConfigFile); + if(SaveConfigFileEx(tConfig, g_strUserConfigFile)) return true; + + if(SaveConfigFileEx(tConfig, g_strGlobalConfigFile)) return true; + } + else // Prefer global + { + if(SaveConfigFileEx(tConfig, g_strGlobalConfigFile)) return true; + + EnsureDirOfFileExists(g_strUserConfigFile); + if(SaveConfigFileEx(tConfig, g_strUserConfigFile)) return true; + } + + return false; + } + + internal static string TryCreateBackup(string strFilePath) + { + if(string.IsNullOrEmpty(strFilePath)) { Debug.Assert(false); return null; } + + try + { + DateTime dt = DateTime.Now; + string strBackupPath = UrlUtil.EnsureTerminatingSeparator( + UrlUtil.GetTempPath(), false) + PwDefs.ShortProductName + + "_" + dt.ToString("yyyyMMddHHmmss") + g_strFileSuffix; + + File.Copy(strFilePath, strBackupPath, true); + return strBackupPath; + } + catch(Exception) { Debug.Assert(false); } + + return null; + } + } +} diff --git a/src/KeePass/DataExchange/CsvStreamReader.cs b/src/KeePass/DataExchange/CsvStreamReader.cs new file mode 100644 index 0000000..cc1d960 --- /dev/null +++ b/src/KeePass/DataExchange/CsvStreamReader.cs @@ -0,0 +1,135 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + public sealed class CsvStreamReader + { + private CharStream m_sChars; + private readonly bool m_bAllowUnquoted; + + [Obsolete] + public CsvStreamReader(string strData) + { + m_sChars = new CharStream(strData); + m_bAllowUnquoted = false; + } + + public CsvStreamReader(string strData, bool bAllowUnquoted) + { + m_sChars = new CharStream(strData); + m_bAllowUnquoted = bAllowUnquoted; + } + + public string[] ReadLine() + { + return (m_bAllowUnquoted ? ReadLineUnquoted() : ReadLineQuoted()); + } + + private string[] ReadLineQuoted() + { + if(m_sChars.PeekChar() == char.MinValue) return null; + + List v = new List(); + StringBuilder sb = new StringBuilder(); + bool bInField = false; + + while(true) + { + char ch = m_sChars.ReadChar(); + if(ch == char.MinValue) break; + + if((ch == '\"') && !bInField) bInField = true; + else if((ch == '\"') && bInField) + { + if(m_sChars.PeekChar() == '\"') + { + m_sChars.ReadChar(); + sb.Append('\"'); + } + else + { + v.Add(sb.ToString()); + if(sb.Length > 0) sb.Remove(0, sb.Length); + + bInField = false; + } + } + else if(((ch == '\r') || (ch == '\n')) && !bInField) break; + else if(bInField) sb.Append(ch); + } + Debug.Assert(!bInField); + Debug.Assert(sb.Length == 0); + if(sb.Length > 0) v.Add(sb.ToString()); + + return v.ToArray(); + } + + private string[] ReadLineUnquoted() + { + char chFirst = m_sChars.PeekChar(); + if(chFirst == char.MinValue) return null; + if((chFirst == '\r') || (chFirst == '\n')) + { + m_sChars.ReadChar(); // Advance + return MemUtil.EmptyArray(); + } + + List v = new List(); + StringBuilder sb = new StringBuilder(); + bool bInField = false; + + while(true) + { + char ch = m_sChars.ReadChar(); + if(ch == char.MinValue) break; + + if((ch == '\"') && !bInField) bInField = true; + else if((ch == '\"') && bInField) + { + if(m_sChars.PeekChar() == '\"') + { + m_sChars.ReadChar(); + sb.Append('\"'); + } + else bInField = false; + } + else if(((ch == '\r') || (ch == '\n')) && !bInField) break; + else if(bInField) sb.Append(ch); + else if(ch == ',') + { + v.Add(sb.ToString()); + if(sb.Length > 0) sb.Remove(0, sb.Length); + } + else sb.Append(ch); + } + Debug.Assert(!bInField); + v.Add(sb.ToString()); + + return v.ToArray(); + } + } +} diff --git a/src/KeePass/DataExchange/CsvStreamReaderEx.cs b/src/KeePass/DataExchange/CsvStreamReaderEx.cs new file mode 100644 index 0000000..4643302 --- /dev/null +++ b/src/KeePass/DataExchange/CsvStreamReaderEx.cs @@ -0,0 +1,202 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + public sealed class CsvOptions + { + private char m_chFieldSep = ','; + public char FieldSeparator + { + get { return m_chFieldSep; } + set { m_chFieldSep = value; } + } + + private char m_chRecSep = '\n'; + public char RecordSeparator + { + get { return m_chRecSep; } + set { m_chRecSep = value; } + } + + private char m_chTextQual = '\"'; + public char TextQualifier + { + get { return m_chTextQual; } + set { m_chTextQual = value; } + } + + private bool m_bBackEscape = true; + public bool BackslashIsEscape + { + get { return m_bBackEscape; } + set { m_bBackEscape = value; } + } + + private bool m_bTrimFields = true; + public bool TrimFields + { + get { return m_bTrimFields; } + set { m_bTrimFields = value; } + } + + private string m_strNewLineSeq = "\r\n"; + public string NewLineSequence + { + get { return m_strNewLineSeq; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strNewLineSeq = value; + } + } + } + + public sealed class CsvStreamReaderEx + { + private CharStream m_sChars; + private CsvOptions m_opt; + + public CsvStreamReaderEx(string strData) + { + Init(strData, null); + } + + public CsvStreamReaderEx(string strData, CsvOptions opt) + { + Init(strData, opt); + } + + private void Init(string strData, CsvOptions opt) + { + if(strData == null) throw new ArgumentNullException("strData"); + + m_opt = (opt ?? new CsvOptions()); + + string strInput = strData; + + // Normalize to Unix "\n" right now; the new lines are + // converted back in the AddField method + strInput = StrUtil.NormalizeNewLines(strInput, false); + + strInput = strInput.Trim(new char[] { (char)0 }); + + m_sChars = new CharStream(strInput); + } + + public string[] ReadLine() + { + char chFirst = m_sChars.PeekChar(); + if(chFirst == char.MinValue) return null; + + List v = new List(); + StringBuilder sb = new StringBuilder(); + bool bInText = false; + + char chFS = m_opt.FieldSeparator, chRS = m_opt.RecordSeparator; + char chTQ = m_opt.TextQualifier; + + while(true) + { + char ch = m_sChars.ReadChar(); + if(ch == char.MinValue) break; + + Debug.Assert(ch != '\r'); // Was normalized to Unix "\n" + + if((ch == '\\') && m_opt.BackslashIsEscape) + { + char chEsc = m_sChars.ReadChar(); + if(chEsc == char.MinValue) break; + + if(chEsc == 'n') sb.Append('\n'); + else if(chEsc == 'r') sb.Append('\r'); + else if(chEsc == 't') sb.Append('\t'); + else if(chEsc == 'u') + { + char chNum1 = m_sChars.ReadChar(); + char chNum2 = m_sChars.ReadChar(); + char chNum3 = m_sChars.ReadChar(); + char chNum4 = m_sChars.ReadChar(); + if(chNum4 != char.MinValue) // Implies the others + { + StringBuilder sbNum = new StringBuilder(); + sbNum.Append(chNum3); // Little-endian + sbNum.Append(chNum4); + sbNum.Append(chNum1); + sbNum.Append(chNum2); + + byte[] pbNum = MemUtil.HexStringToByteArray(sbNum.ToString()); + ushort usNum = MemUtil.BytesToUInt16(pbNum); + + sb.Append((char)usNum); + } + } + else sb.Append(chEsc); + } + else if(ch == chTQ) + { + if(!bInText) bInText = true; + else // bInText + { + char chNext = m_sChars.PeekChar(); + if(chNext == chTQ) + { + m_sChars.ReadChar(); + sb.Append(chTQ); + } + else bInText = false; + } + } + else if((ch == chRS) && !bInText) break; + else if(bInText) sb.Append(ch); + else if(ch == chFS) + { + AddField(v, sb.ToString()); + if(sb.Length > 0) sb.Remove(0, sb.Length); + } + else sb.Append(ch); + } + // Debug.Assert(!bInText); + AddField(v, sb.ToString()); + + return v.ToArray(); + } + + private void AddField(List v, string strField) + { + // Escape characters might have been used to insert + // new lines that might not conform to Unix "\n" + strField = StrUtil.NormalizeNewLines(strField, false); + + // Transform to final form of new lines + strField = strField.Replace("\n", m_opt.NewLineSequence); + + if(m_opt.TrimFields) strField = strField.Trim(); + + v.Add(strField); + } + } +} diff --git a/src/KeePass/DataExchange/CsvStreamWriter.cs b/src/KeePass/DataExchange/CsvStreamWriter.cs new file mode 100644 index 0000000..e75234d --- /dev/null +++ b/src/KeePass/DataExchange/CsvStreamWriter.cs @@ -0,0 +1,86 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + // Compatible with RFC 4180 + internal sealed class CsvStreamWriter + { + private readonly StreamWriter m_sw; + + public CsvStreamWriter(StreamWriter sw) + { + if(sw == null) throw new ArgumentNullException("sw"); + + m_sw = sw; + } + + private static readonly char[] g_vQuReq = new char[] { + '\t', '\n', '\r', '\"', ',', ';' }; + private static bool AreQuotesRequired(string str) + { + if(str == null) { Debug.Assert(false); return false; } + + int cc = str.Length; + if(cc == 0) return false; + + if(char.IsWhiteSpace(str[0]) || char.IsWhiteSpace(str[cc - 1])) + return true; + + return (str.IndexOfAny(g_vQuReq) >= 0); + } + + public void WriteLine(string[] vFields) + { + if(vFields == null) { Debug.Assert(false); return; } + + for(int i = 0; i < vFields.Length; ++i) + { + if(i != 0) m_sw.Write(','); + + string str = vFields[i]; + Debug.Assert(str != null); + if(!string.IsNullOrEmpty(str)) + { + if(AreQuotesRequired(str)) + { + m_sw.Write('\"'); + + string strEsc = StrUtil.NormalizeNewLines(str, true); + strEsc = strEsc.Replace("\"", "\"\""); + m_sw.Write(strEsc); + + m_sw.Write('\"'); + } + else m_sw.Write(str); + } + } + + m_sw.Write("\r\n"); // m_sw.WriteLine uses m_sw.NewLine + } + } +} diff --git a/src/KeePass/DataExchange/CsvTableEntryReader.cs b/src/KeePass/DataExchange/CsvTableEntryReader.cs new file mode 100644 index 0000000..f7ab954 --- /dev/null +++ b/src/KeePass/DataExchange/CsvTableEntryReader.cs @@ -0,0 +1,74 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +using KeePassLib; + +namespace KeePass.DataExchange +{ + internal sealed class CsvTableEntryReader : CsvTableObjectReader + { + private readonly PwDatabase m_pd; + + public CsvTableEntryReader(PwDatabase pdContext) : + base(CsvTableEntryReader.EntryNew, CsvTableEntryReader.EntryCommit(pdContext)) + { + m_pd = pdContext; + } + + private static PwEntry EntryNew(string[] vContextRow) + { + return new PwEntry(true, true); + } + + private static CsvTableObjectAction EntryCommit(PwDatabase pdContext) + { + CsvTableObjectAction f = delegate(PwEntry pe, string[] vContextRow) + { + if(pe == null) { Debug.Assert(false); return; } + + if(pe.ParentGroup == null) + { + PwGroup pg = ((pdContext != null) ? pdContext.RootGroup : null); + if(pg != null) pg.AddEntry(pe, true); + else { Debug.Assert(false); } + } + }; + + return f; + } + + public void SetDataAppend(string strColumn, string strStringName) + { + if(string.IsNullOrEmpty(strStringName)) { Debug.Assert(false); return; } + + CsvTableDataHandler f = delegate(string strData, + PwEntry peContext, string[] vContextRow) + { + ImportUtil.AppendToField(peContext, strStringName, strData, m_pd); + }; + + SetDataHandler(strColumn, f); + } + } +} diff --git a/src/KeePass/DataExchange/CsvTableObjectReader.cs b/src/KeePass/DataExchange/CsvTableObjectReader.cs new file mode 100644 index 0000000..b6e51ad --- /dev/null +++ b/src/KeePass/DataExchange/CsvTableObjectReader.cs @@ -0,0 +1,118 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace KeePass.DataExchange +{ + internal delegate T CsvTableObjectFunc(string[] vContextRow); + internal delegate void CsvTableObjectAction(T t, string[] vContextRow); + internal delegate void CsvTableDataHandler(string strData, T tContext, + string[] vContextRow); + + internal abstract class CsvTableObjectReader + { + // For all streams + private readonly CsvTableObjectFunc m_fObjectNew; + private readonly CsvTableObjectAction m_fObjectCommit; + private readonly Dictionary> m_dHandlers = + new Dictionary>(); + + // For the current stream + private readonly Dictionary m_dColumns = + new Dictionary(); + + public CsvTableObjectReader(CsvTableObjectFunc fObjectNew, + CsvTableObjectAction fObjectCommit) + { + m_fObjectNew = fObjectNew; + m_fObjectCommit = fObjectCommit; + } + + public void SetDataHandler(string strColumn, CsvTableDataHandler f) + { + if(strColumn == null) { Debug.Assert(false); return; } + + m_dHandlers[strColumn] = f; + } + + public void Read(CsvStreamReaderEx csr) + { + if(csr == null) { Debug.Assert(false); return; } + + string[] vHeader; + while(true) + { + vHeader = csr.ReadLine(); + if(vHeader == null) return; + if(vHeader.Length == 0) continue; + if((vHeader.Length == 1) && (vHeader[0].Length == 0)) continue; + break; + } + + m_dColumns.Clear(); + + CsvTableDataHandler[] vHandlers = new CsvTableDataHandler[vHeader.Length]; + for(int i = vHeader.Length - 1; i >= 0; --i) + { + string str = vHeader[i]; + + m_dColumns[str] = i; + + CsvTableDataHandler f; + m_dHandlers.TryGetValue(str, out f); + vHandlers[i] = f; + } + + while(true) + { + string[] vRow = csr.ReadLine(); + if(vRow == null) break; + if(vRow.Length == 0) continue; + if((vRow.Length == 1) && (vRow[0].Length == 0)) continue; + + T t = ((m_fObjectNew != null) ? m_fObjectNew(vRow) : default(T)); + + Debug.Assert(vRow.Length == vHandlers.Length); + int m = Math.Min(vRow.Length, vHandlers.Length); + for(int i = 0; i < m; ++i) + { + CsvTableDataHandler f = vHandlers[i]; + if(f != null) f(vRow[i], t, vRow); + } + + if(m_fObjectCommit != null) m_fObjectCommit(t, vRow); + } + } + + public string GetData(string[] vRow, string strColumn, string strDefault) + { + if(vRow == null) { Debug.Assert(false); return strDefault; } + if(strColumn == null) { Debug.Assert(false); return strDefault; } + + int i; + if(!m_dColumns.TryGetValue(strColumn, out i)) return strDefault; + + return ((i < vRow.Length) ? vRow[i] : strDefault); + } + } +} diff --git a/src/KeePass/DataExchange/ExportUtil.cs b/src/KeePass/DataExchange/ExportUtil.cs new file mode 100644 index 0000000..e409312 --- /dev/null +++ b/src/KeePass/DataExchange/ExportUtil.cs @@ -0,0 +1,274 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Windows.Forms; + +using KeePass.App; +using KeePass.Forms; +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Delegates; +using KeePassLib.Interfaces; +using KeePassLib.Keys; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +using NativeLib = KeePassLib.Native.NativeLib; + +namespace KeePass.DataExchange +{ + public static class ExportUtil + { + public static bool Export(PwExportInfo pwExportInfo, IStatusLogger slLogger) + { + if(pwExportInfo == null) throw new ArgumentNullException("pwExportInfo"); + if(pwExportInfo.DataGroup == null) throw new ArgumentException(); + + if(!AppPolicy.Try(AppPolicyId.Export)) return false; + + ExchangeDataForm dlg = new ExchangeDataForm(); + dlg.InitEx(true, pwExportInfo.ContextDatabase, pwExportInfo.DataGroup); + dlg.ExportInfo = pwExportInfo; + + bool bStatusActive = false; + + try + { + if(dlg.ShowDialog() == DialogResult.OK) + { + FileFormatProvider ffp = dlg.ResultFormat; + if(ffp == null) { Debug.Assert(false); return false; } + + IOConnectionInfo ioc = null; + if(ffp.RequiresFile) + { + string[] vFiles = dlg.ResultFiles; + if(vFiles == null) { Debug.Assert(false); return false; } + if(vFiles.Length == 0) { Debug.Assert(false); return false; } + Debug.Assert(vFiles.Length == 1); + + string strFile = vFiles[0]; + if(string.IsNullOrEmpty(strFile)) { Debug.Assert(false); return false; } + + ioc = IOConnectionInfo.FromPath(strFile); + } + + if(slLogger != null) + { + slLogger.StartLogging(KPRes.ExportingStatusMsg, true); + bStatusActive = true; + } + + Application.DoEvents(); // Redraw parent window + return Export(pwExportInfo, ffp, ioc, slLogger); + } + } + catch(Exception ex) { MessageService.ShowWarning(ex); } + finally + { + UIUtil.DestroyForm(dlg); + if(bStatusActive) slLogger.EndLogging(); + } + + return false; + } + + public static bool Export(PwExportInfo pwExportInfo, string strFormatName, + IOConnectionInfo iocOutput) + { + if(strFormatName == null) throw new ArgumentNullException("strFormatName"); + // iocOutput may be null + + FileFormatProvider ffp = Program.FileFormatPool.Find(strFormatName); + if(ffp == null) return false; + + NullStatusLogger slLogger = new NullStatusLogger(); + return Export(pwExportInfo, ffp, iocOutput, slLogger); + } + + public static bool Export(PwExportInfo pwExportInfo, FileFormatProvider fileFormat, + IOConnectionInfo iocOutput, IStatusLogger slLogger) + { + if(pwExportInfo == null) throw new ArgumentNullException("pwExportInfo"); + if(pwExportInfo.DataGroup == null) throw new ArgumentException(); + if(fileFormat == null) throw new ArgumentNullException("fileFormat"); + + bool bFileReq = fileFormat.RequiresFile; + if(bFileReq && (iocOutput == null)) + throw new ArgumentNullException("iocOutput"); + if(bFileReq && (iocOutput.Path.Length == 0)) + throw new ArgumentException(); + + PwDatabase pd = pwExportInfo.ContextDatabase; + Debug.Assert(pd != null); + + if(!AppPolicy.Try(AppPolicyId.Export)) return false; + if(!AppPolicy.Current.ExportNoKey && (pd != null)) + { + if(!KeyUtil.ReAskKey(pd, true)) return false; + } + + if(!fileFormat.SupportsExport) return false; + if(!fileFormat.TryBeginExport()) return false; + + CompositeKey ckOrgMasterKey = null; + DateTime dtOrgMasterKey = PwDefs.DtDefaultNow; + + PwGroup pgOrgData = pwExportInfo.DataGroup; + PwGroup pgOrgRoot = ((pd != null) ? pd.RootGroup : null); + bool bParentGroups = (pwExportInfo.ExportParentGroups && (pd != null) && + (pgOrgData != pgOrgRoot)); + + bool bExistedAlready = true; // No deletion by default + bool bResult = false; + + try + { + if(pwExportInfo.ExportMasterKeySpec && fileFormat.RequiresKey && + (pd != null)) + { + KeyCreationFormResult r; + DialogResult dr = KeyCreationForm.ShowDialog(iocOutput, true, out r); + if((dr != DialogResult.OK) || (r == null)) return false; + + ckOrgMasterKey = pd.MasterKey; + dtOrgMasterKey = pd.MasterKeyChanged; + + pd.MasterKey = r.CompositeKey; + pd.MasterKeyChanged = DateTime.UtcNow; + } + + if(bParentGroups) + { + PwGroup pgNew = WithParentGroups(pgOrgData, pd); + pwExportInfo.DataGroup = pgNew; + pd.RootGroup = pgNew; + } + + if(bFileReq) bExistedAlready = IOConnection.FileExists(iocOutput); + + Stream s = (bFileReq ? IOConnection.OpenWrite(iocOutput) : null); + try { bResult = fileFormat.Export(pwExportInfo, s, slLogger); } + finally { if(s != null) s.Close(); } + + if(bFileReq && bResult) + { + if(pwExportInfo.ExportPostOpen) + NativeLib.StartProcess(iocOutput.Path); + if(pwExportInfo.ExportPostShow) + WinUtil.ShowFileInFileManager(iocOutput.Path, true); + } + } + catch(Exception ex) { MessageService.ShowWarning(ex); } + finally + { + if(ckOrgMasterKey != null) + { + pd.MasterKey = ckOrgMasterKey; + pd.MasterKeyChanged = dtOrgMasterKey; + } + + if(bParentGroups) + { + pwExportInfo.DataGroup = pgOrgData; + pd.RootGroup = pgOrgRoot; + } + } + + if(bFileReq && !bResult && !bExistedAlready) + { + try { IOConnection.DeleteFile(iocOutput); } + catch(Exception) { } + } + + return bResult; + } + + private static PwGroup WithParentGroups(PwGroup pg, PwDatabase pd) + { + if(pg == null) { Debug.Assert(false); return null; } + if(pd == null) { Debug.Assert(false); return pg; } + + Dictionary dUuids = CollectUuids(pg); + + PwGroup pgNew = FilterCloneGroup(pd.RootGroup, dUuids); + Debug.Assert(pgNew.GetEntriesCount(true) == pg.GetEntriesCount(true)); + return pgNew; + } + + private static Dictionary CollectUuids(PwGroup pg) + { + Dictionary d = new Dictionary(); + + Action fAdd = delegate(IStructureItem it) + { + if(it == null) { Debug.Assert(false); return; } + + Debug.Assert(!d.ContainsKey(it.Uuid)); + d[it.Uuid] = true; + + PwGroup pgParent = it.ParentGroup; + while(pgParent != null) + { + d[pgParent.Uuid] = true; + pgParent = pgParent.ParentGroup; + } + }; + + GroupHandler gh = delegate(PwGroup pgCur) { fAdd(pgCur); return true; }; + EntryHandler eh = delegate(PwEntry peCur) { fAdd(peCur); return true; }; + + fAdd(pg); + pg.TraverseTree(TraversalMethod.PreOrder, gh, eh); + + return d; + } + + private static PwGroup FilterCloneGroup(PwGroup pg, Dictionary dUuids) + { + PwGroup pgNew = new PwGroup(); + pgNew.Uuid = pg.Uuid; + pgNew.AssignProperties(pg, false, true); + Debug.Assert(pgNew.EqualsGroup(pg, (PwCompareOptions.IgnoreParentGroup | + PwCompareOptions.PropertiesOnly), MemProtCmpMode.Full)); + + foreach(PwEntry pe in pg.Entries) + { + if(dUuids.ContainsKey(pe.Uuid)) + pgNew.AddEntry(pe.CloneDeep(), true, false); + } + + foreach(PwGroup pgSub in pg.Groups) + { + if(dUuids.ContainsKey(pgSub.Uuid)) + pgNew.AddGroup(FilterCloneGroup(pgSub, dUuids), true, false); + } + + return pgNew; + } + } +} diff --git a/src/KeePass/DataExchange/FileFormatPool.cs b/src/KeePass/DataExchange/FileFormatPool.cs new file mode 100644 index 0000000..e7eaee1 --- /dev/null +++ b/src/KeePass/DataExchange/FileFormatPool.cs @@ -0,0 +1,227 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +using KeePass.DataExchange.Formats; +using KeePass.UI; + +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + public sealed class FileFormatPool : IEnumerable + { + private readonly List m_lFormats = new List(); + + public IEnumerable Importers + { + get + { + List l = new List(); + foreach(FileFormatProvider p in m_lFormats) + { + if(p.SupportsImport) l.Add(p); + } + return l; + } + } + + public IEnumerable Exporters + { + get + { + List l = new List(); + foreach(FileFormatProvider p in m_lFormats) + { + if(p.SupportsExport) l.Add(p); + } + return l; + } + } + + public int Count + { + get { return m_lFormats.Count; } + } + + public FileFormatPool() + { + List l = m_lFormats; + + l.Add(new KeePassCsv1x()); + l.Add(new KeePassKdb1x()); + l.Add(new KeePassKdb2x()); + l.Add(new KeePassKdb2xRepair()); + l.Add(new KeePassKdb2x3()); + l.Add(new KeePassXml1x()); + l.Add(new KeePassXml2x()); + + l.Add(new GenericCsv()); + + l.Add(new KeePassHtml2x()); + l.Add(new XslTransform2x()); + l.Add(new WinFavorites10(false)); + l.Add(new WinFavorites10(true)); + + l.Add(new OnePw1Pux8()); + l.Add(new OnePwProCsv599()); + l.Add(new AmpXml250()); + l.Add(new AnyPwCsv144()); + l.Add(new BitwardenJson112()); + l.Add(new CodeWalletTxt605()); + l.Add(new DashlaneCsv2()); + l.Add(new DashlaneJson6()); + l.Add(new DataVaultCsv47()); + l.Add(new DesktopKnoxXml32()); + l.Add(new EnpassTxt5()); + l.Add(new FlexWalletXml17()); + l.Add(new HandySafeTxt512()); + l.Add(new HandySafeProXml12()); + l.Add(new KasperskyPwMgrTxt90()); + l.Add(new KasperskyPwMgrXml50()); + l.Add(new KeePassXXml041()); + l.Add(new KeeperJson16()); + l.Add(new KeyFolderXml1()); + l.Add(new LastPassCsv2()); + l.Add(new MSecureCsv355()); + l.Add(new NetworkPwMgrCsv4()); + l.Add(new NortonIdSafeCsv2013()); + l.Add(new NPasswordNpw102()); + l.Add(new PassKeeper12()); + l.Add(new PpKeeperHtml270()); + l.Add(new PwAgentXml3()); + l.Add(new PwDepotXml26()); + l.Add(new PwKeeperCsv70()); + l.Add(new PwMemory2008Xml104()); + l.Add(new PwPrompterDat12()); + l.Add(new PwSafeXml302()); + l.Add(new PwSaverXml412()); + l.Add(new PwsPlusCsv1007()); + l.Add(new PwTresorXml100()); + l.Add(new PVaultTxt14()); + l.Add(new PinsTxt450()); + l.Add(new RevelationXml04()); + l.Add(new RoboFormHtml69()); + l.Add(new SafeWalletXml3()); + l.Add(new SecurityTxt12()); + l.Add(new SplashIdCsv402()); + l.Add(new SteganosCsv20()); + l.Add(new SteganosUI2007()); + l.Add(new StickyPwXml50()); + l.Add(new TrueKeyCsv4()); + l.Add(new TurboPwsCsv5()); + l.Add(new VisKeeperTxt3()); + l.Add(new Whisper32Csv116()); + l.Add(new ZdnPwProTxt314()); + + l.Add(new ChromeCsv66()); + l.Add(new MozillaBookmarksHtml100()); + l.Add(new MozillaBookmarksJson100()); + l.Add(new PwExporterXml105()); + + l.Add(new Spamex20070328()); + +#if DEBUG + // Ensure name uniqueness + for(int i = 0; i < l.Count; ++i) + { + FileFormatProvider pi = l[i]; + for(int j = i + 1; j < l.Count; ++j) + { + FileFormatProvider pj = l[j]; + Debug.Assert(!string.Equals(pi.FormatName, pj.FormatName, StrUtil.CaseIgnoreCmp)); + Debug.Assert(!string.Equals(pi.FormatName, pj.DisplayName, StrUtil.CaseIgnoreCmp)); + Debug.Assert(!string.Equals(pi.DisplayName, pj.FormatName, StrUtil.CaseIgnoreCmp)); + Debug.Assert(!string.Equals(pi.DisplayName, pj.DisplayName, StrUtil.CaseIgnoreCmp)); + } + } + + foreach(FileFormatProvider p in l) + { + Type t = p.GetType(); + Debug.Assert(t.IsNotPublic); + Debug.Assert(t.IsSealed || l.Exists(px => px.GetType().IsSubclassOf(t))); + + string strExts = p.DefaultExtension; + if(!string.IsNullOrEmpty(strExts)) + { + Debug.Assert(!strExts.StartsWith(".")); + Debug.Assert(strExts.ToLower() == strExts); + + string strExtU = UIUtil.GetPrimaryFileTypeExt(strExts).ToUpper(); + Debug.Assert(p.DisplayName.EndsWith(" " + strExtU) || + p.DisplayName.Contains(" " + strExtU + " ") || + p.DisplayName.Contains(" " + strExtU + "-")); + } + } +#endif + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_lFormats.GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return m_lFormats.GetEnumerator(); + } + + public void Add(FileFormatProvider p) + { + if(p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); } + + m_lFormats.Add(p); + } + + public bool Remove(FileFormatProvider p) + { + if(p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); } + + return m_lFormats.Remove(p); + } + + public FileFormatProvider Find(string strName) + { + if(string.IsNullOrEmpty(strName)) return null; + + // Format and display names may differ (e.g. the Generic + // CSV Importer has different names) + + foreach(FileFormatProvider p in m_lFormats) + { + if(string.Equals(strName, p.DisplayName, StrUtil.CaseIgnoreCmp)) + return p; + } + + foreach(FileFormatProvider p in m_lFormats) + { + if(string.Equals(strName, p.FormatName, StrUtil.CaseIgnoreCmp)) + return p; + } + + return null; + } + } +} diff --git a/src/KeePass/DataExchange/FileFormatProvider.cs b/src/KeePass/DataExchange/FileFormatProvider.cs new file mode 100644 index 0000000..473bb76 --- /dev/null +++ b/src/KeePass/DataExchange/FileFormatProvider.cs @@ -0,0 +1,168 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; + +namespace KeePass.DataExchange +{ + public abstract class FileFormatProvider + { + public abstract bool SupportsImport { get; } + public abstract bool SupportsExport { get; } + + public abstract string FormatName { get; } + + public virtual string DisplayName + { + get { return this.FormatName; } + } + + /// + /// Default file name extension, without leading dot. + /// If there are multiple default/equivalent extensions + /// (like e.g. "html" and "htm"), specify all of them + /// separated by a '|' (e.g. "html|htm"). + /// + public virtual string DefaultExtension + { + get { return string.Empty; } + } + + /// + /// Type of the original application using this format (like + /// password manager / KPRes.PasswordManagers, + /// web site / KPRes.WebSites, + /// browser / KPRes.Browser, etc. + /// + public virtual string ApplicationGroup + { + get { return KPRes.General; } + } + + /// + /// This property indicates whether entries are only appended + /// to the end of the root group. This is true for example if + /// the file format does not support groups (i.e. no hierarchy). + /// + public virtual bool ImportAppendsToRootGroupOnly + { + get { return false; } + } + + public virtual bool RequiresFile + { + get { return true; } + } + + public virtual bool RequiresKey + { + get { return false; } + } + + public virtual bool SupportsUuids + { + get { return false; } + } + + public virtual Image SmallIcon + { + get { return null; } + } + + /// + /// If the importer is implemented as a profile for the generic + /// XML importer, return the profile using this property (in + /// this case the Import method must not be overridden!). + /// + internal virtual GxiProfile XmlProfile + { + get { return null; } + } + + /// + /// Called before the Import method is invoked. + /// + /// Returns true, if the Import method + /// can be invoked. If it returns false, something has + /// failed and the import process should be aborted. + public virtual bool TryBeginImport() + { + return true; + } + + /// + /// Called before the Export method is invoked. + /// + /// Returns true, if the Export method + /// can be invoked. If it returns false, something has + /// failed and the export process should be aborted. + public virtual bool TryBeginExport() + { + return true; + } + + /// + /// Import a stream into a database. Throws an exception if an error + /// occurs. Do not call the base class method when overriding it. + /// + /// Data storage into which the data will be imported. + /// Input stream to read the data from. + /// Status logger. May be null. + public virtual void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + GxiProfile p = this.XmlProfile; + if(p != null) + { + if(pwStorage == null) throw new ArgumentNullException("pwStorage"); + + GxiImporter.Import(pwStorage.RootGroup, sInput, p, pwStorage, slLogger); + return; + } + + throw new NotSupportedException(); + } + + /// + /// Export data into a stream. Throws an exception if an error + /// occurs (like writing to stream fails, etc.). Returns true, + /// if the export was successful. + /// + /// Contains the data source and detailed + /// information about which entries should be exported. + /// Output stream to write the data to. + /// Status logger. May be null. + /// Returns false, if the user has aborted the export + /// process (like clicking Cancel in an additional export settings + /// dialog). + public virtual bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/AmpXml250.cs b/src/KeePass/DataExchange/Formats/AmpXml250.cs new file mode 100644 index 0000000..b59254f --- /dev/null +++ b/src/KeePass/DataExchange/Formats/AmpXml250.cs @@ -0,0 +1,207 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 2.50-3.21+ + internal sealed class AmpXml250 : FileFormatProvider + { + private const string ElemRoot = "AmP_FILE"; + + private const string ElemInfo = "INFO"; + private const string ElemData = "DATA"; + + private const string ElemCategory = "Kategorie"; + private const string ElemTitle = "Bezeichnung"; + private const string ElemUserName = "Benutzername"; + private const string ElemPassword1 = "Passwort1"; + private const string ElemPassword2 = "Passwort2"; + private const string ElemExpiry = "Ablaufdatum"; + private const string ElemUrl = "URL_Programm"; + private const string ElemNotes = "Kommentar"; + + private const string ElemCustom = "Benutzerdefinierte_Felder"; + private const string ElemCustomName = "name"; + private const string ElemCustomValue = "wert"; + + private const string ValueNoData = "n/a"; + private const string ValueNone = "keins"; + private const string ValueNever = "nie"; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Alle meine Passworte XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strDoc = sr.ReadToEnd(); + sr.Close(); + + strDoc = XmlUtil.DecodeHtmlEntities(strDoc); + + ImportFileString(strDoc, pwStorage, slLogger); + } + + private static void ImportFileString(string strXmlDoc, PwDatabase pwStorage, + IStatusLogger slLogger) + { + XmlDocument doc = XmlUtilEx.CreateXmlDocument(); + doc.LoadXml(strXmlDoc); + + XmlElement xmlRoot = doc.DocumentElement; + Debug.Assert(xmlRoot.Name == ElemRoot); + + foreach(XmlNode xmlChild in xmlRoot.ChildNodes) + { + if(xmlChild.Name == ElemData) + LoadDataNode(xmlChild, pwStorage, slLogger); + else if(xmlChild.Name == ElemInfo) { } + else { Debug.Assert(false); } + } + } + + private static void LoadDataNode(XmlNode xmlNode, PwDatabase pwStorage, + IStatusLogger slLogger) + { + uint uCat = 0, uCount = (uint)xmlNode.ChildNodes.Count; + foreach(XmlNode xmlCategory in xmlNode.ChildNodes) + { + LoadCategoryNode(xmlCategory, pwStorage); + ++uCat; + ImportUtil.SetStatus(slLogger, (uCat * 100) / uCount); + } + } + + private static void LoadCategoryNode(XmlNode xmlNode, PwDatabase pwStorage) + { + PwGroup pg = new PwGroup(true, true, xmlNode.Name, PwIcon.Folder); + pwStorage.RootGroup.AddGroup(pg, true); + + PwEntry pe = new PwEntry(true, true); + + foreach(XmlNode xmlChild in xmlNode) + { + string strInner = XmlUtil.SafeInnerText(xmlChild); + if(strInner == ValueNoData) strInner = string.Empty; + + if(xmlChild.Name == ElemCategory) + { + // strInner may contain special characters, thus + // update the group name now + pg.Name = strInner; + } + else if(xmlChild.Name == ElemTitle) + { + AddEntryIfValid(pg, ref pe); + + Debug.Assert(strInner.Length > 0); + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, strInner)); + } + else if(xmlChild.Name == ElemUserName) + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, strInner)); + else if(xmlChild.Name == ElemPassword1) + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, strInner)); + else if(xmlChild.Name == ElemPassword2) + { + if((strInner.Length > 0) && (strInner != ValueNone)) + pe.Strings.Set(PwDefs.PasswordField + @" 2", new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, strInner)); + } + else if(xmlChild.Name == ElemExpiry) + { + if((strInner.Length > 0) && (strInner != ValueNever)) + { + try + { + DateTime dt = DateTime.Parse(strInner); + pe.ExpiryTime = TimeUtil.ToUtc(dt, false); + pe.Expires = true; + } + catch(Exception) { Debug.Assert(false); } + } + } + else if(xmlChild.Name == ElemUrl) + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, strInner)); + else if(xmlChild.Name == ElemNotes) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, strInner)); + else if(xmlChild.Name == ElemCustom) + LoadCustomFields(xmlChild, pe, pwStorage); + else { Debug.Assert(false); } + } + + AddEntryIfValid(pg, ref pe); + } + + private static void AddEntryIfValid(PwGroup pgContainer, ref PwEntry pe) + { + try + { + if(pe == null) return; + if(pe.Strings.ReadSafe(PwDefs.TitleField).Length == 0) return; + + pgContainer.AddEntry(pe, true); + } + finally { pe = new PwEntry(true, true); } + } + + private static void LoadCustomFields(XmlNode xmlNode, PwEntry pe, + PwDatabase pwStorage) + { + string strKey = string.Empty; + + foreach(XmlNode xn in xmlNode.ChildNodes) + { + if(xn.Name == ElemCustomName) + strKey = XmlUtil.SafeInnerText(xn); + else if(xn.Name == ElemCustomValue) + { + if(strKey.Length == 0) { Debug.Assert(false); continue; } + + ImportUtil.AppendToField(pe, strKey, XmlUtil.SafeInnerText(xn), + pwStorage); + } + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/AnyPwCsv144.cs b/src/KeePass/DataExchange/Formats/AnyPwCsv144.cs new file mode 100644 index 0000000..dc83486 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/AnyPwCsv144.cs @@ -0,0 +1,121 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.44 & Pro 1.07 + internal sealed class AnyPwCsv144 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Any Password CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + + string[] vLines = strData.Split(new char[] { '\r', '\n' }, + StringSplitOptions.RemoveEmptyEntries); + + foreach(string strLine in vLines) + { + if(strLine.Length > 5) ProcessCsvLine(strLine, pwStorage); + } + } + + private static void ProcessCsvLine(string strLine, PwDatabase pwStorage) + { + List list = ImportUtil.SplitCsvLine(strLine, ","); + Debug.Assert((list.Count == 6) || (list.Count == 7)); + if(list.Count < 6) return; + bool bIsPro = (list.Count >= 7); // Std exports 6 fields only + + PwEntry pe = new PwEntry(true, true); + pwStorage.RootGroup.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + ParseCsvWord(list[0], false))); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, + ParseCsvWord(list[1], false))); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + ParseCsvWord(list[2], false))); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, + ParseCsvWord(list[3], false))); + + int p = 3; + if(bIsPro) + pe.Strings.Set(KPRes.Custom, new ProtectedString(false, + ParseCsvWord(list[++p], false))); + + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, + ParseCsvWord(list[++p], true))); + + DateTime dt; + if(DateTime.TryParse(ParseCsvWord(list[++p], false), out dt)) + pe.CreationTime = pe.LastAccessTime = pe.LastModificationTime = + TimeUtil.ToUtc(dt, false); + else { Debug.Assert(false); } + } + + private static string ParseCsvWord(string strWord, bool bFixCodes) + { + string str = strWord.Trim(); + + if((str.Length >= 2) && str.StartsWith("\"") && str.EndsWith("\"")) + str = str.Substring(1, str.Length - 2); + + str = str.Replace("\"\"", "\""); + + if(bFixCodes) + { + str = str.Replace("<13>", string.Empty); + str = str.Replace("<10>", "\r\n"); + } + + return str; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/BitwardenJson112.cs b/src/KeePass/DataExchange/Formats/BitwardenJson112.cs new file mode 100644 index 0000000..3e8e964 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/BitwardenJson112.cs @@ -0,0 +1,275 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.12-2022.5.1+ + internal sealed class BitwardenJson112 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Bitwarden JSON"; } } + public override string DefaultExtension { get { return "json"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + using(StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true)) + { + string str = sr.ReadToEnd(); + if(!string.IsNullOrEmpty(str)) + { + CharStream cs = new CharStream(str); + ImportRoot(new JsonObject(cs), pwStorage); + } + } + } + + private static void ImportRoot(JsonObject jo, PwDatabase pd) + { + if(jo.GetValue("encrypted", false)) + throw new FormatException(KPRes.NoEncNoCompress); + + Dictionary dGroups = new Dictionary(); + JsonObject[] vGroups = jo.GetValueArray("folders"); + if(vGroups != null) ImportGroups(vGroups, dGroups, pd); + dGroups[string.Empty] = pd.RootGroup; // Also when vGroups is null + + Dictionary dCollections = new Dictionary(); + JsonObject[] vCollections = jo.GetValueArray("collections"); + if(vCollections != null) ImportCollections(vCollections, dCollections); + + JsonObject[] vEntries = jo.GetValueArray("items"); + if(vEntries != null) ImportEntries(vEntries, dGroups, dCollections, pd); + } + + private static void ImportGroups(JsonObject[] vGroups, + Dictionary dGroups, PwDatabase pd) + { + char[] vSep = new char[] { '/' }; + + foreach(JsonObject jo in vGroups) + { + if(jo == null) { Debug.Assert(false); continue; } + + string strID = (jo.GetValue("id") ?? string.Empty); + string strName = (jo.GetValue("name") ?? string.Empty); + + dGroups[strID] = pd.RootGroup.FindCreateSubTree(strName, vSep); + } + } + + private static void ImportCollections(JsonObject[] vCollections, + Dictionary dCollections) + { + foreach(JsonObject jo in vCollections) + { + if(jo == null) { Debug.Assert(false); continue; } + + string strID = jo.GetValue("id"); + string strName = jo.GetValue("name"); + + if(!string.IsNullOrEmpty(strID) && !string.IsNullOrEmpty(strName)) + dCollections[strID] = strName.Replace("/", " / "); + else { Debug.Assert(false); } + } + } + + private static void ImportEntries(JsonObject[] vEntries, + Dictionary dGroups, Dictionary dCollections, + PwDatabase pd) + { + foreach(JsonObject jo in vEntries) + { + if(jo == null) { Debug.Assert(false); continue; } + + ImportEntry(jo, dGroups, dCollections, pd); + } + } + + private static void ImportEntry(JsonObject jo, Dictionary dGroups, + Dictionary dCollections, PwDatabase pd) + { + PwEntry pe = new PwEntry(true, true); + + PwGroup pg; + string strGroupID = (jo.GetValue("folderId") ?? string.Empty); + dGroups.TryGetValue(strGroupID, out pg); + if(pg == null) { Debug.Assert(false); pg = dGroups[string.Empty]; } + pg.AddEntry(pe, true); + + foreach(string strID in jo.GetValueArray("collectionIds", true)) + { + if(string.IsNullOrEmpty(strID)) { Debug.Assert(false); continue; } + + string strName; + if(dCollections.TryGetValue(strID, out strName)) + pe.AddTag(strName); + else { Debug.Assert(false); } + } + + ImportString(jo, "name", pe, PwDefs.TitleField, pd); + ImportString(jo, "notes", pe, PwDefs.NotesField, pd); + + bool bFav = jo.GetValue("favorite", false); + if(bFav) pe.AddTag(PwDefs.FavoriteTag); + + JsonObject joSub = jo.GetValue("login"); + if(joSub != null) ImportLogin(joSub, pe, pd); + + joSub = jo.GetValue("card"); + if(joSub != null) ImportCard(joSub, pe, pd); + + JsonObject[] v = jo.GetValueArray("fields"); + if(v != null) ImportFields(v, pe, pd); + + joSub = jo.GetValue("identity"); + if(joSub != null) ImportIdentity(joSub, pe, pd); + } + + private static void ImportLogin(JsonObject jo, PwEntry pe, PwDatabase pd) + { + ImportString(jo, "username", pe, PwDefs.UserNameField, pd); + ImportString(jo, "password", pe, PwDefs.PasswordField, pd); + + // https://bitwarden.com/help/authenticator-keys/ + string strOtp = jo.GetValue("totp"); + if((strOtp != null) && strOtp.StartsWith(EntryUtil.OtpAuthScheme + ":", + StrUtil.CaseIgnoreCmp)) + { + try { EntryUtil.ImportOtpAuth(pe, strOtp, pd); } + catch(Exception) { Debug.Assert(false); } + } + else // Null, Steam URI, ... + { + ImportString(jo, "totp", pe, "TOTP", pd); + pe.Strings.EnableProtection("TOTP", true); + } + + foreach(JsonObject joUri in jo.GetValueArray("uris", true)) + { + if(joUri == null) { Debug.Assert(false); continue; } + + string str = joUri.GetValue("uri"); + ImportUtil.CreateFieldWithIndex(pe.Strings, PwDefs.UrlField, + str, pd, false); + } + } + + private static void ImportCard(JsonObject jo, PwEntry pe, PwDatabase pd) + { + ImportString(jo, "cardholderName", pe, PwDefs.UserNameField, pd); + ImportString(jo, "brand", pe, "Brand", pd); + ImportString(jo, "number", pe, PwDefs.UserNameField, pd); + ImportString(jo, "code", pe, PwDefs.PasswordField, pd); + + int iYear, iMonth; + string strYear = (jo.GetValue("expYear") ?? string.Empty); + int.TryParse(strYear, out iYear); + if((iYear >= 1) && (iYear <= 9999)) + { + string strMonth = (jo.GetValue("expMonth") ?? string.Empty); + int.TryParse(strMonth, out iMonth); + if((iMonth <= 0) || (iMonth >= 13)) { Debug.Assert(false); iMonth = 1; } + + pe.Expires = true; + pe.ExpiryTime = TimeUtil.ToUtc(new DateTime(iYear, iMonth, 1), false); + } + else { Debug.Assert(strYear.Length == 0); } + } + + private static void ImportFields(JsonObject[] vFields, PwEntry pe, PwDatabase pd) + { + foreach(JsonObject jo in vFields) + { + if(jo == null) { Debug.Assert(false); continue; } + + string strName = jo.GetValue("name"); + string strValue = (jo.GetValue("value") ?? string.Empty); + long lType = jo.GetValue("type", 0); + + if(!string.IsNullOrEmpty(strName)) + { + ImportUtil.AppendToField(pe, strName, strValue, pd); + + if((lType == 1) && !PwDefs.IsStandardField(strName)) + pe.Strings.EnableProtection(strName, true); + } + else { Debug.Assert(false); } + } + } + + private static void ImportIdentity(JsonObject jo, PwEntry pe, PwDatabase pd) + { + ImportString(jo, "title", pe, PwDefs.UserNameField, pd, " "); + ImportString(jo, "firstName", pe, PwDefs.UserNameField, pd, " "); + ImportString(jo, "middleName", pe, PwDefs.UserNameField, pd, " "); + ImportString(jo, "lastName", pe, PwDefs.UserNameField, pd, " "); + ImportString(jo, "address1", pe, "Address 1", pd); + ImportString(jo, "address2", pe, "Address 2", pd); + ImportString(jo, "address3", pe, "Address 3", pd); + ImportString(jo, "city", pe, "City", pd); + ImportString(jo, "state", pe, "State / Province", pd); + ImportString(jo, "postalCode", pe, "Zip / Postal Code", pd); + ImportString(jo, "country", pe, "Country", pd); + ImportString(jo, "company", pe, "Company", pd); + + string str = jo.GetValue("email"); + if(!string.IsNullOrEmpty(str)) + ImportUtil.AppendToField(pe, PwDefs.UrlField, "mailto:" + str, pd); + + ImportString(jo, "phone", pe, "Phone", pd); + ImportString(jo, "ssn", pe, "Social Security Number", pd); + ImportString(jo, "username", pe, PwDefs.UserNameField, pd); + ImportString(jo, "passportNumber", pe, "Passport Number", pd); + ImportString(jo, "licenseNumber", pe, "License Number", pd); + } + + private static void ImportString(JsonObject jo, string strJsonKey, PwEntry pe, + string strFieldName, PwDatabase pd) + { + ImportString(jo, strJsonKey, pe, strFieldName, pd, null); + } + + private static void ImportString(JsonObject jo, string strJsonKey, PwEntry pe, + string strFieldName, PwDatabase pd, string strSep) + { + string str = jo.GetValue(strJsonKey); + if(string.IsNullOrEmpty(str)) return; + + ImportUtil.AppendToField(pe, strFieldName, str, pd, strSep, false); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/ChromeCsv66.cs b/src/KeePass/DataExchange/Formats/ChromeCsv66.cs new file mode 100644 index 0000000..40a234b --- /dev/null +++ b/src/KeePass/DataExchange/Formats/ChromeCsv66.cs @@ -0,0 +1,88 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class ChromeCsv66 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Google Chrome Passwords CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.Browser; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true); + string str = sr.ReadToEnd(); + sr.Close(); + + CsvOptions opt = new CsvOptions(); + opt.BackslashIsEscape = false; + + CsvStreamReaderEx csr = new CsvStreamReaderEx(str, opt); + + while(true) + { + string[] vLine = csr.ReadLine(); + if(vLine == null) break; + + AddEntry(vLine, pwStorage); + } + } + + private static void AddEntry(string[] vLine, PwDatabase pd) + { + if(vLine.Length != 4) { Debug.Assert(vLine.Length == 0); return; } + + if(vLine[0].Equals("name", StrUtil.CaseIgnoreCmp) && + vLine[1].Equals("url", StrUtil.CaseIgnoreCmp)) + return; + + PwEntry pe = new PwEntry(true, true); + pd.RootGroup.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pd.MemoryProtection.ProtectTitle, vLine[0])); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pd.MemoryProtection.ProtectUrl, vLine[1])); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pd.MemoryProtection.ProtectUserName, vLine[2])); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pd.MemoryProtection.ProtectPassword, vLine[3])); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/CodeWalletTxt605.cs b/src/KeePass/DataExchange/Formats/CodeWalletTxt605.cs new file mode 100644 index 0000000..10fcbba --- /dev/null +++ b/src/KeePass/DataExchange/Formats/CodeWalletTxt605.cs @@ -0,0 +1,114 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 6.05-6.62+ + internal sealed class CodeWalletTxt605 : FileFormatProvider + { + private const string FieldSeparator = "*---------------------------------------------------"; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "CodeWallet TXT"; } } + public override string DefaultExtension { get { return "txt"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Unicode); + string strData = sr.ReadToEnd(); + sr.Close(); + + string[] vLines = strData.Split(new char[] { '\r', '\n' }); + + bool bDoImport = false; + PwEntry pe = new PwEntry(true, true); + bool bInnerSep = false; + bool bEmptyEntry = true; + string strLastIndexedItem = string.Empty; + string strLastLine = string.Empty; + + foreach(string strLine in vLines) + { + if(strLine.Length == 0) continue; + + if(strLine == FieldSeparator) + { + bInnerSep = !bInnerSep; + if(bInnerSep && !bEmptyEntry) + { + pwStorage.RootGroup.AddEntry(pe, true); + + pe = new PwEntry(true, true); + bEmptyEntry = true; + } + else if(!bInnerSep) + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + strLastLine)); + + bDoImport = true; + } + else if(bDoImport) + { + int nIDLen = strLine.IndexOf(": "); + if(nIDLen > 0) + { + string strIndex = strLine.Substring(0, nIDLen); + if(PwDefs.IsStandardField(strIndex)) + strIndex = Guid.NewGuid().ToString(); + + pe.Strings.Set(strIndex, new ProtectedString( + false, strLine.Remove(0, nIDLen + 2))); + + strLastIndexedItem = strIndex; + } + else if(!bEmptyEntry) + { + pe.Strings.Set(strLastIndexedItem, new ProtectedString( + false, pe.Strings.ReadSafe(strLastIndexedItem) + + MessageService.NewParagraph + strLine)); + } + + bEmptyEntry = false; + } + + strLastLine = strLine; + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/DashlaneCsv2.cs b/src/KeePass/DataExchange/Formats/DashlaneCsv2.cs new file mode 100644 index 0000000..1c9c410 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/DashlaneCsv2.cs @@ -0,0 +1,165 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Native; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 2.3.2-5.0.1+, incompatible with 6.2039.0 + internal sealed class DashlaneCsv2 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Dashlane CSV (< 6)"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true); + string str = sr.ReadToEnd(); + sr.Close(); + + // All fields are enclosed in '"', however '"' in data is + // not encoded (broken format) + + str = str.Trim(); + str = StrUtil.NormalizeNewLines(str, false); // To Unix + char chFieldSep = StrUtil.GetUnusedChar(str); + str = str.Replace("\",\"", new string(chFieldSep, 1)); + char chRecSep = StrUtil.GetUnusedChar(str); + str = str.Replace("\"\n\"", new string(chRecSep, 1)); + if(str.StartsWith("\"") && str.EndsWith("\"") && (str.Length >= 2)) + str = str.Substring(1, str.Length - 2); + else { Debug.Assert(false); } + if(!NativeLib.IsUnix()) str = StrUtil.NormalizeNewLines(str, true); + + CsvOptions opt = new CsvOptions(); + opt.BackslashIsEscape = false; + opt.FieldSeparator = chFieldSep; + opt.RecordSeparator = chRecSep; + opt.TextQualifier = char.MinValue; + + CsvStreamReaderEx csr = new CsvStreamReaderEx(str, opt); + + while(true) + { + string[] vLine = csr.ReadLine(); + if(vLine == null) break; + + AddEntry(vLine, pwStorage); + } + } + + private static Regex m_rxIsDate = null; + private static Regex m_rxIsGuid = null; + private static void AddEntry(string[] vLine, PwDatabase pd) + { + int n = vLine.Length; + if(n == 0) return; + + PwEntry pe = new PwEntry(true, true); + pd.RootGroup.AddEntry(pe, true); + + string[] vFields = null; + if(n == 2) + vFields = new string[2] { PwDefs.TitleField, PwDefs.UrlField }; + else if(n == 3) + vFields = new string[3] { PwDefs.TitleField, PwDefs.UrlField, + PwDefs.UserNameField }; + else if(n == 4) + { + if((vLine[2].Length == 0) && (vLine[3].Length == 0)) + vFields = new string[4] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.NotesField, PwDefs.NotesField }; + else + vFields = new string[4] { PwDefs.TitleField, PwDefs.NotesField, + PwDefs.UserNameField, PwDefs.NotesField }; + } + else if(n == 5) + vFields = new string[5] { PwDefs.TitleField, PwDefs.UrlField, + PwDefs.UserNameField, PwDefs.PasswordField, PwDefs.NotesField }; + else if(n == 6) + vFields = new string[6] { PwDefs.TitleField, PwDefs.UrlField, + PwDefs.UserNameField, PwDefs.UserNameField, PwDefs.PasswordField, + PwDefs.NotesField }; + else if(n == 7) + vFields = new string[7] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.NotesField, PwDefs.NotesField, PwDefs.NotesField, + PwDefs.NotesField, PwDefs.NotesField }; + + if(m_rxIsDate == null) + { + m_rxIsDate = new Regex(@"^\d{4}-\d+-\d+$"); + m_rxIsGuid = new Regex( + @"^\{[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\}$"); + } + + if((vLine[0].Length == 0) && (n >= 2) && m_rxIsDate.IsMatch(vLine[1])) + { + vFields = null; + + vLine[0] = KPRes.Id; + for(int i = 1; i < n; ++i) + { + string strPart = vLine[i]; + if(strPart.Equals("NO_TYPE", StrUtil.CaseIgnoreCmp) || + m_rxIsGuid.IsMatch(strPart)) + vLine[i] = string.Empty; + } + } + + for(int i = 0; i < n; ++i) + { + string str = vLine[i]; + if(str.Length == 0) continue; + if(str.Equals("dashlaneappcredential", StrUtil.CaseIgnoreCmp)) + continue; + + string strField = ((vFields != null) ? vFields[i] : null); + if(strField == null) + { + if(i == 0) strField = PwDefs.TitleField; + else strField = PwDefs.NotesField; + } + + if(strField == PwDefs.UrlField) + str = ImportUtil.FixUrl(str); + + ImportUtil.AppendToField(pe, strField, str, pd); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/DashlaneJson6.cs b/src/KeePass/DataExchange/Formats/DashlaneJson6.cs new file mode 100644 index 0000000..80a7afd --- /dev/null +++ b/src/KeePass/DataExchange/Formats/DashlaneJson6.cs @@ -0,0 +1,228 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 6.2039.0+ + internal sealed class DashlaneJson6 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Dashlane JSON (\u2265 6)"; } } + public override string DefaultExtension { get { return "json"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + using(StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true)) + { + string str = sr.ReadToEnd(); + if(!string.IsNullOrEmpty(str)) + { + CharStream cs = new CharStream(str); + ImportRoot(new JsonObject(cs), pwStorage); + } + } + } + + private static void ImportRoot(JsonObject jo, PwDatabase pd) + { + foreach(string strType in jo.Items.Keys) + { + if(strType == null) { Debug.Assert(false); continue; } + string strTypeNorm = strType.Trim().ToLower(); + + JsonObject[] vEntries = jo.GetValueArray(strType); + if(vEntries == null) { Debug.Assert(false); continue; } + + foreach(JsonObject joEntry in vEntries) + { + if(joEntry == null) { Debug.Assert(false); continue; } + ImportEntry(joEntry, pd, strTypeNorm); + } + } + } + + private static void ImportEntry(JsonObject jo, PwDatabase pd, string strTypeNorm) + { + PwEntry pe = new PwEntry(true, true); + pd.RootGroup.AddEntry(pe, true); + + if(strTypeNorm.StartsWith("paymentmean")) + strTypeNorm = "paymentmean"; + + switch(strTypeNorm) + { + case "bankstatement": + case "fiscalstatement": + pe.IconId = PwIcon.Homebanking; + break; + + case "driverlicence": + case "idcard": + case "passport": + case "socialsecuritystatement": + pe.IconId = PwIcon.Identity; + break; + + case "email": + pe.IconId = PwIcon.EMail; + break; + + case "identity": + pe.IconId = PwIcon.UserCommunication; + break; + + case "paymentmean": + pe.IconId = PwIcon.Money; + break; + + default: + Debug.Assert(strTypeNorm == "authentifiant"); + break; + } + + foreach(KeyValuePair kvp in jo.Items) + { + string strValue = (kvp.Value as string); + if(strValue == null) + { + Debug.Assert(false); + if(kvp.Value != null) strValue = kvp.Value.ToString(); + } + if(strValue == null) { Debug.Assert(false); continue; } + + // Ignore GUIDs + if(Regex.IsMatch(strValue, "^\\{\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}\\}$", + RegexOptions.Singleline)) + continue; + + string strKey = kvp.Key; + if(strKey == null) { Debug.Assert(false); continue; } + strKey = strKey.Trim(); + if(string.IsNullOrEmpty(strKey)) { Debug.Assert(false); continue; } + if(strKey.StartsWith("BankAccount", StrUtil.CaseIgnoreCmp) && + (strKey.Length > 11)) + strKey = strKey.Substring(11); + if(strKey.IndexOf("Number", StrUtil.CaseIgnoreCmp) >= 0) + strKey = PwDefs.UserNameField; + strKey = (new string(char.ToUpper(strKey[0]), 1)) + + strKey.Substring(1); + + string strNorm = strKey.ToLower(); + switch(strNorm) + { + case "fullname": + case "name": + case "socialsecurityfullname": + strKey = PwDefs.TitleField; + break; + + case "domain": + strKey = PwDefs.UrlField; + break; + + case "expiredate": + DateTime? odt = ParseDate(strValue); + if(odt.HasValue) + { + pe.Expires = true; + pe.ExpiryTime = odt.Value; + strValue = string.Empty; + } + break; + + case "secondarylogin": + strKey = KPRes.UserName + " 2"; + break; + + default: + if(!strNorm.Contains("date") && !strNorm.Contains("time")) + { + string strStd = ImportUtil.MapNameToStandardField(strKey, true); + if(!string.IsNullOrEmpty(strStd)) strKey = strStd; + } + break; + } + + if(strKey == PwDefs.UrlField) + strValue = ImportUtil.FixUrl(strValue); + else if(strNorm.Contains("time")) + strValue = TryConvertTime(strValue); + + if(!string.IsNullOrEmpty(strValue)) + ImportUtil.AppendToField(pe, strKey, strValue, pd); + } + } + + private static DateTime? ParseDate(string str) + { + if(string.IsNullOrEmpty(str)) { Debug.Assert(false); return null; } + + DateTime dt; + if(DateTime.TryParseExact(str.Trim(), "yyyy'-'M'-'d", + NumberFormatInfo.InvariantInfo, DateTimeStyles.AssumeLocal, out dt)) + return TimeUtil.ToUtc(dt, false); + + Debug.Assert(false); + return null; + } + + private static string TryConvertTime(string str) + { + if(string.IsNullOrEmpty(str)) return string.Empty; + + try + { + if(Regex.IsMatch(str, "^\\d+$", RegexOptions.Singleline)) + { + ulong u; + if(ulong.TryParse(str, out u)) + { + DateTime dt = TimeUtil.ConvertUnixTime(u); + if(dt > TimeUtil.UnixRoot) + return TimeUtil.ToDisplayString(dt); + } + else { Debug.Assert(false); } + } + } + catch(Exception) { Debug.Assert(false); } + + return str; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/DataVaultCsv47.cs b/src/KeePass/DataExchange/Formats/DataVaultCsv47.cs new file mode 100644 index 0000000..7695fd5 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/DataVaultCsv47.cs @@ -0,0 +1,95 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; + +namespace KeePass.DataExchange.Formats +{ + // 4.7.35-6.2.7+ + internal sealed class DataVaultCsv47 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "DataVault CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + string strData; + using(StreamReader sr = new StreamReader(sInput, Encoding.Default)) + { + strData = sr.ReadToEnd(); + } + + // Fix new-line sequences + strData = strData.Replace("\r\r\n", "\r\n"); + + CsvStreamReader csv = new CsvStreamReader(strData, false); + while(true) + { + string[] v = csv.ReadLine(); + if(v == null) break; + if(v.Length == 0) continue; + + PwEntry pe = new PwEntry(true, true); + pwStorage.RootGroup.AddEntry(pe, true); + + ImportUtil.AppendToField(pe, PwDefs.TitleField, v[0], pwStorage); + + int p = 1; + while((p + 1) < v.Length) + { + string strMapped = ImportUtil.MapNameToStandardField(v[p], true); + string strKey = (string.IsNullOrEmpty(strMapped) ? v[p] : strMapped); + string strValue = v[p + 1]; + + p += 2; + + if(strKey.Length == 0) + { + if(strValue.Length == 0) continue; + + Debug.Assert(false); + strKey = PwDefs.NotesField; + } + + ImportUtil.AppendToField(pe, strKey, strValue, pwStorage); + } + + if((p < v.Length) && !string.IsNullOrEmpty(v[p])) + ImportUtil.AppendToField(pe, PwDefs.NotesField, v[p], pwStorage); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/DesktopKnoxXml32.cs b/src/KeePass/DataExchange/Formats/DesktopKnoxXml32.cs new file mode 100644 index 0000000..937d882 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/DesktopKnoxXml32.cs @@ -0,0 +1,111 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 3.2+ + internal sealed class DesktopKnoxXml32 : FileFormatProvider + { + private const string ElemRoot = "SafeCatalog"; + + private const string ElemEntry = "SafeElement"; + + private const string ElemCategory = "Category"; + private const string ElemTitle = "Title"; + private const string ElemNotes = "Content"; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "DesktopKnox XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, StrUtil.Utf8); + string strDoc = sr.ReadToEnd(); + sr.Close(); + + XmlDocument doc = XmlUtilEx.CreateXmlDocument(); + doc.LoadXml(strDoc); + + XmlElement xmlRoot = doc.DocumentElement; + Debug.Assert(xmlRoot.Name == ElemRoot); + + Dictionary dictGroups = new Dictionary(); + dictGroups[string.Empty] = pwStorage.RootGroup; + + foreach(XmlNode xmlChild in xmlRoot.ChildNodes) + { + if(xmlChild.Name == ElemEntry) + ImportEntry(xmlChild, pwStorage, dictGroups); + else { Debug.Assert(false); } + } + } + + private static void ImportEntry(XmlNode xmlNode, PwDatabase pwStorage, + Dictionary dGroups) + { + PwEntry pe = new PwEntry(true, true); + string strGroup = string.Empty; + + foreach(XmlNode xmlChild in xmlNode) + { + string strInner = XmlUtil.SafeInnerText(xmlChild); + + if(xmlChild.Name == ElemCategory) + strGroup = strInner; + else if(xmlChild.Name == ElemTitle) + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, strInner)); + else if(xmlChild.Name == ElemNotes) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, strInner)); + } + + PwGroup pg; + dGroups.TryGetValue(strGroup, out pg); + if(pg == null) + { + pg = new PwGroup(true, true); + pg.Name = strGroup; + dGroups[string.Empty].AddGroup(pg, true); + dGroups[strGroup] = pg; + } + pg.AddEntry(pe, true); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/EnpassTxt5.cs b/src/KeePass/DataExchange/Formats/EnpassTxt5.cs new file mode 100644 index 0000000..aa30ce4 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/EnpassTxt5.cs @@ -0,0 +1,140 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 5.3.0.1-6.0.4+ + internal sealed class EnpassTxt5 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Enpass TXT"; } } + public override string DefaultExtension { get { return "txt"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + PwGroup pg = pwStorage.RootGroup; + const string strSep = ": "; // Both ": " and " : " are used + + strData = StrUtil.NormalizeNewLines(strData, false); + + int iSep = strData.IndexOf(strSep); + if(iSep < 0) throw new FormatException(); + string strTitleKey = strData.Substring(0, iSep).Trim(); + if(strTitleKey.Length == 0) throw new FormatException(); + if(strTitleKey.IndexOf('\n') >= 0) throw new FormatException(); + + PwEntry pe = null; + string strName = PwDefs.TitleField; + + string[] vLines = strData.Split('\n'); + foreach(string strLine in vLines) + { + if(strLine == null) { Debug.Assert(false); continue; } + // Do not trim strLine, otherwise strSep might not be detected + + string strValue = strLine; + + iSep = strLine.IndexOf(strSep); + if(iSep >= 0) + { + string strCurName = strLine.Substring(0, iSep).Trim(); + strValue = strLine.Substring(iSep + strSep.Length); + + if(strCurName == strTitleKey) + { + FinishEntry(pe); + + pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + strName = PwDefs.TitleField; + } + else if(strName == PwDefs.NotesField) + strValue = strLine; // Restore + else + { + strName = ImportUtil.MapNameToStandardField(strCurName, true); + if(string.IsNullOrEmpty(strName)) + { + strName = strCurName; + if(string.IsNullOrEmpty(strName)) + { + Debug.Assert(false); + strName = PwDefs.NotesField; + strValue = strLine; // Restore + } + } + } + } + + if(pe != null) + { + strValue = strValue.Trim(); + + if(strValue.Length != 0) + ImportUtil.AppendToField(pe, strName, strValue, pwStorage); + else if(strName == PwDefs.NotesField) + { + ProtectedString ps = pe.Strings.GetSafe(strName); + pe.Strings.Set(strName, ps + MessageService.NewLine); + } + } + else { Debug.Assert(false); } + } + + FinishEntry(pe); + } + + private static void FinishEntry(PwEntry pe) + { + if(pe == null) return; + + List lKeys = pe.Strings.GetKeys(); + foreach(string strKey in lKeys) + { + ProtectedString ps = pe.Strings.GetSafe(strKey); + pe.Strings.Set(strKey, new ProtectedString( + ps.IsProtected, ps.ReadString().Trim())); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/FlexWalletXml17.cs b/src/KeePass/DataExchange/Formats/FlexWalletXml17.cs new file mode 100644 index 0000000..5b70cdf --- /dev/null +++ b/src/KeePass/DataExchange/Formats/FlexWalletXml17.cs @@ -0,0 +1,186 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.7 + internal sealed class FlexWalletXml17 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "FlexWallet XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + private const string ElemRoot = "FlexWallet"; + + // In 1.7 the node names are Pascal-cased and in 2006 they are + // lower-cased. Therefore, compare them case-insensitively. + + private const string ElemCategory = "Category"; + private const string ElemEntry = "Card"; + + private const string ElemField = "Field"; + private const string ElemNotes = "Notes"; + + private const string AttribData = "Description"; // 1.7 + private const string AttribName = "name"; // 2006 + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strDoc = sr.ReadToEnd(); + sr.Close(); + + ImportFileString(strDoc, pwStorage); + } + + private static void ImportFileString(string strXmlDoc, PwDatabase pwStorage) + { + XmlDocument doc = XmlUtilEx.CreateXmlDocument(); + doc.LoadXml(strXmlDoc); + + XmlElement xmlRoot = doc.DocumentElement; + Debug.Assert(xmlRoot.Name == ElemRoot); + + foreach(XmlNode xmlChild in xmlRoot.ChildNodes) + { + if(xmlChild.Name.Equals(ElemCategory, StrUtil.CaseIgnoreCmp)) + ImportCategory(xmlChild, pwStorage.RootGroup, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ImportCategory(XmlNode xmlNode, PwGroup pgContainer, + PwDatabase pwStorage) + { + string strName = ReadNameAttrib(xmlNode); + if(string.IsNullOrEmpty(strName)) strName = KPRes.Group; + + PwGroup pg = new PwGroup(true, true, strName, PwIcon.Folder); + pgContainer.AddGroup(pg, true); + + foreach(XmlNode xmlChild in xmlNode.ChildNodes) + { + if(xmlChild.Name.Equals(ElemEntry, StrUtil.CaseIgnoreCmp)) + ImportEntry(xmlChild, pg, pwStorage); + else if(xmlChild.Name.Equals(ElemCategory, StrUtil.CaseIgnoreCmp)) + ImportCategory(xmlChild, pg, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ImportEntry(XmlNode xmlNode, PwGroup pg, PwDatabase pwStorage) + { + PwEntry pe = new PwEntry(true, true); + + string strTitle = ReadNameAttrib(xmlNode); + if(!string.IsNullOrEmpty(strTitle)) + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, strTitle)); + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name.Equals(ElemField, StrUtil.CaseIgnoreCmp)) + { + string strName = ReadNameAttrib(xmlChild); + if(string.IsNullOrEmpty(strName)) continue; + + string strValue = XmlUtil.SafeInnerText(xmlChild); + + string strKpName = ImportUtil.MapNameToStandardField(strName, true); + if(string.IsNullOrEmpty(strKpName)) strKpName = strName; + + ImportUtil.AppendToField(pe, strKpName, strValue, pwStorage); + } + else if(xmlChild.Name.Equals(ElemNotes, StrUtil.CaseIgnoreCmp)) + ImportUtil.AppendToField(pe, PwDefs.NotesField, + XmlUtil.SafeInnerText(xmlChild), pwStorage); + else { Debug.Assert(false); } + } + + // RenameFields(pe); + pg.AddEntry(pe, true); + } + + private static string ReadNameAttrib(XmlNode xmlNode) + { + if(xmlNode == null) { Debug.Assert(false); return string.Empty; } + + try + { + if(xmlNode.Attributes.GetNamedItem(AttribData) != null) // 1.7 + return (xmlNode.Attributes[AttribData].Value ?? string.Empty); + if(xmlNode.Attributes.GetNamedItem(AttribName) != null) // 2006 + return (xmlNode.Attributes[AttribName].Value ?? string.Empty); + + Debug.Assert(false); + } + catch(Exception) { Debug.Assert(false); } + + return string.Empty; + } + + /* private static void RenameFields(PwEntry pe) + { + string[] vMap = new string[] { + "Acct #", PwDefs.UserNameField, + "Subject", PwDefs.UserNameField, + "Location", PwDefs.UserNameField, + "Combination", PwDefs.PasswordField, + "Username", PwDefs.UserNameField, + "Website", PwDefs.UrlField, + "Serial #", PwDefs.PasswordField, + "Product ID", PwDefs.UserNameField + }; + + Debug.Assert((vMap.Length % 2) == 0); + for(int i = 0; i < vMap.Length; i += 2) + { + string strFrom = vMap[i], strTo = vMap[i + 1]; + + if(pe.Strings.ReadSafe(strTo).Length > 0) continue; + + string strData = pe.Strings.ReadSafe(strFrom); + if(strData.Length > 0) + { + pe.Strings.Set(strTo, new ProtectedString(false, strData)); + if(!pe.Strings.Remove(strFrom)) { Debug.Assert(false); } + } + } + } */ + } +} diff --git a/src/KeePass/DataExchange/Formats/GenericCsv.cs b/src/KeePass/DataExchange/Formats/GenericCsv.cs new file mode 100644 index 0000000..4245bd9 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/GenericCsv.cs @@ -0,0 +1,62 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text; + +using KeePass.Forms; +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class GenericCsv : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return KPRes.CsvTextFile; } } + public override string DisplayName { get { return KPRes.GenericCsvImporter; } } + // public override string DefaultExtension { get { return "*"; } } + public override string DefaultExtension { get { return "csv|tsv|tab|txt|asc"; } } + public override string ApplicationGroup { get { return KPRes.General; } } + + public override Image SmallIcon + { + get { return KeePass.Properties.Resources.B16x16_Wizard; } + } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + byte[] pb = MemUtil.Read(sInput); + + CsvImportForm dlg = new CsvImportForm(); + dlg.InitEx(pwStorage, pb); + UIUtil.ShowDialogAndDestroy(dlg); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/HandySafeProXml12.cs b/src/KeePass/DataExchange/Formats/HandySafeProXml12.cs new file mode 100644 index 0000000..3b22e37 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/HandySafeProXml12.cs @@ -0,0 +1,145 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml.Serialization; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + [XmlRoot("HandySafe")] + public sealed class HspFolder + { + [XmlAttribute("name")] + public string Name { get; set; } + + [XmlElement("Folder")] + public HspFolder[] Folders { get; set; } + + [XmlElement("Card")] + public HspCard[] Cards { get; set; } + } + + public sealed class HspCard + { + [XmlAttribute("name")] + public string Name { get; set; } + + [XmlElement("Field")] + public HspField[] Fields { get; set; } + + public string Note { get; set; } + } + + public sealed class HspField + { + [XmlAttribute("name")] + public string Name { get; set; } + + [XmlText] + public string Value { get; set; } + } + + // 1.2-3.01+ + internal sealed class HandySafeProXml12 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Handy Safe Pro XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + HspFolder hspRoot = XmlUtilEx.Deserialize(sInput); + + AddFolder(pwStorage.RootGroup, hspRoot, false); + } + + private static void AddFolder(PwGroup pgParent, HspFolder hspFolder, + bool bNewGroup) + { + if(hspFolder == null) { Debug.Assert(false); return; } + + PwGroup pg; + if(bNewGroup) + { + pg = new PwGroup(true, true); + pgParent.AddGroup(pg, true); + + if(!string.IsNullOrEmpty(hspFolder.Name)) + pg.Name = hspFolder.Name; + } + else pg = pgParent; + + if(hspFolder.Folders != null) + { + foreach(HspFolder fld in hspFolder.Folders) + AddFolder(pg, fld, true); + } + + if(hspFolder.Cards != null) + { + foreach(HspCard crd in hspFolder.Cards) + AddCard(pg, crd); + } + } + + private static void AddCard(PwGroup pgParent, HspCard hspCard) + { + if(hspCard == null) { Debug.Assert(false); return; } + + PwEntry pe = new PwEntry(true, true); + pgParent.AddEntry(pe, true); + + if(!string.IsNullOrEmpty(hspCard.Name)) + pe.Strings.Set(PwDefs.TitleField, new ProtectedString(false, hspCard.Name)); + + if(!string.IsNullOrEmpty(hspCard.Note)) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString(false, hspCard.Note)); + + if(hspCard.Fields == null) return; + foreach(HspField fld in hspCard.Fields) + { + if(fld == null) { Debug.Assert(false); continue; } + if(string.IsNullOrEmpty(fld.Name) || string.IsNullOrEmpty(fld.Value)) continue; + + string strKey = ImportUtil.MapNameToStandardField(fld.Name, true); + if(string.IsNullOrEmpty(strKey)) strKey = fld.Name; + + string strValue = pe.Strings.ReadSafe(strKey); + if(strValue.Length > 0) strValue += ", "; + strValue += fld.Value; + pe.Strings.Set(strKey, new ProtectedString(false, strValue)); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/HandySafeTxt512.cs b/src/KeePass/DataExchange/Formats/HandySafeTxt512.cs new file mode 100644 index 0000000..e332d49 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/HandySafeTxt512.cs @@ -0,0 +1,139 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 5.12 + internal sealed class HandySafeTxt512 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Handy Safe TXT"; } } + public override string DefaultExtension { get { return "txt"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + private const string StrGroupStart = "[Category: "; + private const string StrGroupEnd = "]"; + private const string StrEntryStart = "[Card, "; + private const string StrEntryEnd = "]"; + private const string StrNotesBegin = "Note:"; + private const string StrFieldSplit = ": "; + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + + strData = strData.Replace("\r", string.Empty); + string[] vLines = strData.Split(new char[] { '\n' }); + + PwGroup pg = pwStorage.RootGroup; + Dictionary dItems = new Dictionary(); + bool bInNotes = false; + + foreach(string strLine in vLines) + { + if(strLine.StartsWith(StrGroupStart) && strLine.EndsWith(StrGroupEnd)) + { + AddEntry(pg, dItems, ref bInNotes); + dItems.Clear(); + + pg = new PwGroup(true, true); + pg.Name = strLine.Substring(StrGroupStart.Length, strLine.Length - + StrGroupStart.Length - StrGroupEnd.Length); + + pwStorage.RootGroup.AddGroup(pg, true); + } + else if(strLine.StartsWith(StrEntryStart) && strLine.EndsWith(StrEntryEnd)) + { + AddEntry(pg, dItems, ref bInNotes); + dItems.Clear(); + } + else if(strLine == StrNotesBegin) bInNotes = true; + else if(bInNotes) + { + if(dItems.ContainsKey(PwDefs.NotesField)) + dItems[PwDefs.NotesField] += MessageService.NewLine + strLine; + else dItems[PwDefs.NotesField] = strLine; + } + else + { + int nSplitPos = strLine.IndexOf(StrFieldSplit); + if(nSplitPos < 0) { Debug.Assert(false); } + else + { + AddField(dItems, strLine.Substring(0, nSplitPos), + strLine.Substring(nSplitPos + StrFieldSplit.Length)); + } + } + } + + AddEntry(pg, dItems, ref bInNotes); + } + + private static void AddField(Dictionary dItems, + string strKey, string strValue) + { + string strKeyTrl = ImportUtil.MapNameToStandardField(strKey, true); + if(string.IsNullOrEmpty(strKeyTrl)) strKeyTrl = strKey; + + if(!dItems.ContainsKey(strKeyTrl)) + { + dItems[strKeyTrl] = strValue; + return; + } + + string strPreValue = dItems[strKeyTrl]; + if((strPreValue.Length > 0) && (strValue.Length > 0)) + strPreValue += ", "; + + dItems[strKeyTrl] = strPreValue + strValue; + } + + private static void AddEntry(PwGroup pg, Dictionary dItems, + ref bool bInNotes) + { + if(dItems.Count == 0) return; + + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + foreach(KeyValuePair kvp in dItems) + pe.Strings.Set(kvp.Key, new ProtectedString(false, kvp.Value)); + + bInNotes = false; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KasperskyPwMgrTxt90.cs b/src/KeePass/DataExchange/Formats/KasperskyPwMgrTxt90.cs new file mode 100644 index 0000000..161bd4f --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KasperskyPwMgrTxt90.cs @@ -0,0 +1,186 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 9.0.2+ + internal sealed class KasperskyPwMgrTxt90 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Kaspersky Password Manager TXT"; } } + public override string DefaultExtension { get { return "txt"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + string strAll; + using(StreamReader sr = new StreamReader(sInput, Encoding.UTF8, true)) + { + strAll = sr.ReadToEnd(); + } + + // Fix new-line sequences and normalize to '\n' + strAll = strAll.Replace("\r\r\n", "\r\n"); + strAll = StrUtil.NormalizeNewLines(strAll, false); + + string[] vBlocks = strAll.Split(new string[] { "\n\n---\n\n" }, + StringSplitOptions.None); + PwGroup pg = pwStorage.RootGroup; + + foreach(string strBlock in vBlocks) + ImportBlock(pwStorage, ref pg, strBlock); + } + + private static void ImportBlock(PwDatabase pd, ref PwGroup pg, string strBlock) + { + if(strBlock == null) { Debug.Assert(false); return; } + strBlock = strBlock.Trim(); + if(strBlock.Length == 0) return; + + string strFirstLine = strBlock; + int iNL = strBlock.IndexOf('\n'); + if(iNL >= 0) strFirstLine = strBlock.Substring(0, iNL).Trim(); + + if(strFirstLine.IndexOf(':') < 0) + { + if(strFirstLine.Length == 0) { Debug.Assert(false); pg = pd.RootGroup; } + else + { + pg = new PwGroup(true, true); + pg.Name = strFirstLine; + + if(strFirstLine.Equals("Websites", StrUtil.CaseIgnoreCmp)) + pg.IconId = PwIcon.World; + else if(strFirstLine.Equals("Applications", StrUtil.CaseIgnoreCmp)) + pg.IconId = PwIcon.Run; + else if(strFirstLine.Equals("Notes", StrUtil.CaseIgnoreCmp)) + pg.IconId = PwIcon.Note; + + pd.RootGroup.AddGroup(pg, true); + } + + if(iNL < 0) return; // Group without entry + strBlock = strBlock.Substring(iNL + 1).Trim(); + } + + if(strBlock.Length != 0) + { + string[] vLines = strBlock.Split('\n'); + ImportEntry(pd, pg, vLines); + } + } + + private static void ImportEntry(PwDatabase pd, PwGroup pg, string[] vLines) + { + PwEntry pe = new PwEntry(true, true); + bool bFoundData = false; + + StringBuilder sbNotes = new StringBuilder(); + bool bInNotes = false; + + foreach(string strLine in vLines) + { + if(bInNotes) { sbNotes.AppendLine(strLine); continue; } + + int iSep = strLine.IndexOf(':'); + if(iSep < 0) + { + Debug.Assert(false); + string str = strLine.Trim(); + if(str.Length != 0) sbNotes.AppendLine(str); + continue; + } + + string strKey = strLine.Substring(0, iSep).Trim(); + if(strKey.Length == 0) + { + Debug.Assert(false); + strKey = PwDefs.NotesField; + } + + string strValue = strLine.Substring(iSep + 1).Trim(); + + bFoundData |= (strValue.Length != 0); + + string strKeyL = strKey.ToLowerInvariant(); + switch(strKeyL) + { + case "website name": + case "login name": // Name of a user/password pair + case "application": + case "name": // Secure note + strKey = PwDefs.TitleField; + break; + + case "login": + strKey = PwDefs.UserNameField; + break; + + case "password": + strKey = PwDefs.PasswordField; + break; + + case "website url": + strKey = PwDefs.UrlField; + break; + + case "comment": + case "text": // Secure note + strKey = PwDefs.NotesField; + break; + + default: + Debug.Assert(false); + string strMapped = ImportUtil.MapNameToStandardField( + strKey, true); + if(!string.IsNullOrEmpty(strMapped)) + strKey = strMapped; + break; + } + + if(strKey == PwDefs.NotesField) + { + sbNotes.AppendLine(strValue); + bInNotes = true; + } + else ImportUtil.AppendToField(pe, strKey, strValue, pd); + } + + string strNotes = sbNotes.ToString().Trim(); + ImportUtil.AppendToField(pe, PwDefs.NotesField, strNotes, pd); + + if(bFoundData) pg.AddEntry(pe, true); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KasperskyPwMgrXml50.cs b/src/KeePass/DataExchange/Formats/KasperskyPwMgrXml50.cs new file mode 100644 index 0000000..c6c2a02 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KasperskyPwMgrXml50.cs @@ -0,0 +1,42 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; + +namespace KeePass.DataExchange.Formats +{ + // Sticky Password is basically the same password manager as + // Kaspersky Password Manager, and the exported XML files + // are exactly the same. + + // 5.0.0.148-5.0.0.183+ + internal sealed class KasperskyPwMgrXml50 : StickyPwXml50 + { + public override string FormatName { get { return "Kaspersky Password Manager XML"; } } + } +} diff --git a/src/KeePass/DataExchange/Formats/KeePassCsv1x.cs b/src/KeePass/DataExchange/Formats/KeePassCsv1x.cs new file mode 100644 index 0000000..4df190c --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeePassCsv1x.cs @@ -0,0 +1,180 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePassLib; +using KeePassLib.Delegates; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class KeePassCsv1x : FileFormatProvider + { + public override bool SupportsImport { get { return false; } } + public override bool SupportsExport { get { return true; } } + + public override string FormatName { get { return "KeePass CSV (1.x)"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return PwDefs.ShortProductName; } } + + /* public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.UTF8); + string strFileContents = sr.ReadToEnd(); + sr.Close(); + + CharStream csSource = new CharStream(strFileContents); + + while(true) + { + if(!ReadEntry(pwStorage, csSource)) break; + } + } + + private static bool ReadEntry(PwDatabase pwStorage, CharStream csSource) + { + PwEntry pe = new PwEntry(true, true); + + string strTitle = ReadCsvField(csSource); + if(strTitle == null) return false; // No entry available + + string strUser = ReadCsvField(csSource); + if(strUser == null) throw new InvalidDataException(); + + string strPassword = ReadCsvField(csSource); + if(strPassword == null) throw new InvalidDataException(); + + string strUrl = ReadCsvField(csSource); + if(strUrl == null) throw new InvalidDataException(); + + string strNotes = ReadCsvField(csSource); + if(strNotes == null) throw new InvalidDataException(); + + if((strTitle == "Account") && (strUser == "Login Name") && + (strPassword == "Password") && (strUrl == "Web Site") && + (strNotes == "Comments")) + { + return true; // Ignore header entry + } + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, strTitle)); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, strUser)); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, strPassword)); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, strUrl)); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, strNotes)); + + pwStorage.RootGroup.AddEntry(pe, true); + return true; + } + + private static string ReadCsvField(CharStream csSource) + { + StringBuilder sb = new StringBuilder(); + bool bInField = false; + + while(true) + { + char ch = csSource.ReadChar(); + if(ch == char.MinValue) + return null; + + if((ch == '\"') && !bInField) + bInField = true; + else if((ch == '\"') && bInField) + break; + else if(ch == '\\') + { + char chSub = csSource.ReadChar(); + if(chSub == char.MinValue) + throw new InvalidDataException(); + + sb.Append(chSub); + } + else if(bInField) + sb.Append(ch); + } + + return sb.ToString(); + } */ + + public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + PwGroup pg = (pwExportInfo.DataGroup ?? ((pwExportInfo.ContextDatabase != + null) ? pwExportInfo.ContextDatabase.RootGroup : null)); + + StreamWriter sw = new StreamWriter(sOutput, StrUtil.Utf8); + sw.Write("\"Account\",\"Login Name\",\"Password\",\"Web Site\",\"Comments\"\r\n"); + + EntryHandler eh = delegate(PwEntry pe) + { + WriteCsvEntry(sw, pe); + return true; + }; + + if(pg != null) pg.TraverseTree(TraversalMethod.PreOrder, null, eh); + + sw.Close(); + return true; + } + + private static void WriteCsvEntry(StreamWriter sw, PwEntry pe) + { + if(sw == null) { Debug.Assert(false); return; } + if(pe == null) { Debug.Assert(false); return; } + + const string strSep = "\",\""; + + sw.Write("\""); + WriteCsvString(sw, pe.Strings.ReadSafe(PwDefs.TitleField), strSep); + WriteCsvString(sw, pe.Strings.ReadSafe(PwDefs.UserNameField), strSep); + WriteCsvString(sw, pe.Strings.ReadSafe(PwDefs.PasswordField), strSep); + WriteCsvString(sw, pe.Strings.ReadSafe(PwDefs.UrlField), strSep); + WriteCsvString(sw, pe.Strings.ReadSafe(PwDefs.NotesField), "\"\r\n"); + } + + private static void WriteCsvString(StreamWriter sw, string strText, + string strAppend) + { + string str = strText; + if(!string.IsNullOrEmpty(str)) + { + str = str.Replace("\\", "\\\\"); + str = str.Replace("\"", "\\\""); + + sw.Write(str); + } + + if(!string.IsNullOrEmpty(strAppend)) sw.Write(strAppend); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KeePassHtml2x.cs b/src/KeePass/DataExchange/Formats/KeePassHtml2x.cs new file mode 100644 index 0000000..a3168b0 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeePassHtml2x.cs @@ -0,0 +1,121 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Windows.Forms; + +using KeePass.Forms; +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class KeePassHtml2x : FileFormatProvider + { + public override bool SupportsImport { get { return false; } } + public override bool SupportsExport { get { return true; } } + + public override string FormatName { get { return KPRes.CustomizableHtml; } } + public override string DefaultExtension { get { return "html|htm"; } } + public override string ApplicationGroup { get { return KPRes.General; } } + + public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + ImageList il = null; + MainForm mf = Program.MainForm; + if((mf != null) && (mf.ActiveDatabase == pwExportInfo.ContextDatabase)) + il = mf.ClientIcons; + + PrintForm dlg = new PrintForm(); + dlg.InitEx(pwExportInfo.DataGroup, pwExportInfo.ContextDatabase, il, + false, -1); + + bool bResult = false; + try + { + if(dlg.ShowDialog() == DialogResult.OK) + { + byte[] pb = StrUtil.Utf8.GetBytes(dlg.GeneratedHtml); + sOutput.Write(pb, 0, pb.Length); + sOutput.Close(); + + bResult = true; + } + } + finally { UIUtil.DestroyForm(dlg); } + + return bResult; + } + + internal static StringBuilder HtmlPart1ToHead(bool bRtl, string strTitle) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine(""); + + sb.Append(""); + + sb.AppendLine(""); + sb.AppendLine(""); + sb.AppendLine(""); + sb.AppendLine(""); + sb.AppendLine(""); + sb.AppendLine(""); + + sb.Append(""); + sb.Append(StrUtil.StringToHtml(strTitle)); + sb.AppendLine(""); + + return sb; + } + + internal static void HtmlPart2ToStyle(StringBuilder sb) + { + sb.AppendLine(""); + sb.AppendLine(""); + sb.AppendLine(""); + } + + internal static void HtmlPart4ToEnd(StringBuilder sb) + { + sb.AppendLine(""); + sb.AppendLine(""); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KeePassKdb1x.cs b/src/KeePass/DataExchange/Formats/KeePassKdb1x.cs new file mode 100644 index 0000000..3a2df42 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeePassKdb1x.cs @@ -0,0 +1,123 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Native; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class KeePassKdb1x : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return true; } } + + public override string FormatName { get { return "KeePass KDB (1.x)"; } } + public override string DefaultExtension { get { return KeePassKdb1x.FileExt1; } } + public override string ApplicationGroup { get { return PwDefs.ShortProductName; } } + + public override bool RequiresKey { get { return true; } } + public override bool SupportsUuids { get { return true; } } + + public override Image SmallIcon + { + get { return KeePass.Properties.Resources.B16x16_KeePass; } + } + + internal const string FileExt1 = "kdb"; + internal const string FileExt2 = "pwd"; + + public override bool TryBeginImport() + { + if(NativeLib.IsUnix()) + { + MessageService.ShowWarning(KPRes.KeePassLibCNotWindows, + KPRes.KeePassLibCNotWindowsHint); + return false; + } + + Exception exLib; + if(!KdbFile.IsLibraryInstalled(out exLib)) + { + MessageService.ShowWarning(KPRes.KeePassLibCNotFound, + KPRes.KdbKeePassLibC, exLib); + return false; + } + + return true; + } + + public override bool TryBeginExport() + { + return TryBeginImport(); + } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + string strTempFile = Program.TempFilesPool.GetTempFileName(); + + BinaryReader br = new BinaryReader(sInput); + byte[] pb = br.ReadBytes((int)sInput.Length); + br.Close(); + File.WriteAllBytes(strTempFile, pb); + + KdbFile kdb = new KdbFile(pwStorage, slLogger); + kdb.Load(strTempFile); + + Program.TempFilesPool.Delete(strTempFile); + } + + public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + PwDatabase pd = (pwExportInfo.ContextDatabase ?? new PwDatabase()); + + string strTempFile = Program.TempFilesPool.GetTempFileName(false); + + try + { + KdbFile kdb = new KdbFile(pd, slLogger); + kdb.Save(strTempFile, pwExportInfo.DataGroup); + + byte[] pbKdb = File.ReadAllBytes(strTempFile); + sOutput.Write(pbKdb, 0, pbKdb.Length); + MemUtil.ZeroByteArray(pbKdb); + } + catch(Exception exKdb) + { + if(slLogger != null) slLogger.SetText(exKdb.Message, LogStatusType.Error); + + return false; + } + finally { Program.TempFilesPool.Delete(strTempFile); } + + return true; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KeePassKdb2x.cs b/src/KeePass/DataExchange/Formats/KeePassKdb2x.cs new file mode 100644 index 0000000..6663f8f --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeePassKdb2x.cs @@ -0,0 +1,159 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Text; + +using KeePass.App; +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Collections; +using KeePassLib.Cryptography.Cipher; +using KeePassLib.Cryptography.KeyDerivation; +using KeePassLib.Delegates; +using KeePassLib.Interfaces; +using KeePassLib.Serialization; + +namespace KeePass.DataExchange.Formats +{ + internal class KeePassKdb2x : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return true; } } + + public override string FormatName { get { return "KeePass KDBX (2.x)"; } } + public override string DefaultExtension { get { return AppDefs.FileExtension.FileExt; } } + public override string ApplicationGroup { get { return PwDefs.ShortProductName; } } + + public override bool RequiresKey { get { return true; } } + public override bool SupportsUuids { get { return true; } } + + public override Image SmallIcon + { + get { return KeePass.Properties.Resources.B16x16_KeePass; } + } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + KdbxFile kdbx = new KdbxFile(pwStorage); + kdbx.Load(sInput, KdbxFormat.Default, slLogger); + } + + public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + KdbxFile kdbx = new KdbxFile(pwExportInfo.ContextDatabase); + kdbx.Save(sOutput, pwExportInfo.DataGroup, KdbxFormat.Default, slLogger); + return true; + } + } + + // KDBX 3.1 export module + internal sealed class KeePassKdb2x3 : KeePassKdb2x + { + // Only list base class as import module + public override bool SupportsImport { get { return false; } } + + public override string FormatName + { + get { return ("KeePass KDBX (2.34, " + KPRes.OldFormat + ")"); } + } + + public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + PwDatabase pd = pwExportInfo.ContextDatabase; + PwGroup pgRoot = pwExportInfo.DataGroup; + + // Remove everything that requires KDBX 4 or higher; + // see also KdbxFile.GetMinKdbxVersion + + PwUuid puCipher = pd.DataCipherUuid; + if(puCipher.Equals(ChaCha20Engine.ChaCha20Uuid)) + pd.DataCipherUuid = StandardAesEngine.AesUuid; + + KdfParameters pKdf = pd.KdfParameters; + AesKdf kdfAes = new AesKdf(); + if(!pKdf.KdfUuid.Equals(kdfAes.Uuid)) + pd.KdfParameters = kdfAes.GetDefaultParameters(); + + VariantDictionary vdPublic = pd.PublicCustomData; + pd.PublicCustomData = new VariantDictionary(); + + List lCustomGK = new List(); + List lCustomGV = new List(); + List lCustomEK = new List(); + List lCustomEV = new List(); + + GroupHandler gh = delegate(PwGroup pg) + { + if(pg == null) { Debug.Assert(false); return true; } + if(pg.CustomData.Count > 0) + { + lCustomGK.Add(pg); + lCustomGV.Add(pg.CustomData); + pg.CustomData = new StringDictionaryEx(); + } + return true; + }; + EntryHandler eh = delegate(PwEntry pe) + { + if(pe == null) { Debug.Assert(false); return true; } + if(pe.CustomData.Count > 0) + { + lCustomEK.Add(pe); + lCustomEV.Add(pe.CustomData); + pe.CustomData = new StringDictionaryEx(); + } + return true; + }; + + gh(pgRoot); + pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, eh); + + try + { + KdbxFile kdbx = new KdbxFile(pd); + kdbx.ForceVersion = KdbxFile.FileVersion32_3_1; + kdbx.Save(sOutput, pgRoot, KdbxFormat.Default, slLogger); + } + finally + { + // Restore + + pd.DataCipherUuid = puCipher; + pd.KdfParameters = pKdf; + pd.PublicCustomData = vdPublic; + + for(int i = 0; i < lCustomGK.Count; ++i) + lCustomGK[i].CustomData = lCustomGV[i]; + for(int i = 0; i < lCustomEK.Count; ++i) + lCustomEK[i].CustomData = lCustomEV[i]; + } + + return true; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KeePassKdb2xRepair.cs b/src/KeePass/DataExchange/Formats/KeePassKdb2xRepair.cs new file mode 100644 index 0000000..b5671ef --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeePassKdb2xRepair.cs @@ -0,0 +1,139 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text; +using System.Windows.Forms; + +using KeePass.App; +using KeePass.Native; +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class KeePassKdb2xRepair : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName + { + get { return "KeePass KDBX (2.x) (" + KPRes.RepairMode + ")"; } + } + public override string DefaultExtension { get { return AppDefs.FileExtension.FileExt; } } + public override string ApplicationGroup { get { return PwDefs.ShortProductName; } } + + public override bool RequiresKey { get { return true; } } + public override bool SupportsUuids { get { return true; } } + + public override Image SmallIcon + { + get { return KeePass.Properties.Resources.B16x16_KeePass; } + } + + public override bool TryBeginImport() + { + string strTitle = KPRes.Warning + "!"; + string strMsg = KPRes.RepairModeInt + MessageService.NewParagraph + + KPRes.RepairModeUse + MessageService.NewParagraph + + KPRes.RepairModeQ; + + int iYes = (int)DialogResult.Yes; + int iNo = (int)DialogResult.No; + int r = VistaTaskDialog.ShowMessageBoxEx(strMsg, strTitle, + PwDefs.ShortProductName, VtdIcon.Warning, null, + KPRes.YesCmd, iYes, KPRes.NoCmd, iNo); + if(r < 0) + r = (MessageService.AskYesNo(strTitle + MessageService.NewParagraph + + strMsg, PwDefs.ShortProductName, false, MessageBoxIcon.Warning) ? + iYes : iNo); + + return ((r == iYes) || (r == (int)DialogResult.OK)); + } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + KdbxFile kdbx = new KdbxFile(pwStorage); + // CappedByteStream s = new CappedByteStream(sInput, 64); + + kdbx.RepairMode = true; + + try { kdbx.Load(sInput, KdbxFormat.Default, slLogger); } + catch(Exception) { } + } + + /* private sealed class CappedByteStream : Stream + { + private Stream m_sBase; + private int m_nMaxRead; + + public override bool CanRead { get { return m_sBase.CanRead; } } + public override bool CanSeek { get { return m_sBase.CanSeek; } } + public override bool CanWrite { get { return m_sBase.CanWrite; } } + public override long Length { get { return m_sBase.Length; } } + public override long Position + { + get { return m_sBase.Position; } + set { m_sBase.Position = value; } + } + + public CappedByteStream(Stream sBase, int nMaxRead) + { + if(sBase == null) throw new ArgumentNullException("sBase"); + if(nMaxRead <= 0) throw new ArgumentException(); + + m_sBase = sBase; + m_nMaxRead = nMaxRead; + } + + public override void Flush() { m_sBase.Flush(); } + + public override int Read(byte[] buffer, int offset, int count) + { + if(count > m_nMaxRead) count = m_nMaxRead; + return m_sBase.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return m_sBase.Seek(offset, origin); + } + + public override void SetLength(long value) + { + m_sBase.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + m_sBase.Write(buffer, offset, count); + } + } */ + } +} diff --git a/src/KeePass/DataExchange/Formats/KeePassXXml041.cs b/src/KeePass/DataExchange/Formats/KeePassXXml041.cs new file mode 100644 index 0000000..d23a840 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeePassXXml041.cs @@ -0,0 +1,219 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Collections; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 0.4.1 + internal sealed class KeePassXXml041 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "KeePassX XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool SupportsUuids { get { return false; } } + + private const string ElemRoot = "database"; + + private const string ElemGroup = "group"; + private const string ElemTitle = "title"; + private const string ElemIcon = "icon"; + + private const string ElemEntry = "entry"; + private const string ElemUserName = "username"; + private const string ElemUrl = "url"; + private const string ElemPassword = "password"; + private const string ElemNotes = "comment"; + private const string ElemCreationTime = "creation"; + private const string ElemLastModTime = "lastmod"; + private const string ElemLastAccessTime = "lastaccess"; + private const string ElemExpiryTime = "expire"; + private const string ElemAttachDesc = "bindesc"; + private const string ElemAttachment = "bin"; + + private const string ValueNever = "Never"; + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + XmlDocument xmlDoc = XmlUtilEx.CreateXmlDocument(); + xmlDoc.Load(sInput); + + XmlNode xmlRoot = xmlDoc.DocumentElement; + Debug.Assert(xmlRoot.Name == ElemRoot); + + Stack vGroups = new Stack(); + vGroups.Push(pwStorage.RootGroup); + + int nNodeCount = xmlRoot.ChildNodes.Count; + for(int i = 0; i < nNodeCount; ++i) + { + XmlNode xmlChild = xmlRoot.ChildNodes[i]; + + if(xmlChild.Name == ElemGroup) + ReadGroup(xmlChild, vGroups, pwStorage); + else { Debug.Assert(false); } + + if(slLogger != null) + slLogger.SetProgress((uint)(((i + 1) * 100) / nNodeCount)); + } + } + + private static PwIcon ReadIcon(XmlNode xmlChild, PwIcon pwDefault) + { + int nIcon; + if(StrUtil.TryParseInt(XmlUtil.SafeInnerText(xmlChild), out nIcon)) + { + if((nIcon >= 0) && (nIcon < (int)PwIcon.Count)) return (PwIcon)nIcon; + } + else { Debug.Assert(false); } + + return pwDefault; + } + + private static void ReadGroup(XmlNode xmlNode, Stack vGroups, + PwDatabase pwStorage) + { + if(vGroups.Count == 0) { Debug.Assert(false); return; } + PwGroup pgParent = vGroups.Peek(); + + PwGroup pg = new PwGroup(true, true); + pgParent.AddGroup(pg, true); + vGroups.Push(pg); + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemTitle) + pg.Name = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemIcon) + pg.IconId = ReadIcon(xmlChild, pg.IconId); + else if(xmlChild.Name == ElemGroup) + ReadGroup(xmlChild, vGroups, pwStorage); + else if(xmlChild.Name == ElemEntry) + ReadEntry(xmlChild, pg, pwStorage); + else { Debug.Assert(false); } + } + + vGroups.Pop(); + } + + private static void ReadEntry(XmlNode xmlNode, PwGroup pgParent, + PwDatabase pwStorage) + { + PwEntry pe = new PwEntry(true, true); + pgParent.AddEntry(pe, true); + + string strAttachDesc = null, strAttachment = null; + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemTitle) + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemUserName) + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemUrl) + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemPassword) + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemNotes) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, + FilterSpecial(XmlUtil.SafeInnerXml(xmlChild)))); + else if(xmlChild.Name == ElemIcon) + pe.IconId = ReadIcon(xmlChild, pe.IconId); + else if(xmlChild.Name == ElemCreationTime) + pe.CreationTime = ParseTime(XmlUtil.SafeInnerText(xmlChild)); + else if(xmlChild.Name == ElemLastModTime) + pe.LastModificationTime = ParseTime(XmlUtil.SafeInnerText(xmlChild)); + else if(xmlChild.Name == ElemLastAccessTime) + pe.LastAccessTime = ParseTime(XmlUtil.SafeInnerText(xmlChild)); + else if(xmlChild.Name == ElemExpiryTime) + { + string strDate = XmlUtil.SafeInnerText(xmlChild); + pe.Expires = (strDate != ValueNever); + if(pe.Expires) pe.ExpiryTime = ParseTime(strDate); + } + else if(xmlChild.Name == ElemAttachDesc) + strAttachDesc = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemAttachment) + strAttachment = XmlUtil.SafeInnerText(xmlChild); + else { Debug.Assert(false); } + } + + if(!string.IsNullOrEmpty(strAttachDesc) && (strAttachment != null)) + { + byte[] pbData = Convert.FromBase64String(strAttachment); + ProtectedBinary pb = new ProtectedBinary(false, pbData); + pe.Binaries.Set(strAttachDesc, pb); + } + } + + private static DateTime ParseTime(string str) + { + if(string.IsNullOrEmpty(str)) { Debug.Assert(false); return DateTime.UtcNow; } + if(str == "0000-00-00T00:00:00") return DateTime.UtcNow; + + DateTime dt; + if(DateTime.TryParse(str, out dt)) + return TimeUtil.ToUtc(dt, false); + + Debug.Assert(false); + return DateTime.UtcNow; + } + + private static string FilterSpecial(string strData) + { + string str = strData; + + str = str.Replace(@"
", MessageService.NewLine); + str = str.Replace(@"
", MessageService.NewLine); + + str = StrUtil.XmlToString(str); + return str; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KeePassXml1x.cs b/src/KeePass/DataExchange/Formats/KeePassXml1x.cs new file mode 100644 index 0000000..fb432ba --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeePassXml1x.cs @@ -0,0 +1,204 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Collections; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class KeePassXml1x : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "KeePass XML (1.x)"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return PwDefs.ShortProductName; } } + + public override bool SupportsUuids { get { return true; } } + + private const string ElemRoot = "pwlist"; + private const string ElemEntry = "pwentry"; + private const string ElemGroup = "group"; + private const string ElemTitle = "title"; + private const string ElemUserName = "username"; + private const string ElemUrl = "url"; + private const string ElemPassword = "password"; + private const string ElemNotes = "notes"; + private const string ElemUuid = "uuid"; + private const string ElemImage = "image"; + private const string ElemCreationTime = "creationtime"; + private const string ElemLastModTime = "lastmodtime"; + private const string ElemLastAccessTime = "lastaccesstime"; + private const string ElemExpiryTime = "expiretime"; + private const string ElemAttachDesc = "attachdesc"; + private const string ElemAttachment = "attachment"; + + private const string AttribGroupTree = "tree"; + private const string AttribExpires = "expires"; + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + XmlDocument xmlDoc = XmlUtilEx.CreateXmlDocument(); + xmlDoc.Load(sInput); + + XmlNode xmlRoot = xmlDoc.DocumentElement; + Debug.Assert(xmlRoot.Name == ElemRoot); + + int nNodeCount = xmlRoot.ChildNodes.Count; + for(int i = 0; i < nNodeCount; ++i) + { + XmlNode xmlChild = xmlRoot.ChildNodes[i]; + + if(xmlChild.Name == ElemEntry) + ReadEntry(xmlChild, pwStorage); + else { Debug.Assert(false); } + + if(slLogger != null) + slLogger.SetProgress((uint)(((i + 1) * 100) / nNodeCount)); + } + } + + private static void ReadEntry(XmlNode xmlNode, PwDatabase pwStorage) + { + PwEntry pe = new PwEntry(true, true); + PwGroup pg = pwStorage.RootGroup; + + string strAttachDesc = null, strAttachment = null; + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemGroup) + { + string strPreTree = null; + try + { + XmlNode xmlTree = xmlChild.Attributes.GetNamedItem(AttribGroupTree); + strPreTree = xmlTree.Value; + } + catch(Exception) { } + + string strLast = XmlUtil.SafeInnerText(xmlChild); + string strGroup = ((!string.IsNullOrEmpty(strPreTree)) ? + strPreTree + "\\" + strLast : strLast); + + pg = pwStorage.RootGroup.FindCreateSubTree(strGroup, + new string[1] { "\\" }, true); + } + else if(xmlChild.Name == ElemTitle) + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemUserName) + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemUrl) + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemPassword) + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemNotes) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemUuid) + pe.SetUuid(new PwUuid(MemUtil.HexStringToByteArray( + XmlUtil.SafeInnerText(xmlChild))), false); + else if(xmlChild.Name == ElemImage) + { + int nImage; + if(int.TryParse(XmlUtil.SafeInnerText(xmlChild), out nImage)) + { + if((nImage >= 0) && (nImage < (int)PwIcon.Count)) + pe.IconId = (PwIcon)nImage; + else { Debug.Assert(false); } + } + else { Debug.Assert(false); } + } + else if(xmlChild.Name == ElemCreationTime) + pe.CreationTime = ParseTime(XmlUtil.SafeInnerText(xmlChild)); + else if(xmlChild.Name == ElemLastModTime) + pe.LastModificationTime = ParseTime(XmlUtil.SafeInnerText(xmlChild)); + else if(xmlChild.Name == ElemLastAccessTime) + pe.LastAccessTime = ParseTime(XmlUtil.SafeInnerText(xmlChild)); + else if(xmlChild.Name == ElemExpiryTime) + { + try + { + XmlNode xmlExpires = xmlChild.Attributes.GetNamedItem(AttribExpires); + if(StrUtil.StringToBool(xmlExpires.Value)) + { + pe.Expires = true; + pe.ExpiryTime = ParseTime(XmlUtil.SafeInnerText(xmlChild)); + } + else { Debug.Assert(ParseTime(XmlUtil.SafeInnerText(xmlChild)).Year == 2999); } + } + catch(Exception) { Debug.Assert(false); } + } + else if(xmlChild.Name == ElemAttachDesc) + strAttachDesc = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemAttachment) + strAttachment = XmlUtil.SafeInnerText(xmlChild); + else { Debug.Assert(false); } + } + + if(!string.IsNullOrEmpty(strAttachDesc) && (strAttachment != null)) + { + byte[] pbData = Convert.FromBase64String(strAttachment); + ProtectedBinary pb = new ProtectedBinary(false, pbData); + pe.Binaries.Set(strAttachDesc, pb); + } + + pg.AddEntry(pe, true); + } + + private static DateTime ParseTime(string str) + { + if(string.IsNullOrEmpty(str)) { Debug.Assert(false); return DateTime.UtcNow; } + if(str == "0000-00-00T00:00:00") return DateTime.UtcNow; + + DateTime dt; + if(DateTime.TryParse(str, out dt)) + return TimeUtil.ToUtc(dt, false); + + Debug.Assert(false); + return DateTime.UtcNow; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KeePassXml2x.cs b/src/KeePass/DataExchange/Formats/KeePassXml2x.cs new file mode 100644 index 0000000..d1b6f4b --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeePassXml2x.cs @@ -0,0 +1,73 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Collections; +using KeePassLib.Interfaces; +using KeePassLib.Serialization; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class KeePassXml2x : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return true; } } + + public override string FormatName { get { return "KeePass XML (2.x)"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return PwDefs.ShortProductName; } } + + public override bool SupportsUuids { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + KdbxFile kdbx = new KdbxFile(pwStorage); + kdbx.Load(sInput, KdbxFormat.PlainXml, slLogger); + } + + public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + PwDatabase pd = (pwExportInfo.ContextDatabase ?? new PwDatabase()); + + PwObjectList vDel = null; + if(!pwExportInfo.ExportDeletedObjects) + { + vDel = pd.DeletedObjects.CloneShallow(); + pd.DeletedObjects.Clear(); + } + + KdbxFile kdb = new KdbxFile(pd); + kdb.Save(sOutput, pwExportInfo.DataGroup, KdbxFormat.PlainXml, slLogger); + + // Restore deleted objects list + if(vDel != null) pd.DeletedObjects.Add(vDel); + + return true; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KeeperJson16.cs b/src/KeePass/DataExchange/Formats/KeeperJson16.cs new file mode 100644 index 0000000..00d3afd --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeeperJson16.cs @@ -0,0 +1,134 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 16.0.0+ + internal sealed class KeeperJson16 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Keeper JSON"; } } + public override string DefaultExtension { get { return "json"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + using(StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true)) + { + string str = sr.ReadToEnd(); + if(string.IsNullOrEmpty(str)) { Debug.Assert(false); return; } + + CharStream cs = new CharStream(str); + JsonObject joRoot = new JsonObject(cs); + + JsonObject[] v = joRoot.GetValueArray("records"); + ImportRecords(v, pwStorage); + } + } + + private static void ImportRecords(JsonObject[] v, PwDatabase pd) + { + if(v == null) { Debug.Assert(false); return; } + + Dictionary dGroups = new Dictionary(); + string strGroupSep = MemUtil.ByteArrayToHexString(Guid.NewGuid().ToByteArray()); + string strBackspCode = MemUtil.ByteArrayToHexString(Guid.NewGuid().ToByteArray()); + + foreach(JsonObject jo in v) + { + if(jo == null) { Debug.Assert(false); continue; } + + PwEntry pe = new PwEntry(true, true); + + ImportUtil.AppendToField(pe, PwDefs.TitleField, + jo.GetValue("title"), pd); + ImportUtil.AppendToField(pe, PwDefs.UserNameField, + jo.GetValue("login"), pd); + ImportUtil.AppendToField(pe, PwDefs.PasswordField, + jo.GetValue("password"), pd); + ImportUtil.AppendToField(pe, PwDefs.UrlField, + jo.GetValue("login_url"), pd); + ImportUtil.AppendToField(pe, PwDefs.NotesField, + jo.GetValue("notes"), pd); + + JsonObject joCustom = jo.GetValue("custom_fields"); + if(joCustom != null) + { + foreach(KeyValuePair kvp in joCustom.Items) + { + string strValue = (kvp.Value as string); + if(strValue == null) { Debug.Assert(false); continue; } + + if(kvp.Key == "TFC:Keeper") + { + try { EntryUtil.ImportOtpAuth(pe, strValue, pd); } + catch(Exception) { Debug.Assert(false); } + } + else ImportUtil.AppendToField(pe, kvp.Key, strValue, pd); + } + } + + PwGroup pg = null; + JsonObject[] vFolders = jo.GetValueArray("folders"); + if((vFolders != null) && (vFolders.Length >= 1)) + { + JsonObject joFolder = vFolders[0]; + if(joFolder != null) + { + string strGroup = joFolder.GetValue("folder"); + if(!string.IsNullOrEmpty(strGroup)) + { + strGroup = strGroup.Replace("\\\\", strBackspCode); + strGroup = strGroup.Replace("\\", strGroupSep); + strGroup = strGroup.Replace(strBackspCode, "\\"); + + if(!dGroups.TryGetValue(strGroup, out pg)) + { + pg = pd.RootGroup.FindCreateSubTree(strGroup, + new string[] { strGroupSep }, true); + dGroups[strGroup] = pg; + } + } + else { Debug.Assert(false); } + } + else { Debug.Assert(false); } + } + if(pg == null) pg = pd.RootGroup; + + pg.AddEntry(pe, true); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/KeyFolderXml1.cs b/src/KeePass/DataExchange/Formats/KeyFolderXml1.cs new file mode 100644 index 0000000..f1c962d --- /dev/null +++ b/src/KeePass/DataExchange/Formats/KeyFolderXml1.cs @@ -0,0 +1,186 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.22+ + internal sealed class KeyFolderXml1 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Key Folder XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + using(StreamReader sr = new StreamReader(sInput, Encoding.UTF8, true)) + { + XmlDocument d = XmlUtilEx.CreateXmlDocument(); + d.LoadXml(sr.ReadToEnd()); + + ImportGroup(d.DocumentElement, pwStorage.RootGroup, pwStorage); + } + } + + private static void ImportGroup(XmlNode xnFolder, PwGroup pg, PwDatabase pd) + { + foreach(XmlNode xn in xnFolder.ChildNodes) + { + switch(xn.Name) + { + case "name": + pg.Name = XmlUtil.SafeInnerText(xn); + break; + + case "folder": + PwGroup pgSub = new PwGroup(true, true); + pg.AddGroup(pgSub, true); + ImportGroup(xn, pgSub, pd); + break; + + case "item": + ImportEntry(xn, pg, pd); + break; + + default: + Debug.Assert(false); // Unknown node + break; + } + } + } + + private static void ImportEntry(XmlNode xnItem, PwGroup pg, PwDatabase pd) + { + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + bool bFirstUrl = true; + DateTime? odt; + + foreach(XmlNode xn in xnItem.ChildNodes) + { + switch(xn.Name) + { + case "name": + ImportUtil.AppendToField(pe, PwDefs.TitleField, + XmlUtil.SafeInnerText(xn), pd); + break; + + case "username": + ImportUtil.AppendToField(pe, PwDefs.UserNameField, + XmlUtil.SafeInnerText(xn), pd); + break; + + case "password": + ImportUtil.AppendToField(pe, PwDefs.PasswordField, + XmlUtil.SafeInnerText(xn), pd); + break; + + case "link": + string strType = GetChildValue(xn, "type"); + string strName = GetChildValue(xn, "name"); + string strUrl = GetChildValue(xn, "url"); + if(string.IsNullOrEmpty(strUrl)) continue; + + if(bFirstUrl) + { + strName = PwDefs.UrlField; + bFirstUrl = false; + } + + if(strType == "mail") strUrl = "mailto:" + strUrl; + + ImportUtil.CreateFieldWithIndex(pe.Strings, strName, + strUrl, pd, false); + break; + + case "note": + ImportUtil.AppendToField(pe, PwDefs.NotesField, + XmlUtil.SafeInnerText(xn), pd); + break; + + case "created": + odt = TryParseDate(xn); + if(odt.HasValue) pe.CreationTime = odt.Value; + break; + + case "changed": + odt = TryParseDate(xn); + if(odt.HasValue) pe.LastModificationTime = odt.Value; + break; + + case "expire": + odt = TryParseDate(xn); + if(odt.HasValue) + { + pe.Expires = true; + pe.ExpiryTime = odt.Value; + } + break; + + default: + Debug.Assert(false); // Unknown node + break; + } + } + } + + private static string GetChildValue(XmlNode xn, string strChildName) + { + XmlNode xnChild = XmlUtil.FindMultiChild(xn.ChildNodes, strChildName, 0); + if(xnChild == null) { Debug.Assert(false); return string.Empty; } + return XmlUtil.SafeInnerText(xnChild); + } + + private static DateTime? TryParseDate(XmlNode xn) + { + string str = XmlUtil.SafeInnerText(xn); + if(string.IsNullOrEmpty(str)) { Debug.Assert(false); return null; } + + DateTime dt; + if(!DateTime.TryParseExact(str, @"dd'.'MM'.'yyyy", + CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out dt)) + { + Debug.Assert(false); + if(!StrUtil.TryParseDateTime(str, out dt)) + return null; + } + + return TimeUtil.ToUtc(dt, false); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/LastPassCsv2.cs b/src/KeePass/DataExchange/Formats/LastPassCsv2.cs new file mode 100644 index 0000000..ba5bf09 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/LastPassCsv2.cs @@ -0,0 +1,154 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 2.0.2-4.65.0.5+ + internal sealed class LastPassCsv2 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "LastPass CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return false; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + // The Chrome extension of LastPass 4.1.35 encodes some + // special characters as XML entities; the web version and + // the Firefox extension do not do this + strData = strData.Replace(@"<", @"<"); + strData = strData.Replace(@">", @">"); + strData = strData.Replace(@"&", @"&"); + + CsvOptions opt = new CsvOptions(); + opt.BackslashIsEscape = false; + + CsvStreamReaderEx csr = new CsvStreamReaderEx(strData, opt); + ImportCsv(csr, pwStorage); + } + + private static void ImportCsv(CsvStreamReaderEx csr, PwDatabase pd) + { + CsvTableEntryReader ctr = new CsvTableEntryReader(pd); + + const string strColUrl = "url"; + + Predicate fIsSecNote = delegate(string[] vRow) + { + string str = ctr.GetData(vRow, strColUrl, string.Empty); + return str.Equals("http://sn", StrUtil.CaseIgnoreCmp); + }; + + ctr.SetDataAppend("name", PwDefs.TitleField); + ctr.SetDataAppend("username", PwDefs.UserNameField); + ctr.SetDataAppend("password", PwDefs.PasswordField); + + ctr.SetDataHandler(strColUrl, delegate(string str, PwEntry pe, + string[] vContextRow) + { + if(!fIsSecNote(vContextRow)) + ImportUtil.AppendToField(pe, PwDefs.UrlField, str, pd); + }); + + ctr.SetDataHandler("extra", delegate(string str, PwEntry pe, + string[] vContextRow) + { + if(fIsSecNote(vContextRow) && str.StartsWith("NoteType:", + StrUtil.CaseIgnoreCmp)) + { + AddNoteFields(pe, str, pd); + return; + } + + ImportUtil.AppendToField(pe, PwDefs.NotesField, str, pd); + }); + + ctr.SetDataHandler("grouping", delegate(string str, PwEntry pe, + string[] vContextRow) + { + if(str.Length == 0) return; + + PwGroup pg = pd.RootGroup.FindCreateSubTree(str, + new string[1] { "\\" }, true); + pg.AddEntry(pe, true); + }); + + ctr.SetDataHandler("fav", delegate(string str, PwEntry pe, + string[] vContextRow) + { + if(StrUtil.StringToBool(str)) pe.AddTag(PwDefs.FavoriteTag); + }); + + ctr.Read(csr); + } + + private static void AddNoteFields(PwEntry pe, string strNotes, + PwDatabase pd) + { + string strData = StrUtil.NormalizeNewLines(strNotes, false); + string[] vLines = strData.Split('\n'); + + string strFieldName = PwDefs.NotesField; + bool bNotesFound = false; + foreach(string strLine in vLines) + { + int iFieldLen = strLine.IndexOf(':'); + int iDataOffset = 0; + if((iFieldLen > 0) && !bNotesFound) + { + string strRaw = strLine.Substring(0, iFieldLen).Trim(); + string strField = ImportUtil.MapNameToStandardField(strRaw, false); + if(string.IsNullOrEmpty(strField)) strField = strRaw; + + if(strField.Length != 0) + { + strFieldName = strField; + iDataOffset = iFieldLen + 1; + + bNotesFound |= (strRaw == "Notes"); // Not PwDefs.NotesField + } + } + + ImportUtil.AppendToField(pe, strFieldName, strLine.Substring( + iDataOffset), pd); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/MSecureCsv355.cs b/src/KeePass/DataExchange/Formats/MSecureCsv355.cs new file mode 100644 index 0000000..535e339 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/MSecureCsv355.cs @@ -0,0 +1,318 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 3.5.5+ + internal sealed class MSecureCsv355 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "mSecure CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return false; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default, true); + string str = sr.ReadToEnd(); + sr.Close(); + + CsvOptions opt = new CsvOptions(); + + // Backslashes are not escaped, even though "\\n" is used + // to encode new-line characters + opt.BackslashIsEscape = false; + opt.FieldSeparator = ';'; + + CsvStreamReaderEx csr = new CsvStreamReaderEx(str, opt); + Dictionary dGroups = new Dictionary(); + + while(true) + { + string[] vLine = csr.ReadLine(); + if(vLine == null) break; + + AddEntry(vLine, pwStorage, dGroups); + } + } + + private static void AddEntry(string[] vLine, PwDatabase pd, + Dictionary dGroups) + { + if(vLine.Length < 2) return; + + string strGroup = vLine[0]; + PwGroup pg; + if(string.IsNullOrEmpty(strGroup)) + pg = pd.RootGroup; + else + { + if(!dGroups.TryGetValue(strGroup, out pg)) + { + pg = new PwGroup(true, true); + pg.Name = strGroup; + + pd.RootGroup.AddGroup(pg, true); + dGroups[strGroup] = pg; + } + } + + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + MsAppend(pe, PwDefs.TitleField, vLine, 2, pd); + MsAppend(pe, PwDefs.NotesField, vLine, 3, pd); + + string strType = vLine[1]; + int i = 3; + DateTime dt; + + switch(strType) + { + case "Bank Accounts": + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + MsAppend(pe, "Name", vLine, ++i, pd); + MsAppend(pe, "Branch", vLine, ++i, pd); + MsAppend(pe, "Phone No.", vLine, ++i, pd); + + pe.IconId = PwIcon.Money; + break; + + case "Birthdays": + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + + pe.IconId = PwIcon.UserCommunication; + break; + + case "Calling Cards": + case "Social Security": + case "Voice Mail": + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + + pe.IconId = PwIcon.UserKey; + break; + + case "Clothes Size": + MsAppend(pe, "Shirt Size", vLine, ++i, pd); + MsAppend(pe, "Pant Size", vLine, ++i, pd); + MsAppend(pe, "Shoe Size", vLine, ++i, pd); + MsAppend(pe, "Dress Size", vLine, ++i, pd); + break; + + case "Combinations": + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + break; + + case "Credit Cards": + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + + ++i; + if((vLine.Length > i) && StrUtil.TryParseDateTime( + vLine[i], out dt)) + { + pe.Expires = true; + pe.ExpiryTime = TimeUtil.ToUtc(dt, false); + } + else MsAppend(pe, "Expiration", vLine, i, pd); + + MsAppend(pe, "Name", vLine, ++i, pd); + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + MsAppend(pe, "Bank", vLine, ++i, pd); + MsAppend(pe, "Security Code", vLine, ++i, pd); + + pe.IconId = PwIcon.Money; + break; + + case "Email Accounts": + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + MsAppend(pe, "POP3 Host", vLine, ++i, pd); + MsAppend(pe, "SMTP Host", vLine, ++i, pd); + + pe.IconId = PwIcon.EMail; + break; + + case "Frequent Flyer": + MsAppend(pe, "Number", vLine, ++i, pd); + MsAppend(pe, PwDefs.UrlField, vLine, ++i, pd); + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + MsAppend(pe, "Mileage", vLine, ++i, pd); + break; + + case "Identity": + ++i; + MsAppend(pe, PwDefs.UserNameField, vLine, i + 1, pd); // Last name + MsAppend(pe, PwDefs.UserNameField, vLine, i, pd); // First name + ++i; + + MsAppend(pe, "Nick Name", vLine, ++i, pd); + MsAppend(pe, "Company", vLine, ++i, pd); + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, "Address", vLine, ++i, pd); + MsAppend(pe, "Address 2", vLine, ++i, pd); + MsAppend(pe, "City", vLine, ++i, pd); + MsAppend(pe, "State", vLine, ++i, pd); + MsAppend(pe, "Country", vLine, ++i, pd); + MsAppend(pe, "Zip", vLine, ++i, pd); + MsAppend(pe, "Home Phone", vLine, ++i, pd); + MsAppend(pe, "Office Phone", vLine, ++i, pd); + MsAppend(pe, "Mobile Phone", vLine, ++i, pd); + MsAppend(pe, "E-Mail", vLine, ++i, pd); + MsAppend(pe, "E-Mail 2", vLine, ++i, pd); + MsAppend(pe, "Skype", vLine, ++i, pd); + MsAppend(pe, PwDefs.UrlField, vLine, ++i, pd); + + pe.IconId = PwIcon.UserCommunication; + break; + + case "Insurance": + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, "Group No.", vLine, ++i, pd); + MsAppend(pe, "Insured", vLine, ++i, pd); + MsAppend(pe, "Date", vLine, ++i, pd); + MsAppend(pe, "Phone No.", vLine, ++i, pd); + + pe.IconId = PwIcon.Certificate; + break; + + case "Memberships": + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, "Date", vLine, ++i, pd); + + pe.IconId = PwIcon.UserKey; + break; + + case "Note": + pe.IconId = PwIcon.Notepad; + break; + + case "Passport": + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + MsAppend(pe, "Type", vLine, ++i, pd); + MsAppend(pe, "Issuing Country", vLine, ++i, pd); + MsAppend(pe, "Issuing Authority", vLine, ++i, pd); + MsAppend(pe, "Nationality", vLine, ++i, pd); + + ++i; + if((vLine.Length > i) && StrUtil.TryParseDateTime( + vLine[i], out dt)) + { + pe.Expires = true; + pe.ExpiryTime = TimeUtil.ToUtc(dt, false); + } + else MsAppend(pe, "Expiration", vLine, i, pd); + + MsAppend(pe, "Place of Birth", vLine, ++i, pd); + + pe.IconId = PwIcon.Certificate; + break; + + case "Prescriptions": + MsAppend(pe, "RX Number", vLine, ++i, pd); + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, "Doctor", vLine, ++i, pd); + MsAppend(pe, "Pharmacy", vLine, ++i, pd); + MsAppend(pe, "Phone No.", vLine, ++i, pd); + break; + + case "Registration Codes": + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, "Date", vLine, ++i, pd); + + pe.IconId = PwIcon.UserKey; + break; + + case "Unassigned": + MsAppend(pe, "Field 1", vLine, ++i, pd); + MsAppend(pe, "Field 2", vLine, ++i, pd); + MsAppend(pe, "Field 3", vLine, ++i, pd); + MsAppend(pe, "Field 4", vLine, ++i, pd); + MsAppend(pe, "Field 5", vLine, ++i, pd); + MsAppend(pe, "Field 6", vLine, ++i, pd); + break; + + case "Vehicle Info": + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + MsAppend(pe, "Date Purchased", vLine, ++i, pd); + MsAppend(pe, "Tire Size", vLine, ++i, pd); + break; + + case "Web Logins": + MsAppend(pe, PwDefs.UrlField, vLine, ++i, pd); + MsAppend(pe, PwDefs.UserNameField, vLine, ++i, pd); + MsAppend(pe, PwDefs.PasswordField, vLine, ++i, pd); + break; + + default: + Debug.Assert(false); + break; + } + Debug.Assert((i + 1) == vLine.Length); + } + + private static void MsAppend(PwEntry pe, string strFieldName, + string[] vLine, int iIndex, PwDatabase pdContext) + { + if(iIndex >= vLine.Length) { Debug.Assert(false); return; } + + string strValue = vLine[iIndex]; + if(string.IsNullOrEmpty(strValue)) return; + + strValue = strValue.Replace("\\r\\n", "\\n"); + strValue = strValue.Replace("\\r", "\\n"); + + if(PwDefs.IsStandardField(strFieldName) && + (strFieldName != PwDefs.NotesField)) + { + while(strValue.EndsWith("\\n")) + { + strValue = strValue.Substring(0, strValue.Length - 2); + } + + strValue = strValue.Replace("\\n", ", "); + } + else strValue = strValue.Replace("\\n", MessageService.NewLine); + + ImportUtil.AppendToField(pe, strFieldName, strValue, pdContext); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/MozillaBookmarksHtml100.cs b/src/KeePass/DataExchange/Formats/MozillaBookmarksHtml100.cs new file mode 100644 index 0000000..e5ff6c5 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/MozillaBookmarksHtml100.cs @@ -0,0 +1,413 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Globalization; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Cryptography; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.00 + internal sealed class MozillaBookmarksHtml100 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return true; } } + + public override string FormatName { get { return "Mozilla Bookmarks HTML"; } } + public override string DefaultExtension { get { return "html|htm"; } } + public override string ApplicationGroup { get { return KPRes.Browser; } } + + // ////////////////////////////////////////////////////////////////// + // Import + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.UTF8); + string strContent = sr.ReadToEnd(); + sr.Close(); + + if(strContent.IndexOf(@"") < 0) + throw new FormatException("Invalid DOCTYPE!"); + + strContent = strContent.Replace(@"", string.Empty); + strContent = strContent.Replace(@"
", string.Empty); + strContent = strContent.Replace(@"

", string.Empty); + // strContent = strContent.Replace(@"

", string.Empty); + // strContent = strContent.Replace(@"
", string.Empty); + // strContent = strContent.Replace(@"
", string.Empty); + strContent = strContent.Replace(@"
", string.Empty); + + // int nOffset = strContent.IndexOf('&'); + // while(nOffset >= 0) + // { + // string str4 = strContent.Substring(nOffset, 4); + // string str5 = strContent.Substring(nOffset, 5); + // string str6 = strContent.Substring(nOffset, 6); + // if((str6 != @" ") && (str5 != @"&") && (str4 != @"<") && + // (str4 != @">") && (str5 != @"'") && (str6 != @""")) + // { + // strContent = strContent.Remove(nOffset, 1); + // strContent = strContent.Insert(nOffset, @"&"); + // } + // else nOffset = strContent.IndexOf('&', nOffset + 1); + // } + + string[] vPreserve = new string[] { @" ", @"&", @"<", + @">", @"'", @""" }; + Dictionary dPreserve = new Dictionary(); + CryptoRandom cr = CryptoRandom.Instance; + foreach(string strPreserve in vPreserve) + { + string strCode = Convert.ToBase64String(cr.GetRandomBytes(16)); + Debug.Assert(strCode.IndexOf('&') < 0); + dPreserve[strPreserve] = strCode; + + strContent = strContent.Replace(strPreserve, strCode); + } + strContent = strContent.Replace(@"&", @"&"); + foreach(KeyValuePair kvpPreserve in dPreserve) + { + strContent = strContent.Replace(kvpPreserve.Value, kvpPreserve.Key); + } + + // Terminate
s + int iDD = -1; + while(true) + { + iDD = strContent.IndexOf(@"
", iDD + 1); + if(iDD < 0) break; + + int iNextTag = strContent.IndexOf('<', iDD + 1); + if(iNextTag <= 0) { Debug.Assert(false); break; } + + strContent = strContent.Insert(iNextTag, @"
"); + } + + strContent = "" + strContent + ""; + + byte[] pbFixedData = StrUtil.Utf8.GetBytes(strContent); + MemoryStream msFixed = new MemoryStream(pbFixedData, false); + + XmlDocument xmlDoc = XmlUtilEx.CreateXmlDocument(); + xmlDoc.Load(msFixed); + msFixed.Close(); + + XmlNode xmlRoot = xmlDoc.DocumentElement; + foreach(XmlNode xmlChild in xmlRoot) + { + if(xmlChild.Name == "META") + ImportMeta(xmlChild, pwStorage); + } + } + + private static void ImportMeta(XmlNode xmlNode, PwDatabase pwStorage) + { + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == "DL") + ImportGroup(xmlChild, pwStorage, pwStorage.RootGroup); + else if(xmlChild.Name == "TITLE") { } + else if(xmlChild.Name == "H1") { } + else { Debug.Assert(false); } + } + } + + private static void ImportGroup(XmlNode xmlNode, PwDatabase pwStorage, + PwGroup pg) + { + PwGroup pgSub = pg; + PwEntry pe = null; + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == "A") + { + pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + XmlUtil.SafeInnerText(xmlChild))); + + XmlNode xnUrl = xmlChild.Attributes.GetNamedItem("HREF"); + if((xnUrl != null) && (xnUrl.Value != null)) + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, xnUrl.Value)); + else { Debug.Assert(false); } + + // pe.Strings.Set("RDF_ID", new ProtectedString( + // false, xmlChild.Attributes.GetNamedItem("ID").Value)); + + ImportIcon(xmlChild, pe, pwStorage); + + XmlNode xnTags = xmlChild.Attributes.GetNamedItem("TAGS"); + if((xnTags != null) && (xnTags.Value != null)) + StrUtil.AddTags(pe.Tags, xnTags.Value.Split(',')); + } + else if(xmlChild.Name == "DD") + { + if(pe != null) + ImportUtil.AppendToField(pe, PwDefs.NotesField, + XmlUtil.SafeInnerText(xmlChild).Trim(), pwStorage); + else { Debug.Assert(false); } + } + else if(xmlChild.Name == "H3") + { + string strGroup = XmlUtil.SafeInnerText(xmlChild); + if(strGroup.Length == 0) { Debug.Assert(false); pgSub = pg; } + else + { + pgSub = new PwGroup(true, true, strGroup, PwIcon.Folder); + pg.AddGroup(pgSub, true); + } + } + else if(xmlChild.Name == "DL") + ImportGroup(xmlChild, pwStorage, pgSub); + else { Debug.Assert(false); } + } + } + + private static void ImportIcon(XmlNode xn, PwEntry pe, PwDatabase pd) + { + XmlNode xnIcon = xn.Attributes.GetNamedItem("ICON"); + if(xnIcon == null) return; + + string strIcon = xnIcon.Value; + if(!StrUtil.IsDataUri(strIcon)) { Debug.Assert(false); return; } + + try + { + byte[] pbImage = StrUtil.DataUriToData(strIcon); + if((pbImage == null) || (pbImage.Length == 0)) { Debug.Assert(false); return; } + + Image img = GfxUtil.LoadImage(pbImage); + if(img == null) { Debug.Assert(false); return; } + + byte[] pbPng; + int wMax = PwCustomIcon.MaxWidth; + int hMax = PwCustomIcon.MaxHeight; + if((img.Width <= wMax) && (img.Height <= hMax)) + { + using(MemoryStream msPng = new MemoryStream()) + { + img.Save(msPng, ImageFormat.Png); + pbPng = msPng.ToArray(); + } + } + else + { + using(Image imgSc = GfxUtil.ScaleImage(img, wMax, hMax)) + { + using(MemoryStream msPng = new MemoryStream()) + { + imgSc.Save(msPng, ImageFormat.Png); + pbPng = msPng.ToArray(); + } + } + } + img.Dispose(); + + PwUuid pwUuid = null; + int iEx = pd.GetCustomIconIndex(pbPng); + if(iEx >= 0) pwUuid = pd.CustomIcons[iEx].Uuid; + else + { + pwUuid = new PwUuid(true); + pd.CustomIcons.Add(new PwCustomIcon(pwUuid, pbPng)); + pd.UINeedsIconUpdate = true; + pd.Modified = true; + } + pe.CustomIconUuid = pwUuid; + } + catch(Exception) { Debug.Assert(false); } + } + + // ////////////////////////////////////////////////////////////////// + // Export + + public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + StringBuilder sb = new StringBuilder(); + + sb.AppendLine(""); + sb.AppendLine(""); + sb.AppendLine(""); + sb.AppendLine("Bookmarks"); + sb.AppendLine("

Bookmarks

"); + sb.AppendLine(); + sb.AppendLine("

"); + + ExportGroup(sb, pwExportInfo.DataGroup, 1, pwExportInfo.ContextDatabase); + + sb.AppendLine("

"); + + string strData = sb.ToString(); + strData = StrUtil.NormalizeNewLines(strData, false); + + byte[] pbData = StrUtil.Utf8.GetBytes(strData); + sOutput.Write(pbData, 0, pbData.Length); + sOutput.Close(); + return true; + } + + private static void ExportGroup(StringBuilder sb, PwGroup pg, uint uIndent, + PwDatabase pd) + { + ExportData(sb, uIndent, "
", pg.Name, true, "", true); + ExportData(sb, uIndent, "

", null, false, null, true); + + foreach(PwGroup pgSub in pg.Groups) + { + ExportGroup(sb, pgSub, uIndent + 1, pd); + } + +#if DEBUG + List l = new List(); + l.Add("Tag 1"); + l.Add("Tag 2"); + Debug.Assert(StrUtil.TagsToString(l, false) == "Tag 1;Tag 2"); +#endif + + foreach(PwEntry pe in pg.Entries) + { + string strUrl = pe.Strings.ReadSafe(PwDefs.UrlField); + if(strUrl.Length == 0) continue; + + // Encode only when really required; '&' does not need + // to be encoded + bool bEncUrl = (strUrl.IndexOfAny(new char[] { + '\"', '<', '>' }) >= 0); + + ExportData(sb, uIndent + 1, "

0) + { + string strTags = StrUtil.TagsToString(pe.Tags, false); + strTags = strTags.Replace(';', ','); // Without space + + ExportData(sb, 0, " TAGS=\"", strTags, true, "\"", false); + } + + string strTitle = pe.Strings.ReadSafe(PwDefs.TitleField); + if(strTitle.Length == 0) strTitle = strUrl; + + ExportData(sb, 0, ">", strTitle, true, "", true); + + string strNotes = pe.Strings.ReadSafe(PwDefs.NotesField); + if(strNotes.Length > 0) + ExportData(sb, uIndent + 1, "
", strNotes, true, null, true); + } + + ExportData(sb, uIndent, "

", null, false, null, true); + } + + private static void ExportData(StringBuilder sb, uint uIndent, + string strRawPrefix, string strData, bool bEncodeData, + string strRawSuffix, bool bNewLine) + { + if(uIndent > 0) sb.Append(new string(' ', 4 * (int)uIndent)); + if(strRawPrefix != null) sb.Append(strRawPrefix); + + if(strData != null) + { + if(bEncodeData) + { + // Apply HTML encodings except '\n' -> "
" + const string strNewLine = "899A13DDD6BA4B24BA2CA6C756E7B936"; + string str = StrUtil.NormalizeNewLines(strData, false); + str = str.Replace("\n", strNewLine); + str = StrUtil.StringToHtml(str); + str = str.Replace(strNewLine, "\n"); + + sb.Append(str); + } + else sb.Append(strData); + } + + if(strRawSuffix != null) sb.Append(strRawSuffix); + + if(bNewLine) sb.AppendLine(); + } + + private static void ExportTimes(StringBuilder sb, ITimeLogger tl) + { + if(tl == null) { Debug.Assert(false); return; } + + try + { + long t = (long)TimeUtil.SerializeUnix(tl.CreationTime); + ExportData(sb, 0, " ADD_DATE=\"", t.ToString( + NumberFormatInfo.InvariantInfo), false, "\"", false); + + t = (long)TimeUtil.SerializeUnix(tl.LastModificationTime); + ExportData(sb, 0, " LAST_MODIFIED=\"", t.ToString( + NumberFormatInfo.InvariantInfo), false, "\"", false); + } + catch(Exception) { Debug.Assert(false); } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/MozillaBookmarksJson100.cs b/src/KeePass/DataExchange/Formats/MozillaBookmarksJson100.cs new file mode 100644 index 0000000..c3ba62b --- /dev/null +++ b/src/KeePass/DataExchange/Formats/MozillaBookmarksJson100.cs @@ -0,0 +1,199 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.00 + internal sealed class MozillaBookmarksJson100 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Mozilla Bookmarks JSON"; } } + public override string DefaultExtension { get { return "json"; } } + public override string ApplicationGroup { get { return KPRes.Browser; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + JsonObject jo; + using(StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true)) + { + string strJson = sr.ReadToEnd(); + if(string.IsNullOrEmpty(strJson)) return; + + jo = new JsonObject(new CharStream(strJson)); + } + + Dictionary> dTags = + new Dictionary>(); + List lCreatedEntries = new List(); + + AddObject(pwStorage.RootGroup, jo, pwStorage, false, dTags, + lCreatedEntries); + + // Tags support (old versions) + foreach(PwEntry pe in lCreatedEntries) + { + string strUri = pe.Strings.ReadSafe(PwDefs.UrlField); + if(strUri.Length == 0) continue; + + foreach(KeyValuePair> kvp in dTags) + { + foreach(string strTagUri in kvp.Value) + { + if(strUri.Equals(strTagUri, StrUtil.CaseIgnoreCmp)) + pe.AddTag(kvp.Key); + } + } + } + } + + private static void AddObject(PwGroup pgStorage, JsonObject jo, + PwDatabase pwContext, bool bCreateSubGroups, + Dictionary> dTags, List lCreatedEntries) + { + string strRoot = jo.GetValue("root"); + if(string.Equals(strRoot, "tagsFolder", StrUtil.CaseIgnoreCmp)) + { + ImportTags(jo, dTags); + return; + } + + JsonObject[] v = jo.GetValueArray("children"); + if(v != null) + { + PwGroup pgNew; + if(bCreateSubGroups) + { + pgNew = new PwGroup(true, true); + pgNew.Name = (jo.GetValue("title") ?? string.Empty); + + pgStorage.AddGroup(pgNew, true); + } + else pgNew = pgStorage; + + foreach(JsonObject joSub in v) + { + if(joSub == null) { Debug.Assert(false); continue; } + + AddObject(pgNew, joSub, pwContext, true, dTags, lCreatedEntries); + } + + return; + } + + PwEntry pe = new PwEntry(true, true); + + // SetString(pe, "Index", false, jo, "index"); + SetString(pe, PwDefs.TitleField, pwContext.MemoryProtection.ProtectTitle, + jo, "title"); + // SetString(pe, "ID", false, jo, "id"); + SetString(pe, PwDefs.UrlField, pwContext.MemoryProtection.ProtectUrl, + jo, "uri"); + // SetString(pe, "CharSet", false, jo, "charset"); + + foreach(JsonObject joAnno in jo.GetValueArray("annos", true)) + { + if(joAnno == null) { Debug.Assert(false); continue; } + + string strName = joAnno.GetValue("name"); + string strValue = joAnno.GetValue("value"); + + if((strName == "bookmarkProperties/description") && + !string.IsNullOrEmpty(strValue)) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwContext.MemoryProtection.ProtectNotes, strValue)); + } + + // Tags support (new versions) + string strTags = jo.GetValue("tags"); + if(!string.IsNullOrEmpty(strTags)) + StrUtil.AddTags(pe.Tags, strTags.Split(',')); + + string strKeyword = jo.GetValue("keyword"); + if(!string.IsNullOrEmpty(strKeyword)) + ImportUtil.AppendToField(pe, "Keyword", strKeyword, pwContext); + + if((pe.Strings.ReadSafe(PwDefs.TitleField).Length != 0) || + (pe.Strings.ReadSafe(PwDefs.UrlField).Length != 0)) + { + pgStorage.AddEntry(pe, true); + lCreatedEntries.Add(pe); + } + } + + private static void SetString(PwEntry pe, string strEntryKey, bool bProtect, + JsonObject jo, string strObjectKey) + { + string str = jo.GetValue(strObjectKey); + if(string.IsNullOrEmpty(str)) return; + + pe.Strings.Set(strEntryKey, new ProtectedString(bProtect, str)); + } + + // Tags support (old versions) + private static void ImportTags(JsonObject joTagsRoot, + Dictionary> dTags) + { + JsonObject[] v = joTagsRoot.GetValueArray("children"); + if(v == null) { Debug.Assert(false); return; } + + foreach(JsonObject joTag in v) + { + if(joTag == null) { Debug.Assert(false); continue; } + + string strName = joTag.GetValue("title"); + if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); continue; } + + List lUris; + dTags.TryGetValue(strName, out lUris); + if(lUris == null) + { + lUris = new List(); + dTags[strName] = lUris; + } + + JsonObject[] vUris = joTag.GetValueArray("children"); + if(vUris == null) { Debug.Assert(false); continue; } + + foreach(JsonObject joUri in vUris) + { + if(joUri == null) { Debug.Assert(false); continue; } + + string strUri = joUri.GetValue("uri"); + if(!string.IsNullOrEmpty(strUri)) lUris.Add(strUri); + } + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/NPasswordNpw102.cs b/src/KeePass/DataExchange/Formats/NPasswordNpw102.cs new file mode 100644 index 0000000..f218b98 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/NPasswordNpw102.cs @@ -0,0 +1,242 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.0.2.41-1.0.2.44+ + internal sealed class NPasswordNpw102 : FileFormatProvider + { + private const string ElemGroup = "folder"; + + private const string ElemEntry = "record"; + private const string ElemEntryUser = "login"; + private const string ElemEntryPassword = "pass"; + private const string ElemEntryPassword2 = "additional"; + private const string ElemEntryUrl = "link"; + private const string ElemEntryNotes = "comments"; + private const string ElemEntryExpires = "expires"; + private const string ElemEntryExpiryTime = "expire_date"; + + private const string ElemEntryUnsupp0 = "data"; + private const string ElemEntryUnsupp1 = "script"; + + private const string ElemAutoType = "macro"; + private const string ElemAutoTypePlh = "item"; + + private const string ElemTags = "keywords"; + + private const string ElemUnsupp0 = "settings"; + + private static readonly string Password2Key = PwDefs.PasswordField + " 2"; + + private static Dictionary m_dAutoTypeConv = null; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "nPassword NPW"; } } + public override string DefaultExtension { get { return "npw"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + if(m_dAutoTypeConv == null) + { + Dictionary d = new Dictionary(); + + d[@"{login}"] = @"{USERNAME}"; + d[@"{password}"] = @"{PASSWORD}"; + d[@"{additional key}"] = @"{S:" + Password2Key + @"}"; + d[@"{url}"] = @"{URL}"; + d[@"{memo}"] = @"{NOTES}"; + d[@"[tab]"] = @"{TAB}"; + d[@"[enter]"] = @"{ENTER}"; + + m_dAutoTypeConv = d; + } + + byte[] pbData = MemUtil.Read(sInput); + + // nPassword has options for encrypting/compressing exports, + // which are unsupported; the file must start with " 0) + { + if(pg.Name.Length > 0) pg.Name += " "; + pg.Name += strValue; + } + } + else if(xmlChild.Name == ElemGroup) + ReadGroup(xmlChild, pg, pwStorage); + else if(xmlChild.Name == ElemEntry) + ReadEntry(xmlChild, pg, pwStorage); + else if(xmlChild.Name == ElemTags) + AddTags(pg.Tags, XmlUtil.SafeInnerText(xmlChild)); + else { Debug.Assert(false); } + } + } + + private static void ReadEntry(XmlNode xmlNode, PwGroup pgParent, PwDatabase pwStorage) + { + PwEntry pe = new PwEntry(true, true); + pgParent.AddEntry(pe, true); + + DateTime? odtExpiry = null; + + foreach(XmlNode xmlChild in xmlNode) + { + string strValue = XmlUtil.SafeInnerText(xmlChild); + + if(xmlChild.NodeType == XmlNodeType.Text) + ImportUtil.AppendToField(pe, PwDefs.TitleField, (xmlChild.Value ?? + string.Empty).Trim(), pwStorage, " ", false); + else if(xmlChild.Name == ElemEntryUser) + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, strValue)); + else if(xmlChild.Name == ElemEntryPassword) + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, strValue)); + else if(xmlChild.Name == ElemEntryPassword2) + { + if(strValue.Length > 0) // Prevent empty item + pe.Strings.Set(Password2Key, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, strValue)); + } + else if(xmlChild.Name == ElemEntryUrl) + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, strValue)); + else if(xmlChild.Name == ElemEntryNotes) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, strValue)); + else if(xmlChild.Name == ElemTags) + AddTags(pe.Tags, strValue); + else if(xmlChild.Name == ElemEntryExpires) + pe.Expires = StrUtil.StringToBool(strValue); + else if(xmlChild.Name == ElemEntryExpiryTime) + { + DateTime dt; + if(TimeUtil.FromDisplayStringEx(strValue, out dt)) + odtExpiry = TimeUtil.ToUtc(dt, false); + else { Debug.Assert(false); } + } + else if(xmlChild.Name == ElemAutoType) + ReadAutoType(xmlChild, pe); + else if(xmlChild.Name == ElemEntryUnsupp0) { } + else if(xmlChild.Name == ElemEntryUnsupp1) { } + else { Debug.Assert(false); } + } + + if(odtExpiry.HasValue) pe.ExpiryTime = odtExpiry.Value; + else pe.Expires = false; + } + + private static void ReadAutoType(XmlNode xmlNode, PwEntry pe) + { + string strSeq = string.Empty; + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemAutoTypePlh) + { + string strValue = XmlUtil.SafeInnerText(xmlChild); + + string strConv = null; + foreach(KeyValuePair kvp in m_dAutoTypeConv) + { + if(kvp.Key.Equals(strValue, StrUtil.CaseIgnoreCmp)) + { + strConv = kvp.Value; + break; + } + } + + if(strConv != null) strSeq += strConv; + else { Debug.Assert(false); strSeq += strValue; } + } + else { Debug.Assert(false); } + } + + pe.AutoType.DefaultSequence = strSeq; + } + + private static void AddTags(List lTags, string strNewTags) + { + if(string.IsNullOrEmpty(strNewTags)) return; + + StrUtil.AddTags(lTags, StrUtil.StringToTags( + strNewTags.Replace(' ', ';'))); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/NetworkPwMgrCsv4.cs b/src/KeePass/DataExchange/Formats/NetworkPwMgrCsv4.cs new file mode 100644 index 0000000..c613b3b --- /dev/null +++ b/src/KeePass/DataExchange/Formats/NetworkPwMgrCsv4.cs @@ -0,0 +1,124 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; + +namespace KeePass.DataExchange.Formats +{ + // 4.0+ + internal sealed class NetworkPwMgrCsv4 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Network Password Manager CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + + CsvOptions opt = new CsvOptions(); + opt.BackslashIsEscape = false; + opt.TextQualifier = char.MaxValue; // No text qualifier + + CsvStreamReaderEx csv = new CsvStreamReaderEx(strData, opt); + PwGroup pg = pwStorage.RootGroup; + char[] vGroupSplit = new char[] { '\\' }; + + while(true) + { + string[] v = csv.ReadLine(); + if(v == null) break; + if(v.Length < 1) continue; + + for(int i = 0; i < v.Length; ++i) + v[i] = ParseString(v[i]); + + if(v[0].StartsWith("\\")) // Group + { + string strGroup = v[0].Trim(vGroupSplit); // Also from end + if(strGroup.Length > 0) + { + pg = pwStorage.RootGroup.FindCreateSubTree(strGroup, + vGroupSplit); + + if(v.Length >= 6) pg.Notes = v[5].Trim(); + if((v.Length >= 5) && (v[4].Trim().Length > 0)) + { + if(pg.Notes.Length > 0) + pg.Notes += Environment.NewLine + Environment.NewLine; + + pg.Notes += v[4].Trim(); + } + } + } + else // Entry + { + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + List l = new List(v); + while(l.Count < 8) + { + Debug.Assert(false); + l.Add(string.Empty); + } + + ImportUtil.AppendToField(pe, PwDefs.TitleField, l[0], pwStorage); + ImportUtil.AppendToField(pe, PwDefs.UserNameField, l[1], pwStorage); + ImportUtil.AppendToField(pe, PwDefs.PasswordField, l[2], pwStorage); + ImportUtil.AppendToField(pe, PwDefs.UrlField, l[3], pwStorage); + ImportUtil.AppendToField(pe, PwDefs.NotesField, l[4], pwStorage); + + if(l[5].Length > 0) + ImportUtil.AppendToField(pe, "Custom 1", l[5], pwStorage); + if(l[6].Length > 0) + ImportUtil.AppendToField(pe, "Custom 2", l[6], pwStorage); + if(l[7].Length > 0) + ImportUtil.AppendToField(pe, "Custom 3", l[7], pwStorage); + } + } + } + + private static string ParseString(string str) + { + if(str == null) { Debug.Assert(false); return string.Empty; } + + str = str.Replace(@"#44", ","); + str = str.Replace(@"#13", Environment.NewLine); + + return str; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/NortonIdSafeCsv2013.cs b/src/KeePass/DataExchange/Formats/NortonIdSafeCsv2013.cs new file mode 100644 index 0000000..96cc090 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/NortonIdSafeCsv2013.cs @@ -0,0 +1,84 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 2013.4.0.10 + internal sealed class NortonIdSafeCsv2013 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Norton Identity Safe CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Unicode, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + CsvOptions opt = new CsvOptions(); + opt.BackslashIsEscape = false; + + CsvStreamReaderEx csv = new CsvStreamReaderEx(strData, opt); + + while(true) + { + string[] v = csv.ReadLine(); + if(v == null) break; + if(v.Length < 5) continue; + + if(v[0].Equals("url", StrUtil.CaseIgnoreCmp) && + v[1].Equals("username", StrUtil.CaseIgnoreCmp) && + v[2].Equals("password", StrUtil.CaseIgnoreCmp)) + continue; // Header + + PwGroup pg = pwStorage.RootGroup; + string strGroup = v[4]; + if(!string.IsNullOrEmpty(strGroup)) + pg = pg.FindCreateGroup(strGroup, true); + + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + ImportUtil.AppendToField(pe, PwDefs.UrlField, v[0], pwStorage); + ImportUtil.AppendToField(pe, PwDefs.UserNameField, v[1], pwStorage); + ImportUtil.AppendToField(pe, PwDefs.PasswordField, v[2], pwStorage); + ImportUtil.AppendToField(pe, PwDefs.TitleField, v[3], pwStorage); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/OnePw1Pux8.cs b/src/KeePass/DataExchange/Formats/OnePw1Pux8.cs new file mode 100644 index 0000000..9ef0ebf --- /dev/null +++ b/src/KeePass/DataExchange/Formats/OnePw1Pux8.cs @@ -0,0 +1,318 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; +using KeePass.Util.Archive; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 8.7.0 (1PUX version 3) + internal sealed class OnePw1Pux8 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "1Password 1PUX"; } } + public override string DefaultExtension { get { return "1pux"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + using(ZipArchiveEx za = new ZipArchiveEx(sInput)) + { + string str; + using(Stream s = za.OpenEntry("export.data")) + { + if(s == null) throw new FormatException(); + + using(StreamReader sr = new StreamReader(s, StrUtil.Utf8, true)) + { + str = sr.ReadToEnd(); + } + } + + CharStream cs = new CharStream(str); + JsonObject jo = new JsonObject(cs); + ImportRoot(jo, za, pwStorage); + } + } + + private static void ImportRoot(JsonObject jo, ZipArchiveEx za, PwDatabase pd) + { + foreach(JsonObject joAcc in jo.GetValueArray("accounts", true)) + { + foreach(JsonObject joVault in joAcc.GetValueArray("vaults", true)) + { + PwGroup pg = pd.RootGroup; + + JsonObject joAttrs = joVault.GetValue("attrs"); + if(joAttrs != null) + { + string strGroup = joAttrs.GetValue("name"); + if(!string.IsNullOrEmpty(strGroup)) + { + pg = new PwGroup(true, true); + pg.Name = strGroup; + pd.RootGroup.AddGroup(pg, true, false); + + string strNotes = joAttrs.GetValue("desc"); + if(!string.IsNullOrEmpty(strNotes)) + pg.Notes = strNotes; + } + else { Debug.Assert(false); } + } + else { Debug.Assert(false); } + + foreach(JsonObject joItem in joVault.GetValueArray("items", true)) + ImportItem(joItem, za, pg, pd); + } + } + } + + private static void ImportItem(JsonObject jo, ZipArchiveEx za, PwGroup pg, + PwDatabase pd) + { + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true, false); + + if(jo.GetValue("favIndex", 0) != 0) + pe.AddTag(PwDefs.FavoriteTag); + + ulong u = jo.GetValue("createdAt", 0); + if(u != 0) pe.CreationTime = TimeUtil.ConvertUnixTime(u); + else { Debug.Assert(false); } + + u = jo.GetValue("updatedAt", 0); + if(u != 0) pe.LastModificationTime = TimeUtil.ConvertUnixTime(u); + else { Debug.Assert(false); } + + JsonObject joOverview = jo.GetValue("overview"); + if(joOverview != null) + { + ImportUtil.AppendToField(pe, PwDefs.TitleField, + joOverview.GetValue("title"), pd); + + string strUrl = joOverview.GetValue("url"); + ImportUtil.AppendToField(pe, PwDefs.UrlField, strUrl, pd); + + foreach(JsonObject joUrl in joOverview.GetValueArray("urls", true)) + { + string str = joUrl.GetValue("url"); + if(str != strUrl) + ImportUtil.CreateFieldWithIndex(pe.Strings, PwDefs.UrlField, + str, pd, false); + } + + foreach(string strTag in joOverview.GetValueArray("tags", true)) + pe.AddTag(strTag); + } + else { Debug.Assert(false); } + + JsonObject joDetails = jo.GetValue("details"); + if(joDetails != null) + { + string str = joDetails.GetValue("notesPlain"); + if(!string.IsNullOrEmpty(str)) + ImportUtil.AppendToField(pe, PwDefs.NotesField, str, pd); + + JsonObject joFile = joDetails.GetValue("documentAttributes"); + if(joFile != null) ImportAttachment(joFile, za, pe); + + foreach(JsonObject joLF in joDetails.GetValueArray("loginFields", true)) + ImportLoginField(joLF, za, pe, pd); + + foreach(JsonObject joSection in joDetails.GetValueArray("sections", true)) + { + string strSection = joSection.GetValue("title"); + + foreach(JsonObject joField in joSection.GetValueArray("fields", true)) + ImportSectionField(joField, za, strSection, pe, pd); + } + } + else { Debug.Assert(false); } + } + + private static void ImportLoginField(JsonObject jo, ZipArchiveEx za, + PwEntry pe, PwDatabase pd) + { + string strName; + string strDsg = jo.GetValue("designation"); + if(strDsg == "username") + strName = PwDefs.UserNameField; + else if(strDsg == "password") + strName = PwDefs.PasswordField; + else + { + strName = jo.GetValue("name"); + if(string.IsNullOrEmpty(strName)) + { + Debug.Assert(false); + strName = PwDefs.NotesField; + } + else + { + string strM = ImportUtil.MapNameToStandardField(strName, true); + if(!string.IsNullOrEmpty(strM)) strName = strM; + } + } + + string strValue = jo.GetValue("value"); + ImportUtil.AppendToField(pe, strName, strValue, pd); + } + + private static void ImportSectionField(JsonObject jo, ZipArchiveEx za, + string strSection, PwEntry pe, PwDatabase pd) + { + JsonObject joValue = jo.GetValue("value"); + if(joValue == null) { Debug.Assert(false); return; } + + if(joValue.GetValue("reference") != null) return; + + JsonObject joFile = joValue.GetValue("file"); + if(joFile != null) + { + ImportAttachment(joFile, za, pe); + return; + } + + string strName = (jo.GetValue("title") ?? string.Empty); + if(!string.IsNullOrEmpty(strSection)) + { + if(strName.Length == 0) strName = strSection; + else strName = strSection + " - " + strName; + } + else if(strName.Length == 0) { Debug.Assert(false); return; } + else + { + string strM = ImportUtil.MapNameToStandardField(strName, false); + if(!string.IsNullOrEmpty(strM)) strName = strM; + } + + JsonObject joAddr = joValue.GetValue("address"); + if(joAddr != null) + { + StringBuilder sb = new StringBuilder(); + Action fAppend = delegate(string strN) + { + string strV = joAddr.GetValue(strN); + if(!string.IsNullOrEmpty(strV)) sb.AppendLine(strV); + }; + + fAppend("street"); + fAppend("zip"); + fAppend("city"); + fAppend("state"); + fAppend("country"); + + ImportUtil.AppendToField(pe, strName, sb.ToString(), pd); + return; + } + + string str = joValue.GetValue("concealed"); + if(str != null) + { + ImportUtil.AppendToField(pe, strName, str, pd); + pe.Strings.EnableProtection(strName, true); + return; + } + + ulong u = joValue.GetValue("date", 0); + if(u != 0) + { + DateTime dt = TimeUtil.ConvertUnixTime(u); + str = TimeUtil.ToDisplayString(dt); + ImportUtil.AppendToField(pe, strName, str, pd); + return; + } + + JsonObject joEMail = joValue.GetValue("email"); + if(joEMail != null) + { + ImportUtil.AppendToField(pe, strName, joEMail.GetValue( + "email_address"), pd); + return; + } + + u = joValue.GetValue("monthYear", 0); + if(u != 0) + { + str = (u / 100).ToString() + "-" + + (u % 100).ToString().PadLeft(2, '0'); + ImportUtil.AppendToField(pe, strName, str, pd); + return; + } + + str = joValue.GetValue("totp"); + if(str != null) + { + try { EntryUtil.ImportOtpAuth(pe, str, pd); } + catch(Exception) + { + Debug.Assert(false); + ImportUtil.AppendToField(pe, strName, str, pd); + } + return; + } + + foreach(KeyValuePair kvp in joValue.Items) + { + if(kvp.Value == null) continue; // E.g. null 'date' + if(kvp.Value is JsonObject) { Debug.Assert(false); continue; } + ImportUtil.AppendToField(pe, strName, kvp.Value.ToString(), pd); + } + } + + private static void ImportAttachment(JsonObject jo, ZipArchiveEx za, + PwEntry pe) + { + string strFileName = jo.GetValue("fileName"); + if(string.IsNullOrEmpty(strFileName)) { Debug.Assert(false); return; } + + string strDocId = jo.GetValue("documentId"); + if(string.IsNullOrEmpty(strDocId)) { Debug.Assert(false); return; } + + byte[] pbData; + using(Stream s = za.OpenEntry("files/" + strDocId + "__" + strFileName)) + { + if(s == null) throw new FormatException(); + pbData = MemUtil.Read(s); + } + + Debug.Assert(pbData.LongLength == jo.GetValue("decryptedSize", -1)); + + if(FileDialogsEx.CheckAttachmentSize(pbData.LongLength, + KPRes.AttachFailed + MessageService.NewLine + strFileName)) + pe.Binaries.Set(strFileName, new ProtectedBinary(false, pbData)); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/OnePwProCsv599.cs b/src/KeePass/DataExchange/Formats/OnePwProCsv599.cs new file mode 100644 index 0000000..0b3fcb3 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/OnePwProCsv599.cs @@ -0,0 +1,200 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1PW 6.15-7.05+ and its predecessor 1Password Pro 5.99, + // not 1Password (which is an entirely different product) + internal sealed class OnePwProCsv599 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "1PW & 1Password Pro CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return false; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + string[] vLines = strData.Split(new char[] { '\r', '\n' }, + StringSplitOptions.RemoveEmptyEntries); + + Dictionary dictGroups = new Dictionary(); + foreach(string strLine in vLines) + { + ProcessCsvLine(strLine, pwStorage, dictGroups); + } + } + + private static void ProcessCsvLine(string strLine, PwDatabase pwStorage, + Dictionary dictGroups) + { + if(strLine == "\"Bezeichnung\"\t\"User/ID\"\t\"1.Passwort\"\t\"Url/Programm\"\t\"Geändert am\"\t\"Bemerkung\"\t\"2.Passwort\"\t\"Läuft ab\"\t\"Kategorie\"\t\"Eigene Felder\"") + return; + + string str = strLine; + if(str.StartsWith("\"") && str.EndsWith("\"")) + str = str.Substring(1, str.Length - 2); + else { Debug.Assert(false); } + + string[] list = str.Split(new string[] { "\"\t\"" }, StringSplitOptions.None); + + int iOffset; + if(list.Length == 11) iOffset = 0; // 1Password Pro 5.99 + else if(list.Length == 10) iOffset = -1; // 1PW 6.15 + else if(list.Length > 11) iOffset = 0; // Unknown extension + else return; + + string strGroup = list[9 + iOffset]; + PwGroup pg; + if(dictGroups.ContainsKey(strGroup)) pg = dictGroups[strGroup]; + else + { + pg = new PwGroup(true, true, strGroup, PwIcon.Folder); + pwStorage.RootGroup.AddGroup(pg, true); + dictGroups[strGroup] = pg; + } + + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + ParseCsvWord(list[1 + iOffset]))); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, + ParseCsvWord(list[2 + iOffset]))); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + ParseCsvWord(list[3 + iOffset]))); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, + ParseCsvWord(list[4 + iOffset]))); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, + ParseCsvWord(list[6 + iOffset]))); + pe.Strings.Set(PwDefs.PasswordField + " 2", new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + ParseCsvWord(list[7 + iOffset]))); + + // 1Password Pro only: + // Debug.Assert(list[9] == list[0]); // Very mysterious format... + + DateTime dt; + if(ParseDateTime(list[5 + iOffset], out dt)) + { + pe.CreationTime = pe.LastAccessTime = pe.LastModificationTime = dt; + } + else { Debug.Assert(false); } + + if(ParseDateTime(list[8 + iOffset], out dt)) + { + pe.Expires = true; + pe.ExpiryTime = dt; + } + + AddCustomFields(pe, list[10 + iOffset]); + } + + private static string ParseCsvWord(string strWord) + { + string str = strWord; + + str = str.Replace("\\r", string.Empty); + str = str.Replace("\\n", "\r\n"); + + return str; + } + + private static bool ParseDateTime(string str, out DateTime dt) + { + dt = DateTime.MinValue; + if(string.IsNullOrEmpty(str)) return false; + if(str.Trim().Equals("nie", StrUtil.CaseIgnoreCmp)) return false; + if(str.Trim().Equals("never", StrUtil.CaseIgnoreCmp)) return false; + if(str.Trim().Equals("morgen", StrUtil.CaseIgnoreCmp)) + { + dt = DateTime.UtcNow.AddDays(1.0); + return true; + } + + string[] list = str.Split(new char[] { '.', '\r', '\n', ' ', '\t', + '-', ':' }, StringSplitOptions.RemoveEmptyEntries); + + try + { + if(list.Length == 6) + dt = (new DateTime(int.Parse(list[2]), int.Parse(list[1]), + int.Parse(list[0]), int.Parse(list[3]), int.Parse(list[4]), + int.Parse(list[5]), DateTimeKind.Local)).ToUniversalTime(); + else if(list.Length == 3) + dt = (new DateTime(int.Parse(list[2]), int.Parse(list[1]), + int.Parse(list[0]), 0, 0, 0, DateTimeKind.Local)).ToUniversalTime(); + else { Debug.Assert(false); return false; } + } + catch(Exception) { Debug.Assert(false); return false; } + + return true; + } + + private static void AddCustomFields(PwEntry pe, string strCustom) + { + string[] vItems = strCustom.Split(new string[] { @"|~#~|" }, + StringSplitOptions.RemoveEmptyEntries); + + foreach(string strItem in vItems) + { + string[] vData = strItem.Split(new char[] { '|' }, + StringSplitOptions.None); + + if(vData.Length >= 3) + { + string strValue = vData[2]; + for(int i = 3; i < vData.Length; ++i) + strValue += @"|" + vData[i]; + + pe.Strings.Set(vData[1], new ProtectedString(false, + strValue)); + } + else { Debug.Assert(false); } + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PVaultTxt14.cs b/src/KeePass/DataExchange/Formats/PVaultTxt14.cs new file mode 100644 index 0000000..2d34694 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PVaultTxt14.cs @@ -0,0 +1,117 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; + +namespace KeePass.DataExchange.Formats +{ + // 1.4 + internal sealed class PVaultTxt14 : FileFormatProvider + { + private const string InitGroup = "************"; + private const string InitNewEntry = "----------------------"; + + private const string InitTitle = "Account: "; + private const string InitUser = "User Name: "; + private const string InitPassword = "Password: "; + private const string InitURL = "Hyperlink: "; + private const string InitEMail = "Email: "; + + private const string InitNotes = "Comments: "; + private const string ContinueNotes = " "; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Personal Vault TXT"; } } + public override string DefaultExtension { get { return "txt"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + + string[] vLines = strData.Split(new char[] { '\r', '\n' }); + + PwGroup pg = pwStorage.RootGroup; + PwEntry pe = new PwEntry(true, true); + + foreach(string strLine in vLines) + { + if(strLine.StartsWith(InitGroup)) + { + string strGroup = strLine.Remove(0, InitGroup.Length); + if(strGroup.Length > InitGroup.Length) + strGroup = strGroup.Substring(0, strGroup.Length - InitGroup.Length); + + pg = pwStorage.RootGroup.FindCreateGroup(strGroup, true); + + pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + } + else if(strLine.StartsWith(InitNewEntry)) + { + pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + } + else if(strLine.StartsWith(InitTitle)) + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + strLine.Remove(0, InitTitle.Length))); + else if(strLine.StartsWith(InitUser)) + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, + strLine.Remove(0, InitUser.Length))); + else if(strLine.StartsWith(InitPassword)) + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + strLine.Remove(0, InitPassword.Length))); + else if(strLine.StartsWith(InitURL)) + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, + strLine.Remove(0, InitURL.Length))); + else if(strLine.StartsWith(InitEMail)) + pe.Strings.Set("E-Mail", new ProtectedString( + false, + strLine.Remove(0, InitEMail.Length))); + else if(strLine.StartsWith(InitNotes)) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, + strLine.Remove(0, InitNotes.Length))); + else if(strLine.StartsWith(ContinueNotes)) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, + pe.Strings.ReadSafe(PwDefs.NotesField) + "\r\n" + + strLine.Remove(0, ContinueNotes.Length))); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PassKeeper12.cs b/src/KeePass/DataExchange/Formats/PassKeeper12.cs new file mode 100644 index 0000000..faff85f --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PassKeeper12.cs @@ -0,0 +1,127 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +using KeePass.App; +using KeePass.Native; +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.2 + internal sealed class PassKeeper12 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "PassKeeper"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + public override bool RequiresFile { get { return false; } } + + public override Image SmallIcon + { + get { return KeePass.Properties.Resources.B16x16_View_Detailed; } + } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + if(!MessageService.AskYesNo(KPRes.ImportMustRead + MessageService.NewParagraph + + KPRes.ImportMustReadQuestion)) + { + AppHelp.ShowHelp(AppDefs.HelpTopics.ImportExport, + AppDefs.HelpTopics.ImportExportPassKeeper); + return; + } + + PwEntry pePrev = new PwEntry(true, true); + + for(int i = 0; i < 20; ++i) + { + Thread.Sleep(500); + Application.DoEvents(); + } + + try + { + while(true) + { + PwEntry pe = ImportEntry(pwStorage); + + if(ImportUtil.EntryEquals(pe, pePrev)) + { + if(pe.ParentGroup != null) // Remove duplicate + pe.ParentGroup.Entries.Remove(pe); + break; + } + + ImportUtil.GuiSendKeysPrc(@"{DOWN}"); + pePrev = pe; + } + + MessageService.ShowInfo(KPRes.ImportFinished); + } + catch(Exception exImp) { MessageService.ShowWarning(exImp); } + } + + private static PwEntry ImportEntry(PwDatabase pwDb) + { + ImportUtil.GuiSendWaitWindowChange(@"{ENTER}"); + Thread.Sleep(250); + ImportUtil.GuiSendKeysPrc(string.Empty); // Process messages + + string strTitle = ImportUtil.GuiSendRetrieve(string.Empty); + string strUserName = ImportUtil.GuiSendRetrieve(@"{TAB}"); + string strPassword = ImportUtil.GuiSendRetrieve(@"{TAB}"); + string strNotes = ImportUtil.GuiSendRetrieve(@"{TAB}"); + + ImportUtil.GuiSendWaitWindowChange(@"{ESC}"); + + PwGroup pg = pwDb.RootGroup; + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwDb.MemoryProtection.ProtectTitle, strTitle)); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwDb.MemoryProtection.ProtectUserName, strUserName)); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwDb.MemoryProtection.ProtectPassword, strPassword)); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwDb.MemoryProtection.ProtectNotes, strNotes)); + + return pe; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PinsTxt450.cs b/src/KeePass/DataExchange/Formats/PinsTxt450.cs new file mode 100644 index 0000000..ea1f2aa --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PinsTxt450.cs @@ -0,0 +1,117 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 4.50 + internal sealed class PinsTxt450 : FileFormatProvider + { + private const string FirstLine = "\"Category\"\t\"System\"\t\"User\"\t" + + "\"Password\"\t\"URL/Comments\"\t\"Custom\"\t\"Start date\"\t\"Expires\"\t" + + "\"More info\""; + private const string FieldSeparator = "\"\t\""; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "PINs TXT"; } } + public override string DefaultExtension { get { return "txt"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + + string[] vLines = strData.Split(new char[] { '\r', '\n' }); + + bool bFirst = true; + foreach(string strLine in vLines) + { + if(bFirst) + { + if(strLine != FirstLine) + throw new FormatException("Format error. First line is invalid. Read the documentation."); + + bFirst = false; + } + else if(strLine.Length > 5) ImportLine(strLine, pwStorage); + } + } + + private static void ImportLine(string strLine, PwDatabase pwStorage) + { + string[] vParts = strLine.Split(new string[] { FieldSeparator }, + StringSplitOptions.None); + Debug.Assert(vParts.Length == 9); + if(vParts.Length != 9) + throw new FormatException("Line:\r\n" + strLine); + + vParts[0] = vParts[0].Remove(0, 1); + vParts[8] = vParts[8].Substring(0, vParts[8].Length - 1); + + vParts[8] = vParts[8].Replace("||", "\r\n"); + + PwGroup pg = pwStorage.RootGroup.FindCreateGroup(vParts[0], true); + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, vParts[1])); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, vParts[2])); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, vParts[3])); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, vParts[4])); + + if(vParts[5].Length > 0) + pe.Strings.Set("Custom", new ProtectedString(false, vParts[5])); + + DateTime dt; + if((vParts[6].Length > 0) && DateTime.TryParse(vParts[6], out dt)) + pe.CreationTime = pe.LastModificationTime = pe.LastAccessTime = + TimeUtil.ToUtc(dt, false); + + if((vParts[7].Length > 0) && DateTime.TryParse(vParts[7], out dt)) + { + pe.ExpiryTime = TimeUtil.ToUtc(dt, false); + pe.Expires = true; + } + + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, vParts[8])); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PpKeeperHtml270.cs b/src/KeePass/DataExchange/Formats/PpKeeperHtml270.cs new file mode 100644 index 0000000..90c22bb --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PpKeeperHtml270.cs @@ -0,0 +1,191 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 2.50, 2.60 and 2.70 + internal sealed class PpKeeperHtml270 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Passphrase Keeper HTML"; } } + public override string DefaultExtension { get { return "html|htm"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + private const string m_strStartTd = ""; + private const string m_strEndTd = ""; + + private const string m_strModifiedField = @"{0530D298-F983-454C-B5A3-BFB0775844D1}"; + + private const string m_strModifiedHdrStart = "Modified"; + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + + // Normalize 2.70 files + strData = strData.Replace("", m_strStartTd); + strData = strData.Replace("", m_strStartTd); + strData = strData.Replace("", m_strStartTd); + strData = strData.Replace("", m_strStartTd); + strData = strData.Replace("", m_strStartTd); + strData = strData.Replace("", m_strStartTd); + + // Additionally support old versions + string[] vRepl = new string[5] { + // 2.60 + "", + + // 2.50 and 2.60 + "", + "", + "", + "" + }; + foreach(string strRepl in vRepl) + { + strData = Regex.Replace(strData, strRepl, m_strStartTd); + } + strData = strData.Replace("\r\n", m_strEndTd + "\r\n"); + + int nOffset = 0; + + PwEntry peHeader; + if(!ReadEntry(out peHeader, strData, ref nOffset, pwStorage)) + { + Debug.Assert(false); + return; + } + + while((nOffset >= 0) && (nOffset < strData.Length)) + { + PwEntry pe; + if(!ReadEntry(out pe, strData, ref nOffset, pwStorage)) + { + Debug.Assert(false); + break; + } + if(pe == null) break; + + pwStorage.RootGroup.AddEntry(pe, true); + } + } + + private static bool ReadEntry(out PwEntry pe, string strData, + ref int nOffset, PwDatabase pd) + { + pe = new PwEntry(true, true); + + if(!ReadString(strData, ref nOffset, m_strStartTd, m_strEndTd, pe, null, false)) + { + pe = null; + return true; + } + if(!ReadString(strData, ref nOffset, m_strStartTd, m_strEndTd, pe, + PwDefs.TitleField, pd.MemoryProtection.ProtectTitle)) + return false; + if(!ReadString(strData, ref nOffset, m_strStartTd, m_strEndTd, pe, + PwDefs.UserNameField, pd.MemoryProtection.ProtectUserName)) + return false; + if(!ReadString(strData, ref nOffset, m_strStartTd, m_strEndTd, pe, + PwDefs.PasswordField, pd.MemoryProtection.ProtectPassword)) + return false; + if(!ReadString(strData, ref nOffset, m_strStartTd, m_strEndTd, pe, + PwDefs.UrlField, pd.MemoryProtection.ProtectUrl)) + return false; + if(!ReadString(strData, ref nOffset, m_strStartTd, m_strEndTd, pe, + PwDefs.NotesField, pd.MemoryProtection.ProtectNotes)) + return false; + if(!ReadString(strData, ref nOffset, m_strStartTd, m_strEndTd, pe, + m_strModifiedField, false)) + return false; + + return true; + } + + private static bool ReadString(string strData, ref int nOffset, + string strStart, string strEnd, PwEntry pe, string strFieldName, + bool bProtect) + { + nOffset = strData.IndexOf(strStart, nOffset); + if(nOffset < 0) return false; + + string strRawValue = StrUtil.GetStringBetween(strData, nOffset, + strStart, strEnd); + + string strValue = strRawValue.Trim(); + if(strValue == @"
") strValue = string.Empty; + strValue = strValue.Replace("\r", string.Empty); + strValue = strValue.Replace("\n", string.Empty); + strValue = strValue.Replace(@"
", MessageService.NewLine); + + if((strFieldName != null) && (strFieldName == m_strModifiedField)) + { + DateTime dt = ReadModified(strValue); + pe.CreationTime = dt; + pe.LastModificationTime = dt; + } + else if(strFieldName != null) + pe.Strings.Set(strFieldName, new ProtectedString(bProtect, strValue)); + + nOffset += strStart.Length + strRawValue.Length + strEnd.Length; + return true; + } + + private static DateTime ReadModified(string strValue) + { + if(strValue == null) { Debug.Assert(false); return DateTime.UtcNow; } + if(strValue.StartsWith(m_strModifiedHdrStart)) return DateTime.UtcNow; + + string[] vParts = strValue.Split(new char[] { ' ', ':', '/' }, + StringSplitOptions.RemoveEmptyEntries); + if(vParts.Length != 6) { Debug.Assert(false); return DateTime.UtcNow; } + + try + { + return (new DateTime(int.Parse(vParts[2]), int.Parse(vParts[0]), + int.Parse(vParts[1]), int.Parse(vParts[3]), int.Parse(vParts[4]), + int.Parse(vParts[5]), DateTimeKind.Local)).ToUniversalTime(); + } + catch(Exception) { Debug.Assert(false); } + + return DateTime.UtcNow; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwAgentXml2.cs b/src/KeePass/DataExchange/Formats/PwAgentXml2.cs new file mode 100644 index 0000000..1fd51fc --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwAgentXml2.cs @@ -0,0 +1,155 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 2.3.4-2.6.2+ + internal static class PwAgentXml2 + { + private const string ElemGroup = "group"; + private const string ElemGroupName = "name"; + + private const string ElemEntry = "entry"; + private const string ElemEntryName = "name"; + private const string ElemEntryType = "type"; + private const string ElemEntryUser = "account"; + private const string ElemEntryPassword = "password"; + private const string ElemEntryURL = "link"; + private const string ElemEntryNotes = "note"; + private const string ElemEntryCreationTime = "date_added"; + private const string ElemEntryLastModTime = "date_modified"; + private const string ElemEntryExpireTime = "date_expire"; + + internal static void Import(PwDatabase pwStorage, XmlDocument d) + { + XmlNode xmlRoot = d.DocumentElement; + Debug.Assert(xmlRoot.Name == "data"); + + foreach(XmlNode xmlChild in xmlRoot.ChildNodes) + { + if(xmlChild.Name == ElemGroup) + ReadGroup(xmlChild, pwStorage.RootGroup, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ReadGroup(XmlNode xmlNode, PwGroup pgParent, PwDatabase pwStorage) + { + PwGroup pg = new PwGroup(true, true); + pgParent.AddGroup(pg, true); + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemGroupName) + pg.Name = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemGroup) + ReadGroup(xmlChild, pg, pwStorage); + else if(xmlChild.Name == ElemEntry) + ReadEntry(xmlChild, pg, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ReadEntry(XmlNode xmlNode, PwGroup pgParent, PwDatabase pwStorage) + { + PwEntry pe = new PwEntry(true, true); + pgParent.AddEntry(pe, true); + + DateTime dt; + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemEntryName) + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemEntryType) + pe.IconId = ((XmlUtil.SafeInnerText(xmlChild) != "1") ? + PwIcon.Key : PwIcon.PaperNew); + else if(xmlChild.Name == ElemEntryUser) + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemEntryPassword) + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemEntryURL) + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemEntryNotes) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemEntryCreationTime) + { + if(ParseDate(xmlChild, out dt)) + pe.CreationTime = dt; + } + else if(xmlChild.Name == ElemEntryLastModTime) + { + if(ParseDate(xmlChild, out dt)) + pe.LastModificationTime = dt; + } + else if(xmlChild.Name == ElemEntryExpireTime) + { + if(ParseDate(xmlChild, out dt)) + { + pe.ExpiryTime = dt; + pe.Expires = true; + } + } + else { Debug.Assert(false); } + } + } + + private static bool ParseDate(XmlNode xn, out DateTime dtOut) + { + string strDate = XmlUtil.SafeInnerText(xn); + if(strDate.Length == 0) + { + dtOut = DateTime.UtcNow; + return false; + } + + if(DateTime.TryParse(strDate, out dtOut)) + { + dtOut = TimeUtil.ToUtc(dtOut, false); + return true; + } + + Debug.Assert(false); + dtOut = DateTime.UtcNow; + return false; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwAgentXml3.cs b/src/KeePass/DataExchange/Formats/PwAgentXml3.cs new file mode 100644 index 0000000..ce98ac7 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwAgentXml3.cs @@ -0,0 +1,200 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 19.6.28+ + internal sealed class PwAgentXml3 : FileFormatProvider + { + private const string ElemGroup = "group"; + private const string ElemEntry = "item"; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Password Agent XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + byte[] pb = MemUtil.Read(sInput); + + if(ImportOld(pwStorage, pb)) return; + + XmlDocument d = XmlUtilEx.CreateXmlDocument(); + using(MemoryStream ms = new MemoryStream(pb, false)) + { + using(StreamReader sr = new StreamReader(ms, StrUtil.Utf8, true)) + { + d.Load(sr); + } + } + + XmlNode xmlRoot = d.DocumentElement; + Debug.Assert(xmlRoot.Name == "data"); + + foreach(XmlNode xmlChild in xmlRoot.ChildNodes) + { + if(xmlChild.Name == ElemGroup) + ReadGroup(xmlChild, pwStorage.RootGroup, pwStorage); + else if(xmlChild.Name == ElemEntry) + ReadEntry(xmlChild, pwStorage.RootGroup, pwStorage); + else { Debug.Assert(false); } + } + } + + internal static bool ImportOld(PwDatabase pwStorage, byte[] pb) + { + // Version 2 uses ANSI encoding, version 3 uses UTF-8 + // encoding (with BOM) + XmlDocument dAnsi = XmlUtilEx.CreateXmlDocument(); + try + { + using(MemoryStream ms = new MemoryStream(pb, false)) + { + using(StreamReader sr = new StreamReader(ms, Encoding.Default, true)) + { + dAnsi.Load(sr); + + XmlElement xmlRoot = dAnsi.DocumentElement; + + // Version 2 has three "ver_*" attributes, + // version 3 has a "version" attribute + if(xmlRoot.Attributes["ver_major"] == null) + return false; + } + } + } + catch(Exception) { Debug.Assert(false); return false; } + + PwAgentXml2.Import(pwStorage, dAnsi); + return true; + } + + private static void ReadGroup(XmlNode xmlNode, PwGroup pgParent, PwDatabase pwStorage) + { + PwGroup pg = new PwGroup(true, true); + pgParent.AddGroup(pg, true); + + ReadDate(pg, xmlNode.Attributes["dateModified"], true, true, false); + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == "title") + pg.Name = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemGroup) + ReadGroup(xmlChild, pg, pwStorage); + else if(xmlChild.Name == ElemEntry) + ReadEntry(xmlChild, pg, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ReadEntry(XmlNode xmlNode, PwGroup pgParent, PwDatabase pwStorage) + { + PwEntry pe = new PwEntry(true, true); + pgParent.AddEntry(pe, true); + + ReadDate(pe, xmlNode.Attributes["dateModified"], true, true, false); + + foreach(XmlNode xmlChild in xmlNode) + { + string str = XmlUtil.SafeInnerText(xmlChild); + + if(xmlChild.Name == "title") + ImportUtil.AppendToField(pe, PwDefs.TitleField, str, pwStorage); + else if(xmlChild.Name == "userId") + ImportUtil.AppendToField(pe, PwDefs.UserNameField, str, pwStorage); + else if(xmlChild.Name == "password") + ImportUtil.AppendToField(pe, PwDefs.PasswordField, str, pwStorage); + else if(xmlChild.Name == "note") + ImportUtil.AppendToField(pe, PwDefs.NotesField, str, pwStorage); + else if(xmlChild.Name == "link") + ImportUtil.AppendToField(pe, PwDefs.UrlField, str, pwStorage); + else if(xmlChild.Name == "dateAdded") + ReadDate(pe, xmlChild, true, false, false); + else if(xmlChild.Name == "dateModified") + ReadDate(pe, xmlChild, false, true, false); + else if(xmlChild.Name == "dateExpires") + ReadDate(pe, xmlChild, false, false, true); + else if(xmlChild.Name == "attachment") + ReadAttachment(xmlChild, pe); + else { Debug.Assert(false); } + } + } + + private static void ReadAttachment(XmlNode xmlNode, PwEntry pe) + { + XmlNode xnName = xmlNode.SelectSingleNode("fileName"); + XmlNode xnValue = xmlNode.SelectSingleNode("fileBytes"); + + string strName = XmlUtil.SafeInnerText(xnName); + if(strName.Length == 0) { Debug.Assert(false); strName = Guid.NewGuid().ToString(); } + + string strValue = XmlUtil.SafeInnerText(xnValue); + if(strValue.Length == 0) { Debug.Assert(false); return; } + + pe.Binaries.Set(strName, new ProtectedBinary(false, + Convert.FromBase64String(strValue))); + } + + private static void ReadDate(ITimeLogger tl, XmlNode xn, + bool bSetCreation, bool bSetLastMod, bool bSetExpiry) + { + if(tl == null) { Debug.Assert(false); return; } + if(xn == null) { Debug.Assert(false); return; } + + try + { + XmlAttribute xa = (xn as XmlAttribute); + string str = ((xa != null) ? xa.Value : xn.InnerText); + if(string.IsNullOrEmpty(str)) return; // No assert + + DateTime dt = TimeUtil.ToUtc(XmlConvert.ToDateTime( + str, XmlDateTimeSerializationMode.Utc), true); + + if(bSetCreation) tl.CreationTime = dt; + if(bSetLastMod) tl.LastModificationTime = dt; + if(bSetExpiry) + { + tl.Expires = true; + tl.ExpiryTime = dt; + } + } + catch(Exception) { Debug.Assert(false); } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwDepotXml26.cs b/src/KeePass/DataExchange/Formats/PwDepotXml26.cs new file mode 100644 index 0000000..b11825e --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwDepotXml26.cs @@ -0,0 +1,458 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 2.6-16.0.7+ + internal sealed class PwDepotXml26 : FileFormatProvider + { + // Old versions used upper-case node names, whereas + // newer versions use lower-case node names + private const string ElemGroup = "group"; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Password Depot XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + // Remove vertical tabulators + strData = strData.Replace("\u000B", string.Empty); + + XmlDocument xd = XmlUtilEx.CreateXmlDocument(); + xd.LoadXml(strData); + + PwGroup pgRoot = pwStorage.RootGroup; + Dictionary dItems = new Dictionary(); + string strFavs = null; + + foreach(XmlNode xn in xd.DocumentElement.ChildNodes) + { + string strName = xn.Name.ToLowerInvariant(); + + if(strName == "passwords") + ReadContainer(xn, pgRoot, pwStorage, dItems); + else if(strName == "recyclebin") + { + PwGroup pg = new PwGroup(true, true, KPRes.RecycleBin + + " (Password Depot)", PwIcon.TrashBin); + pgRoot.AddGroup(pg, true); + ReadContainer(xn, pg, pwStorage, dItems); + } + else if(strName == "favorites") + strFavs = XmlUtil.SafeInnerText(xn).Trim(); + else + { + Debug.Assert((strName == "header") || (strName == "sitestoignore") || + (strName == "categories")); + } + } + + if(!string.IsNullOrEmpty(strFavs)) + { + try + { + byte[] pbList = Convert.FromBase64String(strFavs); + string strList = StrUtil.Utf8.GetString(pbList); + string[] v = strList.Split(new char[] { '\r', '\n' }, + StringSplitOptions.RemoveEmptyEntries); + foreach(string str in v) + { + IStructureItem si; + if(!dItems.TryGetValue(str, out si)) { Debug.Assert(false); continue; } + + PwGroup pg = (si as PwGroup); + if(pg != null) pg.Tags.Add(PwDefs.FavoriteTag); + + PwEntry pe = (si as PwEntry); + if(pe != null) pe.AddTag(PwDefs.FavoriteTag); + } + } + catch(Exception) { Debug.Assert(false); } + } + } + + private static void ReadContainer(XmlNode xnContainer, PwGroup pgParent, + PwDatabase pd, Dictionary dItems) + { + foreach(XmlNode xn in xnContainer.ChildNodes) + { + string strName = xn.Name.ToLowerInvariant(); + + if(strName == ElemGroup) + ReadGroup(xn, pgParent, pd, dItems); + else { Debug.Assert(false); } + } + } + + private static void ReadGroup(XmlNode xnGroup, PwGroup pgParent, PwDatabase pd, + Dictionary dItems) + { + PwGroup pg = new PwGroup(true, true); + pgParent.AddGroup(pg, true); + + string str = GetAttribute(xnGroup, "name"); + if(string.IsNullOrEmpty(str)) { Debug.Assert(false); str = KPRes.Group; } + pg.Name = str; + + str = GetAttribute(xnGroup, "fingerprint"); + if(string.IsNullOrEmpty(str)) { Debug.Assert(false); } + else if(dItems == null) { Debug.Assert(false); } + else if(dItems.ContainsKey(str)) { } // Recycle bin UUID = primary group UUID + else dItems[str] = pg; + + str = GetAttribute(xnGroup, "imageindex"); + if(!string.IsNullOrEmpty(str)) pg.IconId = MapIcon(str, false); + + foreach(XmlNode xn in xnGroup.ChildNodes) + { + string strName = xn.Name.ToLowerInvariant(); + + if(strName == ElemGroup) + ReadGroup(xn, pg, pd, dItems); + else if(strName == "item") + ReadEntry(xn, pg, pd, dItems); + else { Debug.Assert(false); } + } + } + + private static void ReadEntry(XmlNode xnEntry, PwGroup pg, PwDatabase pd, + Dictionary dItems) + { + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + foreach(XmlNode xn in xnEntry.ChildNodes) + { + string strName = xn.Name.ToLowerInvariant(); + + if(strName == "description") + ImportUtil.AppendToField(pe, PwDefs.TitleField, + XmlUtil.SafeInnerText(xn), pd); + else if(strName == "username") + ImportUtil.AppendToField(pe, PwDefs.UserNameField, + XmlUtil.SafeInnerText(xn), pd); + else if(strName == "password") + ImportUtil.AppendToField(pe, PwDefs.PasswordField, + XmlUtil.SafeInnerText(xn), pd); + else if(strName == "url") + ImportUtil.CreateFieldWithIndex(pe.Strings, PwDefs.UrlField, + XmlUtil.SafeInnerText(xn), pd, false); + else if(strName == "comment") + ImportUtil.AppendToField(pe, PwDefs.NotesField, + XmlUtil.SafeInnerText(xn), pd); + else if(strName == "expirydate") + { + DateTime? odt = ReadTime(xn); + if(odt.HasValue) + { + pe.ExpiryTime = odt.Value; + pe.Expires = true; + } + } + else if(strName == "created") + { + DateTime? odt = ReadTime(xn); + if(odt.HasValue) pe.CreationTime = odt.Value; + } + else if(strName == "lastmodified") + { + DateTime? odt = ReadTime(xn); + if(odt.HasValue) pe.LastModificationTime = odt.Value; + } + else if(strName == "lastaccessed") + { + DateTime? odt = ReadTime(xn); + if(odt.HasValue) pe.LastAccessTime = odt.Value; + } + else if(strName == "usagecount") + { + ulong u; + if(ulong.TryParse(XmlUtil.SafeInnerText(xn), out u)) + pe.UsageCount = u; + } + else if(strName == "tags") + { + List l = StrUtil.StringToTags(XmlUtil.SafeInnerText(xn)); + StrUtil.AddTags(pe.Tags, l); + } + else if(strName == "fingerprint") + { + string str = XmlUtil.SafeInnerText(xn); + if(str.Length == 0) { Debug.Assert(false); } + else if(dItems == null) { } // History, ... + else if(dItems.ContainsKey(str)) { Debug.Assert(false); } + else dItems[str] = pe; + } + else if(strName == "template") + pe.AutoType.DefaultSequence = MapAutoType(XmlUtil.SafeInnerText(xn)); + else if(strName == "imageindex") + pe.IconId = MapIcon(XmlUtil.SafeInnerText(xn), true); + else if(strName == "urls") + ReadUrls(xn, pe, pd); + else if(strName == "customfields") + ReadCustomFields(xn, pe, pd); + else if(strName == "hitems") + ReadHistory(xn, pe, pd); + } + } + + private static void ReadUrls(XmlNode xnUrls, PwEntry pe, PwDatabase pd) + { + foreach(XmlNode xn in xnUrls.ChildNodes) + { + string strName = xn.Name.ToLowerInvariant(); + + if(strName == "url") + ImportUtil.CreateFieldWithIndex(pe.Strings, PwDefs.UrlField, + XmlUtil.SafeInnerText(xn), pd, false); + else { Debug.Assert(false); } + } + } + + private static void ReadCustomFields(XmlNode xnFields, PwEntry pe, PwDatabase pd) + { + foreach(XmlNode xn in xnFields.ChildNodes) + { + string strName = xn.Name.ToLowerInvariant(); + + if(strName == "field") + ReadCustomField(xn, pe, pd); + else { Debug.Assert(false); } + } + } + + private static void ReadCustomField(XmlNode xnField, PwEntry pe, PwDatabase pd) + { + string strKey = string.Empty, strValue = string.Empty; + + foreach(XmlNode xn in xnField.ChildNodes) + { + string strName = xn.Name.ToLowerInvariant(); + + if(strName == "name") + strKey = XmlUtil.SafeInnerText(xn); + else if(strName == "value") + strValue = XmlUtil.SafeInnerText(xn); + else { Debug.Assert(strName == "visible"); } + } + + if(strKey == "IDS_InformationText") + strKey = PwDefs.NotesField; + else if(strKey.Length == 0) + { + Debug.Assert(false); + strKey = Guid.NewGuid().ToString(); + } + + ImportUtil.AppendToField(pe, strKey, strValue, pd); + } + + private static void ReadHistory(XmlNode xnHistory, PwEntry pe, PwDatabase pd) + { + PwGroup pgH = new PwGroup(true, true); + + foreach(XmlNode xn in xnHistory.ChildNodes) + { + string strName = xn.Name.ToLowerInvariant(); + + if(strName == "hitem") + ReadEntry(xn, pgH, pd, null); + else { Debug.Assert(false); } + } + + foreach(PwEntry peH in pgH.Entries) + { + if(peH.History.UCount != 0) { Debug.Assert(false); peH.History.Clear(); } + + peH.ParentGroup = null; + peH.SetUuid(pe.Uuid, false); + + pe.History.Add(peH); + } + + pe.History.Sort(EntryUtil.CompareLastMod); + } + + private static PwIcon MapIcon(string strIconId, bool bEntryIcon) + { + PwIcon ico = (bEntryIcon ? PwIcon.Key : PwIcon.Folder); + + int idIcon; + if(!int.TryParse(strIconId, out idIcon)) { Debug.Assert(false); return ico; } + + ++idIcon; // In the icon picker dialog, all indices are + 1 + switch(idIcon) + { + // case 1: ico = PwIcon.Key; break; // 1, 2, 3 + case 4: ico = PwIcon.FolderOpen; break; + case 5: + case 6: ico = PwIcon.LockOpen; break; + case 15: + case 16: ico = PwIcon.EMail; break; + case 17: + case 18: ico = PwIcon.ProgramIcons; break; + case 21: + case 22: ico = PwIcon.World; break; + case 23: + case 24: ico = PwIcon.UserCommunication; break; + case 25: + case 26: ico = PwIcon.Money; break; + case 27: + case 28: ico = PwIcon.Star; break; + case 39: ico = PwIcon.Disk; break; + case 40: ico = PwIcon.Clock; break; + case 41: ico = PwIcon.Money; break; + case 42: ico = PwIcon.Star; break; + case 47: ico = PwIcon.Folder; break; + case 48: + case 49: ico = PwIcon.TrashBin; break; + case 53: ico = PwIcon.Identity; break; + case 54: ico = PwIcon.Info; break; + case 62: + case 64: ico = PwIcon.PaperLocked; break; + case 66: ico = PwIcon.Book; break; + case 67: ico = PwIcon.Expired; break; + case 68: ico = PwIcon.Warning; break; + case 69: ico = PwIcon.MultiKeys; break; + case 73: ico = PwIcon.PaperNew; break; + case 75: ico = PwIcon.Home; break; + case 77: ico = PwIcon.Archive; break; + case 81: ico = PwIcon.Money; break; + case 83: ico = PwIcon.Clock; break; + case 85: ico = PwIcon.Star; break; + case 86: ico = PwIcon.LockOpen; break; + case 87: ico = PwIcon.Certificate; break; + case 91: ico = PwIcon.World; break; + case 92: + case 93: + case 94: + case 95: ico = PwIcon.Note; break; + case 97: ico = PwIcon.Drive; break; + case 100: ico = PwIcon.UserCommunication; break; + case 101: ico = PwIcon.Monitor; break; + case 111: + case 112: ico = PwIcon.Identity; break; + case 113: ico = PwIcon.EMail; break; + default: break; + }; + + return ico; + } + + private static string MapAutoType(string str) + { + str = str.Replace('<', '{'); + str = str.Replace('>', '}'); + + str = StrUtil.ReplaceCaseInsensitive(str, @"{USER}", + @"{" + PwDefs.UserNameField.ToUpperInvariant() + @"}"); + str = StrUtil.ReplaceCaseInsensitive(str, @"{PASS}", + @"{" + PwDefs.PasswordField.ToUpperInvariant() + @"}"); + str = StrUtil.ReplaceCaseInsensitive(str, @"{CLEAR}", @"{CLEARFIELD}"); + str = StrUtil.ReplaceCaseInsensitive(str, @"{ARROW_LEFT}", @"{LEFT}"); + str = StrUtil.ReplaceCaseInsensitive(str, @"{ARROW_UP}", @"{UP}"); + str = StrUtil.ReplaceCaseInsensitive(str, @"{ARROW_RIGHT}", @"{RIGHT}"); + str = StrUtil.ReplaceCaseInsensitive(str, @"{ARROW_DOWN}", @"{DOWN}"); + str = StrUtil.ReplaceCaseInsensitive(str, @"{DELAY=", @"{DELAY "); + + if(str.Equals(PwDefs.DefaultAutoTypeSequence, StrUtil.CaseIgnoreCmp)) + return string.Empty; + return str; + } + + private static DateTime? ReadTime(XmlNode xn) + { + DateTime? odt = ReadTimeRaw(xn); + if(!odt.HasValue) return null; + + if(odt.Value.Year < 1950) return null; + + return odt.Value; + } + + private static DateTime? ReadTimeRaw(XmlNode xn) + { + string strFormat = GetAttribute(xn, "fmt"); + string strTime = XmlUtil.SafeInnerText(xn); + + if(strTime == "00.00.0000") return null; // Parsing fails + // Another dummy value is 30.12.1899 (handled by ReadTime) + + DateTime dt; + if(!string.IsNullOrEmpty(strFormat)) + { + strFormat = strFormat.Replace("mm.", "MM."); + strFormat = strFormat.Replace('h', 'H'); + + if(DateTime.TryParseExact(strTime, strFormat, null, + DateTimeStyles.AssumeLocal, out dt)) + return TimeUtil.ToUtc(dt, false); + } + Debug.Assert(false); + + if(DateTime.TryParse(strTime, out dt)) + return TimeUtil.ToUtc(dt, false); + + return null; + } + + private static string GetAttribute(XmlNode xn, string strAttrib) + { + Debug.Assert(strAttrib == strAttrib.ToLowerInvariant()); + + try + { + XmlAttributeCollection xac = xn.Attributes; + + XmlNode xnAttrib = xac.GetNamedItem(strAttrib); + if(xnAttrib != null) return xnAttrib.Value; + + xnAttrib = xac.GetNamedItem(strAttrib.ToUpperInvariant()); + if(xnAttrib != null) return xnAttrib.Value; + } + catch(Exception) { Debug.Assert(false); } + + return null; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwExporterXml105.cs b/src/KeePass/DataExchange/Formats/PwExporterXml105.cs new file mode 100644 index 0000000..f14dd31 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwExporterXml105.cs @@ -0,0 +1,178 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.0.5-1.3.4+ + internal sealed class PwExporterXml105 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Password Exporter XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.Browser; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + private const string ElemRoot = "xml"; + private const string ElemEntries = "entries"; + private const string ElemEntry = "entry"; + + private const string AttrUser = "user"; + private const string AttrPassword = "password"; + private const string AttrURL = "host"; + private const string AttrUserFieldName = "userFieldName"; + private const string AttrPasswordFieldName = "passFieldName"; + + private const string DbUserFieldName = "FieldID_UserName"; + private const string DbPasswordFieldName = "FieldID_Password"; + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strDoc = sr.ReadToEnd(); + sr.Close(); + + // Fix '<' characters, for version 1.0.5 + int nIndex = strDoc.IndexOf('<'); + while(nIndex >= 0) + { + int nAttrib = strDoc.LastIndexOf("=\"", nIndex); + int nElem = strDoc.LastIndexOf('>', nIndex); + + if(nAttrib > nElem) + { + strDoc = strDoc.Remove(nIndex, 1); + strDoc = strDoc.Insert(nIndex, @"<"); + } + nIndex = strDoc.IndexOf('<', nIndex + 1); + } + + // Fix '>' characters, for version 1.0.5 + nIndex = strDoc.IndexOf('>'); + while(nIndex >= 0) + { + char chPrev = strDoc[nIndex - 1]; + string strPrev4 = strDoc.Substring(nIndex - 3, 4); + + if((chPrev != '/') && (chPrev != '\"') && (strPrev4 != @"xml>") && + (strPrev4 != @"ies>")) + { + strDoc = strDoc.Remove(nIndex, 1); + strDoc = strDoc.Insert(nIndex, @">"); + } + nIndex = strDoc.IndexOf('>', nIndex + 1); + } + + MemoryStream ms = new MemoryStream(StrUtil.Utf8.GetBytes(strDoc), false); + XmlDocument xmlDoc = XmlUtilEx.CreateXmlDocument(); + xmlDoc.Load(ms); + ms.Close(); + + XmlNode xmlRoot = xmlDoc.DocumentElement; + if(xmlRoot.Name != ElemRoot) + throw new FormatException("Invalid root element!"); + + foreach(XmlNode xmlChild in xmlRoot.ChildNodes) + { + if(xmlChild.Name == ElemEntries) + ImportEntries(xmlChild, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ImportEntries(XmlNode xmlNode, PwDatabase pwStorage) + { + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemEntry) + ImportEntry(xmlChild, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ImportEntry(XmlNode xmlNode, PwDatabase pwStorage) + { + PwEntry pe = new PwEntry(true, true); + pwStorage.RootGroup.AddEntry(pe, true); + + XmlAttributeCollection col = xmlNode.Attributes; + if(col == null) return; + + XmlNode xmlAttrib; + xmlAttrib = col.GetNamedItem(AttrUser); + if(xmlAttrib != null) pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, PctDecode(xmlAttrib.Value))); + else { Debug.Assert(false); } + + xmlAttrib = col.GetNamedItem(AttrPassword); + if(xmlAttrib != null) pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, PctDecode(xmlAttrib.Value))); + else { Debug.Assert(false); } + + xmlAttrib = col.GetNamedItem(AttrURL); + if(xmlAttrib != null) pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, PctDecode(xmlAttrib.Value))); + else { Debug.Assert(false); } + + xmlAttrib = col.GetNamedItem(AttrUserFieldName); + if(xmlAttrib != null) pe.Strings.Set(DbUserFieldName, new ProtectedString( + false, PctDecode(xmlAttrib.Value))); + else { Debug.Assert(false); } + + xmlAttrib = col.GetNamedItem(AttrPasswordFieldName); + if(xmlAttrib != null) pe.Strings.Set(DbPasswordFieldName, new ProtectedString( + false, PctDecode(xmlAttrib.Value))); + else { Debug.Assert(false); } + } + + // For version 1.3.4 + private static string PctDecode(string strText) + { + if(string.IsNullOrEmpty(strText)) return string.Empty; + + string str = strText; + + str = str.Replace("%3C", "<"); + str = str.Replace("%3E", ">"); + str = str.Replace("%22", "\""); + str = str.Replace("%26", "&"); + str = str.Replace("%25", "%"); // Must be last + + return str; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwKeeperCsv70.cs b/src/KeePass/DataExchange/Formats/PwKeeperCsv70.cs new file mode 100644 index 0000000..d2e76ce --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwKeeperCsv70.cs @@ -0,0 +1,102 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; + +namespace KeePass.DataExchange.Formats +{ + // 7.0 + internal sealed class PwKeeperCsv70 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Password Keeper CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + + string[] vLines = strData.Split(new char[] { '\r', '\n' }); + + foreach(string strLine in vLines) + { + if(strLine.Length > 5) ProcessCsvLine(strLine, pwStorage); + } + } + + private static void ProcessCsvLine(string strLine, PwDatabase pwStorage) + { + List list = ImportUtil.SplitCsvLine(strLine, ","); + Debug.Assert(list.Count == 5); + + PwEntry pe = new PwEntry(true, true); + pwStorage.RootGroup.AddEntry(pe, true); + + if(list.Count == 5) + { + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + ProcessCsvWord(list[0]))); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, + ProcessCsvWord(list[1]))); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + ProcessCsvWord(list[2]))); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, + ProcessCsvWord(list[3]))); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, + ProcessCsvWord(list[4]))); + } + else throw new FormatException("Invalid field count!"); + } + + private static string ProcessCsvWord(string strWord) + { + if(strWord == null) return string.Empty; + if(strWord.Length < 2) return strWord; + + if(strWord.StartsWith("\"") && strWord.EndsWith("\"")) + return strWord.Substring(1, strWord.Length - 2); + + return strWord; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwMemory2008Xml104.cs b/src/KeePass/DataExchange/Formats/PwMemory2008Xml104.cs new file mode 100644 index 0000000..fe1341d --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwMemory2008Xml104.cs @@ -0,0 +1,129 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.0.4 + internal sealed class PwMemory2008Xml104 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Password Memory 2008 XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + string str = Preprocess(sInput); + + PwMemory2008XmlFile_Priv f = null; + using(MemoryStream ms = new MemoryStream(StrUtil.Utf8.GetBytes(str), false)) + { + f = XmlUtilEx.Deserialize(ms); + } + if((f == null) || (f.Cells == null)) return; + + Dictionary vGroups = new Dictionary(); + + for(int iLine = 2; iLine < f.Cells.Length; ++iLine) + { + string[] vCells = f.Cells[iLine]; + if((vCells == null) || (vCells.Length != 6)) continue; + if((vCells[1] == null) || (vCells[2] == null) || + (vCells[3] == null) || (vCells[4] == null)) continue; + + string strGroup = vCells[4]; + PwGroup pg; + if(strGroup == ".") pg = pwStorage.RootGroup; + else if(vGroups.ContainsKey(strGroup)) pg = vGroups[strGroup]; + else + { + pg = new PwGroup(true, true); + pg.Name = strGroup; + pwStorage.RootGroup.AddGroup(pg, true); + + vGroups[strGroup] = pg; + } + + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + if(vCells[1] != ".") + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, vCells[1])); + if(vCells[2] != ".") + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, vCells[2])); + if(vCells[3] != ".") + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, vCells[3])); + } + } + + private static string Preprocess(Stream sInput) + { + StreamReader sr = new StreamReader(sInput, Encoding.UTF8); + string str = sr.ReadToEnd(); + sr.Close(); + + const string strStartTag = " + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Windows.Forms; + +using KeePass.Forms; +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Resources; +using KeePassLib.Security; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class PwPrompterDat12 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Password Prompter DAT"; } } + public override string DefaultExtension { get { return "dat"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + SingleLineEditForm dlg = new SingleLineEditForm(); + dlg.InitEx(KPRes.Password, KPRes.Import + ": " + this.FormatName, + KPRes.PasswordPrompt, Properties.Resources.B48x48_KGPG_Key2, + string.Empty, null); + if(UIUtil.ShowDialogNotValue(dlg, DialogResult.OK)) return; + string strPassword = dlg.ResultString; + UIUtil.DestroyForm(dlg); + + byte[] pbPassword = Encoding.Default.GetBytes(strPassword); + + BinaryReader br = new BinaryReader(sInput, Encoding.Default); + + ushort usFileVersion = br.ReadUInt16(); + if(usFileVersion != 0x0100) + throw new Exception(KLRes.FileVersionUnsupported); + + uint uEntries = br.ReadUInt32(); + uint uKeySize = br.ReadUInt32(); + Debug.Assert(uKeySize == 50); // It's a constant + + byte btKeyArrayLen = br.ReadByte(); + byte[] pbKey = br.ReadBytes(btKeyArrayLen); + + byte btValidArrayLen = br.ReadByte(); + byte[] pbValid = br.ReadBytes(btValidArrayLen); + + if(pbPassword.Length > 0) + { + MangleSetKey(pbPassword); + MangleDecode(pbKey); + } + + MangleSetKey(pbKey); + MangleDecode(pbValid); + string strValid = Encoding.Default.GetString(pbValid); + if(strValid != "aacaaaadaaeabaacyuioqaqqaaaaaertaaajkadaadaaxywqea") + throw new Exception(KLRes.InvalidCompositeKey); + + for(uint uEntry = 0; uEntry < uEntries; ++uEntry) + { + PwEntry pe = new PwEntry(true, true); + pwStorage.RootGroup.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, ReadString(br))); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, ReadString(br))); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, ReadString(br))); + pe.Strings.Set("Hint", new ProtectedString(false, ReadString(br))); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, ReadString(br))); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, ReadString(br))); + } + + br.Close(); + sInput.Close(); + } + + private string ReadString(BinaryReader br) + { + byte btLen = br.ReadByte(); + byte[] pbData = br.ReadBytes(btLen); + + MangleDecode(pbData); + + return Encoding.Default.GetString(pbData); + } + + byte[] m_pbMangleKey = null; + private void MangleSetKey(byte[] pbKey) + { + if(pbKey == null) { Debug.Assert(false); return; } + + m_pbMangleKey = new byte[pbKey.Length]; + Array.Copy(pbKey, m_pbMangleKey, pbKey.Length); + } + + private void MangleDecode(byte[] pbData) + { + if(m_pbMangleKey == null) { Debug.Assert(false); return; } + + int nKeyIndex = 0, nIndex = 0, nRemLen = pbData.Length; + bool bUp = true; + + while(nRemLen > 0) + { + if(nKeyIndex > (m_pbMangleKey.Length - 1)) + { + nKeyIndex = m_pbMangleKey.Length - 1; + bUp = false; + } + else if(nKeyIndex < 0) + { + nKeyIndex = 0; + bUp = true; + } + + pbData[nIndex] ^= m_pbMangleKey[nKeyIndex]; + + nKeyIndex += (bUp ? 1 : -1); + + ++nIndex; + --nRemLen; + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwSafeXml302.cs b/src/KeePass/DataExchange/Formats/PwSafeXml302.cs new file mode 100644 index 0000000..756bf3b --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwSafeXml302.cs @@ -0,0 +1,351 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 3.02-3.30+ + internal sealed class PwSafeXml302 : FileFormatProvider + { + private const string AttribLineBreak = "delimiter"; + + private const string ElemEntry = "entry"; + private const string ElemGroup = "group"; + private const string ElemTitle = "title"; + private const string ElemUserName = "username"; + private const string ElemPassword = "password"; + private const string ElemURL = "url"; + private const string ElemNotes = "notes"; + private const string ElemEMail = "email"; + + private const string ElemAutoType = "autotype"; + private const string ElemRunCommand = "runcommand"; + + private const string ElemCreationTime = "ctime"; + private const string ElemLastAccessTime = "atime"; + private const string ElemExpireTime = "ltime"; + private const string ElemLastModTime = "pmtime"; + private const string ElemRecordModTime = "rmtime"; + private const string ElemCreationTimeX = "ctimex"; + private const string ElemLastAccessTimeX = "atimex"; + private const string ElemExpireTimeX = "xtimex"; // Yes, inconsistent + private const string ElemLastModTimeX = "pmtimex"; + private const string ElemRecordModTimeX = "rmtimex"; + + private const string ElemEntryHistory = "pwhistory"; + private const string ElemEntryHistoryContainer = "history_entries"; + private const string ElemEntryHistoryItem = "history_entry"; + private const string ElemEntryHistoryItemTime = "changed"; + private const string ElemEntryHistoryItemTimeX = "changedx"; + private const string ElemEntryHistoryItemPassword = "oldpassword"; + + private const string ElemTimePartDate = "date"; + private const string ElemTimePartTime = "time"; + + private const string XPathUseDefaultUser = "Preferences/UseDefaultUser"; + private const string XPathDefaultUser = "Preferences/DefaultUsername"; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Password Safe XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + private sealed class DatePasswordPair + { + public DateTime Time = DateTime.UtcNow; + public string Password = string.Empty; + } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + byte[] pbData = MemUtil.Read(sInput); + + try + { + string strData = StrUtil.Utf8.GetString(pbData); + if(strData.StartsWith("", + StrUtil.CaseIgnoreCmp) && (strData.IndexOf( + "WhatSaved=\"Password Safe V3.29\"", StrUtil.CaseIgnoreCmp) >= 0)) + { + // Fix broken XML exported by Password Safe 3.29; + // this has been fixed in 3.30 + strData = strData.Replace(" listHistory = null; + + foreach(XmlNode xmlChild in xmlNode.ChildNodes) + { + if(xmlChild.Name == ElemGroup) + strGroupName = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemTitle) + pe.Strings.Set(PwDefs.TitleField, + new ProtectedString(pwStorage.MemoryProtection.ProtectTitle, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemUserName) + pe.Strings.Set(PwDefs.UserNameField, + new ProtectedString(pwStorage.MemoryProtection.ProtectUserName, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemPassword) + pe.Strings.Set(PwDefs.PasswordField, + new ProtectedString(pwStorage.MemoryProtection.ProtectPassword, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemURL) + pe.Strings.Set(PwDefs.UrlField, + new ProtectedString(pwStorage.MemoryProtection.ProtectUrl, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemNotes) + pe.Strings.Set(PwDefs.NotesField, + new ProtectedString(pwStorage.MemoryProtection.ProtectNotes, + XmlUtil.SafeInnerText(xmlChild, strLineBreak))); + else if(xmlChild.Name == ElemEMail) + pe.Strings.Set("E-Mail", new ProtectedString(false, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemCreationTime) + pe.CreationTime = ReadDateTime(xmlChild); + else if(xmlChild.Name == ElemLastAccessTime) + pe.LastAccessTime = ReadDateTime(xmlChild); + else if(xmlChild.Name == ElemExpireTime) + { + pe.ExpiryTime = ReadDateTime(xmlChild); + pe.Expires = true; + } + else if(xmlChild.Name == ElemLastModTime) // = last mod + pe.LastModificationTime = ReadDateTime(xmlChild); + else if(xmlChild.Name == ElemRecordModTime) // = last mod + pe.LastModificationTime = ReadDateTime(xmlChild); + else if(xmlChild.Name == ElemCreationTimeX) + pe.CreationTime = ReadDateTimeX(xmlChild); + else if(xmlChild.Name == ElemLastAccessTimeX) + pe.LastAccessTime = ReadDateTimeX(xmlChild); + else if(xmlChild.Name == ElemExpireTimeX) + { + pe.ExpiryTime = ReadDateTimeX(xmlChild); + pe.Expires = true; + } + else if(xmlChild.Name == ElemLastModTimeX) // = last mod + pe.LastModificationTime = ReadDateTimeX(xmlChild); + else if(xmlChild.Name == ElemRecordModTimeX) // = last mod + pe.LastModificationTime = ReadDateTimeX(xmlChild); + else if(xmlChild.Name == ElemAutoType) + pe.AutoType.DefaultSequence = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemRunCommand) + pe.OverrideUrl = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemEntryHistory) + listHistory = ReadEntryHistory(xmlChild); + } + + if(listHistory != null) + { + string strPassword = pe.Strings.ReadSafe(PwDefs.PasswordField); + DateTime dtLastMod = pe.LastModificationTime; + + foreach(DatePasswordPair dpp in listHistory) + { + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + dpp.Password)); + pe.LastModificationTime = dpp.Time; + + pe.CreateBackup(null); + } + // Maintain backups manually now (backups from the imported file + // might have been out of order) + pe.MaintainBackups(pwStorage); + + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + strPassword)); + pe.LastModificationTime = dtLastMod; + } + + PwGroup pgContainer = pwStorage.RootGroup; + if(strGroupName.Length != 0) + pgContainer = pwStorage.RootGroup.FindCreateSubTree(strGroupName, + new string[1] { "." }, true); + pgContainer.AddEntry(pe, true); + pgContainer.IsExpanded = true; + } + + private static DateTime ReadDateTime(XmlNode xmlNode) + { + Debug.Assert(xmlNode != null); if(xmlNode == null) return DateTime.UtcNow; + + int[] vTimeParts = new int[6]; + DateTime dtTemp; + foreach(XmlNode xmlChild in xmlNode.ChildNodes) + { + if(xmlChild.Name == ElemTimePartDate) + { + if(DateTime.TryParse(XmlUtil.SafeInnerText(xmlChild), out dtTemp)) + { + vTimeParts[0] = dtTemp.Year; + vTimeParts[1] = dtTemp.Month; + vTimeParts[2] = dtTemp.Day; + } + } + else if(xmlChild.Name == ElemTimePartTime) + { + if(DateTime.TryParse(XmlUtil.SafeInnerText(xmlChild), out dtTemp)) + { + vTimeParts[3] = dtTemp.Hour; + vTimeParts[4] = dtTemp.Minute; + vTimeParts[5] = dtTemp.Second; + } + } + else { Debug.Assert(false); } + } + + return (new DateTime(vTimeParts[0], vTimeParts[1], vTimeParts[2], + vTimeParts[3], vTimeParts[4], vTimeParts[5], + DateTimeKind.Local)).ToUniversalTime(); + } + + private static DateTime ReadDateTimeX(XmlNode xmlNode) + { + string strDate = XmlUtil.SafeInnerText(xmlNode); + + DateTime dt; + if(StrUtil.TryParseDateTime(strDate, out dt)) + return TimeUtil.ToUtc(dt, false); + + Debug.Assert(false); + return DateTime.UtcNow; + } + + private static List ReadEntryHistory(XmlNode xmlNode) + { + List list = null; + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemEntryHistoryContainer) + list = ReadEntryHistoryContainer(xmlChild); + } + + return list; + } + + private static List ReadEntryHistoryContainer(XmlNode xmlNode) + { + List list = new List(); + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemEntryHistoryItem) + list.Add(ReadEntryHistoryItem(xmlChild)); + } + + return list; + } + + private static DatePasswordPair ReadEntryHistoryItem(XmlNode xmlNode) + { + DatePasswordPair dpp = new DatePasswordPair(); + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemEntryHistoryItemTime) + dpp.Time = ReadDateTime(xmlChild); + else if(xmlChild.Name == ElemEntryHistoryItemTimeX) + dpp.Time = ReadDateTimeX(xmlChild); + else if(xmlChild.Name == ElemEntryHistoryItemPassword) + dpp.Password = XmlUtil.SafeInnerText(xmlChild); + } + + return dpp; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwSaverXml412.cs b/src/KeePass/DataExchange/Formats/PwSaverXml412.cs new file mode 100644 index 0000000..d48bd74 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwSaverXml412.cs @@ -0,0 +1,209 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 4.1.2+ + internal sealed class PwSaverXml412 : FileFormatProvider + { + private const string ElemRoot = "ROOT"; + + private const string ElemGroup = "FOLDER"; + private const string ElemRecycleBin = "GARBAGE"; + private const string ElemEntry = "RECORD"; + + private const string ElemName = "NAME"; + private const string ElemIcon = "ICON"; + + private const string ElemFields = "FIELDS"; + private const string ElemField = "FIELD"; + private const string ElemID = "ID"; + private const string ElemType = "TYPE"; + private const string ElemValue = "VALUE"; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Password Saver XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, StrUtil.Utf8); + string strDoc = sr.ReadToEnd(); + sr.Close(); + + XmlDocument doc = XmlUtilEx.CreateXmlDocument(); + doc.LoadXml(strDoc); + + XmlElement xmlRoot = doc.DocumentElement; + Debug.Assert(xmlRoot.Name == ElemRoot); + + PwGroup pgRoot = pwStorage.RootGroup; + + foreach(XmlNode xmlChild in xmlRoot.ChildNodes) + { + if(xmlChild.Name == ElemGroup) + ImportGroup(xmlChild, pgRoot, pwStorage, false); + else if(xmlChild.Name == ElemRecycleBin) + ImportGroup(xmlChild, pgRoot, pwStorage, true); + else if(xmlChild.Name == ElemEntry) + ImportEntry(xmlChild, pgRoot, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ImportGroup(XmlNode xn, PwGroup pgParent, PwDatabase pd, + bool bIsRecycleBin) + { + PwGroup pg; + if(!bIsRecycleBin) + { + pg = new PwGroup(true, true); + pgParent.AddGroup(pg, true); + } + else + { + pg = pd.RootGroup.FindGroup(pd.RecycleBinUuid, true); + + if(pg == null) + { + pg = new PwGroup(true, true, KPRes.RecycleBin, PwIcon.TrashBin); + pgParent.AddGroup(pg, true); + + pd.RecycleBinUuid = pg.Uuid; + pd.RecycleBinChanged = DateTime.UtcNow; + } + } + + foreach(XmlNode xmlChild in xn.ChildNodes) + { + if(xmlChild.Name == ElemName) + pg.Name = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemIcon) + pg.IconId = GetIcon(XmlUtil.SafeInnerText(xmlChild)); + else if(xmlChild.Name == ElemGroup) + ImportGroup(xmlChild, pg, pd, false); + else if(xmlChild.Name == ElemEntry) + ImportEntry(xmlChild, pg, pd); + else { Debug.Assert(false); } + } + } + + private static void ImportEntry(XmlNode xn, PwGroup pgParent, PwDatabase pd) + { + PwEntry pe = new PwEntry(true, true); + pgParent.AddEntry(pe, true); + + foreach(XmlNode xmlChild in xn.ChildNodes) + { + if(xmlChild.Name == ElemName) + ImportUtil.AppendToField(pe, PwDefs.TitleField, + XmlUtil.SafeInnerText(xmlChild), pd); + else if(xmlChild.Name == ElemIcon) + pe.IconId = GetIcon(XmlUtil.SafeInnerText(xmlChild)); + else if(xmlChild.Name == ElemFields) + ImportFields(xmlChild, pe, pd); + else { Debug.Assert(false); } + } + } + + private static void ImportFields(XmlNode xn, PwEntry pe, PwDatabase pd) + { + foreach(XmlNode xmlChild in xn.ChildNodes) + { + if(xmlChild.Name == ElemField) + ImportField(xmlChild, pe, pd); + else { Debug.Assert(false); } + } + } + + private static void ImportField(XmlNode xn, PwEntry pe, PwDatabase pd) + { + string strName = null; + string strValue = null; + + foreach(XmlNode xmlChild in xn.ChildNodes) + { + if(xmlChild.Name == ElemID) { } + else if(xmlChild.Name == ElemName) + strName = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemType) { } + else if(xmlChild.Name == ElemValue) + strValue = XmlUtil.SafeInnerText(xmlChild); + else { Debug.Assert(false); } + } + + if(!string.IsNullOrEmpty(strName) && !string.IsNullOrEmpty(strValue)) + { + string strF = ImportUtil.MapNameToStandardField(strName, true); + if((strName == "Control Panel") || (strName == "Webmail Interface")) + strF = PwDefs.UrlField; + else if(strName == "FTP Address") + strF = strName; + else if(strName == "FTP Username") + strF = "FTP User Name"; + else if(strName == "FTP Password") + strF = strName; + + if(string.IsNullOrEmpty(strF)) strF = strName; + + ImportUtil.AppendToField(pe, strF, strValue, pd, null, true); + } + } + + private static PwIcon GetIcon(string strName) + { + if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return PwIcon.Key; } + + string str = strName.ToUpperInvariant(); + + if(str == "FOLDER") return PwIcon.Folder; + if(str == "RECORD") return PwIcon.Key; + if(str == "WEBSITE.ICO") return PwIcon.Home; + if(str == "HOSTING.ICO") return PwIcon.NetworkServer; + if(str == "DIALUP.ICO") return PwIcon.WorldSocket; + if(str == "SHOPING.ICO") return PwIcon.ClipboardReady; // Sic + if(str == "AUCTION.ICO") return PwIcon.Tool; + if(str == "MESSENGER.ICO") return PwIcon.UserCommunication; + if(str == "SOFTWARE_SERIALS.ICO") return PwIcon.CDRom; + if(str == "CREDITCARD.ICO") return PwIcon.Identity; + if(str == "MAILBOX.ICO") return PwIcon.EMailBox; + + Debug.Assert(false); + return PwIcon.Key; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwTresorXml100.cs b/src/KeePass/DataExchange/Formats/PwTresorXml100.cs new file mode 100644 index 0000000..e5e63e9 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwTresorXml100.cs @@ -0,0 +1,123 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.0.2001.157 + internal sealed class PwTresorXml100 : FileFormatProvider + { + private const string ElemGroup = "Group"; + private const string ElemGroupName = "groupname"; + + private const string ElemEntry = "PassItem"; + private const string ElemEntryName = "itemname"; + private const string ElemEntryUser = "username"; + private const string ElemEntryPassword = "password"; + private const string ElemEntryURL = "url"; + private const string ElemEntryNotes = "description"; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Passwort.Tresor XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + + XmlDocument xmlDoc = XmlUtilEx.CreateXmlDocument(); + xmlDoc.Load(sr); + + XmlNode xmlRoot = xmlDoc.DocumentElement; + + foreach(XmlNode xmlChild in xmlRoot.ChildNodes) + { + if(xmlChild.Name == ElemGroup) + ReadGroup(xmlChild, pwStorage.RootGroup, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ReadGroup(XmlNode xmlNode, PwGroup pgParent, PwDatabase pwStorage) + { + PwGroup pg = new PwGroup(true, true); + pgParent.AddGroup(pg, true); + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemGroupName) + pg.Name = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == ElemGroup) + ReadGroup(xmlChild, pg, pwStorage); + else if(xmlChild.Name == ElemEntry) + ReadEntry(xmlChild, pg, pwStorage); + else { Debug.Assert(false); } + } + } + + private static void ReadEntry(XmlNode xmlNode, PwGroup pgParent, PwDatabase pwStorage) + { + PwEntry pe = new PwEntry(true, true); + pgParent.AddEntry(pe, true); + + foreach(XmlNode xmlChild in xmlNode) + { + if(xmlChild.Name == ElemEntryName) + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemEntryUser) + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemEntryPassword) + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemEntryURL) + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, + XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == ElemEntryNotes) + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, + XmlUtil.SafeInnerText(xmlChild))); + else { Debug.Assert(false); } + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/PwsPlusCsv1007.cs b/src/KeePass/DataExchange/Formats/PwsPlusCsv1007.cs new file mode 100644 index 0000000..6754ad3 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/PwsPlusCsv1007.cs @@ -0,0 +1,113 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class PwsPlusCsv1007 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Passwords Plus CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + + CsvStreamReader csv = new CsvStreamReader(strData, true); + Dictionary dictGroups = new Dictionary(); + + while(true) + { + string[] vLine = csv.ReadLine(); + if(vLine == null) break; + if(vLine.Length == 0) continue; // Skip empty line + if(vLine.Length == 5) continue; // Skip header line + if(vLine.Length != 34) { Debug.Assert(false); continue; } + + string strType = vLine[0].Trim(); + if(strType.Equals("Is Template", StrUtil.CaseIgnoreCmp)) continue; + if(strType.Equals("1")) continue; // Skip template + + string strGroup = vLine[2].Trim(); + PwGroup pg; + if(strGroup.Length == 0) pg = pwStorage.RootGroup; + else + { + if(dictGroups.ContainsKey(strGroup)) pg = dictGroups[strGroup]; + else + { + pg = new PwGroup(true, true, strGroup, PwIcon.Folder); + pwStorage.RootGroup.AddGroup(pg, true); + dictGroups[strGroup] = pg; + } + } + + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + string strTitle = vLine[1].Trim(); + if(strTitle.Length > 0) + ImportUtil.AppendToField(pe, PwDefs.TitleField, strTitle, pwStorage); + + for(int i = 0; i < 10; ++i) + { + string strKey = vLine[(i * 3) + 3].Trim(); + string strValue = vLine[(i * 3) + 4].Trim(); + if((strKey.Length == 0) || (strValue.Length == 0)) continue; + + string strMapped = ImportUtil.MapNameToStandardField(strKey, true); + if(string.IsNullOrEmpty(strMapped)) strMapped = strKey; + ImportUtil.AppendToField(pe, strMapped, strValue, pwStorage); + } + + string strNotesPre = pe.Strings.ReadSafe(PwDefs.NotesField); + string strNotes = vLine[33].Trim(); + if(strNotes.Length > 0) + { + if(strNotesPre.Length == 0) + ImportUtil.AppendToField(pe, PwDefs.NotesField, strNotes, pwStorage); + else + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + ((pwStorage == null) ? false : + pwStorage.MemoryProtection.ProtectNotes), strNotesPre + + Environment.NewLine + Environment.NewLine + strNotes)); + } + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/RevelationXml04.cs b/src/KeePass/DataExchange/Formats/RevelationXml04.cs new file mode 100644 index 0000000..2bad255 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/RevelationXml04.cs @@ -0,0 +1,184 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; +using KeePassLib.Security; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class RevelationXml04 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Revelation XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.UTF8); + string strDoc = sr.ReadToEnd(); + sr.Close(); + + XmlDocument doc = XmlUtilEx.CreateXmlDocument(); + doc.LoadXml(strDoc); + + ProcessEntries(pwStorage, pwStorage.RootGroup, + doc.DocumentElement.ChildNodes); + } + + private static void ProcessEntries(PwDatabase pd, PwGroup pgParent, + XmlNodeList xlNodes) + { + foreach(XmlNode xmlChild in xlNodes) + { + if(xmlChild.Name == "entry") + { + XmlNode xnType = xmlChild.Attributes.GetNamedItem("type"); + if(xnType == null) { Debug.Assert(false); } + else + { + if(xnType.Value == "folder") + ImportGroup(pd, pgParent, xmlChild); + else ImportEntry(pd, pgParent, xmlChild); + } + } + } + } + + private static void ImportGroup(PwDatabase pd, PwGroup pgParent, XmlNode xmlNode) + { + PwGroup pg = new PwGroup(true, true); + pgParent.AddGroup(pg, true); + + foreach(XmlNode xmlChild in xmlNode.ChildNodes) + { + if(xmlChild.Name == "name") + pg.Name = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == "description") + pg.Notes = XmlUtil.SafeInnerText(xmlChild); + else if(xmlChild.Name == "entry") { } + else if(xmlChild.Name == "updated") + pg.LastModificationTime = ImportTime(xmlChild); + else { Debug.Assert(false); } + } + + ProcessEntries(pd, pg, xmlNode.ChildNodes); + } + + private static void ImportEntry(PwDatabase pd, PwGroup pgParent, XmlNode xmlNode) + { + PwEntry pe = new PwEntry(true, true); + pgParent.AddEntry(pe, true); + + foreach(XmlNode xmlChild in xmlNode.ChildNodes) + { + if(xmlChild.Name == "name") + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pd.MemoryProtection.ProtectTitle, XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == "description") + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pd.MemoryProtection.ProtectNotes, XmlUtil.SafeInnerText(xmlChild))); + else if(xmlChild.Name == "updated") + pe.LastModificationTime = ImportTime(xmlChild); + else if(xmlChild.Name == "field") + { + XmlNode xnName = xmlChild.Attributes.GetNamedItem("id"); + if(xnName == null) { Debug.Assert(false); } + else + { + KeyValuePair kvp = MapFieldName(xnName.Value, pd); + pe.Strings.Set(kvp.Key, new ProtectedString(kvp.Value, + XmlUtil.SafeInnerText(xmlChild))); + } + } + else { Debug.Assert(false); } + } + } + + private static KeyValuePair MapFieldName(string strFieldName, + PwDatabase pdContext) + { + switch(strFieldName) + { + case "creditcard-cardnumber": + case "generic-username": + case "generic-location": + case "phone-phonenumber": + return new KeyValuePair(PwDefs.UserNameField, + pdContext.MemoryProtection.ProtectUserName); + case "generic-code": + case "generic-password": + case "generic-pin": + return new KeyValuePair(PwDefs.PasswordField, + pdContext.MemoryProtection.ProtectPassword); + case "generic-hostname": + case "generic-url": + return new KeyValuePair(PwDefs.UrlField, + pdContext.MemoryProtection.ProtectUrl); + case "creditcard-cardtype": + return new KeyValuePair("Card Type", false); + case "creditcard-expirydate": + return new KeyValuePair(KPRes.ExpiryTime, false); + case "creditcard-ccv": + return new KeyValuePair("CCV Number", false); + case "generic-certificate": + return new KeyValuePair("Certificate", false); + case "generic-keyfile": + return new KeyValuePair("Key File", false); + case "generic-database": + return new KeyValuePair(KPRes.Database, false); + case "generic-email": + return new KeyValuePair(KPRes.EMail, false); + case "generic-port": + return new KeyValuePair("Port", false); + case "generic-domain": + return new KeyValuePair("Domain", false); + default: Debug.Assert(false); break; + } + + return new KeyValuePair(strFieldName, false); + } + + private static DateTime ImportTime(XmlNode xn) + { + string str = XmlUtil.SafeInnerText(xn); + + double dtUnix; + if(!double.TryParse(str, out dtUnix)) { Debug.Assert(false); } + else return TimeUtil.ConvertUnixTime(dtUnix); + + return DateTime.UtcNow; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/RoboFormHtml69.cs b/src/KeePass/DataExchange/Formats/RoboFormHtml69.cs new file mode 100644 index 0000000..5f4fb6d --- /dev/null +++ b/src/KeePass/DataExchange/Formats/RoboFormHtml69.cs @@ -0,0 +1,209 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Windows.Forms; + +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 6.9.82-8.4.3.4+ + internal sealed class RoboFormHtml69 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "RoboForm HTML (Logins/PassCards)"; } } + public override string DefaultExtension { get { return "html|htm"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Unicode, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + strData = strData.Replace(@"", string.Empty); + strData = strData.Replace(@"­", string.Empty); + + using(WebBrowser wb = new WebBrowser()) + { + wb.Visible = false; + wb.ScriptErrorsSuppressed = true; + + UIUtil.SetWebBrowserDocument(wb, strData); + ImportPriv(pwStorage, wb.Document.Body); + } + } + + private static string ParseTitle(string strTitle, PwDatabase pd, + out PwGroup pg) + { + pg = pd.RootGroup; + + // In 7.9.5.9 '/' is used; in earlier versions '\\' + char[] vSeps = new char[] { '/', '\\' }; + + int iLastSep = strTitle.LastIndexOfAny(vSeps); + if(iLastSep >= 0) + { + string strTree = strTitle.Substring(0, iLastSep); + pg = pd.RootGroup.FindCreateSubTree(strTree, vSeps, true); + + return strTitle.Substring(iLastSep + 1); + } + + return strTitle; + } + + private static string MapKey(string strKey) + { + string s = ImportUtil.MapNameToStandardField(strKey, true); + if(string.IsNullOrEmpty(s)) return strKey; + + if((s == PwDefs.TitleField) || (s == PwDefs.UrlField)) + return strKey; + + return s; + } + + private static List GetElements(HtmlElement hRoot, + string strTagName, string strAttribName, string strAttribValue) + { + List l = new List(); + if(hRoot == null) { Debug.Assert(false); return l; } + if(string.IsNullOrEmpty(strTagName)) { Debug.Assert(false); return l; } + + foreach(HtmlElement hEl in hRoot.GetElementsByTagName(strTagName)) + { + if(!string.IsNullOrEmpty(strAttribName) && (strAttribValue != null)) + { + string strValue = XmlUtil.SafeAttribute(hEl, strAttribName); + if(!strValue.Equals(strAttribValue, StrUtil.CaseIgnoreCmp)) + continue; + } + + l.Add(hEl); + } + + return l; + } + + private static void ImportPriv(PwDatabase pd, HtmlElement hBody) + { +#if DEBUG + bool bHasSpanCaptions = (GetElements(hBody, "SPAN", "class", + "caption").Count > 0); +#endif + + foreach(HtmlElement hTable in hBody.GetElementsByTagName("TABLE")) + { + Debug.Assert(XmlUtil.SafeAttribute(hTable, "width") == "100%"); + string strRules = XmlUtil.SafeAttribute(hTable, "rules"); + string strFrame = XmlUtil.SafeAttribute(hTable, "frame"); + if(strRules.Equals("cols", StrUtil.CaseIgnoreCmp) && + strFrame.Equals("void", StrUtil.CaseIgnoreCmp)) + continue; + + PwEntry pe = new PwEntry(true, true); + PwGroup pg = null; + bool bNotesHeaderFound = false; + + foreach(HtmlElement hTr in hTable.GetElementsByTagName("TR")) + { + // 7.9.1.1+ + List lCaption = GetElements(hTr, "SPAN", + "class", "caption"); + if(lCaption.Count == 0) + lCaption = GetElements(hTr, "DIV", "class", "caption"); + if(lCaption.Count > 0) + { + string strTitle = ParseTitle(XmlUtil.SafeInnerText( + lCaption[0]), pd, out pg); + ImportUtil.AppendToField(pe, PwDefs.TitleField, strTitle, pd); + continue; // Data is in next TR + } + + // 7.9.1.1+ + if(hTr.GetElementsByTagName("TABLE").Count > 0) continue; + + HtmlElementCollection lTd = hTr.GetElementsByTagName("TD"); + if(lTd.Count == 1) + { + HtmlElement e = lTd[0]; + string strText = XmlUtil.SafeInnerText(e); + string strClass = XmlUtil.SafeAttribute(e, "class"); + + if(strClass.Equals("caption", StrUtil.CaseIgnoreCmp)) + { + Debug.Assert(pg == null); + strText = ParseTitle(strText, pd, out pg); + ImportUtil.AppendToField(pe, PwDefs.TitleField, strText, pd); + } + else if(strClass.Equals("subcaption", StrUtil.CaseIgnoreCmp)) + ImportUtil.AppendToField(pe, PwDefs.UrlField, + ImportUtil.FixUrl(strText), pd); + else if(strClass.Equals("field", StrUtil.CaseIgnoreCmp)) + { + // 7.9.2.5+ + if(strText.EndsWith(":") && !bNotesHeaderFound) + bNotesHeaderFound = true; + else + ImportUtil.AppendToField(pe, PwDefs.NotesField, + strText.Trim(), pd); + } + else { Debug.Assert(false); } + } + else if((lTd.Count == 2) || (lTd.Count == 3)) + { + string strKey = XmlUtil.SafeInnerText(lTd[0]); + string strValue = XmlUtil.SafeInnerText(lTd[lTd.Count - 1]); + if(lTd.Count == 3) { Debug.Assert(string.IsNullOrEmpty(lTd[1].InnerText)); } + + if(strKey.EndsWith(":")) // 7.9.1.1+ + strKey = strKey.Substring(0, strKey.Length - 1); + + if(strKey.Length > 0) + ImportUtil.AppendToField(pe, MapKey(strKey), strValue, pd); + else { Debug.Assert(false); } + } + else { Debug.Assert(false); } + } + + if(pg != null) pg.AddEntry(pe, true); +#if DEBUG + else { Debug.Assert(bHasSpanCaptions); } +#endif + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/SafeWalletXml3.cs b/src/KeePass/DataExchange/Formats/SafeWalletXml3.cs new file mode 100644 index 0000000..30ef9e7 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/SafeWalletXml3.cs @@ -0,0 +1,183 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 2.4.1.2-3.0.7.2022+ + internal sealed class SafeWalletXml3 : FileFormatProvider + { + private static readonly string[] ElemsVault = new string[] { + "T37" // 3.0.5 + }; + private static readonly string[] ElemsGroup = new string[] { + "Folder", // 2.4.1.2 + "T3", // 3.0.5 + "T21" // 3.0.7, special group for web entries + }; + private static readonly string[] ElemsEntry = new string[] { + "Card", // 3.0.4 + "T4" // 3.0.5 + }; + private static readonly string[] ElemsProps = new string[] { + "Property", // 3.0.4 + "T257", "T258", "T259", "T263", "T264", "T265", // 3.0.5 + "T266", "T267" // 3.0.5 + }; + private static readonly string[] ElemsWebEntry = new string[] { + "T22" // 3.0.7 + }; + + private const string AttribCaption = "Caption"; + + private const string AttribWebUrl = "URL"; + private const string AttribWebUserName = "Username"; + private const string AttribWebPassword = "Password"; + + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "SafeWallet XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return false; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Unicode); + string strDoc = sr.ReadToEnd(); + sr.Close(); + + XmlDocument xd = XmlUtilEx.CreateXmlDocument(); + xd.LoadXml(strDoc); + + XmlNode xnRoot = xd.DocumentElement; + Debug.Assert(xnRoot.Name == "SafeWallet"); + foreach(XmlNode xn in xnRoot.ChildNodes) + { + if(Array.IndexOf(ElemsGroup, xn.Name) >= 0) + AddGroup(xn, pwStorage.RootGroup, pwStorage); // 2.4.1.2 + else if(Array.IndexOf(ElemsEntry, xn.Name) >= 0) + AddEntry(xn, pwStorage.RootGroup, pwStorage); // 3.0.4 + else if(Array.IndexOf(ElemsVault, xn.Name) >= 0) + ImportVault(xn, pwStorage); // 3.0.5 + } + } + + private static void AddEntry(XmlNode xnEntry, PwGroup pg, PwDatabase pd) + { + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + XmlNode xnTitle = xnEntry.Attributes.GetNamedItem(AttribCaption); + string strTitle = ((xnTitle != null) ? xnTitle.Value : string.Empty); + ImportUtil.AppendToField(pe, PwDefs.TitleField, strTitle ?? string.Empty, pd); + + foreach(XmlNode xn in xnEntry.ChildNodes) + { + if(Array.IndexOf(ElemsProps, xn.Name) >= 0) + { + XmlNode xnField = xn.Attributes.GetNamedItem(AttribCaption); + string strField = ((xnField != null) ? xnField.Value : null); + if(string.IsNullOrEmpty(strField)) { Debug.Assert(false); } + else + { + string strMap = ImportUtil.MapNameToStandardField(strField, false); + if(string.IsNullOrEmpty(strMap)) strMap = strField; + + ImportUtil.AppendToField(pe, strMap, + XmlUtil.SafeInnerText(xn), pd); + } + } + else { Debug.Assert(false); } // Unknown node + } + } + + private static void AddWebEntry(XmlNode xnEntry, PwGroup pg, PwDatabase pd) + { + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + XmlNode xn = xnEntry.Attributes.GetNamedItem(AttribCaption); + string str = ((xn != null) ? xn.Value : string.Empty); + ImportUtil.AppendToField(pe, PwDefs.TitleField, str ?? string.Empty, pd); + + xn = xnEntry.Attributes.GetNamedItem(AttribWebUrl); + str = ((xn != null) ? xn.Value : string.Empty); + ImportUtil.AppendToField(pe, PwDefs.UrlField, str ?? string.Empty, pd); + + xn = xnEntry.Attributes.GetNamedItem(AttribWebUserName); + str = ((xn != null) ? xn.Value : string.Empty); + ImportUtil.AppendToField(pe, PwDefs.UserNameField, str ?? string.Empty, pd); + + xn = xnEntry.Attributes.GetNamedItem(AttribWebPassword); + str = ((xn != null) ? xn.Value : string.Empty); + ImportUtil.AppendToField(pe, PwDefs.PasswordField, str ?? string.Empty, pd); + } + + private static void ImportVault(XmlNode xnVault, PwDatabase pd) + { + foreach(XmlNode xn in xnVault.ChildNodes) + { + if(Array.IndexOf(ElemsGroup, xn.Name) >= 0) + AddGroup(xn, pd.RootGroup, pd); + else if(Array.IndexOf(ElemsEntry, xn.Name) >= 0) + AddEntry(xn, pd.RootGroup, pd); + else { Debug.Assert(false); } // Unknown node + } + } + + private static void AddGroup(XmlNode xnGrp, PwGroup pgParent, PwDatabase pd) + { + PwGroup pg = new PwGroup(true, true); + pgParent.AddGroup(pg, true); + + XmlNode xnName = xnGrp.Attributes.GetNamedItem(AttribCaption); + string strName = ((xnName != null) ? xnName.Value : null); + if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); strName = KPRes.Group; } + pg.Name = strName; + + foreach(XmlNode xn in xnGrp) + { + if(Array.IndexOf(ElemsGroup, xn.Name) >= 0) + AddGroup(xn, pg, pd); + else if(Array.IndexOf(ElemsEntry, xn.Name) >= 0) + AddEntry(xn, pg, pd); + else if(Array.IndexOf(ElemsWebEntry, xn.Name) >= 0) + AddWebEntry(xn, pg, pd); + else { Debug.Assert(false); } // Unknown node + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/SecurityTxt12.cs b/src/KeePass/DataExchange/Formats/SecurityTxt12.cs new file mode 100644 index 0000000..9ad8632 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/SecurityTxt12.cs @@ -0,0 +1,135 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; + +namespace KeePass.DataExchange.Formats +{ + // 1.2 + internal sealed class SecurityTxt12 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Security TXT"; } } + public override string DefaultExtension { get { return "txt"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + private sealed class SecLine + { + public string Text = string.Empty; + public List SubLines = new List(); + } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + + Stack vGroups = new Stack(); + SecLine secRoot = new SecLine(); + vGroups.Push(secRoot); + + char[] vTrim = new char[] { '\t', '\n', '\r', ' ' }; + + while(true) + { + string str = sr.ReadLine(); + if(str == null) break; + if(str.Length == 0) continue; + + SecLine line = new SecLine(); + line.Text = str.Trim(vTrim); + + int nTabs = CountTabs(str); + + if(nTabs == vGroups.Count) + { + vGroups.Peek().SubLines.Add(line); + vGroups.Push(line); + } + else + { + while(nTabs < (vGroups.Count - 1)) + vGroups.Pop(); + + vGroups.Peek().SubLines.Add(line); + vGroups.Push(line); + } + } + + AddSecLine(pwStorage.RootGroup, secRoot, true, pwStorage); + + sr.Close(); + } + + private static int CountTabs(string str) + { + Debug.Assert(str != null); if(str == null) return 0; + + int nTabs = 0; + + for(int i = 0; i < str.Length; ++i) + { + if(str[i] != '\t') break; + ++nTabs; + } + + return nTabs; + } + + private void AddSecLine(PwGroup pgContainer, SecLine line, bool bIsContainer, + PwDatabase pwParent) + { + if(!bIsContainer) + { + if(line.SubLines.Count > 0) + { + PwGroup pg = new PwGroup(true, true); + pg.Name = line.Text; + + pgContainer.AddGroup(pg, true); + + pgContainer = pg; + } + else + { + PwEntry pe = new PwEntry(true, true); + pgContainer.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwParent.MemoryProtection.ProtectTitle, line.Text)); + } + } + + foreach(SecLine subLine in line.SubLines) + AddSecLine(pgContainer, subLine, false, pwParent); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/Spamex20070328.cs b/src/KeePass/DataExchange/Formats/Spamex20070328.cs new file mode 100644 index 0000000..071894a --- /dev/null +++ b/src/KeePass/DataExchange/Formats/Spamex20070328.cs @@ -0,0 +1,245 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Net; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Windows.Forms; + +using KeePass.Forms; +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Resources; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // Originally written on 2007-03-28, updated on 2012-04-15 + internal sealed class Spamex20070328 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Spamex.com"; } } + public override string ApplicationGroup { get { return KPRes.WebSites; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + public override bool RequiresFile { get { return false; } } + + public override Image SmallIcon + { + get { return KeePass.Properties.Resources.B16x16_WWW; } + } + + private const string UrlDomain = "www.spamex.com"; + private const string UrlBase = "https://www.spamex.com"; + + private const string UrlLoginPage = "https://www.spamex.com/tool/"; + private const string UrlIndexPage = "https://www.spamex.com/tool/listaliases.cfm"; + + private const string UrlIndexAliasLink = ""; + private const string StrTabLinkUrl = "/tool/listaliases.cfm"; + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + slLogger.SetText("> Spamex.com...", LogStatusType.Info); + + SingleLineEditForm dlgUser = new SingleLineEditForm(); + dlgUser.InitEx("Spamex.com", KPRes.WebSiteLogin + " - " + KPRes.UserName, + KPRes.UserNamePrompt, KeePass.Properties.Resources.B48x48_WWW, + string.Empty, null); + if(UIUtil.ShowDialogNotValue(dlgUser, DialogResult.OK)) return; + string strUser = dlgUser.ResultString; + UIUtil.DestroyForm(dlgUser); + + SingleLineEditForm dlgPassword = new SingleLineEditForm(); + dlgPassword.InitEx("Spamex.com", KPRes.WebSiteLogin + " - " + KPRes.Password, + KPRes.PasswordPrompt, KeePass.Properties.Resources.B48x48_WWW, + string.Empty, null); + if(UIUtil.ShowDialogNotValue(dlgPassword, DialogResult.OK)) return; + string strPassword = dlgPassword.ResultString; + UIUtil.DestroyForm(dlgPassword); + + RemoteCertificateValidationCallback pPrevCertCb = + ServicePointManager.ServerCertificateValidationCallback; + ServicePointManager.ServerCertificateValidationCallback = + delegate(object sender, X509Certificate certificate, X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + return true; + }; + + try + { + slLogger.SetText(KPRes.ImportingStatusMsg, LogStatusType.Info); + + string strPostData = @"toollogin=&MetaDomain=&LoginEmail=" + + strUser + @"&LoginPassword=" + strPassword + @"&Remember=1"; + + List> vCookies; + string strMain = NetUtil.WebPageLogin(new Uri(UrlLoginPage), + strPostData, out vCookies); + + if(strMain.IndexOf("Welcome " + strUser + "") < 0) + { + MessageService.ShowWarning(KPRes.InvalidUserPassword); + return; + } + + string strIndexPage = NetUtil.WebPageGetWithCookies(new Uri(UrlIndexPage), + vCookies, UrlDomain); + + ImportIndex(pwStorage, strIndexPage, vCookies, slLogger); + + int nOffset = 0; + List vSubPages = new List(); + while(true) + { + string strLink = StrUtil.GetStringBetween(strIndexPage, nOffset, + StrTabLinksStart, StrTabLinksEnd, out nOffset); + ++nOffset; + + if(strLink.Length == 0) break; + + if(!strLink.StartsWith(StrTabLinkUrl)) continue; + if(vSubPages.IndexOf(strLink) >= 0) continue; + + vSubPages.Add(strLink); + + string strSubPage = NetUtil.WebPageGetWithCookies(new Uri( + UrlBase + strLink), vCookies, UrlDomain); + + ImportIndex(pwStorage, strSubPage, vCookies, slLogger); + } + } + finally + { + ServicePointManager.ServerCertificateValidationCallback = pPrevCertCb; + } + } + + private static void ImportIndex(PwDatabase pwStorage, string strIndexPage, + List> vCookies, IStatusLogger slf) + { + int nOffset = 0; + while(true) + { + int nStart = strIndexPage.IndexOf(UrlIndexAliasLink, nOffset); + if(nStart < 0) break; + + nStart += UrlIndexAliasLink.Length; + + StringBuilder sbCode = new StringBuilder(); + while(true) + { + if(strIndexPage[nStart] == '\"') break; + sbCode.Append(strIndexPage[nStart]); + ++nStart; + } + + ImportAccount(pwStorage, sbCode.ToString(), vCookies, slf); + + nOffset = nStart + 1; + } + } + + private static void ImportAccount(PwDatabase pwStorage, string strID, + List> vCookies, IStatusLogger slf) + { + string strPage = NetUtil.WebPageGetWithCookies(new Uri( + UrlAccountPage + strID), vCookies, UrlDomain); + + PwEntry pe = new PwEntry(true, true); + pwStorage.RootGroup.AddEntry(pe, true); + + string str; + + string strTitle = StrUtil.GetStringBetween(strPage, 0, "Subject : ", ""); + if(strTitle.StartsWith("")) strTitle = strTitle.Substring(3, strTitle.Length - 3); + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, strTitle)); + + string strUser = StrUtil.GetStringBetween(strPage, 0, "Site Username : ", ""); + if(strUser.StartsWith("")) strUser = strUser.Substring(3, strUser.Length - 3); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, strUser)); + + str = StrUtil.GetStringBetween(strPage, 0, "Site Password : ", ""); + if(str.StartsWith("")) str = str.Substring(3, str.Length - 3); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, str)); + + str = StrUtil.GetStringBetween(strPage, 0, "Site Domain : ", ""); + if(str.StartsWith("")) str = str.Substring(3, str.Length - 3); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUrl, str)); + + str = StrUtil.GetStringBetween(strPage, 0, "Notes : ", ""); + if(str.StartsWith("")) str = str.Substring(3, str.Length - 3); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, str)); + + str = StrUtil.GetStringBetween(strPage, 0, "Address: ", ""); + if(str.StartsWith("")) str = str.Substring(3, str.Length - 3); + pe.Strings.Set("Address", new ProtectedString(false, str)); + + str = StrUtil.GetStringBetween(strPage, 0, "Forwards to: ", ""); + if(str.StartsWith("")) str = str.Substring(3, str.Length - 3); + pe.Strings.Set("Forward To", new ProtectedString(false, str)); + + str = StrUtil.GetStringBetween(strPage, 0, "Reply-To Messages: ", ""); + if(str.StartsWith("")) str = str.Substring(3, str.Length - 3); + pe.Strings.Set("Reply-To Messages", new ProtectedString(false, str)); + + str = StrUtil.GetStringBetween(strPage, 0, "Allow Reply From: ", ""); + if(str.StartsWith("")) str = str.Substring(3, str.Length - 3); + pe.Strings.Set("Allow Reply From", new ProtectedString(false, str)); + + str = StrUtil.GetStringBetween(strPage, 0, "Filter Mode: ", ""); + if(str.StartsWith("")) str = str.Substring(3, str.Length - 3); + pe.Strings.Set("Filter Mode", new ProtectedString(false, str)); + + str = StrUtil.GetStringBetween(strPage, 0, "Created: ", ""); + if(str.StartsWith("")) str = str.Substring(3, str.Length - 3); + pe.Strings.Set("Created", new ProtectedString(false, str)); + + slf.SetText(strTitle + " - " + strUser + " (" + strID + ")", + LogStatusType.Info); + + if(!slf.ContinueWork()) + throw new InvalidOperationException(string.Empty); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/SplashIdCsv402.cs b/src/KeePass/DataExchange/Formats/SplashIdCsv402.cs new file mode 100644 index 0000000..6fcec3b --- /dev/null +++ b/src/KeePass/DataExchange/Formats/SplashIdCsv402.cs @@ -0,0 +1,296 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 3.4-5.3+, 8.3.1 confirmed by user, types from web 2020-09 (version 8.3) + internal sealed class SplashIdCsv402 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "SplashID CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return false; } } + + private const string StrHeader = "SplashID Export File"; + + private static SplashIdMapping[] m_vMappings = null; + private static SplashIdMapping[] SplashIdMappings + { + get + { + if(m_vMappings != null) return m_vMappings; + + m_vMappings = new SplashIdMapping[] { + new SplashIdMapping("Addresses", PwIcon.UserCommunication, + new string[] { PwDefs.TitleField, // Name + PwDefs.NotesField, // Address + PwDefs.NotesField, // Address 2 + PwDefs.NotesField, // City + PwDefs.NotesField, // State + PwDefs.NotesField, // Zip Code + PwDefs.NotesField, // Country + PwDefs.UserNameField, // Email + PwDefs.NotesField }), // Phone + new SplashIdMapping("Bank Accounts", PwIcon.Homebanking, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField, "Name", "Branch", "Phone #" }), + new SplashIdMapping("Bank Accts", PwIcon.Homebanking, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField, "Name", "Branch", "Phone #" }), + new SplashIdMapping("Birthdays", PwIcon.UserCommunication, + new string[] { PwDefs.TitleField, PwDefs.UserNameField }), + new SplashIdMapping("Calling Cards", PwIcon.UserKey, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField }), + new SplashIdMapping("Clothes Size", PwIcon.UserCommunication, + new string[] { PwDefs.TitleField, "Shirt Size", "Pant Size", + "Shoe Size", "Dress Size", "Ring Size" }), + new SplashIdMapping("Combinations", PwIcon.Key, + new string[] { PwDefs.TitleField, PwDefs.PasswordField }), + new SplashIdMapping("Credit Cards", PwIcon.Money, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + "Expiry Date", "Name", PwDefs.PasswordField, "Bank" }), + new SplashIdMapping("Email Accounts", PwIcon.EMail, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField, "POP3 Host", "SMTP Host" }), + new SplashIdMapping("Email Accts", PwIcon.EMail, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField, "POP3 Host", "SMTP Host" }), + new SplashIdMapping("Emergency Info", PwIcon.UserCommunication, + new string[] { PwDefs.TitleField, PwDefs.UserNameField }), + new SplashIdMapping("Files", PwIcon.PaperNew, + new string[] { PwDefs.TitleField, PwDefs.NotesField, + PwDefs.UserNameField, "Date" }), + new SplashIdMapping("Frequent Flyer", PwIcon.PaperQ, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + "Name", "Date" }), + new SplashIdMapping("Identification", PwIcon.UserKey, + new string[] { PwDefs.TitleField, PwDefs.PasswordField, + PwDefs.UserNameField, "Date" }), + new SplashIdMapping("Insurance", PwIcon.ClipboardReady, + new string[] { PwDefs.TitleField, PwDefs.PasswordField, + PwDefs.UserNameField, "Insured", "Date", "Phone #" }), + new SplashIdMapping("Memberships", PwIcon.UserKey, + new string[] { PwDefs.TitleField, PwDefs.PasswordField, + PwDefs.UserNameField, "Date" }), + new SplashIdMapping("Phone Numbers", PwIcon.UserCommunication, + new string[] { PwDefs.TitleField, PwDefs.UserNameField }), + new SplashIdMapping("Prescriptions", PwIcon.ClipboardReady, + new string[] { PwDefs.TitleField, PwDefs.PasswordField, + PwDefs.UserNameField, "Doctor", "Pharmacy", "Phone #" }), + new SplashIdMapping("Serial Numbers", PwIcon.Key, + new string[] { PwDefs.TitleField, PwDefs.PasswordField, + "Date", "Reseller" }), + new SplashIdMapping("Servers", PwIcon.NetworkServer, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField, PwDefs.UrlField }), + new SplashIdMapping("Vehicle Info", PwIcon.PaperReady, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField, "Insurance", "Year" }), + new SplashIdMapping("Vehicles", PwIcon.PaperReady, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField, "Insurance", "Year" }), + new SplashIdMapping("Voice Mail", PwIcon.IRCommunication, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField }), + new SplashIdMapping("Web Logins", PwIcon.Key, + new string[] { PwDefs.TitleField, PwDefs.UserNameField, + PwDefs.PasswordField, PwDefs.UrlField }) + }; + return m_vMappings; + } + } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + CsvOptions o = new CsvOptions(); + o.BackslashIsEscape = false; + + CsvStreamReaderEx csv = new CsvStreamReaderEx(strData, o); + + SortedDictionary dictGroups = + new SortedDictionary(); + while(true) + { + string[] vLine = csv.ReadLine(); + if(vLine == null) break; + if(vLine.Length == 0) continue; + + if(vLine.Length == 1) + { + Debug.Assert(vLine[0] == StrHeader); + continue; + } + + // Support old version 3.4 + if(vLine.Length == 9) + { + string[] v = new string[13]; + for(int i = 0; i < 7; ++i) v[i] = vLine[i]; + for(int i = 7; i < 11; ++i) v[i] = string.Empty; + v[11] = vLine[7]; + v[12] = vLine[8]; + + vLine = v; + } + + if(vLine.Length == 13) + ProcessCsvLine(vLine, pwStorage, dictGroups); + else { Debug.Assert(false); } + } + } + + private static void ProcessCsvLine(string[] vLine, PwDatabase pwStorage, + SortedDictionary dictGroups) + { + string strType = ParseCsvWord(vLine[0]); + + string strGroupName = ParseCsvWord(vLine[12]); // + " - " + strType; + if(strGroupName.Length == 0) strGroupName = strType; + + SplashIdMapping mp = null; + foreach(SplashIdMapping mpFind in SplashIdCsv402.SplashIdMappings) + { + if(mpFind.TypeName == strType) + { + mp = mpFind; + break; + } + } + + PwIcon pwIcon = ((mp != null) ? mp.Icon : PwIcon.Key); + + PwGroup pg = null; + if(dictGroups.ContainsKey(strGroupName)) + pg = dictGroups[strGroupName]; + else + { + // PwIcon pwGroupIcon = ((pwIcon == PwIcon.Key) ? + // PwIcon.FolderOpen : pwIcon); + // pg = new PwGroup(true, true, strGroupName, pwGroupIcon); + + pg = new PwGroup(true, true); + pg.Name = strGroupName; + + pwStorage.RootGroup.AddGroup(pg, true); + dictGroups[strGroupName] = pg; + } + + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + pe.IconId = pwIcon; + + StrUtil.AddTags(pe.Tags, StrUtil.StringToTags(strType)); + + for(int iField = 0; iField < 9; ++iField) + { + string strData = ParseCsvWord(vLine[iField + 1]); + if(strData.Length == 0) continue; + + string strLookup = ((mp != null) ? mp.FieldNames[iField] : + null); + string strField = (strLookup ?? ("Field " + (iField + 1).ToString())); + + ImportUtil.AppendToField(pe, strField, strData, pwStorage); + } + + ImportUtil.AppendToField(pe, PwDefs.NotesField, ParseCsvWord(vLine[11]), + pwStorage); + + DateTime? odt = TimeUtil.ParseUSTextDate(ParseCsvWord(vLine[10]), + DateTimeKind.Local); + if(odt.HasValue) + { + DateTime dt = TimeUtil.ToUtc(odt.Value, false); + pe.LastAccessTime = dt; + pe.LastModificationTime = dt; + } + } + + private static string ParseCsvWord(string strWord) + { + if(strWord == null) { Debug.Assert(false); return string.Empty; } + + string str = strWord; + str = str.Replace('\u000B', '\n'); // 0x0B = new line + str = StrUtil.NormalizeNewLines(str, true); + return str; + } + + private sealed class SplashIdMapping + { + private readonly string m_strTypeName; + public string TypeName + { + get { return m_strTypeName; } + } + + private readonly PwIcon m_pwIcon; + public PwIcon Icon + { + get { return m_pwIcon; } + } + + private string[] m_vFieldNames = new string[9]; + public string[] FieldNames + { + get { return m_vFieldNames; } + } + + public SplashIdMapping(string strTypeName, PwIcon pwIcon, string[] vFieldNames) + { + Debug.Assert(strTypeName != null); + if(strTypeName == null) throw new ArgumentNullException("strTypeName"); + + Debug.Assert(vFieldNames != null); + if(vFieldNames == null) throw new ArgumentNullException("vFieldNames"); + + m_strTypeName = strTypeName; + m_pwIcon = pwIcon; + + int nMin = Math.Min(m_vFieldNames.Length, vFieldNames.Length); + for(int i = 0; i < nMin; ++i) + m_vFieldNames[i] = vFieldNames[i]; + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/SteganosCsv20.cs b/src/KeePass/DataExchange/Formats/SteganosCsv20.cs new file mode 100644 index 0000000..3702a71 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/SteganosCsv20.cs @@ -0,0 +1,182 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 20.0.7-22.3.1+ + internal sealed class SteganosCsv20 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Steganos Password Manager CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + CsvOptions opt = new CsvOptions(); + opt.BackslashIsEscape = false; + // opt.TextQualifier = char.MinValue; // For 20.0.7, not 22.3.1 + opt.TrimFields = true; + + CsvStreamReaderEx csv = new CsvStreamReaderEx(strData, opt); + + string strMapIgnore = Guid.NewGuid().ToString(); + string strMapGroup = Guid.NewGuid().ToString(); + string strMapTags = Guid.NewGuid().ToString(); + string strMapLastMod = Guid.NewGuid().ToString(); + string strMapEMail = Guid.NewGuid().ToString(); + + Dictionary dMaps = new Dictionary( + StrUtil.CaseIgnoreComparer); + dMaps["title"] = PwDefs.TitleField; + dMaps["type"] = strMapIgnore; + dMaps["username_field"] = strMapIgnore; + dMaps["username"] = PwDefs.UserNameField; + dMaps["password_field"] = strMapIgnore; + dMaps["password"] = PwDefs.PasswordField; + dMaps["url"] = PwDefs.UrlField; + dMaps["category"] = strMapGroup; + dMaps["note"] = PwDefs.NotesField; + dMaps["autofill"] = strMapIgnore; + dMaps["autofillenabled"] = strMapIgnore; + dMaps["last_password_change"] = strMapIgnore; + dMaps["lastmodified"] = strMapLastMod; + dMaps["iban"] = PwDefs.UserNameField; + dMaps["bic"] = "BIC"; + dMaps["banking_pin"] = PwDefs.PasswordField; + dMaps["card_number"] = PwDefs.UserNameField; + dMaps["card_holder"] = "Card Holder"; + dMaps["card_pin"] = PwDefs.PasswordField; + dMaps["card_verification_code"] = "Verification Code"; + dMaps["valid_from"] = "Valid From"; + dMaps["valid_thru"] = "Valid To"; + dMaps["name"] = PwDefs.UserNameField; + dMaps["firstname"] = PwDefs.UserNameField; + dMaps["street"] = PwDefs.NotesField; + dMaps["houseno"] = PwDefs.NotesField; + dMaps["zip"] = PwDefs.NotesField; + dMaps["city"] = PwDefs.NotesField; + dMaps["mobile_phone"] = PwDefs.NotesField; + dMaps["phone"] = PwDefs.NotesField; + dMaps["email"] = strMapEMail; + dMaps["birthday"] = "Birthday"; + dMaps["tags"] = strMapTags; + dMaps["keyword"] = strMapTags; + + string[] vNames = csv.ReadLine(); + if((vNames == null) || (vNames.Length == 0)) { Debug.Assert(false); return; } + + for(int i = 0; i < vNames.Length; ++i) + { + string str = vNames[i]; + + if(string.IsNullOrEmpty(str)) { Debug.Assert(false); str = strMapIgnore; } + else + { + string strMapped = null; + dMaps.TryGetValue(str, out strMapped); + + if(string.IsNullOrEmpty(strMapped)) + { + Debug.Assert(false); + strMapped = ImportUtil.MapNameToStandardField(str, true); + if(string.IsNullOrEmpty(strMapped)) strMapped = PwDefs.NotesField; + } + + str = strMapped; + } + + vNames[i] = str; + } + + Dictionary dGroups = new Dictionary(); + + while(true) + { + string[] v = csv.ReadLine(); + if(v == null) break; + if(v.Length == 0) continue; + + PwEntry pe = new PwEntry(true, true); + PwGroup pg = pwStorage.RootGroup; + + for(int i = 0; i < v.Length; ++i) + { + string strValue = v[i]; + if(string.IsNullOrEmpty(strValue)) continue; + + strValue = strValue.Replace(@"", ","); + strValue = strValue.Replace(@"<-N/L-/>", "\n"); + + strValue = StrUtil.NormalizeNewLines(strValue, true); + + string strName = ((i < vNames.Length) ? vNames[i] : PwDefs.NotesField); + + if(strName == strMapIgnore) { } + else if(strName == strMapGroup) + { + dGroups.TryGetValue(strValue, out pg); + if(pg == null) + { + pg = new PwGroup(true, true); + pg.Name = strValue; + + pwStorage.RootGroup.AddGroup(pg, true); + dGroups[strValue] = pg; + } + } + else if(strName == strMapTags) + StrUtil.AddTags(pe.Tags, StrUtil.StringToTags(strValue)); + else if(strName == strMapLastMod) + { + double dUnix; + if(double.TryParse(strValue, out dUnix)) + pe.LastModificationTime = TimeUtil.ConvertUnixTime(dUnix); + else { Debug.Assert(false); } + } + else if(strName == strMapEMail) + ImportUtil.AppendToField(pe, PwDefs.UrlField, + "mailto:" + strValue, pwStorage); + else ImportUtil.AppendToField(pe, strName, strValue, pwStorage); + } + + pg.AddEntry(pe, true); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/SteganosUI2007.cs b/src/KeePass/DataExchange/Formats/SteganosUI2007.cs new file mode 100644 index 0000000..f2a6209 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/SteganosUI2007.cs @@ -0,0 +1,142 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +using KeePass.App; +using KeePass.Native; +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class SteganosUI2007 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Steganos Password Manager 2007"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool RequiresFile { get { return false; } } + + public override Image SmallIcon + { + get { return KeePass.Properties.Resources.B16x16_View_Detailed; } + } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + if(!MessageService.AskYesNo(KPRes.ImportMustRead + MessageService.NewParagraph + + KPRes.ImportMustReadQuestion)) + { + AppHelp.ShowHelp(AppDefs.HelpTopics.ImportExport, + AppDefs.HelpTopics.ImportExportSteganos); + return; + } + + PwEntry pePrev = new PwEntry(true, true); + + for(int i = 0; i < 20; ++i) + { + Thread.Sleep(500); + Application.DoEvents(); + } + + try + { + while(true) + { + PwEntry pe = ImportEntry(pwStorage); + + if(ImportUtil.EntryEquals(pe, pePrev)) + { + if(pe.ParentGroup != null) // Remove duplicate + pe.ParentGroup.Entries.Remove(pe); + break; + } + + ImportUtil.GuiSendKeysPrc(@"{DOWN}"); + pePrev = pe; + } + + MessageService.ShowInfo(KPRes.ImportFinished); + } + catch(Exception exImp) { MessageService.ShowWarning(exImp); } + } + + private static PwEntry ImportEntry(PwDatabase pwDb) + { + ImportUtil.GuiSendWaitWindowChange(@"{ENTER}"); + Thread.Sleep(1000); + ImportUtil.GuiSendKeysPrc(string.Empty); // Process messages + + string strTitle = ImportUtil.GuiSendRetrieve(string.Empty); + string strGroup = ImportUtil.GuiSendRetrieve(@"{TAB}"); + string strUserName = ImportUtil.GuiSendRetrieve(@"{TAB}"); + ImportUtil.GuiSendKeysPrc(@"{TAB}{TAB}"); + ImportUtil.GuiSendKeysPrc(@" "); + ImportUtil.GuiSendKeysPrc(@"+({TAB})"); + string strPassword = ImportUtil.GuiSendRetrieve(string.Empty); + ImportUtil.GuiSendKeysPrc(@"{TAB} "); + string strNotes = ImportUtil.GuiSendRetrieve(@"{TAB}{TAB}"); + + string strUrl = ImportUtil.GuiSendRetrieve(@"{TAB}"); + string strUrl2 = ImportUtil.GuiSendRetrieve(@"{TAB}"); + + ImportUtil.GuiSendWaitWindowChange(@"{ESC}"); + + if(strGroup.Length == 0) strGroup = "Steganos"; + + PwGroup pg = pwDb.RootGroup.FindCreateGroup(strGroup, true); + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwDb.MemoryProtection.ProtectTitle, strTitle)); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwDb.MemoryProtection.ProtectUserName, strUserName)); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwDb.MemoryProtection.ProtectPassword, strPassword)); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwDb.MemoryProtection.ProtectNotes, strNotes)); + + if(strUrl.Length > 0) + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwDb.MemoryProtection.ProtectUrl, strUrl)); + else + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pwDb.MemoryProtection.ProtectUrl, strUrl2)); + + return pe; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/StickyPwXml50.cs b/src/KeePass/DataExchange/Formats/StickyPwXml50.cs new file mode 100644 index 0000000..95acd02 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/StickyPwXml50.cs @@ -0,0 +1,253 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.XPath; + +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // KasperskyPwMgrXml50 derives from this + + // 5.0.4.232-8.4.4+ + internal class StickyPwXml50 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Sticky Password XML"; } } + public override string DefaultExtension { get { return "xml"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + using(XmlReader xr = XmlUtilEx.CreateXmlReader(sInput)) + { + XPathDocument xpDoc = new XPathDocument(xr); + XPathNavigator xpNav = xpDoc.CreateNavigator(); + + Dictionary dGroups = ImportGroups(xpNav, pwStorage); + + ImportLogins(xpNav, dGroups, pwStorage); + ImportMemos(xpNav, dGroups, pwStorage); + } + } + + private static Dictionary ImportGroups(XPathNavigator xpNav, + PwDatabase pd) + { + List l = new List(); // Original order + Dictionary d = new Dictionary(); + Dictionary dParents = new Dictionary(); + + XPathNodeIterator it = xpNav.Select( + "/root/Database/Groups/Group | /root/Database/SecureMemoGroups/Group"); + while(it.MoveNext()) + { + XPathNavigator xpGroup = it.Current; + PwGroup pg = new PwGroup(true, true); + + string strName = xpGroup.GetAttribute("Name", string.Empty); + if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); strName = KPRes.Group; } + pg.Name = strName; + + string strID = xpGroup.GetAttribute("ID", string.Empty); + if(string.IsNullOrEmpty(strID)) { Debug.Assert(false); continue; } + Debug.Assert(!d.ContainsKey(strID)); + + string strParentID = xpGroup.GetAttribute("ParentID", string.Empty); + + l.Add(pg); + d[strID] = pg; + if(!string.IsNullOrEmpty(strParentID)) dParents[pg] = strParentID; + else { Debug.Assert(false); } + } + + foreach(PwGroup pg in l) + { + string strParentID; + if(dParents.TryGetValue(pg, out strParentID)) + { + PwGroup pgParent; + if(d.TryGetValue(strParentID, out pgParent)) + { + if((pgParent != pg) && !pgParent.IsContainedIn(pg)) + { + pgParent.AddGroup(pg, true); + continue; + } + else { Debug.Assert(false); } + } + // else { Debug.Assert(false); } // May be negative ID + } + else { Debug.Assert(false); } + + pd.RootGroup.AddGroup(pg, true); + } + + d[string.Empty] = pd.RootGroup; + return d; + } + + private static void ImportLogins(XPathNavigator xpNav, + Dictionary dGroups, PwDatabase pd) + { + XPathNodeIterator it = xpNav.Select("/root/Database/Logins/Login"); + while(it.MoveNext()) + { + XPathNavigator xpLogin = it.Current; + PwEntry pe = new PwEntry(true, true); + + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pd.MemoryProtection.ProtectUserName, + xpLogin.GetAttribute("Name", string.Empty))); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pd.MemoryProtection.ProtectPassword, + xpLogin.GetAttribute("Password", string.Empty))); + + ImportTimes(xpLogin, pe); + + string strID = xpLogin.GetAttribute("ID", string.Empty); + + XPathNavigator xpAccLogin = (!string.IsNullOrEmpty(strID) ? + xpNav.SelectSingleNode( + "/root/Database/Accounts/Account/LoginLinks/Login[@SourceLoginID='" + + strID + "']/../..") : null); + if(xpAccLogin == null) { Debug.Assert(false); } + else + { + Debug.Assert(xpAccLogin.Name == "Account"); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pd.MemoryProtection.ProtectTitle, + xpAccLogin.GetAttribute("Name", string.Empty))); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + pd.MemoryProtection.ProtectUrl, + xpAccLogin.GetAttribute("Link", string.Empty))); + + string strNotes = xpAccLogin.GetAttribute("Comments", string.Empty); + strNotes = strNotes.Replace("/n", Environment.NewLine); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pd.MemoryProtection.ProtectNotes, strNotes)); + } + + AddToParent(xpAccLogin, pe, dGroups); + } + } + + private static void ImportMemos(XPathNavigator xpNav, + Dictionary dGroups, PwDatabase pd) + { + XPathNodeIterator it = xpNav.Select("/root/Database/SecureMemos/SecureMemo"); + while(it.MoveNext()) + { + XPathNavigator xpMemo = it.Current; + PwEntry pe = new PwEntry(true, true); + + pe.IconId = PwIcon.PaperNew; + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pd.MemoryProtection.ProtectTitle, + xpMemo.GetAttribute("Name", string.Empty))); + + ImportTimes(xpMemo, pe); + + try + { + string strMemoHex = xpMemo.Value; + byte[] pbMemo = MemUtil.HexStringToByteArray(strMemoHex); + string strMemoRtf = Encoding.Unicode.GetString(pbMemo); + + pe.Binaries.Set(KPRes.Notes + ".rtf", new ProtectedBinary( + false, StrUtil.Utf8.GetBytes(strMemoRtf))); + } + catch(Exception) { Debug.Assert(false); } + + AddToParent(xpMemo, pe, dGroups); + } + } + + private static void AddToParent(XPathNavigator xpNav, PwEntry pe, + Dictionary dGroups) + { + if(xpNav != null) + { + string strParentID = xpNav.GetAttribute("ParentID", string.Empty); + if(!string.IsNullOrEmpty(strParentID)) + { + PwGroup pgParent; + if(dGroups.TryGetValue(strParentID, out pgParent)) + { + pgParent.AddEntry(pe, true); + return; + } + } + else { Debug.Assert(false); } + } + + dGroups[string.Empty].AddEntry(pe, true); + } + + private static DateTime? GetTime(XPathNavigator xpNav, string strAttrib) + { + try + { + string str = xpNav.GetAttribute(strAttrib, string.Empty); + if(!string.IsNullOrEmpty(str)) + return TimeUtil.ToUtc(XmlConvert.ToDateTime(str, + XmlDateTimeSerializationMode.Local), false); + } + catch(Exception) { Debug.Assert(false); } + + return null; + } + + private static void ImportTimes(XPathNavigator xpNav, PwEntry pe) + { + DateTime? odt = GetTime(xpNav, "CreatedDate"); + if(odt.HasValue) pe.CreationTime = odt.Value; + else { Debug.Assert(false); } + + odt = GetTime(xpNav, "ModifiedDate"); + if(odt.HasValue) pe.LastModificationTime = odt.Value; + else { Debug.Assert(false); } + + odt = GetTime(xpNav, "ExpirationDate"); + if(odt.HasValue) + { + pe.Expires = true; + pe.ExpiryTime = odt.Value; + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/TrueKeyCsv4.cs b/src/KeePass/DataExchange/Formats/TrueKeyCsv4.cs new file mode 100644 index 0000000..3f35862 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/TrueKeyCsv4.cs @@ -0,0 +1,259 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Text; + +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class TrueKeyCsv4 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "True Key CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + CsvOptions opt = new CsvOptions(); + opt.BackslashIsEscape = false; + opt.TrimFields = true; + + CsvStreamReaderEx csv = new CsvStreamReaderEx(strData, opt); + + string[] vNames = csv.ReadLine(); + if((vNames == null) || (vNames.Length == 0)) { Debug.Assert(false); return; } + + for(int i = 0; i < vNames.Length; ++i) + vNames[i] = (vNames[i] ?? string.Empty).ToLowerInvariant(); + + while(true) + { + string[] v = csv.ReadLine(); + if(v == null) break; + if(v.Length == 0) continue; + + PwEntry pe = new PwEntry(true, true); + pwStorage.RootGroup.AddEntry(pe, true); + + Debug.Assert(v.Length == vNames.Length); + int m = Math.Min(v.Length, vNames.Length); + + for(int i = 0; i < m; ++i) + { + string strValue = v[i]; + if(string.IsNullOrEmpty(strValue)) continue; + + string strName = vNames[i]; + string strTo = null; + DateTime? odt; + + switch(strName) + { + case "autologin": + case "protectedwithpassword": + case "subdomainonly": + case "type": + case "tk_export_version": + break; // Ignore + + case "kind": + if(strValue.Equals("note", StrUtil.CaseIgnoreCmp)) + pe.IconId = PwIcon.Note; + else if(strValue.Equals("identity", StrUtil.CaseIgnoreCmp) || + strValue.Equals("drivers", StrUtil.CaseIgnoreCmp) || + strValue.Equals("passport", StrUtil.CaseIgnoreCmp) || + strValue.Equals("ssn", StrUtil.CaseIgnoreCmp)) + pe.IconId = PwIcon.Identity; + else if(strValue.Equals("cc", StrUtil.CaseIgnoreCmp)) + pe.IconId = PwIcon.Money; + else if(strValue.Equals("membership", StrUtil.CaseIgnoreCmp)) + pe.IconId = PwIcon.UserKey; + break; + + case "name": + case "title": + strTo = PwDefs.TitleField; + break; + + case "cardholder": + case "email": + case "login": + strTo = PwDefs.UserNameField; + break; + + case "password": + strTo = PwDefs.PasswordField; + break; + + case "url": + case "website": + strTo = PwDefs.UrlField; + break; + + case "document_content": + case "memo": + case "note": + strTo = PwDefs.NotesField; + break; + + case "city": + case "company": + case "country": + case "number": + case "state": + case "street": + case "telephone": + strTo = (new string(char.ToUpperInvariant(strName[0]), 1)) + + strName.Substring(1); + break; + + case "deliveryplace": + strTo = "Delivery Place"; + break; + case "firstname": + strTo = "First Name"; + break; + case "lastname": + strTo = "Last Name"; + break; + case "memberid": + strTo = "Member ID"; + break; + case "phonenumber": + strTo = "Phone Number"; + break; + case "streetnumber": + strTo = "Street Number"; + break; + case "zipcode": + strTo = "ZIP Code"; + break; + + case "dateofbirth": + strTo = "Date of Birth"; + strValue = DateToString(strValue); + break; + + case "expirationdate": + case "expirydate": + odt = ParseTime(strValue); + if(odt.HasValue) + { + pe.Expires = true; + pe.ExpiryTime = odt.Value; + } + break; + + case "favorite": + if(StrUtil.StringToBoolEx(strValue).GetValueOrDefault(false)) + pe.AddTag(PwDefs.FavoriteTag); + break; + + case "gender": + if((strValue == "0") || (strValue == "1")) + { + strTo = "Gender"; + strValue = ((strValue == "0") ? "Male" : "Female"); + } + else { Debug.Assert(false); } + break; + + case "hexcolor": + if((strValue.Length == 6) && StrUtil.IsHexString(strValue, true)) + { + Color c = Color.FromArgb(unchecked((int)(0xFF000000U | + Convert.ToUInt32(strValue, 16)))); + + Color cG = UIUtil.ColorToGrayscale(c); + if(cG.B < 128) c = UIUtil.LightenColor(c, 0.5); + + pe.BackgroundColor = c; + } + else { Debug.Assert(false); } + break; + + case "issuedate": + case "issueddate": + strTo = "Issue Date"; + strValue = DateToString(strValue); + break; + + case "membersince": + strTo = "Member Since"; + strValue = DateToString(strValue); + break; + + default: + Debug.Assert(false); // Unknown field + break; + } + + if(!string.IsNullOrEmpty(strTo)) + ImportUtil.AppendToField(pe, strTo, strValue, pwStorage); + } + } + } + + private static DateTime? ParseTime(string strTime) + { + if(string.IsNullOrEmpty(strTime)) return null; + + DateTime dt; + if(TimeUtil.TryDeserializeUtc(strTime, out dt)) return dt; + + Debug.Assert(false); + return null; + } + + private static string DateToString(string strTime) + { + if(string.IsNullOrEmpty(strTime)) return string.Empty; + + DateTime? odt = ParseTime(strTime); + if(odt.HasValue) + { + DateTime dt = TimeUtil.ToLocal(odt.Value, false); + return TimeUtil.ToDisplayStringDateOnly(dt); + } + + return strTime; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/TurboPwsCsv5.cs b/src/KeePass/DataExchange/Formats/TurboPwsCsv5.cs new file mode 100644 index 0000000..ed5be24 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/TurboPwsCsv5.cs @@ -0,0 +1,117 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; + +namespace KeePass.DataExchange.Formats +{ + // 5.0.1+ + internal sealed class TurboPwsCsv5 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "TurboPasswords CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + sInput.Close(); + + Dictionary dGroups = new Dictionary(); + dGroups[string.Empty] = pwStorage.RootGroup; + + CsvOptions opt = new CsvOptions(); + opt.BackslashIsEscape = false; + + CsvStreamReaderEx csv = new CsvStreamReaderEx(strData, opt); + + while(true) + { + string[] v = csv.ReadLine(); + if(v == null) break; + if(v.Length == 0) continue; + if(v[0].StartsWith("TurboPasswords CSV Export File")) continue; + if(v.Length < 24) { Debug.Assert(false); continue; } + if((v[0] == "Category") && (v[1] == "Type")) continue; + + PwEntry pe = new PwEntry(true, true); + + PwGroup pg; + string strGroup = v[0]; + if(!dGroups.TryGetValue(strGroup, out pg)) + { + pg = new PwGroup(true, true, strGroup, PwIcon.Folder); + dGroups[string.Empty].AddGroup(pg, true); + dGroups[strGroup] = pg; + } + pg.AddEntry(pe, true); + + string strType = v[1]; + + for(int f = 0; f < 6; ++f) + { + string strKey = v[2 + (2 * f)]; + string strValue = v[2 + (2 * f) + 1]; + if(strKey.Length == 0) strKey = PwDefs.NotesField; + if(strValue.Length == 0) continue; + + if(strKey == "Description") + strKey = PwDefs.TitleField; + else if(((strType == "Contact") || (strType == "Personal Info")) && + (strKey == "Name")) + strKey = PwDefs.TitleField; + else if(((strType == "Membership") || (strType == "Insurance")) && + (strKey == "Company")) + strKey = PwDefs.TitleField; + else if(strKey == "SSN") + strKey = PwDefs.UserNameField; + else + { + string strMapped = ImportUtil.MapNameToStandardField(strKey, false); + if(!string.IsNullOrEmpty(strMapped)) strKey = strMapped; + } + + ImportUtil.AppendToField(pe, strKey, strValue, pwStorage); + } + + ImportUtil.AppendToField(pe, PwDefs.NotesField, v[20], pwStorage, + "\r\n\r\n", false); + if(v[21].Length > 0) + ImportUtil.AppendToField(pe, "Login URL", v[21], pwStorage, null, true); + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/VisKeeperTxt3.cs b/src/KeePass/DataExchange/Formats/VisKeeperTxt3.cs new file mode 100644 index 0000000..65f077c --- /dev/null +++ b/src/KeePass/DataExchange/Formats/VisKeeperTxt3.cs @@ -0,0 +1,133 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; +using KeePassLib.Security; + +namespace KeePass.DataExchange.Formats +{ + // 3.3.0+ + internal sealed class VisKeeperTxt3 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "VisKeeper TXT"; } } + public override string DefaultExtension { get { return "txt"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default, true); + string strData = sr.ReadToEnd(); + sr.Close(); + + strData = StrUtil.NormalizeNewLines(strData, false); + + const string strInitGroup = "\n\nOrdner:"; + const string strInitTemplate = "\n\nVorlage:"; + const string strInitEntry = "\n\nEintrag:"; + const string strInitNote = "\n\nNotiz:"; + string[] vSeps = new string[] { strInitGroup, strInitTemplate, + strInitEntry, strInitNote }; + + List lData = StrUtil.SplitWithSep(strData, vSeps, true); + Debug.Assert((lData.Count & 1) == 1); + + PwGroup pgRoot = pwStorage.RootGroup; + + PwGroup pgTemplates = new PwGroup(true, true, "Vorlagen", + PwIcon.MarkedDirectory); + pgRoot.AddGroup(pgTemplates, true); + + for(int i = 1; (i + 1) < lData.Count; i += 2) + { + string strInit = lData[i]; + string strPart = lData[i + 1]; + + if(strInit == strInitGroup) { } + else if(strInit == strInitTemplate) + ImportEntry(strPart, pgTemplates, pwStorage, false); + else if(strInit == strInitEntry) + ImportEntry(strPart, pgRoot, pwStorage, false); + else if(strInit == strInitNote) + ImportEntry(strPart, pgRoot, pwStorage, true); + else { Debug.Assert(false); } + } + } + + private static void ImportEntry(string strData, PwGroup pg, PwDatabase pd, + bool bForceNotes) + { + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + string[] v = strData.Split('\n'); + + if(v.Length == 0) { Debug.Assert(false); return; } + ImportUtil.AppendToField(pe, PwDefs.TitleField, v[0].Trim(), pd); + + int n = v.Length; + for(int j = n - 1; j >= 0; --j) + { + if(v[j].Length > 0) break; + --n; + } + + bool bInNotes = bForceNotes; + for(int i = 1; i < n; ++i) + { + string str = v[i]; + + int iSep = str.IndexOf(':'); + if(iSep <= 0) bInNotes = true; + + if(bInNotes) + { + if(str.Length == 0) + ImportUtil.AppendToField(pe, PwDefs.NotesField, + MessageService.NewLine, pd, string.Empty, false); + else + ImportUtil.AppendToField(pe, PwDefs.NotesField, str, pd); + } + else + { + string strRawKey = str.Substring(0, iSep); + string strValue = str.Substring(iSep + 1).Trim(); + + string strKey = ImportUtil.MapNameToStandardField(strRawKey, false); + if(string.IsNullOrEmpty(strKey)) strKey = strRawKey; + + ImportUtil.AppendToField(pe, strKey, strValue, pd); + } + } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/Whisper32Csv116.cs b/src/KeePass/DataExchange/Formats/Whisper32Csv116.cs new file mode 100644 index 0000000..861c429 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/Whisper32Csv116.cs @@ -0,0 +1,158 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 1.16 + internal sealed class Whisper32Csv116 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "Whisper 32 CSV"; } } + public override string DefaultExtension { get { return "csv"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strDocument = sr.ReadToEnd(); + sr.Close(); + + PwGroup pg = pwStorage.RootGroup; + + CharStream cs = new CharStream(strDocument); + string[] vFields = new string[7]; + char[] vDateFieldSplitter = new char[] { '/' }; + char[] vDateZeroTrim = new char[] { '0' }; + + bool bFirst = true; + while(true) + { + bool bSubZero = false; + for(int iField = 0; iField < vFields.Length; ++iField) + { + vFields[iField] = ReadCsvField(cs); + + if((iField > 0) && (vFields[iField] == null)) + bSubZero = true; + } + if(vFields[0] == null) break; // Import successful + else if(bSubZero) throw new FormatException(); + + if(bFirst) + { + bFirst = false; // Check first line once only + + if((vFields[0] != "ServiceName") || (vFields[1] != "UserName") || + (vFields[2] != "Password") || (vFields[3] != "Memo") || + (vFields[4] != "Expire") || (vFields[5] != "StartDate") || + (vFields[6] != "DaysToLive")) + { + Debug.Assert(false); + throw new FormatException(); + } + else continue; + } + + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + pwStorage.MemoryProtection.ProtectTitle, vFields[0])); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + pwStorage.MemoryProtection.ProtectUserName, vFields[1])); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + pwStorage.MemoryProtection.ProtectPassword, vFields[2])); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + pwStorage.MemoryProtection.ProtectNotes, vFields[3])); + + pe.Expires = (vFields[4] == "true"); + + try + { + string[] vDateParts = vFields[5].Split(vDateFieldSplitter); + DateTime dt = (new DateTime( + int.Parse(vDateParts[2].TrimStart(vDateZeroTrim)), + int.Parse(vDateParts[0].TrimStart(vDateZeroTrim)), + int.Parse(vDateParts[1].TrimStart(vDateZeroTrim)), + 0, 0, 0, DateTimeKind.Local)).ToUniversalTime(); + pe.LastModificationTime = dt; + pe.LastAccessTime = dt; + pe.ExpiryTime = dt.AddDays(double.Parse(vFields[6])); + } + catch(Exception) { Debug.Assert(false); } + + pe.Strings.Set("Days To Live", new ProtectedString(false, + vFields[6])); + } + } + + private static string ReadCsvField(CharStream cs) + { + StringBuilder sbValue = new StringBuilder(); + char ch; + + while(true) + { + ch = cs.ReadChar(); + if(ch == char.MinValue) return null; + else if(ch == '\"') break; + } + + while(true) + { + ch = cs.ReadChar(); + + if(ch == char.MinValue) + return null; + else if(ch == '\r') + continue; + else if(ch == '\"') + { + char chSucc = cs.ReadChar(); + + if(chSucc == '\"') sbValue.Append('\"'); + else break; + } + else if(ch == '\n') + sbValue.Append(MessageService.NewLine); + else sbValue.Append(ch); + } + + return sbValue.ToString(); + } + } +} diff --git a/src/KeePass/DataExchange/Formats/WinFavorites10.cs b/src/KeePass/DataExchange/Formats/WinFavorites10.cs new file mode 100644 index 0000000..b217689 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/WinFavorites10.cs @@ -0,0 +1,331 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Text; +using System.Threading; + +using KeePass.Native; +using KeePass.Resources; +using KeePass.Util; +using KeePass.Util.Spr; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +using NativeLib = KeePassLib.Native.NativeLib; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class WinFavorites10 : FileFormatProvider + { + private readonly bool m_bInRoot; + + private const string IniTypeKey = "Type"; + private const string IniTypeValue = "WinFav-Export 1.0"; + + private static readonly string LnkDescSuffix = " [" + + PwDefs.ShortProductName + "]"; + + public override bool SupportsImport { get { return false; } } + public override bool SupportsExport { get { return true; } } + + public override string FormatName + { + get + { + return (KPRes.WindowsFavorites + " (" + (m_bInRoot ? + KPRes.RootDirectory : (KPRes.Folder + " '" + + GetFolderName(true, null, null) + "'")) + ")"); + } + } + public override string ApplicationGroup { get { return KPRes.General; } } + + public override bool RequiresFile { get { return false; } } + + public override Image SmallIcon + { + get { return KeePass.Properties.Resources.B16x16_Services; } + } + + public WinFavorites10(bool bInRoot) : base() + { + m_bInRoot = bInRoot; + } + + private static string GetFolderName(bool bForceRoot, PwExportInfo pwExportInfo, + PwGroup pg) + { + string strBaseName = UrlUtil.FilterFileName(string.IsNullOrEmpty( + Program.Config.Defaults.WinFavsBaseFolderName) ? PwDefs.ShortProductName : + Program.Config.Defaults.WinFavsBaseFolderName); + if(bForceRoot || (pwExportInfo == null) || (pg == null)) + return strBaseName; + + string strGroup = UrlUtil.FilterFileName(pg.Name); + string strRootName = strBaseName; + if(strGroup.Length > 0) strRootName += (" - " + strGroup); + + if(pwExportInfo.ContextDatabase != null) + { + if(pg == pwExportInfo.ContextDatabase.RootGroup) + strRootName = strBaseName; + } + + return strRootName; + } + + public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + PwGroup pg = pwExportInfo.DataGroup; + if(pg == null) { Debug.Assert(false); return true; } + + string strFavsRoot = Environment.GetFolderPath( + Environment.SpecialFolder.Favorites); + if(string.IsNullOrEmpty(strFavsRoot)) return false; + + uint uTotalGroups, uTotalEntries, uEntriesProcessed = 0; + pwExportInfo.DataGroup.GetCounts(true, out uTotalGroups, out uTotalEntries); + + if(!m_bInRoot) // In folder + { + string strRootName = GetFolderName(false, pwExportInfo, pg); + + string strFavsSub = UrlUtil.EnsureTerminatingSeparator( + strFavsRoot, false) + strRootName; + if(Directory.Exists(strFavsSub)) + { + Directory.Delete(strFavsSub, true); + WaitForDirCommit(strFavsSub, false); + } + + ExportGroup(pwExportInfo.DataGroup, strFavsSub, slLogger, + uTotalEntries, ref uEntriesProcessed, pwExportInfo); + } + else // In root + { + DeletePreviousExport(strFavsRoot, slLogger); + ExportGroup(pwExportInfo.DataGroup, strFavsRoot, slLogger, + uTotalEntries, ref uEntriesProcessed, pwExportInfo); + } + + Debug.Assert(uEntriesProcessed == uTotalEntries); + return true; + } + + private static void ExportGroup(PwGroup pg, string strDir, IStatusLogger slLogger, + uint uTotalEntries, ref uint uEntriesProcessed, PwExportInfo pxi) + { + foreach(PwEntry pe in pg.Entries) + { + ExportEntry(pe, strDir, pxi); + + ++uEntriesProcessed; + if(slLogger != null) + slLogger.SetProgress(((uEntriesProcessed * 50U) / + uTotalEntries) + 50U); + } + + foreach(PwGroup pgSub in pg.Groups) + { + string strGroup = UrlUtil.FilterFileName(pgSub.Name); + string strSub = (UrlUtil.EnsureTerminatingSeparator(strDir, false) + + (!string.IsNullOrEmpty(strGroup) ? strGroup : KPRes.Group)); + + ExportGroup(pgSub, strSub, slLogger, uTotalEntries, + ref uEntriesProcessed, pxi); + } + } + + private static void ExportEntry(PwEntry pe, string strDir, PwExportInfo pxi) + { + PwDatabase pd = ((pxi != null) ? pxi.ContextDatabase : null); + SprContext ctxUrl = new SprContext(pe, pd, SprCompileFlags.NonActive, false, true); + SprContext ctx = ctxUrl.WithoutContentTransformations(); + + KeyValuePair? okvpCmd = null; + string strUrl = SprEngine.Compile(pe.Strings.ReadSafe(PwDefs.UrlField), ctxUrl); + if(WinUtil.IsCommandLineUrl(strUrl)) + { + strUrl = WinUtil.GetCommandLineFromUrl(strUrl); + + if(!NativeLib.IsUnix()) // LNKs only supported on Windows + { + string strApp, strArgs; + StrUtil.SplitCommandLine(strUrl, out strApp, out strArgs); + + if(!string.IsNullOrEmpty(strApp)) + okvpCmd = new KeyValuePair(strApp, strArgs); + } + } + if(string.IsNullOrEmpty(strUrl)) return; + bool bLnk = okvpCmd.HasValue; + + string strTitleCmp = SprEngine.Compile(pe.Strings.ReadSafe(PwDefs.TitleField), ctx); + if(string.IsNullOrEmpty(strTitleCmp)) strTitleCmp = KPRes.Entry; + string strTitle = Program.Config.Defaults.WinFavsFileNamePrefix + strTitleCmp; + + string strSuffix = Program.Config.Defaults.WinFavsFileNameSuffix + + (bLnk ? ".lnk" : ".url"); + strSuffix = UrlUtil.FilterFileName(strSuffix); + + string strFileBase = (UrlUtil.EnsureTerminatingSeparator(strDir, + false) + UrlUtil.FilterFileName(strTitle)); + string strFile = strFileBase + strSuffix; + int iFind = 2; + while(File.Exists(strFile)) + { + strFile = strFileBase + " (" + iFind.ToString() + ")" + strSuffix; + ++iFind; + } + + if(!Directory.Exists(strDir)) + { + try { Directory.CreateDirectory(strDir); } + catch(Exception exDir) + { + throw new Exception(strDir + MessageService.NewParagraph + exDir.Message); + } + + WaitForDirCommit(strDir, true); + } + + try + { + if(bLnk) + { + int ccMaxDesc = NativeMethods.INFOTIPSIZE - 1 - LnkDescSuffix.Length; + string strDesc = StrUtil.CompactString3Dots(strUrl, ccMaxDesc) + + LnkDescSuffix; + + ShellLinkEx sl = new ShellLinkEx(okvpCmd.Value.Key, + okvpCmd.Value.Value, strDesc); + sl.Save(strFile); + } + else + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine(@"[InternetShortcut]"); + sb.AppendLine(@"URL=" + strUrl); // No additional line break + sb.AppendLine(@"[" + PwDefs.ShortProductName + @"]"); + sb.AppendLine(IniTypeKey + @"=" + IniTypeValue); + // Terminating line break is important + + File.WriteAllText(strFile, sb.ToString(), Encoding.Default); + } + } + catch(Exception exWrite) + { + throw new Exception(strFile + MessageService.NewParagraph + exWrite.Message); + } + } + + private static void WaitForDirCommit(string strDir, bool bRequireExists) + { + for(int i = 0; i < 20; ++i) + { + bool bExists = Directory.Exists(strDir); + if(bExists && bRequireExists) return; + if(!bExists && !bRequireExists) return; + + Thread.Sleep(50); + } + } + + private static void DeletePreviousExport(string strDir, IStatusLogger slLogger) + { + List vDirsToDelete = new List(); + + try + { + List lUrlFiles = UrlUtil.GetFilePaths(strDir, "*.url", + SearchOption.AllDirectories); + List lLnkFiles = UrlUtil.GetFilePaths(strDir, "*.lnk", + SearchOption.AllDirectories); + + List lFiles = new List(); + lFiles.AddRange(lUrlFiles); + lFiles.AddRange(lLnkFiles); + + for(int iFile = 0; iFile < lFiles.Count; ++iFile) + { + string strFile = lFiles[iFile]; + try + { + bool bDelete = false; + + if(strFile.EndsWith(".url", StrUtil.CaseIgnoreCmp)) + { + IniFile ini = IniFile.Read(strFile, Encoding.Default); + string strType = ini.Get(PwDefs.ShortProductName, IniTypeKey); + bDelete = ((strType != null) && (strType == IniTypeValue)); + } + else if(strFile.EndsWith(".lnk", StrUtil.CaseIgnoreCmp)) + { + ShellLinkEx sl = ShellLinkEx.Load(strFile); + if(sl != null) + bDelete = ((sl.Description != null) && + sl.Description.EndsWith(LnkDescSuffix)); + } + else { Debug.Assert(false); } + + if(bDelete) + { + File.Delete(strFile); + + string strCont = UrlUtil.GetFileDirectory(strFile, false, true); + if(vDirsToDelete.IndexOf(strCont) < 0) + vDirsToDelete.Add(strCont); + } + } + catch(Exception) { Debug.Assert(false); } + + if(slLogger != null) + slLogger.SetProgress(((uint)iFile * 50U) / (uint)lFiles.Count); + } + + bool bDeleted = true; + while(bDeleted) + { + bDeleted = false; + + for(int i = (vDirsToDelete.Count - 1); i >= 0; --i) + { + try + { + Directory.Delete(vDirsToDelete[i], false); + WaitForDirCommit(vDirsToDelete[i], false); + + vDirsToDelete.RemoveAt(i); + bDeleted = true; + } + catch(Exception) { } // E.g. not empty + } + } + } + catch(Exception) { Debug.Assert(false); } + } + } +} diff --git a/src/KeePass/DataExchange/Formats/XslTransform2x.cs b/src/KeePass/DataExchange/Formats/XslTransform2x.cs new file mode 100644 index 0000000..4485fc0 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/XslTransform2x.cs @@ -0,0 +1,136 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Text; +using System.Windows.Forms; +using System.Xml; +using System.Xml.Xsl; + +using KeePass.App; +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + internal sealed class XslTransform2x : FileFormatProvider + { + private const string ParamXslFile = "XslFile"; + + public override bool SupportsImport { get { return false; } } + public override bool SupportsExport { get { return true; } } + + public override string FormatName { get { return KPRes.XslExporter; } } + public override string ApplicationGroup { get { return KPRes.General; } } + + public override Image SmallIcon + { + get { return FileIcons.GetImageForExtension("xsl", null); } + } + + public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger) + { + string strXslFile; + pwExportInfo.Parameters.TryGetValue(ParamXslFile, out strXslFile); + + if(string.IsNullOrEmpty(strXslFile)) + { + strXslFile = UIGetXslFile(); + + if(string.IsNullOrEmpty(strXslFile)) + return false; + } + + return ExportEx(pwExportInfo, sOutput, slLogger, strXslFile); + } + + private static string UIGetXslFile() + { + string strFilter = UIUtil.CreateFileTypeFilter("xsl", KPRes.XslFileType, true); + OpenFileDialogEx dlgXsl = UIUtil.CreateOpenFileDialog(KPRes.XslSelectFile, + strFilter, 1, "xsl", false, AppDefs.FileDialogContext.Xsl); + + if(dlgXsl.ShowDialog() != DialogResult.OK) return null; + + return dlgXsl.FileName; + } + + private bool ExportEx(PwExportInfo pwExportInfo, Stream sOutput, + IStatusLogger slLogger, string strXslFile) + { + XslCompiledTransform xsl = new XslCompiledTransform(); + try { xsl.Load(strXslFile); } + catch(Exception exXsl) + { + throw new NotSupportedException(strXslFile + MessageService.NewParagraph + + KPRes.NoXslFile + MessageService.NewParagraph + exXsl.Message); + } + + byte[] pbData; + using(MemoryStream ms = new MemoryStream()) + { + PwDatabase pd = (pwExportInfo.ContextDatabase ?? new PwDatabase()); + KdbxFile f = new KdbxFile(pd); + f.Save(ms, pwExportInfo.DataGroup, KdbxFormat.PlainXml, slLogger); + + pbData = ms.ToArray(); + } + if(pbData == null) throw new OutOfMemoryException(); + + XmlWriterSettings xws = xsl.OutputSettings; + if(xws == null) + { + xws = new XmlWriterSettings(); + + xws.CheckCharacters = false; + xws.ConformanceLevel = ConformanceLevel.Auto; + xws.Encoding = StrUtil.Utf8; + // xws.Indent = false; + xws.IndentChars = "\t"; + xws.NewLineChars = MessageService.NewLine; + xws.NewLineHandling = NewLineHandling.None; + xws.OmitXmlDeclaration = true; + } + + using(MemoryStream msIn = new MemoryStream(pbData, false)) + { + using(XmlReader xrIn = XmlUtilEx.CreateXmlReader(msIn)) + { + using(XmlWriter xwOut = XmlWriter.Create(sOutput, xws)) + { + xsl.Transform(xrIn, xwOut); + } + } + } + + MemUtil.ZeroByteArray(pbData); + return true; + } + } +} diff --git a/src/KeePass/DataExchange/Formats/ZdnPwProTxt314.cs b/src/KeePass/DataExchange/Formats/ZdnPwProTxt314.cs new file mode 100644 index 0000000..25c01e5 --- /dev/null +++ b/src/KeePass/DataExchange/Formats/ZdnPwProTxt314.cs @@ -0,0 +1,172 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange.Formats +{ + // 3.1.4 + internal sealed class ZdnPwProTxt314 : FileFormatProvider + { + public override bool SupportsImport { get { return true; } } + public override bool SupportsExport { get { return false; } } + + public override string FormatName { get { return "ZDNet's Password Pro TXT"; } } + public override string DefaultExtension { get { return "txt"; } } + public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } + + public override bool ImportAppendsToRootGroupOnly { get { return true; } } + + private const string StrFieldUser = "User Name: "; + private const string StrFieldPw = "Password: "; + private const string StrFieldUrl = "Shortcut: "; + private const string StrFieldExpires = "Expires: "; + private const string StrFieldType = "Type: "; + private const string StrFieldNotes = "Comments: "; + + public override void Import(PwDatabase pwStorage, Stream sInput, + IStatusLogger slLogger) + { + StreamReader sr = new StreamReader(sInput, Encoding.Default); + string strData = sr.ReadToEnd(); + sr.Close(); + + strData = strData.Replace("\r", string.Empty); + string[] vLines = strData.Split(new char[] { '\n' }); + + if(vLines.Length >= 1) + { + Debug.Assert(vLines[0].StartsWith("Contents of: ")); + vLines[0] = string.Empty; // Trigger 'new entry' below + } + + Dictionary dItems = new Dictionary(); + bool bInNotes = false; + DateTime? dtExpire = null; + + for(int i = 0; i < vLines.Length; ++i) + { + string strLine = vLines[i]; + + if((i + 2) < vLines.Length) + { + string strSep = new string('-', vLines[i + 1].Length); + + if((strLine.Length == 0) && (vLines[i + 2] == strSep) && + (strSep.Length > 0)) + { + AddEntry(pwStorage.RootGroup, dItems, ref bInNotes, ref dtExpire); + dItems.Clear(); + + dItems[PwDefs.TitleField] = vLines[i + 1]; + + i += 2; + continue; + } + } + + if(bInNotes) + { + if(dItems.ContainsKey(PwDefs.NotesField)) + dItems[PwDefs.NotesField] += MessageService.NewLine + strLine; + else dItems[PwDefs.NotesField] = strLine; + } + else if(strLine.StartsWith(StrFieldUser)) + AddField(dItems, PwDefs.UserNameField, strLine.Substring( + StrFieldUser.Length)); + else if(strLine.StartsWith(StrFieldPw)) + AddField(dItems, PwDefs.PasswordField, strLine.Substring( + StrFieldPw.Length)); + else if(strLine.StartsWith(StrFieldUrl)) + AddField(dItems, PwDefs.UrlField, strLine.Substring( + StrFieldUrl.Length)); + else if(strLine.StartsWith(StrFieldType)) + AddField(dItems, "Type", strLine.Substring(StrFieldType.Length)); + else if(strLine.StartsWith(StrFieldExpires)) + { + string strExp = strLine.Substring(StrFieldExpires.Length); + + DateTime dtExp; + if(DateTime.TryParse(strExp, out dtExp)) + dtExpire = TimeUtil.ToUtc(dtExp, false); + else { Debug.Assert(false); } + } + else if(strLine.StartsWith(StrFieldNotes)) + { + AddField(dItems, PwDefs.NotesField, strLine.Substring( + StrFieldNotes.Length)); + bInNotes = true; + } + else { Debug.Assert(false); } + } + + AddEntry(pwStorage.RootGroup, dItems, ref bInNotes, ref dtExpire); + Debug.Assert(!dtExpire.HasValue); + } + + private static void AddField(Dictionary dItems, + string strKey, string strValue) + { + if(!dItems.ContainsKey(strKey)) + { + dItems[strKey] = strValue; + return; + } + + string strPreValue = dItems[strKey]; + if((strPreValue.Length > 0) && (strValue.Length > 0)) + strPreValue += ", "; + + dItems[strKey] = strPreValue + strValue; + } + + private static void AddEntry(PwGroup pg, Dictionary dItems, + ref bool bInNotes, ref DateTime? dtExpire) + { + if(dItems.Count > 0) + { + PwEntry pe = new PwEntry(true, true); + pg.AddEntry(pe, true); + + foreach(KeyValuePair kvp in dItems) + pe.Strings.Set(kvp.Key, new ProtectedString(false, kvp.Value)); + + if(dtExpire.HasValue) + { + pe.Expires = true; + pe.ExpiryTime = dtExpire.Value; + } + } + + bInNotes = false; + dtExpire = null; + } + } +} diff --git a/src/KeePass/DataExchange/GxiImporter.cs b/src/KeePass/DataExchange/GxiImporter.cs new file mode 100644 index 0000000..b17553a --- /dev/null +++ b/src/KeePass/DataExchange/GxiImporter.cs @@ -0,0 +1,383 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.XPath; + +using KeePass.Resources; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Interfaces; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + public static class GxiImporter + { + private sealed class GxiContext // Immutable + { + private PwDatabase m_pd; + public PwDatabase Database { get { return m_pd; } } + + private PwGroup m_pg; + public PwGroup Group { get { return m_pg; } } + + private PwEntry m_pe; + public PwEntry Entry { get { return m_pe; } } + + private Dictionary m_dStringKeyRepl; + public Dictionary StringKeyRepl { get { return m_dStringKeyRepl; } } + private Dictionary m_dStringValueRepl; + public Dictionary StringValueRepl { get { return m_dStringValueRepl; } } + private Dictionary m_dStringKeyRepl2; + public Dictionary StringKeyRepl2 { get { return m_dStringKeyRepl2; } } + private Dictionary m_dStringValueRepl2; + public Dictionary StringValueRepl2 { get { return m_dStringValueRepl2; } } + private Dictionary m_dBinaryKeyRepl; + public Dictionary BinaryKeyRepl { get { return m_dBinaryKeyRepl; } } + + public GxiContext(GxiProfile p, PwDatabase pd, PwGroup pg, PwEntry pe) + { + m_pd = pd; + m_pg = pg; + m_pe = pe; + + m_dStringKeyRepl = GxiImporter.ParseRepl(p.StringKeyRepl); + m_dStringValueRepl = GxiImporter.ParseRepl(p.StringValueRepl); + m_dStringKeyRepl2 = GxiImporter.ParseRepl(p.StringKeyRepl2); + m_dStringValueRepl2 = GxiImporter.ParseRepl(p.StringValueRepl2); + m_dBinaryKeyRepl = GxiImporter.ParseRepl(p.BinaryKeyRepl); + } + + public GxiContext ModifyWith(PwGroup pg) + { + GxiContext c = (GxiContext)MemberwiseClone(); + Debug.Assert(object.ReferenceEquals(c.m_dStringKeyRepl, m_dStringKeyRepl)); + + c.m_pg = pg; + return c; + } + + public GxiContext ModifyWith(PwEntry pe) + { + GxiContext c = (GxiContext)MemberwiseClone(); + Debug.Assert(object.ReferenceEquals(c.m_dStringKeyRepl, m_dStringKeyRepl)); + + c.m_pe = pe; + return c; + } + } + + private delegate void ImportObjectDelegate(XPathNavigator xpRoot, + GxiProfile p, GxiContext c); + + public static void Import(PwGroup pgStorage, Stream s, GxiProfile p, + PwDatabase pdContext, IStatusLogger sl) + { + if(pgStorage == null) throw new ArgumentNullException("pgStorage"); + if(s == null) throw new ArgumentNullException("s"); + if(p == null) throw new ArgumentNullException("p"); + if(pdContext == null) throw new ArgumentNullException("pdContext"); + // sl may be null + + // Import into virtual group first, in order to realize + // an all-or-nothing import + PwGroup pgVirt = new PwGroup(true, true); + + try { ImportPriv(pgVirt, s, p, pdContext, sl); } + finally { s.Close(); } + + foreach(PwGroup pg in pgVirt.Groups) + pgStorage.AddGroup(pg, true); + foreach(PwEntry pe in pgVirt.Entries) + pgStorage.AddEntry(pe, true); + } + + private static void ImportPriv(PwGroup pgStorage, Stream s, GxiProfile p, + PwDatabase pdContext, IStatusLogger sl) + { + StrEncodingInfo sei = StrUtil.GetEncoding(p.Encoding); + StreamReader srRaw; + if((sei != null) && (sei.Encoding != null)) + srRaw = new StreamReader(s, sei.Encoding, true); + else srRaw = new StreamReader(s, true); + string strDoc = srRaw.ReadToEnd(); + srRaw.Close(); + + strDoc = Preprocess(strDoc, p); + + using(StringReader srDoc = new StringReader(strDoc)) + { + using(XmlReader xr = XmlReader.Create(srDoc, + XmlUtilEx.CreateXmlReaderSettings())) + { + XPathDocument xd = new XPathDocument(xr); + + GxiContext c = new GxiContext(p, pdContext, pgStorage, null); + + XPathNavigator xpDoc = xd.CreateNavigator(); + ImportObject(xpDoc, p, p.RootXPath, "/*", GxiImporter.ImportRoot, c); + } + } + } + + private static string Preprocess(string strDoc, GxiProfile p) + { + string str = strDoc; + if(str == null) { Debug.Assert(false); return string.Empty; } + + if(p.RemoveInvalidChars) str = StrUtil.SafeXmlString(str); + if(p.DecodeHtmlEntities) str = XmlUtil.DecodeHtmlEntities(str); + + return str; + } + + private static XPathNodeIterator QueryNodes(XPathNavigator xpBase, + string strXPath, string strAltXPath) + { + if(xpBase == null) { Debug.Assert(false); return null; } + + string strX = (string.IsNullOrEmpty(strXPath) ? strAltXPath : strXPath); + if(string.IsNullOrEmpty(strX)) return null; + + return xpBase.Select(strX); + } + + private static string QueryValue(XPathNavigator xpBase, string strXPath, + bool bQueryName) + { + if(xpBase == null) { Debug.Assert(false); return null; } + if(string.IsNullOrEmpty(strXPath)) return null; + + XPathNavigator xp = xpBase.SelectSingleNode(strXPath); + if(xp == null) return null; + + return (bQueryName ? xp.Name : xp.Value); + } + + private static string QueryValueSafe(XPathNavigator xpBase, string strXPath) + { + return (QueryValue(xpBase, strXPath, false) ?? string.Empty); + } + + // private static string QueryValueSafe(XPathNavigator xpBase, string strXPath, + // bool bQueryName) + // { + // return (QueryValue(xpBase, strXPath, bQueryName) ?? string.Empty); + // } + + private static void ImportObject(XPathNavigator xpBase, GxiProfile p, + string strXPath, string strAltXPath, ImportObjectDelegate f, + GxiContext c) + { + if(f == null) { Debug.Assert(false); return; } + + XPathNodeIterator xi = QueryNodes(xpBase, strXPath, strAltXPath); + if(xi == null) return; // No assert + foreach(XPathNavigator xp in xi) { f(xp, p, c); } + } + + private static void ImportRoot(XPathNavigator xpBase, GxiProfile p, + GxiContext c) + { + ImportObject(xpBase, p, p.GroupXPath, null, GxiImporter.ImportGroup, c); + + if(p.EntriesInRoot) + ImportObject(xpBase, p, p.EntryXPath, null, GxiImporter.ImportEntry, c); + } + + private static void ImportGroup(XPathNavigator xpBase, GxiProfile p, + GxiContext c) + { + PwGroup pg = new PwGroup(true, true); + c.Group.AddGroup(pg, true); + + GxiContext cSub = c.ModifyWith(pg); + + pg.Name = QueryValueSafe(xpBase, p.GroupNameXPath); + if(pg.Name.Length == 0) pg.Name = KPRes.Group; + + if(p.GroupsInGroup) + ImportObject(xpBase, p, p.GroupXPath, null, GxiImporter.ImportGroup, cSub); + if(p.EntriesInGroup) + ImportObject(xpBase, p, p.EntryXPath, null, GxiImporter.ImportEntry, cSub); + } + + private static void ImportEntry(XPathNavigator xpBase, GxiProfile p, + GxiContext c) + { + PwEntry pe = new PwEntry(true, true); + + PwGroup pg = c.Group; // Not the database root group + string strGroupPath = QueryValueSafe(xpBase, p.EntryGroupXPath); + string strGroupPath2 = QueryValueSafe(xpBase, p.EntryGroupXPath2); + if((strGroupPath.Length > 0) && (strGroupPath2.Length > 0)) + { + Debug.Assert(p.EntryGroupSep.Length > 0); + strGroupPath = strGroupPath + p.EntryGroupSep + strGroupPath2; + } + if(strGroupPath.Length > 0) + { + if(p.EntryGroupSep.Length == 0) + pg = pg.FindCreateGroup(strGroupPath, true); + else + pg = pg.FindCreateSubTree(strGroupPath, new string[1]{ + p.EntryGroupSep }, true); + } + pg.AddEntry(pe, true); + + GxiContext cSub = c.ModifyWith(pe); + + ImportObject(xpBase, p, p.StringKvpXPath, null, + GxiImporter.ImportStringKvp, cSub); + ImportObject(xpBase, p, p.StringKvpXPath2, null, + GxiImporter.ImportStringKvp2, cSub); + ImportObject(xpBase, p, p.BinaryKvpXPath, null, + GxiImporter.ImportBinaryKvp, cSub); + } + + private static void ImportStringKvp(XPathNavigator xpBase, GxiProfile p, + GxiContext c) + { + ImportStringKvpEx(xpBase, p, c, true); + } + + private static void ImportStringKvp2(XPathNavigator xpBase, GxiProfile p, + GxiContext c) + { + ImportStringKvpEx(xpBase, p, c, false); + } + + private static void ImportStringKvpEx(XPathNavigator xpBase, GxiProfile p, + GxiContext c, bool bFirst) + { + string strKey = QueryValue(xpBase, (bFirst ? p.StringKeyXPath : + p.StringKeyXPath2), (bFirst ? p.StringKeyUseName : + p.StringKeyUseName2)); + if(string.IsNullOrEmpty(strKey)) return; + + strKey = ApplyRepl(strKey, (bFirst ? c.StringKeyRepl : c.StringKeyRepl2)); + if(strKey.Length == 0) return; + + if(p.StringKeyToStd) + { + string strMapped = ImportUtil.MapNameToStandardField(strKey, + p.StringKeyToStdFuzzy); + if(!string.IsNullOrEmpty(strMapped)) strKey = strMapped; + } + + string strValue = QueryValueSafe(xpBase, (bFirst ? p.StringValueXPath : + p.StringValueXPath2)); + strValue = ApplyRepl(strValue, (bFirst ? c.StringValueRepl : + c.StringValueRepl2)); + + ImportUtil.AppendToField(c.Entry, strKey, strValue, c.Database); + } + + private static void ImportBinaryKvp(XPathNavigator xpBase, GxiProfile p, + GxiContext c) + { + string strKey = QueryValue(xpBase, p.BinaryKeyXPath, p.BinaryKeyUseName); + if(string.IsNullOrEmpty(strKey)) return; + + strKey = ApplyRepl(strKey, c.BinaryKeyRepl); + if(strKey.Length == 0) return; + + string strValue = QueryValueSafe(xpBase, p.BinaryValueXPath); + + byte[] pbValue = null; + if(p.BinaryValueEncoding == GxiBinaryEncoding.Base64) + pbValue = Convert.FromBase64String(strValue); + else if(p.BinaryValueEncoding == GxiBinaryEncoding.Hex) + pbValue = MemUtil.HexStringToByteArray(strValue); + else { Debug.Assert(false); } + + if(pbValue == null) return; + + c.Entry.Binaries.Set(strKey, new ProtectedBinary(false, pbValue)); + } + + internal static Dictionary ParseRepl(string str) + { + Dictionary d = new Dictionary(); + if(str == null) { Debug.Assert(false); return d; } + + CharStream cs = new CharStream(str + ",,"); + StringBuilder sb = new StringBuilder(); + string strKey = string.Empty; + bool bValue = false; + + while(true) + { + char ch = cs.ReadChar(); + if(ch == char.MinValue) break; + + if(ch == ',') + { + if(!bValue) + { + strKey = sb.ToString(); + sb.Remove(0, sb.Length); + } + + if(strKey.Length > 0) d[strKey] = sb.ToString(); + + sb.Remove(0, sb.Length); + bValue = false; + } + else if(ch == '>') + { + strKey = sb.ToString(); + + sb.Remove(0, sb.Length); + bValue = true; + } + else if(ch == '\\') + { + char chSub = cs.ReadChar(); + + if(chSub == 'n') sb.Append('\n'); + else if(chSub == 'r') sb.Append('\r'); + else if(chSub == 't') sb.Append('\t'); + else sb.Append(chSub); + } + else sb.Append(ch); + } + + return d; + } + + private static string ApplyRepl(string str, Dictionary dRepl) + { + if(str == null) { Debug.Assert(false); return string.Empty; } + if(dRepl == null) { Debug.Assert(false); return str; } + + string strOut; + if(dRepl.TryGetValue(str, out strOut)) return strOut; + return str; + } + } +} diff --git a/src/KeePass/DataExchange/GxiProfile.cs b/src/KeePass/DataExchange/GxiProfile.cs new file mode 100644 index 0000000..ffd020f --- /dev/null +++ b/src/KeePass/DataExchange/GxiProfile.cs @@ -0,0 +1,387 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; +using System.ComponentModel; +using System.Diagnostics; + +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + public enum GxiBinaryEncoding + { + Base64 = 0, + Hex, + + Count // Virtual + } + + public sealed class GxiProfile + { + private StrEncodingType m_tEnc = StrEncodingType.Unknown; + public StrEncodingType Encoding + { + get { return m_tEnc; } + set { m_tEnc = value; } + } + + private bool m_bRemoveInvChars = true; + [DefaultValue(true)] + public bool RemoveInvalidChars + { + get { return m_bRemoveInvChars; } + set { m_bRemoveInvChars = value; } + } + + private bool m_bDecodeHtmlEnt = true; + [DefaultValue(true)] + public bool DecodeHtmlEntities + { + get { return m_bDecodeHtmlEnt; } + set { m_bDecodeHtmlEnt = value; } + } + + private string m_strRootXPath = string.Empty; + [DefaultValue("")] + public string RootXPath + { + get { return m_strRootXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strRootXPath = value; + } + } + + private string m_strGroupXPath = string.Empty; + [DefaultValue("")] + public string GroupXPath + { + get { return m_strGroupXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strGroupXPath = value; + } + } + + private string m_strGroupNameXPath = string.Empty; + [DefaultValue("")] + public string GroupNameXPath + { + get { return m_strGroupNameXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strGroupNameXPath = value; + } + } + + private string m_strEntryXPath = string.Empty; + [DefaultValue("")] + public string EntryXPath + { + get { return m_strEntryXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strEntryXPath = value; + } + } + + private string m_strStringKvpXPath = string.Empty; + [DefaultValue("")] + public string StringKvpXPath + { + get { return m_strStringKvpXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringKvpXPath = value; + } + } + + private string m_strStringKeyXPath = string.Empty; + [DefaultValue("")] + public string StringKeyXPath + { + get { return m_strStringKeyXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringKeyXPath = value; + } + } + + private bool m_bStringKeyUseName = false; + [DefaultValue(false)] + public bool StringKeyUseName + { + get { return m_bStringKeyUseName; } + set { m_bStringKeyUseName = value; } + } + + private string m_strStringKeyRepl = string.Empty; + [DefaultValue("")] + public string StringKeyRepl + { + get { return m_strStringKeyRepl; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringKeyRepl = value; + } + } + + private string m_strStringValueXPath = string.Empty; + [DefaultValue("")] + public string StringValueXPath + { + get { return m_strStringValueXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringValueXPath = value; + } + } + + private string m_strStringValueRepl = string.Empty; + [DefaultValue("")] + public string StringValueRepl + { + get { return m_strStringValueRepl; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringValueRepl = value; + } + } + + private string m_strStringKvpXPath2 = string.Empty; + [DefaultValue("")] + public string StringKvpXPath2 + { + get { return m_strStringKvpXPath2; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringKvpXPath2 = value; + } + } + + private string m_strStringKeyXPath2 = string.Empty; + [DefaultValue("")] + public string StringKeyXPath2 + { + get { return m_strStringKeyXPath2; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringKeyXPath2 = value; + } + } + + private bool m_bStringKeyUseName2 = false; + [DefaultValue(false)] + public bool StringKeyUseName2 + { + get { return m_bStringKeyUseName2; } + set { m_bStringKeyUseName2 = value; } + } + + private string m_strStringKeyRepl2 = string.Empty; + [DefaultValue("")] + public string StringKeyRepl2 + { + get { return m_strStringKeyRepl2; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringKeyRepl2 = value; + } + } + + private string m_strStringValueXPath2 = string.Empty; + [DefaultValue("")] + public string StringValueXPath2 + { + get { return m_strStringValueXPath2; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringValueXPath2 = value; + } + } + + private string m_strStringValueRepl2 = string.Empty; + [DefaultValue("")] + public string StringValueRepl2 + { + get { return m_strStringValueRepl2; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strStringValueRepl2 = value; + } + } + + private string m_strBinaryKvpXPath = string.Empty; + [DefaultValue("")] + public string BinaryKvpXPath + { + get { return m_strBinaryKvpXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strBinaryKvpXPath = value; + } + } + + private string m_strBinaryKeyXPath = string.Empty; + [DefaultValue("")] + public string BinaryKeyXPath + { + get { return m_strBinaryKeyXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strBinaryKeyXPath = value; + } + } + + private bool m_bBinaryKeyUseName = false; + [DefaultValue(false)] + public bool BinaryKeyUseName + { + get { return m_bBinaryKeyUseName; } + set { m_bBinaryKeyUseName = value; } + } + + private string m_strBinaryKeyRepl = string.Empty; + [DefaultValue("")] + public string BinaryKeyRepl + { + get { return m_strBinaryKeyRepl; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strBinaryKeyRepl = value; + } + } + + private string m_strBinaryValueXPath = string.Empty; + [DefaultValue("")] + public string BinaryValueXPath + { + get { return m_strBinaryValueXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strBinaryValueXPath = value; + } + } + + private GxiBinaryEncoding m_beBinValue = GxiBinaryEncoding.Base64; + public GxiBinaryEncoding BinaryValueEncoding + { + get { return m_beBinValue; } + set { m_beBinValue = value; } + } + + private string m_strEntryGroupXPath = string.Empty; + [DefaultValue("")] + public string EntryGroupXPath + { + get { return m_strEntryGroupXPath; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strEntryGroupXPath = value; + } + } + + private string m_strEntryGroupXPath2 = string.Empty; + [DefaultValue("")] + public string EntryGroupXPath2 + { + get { return m_strEntryGroupXPath2; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strEntryGroupXPath2 = value; + } + } + + private string m_strEntryGroupSep = string.Empty; + [DefaultValue("")] + public string EntryGroupSep + { + get { return m_strEntryGroupSep; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strEntryGroupSep = value; + } + } + + private bool m_bEntriesInRoot = true; + [DefaultValue(true)] + public bool EntriesInRoot + { + get { return m_bEntriesInRoot; } + set { m_bEntriesInRoot = value; } + } + + private bool m_bEntriesInGroup = true; + [DefaultValue(true)] + public bool EntriesInGroup + { + get { return m_bEntriesInGroup; } + set { m_bEntriesInGroup = value; } + } + + private bool m_bGroupsInGroup = true; + [DefaultValue(true)] + public bool GroupsInGroup + { + get { return m_bGroupsInGroup; } + set { m_bGroupsInGroup = value; } + } + + private bool m_bStringKeyToStd = true; + [DefaultValue(true)] + public bool StringKeyToStd + { + get { return m_bStringKeyToStd; } + set { m_bStringKeyToStd = value; } + } + + private bool m_bStringKeyToStdFuzzy = false; + [DefaultValue(false)] + public bool StringKeyToStdFuzzy + { + get { return m_bStringKeyToStdFuzzy; } + set { m_bStringKeyToStdFuzzy = value; } + } + } +} diff --git a/src/KeePass/DataExchange/ImportUtil.cs b/src/KeePass/DataExchange/ImportUtil.cs new file mode 100644 index 0000000..dbed424 --- /dev/null +++ b/src/KeePass/DataExchange/ImportUtil.cs @@ -0,0 +1,732 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +using KeePass.App; +using KeePass.DataExchange.Formats; +using KeePass.Ecas; +using KeePass.Forms; +using KeePass.Native; +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Collections; +using KeePassLib.Interfaces; +using KeePassLib.Keys; +using KeePassLib.Resources; +using KeePassLib.Security; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + public static class ImportUtil + { + public static bool? Import(PwDatabase pwStorage, out bool bAppendedToRootOnly, + Form fParent) + { + bAppendedToRootOnly = false; + + if(pwStorage == null) throw new ArgumentNullException("pwStorage"); + if(!pwStorage.IsOpen) { Debug.Assert(false); return null; } + if(!AppPolicy.Try(AppPolicyId.Import)) return null; + + ExchangeDataForm dlg = new ExchangeDataForm(); + dlg.InitEx(false, pwStorage, pwStorage.RootGroup); + + if(UIUtil.ShowDialogNotValue(dlg, DialogResult.OK)) return null; + + FileFormatProvider ffp = dlg.ResultFormat; + if(ffp == null) + { + Debug.Assert(false); + MessageService.ShowWarning(KPRes.ImportFailed); + UIUtil.DestroyForm(dlg); + return null; + } + + bAppendedToRootOnly = ffp.ImportAppendsToRootGroupOnly; + + List lConnections = new List(); + foreach(string strFile in dlg.ResultFiles) + lConnections.Add(IOConnectionInfo.FromPath(strFile)); + + UIUtil.DestroyForm(dlg); + return Import(pwStorage, ffp, lConnections.ToArray(), false, null, + false, fParent); + } + + public static bool? Import(PwDatabase pwDatabase, FileFormatProvider fmtImp, + IOConnectionInfo[] vConnections, bool bSynchronize, IUIOperations uiOps, + bool bForceSave, Form fParent) + { + if(pwDatabase == null) throw new ArgumentNullException("pwDatabase"); + if(!pwDatabase.IsOpen) { Debug.Assert(false); return null; } + if(fmtImp == null) throw new ArgumentNullException("fmtImp"); + if(vConnections == null) throw new ArgumentNullException("vConnections"); + + if(!AppPolicy.Try(AppPolicyId.Import)) return null; + if(!fmtImp.TryBeginImport()) return null; + + MainForm mf = Program.MainForm; // Null for KPScript + bool bUseTempDb = (fmtImp.SupportsUuids || fmtImp.RequiresKey); + bool bAllSuccess = true; + + IStatusLogger dlgStatus; + if(Program.Config.UI.ShowImportStatusDialog || + ((mf != null) && !mf.HasFormLoaded)) + dlgStatus = new OnDemandStatusDialog(false, fParent); + else dlgStatus = new UIBlockerStatusLogger(fParent); + + dlgStatus.StartLogging(PwDefs.ShortProductName + " - " + (bSynchronize ? + KPRes.Synchronizing : KPRes.ImportingStatusMsg), false); + dlgStatus.SetText(bSynchronize ? KPRes.Synchronizing : + KPRes.ImportingStatusMsg, LogStatusType.Info); + + if(vConnections.Length == 0) + { + try + { + pwDatabase.Modified = true; + fmtImp.Import(pwDatabase, null, dlgStatus); + } + catch(Exception ex) + { + MessageService.ShowWarning(ex); + bAllSuccess = false; + } + + dlgStatus.EndLogging(); + return bAllSuccess; + } + + foreach(IOConnectionInfo iocIn in vConnections) + { + Stream s = null; + try { s = IOConnection.OpenRead(iocIn); } + catch(Exception ex) + { + MessageService.ShowWarning(iocIn.GetDisplayName(), ex); + bAllSuccess = false; + continue; + } + if(s == null) { Debug.Assert(false); bAllSuccess = false; continue; } + + PwDatabase pwImp; + if(bUseTempDb) + { + pwImp = new PwDatabase(); + pwImp.New(new IOConnectionInfo(), pwDatabase.MasterKey); + pwImp.MemoryProtection = pwDatabase.MemoryProtection.CloneDeep(); + } + else pwImp = pwDatabase; + + if(fmtImp.RequiresKey && !bSynchronize) + { + KeyPromptFormResult r; + DialogResult dr = KeyPromptForm.ShowDialog(iocIn, false, null, out r); + if((dr != DialogResult.OK) || (r == null)) + { + s.Close(); + bAllSuccess = false; + continue; + } + + pwImp.MasterKey = r.CompositeKey; + } + else if(bSynchronize) pwImp.MasterKey = pwDatabase.MasterKey; + + dlgStatus.SetText((bSynchronize ? KPRes.Synchronizing : + KPRes.ImportingStatusMsg) + " (" + iocIn.GetDisplayName() + + ")", LogStatusType.Info); + + try + { + pwImp.Modified = true; + fmtImp.Import(pwImp, s, dlgStatus); + } + catch(Exception ex) + { + string strMsg = ex.Message; + if(bSynchronize && (ex is InvalidCompositeKeyException)) + strMsg = KLRes.InvalidCompositeKey + MessageService.NewParagraph + + KPRes.SynchronizingHint; + MessageService.ShowWarning(iocIn.GetDisplayName(), + KPRes.FileImportFailed, strMsg); + + bAllSuccess = false; + continue; + } + finally { s.Close(); } + + if(bUseTempDb) + { + PwMergeMethod mm; + if(!fmtImp.SupportsUuids) mm = PwMergeMethod.CreateNewUuids; + else if(bSynchronize) mm = PwMergeMethod.Synchronize; + else + { + ImportMethodForm imf = new ImportMethodForm(); + if(UIUtil.ShowDialogNotValue(imf, DialogResult.OK)) + { + bAllSuccess = false; + continue; + } + mm = imf.MergeMethod; + UIUtil.DestroyForm(imf); + } + + try + { + pwDatabase.Modified = true; + pwDatabase.MergeIn(pwImp, mm, dlgStatus); + } + catch(Exception ex) + { + MessageService.ShowWarning(iocIn.GetDisplayName(), + KPRes.ImportFailed, ex); + bAllSuccess = false; + continue; + } + } + } + + if(bSynchronize && bAllSuccess) + { + if(uiOps == null) { Debug.Assert(false); throw new ArgumentNullException("uiOps"); } + + dlgStatus.SetText(KPRes.Synchronizing + " (" + + KPRes.SavingDatabase + ")", LogStatusType.Info); + + if(mf != null) + { + try { mf.DocumentManager.ActiveDatabase = pwDatabase; } + catch(Exception) { Debug.Assert(false); } + } + + if(uiOps.UIFileSave(bForceSave)) + { + foreach(IOConnectionInfo ioc in vConnections) + { + try + { + // dlgStatus.SetText(KPRes.Synchronizing + " (" + + // KPRes.SavingDatabase + " " + ioc.GetDisplayName() + + // ")", LogStatusType.Info); + + string strSource = pwDatabase.IOConnectionInfo.Path; + if(!string.Equals(ioc.Path, strSource, StrUtil.CaseIgnoreCmp)) + { + bool bSaveAs = true; + + if(pwDatabase.IOConnectionInfo.IsLocalFile() && + ioc.IsLocalFile()) + { + // Do not try to copy an encrypted file; + // https://sourceforge.net/p/keepass/discussion/329220/thread/9c9eb989/ + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363851.aspx + if((long)(File.GetAttributes(strSource) & + FileAttributes.Encrypted) == 0) + { + File.Copy(strSource, ioc.Path, true); + bSaveAs = false; + } + } + + if(bSaveAs) pwDatabase.SaveAs(ioc, false, null); + } + // else { } // No assert (sync on save) + + if(mf != null) + mf.FileMruList.AddItem(ioc.GetDisplayName(), + ioc.CloneDeep()); + } + catch(Exception ex) + { + MessageService.ShowWarning( + pwDatabase.IOConnectionInfo.GetDisplayName() + + MessageService.NewLine + ioc.GetDisplayName(), + KPRes.SyncFailed, ex); + bAllSuccess = false; + continue; + } + } + } + else + { + MessageService.ShowWarning( + pwDatabase.IOConnectionInfo.GetDisplayName(), KPRes.SyncFailed); + bAllSuccess = false; + } + } + + dlgStatus.EndLogging(); + return bAllSuccess; + } + + public static bool? Import(PwDatabase pd, FileFormatProvider fmtImp, + IOConnectionInfo iocImp, PwMergeMethod mm, CompositeKey cmpKey) + { + if(pd == null) throw new ArgumentNullException("pd"); + if(fmtImp == null) throw new ArgumentNullException("fmtImp"); + if(iocImp == null) throw new ArgumentNullException("iocImp"); + if(cmpKey == null) cmpKey = new CompositeKey(); + + if(!AppPolicy.Try(AppPolicyId.Import)) return null; + if(!fmtImp.TryBeginImport()) return null; + + PwDatabase pdImp = new PwDatabase(); + pdImp.New(new IOConnectionInfo(), cmpKey); + pdImp.MemoryProtection = pd.MemoryProtection.CloneDeep(); + + Stream s = IOConnection.OpenRead(iocImp); + if(s == null) + throw new FileNotFoundException(iocImp.GetDisplayName() + + MessageService.NewParagraph + KPRes.FileNotFoundError); + + try { fmtImp.Import(pdImp, s, null); } + finally { s.Close(); } + + pd.Modified = true; + pd.MergeIn(pdImp, mm); + return true; + } + + public static bool? Synchronize(PwDatabase pwStorage, IUIOperations uiOps, + bool bOpenFromUrl, Form fParent) + { + if(pwStorage == null) throw new ArgumentNullException("pwStorage"); + if(!pwStorage.IsOpen) { Debug.Assert(false); return null; } + if(!AppPolicy.Try(AppPolicyId.Import)) return null; + + List lConnections = new List(); + if(!bOpenFromUrl) + { + OpenFileDialogEx ofd = UIUtil.CreateOpenFileDialog(KPRes.Synchronize, + UIUtil.CreateFileTypeFilter(AppDefs.FileExtension.FileExt, + KPRes.KdbxFiles, true), 1, null, true, + AppDefs.FileDialogContext.Sync); + + if(ofd.ShowDialog() != DialogResult.OK) return null; + + foreach(string strSelFile in ofd.FileNames) + lConnections.Add(IOConnectionInfo.FromPath(strSelFile)); + } + else // Open URL + { + IOConnectionForm iocf = new IOConnectionForm(); + iocf.InitEx(false, null, true, true); + + if(UIUtil.ShowDialogNotValue(iocf, DialogResult.OK)) return null; + + lConnections.Add(iocf.IOConnectionInfo); + UIUtil.DestroyForm(iocf); + } + + return Import(pwStorage, new KeePassKdb2x(), lConnections.ToArray(), + true, uiOps, false, fParent); + } + + public static bool? Synchronize(PwDatabase pwStorage, IUIOperations uiOps, + IOConnectionInfo iocSyncWith, bool bForceSave, Form fParent) + { + if(pwStorage == null) throw new ArgumentNullException("pwStorage"); + if(!pwStorage.IsOpen) { Debug.Assert(false); return null; } + if(iocSyncWith == null) throw new ArgumentNullException("iocSyncWith"); + if(!AppPolicy.Try(AppPolicyId.Import)) return null; + + Program.TriggerSystem.RaiseEvent(EcasEventIDs.SynchronizingDatabaseFile, + EcasProperty.Database, pwStorage); + + IOConnectionInfo[] vConnections = new IOConnectionInfo[1] { iocSyncWith }; + + bool? ob = Import(pwStorage, new KeePassKdb2x(), vConnections, + true, uiOps, bForceSave, fParent); + + // Always raise the post event, such that the event pair can + // for instance be used to turn off/on other triggers + Program.TriggerSystem.RaiseEvent(EcasEventIDs.SynchronizedDatabaseFile, + EcasProperty.Database, pwStorage); + + return ob; + } + + public static int CountQuotes(string str, int posMax) + { + int i = 0, n = 0; + + while(true) + { + i = str.IndexOf('\"', i); + if(i < 0) return n; + + ++i; + if(i > posMax) return n; + + ++n; + } + } + + public static List SplitCsvLine(string strLine, string strDelimiter) + { + List list = new List(); + + int nOffset = 0; + while(true) + { + int i = strLine.IndexOf(strDelimiter, nOffset); + if(i < 0) break; + + int nQuotes = CountQuotes(strLine, i); + if((nQuotes & 1) == 0) + { + list.Add(strLine.Substring(0, i)); + strLine = strLine.Remove(0, i + strDelimiter.Length); + nOffset = 0; + } + else + { + nOffset = i + strDelimiter.Length; + if(nOffset >= strLine.Length) break; + } + } + + list.Add(strLine); + return list; + } + + public static bool SetStatus(IStatusLogger slLogger, uint uPercent) + { + if(slLogger != null) return slLogger.SetProgress(uPercent); + return true; + } + + private static readonly string[] m_vTitles = { + "title", "system", "account", "entry", + "item", "itemname", "item name", "subject", + "service", "servicename", "service name", + "head", "heading", "card", "product", "provider", "bank", + "type", + + // Non-English names + "seite" + }; + + private static readonly string[] m_vTitlesSubstr = { + "title", "system", "account", "entry", + "item", "subject", "service", "head" + }; + + private static readonly string[] m_vUserNames = { + "user", "name", "username", "user name", "login name", + "login", "form_loginname", "wpname", "mail", + "email", "e-mail", "id", "userid", "user id", + "loginid", "login id", "log", "uin", + "first name", "last name", "card#", "account #", + "member", "member #", "owner", + + // Non-English names + "nom", "benutzername" + }; + + private static readonly string[] m_vUserNamesSubstr = { + "user", "name", "login", "mail", "owner" + }; + + private static readonly string[] m_vPasswords = { + "password", "pass word", "passphrase", "pass phrase", + "pass", "code", "code word", "codeword", + "secret", "secret word", + "key", "keyword", "key word", "keyphrase", "key phrase", + "form_pw", "wppassword", "pin", "pwd", "pw", "pword", + "p", "serial", "serial#", "license key", "reg #", + + // Non-English names + "passwort", "kennwort" + }; + + private static readonly string[] m_vPasswordsSubstr = { + "pass", "code", "secret", "key", "pw", "pin" + }; + + private static readonly string[] m_vUrls = { + "url", "hyper link", "hyperlink", "link", + "host", "hostname", "host name", "server", "address", + "hyper ref", "href", "web", "website", "web site", "site", + "web-site", + + // Non-English names + "ort", "adresse", "webseite" + }; + + private static readonly string[] m_vUrlsSubstr = { + "url", "link", "host", "address", "hyper ref", "href", + "web", "site" + }; + + private static readonly string[] m_vNotes = { + "note", "notes", "comment", "comments", "memo", + "description", "free form", "freeform", + "free text", "freetext", "free", + + // Non-English names + "kommentar", "hinweis" + }; + + private static readonly string[] m_vNotesSubstr = { + "note", "comment", "memo", "description", "free" + }; + + public static string MapNameToStandardField(string strName, bool bAllowFuzzy) + { + if(strName == null) { Debug.Assert(false); return string.Empty; } + + string strFind = strName.Trim().ToLower(); + + if(Array.IndexOf(m_vTitles, strFind) >= 0) + return PwDefs.TitleField; + if(Array.IndexOf(m_vUserNames, strFind) >= 0) + return PwDefs.UserNameField; + if(Array.IndexOf(m_vPasswords, strFind) >= 0) + return PwDefs.PasswordField; + if(Array.IndexOf(m_vUrls, strFind) >= 0) + return PwDefs.UrlField; + if(Array.IndexOf(m_vNotes, strFind) >= 0) + return PwDefs.NotesField; + + if(strFind.Equals(KPRes.Title, StrUtil.CaseIgnoreCmp)) + return PwDefs.TitleField; + if(strFind.Equals(KPRes.UserName, StrUtil.CaseIgnoreCmp)) + return PwDefs.UserNameField; + if(strFind.Equals(KPRes.Password, StrUtil.CaseIgnoreCmp)) + return PwDefs.PasswordField; + if(strFind.Equals(KPRes.Url, StrUtil.CaseIgnoreCmp)) + return PwDefs.UrlField; + if(strFind.Equals(KPRes.Notes, StrUtil.CaseIgnoreCmp)) + return PwDefs.NotesField; + + if(!bAllowFuzzy) return string.Empty; + + // Check for passwords first, then user names ("vb_login_password") + foreach(string strSub in m_vPasswordsSubstr) + { + if(strFind.Contains(strSub)) return PwDefs.PasswordField; + } + foreach(string strSub in m_vUserNamesSubstr) + { + if(strFind.Contains(strSub)) return PwDefs.UserNameField; + } + foreach(string strSub in m_vUrlsSubstr) + { + if(strFind.Contains(strSub)) return PwDefs.UrlField; + } + foreach(string strSub in m_vNotesSubstr) + { + if(strFind.Contains(strSub)) return PwDefs.NotesField; + } + foreach(string strSub in m_vTitlesSubstr) + { + if(strFind.Contains(strSub)) return PwDefs.TitleField; + } + + return string.Empty; + } + + public static void AppendToField(PwEntry pe, string strName, string strValue, + PwDatabase pdContext) + { + AppendToField(pe, strName, strValue, pdContext, null, false); + } + + public static void AppendToField(PwEntry pe, string strName, string strValue, + PwDatabase pdContext, string strSeparator, bool bOnlyIfNotDup) + { + if(pe == null) { Debug.Assert(false); return; } + if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } + + if(strValue == null) { Debug.Assert(false); strValue = string.Empty; } + + if(strSeparator == null) + { + if(PwDefs.IsStandardField(strName) && (strName != PwDefs.NotesField)) + strSeparator = ", "; + else strSeparator = MessageService.NewLine; + } + + ProtectedString psPrev = pe.Strings.Get(strName); + if((psPrev == null) || psPrev.IsEmpty) + { + MemoryProtectionConfig mpc = ((pdContext != null) ? + pdContext.MemoryProtection : new MemoryProtectionConfig()); + bool bProtect = mpc.GetProtection(strName); + + pe.Strings.Set(strName, new ProtectedString(bProtect, strValue)); + } + else if(strValue.Length != 0) + { + bool bAppend = true; + if(bOnlyIfNotDup) + { + ProtectedString psValue = new ProtectedString(false, strValue); + bAppend = !psPrev.Equals(psValue, false); + } + + if(bAppend) + pe.Strings.Set(strName, psPrev + (strSeparator + strValue)); + } + } + + internal static void CreateFieldWithIndex(ProtectedStringDictionary d, + string strName, string strValue, PwDatabase pdContext, bool bAllowEmptyValue) + { + if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } + + MemoryProtectionConfig mpc = ((pdContext != null) ? + pdContext.MemoryProtection : new MemoryProtectionConfig()); + bool bProtect = mpc.GetProtection(strName); + + CreateFieldWithIndex(d, strName, strValue, bProtect, bAllowEmptyValue); + } + + internal static void CreateFieldWithIndex(ProtectedStringDictionary d, + string strName, string strValue, bool bProtect, bool bAllowEmptyValue) + { + if(d == null) { Debug.Assert(false); return; } + if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } + if(strValue == null) { Debug.Assert(false); return; } + if((strValue.Length == 0) && !bAllowEmptyValue) return; + + ProtectedString psValue = new ProtectedString(bProtect, strValue); + + ProtectedString psEx = d.Get(strName); + if((psEx == null) || (PwDefs.IsStandardField(strName) && psEx.IsEmpty)) + { + d.Set(strName, psValue); + return; + } + + NumberFormatInfo nfi = NumberFormatInfo.InvariantInfo; + for(int i = 2; i < int.MaxValue; ++i) + { + string strNameI = strName + " (" + i.ToString(nfi) + ")"; + if(!d.Exists(strNameI)) + { + d.Set(strNameI, psValue); + break; + } + } + } + + public static bool EntryEquals(PwEntry pe1, PwEntry pe2) + { + if(pe1.ParentGroup == null) return false; + if(pe2.ParentGroup == null) return false; + if(pe1.ParentGroup.Name != pe2.ParentGroup.Name) + return false; + + return pe1.Strings.EqualsDictionary(pe2.Strings, + PwCompareOptions.NullEmptyEquivStd, MemProtCmpMode.None); + } + + internal static string GuiSendRetrieve(string strSendPrefix) + { + if(strSendPrefix.Length > 0) + GuiSendKeysPrc(strSendPrefix); + + return GuiRetrieveDataField(); + } + + private static string GuiRetrieveDataField() + { + ClipboardUtil.Clear(); + Application.DoEvents(); + + GuiSendKeysPrc(@"^c"); + + try + { + if(ClipboardUtil.ContainsText()) + return (ClipboardUtil.GetText() ?? string.Empty); + } + catch(Exception) { Debug.Assert(false); } // Opened by other process + + return string.Empty; + } + + internal static void GuiSendKeysPrc(string strSend) + { + if(strSend.Length > 0) + SendInputEx.SendKeysWait(strSend, false); + + Application.DoEvents(); + Thread.Sleep(100); + Application.DoEvents(); + } + + internal static void GuiSendWaitWindowChange(string strSend) + { + IntPtr ptrCur = NativeMethods.GetForegroundWindowHandle(); + + ImportUtil.GuiSendKeysPrc(strSend); + + int nRound = 0; + while(true) + { + Application.DoEvents(); + + IntPtr ptr = NativeMethods.GetForegroundWindowHandle(); + if(ptr != ptrCur) break; + + ++nRound; + if(nRound > 1000) + throw new InvalidOperationException(); + + Thread.Sleep(50); + } + + Thread.Sleep(100); + Application.DoEvents(); + } + + internal static string FixUrl(string strUrl) + { + strUrl = (strUrl ?? string.Empty).Trim(); + + if((strUrl.Length > 0) && (strUrl.IndexOf('.') >= 0) && + (strUrl.IndexOf(':') < 0) && (strUrl.IndexOf('@') < 0)) + { + string strNew = ("https://" + strUrl.ToLower()); + if(strUrl.IndexOf('/') < 0) strNew += "/"; + return strNew; + } + + return strUrl; + } + } +} diff --git a/src/KeePass/DataExchange/JsonObject.cs b/src/KeePass/DataExchange/JsonObject.cs new file mode 100644 index 0000000..4b537ef --- /dev/null +++ b/src/KeePass/DataExchange/JsonObject.cs @@ -0,0 +1,397 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Text; + +using KeePass.Resources; + +using KeePassLib.Resources; +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + public sealed class JsonObject + { + private const int MaxTreeHeight = 50000; + + private Dictionary m_dItems = new Dictionary(); + public IDictionary Items + { + get { return m_dItems; } + } + + private JsonObject() + { + } + + public JsonObject(CharStream csJsonData) + { + if(csJsonData == null) throw new ArgumentNullException("csJsonData"); + + Load(csJsonData); + } + + private static void ThrowDataException() + { + Debug.Assert(false); + throw new FormatException(KLRes.InvalidDataWhileDecoding); + } + + private static void ThrowImplException() + { + Debug.Assert(false); + throw new InvalidOperationException(KLRes.UnknownError); + } + + private void Load(CharStream cs) + { + char chInit = cs.ReadChar(true); + if(chInit != '{') ThrowDataException(); + + Stack sCtx = new Stack(); + sCtx.Push(this); + + while(sCtx.Count != 0) + { + if(sCtx.Count > MaxTreeHeight) + { + Debug.Assert(false); + throw new InvalidOperationException(KLRes.StructsTooDeep); + } + + object oCtx = sCtx.Peek(); + + JsonObject joCtx = (oCtx as JsonObject); + if(joCtx != null) { ReadObjectPart(cs, joCtx, sCtx); continue; } + + List lCtx = (oCtx as List); + if(lCtx != null) { ReadArrayPart(cs, lCtx, sCtx); continue; } + + ThrowImplException(); // Unknown context object + } + } + + private static void ReadObjectPart(CharStream cs, JsonObject joCtx, + Stack sCtx) + { + char ch = cs.PeekChar(true); + + if(ch == '}') EndContainer(cs, joCtx, sCtx); + else if(ch == '\"') + { + string strName = ReadString(cs); + + char chSep = cs.ReadChar(true); + if(chSep != ':') ThrowDataException(); + + object oSub = TryBeginContainer(cs, sCtx); + if(oSub != null) + joCtx.m_dItems[strName] = oSub; + else + { + joCtx.m_dItems[strName] = ReadAtomicValue(cs); + if(cs.PeekChar(true) == ',') cs.ReadChar(true); + } + } + else ThrowDataException(); + } + + private static void ReadArrayPart(CharStream cs, List lCtx, + Stack sCtx) + { + char ch = cs.PeekChar(true); + + if(ch == ']') { EndContainer(cs, lCtx, sCtx); return; } + + object oSub = TryBeginContainer(cs, sCtx); + if(oSub != null) + lCtx.Add(oSub); + else + { + lCtx.Add(ReadAtomicValue(cs)); + if(cs.PeekChar(true) == ',') cs.ReadChar(true); + } + } + + private static object TryBeginContainer(CharStream cs, Stack sCtx) + { + char ch = cs.PeekChar(true); + object oNew = null; + + if(ch == '{') oNew = new JsonObject(); + else if(ch == '[') oNew = new List(); + + if(oNew != null) + { + cs.ReadChar(true); + sCtx.Push(oNew); + } + return oNew; + } + + private static void EndContainer(CharStream cs, object oCtx, + Stack sCtx) + { + Debug.Assert(object.ReferenceEquals(oCtx, sCtx.Peek())); // For Pop() + + char chTerm = cs.ReadChar(true); + if(chTerm == '}') + { + if(!(oCtx is JsonObject)) ThrowImplException(); + } + else if(chTerm == ']') + { + if(!(oCtx is List)) ThrowImplException(); + } + else ThrowImplException(); // Unknown terminator + + sCtx.Pop(); + if(sCtx.Count == 0) return; + + object oParent = sCtx.Peek(); + if((oParent is JsonObject) || (oParent is List)) + { + if(cs.PeekChar(true) == ',') cs.ReadChar(true); + } + else ThrowImplException(); // Unknown context object + } + + private static object ReadAtomicValue(CharStream cs) + { + char chInit = cs.PeekChar(true); + + if(chInit == '\"') return ReadString(cs); + if(chInit == 't') + { + cs.ReadChar(true); + if(cs.ReadChar() != 'r') ThrowDataException(); + if(cs.ReadChar() != 'u') ThrowDataException(); + if(cs.ReadChar() != 'e') ThrowDataException(); + return true; + } + if(chInit == 'f') + { + cs.ReadChar(true); + if(cs.ReadChar() != 'a') ThrowDataException(); + if(cs.ReadChar() != 'l') ThrowDataException(); + if(cs.ReadChar() != 's') ThrowDataException(); + if(cs.ReadChar() != 'e') ThrowDataException(); + return false; + } + if(chInit == 'n') + { + cs.ReadChar(true); + if(cs.ReadChar() != 'u') ThrowDataException(); + if(cs.ReadChar() != 'l') ThrowDataException(); + if(cs.ReadChar() != 'l') ThrowDataException(); + return null; + } + + return ReadNumber(cs); + } + + private static string ReadString(CharStream cs) + { + char chInit = cs.ReadChar(true); + if(chInit != '\"') ThrowImplException(); // Caller should ensure '\"' + + StringBuilder sb = new StringBuilder(); + + while(true) + { + char ch = cs.ReadChar(); + if(ch == char.MinValue) ThrowDataException(); // End of JSON data + if(ch == '\"') break; // End of string + + if(ch == '\\') + { + char chNext = cs.ReadChar(); + switch(chNext) + { + case '\"': + case '\'': // C + case '/': + case '\\': + case '?': // C + sb.Append(chNext); + break; + + case 'a': sb.Append('\a'); break; // C + case 'b': sb.Append('\b'); break; + case 'f': sb.Append('\f'); break; + case 'n': sb.Append('\n'); break; + case 'r': sb.Append('\r'); break; + case 't': sb.Append('\t'); break; + case 'v': sb.Append('\v'); break; // C + + case 'u': + case 'x': // C, only special case supported + sb.Append(ReadHex4Char(cs)); + break; + + default: ThrowDataException(); break; + } + } + else sb.Append(ch); + } + + return sb.ToString(); + } + + private static char ReadHex4Char(CharStream cs) + { + char ch1 = cs.ReadChar(); + char ch2 = cs.ReadChar(); + char ch3 = cs.ReadChar(); + char ch4 = cs.ReadChar(); + + char[] vHex = new char[4] { ch1, ch2, ch3, ch4 }; + if(Array.IndexOf(vHex, char.MinValue) >= 0) ThrowDataException(); + + string strHex = new string(vHex); + if(!StrUtil.IsHexString(strHex, true)) ThrowDataException(); + + return (char)Convert.ToUInt16(strHex, 16); + } + + private static object ReadNumber(CharStream cs) + { + StringBuilder sb = new StringBuilder(); + bool bFloat = false, bNeg = false; + + while(true) + { + char ch = cs.PeekChar(true); + + if(((ch >= '0') && (ch <= '9')) || (ch == '+')) { } + else if(ch == '-') bNeg = true; + else if(ch == '.') bFloat = true; + else if((ch == 'e') || (ch == 'E')) bFloat = true; + else break; + + cs.ReadChar(true); + sb.Append(ch); + } + if(sb.Length == 0) ThrowDataException(); + + string str = sb.ToString(); + NumberFormatInfo nfi = NumberFormatInfo.InvariantInfo; + + if(bFloat) + { + double d; + if(!double.TryParse(str, NumberStyles.Float, nfi, out d)) + ThrowDataException(); + return d; + } + + if(bNeg) + { + long i; + if(!long.TryParse(str, NumberStyles.Integer, nfi, out i)) + ThrowDataException(); + return i; + } + + ulong u; + if(!ulong.TryParse(str, NumberStyles.Integer, nfi, out u)) + ThrowDataException(); + return u; + } + + private static T ConvertOrDefault(object o, T tDefault) + where T : struct // Use 'as' for class + { + if(o == null) return tDefault; + + try + { + if(o is T) return (T)o; + return (T)Convert.ChangeType(o, typeof(T)); + } + catch(Exception) { Debug.Assert(false); } + + try { return (T)o; } + catch(Exception) { Debug.Assert(false); } + + return tDefault; + } + + public T GetValue(string strKey) + where T : class + { + if(strKey == null) throw new ArgumentNullException("strKey"); + + object o; + m_dItems.TryGetValue(strKey, out o); + return (o as T); + } + + public T GetValue(string strKey, T tDefault) + where T : struct + { + if(strKey == null) throw new ArgumentNullException("strKey"); + + object o; + m_dItems.TryGetValue(strKey, out o); + return ConvertOrDefault(o, tDefault); + } + + public T[] GetValueArray(string strKey) + where T : class + { + return GetValueArray(strKey, false); + } + + internal T[] GetValueArray(string strKey, bool bEmptyIfNotExists) + where T : class + { + List lO = GetValue>(strKey); + if(lO == null) return (bEmptyIfNotExists ? MemUtil.EmptyArray() : null); + + T[] vT = new T[lO.Count]; + for(int i = 0; i < lO.Count; ++i) vT[i] = (lO[i] as T); + + return vT; + } + + public T[] GetValueArray(string strKey, T tDefault) + where T : struct + { + return GetValueArray(strKey, tDefault, false); + } + + internal T[] GetValueArray(string strKey, T tDefault, bool bEmptyIfNotExists) + where T : struct + { + List lO = GetValue>(strKey); + if(lO == null) return (bEmptyIfNotExists ? MemUtil.EmptyArray() : null); + + T[] vT = new T[lO.Count]; + for(int i = 0; i < lO.Count; ++i) + vT[i] = ConvertOrDefault(lO[i], tDefault); + + return vT; + } + } +} diff --git a/src/KeePass/DataExchange/KdbFile.cs b/src/KeePass/DataExchange/KdbFile.cs new file mode 100644 index 0000000..c8ddb09 --- /dev/null +++ b/src/KeePass/DataExchange/KdbFile.cs @@ -0,0 +1,818 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Collections; +using KeePassLib.Cryptography.KeyDerivation; +using KeePassLib.Delegates; +using KeePassLib.Interfaces; +using KeePassLib.Keys; +using KeePassLib.Resources; +using KeePassLib.Security; +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + /// + /// Serialization to KeePass KDB files. + /// + public sealed class KdbFile + { + private PwDatabase m_pwDatabase; + private IStatusLogger m_slLogger; + + private const string KdbPrefix = "KDB: "; + + private const string AutoTypePrefix = "Auto-Type"; + private const string AutoTypeWindowPrefix = "Auto-Type-Window"; + + private const string UrlOverridePrefix = "Url-Override:"; + + public static bool IsLibraryInstalled() + { + Exception ex; + return IsLibraryInstalled(out ex); + } + + public static bool IsLibraryInstalled(out Exception ex) + { + try + { + KdbManager mgr = new KdbManager(); + mgr.Dispose(); + } + catch(Exception exMgr) + { + ex = exMgr; + return false; + } + + ex = null; + return true; + } + + /// + /// Default constructor. + /// + /// The PwDatabase instance that the class + /// will load file data into or use to create a KDB file. Must not be null. + /// Thrown if the database + /// reference is null. + public KdbFile(PwDatabase pwDataStore, IStatusLogger slLogger) + { + Debug.Assert(pwDataStore != null); + if(pwDataStore == null) throw new ArgumentNullException("pwDataStore"); + m_pwDatabase = pwDataStore; + + m_slLogger = slLogger; + } + + private static KdbErrorCode SetDatabaseKey(KdbManager mgr, CompositeKey pwKey) + { + string strPassword = null; + if(pwKey.ContainsType(typeof(KcpPassword))) + { + KcpPassword p = (pwKey.GetUserKey(typeof(KcpPassword)) as KcpPassword); + ProtectedString ps = ((p != null) ? p.Password : null); + if(ps == null) + throw new Exception(KPRes.OptionReqOn + @" '" + + KPRes.MasterPasswordRmbWhileOpen + @"'."); + strPassword = ps.ReadString(); + } + + string strKeyFile = null; + if(pwKey.ContainsType(typeof(KcpKeyFile))) + strKeyFile = (pwKey.GetUserKey(typeof(KcpKeyFile)) as KcpKeyFile).Path; + + KdbErrorCode e; + if(!string.IsNullOrEmpty(strKeyFile)) + e = mgr.SetMasterKey(strKeyFile, true, strPassword, IntPtr.Zero, false); + else if(strPassword != null) + e = mgr.SetMasterKey(strPassword, false, null, IntPtr.Zero, false); + else if(pwKey.ContainsType(typeof(KcpUserAccount))) + throw new Exception(KPRes.KdbWUA); + else throw new Exception(KLRes.InvalidCompositeKey); + + return e; + } + + /// + /// Loads a KDB file and stores all loaded entries in the current + /// PwDatabase instance. + /// + /// Relative or absolute path to the file to open. + public void Load(string strFilePath) + { + Debug.Assert(strFilePath != null); + if(strFilePath == null) throw new ArgumentNullException("strFilePath"); + + using(KdbManager mgr = new KdbManager()) + { + KdbErrorCode e; + + e = KdbFile.SetDatabaseKey(mgr, m_pwDatabase.MasterKey); + if(e != KdbErrorCode.Success) + throw new Exception(KLRes.InvalidCompositeKey); + + e = mgr.OpenDatabase(strFilePath, IntPtr.Zero); + if(e != KdbErrorCode.Success) + throw new Exception(KLRes.FileLoadFailed); + + // Copy properties + m_pwDatabase.KdfParameters = (new AesKdf()).GetDefaultParameters(); + m_pwDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, + mgr.KeyTransformationRounds); + + // Read groups and entries + Dictionary dictGroups = ReadGroups(mgr); + ReadEntries(mgr, dictGroups); + } + } + + private Dictionary ReadGroups(KdbManager mgr) + { + uint uGroupCount = mgr.GroupCount; + Dictionary dictGroups = new Dictionary(); + + Stack vGroupStack = new Stack(); + vGroupStack.Push(m_pwDatabase.RootGroup); + + DateTime dtNeverExpire = KdbManager.GetNeverExpireTime(); + + for(uint uGroup = 0; uGroup < uGroupCount; ++uGroup) + { + KdbGroup g = mgr.GetGroup(uGroup); + + PwGroup pg = new PwGroup(true, false); + + pg.Name = g.Name; + pg.IconId = (g.ImageId < (uint)PwIcon.Count) ? (PwIcon)g.ImageId : PwIcon.Folder; + + pg.CreationTime = g.CreationTime.ToDateTime(); + pg.LastModificationTime = g.LastModificationTime.ToDateTime(); + pg.LastAccessTime = g.LastAccessTime.ToDateTime(); + pg.ExpiryTime = g.ExpirationTime.ToDateTime(); + + pg.Expires = (pg.ExpiryTime != dtNeverExpire); + + pg.IsExpanded = ((g.Flags & (uint)KdbGroupFlags.Expanded) != 0); + + while(g.Level < (vGroupStack.Count - 1)) + vGroupStack.Pop(); + + vGroupStack.Peek().AddGroup(pg, true); + + dictGroups[g.GroupId] = pg; + + if(g.Level == (uint)(vGroupStack.Count - 1)) + vGroupStack.Push(pg); + } + + return dictGroups; + } + + private void ReadEntries(KdbManager mgr, Dictionary dictGroups) + { + DateTime dtNeverExpire = KdbManager.GetNeverExpireTime(); + uint uEntryCount = mgr.EntryCount; + + for(uint uEntry = 0; uEntry < uEntryCount; ++uEntry) + { + KdbEntry e = mgr.GetEntry(uEntry); + + PwGroup pgContainer; + if(!dictGroups.TryGetValue(e.GroupId, out pgContainer)) + { + Debug.Assert(false); + continue; + } + + PwEntry pe = new PwEntry(false, false); + pe.SetUuid(new PwUuid(e.Uuid.ToByteArray()), false); + + pgContainer.AddEntry(pe, true, true); + + pe.IconId = (e.ImageId < (uint)PwIcon.Count) ? (PwIcon)e.ImageId : PwIcon.Key; + + pe.Strings.Set(PwDefs.TitleField, new ProtectedString( + m_pwDatabase.MemoryProtection.ProtectTitle, e.Title)); + pe.Strings.Set(PwDefs.UserNameField, new ProtectedString( + m_pwDatabase.MemoryProtection.ProtectUserName, e.UserName)); + pe.Strings.Set(PwDefs.PasswordField, new ProtectedString( + m_pwDatabase.MemoryProtection.ProtectPassword, e.Password)); + pe.Strings.Set(PwDefs.UrlField, new ProtectedString( + m_pwDatabase.MemoryProtection.ProtectUrl, e.Url)); + + string strNotes = e.Additional; + ImportAutoType(ref strNotes, pe); + ImportUrlOverride(ref strNotes, pe); + pe.Strings.Set(PwDefs.NotesField, new ProtectedString( + m_pwDatabase.MemoryProtection.ProtectNotes, strNotes)); + + pe.CreationTime = e.CreationTime.ToDateTime(); + pe.LastModificationTime = e.LastModificationTime.ToDateTime(); + pe.LastAccessTime = e.LastAccessTime.ToDateTime(); + pe.ExpiryTime = e.ExpirationTime.ToDateTime(); + + pe.Expires = (pe.ExpiryTime != dtNeverExpire); + + if((e.BinaryDataLength > 0) && (e.BinaryData != IntPtr.Zero)) + { + byte[] pbData = KdbManager.ReadBinary(e.BinaryData, e.BinaryDataLength); + Debug.Assert(pbData.Length == e.BinaryDataLength); + + string strDesc = e.BinaryDescription; + if(string.IsNullOrEmpty(strDesc)) strDesc = "Attachment"; + + pe.Binaries.Set(strDesc, new ProtectedBinary(false, pbData)); + } + + if(m_slLogger != null) + { + if(!m_slLogger.SetProgress((100 * uEntry) / uEntryCount)) + throw new Exception(KPRes.Cancel); + } + } + } + + /// + /// Save the contents of the current PwDatabase to a KDB file. + /// + /// Location to save the KDB file to. + public void Save(string strSaveToFile, PwGroup pgDataSource) + { + Debug.Assert(strSaveToFile != null); + if(strSaveToFile == null) throw new ArgumentNullException("strSaveToFile"); + + using(KdbManager mgr = new KdbManager()) + { + KdbErrorCode e = KdbFile.SetDatabaseKey(mgr, m_pwDatabase.MasterKey); + if(e != KdbErrorCode.Success) + { + Debug.Assert(false); + throw new Exception(KLRes.InvalidCompositeKey); + } + + if(m_slLogger != null) + { + if(m_pwDatabase.MasterKey.ContainsType(typeof(KcpUserAccount))) + m_slLogger.SetText(KPRes.KdbWUA, LogStatusType.Warning); + + if(m_pwDatabase.Name.Length != 0) + m_slLogger.SetText(KdbPrefix + KPRes.FormatNoDatabaseName, LogStatusType.Warning); + if(m_pwDatabase.Description.Length != 0) + m_slLogger.SetText(KdbPrefix + KPRes.FormatNoDatabaseDesc, LogStatusType.Warning); + } + + // Set properties + AesKdf kdf = new AesKdf(); + if(!kdf.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid)) + mgr.KeyTransformationRounds = (uint)PwDefs.DefaultKeyEncryptionRounds; + else + { + ulong uRounds = m_pwDatabase.KdfParameters.GetUInt64( + AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds); + uRounds = Math.Min(uRounds, 0xFFFFFFFEUL); + + mgr.KeyTransformationRounds = (uint)uRounds; + } + + PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup); + + // Write groups and entries + Dictionary dictGroups = WriteGroups(mgr, pgRoot); + WriteEntries(mgr, dictGroups, pgRoot); + + e = mgr.SaveDatabase(strSaveToFile); + if(e != KdbErrorCode.Success) + throw new Exception(KLRes.FileSaveFailed); + } + } + + private static Dictionary WriteGroups(KdbManager mgr, + PwGroup pgRoot) + { + Dictionary dictGroups = new Dictionary(); + + uint uGroupIndex = 1; + DateTime dtNeverExpire = KdbManager.GetNeverExpireTime(); + + GroupHandler gh = delegate(PwGroup pg) + { + WriteGroup(pg, pgRoot, ref uGroupIndex, dictGroups, dtNeverExpire, + mgr, false); + return true; + }; + + pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, null); + Debug.Assert(dictGroups.Count == (int)(uGroupIndex - 1)); + + EnsureParentGroupsExported(pgRoot, ref uGroupIndex, dictGroups, + dtNeverExpire, mgr); + return dictGroups; + } + + private static void WriteGroup(PwGroup pg, PwGroup pgRoot, ref uint uGroupIndex, + Dictionary dictGroups, DateTime dtNeverExpire, + KdbManager mgr, bool bForceLevel0) + { + if(pg == pgRoot) return; + + KdbGroup grp = new KdbGroup(); + + grp.GroupId = uGroupIndex; + dictGroups[pg] = grp.GroupId; + + grp.ImageId = (uint)pg.IconId; + grp.Name = pg.Name; + grp.CreationTime.Set(pg.CreationTime); + grp.LastModificationTime.Set(pg.LastModificationTime); + grp.LastAccessTime.Set(pg.LastAccessTime); + + if(pg.Expires) + grp.ExpirationTime.Set(pg.ExpiryTime); + else grp.ExpirationTime.Set(dtNeverExpire); + + grp.Level = (bForceLevel0 ? (ushort)0 : (ushort)(pg.GetDepth() - 1)); + + if(pg.IsExpanded) grp.Flags |= (uint)KdbGroupFlags.Expanded; + + if(!mgr.AddGroup(ref grp)) + { + Debug.Assert(false); + throw new InvalidOperationException(); + } + + ++uGroupIndex; + } + + private static void EnsureParentGroupsExported(PwGroup pgRoot, ref uint uGroupIndex, + Dictionary dictGroups, DateTime dtNeverExpires, + KdbManager mgr) + { + bool bHasAtLeastOneGroup = (dictGroups.Count > 0); + uint uLocalIndex = uGroupIndex; // Local copy, can't use ref in delegate + + EntryHandler eh = delegate(PwEntry pe) + { + PwGroup pg = pe.ParentGroup; + if(pg == null) { Debug.Assert(false); return true; } + if(bHasAtLeastOneGroup && (pg == pgRoot)) return true; + + if(dictGroups.ContainsKey(pg)) return true; + + WriteGroup(pg, pgRoot, ref uLocalIndex, dictGroups, dtNeverExpires, + mgr, true); + return true; + }; + + pgRoot.TraverseTree(TraversalMethod.PreOrder, null, eh); + uGroupIndex = uLocalIndex; + } + + private void WriteEntries(KdbManager mgr, Dictionary dictGroups, + PwGroup pgRoot) + { + bool bWarnedOnce = false; + uint uGroupCount, uEntryCount, uEntriesSaved = 0; + pgRoot.GetCounts(true, out uGroupCount, out uEntryCount); + + DateTime dtNeverExpire = KdbManager.GetNeverExpireTime(); + + EntryHandler eh = delegate(PwEntry pe) + { + KdbEntry e = new KdbEntry(); + + e.Uuid.Set(pe.Uuid.UuidBytes); + + if(pe.ParentGroup != pgRoot) + e.GroupId = dictGroups[pe.ParentGroup]; + else + { + e.GroupId = 1; + if((m_slLogger != null) && !bWarnedOnce) + { + m_slLogger.SetText(KdbPrefix + + KPRes.FormatNoRootEntries, LogStatusType.Warning); + bWarnedOnce = true; + } + + if(dictGroups.Count == 0) + throw new Exception(KPRes.FormatNoSubGroupsInRoot); + } + + e.ImageId = (uint)pe.IconId; + + e.Title = pe.Strings.ReadSafe(PwDefs.TitleField); + e.UserName = pe.Strings.ReadSafe(PwDefs.UserNameField); + e.Password = pe.Strings.ReadSafe(PwDefs.PasswordField); + e.Url = pe.Strings.ReadSafe(PwDefs.UrlField); + + string strNotes = pe.Strings.ReadSafe(PwDefs.NotesField); + ExportCustomStrings(pe, ref strNotes); + ExportAutoType(pe, ref strNotes); + ExportUrlOverride(pe, ref strNotes); + e.Additional = strNotes; + + e.PasswordLength = (uint)e.Password.Length; + + Debug.Assert(TimeUtil.PwTimeLength == 7); + e.CreationTime.Set(pe.CreationTime); + e.LastModificationTime.Set(pe.LastModificationTime); + e.LastAccessTime.Set(pe.LastAccessTime); + + if(pe.Expires) e.ExpirationTime.Set(pe.ExpiryTime); + else e.ExpirationTime.Set(dtNeverExpire); + + IntPtr hBinaryData = IntPtr.Zero; + if(pe.Binaries.UCount >= 1) + { + foreach(KeyValuePair kvp in pe.Binaries) + { + e.BinaryDescription = kvp.Key; + + byte[] pbAttached = kvp.Value.ReadData(); + e.BinaryDataLength = (uint)pbAttached.Length; + + if(e.BinaryDataLength > 0) + { + hBinaryData = Marshal.AllocHGlobal((int)e.BinaryDataLength); + Marshal.Copy(pbAttached, 0, hBinaryData, (int)e.BinaryDataLength); + + e.BinaryData = hBinaryData; + } + + break; + } + + if((pe.Binaries.UCount > 1) && (m_slLogger != null)) + m_slLogger.SetText(KdbPrefix + KPRes.FormatOnlyOneAttachment + "\r\n\r\n" + + KPRes.Entry + ":\r\n" + KPRes.Title + ": " + e.Title + "\r\n" + + KPRes.UserName + ": " + e.UserName, LogStatusType.Warning); + } + + bool bResult = mgr.AddEntry(ref e); + + Marshal.FreeHGlobal(hBinaryData); + hBinaryData = IntPtr.Zero; + + if(!bResult) + { + Debug.Assert(false); + throw new InvalidOperationException(); + } + + ++uEntriesSaved; + if(m_slLogger != null) + if(!m_slLogger.SetProgress((100 * uEntriesSaved) / uEntryCount)) + return false; + + return true; + }; + + if(!pgRoot.TraverseTree(TraversalMethod.PreOrder, null, eh)) + throw new InvalidOperationException(); + } + + /* private static void ImportAutoType(ref string strNotes, PwEntry peStorage) + { + string str = strNotes; + char[] vTrim = new char[] { '\r', '\n', '\t', ' ' }; + + int nFirstAutoType = str.IndexOf(AutoTypePrefix, StringComparison.OrdinalIgnoreCase); + if(nFirstAutoType < 0) nFirstAutoType = int.MaxValue; + int nFirstAutoTypeWindow = str.IndexOf(AutoTypeWindowPrefix, StringComparison.OrdinalIgnoreCase); + if((nFirstAutoTypeWindow >= 0) && (nFirstAutoTypeWindow < nFirstAutoType)) + { + int nWindowEnd = str.IndexOf('\n', nFirstAutoTypeWindow); + if(nWindowEnd < 0) nWindowEnd = str.Length - 1; + + string strWindow = str.Substring(nFirstAutoTypeWindow + AutoTypeWindowPrefix.Length, + nWindowEnd - nFirstAutoTypeWindow - AutoTypeWindowPrefix.Length + 1); + strWindow = strWindow.Trim(vTrim); + + str = str.Remove(nFirstAutoTypeWindow, nWindowEnd - nFirstAutoTypeWindow + 1); + peStorage.AutoType.Set(strWindow, string.Empty); + } + + while(true) + { + int nAutoTypeStart = str.IndexOf(AutoTypePrefix, 0, + StringComparison.OrdinalIgnoreCase); + if(nAutoTypeStart < 0) break; + + int nAutoTypeEnd = str.IndexOf('\n', nAutoTypeStart); + if(nAutoTypeEnd < 0) nAutoTypeEnd = str.Length - 1; + + string strAutoType = str.Substring(nAutoTypeStart + AutoTypePrefix.Length, + nAutoTypeEnd - nAutoTypeStart - AutoTypePrefix.Length + 1); + strAutoType = strAutoType.Trim(vTrim); + + str = str.Remove(nAutoTypeStart, nAutoTypeEnd - nAutoTypeStart + 1); + + int nWindowStart = str.IndexOf(AutoTypeWindowPrefix, 0, + StringComparison.OrdinalIgnoreCase); + + if((nWindowStart < 0) || (nWindowStart >= nAutoTypeStart)) + { + peStorage.AutoType.DefaultSequence = strAutoType; + continue; + } + + int nWindowEnd = str.IndexOf('\n', nWindowStart); + if(nWindowEnd < 0) nWindowEnd = str.Length - 1; + + string strWindow = str.Substring(nWindowStart + AutoTypeWindowPrefix.Length, + nWindowEnd - nWindowStart - AutoTypeWindowPrefix.Length + 1); + strWindow = strWindow.Trim(vTrim); + + str = str.Remove(nWindowStart, nWindowEnd - nWindowStart + 1); + peStorage.AutoType.Set(strWindow, strAutoType); + } + + strNotes = str; + } */ + + private static void ImportAutoType(ref string strNotes, PwEntry peStorage) + { + if(string.IsNullOrEmpty(strNotes)) return; + + string str = strNotes.Replace("\r", string.Empty); + string[] vLines = str.Split('\n'); + + string strOvr = FindPrefixedLine(vLines, AutoTypePrefix + ":"); + if((strOvr != null) && (strOvr.Length > (AutoTypePrefix.Length + 1))) + { + strOvr = strOvr.Substring(AutoTypePrefix.Length + 1).Trim(); + peStorage.AutoType.DefaultSequence = ConvertAutoTypeSequence( + strOvr, true); + } + + StringBuilder sb = new StringBuilder(); + foreach(string strLine in vLines) + { + bool bProcessed = false; + for(int iIdx = 0; iIdx < 32; ++iIdx) + { + string s = ((iIdx == 0) ? string.Empty : ("-" + + iIdx.ToString(NumberFormatInfo.InvariantInfo))); + string strWndPrefix = (AutoTypeWindowPrefix + s + ":"); + string strSeqPrefix = (AutoTypePrefix + s + ":"); + + if(strLine.StartsWith(strWndPrefix, StrUtil.CaseIgnoreCmp) && + (strLine.Length > strWndPrefix.Length)) + { + string strWindow = strLine.Substring(strWndPrefix.Length).Trim(); + string strSeq = FindPrefixedLine(vLines, strSeqPrefix); + if((strSeq != null) && (strSeq.Length > strSeqPrefix.Length)) + peStorage.AutoType.Add(new AutoTypeAssociation( + strWindow, ConvertAutoTypeSequence(strSeq.Substring( + strSeqPrefix.Length), true))); + else // Window, but no sequence + peStorage.AutoType.Add(new AutoTypeAssociation( + strWindow, string.Empty)); + + bProcessed = true; + break; + } + else if(strLine.StartsWith(strSeqPrefix, StrUtil.CaseIgnoreCmp)) + { + bProcessed = true; + break; + } + } + + if(!bProcessed) + { + sb.Append(strLine); + sb.Append(MessageService.NewLine); + } + } + + strNotes = sb.ToString(); + // peStorage.AutoType.Sort(); + } + + private static string FindPrefixedLine(string[] vLines, string strPrefix) + { + foreach(string str in vLines) + { + if(str.StartsWith(strPrefix, StrUtil.CaseIgnoreCmp)) + return str; + } + + return null; + } + + private static Dictionary m_dSeq1xTo2x = null; + private static Dictionary m_dSeq1xTo2xBiDir = null; + private static string ConvertAutoTypeSequence(string strSeq, bool b1xTo2x) + { + if(string.IsNullOrEmpty(strSeq)) return string.Empty; + + if(m_dSeq1xTo2x == null) + { + m_dSeq1xTo2x = new Dictionary(); + m_dSeq1xTo2xBiDir = new Dictionary(); + + // m_dSeq1xTo2x[@"{SPACE}"] = " "; + // m_dSeq1xTo2x[@"{CLEARFIELD}"] = @"{HOME}+({END}){DEL}"; + + m_dSeq1xTo2xBiDir[@"{AT}"] = @"@"; + m_dSeq1xTo2xBiDir[@"{PLUS}"] = @"{+}"; + m_dSeq1xTo2xBiDir[@"{PERCENT}"] = @"{%}"; + m_dSeq1xTo2xBiDir[@"{CARET}"] = @"{^}"; + m_dSeq1xTo2xBiDir[@"{TILDE}"] = @"{~}"; + m_dSeq1xTo2xBiDir[@"{LEFTBRACE}"] = @"{{}"; + m_dSeq1xTo2xBiDir[@"{RIGHTBRACE}"] = @"{}}"; + m_dSeq1xTo2xBiDir[@"{LEFTPAREN}"] = @"{(}"; + m_dSeq1xTo2xBiDir[@"{RIGHTPAREN}"] = @"{)}"; + m_dSeq1xTo2xBiDir[@"(+{END})"] = @"+({END})"; + } + + string str = strSeq.Trim(); + + if(b1xTo2x) + { + foreach(KeyValuePair kvp in m_dSeq1xTo2x) + str = StrUtil.ReplaceCaseInsensitive(str, kvp.Key, kvp.Value); + } + + foreach(KeyValuePair kvp in m_dSeq1xTo2xBiDir) + { + if(b1xTo2x) str = StrUtil.ReplaceCaseInsensitive(str, kvp.Key, kvp.Value); + else str = StrUtil.ReplaceCaseInsensitive(str, kvp.Value, kvp.Key); + } + + if(!b1xTo2x) str = CapitalizePlaceholders(str); + + return str; + } + + private static string CapitalizePlaceholders(string strSeq) + { + string str = strSeq; + + int iOffset = 0; + while(true) + { + int iStart = str.IndexOf('{', iOffset); + if(iStart < 0) break; + + int iEnd = str.IndexOf('}', iStart); + if(iEnd < 0) break; // No assert (user data) + + string strPlaceholder = str.Substring(iStart, iEnd - iStart + 1); + + if(!strPlaceholder.StartsWith("{S:", StrUtil.CaseIgnoreCmp)) + str = str.Replace(strPlaceholder, strPlaceholder.ToUpper()); + + iOffset = iStart + 1; + } + + return str; + } + + private static void ExportCustomStrings(PwEntry peSource, ref string strNotes) + { + bool bSep = false; + foreach(KeyValuePair kvp in peSource.Strings) + { + if(PwDefs.IsStandardField(kvp.Key)) continue; + + if(!bSep) + { + if(strNotes.Length > 0) strNotes += MessageService.NewParagraph; + bSep = true; + } + + strNotes += kvp.Key + ": " + kvp.Value.ReadString() + + MessageService.NewLine; + } + } + + private static void ExportAutoType(PwEntry peSource, ref string strNotes) + { + StringBuilder sbAppend = new StringBuilder(); + bool bSeparator = false; + uint uIndex = 0; + + if((peSource.AutoType.DefaultSequence.Length > 0) && + (peSource.AutoType.AssociationsCount == 0)) // Avoid broken indices + { + if(strNotes.Length > 0) + sbAppend.Append(MessageService.NewParagraph); + + sbAppend.Append(AutoTypePrefix); + sbAppend.Append(@": "); + sbAppend.Append(ConvertAutoTypeSeqExp(peSource.AutoType.DefaultSequence, + peSource)); + sbAppend.Append(MessageService.NewLine); + + bSeparator = true; + ++uIndex; + } + + foreach(AutoTypeAssociation a in peSource.AutoType.Associations) + { + if(!bSeparator) + { + if(strNotes.Length > 0) + sbAppend.Append(MessageService.NewParagraph); + + bSeparator = true; + } + + string strSuffix = ((uIndex > 0) ? ("-" + uIndex.ToString( + NumberFormatInfo.InvariantInfo)) : string.Empty); + + sbAppend.Append(AutoTypePrefix + strSuffix); + sbAppend.Append(@": "); + sbAppend.Append(ConvertAutoTypeSeqExp(a.Sequence, peSource)); + sbAppend.Append(MessageService.NewLine); + sbAppend.Append(AutoTypeWindowPrefix + strSuffix); + sbAppend.Append(@": "); + sbAppend.Append(a.WindowName); + sbAppend.Append(MessageService.NewLine); + + ++uIndex; + } + + strNotes = strNotes.TrimEnd(new char[] { '\r', '\n', '\t', ' ' }); + strNotes += sbAppend.ToString(); + } + + private static string ConvertAutoTypeSeqExp(string strSeq, PwEntry pe) + { + string strExp = strSeq; + if(string.IsNullOrEmpty(strExp)) strExp = pe.GetAutoTypeSequence(); + + return ConvertAutoTypeSequence(strExp, false); + } + + private static void ImportUrlOverride(ref string strNotes, PwEntry peStorage) + { + string str = strNotes; + char[] vTrim = new char[] { '\r', '\n', '\t', ' ' }; + + int nUrlStart = str.IndexOf(UrlOverridePrefix, 0, + StringComparison.OrdinalIgnoreCase); + if(nUrlStart < 0) return; + + int nUrlEnd = str.IndexOf('\n', nUrlStart); + if(nUrlEnd < 0) nUrlEnd = str.Length - 1; + + string strUrl = str.Substring(nUrlStart + UrlOverridePrefix.Length, + nUrlEnd - nUrlStart - UrlOverridePrefix.Length + 1); + strUrl = strUrl.Trim(vTrim); + + peStorage.OverrideUrl = strUrl; + + str = str.Remove(nUrlStart, nUrlEnd - nUrlStart + 1); + + strNotes = str; + } + + private static void ExportUrlOverride(PwEntry peSource, ref string strNotes) + { + if(peSource.OverrideUrl.Length > 0) + { + StringBuilder sbAppend = new StringBuilder(); + + sbAppend.Append(MessageService.NewParagraph); + sbAppend.Append(UrlOverridePrefix); + sbAppend.Append(@" "); + sbAppend.Append(peSource.OverrideUrl); + sbAppend.Append(MessageService.NewLine); + + strNotes = strNotes.TrimEnd(new char[] { '\r', '\n', '\t', ' ' }); + strNotes += sbAppend.ToString(); + } + } + } +} diff --git a/src/KeePass/DataExchange/KdbManager.cs b/src/KeePass/DataExchange/KdbManager.cs new file mode 100644 index 0000000..068e9de --- /dev/null +++ b/src/KeePass/DataExchange/KdbManager.cs @@ -0,0 +1,1163 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#if PocketPC || Smartphone || WindowsCE +#undef KDB_ANSI +#else +// If compiling for the ANSI version of KeePassLibC, define KDB_ANSI. +// If compiling for the Unicode version of KeePassLibC, do not define KDB_ANSI. +#define KDB_ANSI +#endif + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +using KeePassLib.Utility; + +namespace KeePass.DataExchange +{ + /// + /// Structure containing information about a password group. This structure + /// doesn't contain any information about the entries stored in this group. + /// +#if PocketPC || Smartphone || WindowsCE + [StructLayout(LayoutKind.Sequential)] +#else + [StructLayout(LayoutKind.Sequential, Pack = 1)] +#endif + public struct KdbGroup + { + /// + /// The GroupID of the group. + /// + [MarshalAs(UnmanagedType.U4)] + public UInt32 GroupId; + + /// + /// The ImageID of the group. + /// + [MarshalAs(UnmanagedType.U4)] + public UInt32 ImageId; + + /// + /// The Name of the group. + /// +#if KDB_ANSI + [MarshalAs(UnmanagedType.LPStr)] + public string Name; +#else + [MarshalAs(UnmanagedType.LPWStr)] + public string Name; +#endif + + /// + /// The creation time of the group. + /// + public KdbTime CreationTime; + + /// + /// The last modification time of the group. + /// + public KdbTime LastModificationTime; + + /// + /// The last access time of the group. + /// + public KdbTime LastAccessTime; + + /// + /// The expiry time of the group. + /// + public KdbTime ExpirationTime; + + /// + /// Indentation level of the group. + /// + [MarshalAs(UnmanagedType.U2)] + public UInt16 Level; + +#if VPF_ALIGN + /// + /// Dummy entry for alignment purposes. + /// + [MarshalAs(UnmanagedType.U2)] + public UInt16 Dummy; +#endif + + /// + /// Flags of the group (see KdbGroupFlags). + /// + [MarshalAs(UnmanagedType.U4)] + public UInt32 Flags; + } + + /// + /// Password group flags. + /// + [Flags] + public enum KdbGroupFlags + { + /// + /// No special flags. + /// + None = 0, + + /// + /// The group is expanded. + /// + Expanded = 1 + } + + /// + /// Structure containing information about a password entry. + /// +#if PocketPC || Smartphone || WindowsCE + [StructLayout(LayoutKind.Sequential)] +#else + [StructLayout(LayoutKind.Sequential, Pack = 1)] +#endif + public struct KdbEntry + { + /// + /// The UUID of the entry. + /// + public KdbUuid Uuid; + + /// + /// The group ID of the enty. + /// + [MarshalAs(UnmanagedType.U4)] + public UInt32 GroupId; + + /// + /// The image ID of the entry. + /// + [MarshalAs(UnmanagedType.U4)] + public UInt32 ImageId; + +#if KDB_ANSI + /// + /// The title of the entry. + /// + [MarshalAs(UnmanagedType.LPStr)] + public string Title; + + /// + /// The URL of the entry. + /// + [MarshalAs(UnmanagedType.LPStr)] + public string Url; + + /// + /// The user name of the entry. + /// + [MarshalAs(UnmanagedType.LPStr)] + public string UserName; + + /// + /// The password length of the entry. + /// + [MarshalAs(UnmanagedType.U4)] + public UInt32 PasswordLength; + + /// + /// The password of the entry. + /// + [MarshalAs(UnmanagedType.LPStr)] + public string Password; + + /// + /// The notes field of the entry. + /// + [MarshalAs(UnmanagedType.LPStr)] + public string Additional; +#else + /// + /// The title of the entry. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string Title; + + /// + /// The URL of the entry. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string Url; + + /// + /// The user name of the entry. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string UserName; + + /// + /// The password length of the entry. + /// + [MarshalAs(UnmanagedType.U4)] + public UInt32 PasswordLength; + + /// + /// The password of the entry. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string Password; + + /// + /// The notes field of the entry. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string Additional; +#endif + + /// + /// The creation time of the entry. + /// + public KdbTime CreationTime; + + /// + /// The last modification time of the entry. + /// + public KdbTime LastModificationTime; + + /// + /// The last access time of the entry. + /// + public KdbTime LastAccessTime; + + /// + /// The expiration time of the entry. + /// + public KdbTime ExpirationTime; + + /// + /// The description of the binary attachment. + /// +#if KDB_ANSI + [MarshalAs(UnmanagedType.LPStr)] + public string BinaryDescription; +#else + [MarshalAs(UnmanagedType.LPWStr)] + public string BinaryDescription; +#endif + + /// + /// The attachment of the entry. + /// + public IntPtr BinaryData; + + /// + /// The length of the attachment. + /// + [MarshalAs(UnmanagedType.U4)] + public UInt32 BinaryDataLength; + } + + /// + /// Structure containing UUID bytes (16 bytes). + /// +#if PocketPC || Smartphone || WindowsCE + [StructLayout(LayoutKind.Sequential)] +#else + [StructLayout(LayoutKind.Sequential, Pack = 1)] +#endif + public struct KdbUuid + { + public Byte V0; public Byte V1; public Byte V2; public Byte V3; + public Byte V4; public Byte V5; public Byte V6; public Byte V7; + public Byte V8; public Byte V9; public Byte VA; public Byte VB; + public Byte VC; public Byte VD; public Byte VE; public Byte VF; + + /// + /// Convert UUID to a byte array of length 16. + /// + /// Byte array (16 bytes). + public byte[] ToByteArray() + { + return new byte[] { this.V0, this.V1, this.V2, this.V3, this.V4, + this.V5, this.V6, this.V7, this.V8, this.V9, this.VA, + this.VB, this.VC, this.VD, this.VE, this.VF }; + } + + /// + /// Set the UUID using an array of 16 bytes. + /// + /// Bytes to set the UUID to. + public void Set(byte[] pb) + { + Debug.Assert((pb != null) && (pb.Length == 16)); + if(pb == null) throw new ArgumentNullException("pb"); + if(pb.Length != 16) throw new ArgumentException(); + + this.V0 = pb[0]; this.V1 = pb[1]; this.V2 = pb[2]; this.V3 = pb[3]; + this.V4 = pb[4]; this.V5 = pb[5]; this.V6 = pb[6]; this.V7 = pb[7]; + this.V8 = pb[8]; this.V9 = pb[9]; this.VA = pb[10]; this.VB = pb[11]; + this.VC = pb[12]; this.VD = pb[13]; this.VE = pb[14]; this.VF = pb[15]; + } + } + + /// + /// Structure containing time information in a compact, but still easily + /// accessible form. + /// +#if PocketPC || Smartphone || WindowsCE + [StructLayout(LayoutKind.Sequential)] +#else + [StructLayout(LayoutKind.Sequential, Pack = 1)] +#endif + public struct KdbTime + { + [MarshalAs(UnmanagedType.U2)] + public UInt16 Year; + [MarshalAs(UnmanagedType.U1)] + public Byte Month; + [MarshalAs(UnmanagedType.U1)] + public Byte Day; + [MarshalAs(UnmanagedType.U1)] + public Byte Hour; + [MarshalAs(UnmanagedType.U1)] + public Byte Minute; + [MarshalAs(UnmanagedType.U1)] + public Byte Second; + +#if VPF_ALIGN + /// + /// Dummy entry for alignment purposes. + /// + [MarshalAs(UnmanagedType.U1)] + public Byte Dummy; +#endif + + /// + /// Construct a KdbTime with initial values. + /// + /// Year. + /// Month. + /// Day. + /// Hour. + /// Minute. + /// Second. + public KdbTime(UInt16 uYear, Byte uMonth, Byte uDay, Byte uHour, + Byte uMinute, Byte uSecond) + { + this.Year = uYear; + this.Month = uMonth; + this.Day = uDay; + this.Hour = uHour; + this.Minute = uMinute; + this.Second = uSecond; + +#if VPF_ALIGN + this.Dummy = 0; +#endif + } + + /// + /// Convert the current KdbTime object to a DateTime object. + /// + public DateTime ToDateTime() + { + if((this.Year == 0) || (this.Month == 0) || (this.Day == 0)) + return DateTime.UtcNow; + + // https://sourceforge.net/p/keepass/discussion/329221/thread/07599afd/ + try + { + int dy = (int)this.Year; + if(dy > 2999) { Debug.Assert(false); dy = 2999; } + + int dm = (int)this.Month; + if(dm > 12) { Debug.Assert(false); dm = 12; } + + int dd = (int)this.Day; + if(dd > 31) { Debug.Assert(false); dd = 28; } + // Day might not exist in month + + int th = (int)this.Hour; + if(th > 23) { Debug.Assert(false); th = 23; } + + int tm = (int)this.Minute; + if(tm > 59) { Debug.Assert(false); tm = 59; } + + int ts = (int)this.Second; + if(ts > 59) { Debug.Assert(false); ts = 59; } + + return (new DateTime(dy, dm, dd, th, tm, ts, + DateTimeKind.Local)).ToUniversalTime(); + } + catch(Exception) { Debug.Assert(false); } + + return DateTime.UtcNow; + } + + /// + /// Copy data from a DateTime object to the current KdbTime object. + /// + /// Data source. + public void Set(DateTime dt) + { + DateTime dtLocal = TimeUtil.ToLocal(dt, true); + + this.Year = (UInt16)dtLocal.Year; + this.Month = (Byte)dtLocal.Month; + this.Day = (Byte)dtLocal.Day; + this.Hour = (Byte)dtLocal.Hour; + this.Minute = (Byte)dtLocal.Minute; + this.Second = (Byte)dtLocal.Second; + } + + /// + /// A KdbTime element that is used to indicate the never expire time. + /// + public static readonly KdbTime NeverExpireTime = + new KdbTime(2999, 12, 28, 23, 59, 59); + } + + /// + /// Error codes for various functions (OpenDatabase, etc.). + /// + public enum KdbErrorCode + { + /// + /// Unknown error occurred. + /// + Unknown = 0, + + /// + /// Successful function call. + /// + Success, + + /// + /// Invalid parameters were given. + /// + InvalidParam, + + /// + /// Not enough memory to perform requested operation. + /// + NotEnoughMemory, + + /// + /// Invalid key was supplied. + /// + InvalidKey, + + /// + /// The file could not be read. + /// + NoFileAccessRead, + + /// + /// The file could not be written. + /// + NoFileAccessWrite, + + /// + /// A file read error occurred. + /// + FileErrorRead, + + /// + /// A file write error occurred. + /// + FileErrorWrite, + + /// + /// Invalid random source was given. + /// + InvalidRandomSource, + + /// + /// Invalid file structure was detected. + /// + InvalidFileStructure, + + /// + /// Cryptographic error occurred. + /// + CryptoError, + + /// + /// Invalid file size was given/detected. + /// + InvalidFileSize, + + /// + /// Invalid file signature was detected. + /// + InvalidFileSignature, + + /// + /// Invalid file header was detected. + /// + InvalidFileHeader, + + /// + /// The keyfile could not be read. + /// + NoFileAccessReadKey + } + + /// + /// Manager class for KDB files. It can load/save databases, add/change/delete + /// groups and entries, check for KeePassLibC library existence and version, etc. + /// + public sealed class KdbManager : IDisposable + { + internal const string DllFile32 = "KeePassLibC32.dll"; + internal const string DllFile64 = "KeePassLibC64.dll"; + + private static readonly bool m_bX64 = (IntPtr.Size == 8); + +#if KDB_ANSI + private const CharSet DllCharSet = CharSet.Ansi; +#else + private const CharSet DllCharSet = CharSet.Unicode; +#endif + + private static bool m_bFirstInstance = true; + private IntPtr m_pManager = IntPtr.Zero; + + [DllImport(DllFile32, EntryPoint = "GetKeePassVersion")] + private static extern UInt32 GetKeePassVersion32(); + [DllImport(DllFile64, EntryPoint = "GetKeePassVersion")] + private static extern UInt32 GetKeePassVersion64(); + /// + /// Get the KeePass version, which the KeePassLibC library supports. + /// + public static UInt32 KeePassVersion + { + get + { + if(m_bX64) return GetKeePassVersion64(); + else return GetKeePassVersion32(); + } + } + + [DllImport(DllFile32, CharSet = DllCharSet, EntryPoint = "GetKeePassVersionString")] + private static extern IntPtr GetKeePassVersionString32(); + [DllImport(DllFile64, CharSet = DllCharSet, EntryPoint = "GetKeePassVersionString")] + private static extern IntPtr GetKeePassVersionString64(); + /// + /// Get the KeePass version, which the KeePassLibC library supports + /// (the version is returned as a displayable string, if you need to + /// compare versions: use the KeePassVersion property). + /// + public static string KeePassVersionString + { +#if KDB_ANSI + get + { + if(m_bX64) return Marshal.PtrToStringAnsi(GetKeePassVersionString64()); + else return Marshal.PtrToStringAnsi(GetKeePassVersionString32()); + } +#else + get + { + if(m_bX64) return Marshal.PtrToStringUni(GetKeePassVersionString64()); + else return Marshal.PtrToStringUni(GetKeePassVersionString32()); + } +#endif + } + + [DllImport(DllFile32, EntryPoint = "GetLibraryBuild")] + private static extern UInt32 GetLibraryBuild32(); + [DllImport(DllFile64, EntryPoint = "GetLibraryBuild")] + private static extern UInt32 GetLibraryBuild64(); + /// + /// Get the library build version. This version has nothing to do with + /// the supported KeePass version (see KeePassVersion property). + /// + public static UInt32 LibraryBuild + { + get + { + if(m_bX64) return GetLibraryBuild64(); + else return GetLibraryBuild32(); + } + } + + [DllImport(DllFile32, EntryPoint = "GetNumberOfEntries")] + private static extern UInt32 GetNumberOfEntries32(IntPtr pMgr); + [DllImport(DllFile64, EntryPoint = "GetNumberOfEntries")] + private static extern UInt32 GetNumberOfEntries64(IntPtr pMgr); + /// + /// Get the number of entries in this manager instance. + /// + public UInt32 EntryCount + { + get + { + if(m_bX64) return GetNumberOfEntries64(m_pManager); + else return GetNumberOfEntries32(m_pManager); + } + } + + [DllImport(DllFile32, EntryPoint = "GetNumberOfGroups")] + private static extern UInt32 GetNumberOfGroups32(IntPtr pMgr); + [DllImport(DllFile64, EntryPoint = "GetNumberOfGroups")] + private static extern UInt32 GetNumberOfGroups64(IntPtr pMgr); + /// + /// Get the number of groups in this manager instance. + /// + public UInt32 GroupCount + { + get + { + if(m_bX64) return GetNumberOfGroups64(m_pManager); + else return GetNumberOfGroups32(m_pManager); + } + } + + [DllImport(DllFile32, EntryPoint = "GetKeyEncRounds")] + private static extern UInt32 GetKeyEncRounds32(IntPtr pMgr); + [DllImport(DllFile64, EntryPoint = "GetKeyEncRounds")] + private static extern UInt32 GetKeyEncRounds64(IntPtr pMgr); + [DllImport(DllFile32, EntryPoint = "SetKeyEncRounds")] + private static extern void SetKeyEncRounds32(IntPtr pMgr, UInt32 dwRounds); + [DllImport(DllFile64, EntryPoint = "SetKeyEncRounds")] + private static extern void SetKeyEncRounds64(IntPtr pMgr, UInt32 dwRounds); + /// + /// Get or set the number of key transformation rounds (in order to + /// make key-searching attacks harder). + /// + public UInt32 KeyTransformationRounds + { + get + { + if(m_bX64) return GetKeyEncRounds64(m_pManager); + else return GetKeyEncRounds32(m_pManager); + } + set + { + if(m_bX64) SetKeyEncRounds64(m_pManager, value); + else SetKeyEncRounds32(m_pManager, value); + } + } + + [DllImport(DllFile32, EntryPoint = "InitManager")] + private static extern void InitManager32(out IntPtr ppMgr, + [MarshalAs(UnmanagedType.Bool)] bool bFirstInstance); + [DllImport(DllFile64, EntryPoint = "InitManager")] + private static extern void InitManager64(out IntPtr ppMgr, + [MarshalAs(UnmanagedType.Bool)] bool bFirstInstance); + + [DllImport(DllFile32, EntryPoint = "NewDatabase")] + private static extern void NewDatabase32(IntPtr pMgr); + [DllImport(DllFile64, EntryPoint = "NewDatabase")] + private static extern void NewDatabase64(IntPtr pMgr); + /// + /// Construct a new KDB manager instance. + /// + public KdbManager() + { + if(!m_bX64) // Only check 32-bit structures + { +#if VPF_ALIGN + bool bAligned = true; +#else + bool bAligned = false; +#endif + + // Static structure layout assertions + int nExpectedSize = (bAligned ? 52 : 46); + KdbGroup g = new KdbGroup(); + Debug.Assert(Marshal.SizeOf(g) == nExpectedSize); + if(Marshal.SizeOf(g) != nExpectedSize) + throw new FormatException("SizeOf(KdbGroup) invalid!"); + + nExpectedSize = (bAligned ? 92 : 88); + KdbEntry e = new KdbEntry(); + Debug.Assert(Marshal.SizeOf(e) == nExpectedSize); + if(Marshal.SizeOf(e) != nExpectedSize) + throw new FormatException("SizeOf(KdbEntry) invalid!"); + + KdbUuid u = new KdbUuid(); + Debug.Assert(Marshal.SizeOf(u) == 16); + if(Marshal.SizeOf(u) != 16) + throw new FormatException("SizeOf(KdbUuid) invalid!"); + + nExpectedSize = (bAligned ? 8 : 7); + KdbTime t = new KdbTime(); + Debug.Assert(Marshal.SizeOf(t) == nExpectedSize); + if(Marshal.SizeOf(t) != nExpectedSize) + throw new FormatException("SizeOf(KdbTime) invalid!"); + } + + if(m_bX64) KdbManager.InitManager64(out m_pManager, m_bFirstInstance); + else KdbManager.InitManager32(out m_pManager, m_bFirstInstance); + + m_bFirstInstance = false; + + if(m_pManager == IntPtr.Zero) + throw new InvalidOperationException("Failed to initialize manager! DLL installed?"); + + if(m_bX64) KdbManager.NewDatabase64(m_pManager); + else KdbManager.NewDatabase32(m_pManager); + } + + ~KdbManager() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + [DllImport(DllFile32, EntryPoint = "DeleteManager")] + private static extern void DeleteManager32(IntPtr pMgr); + [DllImport(DllFile64, EntryPoint = "DeleteManager")] + private static extern void DeleteManager64(IntPtr pMgr); + private void Dispose(bool bDisposing) + { + if(m_pManager != IntPtr.Zero) + { + try + { + if(m_bX64) KdbManager.DeleteManager64(m_pManager); + else KdbManager.DeleteManager32(m_pManager); + } + catch(Exception) { Debug.Assert(false); } + + m_pManager = IntPtr.Zero; + } + } + + [Obsolete] + public void Unload() + { + Dispose(true); + } + + [DllImport(DllFile32, CharSet = DllCharSet, EntryPoint = "SetMasterKey")] + private static extern Int32 SetMasterKey32(IntPtr pMgr, string pszMasterKey, + [MarshalAs(UnmanagedType.Bool)] bool bDiskDrive, string pszSecondKey, + IntPtr pARI, [MarshalAs(UnmanagedType.Bool)] bool bOverwrite); + [DllImport(DllFile64, CharSet = DllCharSet, EntryPoint = "SetMasterKey")] + private static extern Int32 SetMasterKey64(IntPtr pMgr, string pszMasterKey, + [MarshalAs(UnmanagedType.Bool)] bool bDiskDrive, string pszSecondKey, + IntPtr pARI, [MarshalAs(UnmanagedType.Bool)] bool bOverwrite); + /// + /// Set the master key, which will be used when you call the + /// OpenDatabase or SaveDatabase functions. + /// + /// Master password or path to key file. Must not be null. + /// Indicates if a key file is used. + /// Path to the key file when both master password + /// and key file are used. + /// Random source interface. Set this to IntPtr.Zero + /// if you want to open a KDB file normally. If you want to create a key file, + /// pARI must point to a CNewRandomInterface (see KeePass 1.x + /// source code). + /// Indicates if the target file should be overwritten when + /// creating a new key file. + /// Error code (see KdbErrorCode). + public KdbErrorCode SetMasterKey(string strMasterKey, bool bDiskDrive, + string strSecondKey, IntPtr pARI, bool bOverwrite) + { + Debug.Assert(strMasterKey != null); + if(strMasterKey == null) throw new ArgumentNullException("strMasterKey"); + + if(m_bX64) + return (KdbErrorCode)KdbManager.SetMasterKey64(m_pManager, + strMasterKey, bDiskDrive, strSecondKey, pARI, bOverwrite); + else + return (KdbErrorCode)KdbManager.SetMasterKey32(m_pManager, + strMasterKey, bDiskDrive, strSecondKey, pARI, bOverwrite); + } + + [DllImport(DllFile32, CharSet = DllCharSet, EntryPoint = "GetNumberOfItemsInGroup")] + private static extern UInt32 GetNumberOfItemsInGroup32(IntPtr pMgr, string pszGroup); + [DllImport(DllFile64, CharSet = DllCharSet, EntryPoint = "GetNumberOfItemsInGroup")] + private static extern UInt32 GetNumberOfItemsInGroup64(IntPtr pMgr, string pszGroup); + /// + /// Get the number of entries in a group. + /// + /// Group name, which identifies the group. Note + /// that multiple groups can have the same name, in this case you'll need to + /// use the other counting function which uses group IDs. + /// Number of entries in the specified group. + public UInt32 GetNumberOfEntriesInGroup(string strGroupName) + { + Debug.Assert(strGroupName != null); + if(strGroupName == null) throw new ArgumentNullException("strGroupName"); + + if(m_bX64) return KdbManager.GetNumberOfItemsInGroup64(m_pManager, strGroupName); + else return KdbManager.GetNumberOfItemsInGroup32(m_pManager, strGroupName); + } + + [DllImport(DllFile32, EntryPoint = "GetNumberOfItemsInGroupN")] + private static extern UInt32 GetNumberOfItemsInGroupN32(IntPtr pMgr, UInt32 idGroup); + [DllImport(DllFile64, EntryPoint = "GetNumberOfItemsInGroupN")] + private static extern UInt32 GetNumberOfItemsInGroupN64(IntPtr pMgr, UInt32 idGroup); + /// + /// Get the number of entries in a group. + /// + /// Group ID. + /// Number of entries in the specified group. + public UInt32 GetNumberOfEntriesInGroup(UInt32 uGroupId) + { + Debug.Assert((uGroupId != 0) && (uGroupId != UInt32.MaxValue)); + if((uGroupId == 0) || (uGroupId == UInt32.MaxValue)) + throw new ArgumentException("Invalid group ID!"); + + if(m_bX64) return KdbManager.GetNumberOfItemsInGroupN64(m_pManager, uGroupId); + else return KdbManager.GetNumberOfItemsInGroupN32(m_pManager, uGroupId); + } + + [DllImport(DllFile32, EntryPoint = "LockEntryPassword")] + private static extern IntPtr LockEntryPassword32(IntPtr pMgr, IntPtr pEntry); + [DllImport(DllFile64, EntryPoint = "LockEntryPassword")] + private static extern IntPtr LockEntryPassword64(IntPtr pMgr, IntPtr pEntry); + [DllImport(DllFile32, EntryPoint = "UnlockEntryPassword")] + private static extern IntPtr UnlockEntryPassword32(IntPtr pMgr, IntPtr pEntry); + [DllImport(DllFile64, EntryPoint = "UnlockEntryPassword")] + private static extern IntPtr UnlockEntryPassword64(IntPtr pMgr, IntPtr pEntry); + + [DllImport(DllFile32, EntryPoint = "GetEntry")] + private static extern IntPtr GetEntry32(IntPtr pMgr, UInt32 dwIndex); + [DllImport(DllFile64, EntryPoint = "GetEntry")] + private static extern IntPtr GetEntry64(IntPtr pMgr, UInt32 dwIndex); + /// + /// Get an entry. + /// + /// Index of the entry. This index must be valid, otherwise + /// an ArgumentOutOfRangeException is thrown. + /// The requested entry. Note that any modifications to this + /// structure won't affect the internal data structures of the manager. + public KdbEntry GetEntry(uint uIndex) + { + Debug.Assert(uIndex < this.EntryCount); + + IntPtr p; + if(m_bX64) p = KdbManager.GetEntry64(m_pManager, uIndex); + else p = KdbManager.GetEntry32(m_pManager, uIndex); + + if(p == IntPtr.Zero) throw new ArgumentOutOfRangeException("uIndex"); + + if(m_bX64) KdbManager.UnlockEntryPassword64(m_pManager, p); + else KdbManager.UnlockEntryPassword32(m_pManager, p); + + KdbEntry kdbEntry = (KdbEntry)Marshal.PtrToStructure(p, typeof(KdbEntry)); + + if(m_bX64) KdbManager.LockEntryPassword64(m_pManager, p); + else KdbManager.LockEntryPassword32(m_pManager, p); + + return kdbEntry; + } + + [DllImport(DllFile32, EntryPoint = "GetEntryByGroup")] + private static extern IntPtr GetEntryByGroup32(IntPtr pMgr, UInt32 idGroup, UInt32 dwIndex); + [DllImport(DllFile64, EntryPoint = "GetEntryByGroup")] + private static extern IntPtr GetEntryByGroup64(IntPtr pMgr, UInt32 idGroup, UInt32 dwIndex); + /// + /// Get an entry in a specific group. + /// + /// Index of the entry in the group. This index must + /// be valid, otherwise an ArgumentOutOfRangeException is thrown. + /// ID of the group containing the entry. + /// The requested entry. Note that any modifications to this + /// structure won't affect the internal data structures of the manager. + public KdbEntry GetEntryByGroup(UInt32 uGroupId, UInt32 uIndex) + { + Debug.Assert((uGroupId != 0) && (uGroupId != UInt32.MaxValue)); + if((uGroupId == 0) || (uGroupId == UInt32.MaxValue)) + throw new ArgumentException("Invalid group ID!"); + + Debug.Assert(uIndex < this.EntryCount); + + IntPtr p; + if(m_bX64) p = GetEntryByGroup64(m_pManager, uGroupId, uIndex); + else p = GetEntryByGroup32(m_pManager, uGroupId, uIndex); + + if(p == IntPtr.Zero) throw new ArgumentOutOfRangeException(); + + if(m_bX64) KdbManager.UnlockEntryPassword64(m_pManager, p); + else KdbManager.UnlockEntryPassword32(m_pManager, p); + + KdbEntry kdbEntry = (KdbEntry)Marshal.PtrToStructure(p, typeof(KdbEntry)); + + if(m_bX64) KdbManager.LockEntryPassword64(m_pManager, p); + else KdbManager.LockEntryPassword32(m_pManager, p); + + return kdbEntry; + } + + [DllImport(DllFile32, EntryPoint = "GetGroup")] + private static extern IntPtr GetGroup32(IntPtr pMgr, UInt32 dwIndex); + [DllImport(DllFile64, EntryPoint = "GetGroup")] + private static extern IntPtr GetGroup64(IntPtr pMgr, UInt32 dwIndex); + /// + /// Get a group. + /// + /// Index of the group. Must be valid, otherwise an + /// ArgumentOutOfRangeException is thrown. + /// Group structure. + public KdbGroup GetGroup(UInt32 uIndex) + { + Debug.Assert(uIndex < this.GroupCount); + + IntPtr p; + if(m_bX64) p = KdbManager.GetGroup64(m_pManager, uIndex); + else p = KdbManager.GetGroup32(m_pManager, uIndex); + + if(p == IntPtr.Zero) throw new ArgumentOutOfRangeException("uIndex"); + + return (KdbGroup)Marshal.PtrToStructure(p, typeof(KdbGroup)); + } + + [DllImport(DllFile32, EntryPoint = "GetGroupById")] + private static extern IntPtr GetGroupById32(IntPtr pMgr, UInt32 idGroup); + [DllImport(DllFile64, EntryPoint = "GetGroupById")] + private static extern IntPtr GetGroupById64(IntPtr pMgr, UInt32 idGroup); + /// + /// Get a group via the GroupID. + /// + /// ID of the group. + /// Group structure. + public KdbGroup GetGroupById(UInt32 uGroupId) + { + Debug.Assert((uGroupId != 0) && (uGroupId != UInt32.MaxValue)); + if((uGroupId == 0) || (uGroupId == UInt32.MaxValue)) + throw new ArgumentException("Invalid group ID!"); + + IntPtr p; + if(m_bX64) p = KdbManager.GetGroupById64(m_pManager, uGroupId); + else p = KdbManager.GetGroupById32(m_pManager, uGroupId); + + if(p == IntPtr.Zero) throw new ArgumentOutOfRangeException("uGroupId"); + + return (KdbGroup)Marshal.PtrToStructure(p, typeof(KdbGroup)); + } + + [DllImport(DllFile32, EntryPoint = "GetGroupByIdN")] + private static extern UInt32 GetGroupByIdN32(IntPtr pMgr, UInt32 idGroup); + [DllImport(DllFile64, EntryPoint = "GetGroupByIdN")] + private static extern UInt32 GetGroupByIdN64(IntPtr pMgr, UInt32 idGroup); + /// + /// Get the group index via the GroupID. + /// + /// ID of the group. + /// Group index. + public UInt32 GetGroupByIdN(UInt32 uGroupId) + { + Debug.Assert((uGroupId != 0) && (uGroupId != UInt32.MaxValue)); + if((uGroupId == 0) || (uGroupId == UInt32.MaxValue)) + throw new ArgumentException("Invalid group ID!"); + + if(m_bX64) return KdbManager.GetGroupByIdN64(m_pManager, uGroupId); + else return KdbManager.GetGroupByIdN32(m_pManager, uGroupId); + } + + [DllImport(DllFile32, CharSet = DllCharSet, EntryPoint = "OpenDatabase")] + private static extern Int32 OpenDatabase32(IntPtr pMgr, string pszFile, IntPtr pRepair); + [DllImport(DllFile64, CharSet = DllCharSet, EntryPoint = "OpenDatabase")] + private static extern Int32 OpenDatabase64(IntPtr pMgr, string pszFile, IntPtr pRepair); + /// + /// Open a KDB database. + /// + /// File path of the database. + /// Pointer to a repair information structure. If + /// you want to open a Kdb file normally, set this parameter to + /// IntPtr.Zero. + /// Error code (see KdbErrorCode). + public KdbErrorCode OpenDatabase(string strFile, IntPtr pRepairInfo) + { + Debug.Assert(strFile != null); + if(strFile == null) throw new ArgumentNullException("strFile"); + + if(m_bX64) return (KdbErrorCode)KdbManager.OpenDatabase64(m_pManager, strFile, pRepairInfo); + else return (KdbErrorCode)KdbManager.OpenDatabase32(m_pManager, strFile, pRepairInfo); + } + + [DllImport(DllFile32, CharSet = DllCharSet, EntryPoint = "SaveDatabase")] + private static extern Int32 SaveDatabase32(IntPtr pMgr, string pszFile); + [DllImport(DllFile64, CharSet = DllCharSet, EntryPoint = "SaveDatabase")] + private static extern Int32 SaveDatabase64(IntPtr pMgr, string pszFile); + /// + /// Save the current contents of the manager to a KDB file on disk. + /// + /// File to create. + /// Error code (see KdbErrorCode). + public KdbErrorCode SaveDatabase(string strFile) + { + Debug.Assert(strFile != null); + if(strFile == null) throw new ArgumentNullException("strFile"); + + if(m_bX64) return (KdbErrorCode)KdbManager.SaveDatabase64(m_pManager, strFile); + else return (KdbErrorCode)KdbManager.SaveDatabase32(m_pManager, strFile); + } + + /// + /// Close current database and create a new and empty one. + /// + public void NewDatabase() + { + if(m_bX64) KdbManager.NewDatabase64(m_pManager); + else KdbManager.NewDatabase32(m_pManager); + } + + /// + /// Get the date/time object representing the 'Never Expires' status. + /// + /// DateTime object. + public static DateTime GetNeverExpireTime() + { + return KdbTime.NeverExpireTime.ToDateTime(); + } + + [DllImport(DllFile32, CharSet = DllCharSet, EntryPoint = "AddGroup")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool AddGroup32(IntPtr pMgr, ref KdbGroup pTemplate); + [DllImport(DllFile64, CharSet = DllCharSet, EntryPoint = "AddGroup")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool AddGroup64(IntPtr pMgr, ref KdbGroup pTemplate); + /// + /// Add a new password group. + /// + /// Template containing new group information. + /// Returns true if the group was created successfully. + public bool AddGroup(ref KdbGroup pNewGroup) + { + if(m_bX64) return KdbManager.AddGroup64(m_pManager, ref pNewGroup); + else return KdbManager.AddGroup32(m_pManager, ref pNewGroup); + } + + [DllImport(DllFile32, CharSet = DllCharSet, EntryPoint = "SetGroup")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetGroup32(IntPtr pMgr, UInt32 dwIndex, ref KdbGroup pTemplate); + [DllImport(DllFile64, CharSet = DllCharSet, EntryPoint = "SetGroup")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetGroup64(IntPtr pMgr, UInt32 dwIndex, ref KdbGroup pTemplate); + /// + /// Set/change a password group. + /// + /// Index of the group to be changed. + /// Template containing new group information. + /// Returns true if the group was created successfully. + public bool SetGroup(UInt32 uIndex, ref KdbGroup pNewGroup) + { + Debug.Assert(uIndex < this.GroupCount); + + if(m_bX64) return KdbManager.SetGroup64(m_pManager, uIndex, ref pNewGroup); + else return KdbManager.SetGroup32(m_pManager, uIndex, ref pNewGroup); + } + + [DllImport(DllFile32, EntryPoint = "DeleteGroupById")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteGroupById32(IntPtr pMgr, UInt32 uGroupId); + [DllImport(DllFile64, EntryPoint = "DeleteGroupById")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteGroupById64(IntPtr pMgr, UInt32 uGroupId); + /// + /// Delete a password group. + /// + /// ID of the group to be deleted. + /// If the group has been deleted, the return value is true. + public bool DeleteGroupByID(UInt32 uGroupID) + { + Debug.Assert((uGroupID != 0) && (uGroupID != UInt32.MaxValue)); + if((uGroupID == 0) || (uGroupID == UInt32.MaxValue)) + throw new ArgumentException("Invalid group ID!"); + + if(m_bX64) return KdbManager.DeleteGroupById64(m_pManager, uGroupID); + else return KdbManager.DeleteGroupById32(m_pManager, uGroupID); + } + + [DllImport(DllFile32, CharSet = DllCharSet, EntryPoint = "AddEntry")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool AddEntry32(IntPtr pMgr, ref KdbEntry pTemplate); + [DllImport(DllFile64, CharSet = DllCharSet, EntryPoint = "AddEntry")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool AddEntry64(IntPtr pMgr, ref KdbEntry pTemplate); + /// + /// Add a new password entry. + /// + /// Template containing new entry information. + /// Returns true if the entry was created successfully. + public bool AddEntry(ref KdbEntry peNew) + { + if(m_bX64) return KdbManager.AddEntry64(m_pManager, ref peNew); + else return KdbManager.AddEntry32(m_pManager, ref peNew); + } + + [DllImport(DllFile32, CharSet = DllCharSet, EntryPoint = "SetEntry")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetEntry32(IntPtr pMgr, UInt32 dwIndex, ref KdbEntry pTemplate); + [DllImport(DllFile64, CharSet = DllCharSet, EntryPoint = "SetEntry")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetEntry64(IntPtr pMgr, UInt32 dwIndex, ref KdbEntry pTemplate); + /// + /// Set/change a password entry. + /// + /// Index of the entry to be changed. + /// Template containing new entry information. + /// Returns true if the entry was created successfully. + public bool SetEntry(UInt32 uIndex, ref KdbEntry peNew) + { + Debug.Assert(uIndex < this.EntryCount); + + if(m_bX64) return KdbManager.SetEntry64(m_pManager, uIndex, ref peNew); + else return KdbManager.SetEntry32(m_pManager, uIndex, ref peNew); + } + + [DllImport(DllFile32, EntryPoint = "DeleteEntry")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteEntry32(IntPtr pMgr, UInt32 dwIndex); + [DllImport(DllFile64, EntryPoint = "DeleteEntry")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteEntry64(IntPtr pMgr, UInt32 dwIndex); + /// + /// Delete a password entry. + /// + /// Index of the entry. + /// If the entry has been deleted, the return value is true. + public bool DeleteEntry(UInt32 uIndex) + { + Debug.Assert(uIndex < this.EntryCount); + + if(m_bX64) return KdbManager.DeleteEntry64(m_pManager, uIndex); + else return KdbManager.DeleteEntry32(m_pManager, uIndex); + } + + /// + /// Helper function to extract file attachments. + /// + /// Native memory pointer (as stored in the + /// BinaryData member of KdbEntry. + /// Size in bytes of the memory block. + /// Managed byte array. + public static byte[] ReadBinary(IntPtr pMemory, uint uSize) + { + Debug.Assert(pMemory != IntPtr.Zero); + if(pMemory == IntPtr.Zero) throw new ArgumentNullException("pMemory"); + + byte[] pb = new byte[uSize]; + if(uSize == 0) return pb; + + Marshal.Copy(pMemory, pb, 0, (int)uSize); + return pb; + } + } +} diff --git a/src/KeePass/DataExchange/PwExportInfo.cs b/src/KeePass/DataExchange/PwExportInfo.cs new file mode 100644 index 0000000..9659957 --- /dev/null +++ b/src/KeePass/DataExchange/PwExportInfo.cs @@ -0,0 +1,118 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePassLib; + +namespace KeePass.DataExchange +{ + public sealed class PwExportInfo + { + private PwGroup m_pg; + /// + /// This group contains all entries and subgroups that should + /// be exported. Is never null. + /// + public PwGroup DataGroup + { + get { return m_pg; } + internal set { m_pg = value; } + } + + private PwDatabase m_pd; + /// + /// Optional context database reference. May be null. + /// + public PwDatabase ContextDatabase + { + get { return m_pd; } + } + + private bool m_bExpDel = true; + /// + /// Indicates whether deleted objects should be exported, if + /// the data format supports it. + /// + public bool ExportDeletedObjects + { + get { return m_bExpDel; } + } + + private bool m_bExportMasterKeySpec = false; + internal bool ExportMasterKeySpec + { + get { return m_bExportMasterKeySpec; } + set { m_bExportMasterKeySpec = value; } + } + + private bool m_bExportParentGroups = false; + internal bool ExportParentGroups + { + get { return m_bExportParentGroups; } + set { m_bExportParentGroups = value; } + } + + private bool m_bExportPostOpen = false; + internal bool ExportPostOpen + { + get { return m_bExportPostOpen; } + set { m_bExportPostOpen = value; } + } + + private bool m_bExportPostShow = false; + internal bool ExportPostShow + { + get { return m_bExportPostShow; } + set { m_bExportPostShow = value; } + } + + private Dictionary m_dictParams = + new Dictionary(); + public Dictionary Parameters + { + get { return m_dictParams; } + } + + public PwExportInfo(PwGroup pgDataSource, PwDatabase pwContextInfo) + { + ConstructEx(pgDataSource, pwContextInfo, null); + } + + public PwExportInfo(PwGroup pgDataSource, PwDatabase pwContextInfo, + bool bExportDeleted) + { + ConstructEx(pgDataSource, pwContextInfo, bExportDeleted); + } + + private void ConstructEx(PwGroup pgDataSource, PwDatabase pwContextInfo, + bool? bExportDeleted) + { + if(pgDataSource == null) throw new ArgumentNullException("pgDataSource"); + // pwContextInfo may be null + + m_pg = pgDataSource; + m_pd = pwContextInfo; + + if(bExportDeleted.HasValue) m_bExpDel = bExportDeleted.Value; + } + } +} diff --git a/src/KeePass/Ecas/EcasAction.cs b/src/KeePass/Ecas/EcasAction.cs new file mode 100644 index 0000000..65547dd --- /dev/null +++ b/src/KeePass/Ecas/EcasAction.cs @@ -0,0 +1,79 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; + +using KeePassLib; +using KeePassLib.Interfaces; + +namespace KeePass.Ecas +{ + public sealed class EcasAction : IDeepCloneable, IEcasObject + { + private PwUuid m_type = PwUuid.Zero; + [XmlIgnore] + public PwUuid Type + { + get { return m_type; } + set { m_type = value; } + } + + [XmlElement("TypeGuid")] + public string TypeString + { + get { return Convert.ToBase64String(m_type.UuidBytes, Base64FormattingOptions.None); } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_type = new PwUuid(Convert.FromBase64String(value)); + } + } + + private List m_params = new List(); + [XmlArrayItem("Parameter")] + public List Parameters + { + get { return m_params; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_params = value; + } + } + + public EcasAction() + { + } + + public EcasAction CloneDeep() + { + EcasAction e = new EcasAction(); + + e.m_type = m_type; // PwUuid is immutable + + for(int i = 0; i < m_params.Count; ++i) + e.m_params.Add(m_params[i]); + + return e; + } + } +} diff --git a/src/KeePass/Ecas/EcasActionProvider.cs b/src/KeePass/Ecas/EcasActionProvider.cs new file mode 100644 index 0000000..96b781e --- /dev/null +++ b/src/KeePass/Ecas/EcasActionProvider.cs @@ -0,0 +1,90 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePassLib; + +namespace KeePass.Ecas +{ + public abstract class EcasActionProvider + { + protected List m_actions = new List(); + + internal List Actions + { + get { return m_actions; } + } + + public bool IsSupported(PwUuid uuidType) + { + if(uuidType == null) throw new ArgumentNullException("uuidType"); + + foreach(EcasActionType t in m_actions) + { + if(t.Type.Equals(uuidType)) + return true; + } + + return false; + } + + public EcasActionType Find(string strActionName) + { + if(strActionName == null) throw new ArgumentNullException("strActionName"); + + foreach(EcasActionType t in m_actions) + { + if(t.Name == strActionName) return t; + } + + return null; + } + + public EcasActionType Find(PwUuid uuid) + { + if(uuid == null) throw new ArgumentNullException("uuid"); + + foreach(EcasActionType t in m_actions) + { + if(t.Type.Equals(uuid)) return t; + } + + return null; + } + + public void Execute(EcasAction a, EcasContext ctx) + { + if(a == null) throw new ArgumentNullException("a"); + + foreach(EcasActionType t in m_actions) + { + if(t.Type.Equals(a.Type)) + { + t.ExecuteMethod(a, ctx); + return; + } + } + + throw new NotSupportedException(); + } + } +} diff --git a/src/KeePass/Ecas/EcasActionType.cs b/src/KeePass/Ecas/EcasActionType.cs new file mode 100644 index 0000000..7a1ea9c --- /dev/null +++ b/src/KeePass/Ecas/EcasActionType.cs @@ -0,0 +1,82 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePassLib; + +namespace KeePass.Ecas +{ + public delegate void EcasActionExecute(EcasAction a, EcasContext ctx); + + public sealed class EcasActionType : IEcasParameterized + { + private PwUuid m_type; + public PwUuid Type + { + get { return m_type; } + } + + private string m_strName; + public string Name + { + get { return m_strName; } + } + + private PwIcon m_pwIcon; + public PwIcon Icon + { + get { return m_pwIcon; } + } + + private EcasParameter[] m_vParams; + public EcasParameter[] Parameters + { + get { return m_vParams; } + } + + private EcasActionExecute m_fn; + public EcasActionExecute ExecuteMethod + { + get { return m_fn; } + } + + private static void EcasActionExecuteNull(EcasAction a, EcasContext ctx) + { + } + + public EcasActionType(PwUuid uuidType, string strName, PwIcon pwIcon, + EcasParameter[] vParams, EcasActionExecute f) + { + if((uuidType == null) || PwUuid.Zero.Equals(uuidType)) + throw new ArgumentNullException("uuidType"); + if(strName == null) throw new ArgumentNullException("strName"); + // if(vParams == null) throw new ArgumentNullException("vParams"); + // if(f == null) throw new ArgumentNullException("f"); + + m_type = uuidType; + m_strName = strName; + m_pwIcon = pwIcon; + m_vParams = (vParams ?? EcasParameter.EmptyArray); + m_fn = (f ?? EcasActionExecuteNull); + } + } +} diff --git a/src/KeePass/Ecas/EcasCondition.cs b/src/KeePass/Ecas/EcasCondition.cs new file mode 100644 index 0000000..bf3ef7a --- /dev/null +++ b/src/KeePass/Ecas/EcasCondition.cs @@ -0,0 +1,87 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; + +using KeePassLib; +using KeePassLib.Interfaces; + +namespace KeePass.Ecas +{ + public sealed class EcasCondition : IDeepCloneable, IEcasObject + { + private PwUuid m_type = PwUuid.Zero; + [XmlIgnore] + public PwUuid Type + { + get { return m_type; } + set { m_type = value; } + } + + [XmlElement("TypeGuid")] + public string TypeString + { + get { return Convert.ToBase64String(m_type.UuidBytes, Base64FormattingOptions.None); } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_type = new PwUuid(Convert.FromBase64String(value)); + } + } + + private List m_params = new List(); + [XmlArrayItem("Parameter")] + public List Parameters + { + get { return m_params; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_params = value; + } + } + + private bool m_bNegate = false; + public bool Negate + { + get { return m_bNegate; } + set { m_bNegate = value; } + } + + public EcasCondition() + { + } + + public EcasCondition CloneDeep() + { + EcasCondition e = new EcasCondition(); + + e.m_type = m_type; // PwUuid is immutable + + for(int i = 0; i < m_params.Count; ++i) + e.m_params.Add(m_params[i]); + + e.Negate = m_bNegate; + return e; + } + } +} diff --git a/src/KeePass/Ecas/EcasConditionProvider.cs b/src/KeePass/Ecas/EcasConditionProvider.cs new file mode 100644 index 0000000..f26e800 --- /dev/null +++ b/src/KeePass/Ecas/EcasConditionProvider.cs @@ -0,0 +1,87 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePassLib; + +namespace KeePass.Ecas +{ + public abstract class EcasConditionProvider + { + protected List m_conditions = new List(); + + internal List Conditions + { + get { return m_conditions; } + } + + public bool IsSupported(PwUuid uuidType) + { + if(uuidType == null) throw new ArgumentNullException("uuidType"); + + foreach(EcasConditionType t in m_conditions) + { + if(t.Type.Equals(uuidType)) + return true; + } + + return false; + } + + public EcasConditionType Find(string strConditionName) + { + if(strConditionName == null) throw new ArgumentNullException("strConditionName"); + + foreach(EcasConditionType t in m_conditions) + { + if(t.Name == strConditionName) return t; + } + + return null; + } + + public EcasConditionType Find(PwUuid uuid) + { + if(uuid == null) throw new ArgumentNullException("uuid"); + + foreach(EcasConditionType t in m_conditions) + { + if(t.Type.Equals(uuid)) return t; + } + + return null; + } + + public bool Evaluate(EcasCondition c, EcasContext ctx) + { + if(c == null) throw new ArgumentNullException("c"); + + foreach(EcasConditionType t in m_conditions) + { + if(t.Type.Equals(c.Type)) + return t.EvaluateMethod(c, ctx); + } + + throw new NotSupportedException(); + } + } +} diff --git a/src/KeePass/Ecas/EcasConditionType.cs b/src/KeePass/Ecas/EcasConditionType.cs new file mode 100644 index 0000000..098ca94 --- /dev/null +++ b/src/KeePass/Ecas/EcasConditionType.cs @@ -0,0 +1,83 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePassLib; + +namespace KeePass.Ecas +{ + public delegate bool EcasConditionEvaluate(EcasCondition c, EcasContext ctx); + + public sealed class EcasConditionType : IEcasParameterized + { + private PwUuid m_type; + public PwUuid Type + { + get { return m_type; } + } + + private string m_strName; + public string Name + { + get { return m_strName; } + } + + private PwIcon m_pwIcon; + public PwIcon Icon + { + get { return m_pwIcon; } + } + + private EcasParameter[] m_vParams; + public EcasParameter[] Parameters + { + get { return m_vParams; } + } + + private EcasConditionEvaluate m_fn; + public EcasConditionEvaluate EvaluateMethod + { + get { return m_fn; } + } + + private static bool EcasConditionEvaluateTrue(EcasCondition c, EcasContext ctx) + { + return true; + } + + public EcasConditionType(PwUuid uuidType, string strName, PwIcon pwIcon, + EcasParameter[] vParams, EcasConditionEvaluate f) + { + if((uuidType == null) || PwUuid.Zero.Equals(uuidType)) + throw new ArgumentNullException("uuidType"); + if(strName == null) throw new ArgumentNullException("strName"); + // if(vParams == null) throw new ArgumentNullException("vParams"); + // if(f == null) throw new ArgumentNullException("f"); + + m_type = uuidType; + m_strName = strName; + m_pwIcon = pwIcon; + m_vParams = (vParams ?? EcasParameter.EmptyArray); + m_fn = (f ?? EcasConditionEvaluateTrue); + } + } +} diff --git a/src/KeePass/Ecas/EcasContext.cs b/src/KeePass/Ecas/EcasContext.cs new file mode 100644 index 0000000..dbdc78f --- /dev/null +++ b/src/KeePass/Ecas/EcasContext.cs @@ -0,0 +1,73 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace KeePass.Ecas +{ + public sealed class EcasContext + { + private EcasTriggerSystem m_coll; + public EcasTriggerSystem TriggerSystem + { + get { return m_coll; } + } + + private EcasTrigger m_trigger; + public EcasTrigger Trigger + { + get { return m_trigger; } + } + + private EcasEvent m_eOccured; + public EcasEvent Event + { + get { return m_eOccured; } + } + + private EcasPropertyDictionary m_props; + public EcasPropertyDictionary Properties + { + get { return m_props; } + } + + private bool m_bCancel = false; + public bool Cancel + { + get { return m_bCancel; } + set { m_bCancel = value; } + } + + public EcasContext(EcasTriggerSystem coll, EcasTrigger trigger, + EcasEvent e, EcasPropertyDictionary props) + { + if(coll == null) throw new ArgumentNullException("coll"); + if(trigger == null) throw new ArgumentNullException("trigger"); + if(e == null) throw new ArgumentNullException("e"); + if(props == null) throw new ArgumentNullException("props"); + + m_coll = coll; + m_trigger = trigger; + m_eOccured = e; + m_props = props; + } + } +} diff --git a/src/KeePass/Ecas/EcasDefaultActionProvider.cs b/src/KeePass/Ecas/EcasDefaultActionProvider.cs new file mode 100644 index 0000000..88dcc6f --- /dev/null +++ b/src/KeePass/Ecas/EcasDefaultActionProvider.cs @@ -0,0 +1,738 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +using KeePass.App; +using KeePass.DataExchange; +using KeePass.Forms; +using KeePass.Native; +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Collections; +using KeePassLib.Delegates; +using KeePassLib.Keys; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +using NativeLib = KeePassLib.Native.NativeLib; + +namespace KeePass.Ecas +{ + internal sealed class EcasDefaultActionProvider : EcasActionProvider + { + private const uint IdWindowNormal = 0; + private const uint IdWindowHidden = 1; + private const uint IdWindowMin = 2; + private const uint IdWindowMax = 3; + + private const uint IdTriggerOff = 0; + private const uint IdTriggerOn = 1; + private const uint IdTriggerToggle = 2; + + private const uint IdMbcY = 0; + private const uint IdMbcN = 1; + + private const uint IdMbaNone = 0; + private const uint IdMbaAbort = 1; + private const uint IdMbaCmd = 2; + + public EcasDefaultActionProvider() + { + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0xDA, 0xE5, 0xF8, 0x3B, 0x07, 0x30, 0x4C, 0x13, + 0x9E, 0xEF, 0x2E, 0xBA, 0xCB, 0x6E, 0xE4, 0xC7 }), + KPRes.ExecuteCmdLineUrl, PwIcon.Console, new EcasParameter[] { + new EcasParameter(KPRes.FileOrUrl, EcasValueType.String, null), + new EcasParameter(KPRes.Arguments, EcasValueType.String, null), + new EcasParameter(KPRes.WaitForExit, EcasValueType.Bool, null), + new EcasParameter(KPRes.WindowStyle, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem(IdWindowNormal, KPRes.Normal), + new EcasEnumItem(IdWindowHidden, KPRes.Hidden), + new EcasEnumItem(IdWindowMin, KPRes.Minimized), + new EcasEnumItem(IdWindowMax, KPRes.Maximized) })), + new EcasParameter(KPRes.Verb, EcasValueType.String, null) }, + ExecuteShellCmd)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0xB6, 0x46, 0xA6, 0x9F, 0xDE, 0x94, 0x4B, 0xB9, + 0x9B, 0xAE, 0x3C, 0xA4, 0x7E, 0xCC, 0x10, 0xEA }), + KPRes.TriggerStateChange, PwIcon.Run, new EcasParameter[] { + new EcasParameter(KPRes.TriggerName, EcasValueType.String, null), + new EcasParameter(KPRes.NewState, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem(IdTriggerOn, KPRes.On), + new EcasEnumItem(IdTriggerOff, KPRes.Off), + new EcasEnumItem(IdTriggerToggle, KPRes.Toggle) })) }, + ChangeTriggerOnOff)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0xFD, 0x41, 0x55, 0xD5, 0x79, 0x8F, 0x44, 0xFA, + 0xAB, 0x89, 0xF2, 0xF8, 0x70, 0xEF, 0x94, 0xB8 }), + KPRes.OpenDatabaseFileStc, PwIcon.FolderOpen, new EcasParameter[] { + new EcasParameter(KPRes.FileOrUrl, EcasValueType.String, null), + new EcasParameter(KPRes.IOConnection + " - " + KPRes.UserName, + EcasValueType.String, null), + new EcasParameter(KPRes.IOConnection + " - " + KPRes.Password, + EcasValueType.String, null), + new EcasParameter(KPRes.Password, EcasValueType.String, null), + new EcasParameter(KPRes.KeyFile, EcasValueType.String, null), + new EcasParameter(KPRes.WindowsUserAccount, EcasValueType.Bool, null) }, + OpenDatabaseFile)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0xF5, 0x57, 0x61, 0x4B, 0xF8, 0x4C, 0x41, 0x5D, + 0xA9, 0x13, 0x7A, 0x39, 0xCD, 0x10, 0xF0, 0xBD }), + KPRes.SaveDatabaseStc, PwIcon.Disk, null, + SaveDatabaseFile)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x22, 0xAD, 0x77, 0xE4, 0x17, 0x78, 0x4E, 0xED, + 0x99, 0xB4, 0x57, 0x1D, 0x02, 0xB3, 0xAD, 0x4D }), + KPRes.SynchronizeStc, PwIcon.PaperReady, new EcasParameter[] { + new EcasParameter(KPRes.FileOrUrl, EcasValueType.String, null), + new EcasParameter(KPRes.IOConnection + " - " + KPRes.UserName, + EcasValueType.String, null), + new EcasParameter(KPRes.IOConnection + " - " + KPRes.Password, + EcasValueType.String, null) }, + SyncDatabaseFile)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x80, 0xE6, 0x7F, 0x4E, 0x72, 0xF1, 0x40, 0x45, + 0x91, 0x76, 0x1F, 0x2C, 0x23, 0xD8, 0xEC, 0xBE }), + KPRes.ImportStc, PwIcon.PaperReady, new EcasParameter[] { + new EcasParameter(KPRes.FileOrUrl, EcasValueType.String, null), + new EcasParameter(KPRes.FileFormatStc, EcasValueType.String, null), + new EcasParameter(KPRes.Method, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem((uint)PwMergeMethod.None, KPRes.Default), + new EcasEnumItem((uint)PwMergeMethod.CreateNewUuids, + StrUtil.RemoveAccelerator(KPRes.CreateNewIDs)), + new EcasEnumItem((uint)PwMergeMethod.KeepExisting, + StrUtil.RemoveAccelerator(KPRes.KeepExisting)), + new EcasEnumItem((uint)PwMergeMethod.OverwriteExisting, + StrUtil.RemoveAccelerator(KPRes.OverwriteExisting)), + new EcasEnumItem((uint)PwMergeMethod.OverwriteIfNewer, + StrUtil.RemoveAccelerator(KPRes.OverwriteIfNewer)), + new EcasEnumItem((uint)PwMergeMethod.Synchronize, + StrUtil.RemoveAccelerator(KPRes.OverwriteIfNewerAndApplyDel)) })), + new EcasParameter(KPRes.Password, EcasValueType.String, null), + new EcasParameter(KPRes.KeyFile, EcasValueType.String, null), + new EcasParameter(KPRes.WindowsUserAccount, EcasValueType.Bool, null) }, + ImportIntoCurrentDatabase)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x0F, 0x9A, 0x6B, 0x5B, 0xCE, 0xD5, 0x46, 0xBE, + 0xB9, 0x34, 0xED, 0xB1, 0x3F, 0x94, 0x48, 0x22 }), + KPRes.ExportStc, PwIcon.Disk, new EcasParameter[] { + new EcasParameter(KPRes.FileOrUrl, EcasValueType.String, null), + new EcasParameter(KPRes.FileFormatStc, EcasValueType.String, null), + new EcasParameter(KPRes.Filter + " - " + KPRes.Group, EcasValueType.String, null), + new EcasParameter(KPRes.Filter + " - " + KPRes.Tag, EcasValueType.String, null) }, + ExportDatabaseFile)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x5B, 0xBF, 0x45, 0x9D, 0x54, 0xBF, 0x49, 0xBD, + 0x97, 0xFB, 0x2C, 0xEE, 0x5F, 0x99, 0x0A, 0x67 }), + KPRes.CloseActiveDatabase, PwIcon.PaperReady, null, + CloseDatabaseFile)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x3F, 0xB8, 0x33, 0x2D, 0xD6, 0x16, 0x4E, 0x87, + 0x99, 0x05, 0x64, 0xDB, 0x16, 0x4C, 0xD6, 0x26 }), + KPRes.ActivateDatabaseTab, PwIcon.List, new EcasParameter[] { + new EcasParameter(KPRes.FileOrUrl, EcasValueType.String, null), + new EcasParameter(KPRes.Filter, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem(0, KPRes.All), + new EcasEnumItem(1, KPRes.Triggering) })) }, + ActivateDatabaseTab)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x3B, 0x3D, 0x3E, 0x31, 0xE4, 0xB3, 0x42, 0xA6, + 0xBA, 0xCC, 0xD5, 0xC0, 0x3B, 0xAC, 0xA9, 0x69 }), + KPRes.Wait, PwIcon.Clock, new EcasParameter[] { + new EcasParameter(KPRes.TimeSpan + @" [ms]", EcasValueType.UInt64, null) }, + ExecuteSleep)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x09, 0xF7, 0x8F, 0x73, 0x24, 0xEC, 0x4F, 0xEC, + 0x88, 0xB6, 0x25, 0xD5, 0x30, 0xF4, 0x34, 0x6E }), + KPRes.ShowMessageBox, PwIcon.UserCommunication, new EcasParameter[] { + new EcasParameter(KPRes.MainInstruction, EcasValueType.String, null), + new EcasParameter(KPRes.Text, EcasValueType.String, null), + new EcasParameter(KPRes.Icon, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem((uint)MessageBoxIcon.None, KPRes.None), + new EcasEnumItem((uint)MessageBoxIcon.Information, "i"), + new EcasEnumItem((uint)MessageBoxIcon.Question, "?"), + new EcasEnumItem((uint)MessageBoxIcon.Warning, KPRes.Warning), + new EcasEnumItem((uint)MessageBoxIcon.Error, KPRes.Error) })), + new EcasParameter(KPRes.Buttons, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem((uint)MessageBoxButtons.OK, + KPRes.Ok), + new EcasEnumItem((uint)MessageBoxButtons.OKCancel, + KPRes.Ok + "/" + KPRes.Cancel), + new EcasEnumItem((uint)MessageBoxButtons.YesNo, + KPRes.Yes + "/" + KPRes.No) })), + new EcasParameter(KPRes.ButtonDefault, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem(0, KPRes.Button + " 1"), + new EcasEnumItem(1, KPRes.Button + " 2") })), + new EcasParameter(KPRes.Action + " - " + KPRes.Condition, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem(IdMbcY, KPRes.Button + " " + + KPRes.Ok + "/" + KPRes.Yes), + new EcasEnumItem(IdMbcN, KPRes.Button + " " + + KPRes.Cancel + "/" + KPRes.No) })), + new EcasParameter(KPRes.Action, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem(IdMbaNone, KPRes.None), + new EcasEnumItem(IdMbaAbort, KPRes.AbortTrigger), + new EcasEnumItem(IdMbaCmd, KPRes.ExecuteCmdLineUrl) })), + new EcasParameter(KPRes.Action + " - " + KPRes.Parameters, + EcasValueType.String, null) }, + ShowMessageBox)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x40, 0x69, 0xA5, 0x36, 0x57, 0x1B, 0x47, 0x92, + 0xA9, 0xB3, 0x73, 0x65, 0x30, 0xE0, 0xCF, 0xC3 }), + KPRes.PerformGlobalAutoType, PwIcon.Run, null, ExecuteGlobalAutoType)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x31, 0x70, 0x8F, 0xAD, 0x64, 0x93, 0x43, 0xF5, + 0x94, 0xEE, 0xC8, 0x1A, 0x23, 0x6E, 0x32, 0x4D }), + KPRes.PerformSelectedAutoType, PwIcon.Run, new EcasParameter[] { + new EcasParameter(KPRes.Sequence, EcasValueType.String, null) }, + ExecuteSelectedAutoType)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x42, 0xE8, 0x37, 0x81, 0x73, 0xD3, 0x4E, 0xEC, + 0x81, 0x48, 0x9E, 0x3B, 0x36, 0xAC, 0x83, 0x84 }), + KPRes.ShowEntriesByTag, PwIcon.List, new EcasParameter[] { + new EcasParameter(KPRes.Tag, EcasValueType.String, null) }, + ShowEntriesByTag)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0x95, 0x81, 0x8F, 0x45, 0x99, 0x66, 0x49, 0x88, + 0xAB, 0x3E, 0x86, 0xE8, 0x1A, 0x96, 0x68, 0x36 }), + KPRes.CustomTbButtonAdd, PwIcon.Screen, new EcasParameter[] { + new EcasParameter(KPRes.Id, EcasValueType.String, null), + new EcasParameter(KPRes.Name, EcasValueType.String, null), + new EcasParameter(KPRes.Description, EcasValueType.String, null) }, + AddToolBarButton)); + + m_actions.Add(new EcasActionType(new PwUuid(new byte[] { + 0xD6, 0x6D, 0x41, 0xA2, 0x6C, 0xB2, 0x44, 0xBA, + 0xA4, 0x48, 0x0A, 0x41, 0xFA, 0x09, 0x48, 0x79 }), + KPRes.CustomTbButtonRemove, PwIcon.Screen, new EcasParameter[] { + new EcasParameter(KPRes.Id, EcasValueType.String, null) }, + RemoveToolBarButton)); + } + + private static void ExecuteShellCmd(EcasAction a, EcasContext ctx) + { + string strCmd = EcasUtil.GetParamString(a.Parameters, 0); + string strArgs = EcasUtil.GetParamString(a.Parameters, 1, true, true); + bool bWait = EcasUtil.GetParamBool(a.Parameters, 2); + uint uWindowStyle = EcasUtil.GetParamUInt(a.Parameters, 3); + string strVerb = EcasUtil.GetParamString(a.Parameters, 4, true); + + if(string.IsNullOrEmpty(strCmd)) return; + + Process p = null; + try + { + PwEntry pe = null; + try { pe = Program.MainForm.GetSelectedEntry(false); } + catch(Exception) { Debug.Assert(false); } + + strCmd = WinUtil.CompileUrl(strCmd, pe, true, null, false); + if(string.IsNullOrEmpty(strCmd)) return; // Might be placeholder only + + ProcessStartInfo psi = new ProcessStartInfo(); + psi.FileName = strCmd; + if(!string.IsNullOrEmpty(strArgs)) psi.Arguments = strArgs; + + bool bShEx = true; + if(!string.IsNullOrEmpty(strVerb)) { } // Need ShellExecute + else if((uWindowStyle == IdWindowMin) || + (uWindowStyle == IdWindowMax)) { } // Need ShellExecute + else + { + string strCmdFlt = strCmd.TrimEnd(new char[] { '\"', '\'', + ' ', '\t', '\r', '\n' }); + if(strCmdFlt.EndsWith(".exe", StrUtil.CaseIgnoreCmp) || + strCmdFlt.EndsWith(".com", StrUtil.CaseIgnoreCmp)) + bShEx = false; + } + psi.UseShellExecute = bShEx; + + if(uWindowStyle == IdWindowHidden) + { + psi.CreateNoWindow = true; + psi.WindowStyle = ProcessWindowStyle.Hidden; + } + else if(uWindowStyle == IdWindowMin) + psi.WindowStyle = ProcessWindowStyle.Minimized; + else if(uWindowStyle == IdWindowMax) + psi.WindowStyle = ProcessWindowStyle.Maximized; + + if(!string.IsNullOrEmpty(strVerb)) + psi.Verb = strVerb; + + p = NativeLib.StartProcessEx(psi); + + if((p != null) && bWait) + { + Program.MainForm.UIBlockInteraction(true); + MessageService.ExternalIncrementMessageCount(); + + try { p.WaitForExit(); } + catch(Exception) { Debug.Assert(false); } + + MessageService.ExternalDecrementMessageCount(); + Program.MainForm.UIBlockInteraction(false); + } + } + catch(Exception ex) + { + throw new Exception(strCmd + MessageService.NewParagraph + ex.Message); + } + finally + { + try { if(p != null) p.Dispose(); } + catch(Exception) { Debug.Assert(false); } + } + } + + private static void ChangeTriggerOnOff(EcasAction a, EcasContext ctx) + { + string strName = EcasUtil.GetParamString(a.Parameters, 0, true); + uint uState = EcasUtil.GetParamUInt(a.Parameters, 1); + + EcasTrigger t = null; + if(strName.Length == 0) t = ctx.Trigger; + else + { + foreach(EcasTrigger trg in ctx.TriggerSystem.TriggerCollection) + { + if(trg.Name == strName) { t = trg; break; } + } + } + + if(t == null) throw new Exception(KPRes.ObjectNotFound + + MessageService.NewParagraph + KPRes.TriggerName + ": " + strName + "."); + + if(uState == IdTriggerOn) t.On = true; + else if(uState == IdTriggerOff) t.On = false; + else if(uState == IdTriggerToggle) t.On = !t.On; + else { Debug.Assert(false); } + } + + private static void OpenDatabaseFile(EcasAction a, EcasContext ctx) + { + string strPath = EcasUtil.GetParamString(a.Parameters, 0, true); + if(string.IsNullOrEmpty(strPath)) return; + + string strIOUserName = EcasUtil.GetParamString(a.Parameters, 1, true); + string strIOPassword = EcasUtil.GetParamString(a.Parameters, 2, true); + + IOConnectionInfo ioc = IOFromParameters(strPath, strIOUserName, strIOPassword); + if(ioc == null) return; + + CompositeKey ck = KeyFromParams(a, 3, 4, 5, ioc); + + Program.MainForm.OpenDatabase(ioc, ck, ioc.IsLocalFile()); + } + + private static CompositeKey KeyFromParams(EcasAction a, int iPassword, + int iKeyFile, int iUserAccount, IOConnectionInfo ioc) + { + string strPassword = EcasUtil.GetParamString(a.Parameters, iPassword, true); + string strKeyFile = EcasUtil.GetParamString(a.Parameters, iKeyFile, true); + bool bUserAccount = EcasUtil.GetParamBool(a.Parameters, iUserAccount); + + byte[] pbPasswordUtf8 = null; + if(!string.IsNullOrEmpty(strPassword)) + pbPasswordUtf8 = StrUtil.Utf8.GetBytes(strPassword); + + return KeyUtil.CreateKey(pbPasswordUtf8, strKeyFile, bUserAccount, + ioc, false, false); + } + + private static void SaveDatabaseFile(EcasAction a, EcasContext ctx) + { + Program.MainForm.UIFileSave(false); + } + + private static void SyncDatabaseFile(EcasAction a, EcasContext ctx) + { + string strPath = EcasUtil.GetParamString(a.Parameters, 0, true); + if(string.IsNullOrEmpty(strPath)) return; + + string strIOUserName = EcasUtil.GetParamString(a.Parameters, 1, true); + string strIOPassword = EcasUtil.GetParamString(a.Parameters, 2, true); + + IOConnectionInfo ioc = IOFromParameters(strPath, strIOUserName, strIOPassword); + if(ioc == null) return; + + MainForm mf = Program.MainForm; + PwDatabase pd = mf.ActiveDatabase; + if((pd == null) || !pd.IsOpen) return; + + bool? ob = ImportUtil.Synchronize(pd, mf, ioc, false, mf); + mf.UpdateUISyncPost(ob); + } + + private static IOConnectionInfo IOFromParameters(string strPath, + string strUser, string strPassword) + { + IOConnectionInfo ioc = IOConnectionInfo.FromPath(strPath); + + // Set the user name, which acts as a filter for the MRU items + if(!string.IsNullOrEmpty(strUser)) ioc.UserName = strUser; + + // Try to complete it using the MRU list; this will especially + // retrieve the CredSaveMode of the MRU item (if one exists) + ioc = Program.MainForm.CompleteConnectionInfoUsingMru(ioc); + + // Override the password using the trigger value; do not change + // the CredSaveMode anymore (otherwise e.g. values retrieved + // using field references would be stored in the MRU list) + if(!string.IsNullOrEmpty(strPassword)) ioc.Password = strPassword; + + if(ioc.Password.Length > 0) ioc.IsComplete = true; + + return MainForm.CompleteConnectionInfo(ioc, false, true, true, false); + } + + private static void ImportIntoCurrentDatabase(EcasAction a, EcasContext ctx) + { + PwDatabase pd = Program.MainForm.ActiveDatabase; + if((pd == null) || !pd.IsOpen) return; + + string strPath = EcasUtil.GetParamString(a.Parameters, 0, true); + if(string.IsNullOrEmpty(strPath)) return; + IOConnectionInfo ioc = IOConnectionInfo.FromPath(strPath); + + string strFormat = EcasUtil.GetParamString(a.Parameters, 1, true); + if(string.IsNullOrEmpty(strFormat)) return; + FileFormatProvider ff = Program.FileFormatPool.Find(strFormat); + if(ff == null) + throw new Exception(KPRes.Unknown + ": " + strFormat); + + uint uMethod = EcasUtil.GetParamUInt(a.Parameters, 2); + Type tMM = Enum.GetUnderlyingType(typeof(PwMergeMethod)); + object oMethod = Convert.ChangeType(uMethod, tMM); + PwMergeMethod mm = PwMergeMethod.None; + if(Enum.IsDefined(typeof(PwMergeMethod), oMethod)) + mm = (PwMergeMethod)oMethod; + else { Debug.Assert(false); } + if(mm == PwMergeMethod.None) mm = PwMergeMethod.CreateNewUuids; + + CompositeKey ck = KeyFromParams(a, 3, 4, 5, ioc); + if((ck == null) && ff.RequiresKey) + { + KeyPromptFormResult r; + DialogResult dr = KeyPromptForm.ShowDialog(ioc, false, null, out r); + if((dr != DialogResult.OK) || (r == null)) return; + + ck = r.CompositeKey; + } + + bool? ob = false; // Exception => UI update + try { ob = ImportUtil.Import(pd, ff, ioc, mm, ck); } + finally + { + if(ob.HasValue) + Program.MainForm.UpdateUI(false, null, true, null, true, null, false); + } + } + + private static void ExportDatabaseFile(EcasAction a, EcasContext ctx) + { + string strPath = EcasUtil.GetParamString(a.Parameters, 0, true); + // if(string.IsNullOrEmpty(strPath)) return; // Allow no-file exports + string strFormat = EcasUtil.GetParamString(a.Parameters, 1, true); + if(string.IsNullOrEmpty(strFormat)) return; + string strGroup = EcasUtil.GetParamString(a.Parameters, 2, true); + string strTag = EcasUtil.GetParamString(a.Parameters, 3, true); + + PwDatabase pd = Program.MainForm.ActiveDatabase; + if((pd == null) || !pd.IsOpen) return; + + PwGroup pg = pd.RootGroup; + if(!string.IsNullOrEmpty(strGroup)) + { + char chSep = strGroup[0]; + PwGroup pgSub = pg.FindCreateSubTree(strGroup.Substring(1), + new char[] { chSep }, false); + pg = (pgSub ?? (new PwGroup(true, true, KPRes.Group, PwIcon.Folder))); + } + + strTag = StrUtil.NormalizeTag(strTag); + if(!string.IsNullOrEmpty(strTag)) + { + pg = pg.CloneDeep(); + + GroupHandler gh = delegate(PwGroup pgSub) + { + PwObjectList l = pgSub.Entries; + long n = (long)l.UCount; + for(long i = n - 1; i >= 0; --i) + { + List lTags = l.GetAt((uint)i).GetTagsInherited(); + if(!lTags.Contains(strTag)) + l.RemoveAt((uint)i); + } + + return true; + }; + + gh(pg); + pg.TraverseTree(TraversalMethod.PreOrder, gh, null); + } + + PwExportInfo pei = new PwExportInfo(pg, pd, true); + IOConnectionInfo ioc = (!string.IsNullOrEmpty(strPath) ? + IOConnectionInfo.FromPath(strPath) : null); + ExportUtil.Export(pei, strFormat, ioc); + } + + private static void CloseDatabaseFile(EcasAction a, EcasContext ctx) + { + Program.MainForm.CloseDocument(null, false, false, true, true); + } + + private static void ActivateDatabaseTab(EcasAction a, EcasContext ctx) + { + string strName = EcasUtil.GetParamString(a.Parameters, 0, true); + bool bEmptyName = string.IsNullOrEmpty(strName); + + uint uSel = EcasUtil.GetParamUInt(a.Parameters, 1, 0); + PwDatabase pdSel = ctx.Properties.Get(EcasProperty.Database); + + DocumentManagerEx dm = Program.MainForm.DocumentManager; + foreach(PwDocument doc in dm.Documents) + { + if(doc.Database == null) { Debug.Assert(false); continue; } + + if(uSel == 0) // Select from all + { + if(bEmptyName) continue; // Name required in this case + } + else if(uSel == 1) // Triggering only + { + if(!object.ReferenceEquals(doc.Database, pdSel)) continue; + } + else { Debug.Assert(false); continue; } + + IOConnectionInfo ioc = null; + if((doc.LockedIoc != null) && !string.IsNullOrEmpty(doc.LockedIoc.Path)) + ioc = doc.LockedIoc; + else if((doc.Database.IOConnectionInfo != null) && + !string.IsNullOrEmpty(doc.Database.IOConnectionInfo.Path)) + ioc = doc.Database.IOConnectionInfo; + + if(bEmptyName || ((ioc != null) && (ioc.Path.IndexOf(strName, + StrUtil.CaseIgnoreCmp) >= 0))) + { + Program.MainForm.MakeDocumentActive(doc); + break; + } + } + } + + private static void ExecuteSleep(EcasAction a, EcasContext ctx) + { + uint uTimeSpan = EcasUtil.GetParamUInt(a.Parameters, 0); + + if((uTimeSpan != 0) && (uTimeSpan <= (uint)int.MaxValue)) + Thread.Sleep((int)uTimeSpan); + } + + private static void ExecuteGlobalAutoType(EcasAction a, EcasContext ctx) + { + Program.MainForm.ExecuteGlobalAutoType(); + } + + private static void ExecuteSelectedAutoType(EcasAction a, EcasContext ctx) + { + try + { + // Do not Spr-compile the sequence here; it'll be compiled by + // the auto-type engine (and this expects an auto-type sequence + // as input, not a data string; compiling it here would e.g. + // result in broken '%' characters in passwords) + string strSeq = EcasUtil.GetParamString(a.Parameters, 0, false); + if(string.IsNullOrEmpty(strSeq)) strSeq = null; + + PwEntry pe = Program.MainForm.GetSelectedEntry(true); + if(pe == null) return; + PwDatabase pd = Program.MainForm.DocumentManager.SafeFindContainerOf(pe); + + IntPtr hFg = NativeMethods.GetForegroundWindowHandle(); + if(GlobalWindowManager.HasWindowMW(hFg)) + AutoType.PerformIntoPreviousWindow(Program.MainForm, pe, + pd, strSeq); + else AutoType.PerformIntoCurrentWindow(pe, pd, strSeq); + } + catch(Exception) { Debug.Assert(false); } + } + + private static void ShowEntriesByTag(EcasAction a, EcasContext ctx) + { + string strTag = EcasUtil.GetParamString(a.Parameters, 0, true); + Program.MainForm.ShowEntriesByTag(strTag, false); + } + + private static void AddToolBarButton(EcasAction a, EcasContext ctx) + { + string strID = EcasUtil.GetParamString(a.Parameters, 0, true); + string strName = EcasUtil.GetParamString(a.Parameters, 1, true); + string strDesc = EcasUtil.GetParamString(a.Parameters, 2, true); + + Program.MainForm.AddCustomToolBarButton(strID, strName, strDesc); + } + + private static void RemoveToolBarButton(EcasAction a, EcasContext ctx) + { + string strID = EcasUtil.GetParamString(a.Parameters, 0, true); + Program.MainForm.RemoveCustomToolBarButton(strID); + } + + private static void ShowMessageBox(EcasAction a, EcasContext ctx) + { + VistaTaskDialog vtd = new VistaTaskDialog(); + + string strMain = EcasUtil.GetParamString(a.Parameters, 0, true); + if(!string.IsNullOrEmpty(strMain)) vtd.MainInstruction = strMain; + + string strText = EcasUtil.GetParamString(a.Parameters, 1, true); + if(!string.IsNullOrEmpty(strText)) vtd.Content = strText; + + uint uIcon = EcasUtil.GetParamUInt(a.Parameters, 2, 0); + if(uIcon == (uint)MessageBoxIcon.Information) + vtd.SetIcon(VtdIcon.Information); + else if(uIcon == (uint)MessageBoxIcon.Question) + vtd.SetIcon(VtdCustomIcon.Question); + else if(uIcon == (uint)MessageBoxIcon.Warning) + vtd.SetIcon(VtdIcon.Warning); + else if(uIcon == (uint)MessageBoxIcon.Error) + vtd.SetIcon(VtdIcon.Error); + else { Debug.Assert(uIcon == (uint)MessageBoxIcon.None); } + + vtd.CommandLinks = false; + + uint uBtns = EcasUtil.GetParamUInt(a.Parameters, 3, 0); + bool bCanCancel = false; + if(uBtns == (uint)MessageBoxButtons.OKCancel) + { + vtd.AddButton((int)DialogResult.OK, KPRes.Ok, null); + vtd.AddButton((int)DialogResult.Cancel, KPRes.Cancel, null); + bCanCancel = true; + } + else if(uBtns == (uint)MessageBoxButtons.YesNo) + { + vtd.AddButton((int)DialogResult.OK, KPRes.YesCmd, null); + vtd.AddButton((int)DialogResult.Cancel, KPRes.NoCmd, null); + bCanCancel = true; + } + else vtd.AddButton((int)DialogResult.OK, KPRes.Ok, null); + + uint uDef = EcasUtil.GetParamUInt(a.Parameters, 4, 0); + ReadOnlyCollection lButtons = vtd.Buttons; + if(uDef < (uint)lButtons.Count) + vtd.DefaultButtonID = lButtons[(int)uDef].ID; + + vtd.WindowTitle = PwDefs.ShortProductName; + + string strTrg = ctx.Trigger.Name; + if(!string.IsNullOrEmpty(strTrg)) + { + vtd.FooterText = KPRes.Trigger + @": '" + strTrg + @"'."; + vtd.SetFooterIcon(VtdIcon.Information); + } + + int dr; + if(vtd.ShowDialog()) dr = vtd.Result; + else + { + string str = (strMain ?? string.Empty); + if(!string.IsNullOrEmpty(strText)) + { + if(str.Length > 0) str += MessageService.NewParagraph; + str += strText; + } + + MessageBoxDefaultButton mbdb = MessageBoxDefaultButton.Button1; + if(uDef == 1) mbdb = MessageBoxDefaultButton.Button2; + else if(uDef == 2) mbdb = MessageBoxDefaultButton.Button3; + + MessageService.ExternalIncrementMessageCount(); + try + { + dr = (int)MessageService.SafeShowMessageBox(str, + PwDefs.ShortProductName, (MessageBoxButtons)uBtns, + (MessageBoxIcon)uIcon, mbdb); + } + finally { MessageService.ExternalDecrementMessageCount(); } + } + + uint uActCondID = EcasUtil.GetParamUInt(a.Parameters, 5, 0); + + bool bDrY = ((dr == (int)DialogResult.OK) || + (dr == (int)DialogResult.Yes)); + bool bDrN = ((dr == (int)DialogResult.Cancel) || + (dr == (int)DialogResult.No)); + + bool bPerformAction = (((uActCondID == IdMbcY) && bDrY) || + ((uActCondID == IdMbcN) && bDrN)); + if(!bPerformAction) return; + + uint uActID = EcasUtil.GetParamUInt(a.Parameters, 6, 0); + string strActionParam = EcasUtil.GetParamString(a.Parameters, 7, true); + + if(uActID == IdMbaNone) { } + else if(uActID == IdMbaAbort) + { + if(bCanCancel) ctx.Cancel = true; + } + else if(uActID == IdMbaCmd) + { + if(!string.IsNullOrEmpty(strActionParam)) + WinUtil.OpenUrl(strActionParam, null); + } + else { Debug.Assert(false); } + } + } +} diff --git a/src/KeePass/Ecas/EcasDefaultConditionProvider.cs b/src/KeePass/Ecas/EcasDefaultConditionProvider.cs new file mode 100644 index 0000000..e47de29 --- /dev/null +++ b/src/KeePass/Ecas/EcasDefaultConditionProvider.cs @@ -0,0 +1,179 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Net.NetworkInformation; +using System.Windows.Forms; +using System.Diagnostics; + +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Serialization; +using KeePassLib.Utility; + +namespace KeePass.Ecas +{ + internal sealed class EcasDefaultConditionProvider : EcasConditionProvider + { + public EcasDefaultConditionProvider() + { + m_conditions.Add(new EcasConditionType(new PwUuid(new byte[] { + 0x9F, 0x11, 0xD0, 0xBD, 0xEC, 0xE9, 0x45, 0x3B, + 0xA5, 0x45, 0x26, 0x1F, 0xF7, 0xA4, 0xFF, 0x1F }), + KPRes.EnvironmentVariable, PwIcon.Console, new EcasParameter[] { + new EcasParameter(KPRes.Name, EcasValueType.String, null), + new EcasParameter(KPRes.Value + " - " + KPRes.Comparison, + EcasValueType.EnumStrings, EcasUtil.StdStringCompare), + new EcasParameter(KPRes.Value, EcasValueType.String, null) }, + IsMatchEnvironmentVar)); + + m_conditions.Add(new EcasConditionType(new PwUuid(new byte[] { + 0xB9, 0x0F, 0xF8, 0x07, 0x73, 0x38, 0x4F, 0xEA, + 0xBB, 0x2E, 0xBC, 0x0B, 0xEA, 0x3B, 0x98, 0xC3 }), + KPRes.String, PwIcon.Configuration, new EcasParameter[] { + new EcasParameter(KPRes.String, EcasValueType.String, null), + new EcasParameter(KPRes.Value + " - " + KPRes.Comparison, + EcasValueType.EnumStrings, EcasUtil.StdStringCompare), + new EcasParameter(KPRes.Value, EcasValueType.String, null) }, + IsMatchString)); + + m_conditions.Add(new EcasConditionType(new PwUuid(new byte[] { + 0xCB, 0x4A, 0x9E, 0x34, 0x56, 0x8C, 0x4C, 0x95, + 0xAD, 0x67, 0x4D, 0x1C, 0xA1, 0x04, 0x19, 0xBC }), + KPRes.FileExists, PwIcon.PaperReady, new EcasParameter[] { + new EcasParameter(KPRes.FileOrUrl, EcasValueType.String, null) }, + IsMatchFileExists)); + + m_conditions.Add(new EcasConditionType(new PwUuid(new byte[] { + 0x2A, 0x22, 0x83, 0xA8, 0x9D, 0x13, 0x41, 0xE8, + 0x99, 0x87, 0x8B, 0xAC, 0x21, 0x8D, 0x81, 0xF4 }), + KPRes.RemoteHostReachable, PwIcon.NetworkServer, new EcasParameter[] { + new EcasParameter(KPRes.Host, EcasValueType.String, null) }, + IsHostReachable)); + + m_conditions.Add(new EcasConditionType(new PwUuid(new byte[] { + 0xD3, 0xCA, 0xFA, 0xEF, 0x28, 0x2A, 0x46, 0x4A, + 0x99, 0x90, 0xD8, 0x65, 0xFC, 0xE0, 0x16, 0xED }), + KPRes.DatabaseHasUnsavedChanges, PwIcon.PaperFlag, new EcasParameter[] { + new EcasParameter(KPRes.Database, EcasValueType.EnumStrings, + new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem(0, KPRes.Active), + new EcasEnumItem(1, KPRes.Triggering) })) }, + IsDatabaseModified)); + } + + private static bool IsMatchEnvironmentVar(EcasCondition c, EcasContext ctx) + { + string strName = EcasUtil.GetParamString(c.Parameters, 0, true); + uint uCompareType = EcasUtil.GetParamEnum(c.Parameters, 1, + EcasUtil.StdStringCompareEquals, EcasUtil.StdStringCompare); + string strValue = EcasUtil.GetParamString(c.Parameters, 2, true); + + if(string.IsNullOrEmpty(strName) || (strValue == null)) + return false; + + try + { + string strVar = Environment.GetEnvironmentVariable(strName); + if(strVar == null) return false; + + return EcasUtil.CompareStrings(strVar, strValue, uCompareType); + } + catch(Exception) { Debug.Assert(false); } + + return false; + } + + private static bool IsMatchString(EcasCondition c, EcasContext ctx) + { + string str = EcasUtil.GetParamString(c.Parameters, 0, true); + uint uCompareType = EcasUtil.GetParamEnum(c.Parameters, 1, + EcasUtil.StdStringCompareEquals, EcasUtil.StdStringCompare); + string strValue = EcasUtil.GetParamString(c.Parameters, 2, true); + + if((str == null) || (strValue == null)) return false; + + return EcasUtil.CompareStrings(str, strValue, uCompareType); + } + + private static bool IsMatchFileExists(EcasCondition c, EcasContext ctx) + { + string strFile = EcasUtil.GetParamString(c.Parameters, 0, true); + if(string.IsNullOrEmpty(strFile)) return true; + + try + { + // return File.Exists(strFile); + + IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile); + return IOConnection.FileExists(ioc); + } + catch(Exception) { } + + return false; + } + + private static bool IsHostReachable(EcasCondition c, EcasContext ctx) + { + string strHost = EcasUtil.GetParamString(c.Parameters, 0, true); + if(string.IsNullOrEmpty(strHost)) return true; + + int[] vTimeOuts = { 250, 1250 }; + const string strBuffer = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + byte[] pbBuffer = Encoding.ASCII.GetBytes(strBuffer); + + try + { + Ping ping = new Ping(); // We have sufficient privileges? + PingOptions options = new PingOptions(64, true); + + foreach(int nTimeOut in vTimeOuts) + { + PingReply reply = ping.Send(strHost, nTimeOut, pbBuffer, options); + if(reply.Status == IPStatus.Success) return true; + } + + return false; + } + catch(Exception) { } + + return false; + } + + private static bool IsDatabaseModified(EcasCondition c, EcasContext ctx) + { + PwDatabase pd = null; + + uint uSel = EcasUtil.GetParamUInt(c.Parameters, 0, 0); + if(uSel == 0) + pd = Program.MainForm.ActiveDatabase; + else if(uSel == 1) + pd = ctx.Properties.Get(EcasProperty.Database); + else { Debug.Assert(false); } + + if((pd == null) || !pd.IsOpen) return false; + return pd.Modified; + } + } +} diff --git a/src/KeePass/Ecas/EcasDefaultEventProvider.cs b/src/KeePass/Ecas/EcasDefaultEventProvider.cs new file mode 100644 index 0000000..c522012 --- /dev/null +++ b/src/KeePass/Ecas/EcasDefaultEventProvider.cs @@ -0,0 +1,224 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +using KeePass.Resources; + +using KeePassLib; +using KeePassLib.Utility; +using KeePassLib.Serialization; + +namespace KeePass.Ecas +{ + internal static class EcasEventIDs + { + public static readonly PwUuid OpenedDatabaseFile = new PwUuid(new byte[] { + 0xE5, 0xFF, 0x13, 0x06, 0x85, 0xB8, 0x41, 0x89, + 0xB9, 0x06, 0xF6, 0x9E, 0x2B, 0x3B, 0x40, 0xA7 + }); + public static readonly PwUuid SavingDatabaseFile = new PwUuid(new byte[] { + 0x95, 0xC1, 0xA6, 0xFD, 0x72, 0x7C, 0x40, 0xC7, + 0xA2, 0xF9, 0x5B, 0x0F, 0xA0, 0x99, 0x63, 0x1C + }); + public static readonly PwUuid SavedDatabaseFile = new PwUuid(new byte[] { + 0xB3, 0xA8, 0xFD, 0xFE, 0x78, 0x13, 0x4A, 0x6A, + 0x9C, 0x5D, 0xD5, 0xBA, 0x84, 0x3A, 0x9B, 0x8E + }); + public static readonly PwUuid SynchronizingDatabaseFile = new PwUuid(new byte[] { + 0x06, 0x7E, 0x27, 0xA7, 0x20, 0xB0, 0x47, 0x71, + 0x8F, 0x14, 0x68, 0xD5, 0x01, 0x5C, 0x76, 0x6A + }); + public static readonly PwUuid SynchronizedDatabaseFile = new PwUuid(new byte[] { + 0xB5, 0xA1, 0xE0, 0xD5, 0xA2, 0xF6, 0x44, 0xB3, + 0x8A, 0xA1, 0x84, 0xC6, 0x86, 0xC2, 0xA9, 0x60 + }); + public static readonly PwUuid ClosingDatabaseFilePre = new PwUuid(new byte[] { + 0x8C, 0xEA, 0xDE, 0x9A, 0xA8, 0x17, 0x49, 0x19, + 0xA3, 0x2F, 0xF4, 0x1E, 0x3B, 0x1D, 0xEC, 0x49 + }); + public static readonly PwUuid ClosingDatabaseFilePost = new PwUuid(new byte[] { + 0x94, 0xFA, 0x70, 0xE5, 0xB1, 0x3F, 0x41, 0x26, + 0xA6, 0x4E, 0x06, 0x4F, 0xD8, 0xC3, 0x6C, 0x95 + }); + public static readonly PwUuid CopiedEntryInfo = new PwUuid(new byte[] { + 0x3F, 0x7E, 0x5E, 0xC6, 0x2A, 0x54, 0x4C, 0x58, + 0x95, 0x44, 0x85, 0xFB, 0xF2, 0x6F, 0x56, 0xDC + }); + public static readonly PwUuid AppInitPost = new PwUuid(new byte[] { + 0xD4, 0xCE, 0xCD, 0xB5, 0x4B, 0x98, 0x4F, 0xF2, + 0xA6, 0xA9, 0xE2, 0x55, 0x26, 0x1E, 0xC8, 0xE8 + }); + public static readonly PwUuid AppLoadPost = new PwUuid(new byte[] { + 0xD8, 0xF3, 0x1E, 0xE9, 0xCC, 0x69, 0x48, 0x1B, + 0x89, 0xC5, 0xFC, 0xE2, 0xEA, 0x4B, 0x6A, 0x97 + }); + public static readonly PwUuid AppExit = new PwUuid(new byte[] { + 0x82, 0x8A, 0xB7, 0xAB, 0xB1, 0x1C, 0x4E, 0xBF, + 0x80, 0x39, 0x36, 0x3F, 0x91, 0x71, 0x97, 0x78 + }); + public static readonly PwUuid CustomTbButtonClicked = new PwUuid(new byte[] { + 0x47, 0x47, 0x59, 0x92, 0x97, 0xA7, 0x43, 0xA2, + 0xB9, 0x68, 0x1F, 0x1F, 0xC2, 0xF7, 0x9B, 0x92 + }); + public static readonly PwUuid TimePeriodic = new PwUuid(new byte[] { + 0x6C, 0x44, 0xBB, 0x5D, 0xF1, 0x8B, 0x4C, 0x0D, + 0x88, 0xCE, 0x65, 0xE6, 0xE9, 0xAD, 0x29, 0x8A + }); + + // Obsolete + internal static readonly PwUuid UpdatedUIState = new PwUuid(new byte[] { + 0x8D, 0x12, 0xD4, 0x9A, 0xF2, 0xCB, 0x4F, 0xF7, + 0xA8, 0xEF, 0xCF, 0xDA, 0xAC, 0x62, 0x68, 0x99 + }); + } + + internal sealed class EcasDefaultEventProvider : EcasEventProvider + { + public EcasDefaultEventProvider() + { + EcasParameter[] epFileFilter = new EcasParameter[] { + new EcasParameter(KPRes.FileOrUrl + " - " + KPRes.Comparison, + EcasValueType.EnumStrings, EcasUtil.StdStringCompare), + new EcasParameter(KPRes.FileOrUrl + " - " + KPRes.Filter, + EcasValueType.String, null) }; + EcasParameter[] epValueFilter = new EcasParameter[] { + new EcasParameter(KPRes.Value + " - " + KPRes.Comparison, + EcasValueType.EnumStrings, EcasUtil.StdStringCompare), + new EcasParameter(KPRes.Value + " - " + KPRes.Filter, + EcasValueType.String, null) }; + + m_events.Add(new EcasEventType(EcasEventIDs.AppInitPost, + KPRes.ApplicationInitialized, PwIcon.ProgramIcons, null, null)); + m_events.Add(new EcasEventType(EcasEventIDs.AppLoadPost, + KPRes.ApplicationStarted, PwIcon.ProgramIcons, null, null)); + m_events.Add(new EcasEventType(EcasEventIDs.AppExit, + KPRes.ApplicationExit, PwIcon.ProgramIcons, null, null)); + m_events.Add(new EcasEventType(EcasEventIDs.OpenedDatabaseFile, + KPRes.OpenedDatabaseFile, PwIcon.FolderOpen, epFileFilter, + IsMatchIocDbEvent)); + m_events.Add(new EcasEventType(EcasEventIDs.SavingDatabaseFile, + KPRes.SavingDatabaseFile, PwIcon.Disk, epFileFilter, + IsMatchIocDbEvent)); + m_events.Add(new EcasEventType(EcasEventIDs.SavedDatabaseFile, + KPRes.SavedDatabaseFile, PwIcon.Disk, epFileFilter, + IsMatchIocDbEvent)); + m_events.Add(new EcasEventType(EcasEventIDs.SynchronizingDatabaseFile, + KPRes.SynchronizingDatabaseFile, PwIcon.Disk, epFileFilter, + IsMatchIocDbEvent)); + m_events.Add(new EcasEventType(EcasEventIDs.SynchronizedDatabaseFile, + KPRes.SynchronizedDatabaseFile, PwIcon.Disk, epFileFilter, + IsMatchIocDbEvent)); + m_events.Add(new EcasEventType(EcasEventIDs.ClosingDatabaseFilePre, + KPRes.ClosingDatabaseFile + " (" + KPRes.SavingPre + ")", + PwIcon.PaperQ, epFileFilter, IsMatchIocDbEvent)); + m_events.Add(new EcasEventType(EcasEventIDs.ClosingDatabaseFilePost, + KPRes.ClosingDatabaseFile + " (" + KPRes.SavingPost + ")", + PwIcon.PaperQ, epFileFilter, IsMatchIocDbEvent)); + m_events.Add(new EcasEventType(EcasEventIDs.CopiedEntryInfo, + KPRes.CopiedEntryData, PwIcon.ClipboardReady, epValueFilter, + IsMatchTextEvent)); + // m_events.Add(new EcasEventType(EcasEventIDs.UpdatedUIState, + // KPRes.UpdatedUIState, PwIcon.PaperReady, null, null)); + m_events.Add(new EcasEventType(EcasEventIDs.TimePeriodic, + KPRes.Time + " - " + KPRes.Periodic, PwIcon.Clock, new EcasParameter[] { + new EcasParameter(KPRes.Interval + " [s]", EcasValueType.UInt64, null), + new EcasParameter(KPRes.TimerRestartOnActivity, EcasValueType.Bool, null) }, + IsMatchTimePeriodicEvent)); + m_events.Add(new EcasEventType(EcasEventIDs.CustomTbButtonClicked, + KPRes.CustomTbButtonClicked, PwIcon.Star, new EcasParameter[] { + new EcasParameter(KPRes.Id, EcasValueType.String, null) }, + IsMatchIdEvent)); + } + + private static bool IsMatchIocDbEvent(EcasEvent e, EcasContext ctx) + { + uint uCompareType = EcasUtil.GetParamEnum(e.Parameters, 0, + EcasUtil.StdStringCompareEquals, EcasUtil.StdStringCompare); + + string strFilter = EcasUtil.GetParamString(e.Parameters, 1, true); + if(string.IsNullOrEmpty(strFilter)) return true; + + // Must prefer IOC (e.g. for SavingDatabaseFile) + IOConnectionInfo ioc = ctx.Properties.Get( + EcasProperty.IOConnectionInfo); + if(ioc == null) + { + PwDatabase pd = ctx.Properties.Get(EcasProperty.Database); + if(pd == null) { Debug.Assert(false); return false; } + + ioc = pd.IOConnectionInfo; + } + if(ioc == null) { Debug.Assert(false); return false; } + string strCurFile = ioc.Path; + if(string.IsNullOrEmpty(strCurFile)) return false; + + return EcasUtil.CompareStrings(strCurFile, strFilter, uCompareType); + } + + private static bool IsMatchTextEvent(EcasEvent e, EcasContext ctx) + { + uint uCompareType = EcasUtil.GetParamEnum(e.Parameters, 0, + EcasUtil.StdStringCompareEquals, EcasUtil.StdStringCompare); + + string strFilter = EcasUtil.GetParamString(e.Parameters, 1, true); + if(string.IsNullOrEmpty(strFilter)) return true; + + string str = ctx.Properties.Get(EcasProperty.Text); + if(str == null) { Debug.Assert(false); return false; } + + return EcasUtil.CompareStrings(str, strFilter, uCompareType); + } + + private static bool IsMatchIdEvent(EcasEvent e, EcasContext ctx) + { + string strIdRef = EcasUtil.GetParamString(e.Parameters, 0, true); + if(string.IsNullOrEmpty(strIdRef)) return true; + + string strIdCur = ctx.Properties.Get(EcasProperty.CommandID); + if(string.IsNullOrEmpty(strIdCur)) return false; + + return strIdRef.Equals(strIdCur, StrUtil.CaseIgnoreCmp); + } + + private static bool IsMatchTimePeriodicEvent(EcasEvent e, EcasContext ctx) + { + long lRun = e.RunAtTicks; + bool bRestart = true, bRun = false; + + if(lRun >= 0) + { + DateTime dtNow = DateTime.UtcNow; + + if(dtNow.Ticks >= lRun) bRun = true; + else bRestart = false; + } + + if(bRestart) + { + if(!e.RestartTimer()) return false; + } + + return bRun; + } + } +} diff --git a/src/KeePass/Ecas/EcasEnum.cs b/src/KeePass/Ecas/EcasEnum.cs new file mode 100644 index 0000000..d582424 --- /dev/null +++ b/src/KeePass/Ecas/EcasEnum.cs @@ -0,0 +1,101 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePass.Resources; + +using KeePassLib.Utility; + +namespace KeePass.Ecas +{ + public sealed class EcasEnum + { + private EcasEnumItem[] m_vItems; + public EcasEnumItem[] Items + { + get { return m_vItems; } + } + + public int ItemCount + { + get { return m_vItems.Length; } + } + + public EcasEnum(EcasEnumItem[] vItems) + { + if(vItems == null) throw new ArgumentNullException("vItems"); + + m_vItems = vItems; + } + + public uint GetItemID(string strName, uint uDefaultIfNotFound) + { + if(strName == null) throw new ArgumentNullException("strName"); + + foreach(EcasEnumItem e in m_vItems) + { + if(e.Name == strName) return e.ID; + } + + return uDefaultIfNotFound; + } + + /// + /// Get the localized descriptive text of an enumeration item. + /// + /// ID of the enumeration item. + /// Default value, may be null. + /// Localized enumeration item text or the default value. + public string GetItemString(uint uID, string strDefaultIfNotFound) + { + foreach(EcasEnumItem e in m_vItems) + { + if(e.ID == uID) return e.Name; + } + + return strDefaultIfNotFound; + } + } + + public sealed class EcasEnumItem + { + private uint m_id; + public uint ID + { + get { return m_id; } + } + + private string m_name; + public string Name + { + get { return m_name; } + } + + public EcasEnumItem(uint uID, string strName) + { + if(strName == null) throw new ArgumentNullException("strName"); + + m_id = uID; + m_name = strName; + } + } +} diff --git a/src/KeePass/Ecas/EcasEvent.cs b/src/KeePass/Ecas/EcasEvent.cs new file mode 100644 index 0000000..4809077 --- /dev/null +++ b/src/KeePass/Ecas/EcasEvent.cs @@ -0,0 +1,112 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Xml.Serialization; + +using KeePassLib; +using KeePassLib.Interfaces; + +namespace KeePass.Ecas +{ + public sealed class EcasEvent : IDeepCloneable, IEcasObject + { + private PwUuid m_type = PwUuid.Zero; + [XmlIgnore] + public PwUuid Type + { + get { return m_type; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_type = value; + } + } + + [XmlElement("TypeGuid")] + public string TypeString + { + get { return Convert.ToBase64String(m_type.UuidBytes, Base64FormattingOptions.None); } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_type = new PwUuid(Convert.FromBase64String(value)); + } + } + + private List m_params = new List(); + [XmlArrayItem("Parameter")] + public List Parameters + { + get { return m_params; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_params = value; + } + } + + private long m_lRunAtTicks = -1; + [XmlIgnore] + internal long RunAtTicks + { + get { return m_lRunAtTicks; } + set { m_lRunAtTicks = value; } + } + + public EcasEvent() + { + } + + public EcasEvent CloneDeep() + { + EcasEvent e = new EcasEvent(); + + e.m_type = m_type; // PwUuid is immutable + + for(int i = 0; i < m_params.Count; ++i) + e.m_params.Add(m_params[i]); + + return e; + } + + internal bool RestartTimer() + { + if(!m_type.Equals(EcasEventIDs.TimePeriodic)) { Debug.Assert(false); return false; } + + uint s = EcasUtil.GetParamUInt(m_params, 0); + if(s == 0) return false; + +#if DEBUG + // StackTrace st = new StackTrace(false); + // Trace.WriteLine("[" + (Environment.TickCount / 1000).ToString() + + // "] Restarting timer... (" + st.GetFrame(3).GetMethod().Name + + // " -> " + st.GetFrame(2).GetMethod().Name + + // " -> " + st.GetFrame(1).GetMethod().Name + ")."); +#endif + + DateTime dtNow = DateTime.UtcNow; + m_lRunAtTicks = dtNow.AddSeconds((double)s - 0.45).Ticks; + return true; + } + } +} diff --git a/src/KeePass/Ecas/EcasEventProvider.cs b/src/KeePass/Ecas/EcasEventProvider.cs new file mode 100644 index 0000000..ac90069 --- /dev/null +++ b/src/KeePass/Ecas/EcasEventProvider.cs @@ -0,0 +1,91 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +using KeePassLib; + +namespace KeePass.Ecas +{ + public abstract class EcasEventProvider + { + protected List m_events = new List(); + + internal List Events + { + get { return m_events; } + } + + public bool IsSupported(PwUuid uuidType) + { + if(uuidType == null) throw new ArgumentNullException("uuidType"); + + foreach(EcasEventType t in m_events) + { + if(t.Type.Equals(uuidType)) + return true; + } + + return false; + } + + public EcasEventType Find(string strEventName) + { + if(strEventName == null) throw new ArgumentNullException("strEventName"); + + foreach(EcasEventType t in m_events) + { + if(t.Name == strEventName) return t; + } + + return null; + } + + public EcasEventType Find(PwUuid uuid) + { + if(uuid == null) throw new ArgumentNullException("uuid"); + + foreach(EcasEventType t in m_events) + { + if(t.Type.Equals(uuid)) return t; + } + + return null; + } + + public bool Compare(EcasEvent e, EcasContext ctx) + { + if(e == null) throw new ArgumentNullException("e"); + if(ctx == null) throw new ArgumentNullException("ctx"); + + Debug.Assert(e.Type.Equals(ctx.Event.Type)); + + foreach(EcasEventType t in m_events) + { + if(t.Type.Equals(e.Type)) + return t.CompareMethod(e, ctx); + } + + throw new NotSupportedException(); + } + } +} diff --git a/src/KeePass/Ecas/EcasEventType.cs b/src/KeePass/Ecas/EcasEventType.cs new file mode 100644 index 0000000..4e51375 --- /dev/null +++ b/src/KeePass/Ecas/EcasEventType.cs @@ -0,0 +1,83 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePassLib; + +namespace KeePass.Ecas +{ + public delegate bool EcasEventCompare(EcasEvent e, EcasContext ctx); + + public sealed class EcasEventType : IEcasParameterized + { + private PwUuid m_type; + public PwUuid Type + { + get { return m_type; } + } + + private string m_strName; + public string Name + { + get { return m_strName; } + } + + private PwIcon m_pwIcon; + public PwIcon Icon + { + get { return m_pwIcon; } + } + + private EcasParameter[] m_vParams; + public EcasParameter[] Parameters + { + get { return m_vParams; } + } + + private EcasEventCompare m_fn; + public EcasEventCompare CompareMethod + { + get { return m_fn; } + } + + private static bool EcasEventCompareTrue(EcasEvent e, EcasContext ctx) + { + return true; + } + + public EcasEventType(PwUuid uuidType, string strName, PwIcon pwIcon, + EcasParameter[] vParams, EcasEventCompare f) + { + if((uuidType == null) || PwUuid.Zero.Equals(uuidType)) + throw new ArgumentNullException("uuidType"); + if(strName == null) throw new ArgumentNullException("strName"); + // if(vParams == null) throw new ArgumentNullException("vParams"); + // if(f == null) throw new ArgumentNullException("f"); + + m_type = uuidType; + m_strName = strName; + m_pwIcon = pwIcon; + m_vParams = (vParams ?? EcasParameter.EmptyArray); + m_fn = (f ?? EcasEventCompareTrue); + } + } +} diff --git a/src/KeePass/Ecas/EcasParameter.cs b/src/KeePass/Ecas/EcasParameter.cs new file mode 100644 index 0000000..0fa3fe1 --- /dev/null +++ b/src/KeePass/Ecas/EcasParameter.cs @@ -0,0 +1,69 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePassLib.Utility; + +namespace KeePass.Ecas +{ + public sealed class EcasParameter + { + public static EcasParameter[] EmptyArray + { + get { return MemUtil.EmptyArray(); } + } + + private string m_strName; + public string Name + { + get { return m_strName; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strName = value; + } + } + + private EcasValueType m_type; + public EcasValueType Type + { + get { return m_type; } + set { m_type = value; } + } + + private EcasEnum m_vEnumValues; + public EcasEnum EnumValues + { + get { return m_vEnumValues; } + set { m_vEnumValues = value; } // May be null + } + + public EcasParameter(string strName, EcasValueType t, EcasEnum eEnumValues) + { + if(strName == null) throw new ArgumentNullException("strName"); + + m_strName = strName; + m_type = t; + m_vEnumValues = eEnumValues; + } + } +} diff --git a/src/KeePass/Ecas/EcasPool.cs b/src/KeePass/Ecas/EcasPool.cs new file mode 100644 index 0000000..1ce8af1 --- /dev/null +++ b/src/KeePass/Ecas/EcasPool.cs @@ -0,0 +1,235 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePass.Resources; +using KeePassLib; +using KeePassLib.Utility; + +namespace KeePass.Ecas +{ + public sealed class EcasPool + { + private List m_vEventProviders = + new List(); + private List m_vConditionProviders = + new List(); + private List m_vActionProviders = + new List(); + + internal List EventProviders + { + get { return m_vEventProviders; } + } + + internal List ConditionProviders + { + get { return m_vConditionProviders; } + } + + internal List ActionProviders + { + get { return m_vActionProviders; } + } + + public EcasPool() + { + } + + public EcasPool(bool bAddDefaultProviders) + { + if(bAddDefaultProviders) AddDefaultProviders(); + } + + private void AddDefaultProviders() + { + m_vEventProviders.Add(new EcasDefaultEventProvider()); + m_vConditionProviders.Add(new EcasDefaultConditionProvider()); + m_vActionProviders.Add(new EcasDefaultActionProvider()); + } + + public void AddEventProvider(EcasEventProvider p) + { + if(p == null) throw new ArgumentNullException("p"); + m_vEventProviders.Add(p); + } + + public bool RemoveEventProvider(EcasEventProvider p) + { + if(p == null) throw new ArgumentNullException("p"); + return m_vEventProviders.Remove(p); + } + + public EcasEventType FindEvent(string strEventName) + { + if(strEventName == null) throw new ArgumentNullException("strEventName"); + + foreach(EcasEventProvider p in m_vEventProviders) + { + EcasEventType t = p.Find(strEventName); + if(t != null) return t; + } + + return null; + } + + public EcasEventType FindEvent(PwUuid uuid) + { + if(uuid == null) throw new ArgumentNullException("uuid"); + + foreach(EcasEventProvider p in m_vEventProviders) + { + EcasEventType t = p.Find(uuid); + if(t != null) return t; + } + + return null; + } + + public void AddConditionProvider(EcasConditionProvider p) + { + if(p == null) throw new ArgumentNullException("p"); + m_vConditionProviders.Add(p); + } + + public bool RemoveConditionProvider(EcasConditionProvider p) + { + if(p == null) throw new ArgumentNullException("p"); + return m_vConditionProviders.Remove(p); + } + + public EcasConditionType FindCondition(string strConditionName) + { + if(strConditionName == null) throw new ArgumentNullException("strConditionName"); + + foreach(EcasConditionProvider p in m_vConditionProviders) + { + EcasConditionType t = p.Find(strConditionName); + if(t != null) return t; + } + + return null; + } + + public EcasConditionType FindCondition(PwUuid uuid) + { + if(uuid == null) throw new ArgumentNullException("uuid"); + + foreach(EcasConditionProvider p in m_vConditionProviders) + { + EcasConditionType t = p.Find(uuid); + if(t != null) return t; + } + + return null; + } + + public void AddActionProvider(EcasActionProvider p) + { + if(p == null) throw new ArgumentNullException("p"); + m_vActionProviders.Add(p); + } + + public bool RemoveActionProvider(EcasActionProvider p) + { + if(p == null) throw new ArgumentNullException("p"); + return m_vActionProviders.Remove(p); + } + + public EcasActionType FindAction(string strActionName) + { + if(strActionName == null) throw new ArgumentNullException("strActionName"); + + foreach(EcasActionProvider p in m_vActionProviders) + { + EcasActionType t = p.Find(strActionName); + if(t != null) return t; + } + + return null; + } + + public EcasActionType FindAction(PwUuid uuid) + { + if(uuid == null) throw new ArgumentNullException("uuid"); + + foreach(EcasActionProvider p in m_vActionProviders) + { + EcasActionType t = p.Find(uuid); + if(t != null) return t; + } + + return null; + } + + public bool CompareEvents(EcasEvent e, EcasContext ctx) + { + if(e == null) throw new ArgumentNullException("e"); + if(ctx == null) throw new ArgumentNullException("ctx"); + + if(!e.Type.Equals(ctx.Event.Type)) return false; + + foreach(EcasEventProvider p in m_vEventProviders) + { + if(p.IsSupported(e.Type)) + return p.Compare(e, ctx); + } + + throw new Exception(KPRes.TriggerEventTypeUnknown + " " + + KPRes.TypeUnknownHint + MessageService.NewParagraph + e.TypeString); + } + + public bool EvaluateCondition(EcasCondition c, EcasContext ctx) + { + if(c == null) throw new ArgumentNullException("c"); + + foreach(EcasConditionProvider p in m_vConditionProviders) + { + if(p.IsSupported(c.Type)) + { + bool bResult = p.Evaluate(c, ctx); + return (c.Negate ? !bResult : bResult); + } + } + + throw new Exception(KPRes.TriggerConditionTypeUnknown + " " + + KPRes.TypeUnknownHint + MessageService.NewParagraph + c.TypeString); + } + + public void ExecuteAction(EcasAction a, EcasContext ctx) + { + if(a == null) throw new ArgumentNullException("a"); + + foreach(EcasActionProvider p in m_vActionProviders) + { + if(p.IsSupported(a.Type)) + { + p.Execute(a, ctx); + return; + } + } + + throw new Exception(KPRes.TriggerActionTypeUnknown + " " + + KPRes.TypeUnknownHint + MessageService.NewParagraph + a.TypeString); + } + } +} diff --git a/src/KeePass/Ecas/EcasPropertyDictionary.cs b/src/KeePass/Ecas/EcasPropertyDictionary.cs new file mode 100644 index 0000000..83691ef --- /dev/null +++ b/src/KeePass/Ecas/EcasPropertyDictionary.cs @@ -0,0 +1,69 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace KeePass.Ecas +{ + public static class EcasProperty + { + // Triggering objects + public static readonly string Database = "Database"; // PwDatabase + public static readonly string IOConnectionInfo = "IOConnectionInfo"; // IOConnectionInfo + public static readonly string Text = "Text"; // String + public static readonly string CommandID = "CommandID"; // String + } + + public sealed class EcasPropertyDictionary + { + private Dictionary m_dict = new Dictionary(); + + public EcasPropertyDictionary() + { + } + + public void Set(string strKey, object oValue) + { + if(string.IsNullOrEmpty(strKey)) { Debug.Assert(false); return; } + + m_dict[strKey] = oValue; + } + + public T Get(string strKey) + where T : class + { + if(string.IsNullOrEmpty(strKey)) { Debug.Assert(false); return null; } + + object o; + if(m_dict.TryGetValue(strKey, out o)) + { + if(o == null) return null; + + T p = (o as T); + Debug.Assert(p != null); + return p; + } + + return null; + } + } +} diff --git a/src/KeePass/Ecas/EcasSystemEvents.cs b/src/KeePass/Ecas/EcasSystemEvents.cs new file mode 100644 index 0000000..108f5ec --- /dev/null +++ b/src/KeePass/Ecas/EcasSystemEvents.cs @@ -0,0 +1,46 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; + +using KeePass.Util; + +namespace KeePass.Ecas +{ + public sealed class EcasRaisingEventArgs : CancellableOperationEventArgs + { + private EcasEvent m_evt; + public EcasEvent Event + { + get { return m_evt; } + } + + private EcasPropertyDictionary m_props; + public EcasPropertyDictionary Properties + { + get { return m_props; } + } + + public EcasRaisingEventArgs(EcasEvent evt, EcasPropertyDictionary props) + { + m_evt = evt; + m_props = props; + } + } +} diff --git a/src/KeePass/Ecas/EcasTrigger.cs b/src/KeePass/Ecas/EcasTrigger.cs new file mode 100644 index 0000000..ebb3483 --- /dev/null +++ b/src/KeePass/Ecas/EcasTrigger.cs @@ -0,0 +1,248 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; +using System.ComponentModel; +using System.Diagnostics; + +using KeePassLib; +using KeePassLib.Collections; +using KeePassLib.Interfaces; + +namespace KeePass.Ecas +{ + [DebuggerDisplay("Name = {m_strName}")] + public sealed class EcasTrigger : IDeepCloneable + { + private PwUuid m_uuid = PwUuid.Zero; + [XmlIgnore] + public PwUuid Uuid + { + get { return m_uuid; } + set + { + if(value == null) throw new ArgumentNullException("value"); + + m_uuid = value; + } + } + + [XmlElement("Guid")] + public string UuidString + { + get { return Convert.ToBase64String(m_uuid.UuidBytes, Base64FormattingOptions.None); } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_uuid = new PwUuid(Convert.FromBase64String(value)); + } + } + + private string m_strName = string.Empty; + [DefaultValue("")] + public string Name + { + get { return m_strName; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strName = value; + } + } + + private string m_strComments = string.Empty; + [DefaultValue("")] + public string Comments + { + get { return m_strComments; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_strComments = value; + } + } + + private bool m_bEnabled = true; + [DefaultValue(true)] + public bool Enabled + { + get { return m_bEnabled; } + set { m_bEnabled = value; } + } + + private bool m_bInitiallyOn = true; + [DefaultValue(true)] + public bool InitiallyOn + { + get { return m_bInitiallyOn; } + set { m_bInitiallyOn = value; } + } + + private bool m_bOn = true; + [XmlIgnore] + public bool On + { + get { return m_bOn; } + set { m_bOn = value; } + } + + private bool m_bTurnOffAfterAction = false; + [DefaultValue(false)] + public bool TurnOffAfterAction + { + get { return m_bTurnOffAfterAction; } + set { m_bTurnOffAfterAction = value; } + } + + private PwObjectList m_events = new PwObjectList(); + [XmlIgnore] + public PwObjectList EventCollection + { + get { return m_events; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_events = value; + } + } + + [XmlArray("Events")] + [XmlArrayItem("Event")] + public EcasEvent[] EventArrayForSerialization + { + get { return m_events.CloneShallowToList().ToArray(); } + set { m_events = PwObjectList.FromArray(value); } + } + + private PwObjectList m_conds = new PwObjectList(); + [XmlIgnore] + public PwObjectList ConditionCollection + { + get { return m_conds; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_conds = value; + } + } + + [XmlArray("Conditions")] + [XmlArrayItem("Condition")] + public EcasCondition[] ConditionsArrayForSerialization + { + get { return m_conds.CloneShallowToList().ToArray(); } + set { m_conds = PwObjectList.FromArray(value); } + } + + private PwObjectList m_acts = new PwObjectList(); + [XmlIgnore] + public PwObjectList ActionCollection + { + get { return m_acts; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_acts = value; + } + } + + [XmlArray("Actions")] + [XmlArrayItem("Action")] + public EcasAction[] ActionArrayForSerialization + { + get { return m_acts.CloneShallowToList().ToArray(); } + set { m_acts = PwObjectList.FromArray(value); } + } + + public EcasTrigger() + { + } + + public EcasTrigger(bool bCreateNewUuid) + { + if(bCreateNewUuid) m_uuid = new PwUuid(true); + } + + public EcasTrigger CloneDeep() + { + EcasTrigger e = new EcasTrigger(false); + + e.m_uuid = m_uuid; // PwUuid is immutable + e.m_strName = m_strName; + e.m_strComments = m_strComments; + e.m_bEnabled = m_bEnabled; + e.m_bInitiallyOn = m_bInitiallyOn; + e.m_bOn = m_bOn; + e.m_bTurnOffAfterAction = m_bTurnOffAfterAction; + + for(uint i = 0; i < m_events.UCount; ++i) + e.m_events.Add(m_events.GetAt(i).CloneDeep()); + + for(uint j = 0; j < m_conds.UCount; ++j) + e.m_conds.Add(m_conds.GetAt(j).CloneDeep()); + + for(uint k = 0; k < m_acts.UCount; ++k) + e.m_acts.Add(m_acts.GetAt(k).CloneDeep()); + + return e; + } + + internal void SetToInitialState() + { + m_bOn = m_bInitiallyOn; + } + + public void RunIfMatching(EcasEvent ctxOccured, EcasPropertyDictionary props) + { + if(!m_bEnabled || !m_bOn) return; + + EcasContext ctx = new EcasContext(Program.TriggerSystem, this, + ctxOccured, props); + + bool bEventMatches = false; + foreach(EcasEvent e in m_events) + { + if(Program.EcasPool.CompareEvents(e, ctx)) + { + bEventMatches = true; + break; + } + } + if(!bEventMatches) return; + + foreach(EcasCondition c in m_conds) + { + if(!Program.EcasPool.EvaluateCondition(c, ctx)) + return; + } + + foreach(EcasAction a in m_acts) + { + if(ctx.Cancel) break; + + Program.EcasPool.ExecuteAction(a, ctx); + } + + if(m_bTurnOffAfterAction) m_bOn = false; + } + } +} diff --git a/src/KeePass/Ecas/EcasTriggerSystem.cs b/src/KeePass/Ecas/EcasTriggerSystem.cs new file mode 100644 index 0000000..6aa95aa --- /dev/null +++ b/src/KeePass/Ecas/EcasTriggerSystem.cs @@ -0,0 +1,242 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Windows.Forms; +using System.Xml.Serialization; + +using KeePass.App; +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Collections; +using KeePassLib.Interfaces; +using KeePassLib.Utility; + +namespace KeePass.Ecas +{ + public sealed class EcasTriggerSystem : IDeepCloneable + { + private bool m_bEnabled = true; + [DefaultValue(true)] + public bool Enabled + { + get { return m_bEnabled; } + set { m_bEnabled = value; } + } + + private PwObjectList m_vTriggers = new PwObjectList(); + [XmlIgnore] + public PwObjectList TriggerCollection + { + get { return m_vTriggers; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_vTriggers = value; + } + } + + [XmlArray("Triggers")] + [XmlArrayItem("Trigger")] + public EcasTrigger[] TriggerArrayForSerialization + { + get { return m_vTriggers.CloneShallowToList().ToArray(); } + set { m_vTriggers = PwObjectList.FromArray(value); } + } + + public event EventHandler RaisingEvent; + + public EcasTriggerSystem() + { + } + + public EcasTriggerSystem CloneDeep() + { + EcasTriggerSystem c = new EcasTriggerSystem(); + + c.m_bEnabled = m_bEnabled; + + for(uint i = 0; i < m_vTriggers.UCount; ++i) + c.m_vTriggers.Add(m_vTriggers.GetAt(i).CloneDeep()); + + return c; + } + + internal void SetToInitialState() + { + for(uint i = 0; i < m_vTriggers.UCount; ++i) + m_vTriggers.GetAt(i).SetToInitialState(); + } + + public object FindObjectByUuid(PwUuid pwUuid) + { + if(pwUuid == null) throw new ArgumentNullException("pwUuid"); + + foreach(EcasTrigger t in m_vTriggers) + { + if(t.Uuid.Equals(pwUuid)) return t; + + foreach(EcasEvent e in t.EventCollection) + { + if(e.Type.Equals(pwUuid)) return e; + } + + foreach(EcasCondition c in t.ConditionCollection) + { + if(c.Type.Equals(pwUuid)) return c; + } + + foreach(EcasAction a in t.ActionCollection) + { + if(a.Type.Equals(pwUuid)) return a; + } + } + + return null; + } + + public void RaiseEvent(PwUuid eventType) + { + RaiseEvent(eventType, null); + } + + internal void RaiseEvent(PwUuid eventType, string strPropKey, + object oPropValue) + { + EcasPropertyDictionary d = new EcasPropertyDictionary(); + d.Set(strPropKey, oPropValue); + + RaiseEvent(eventType, d); + } + + public void RaiseEvent(PwUuid eventType, EcasPropertyDictionary props) + { + if(eventType == null) throw new ArgumentNullException("eventType"); + // if(props == null) throw new ArgumentNullException("props"); + + if(!m_bEnabled) return; + + EcasEvent e = new EcasEvent(); + e.Type = eventType; + + RaiseEventObj(e, (props ?? new EcasPropertyDictionary())); + } + + private void RaiseEventObj(EcasEvent e, EcasPropertyDictionary props) + { + // if(e == null) throw new ArgumentNullException("e"); + // if(!m_bEnabled) return; + + if(this.RaisingEvent != null) + { + EcasRaisingEventArgs args = new EcasRaisingEventArgs(e, props); + this.RaisingEvent(this, args); + if(args.Cancel) return; + } + + try + { + foreach(EcasTrigger t in m_vTriggers) + t.RunIfMatching(e, props); + } + catch(Exception ex) + { + if(!VistaTaskDialog.ShowMessageBox(ex.Message, KPRes.TriggerExecutionFailed, + PwDefs.ShortProductName, VtdIcon.Warning, null)) + { + MessageService.ShowWarning(KPRes.TriggerExecutionFailed + ".", ex); + } + } + } + + internal void NotifyUserActivity() + { + // if(!m_bEnabled) return; + + foreach(EcasTrigger t in m_vTriggers) + { + foreach(EcasEvent e in t.EventCollection) + { + if(!e.Type.Equals(EcasEventIDs.TimePeriodic)) continue; + + if(EcasUtil.GetParamBool(e.Parameters, 1)) + e.RestartTimer(); + } + } + } + + internal void CheckTriggers() + { + bool bUIStateUpd = false; + + foreach(EcasTrigger t in m_vTriggers) + { + foreach(EcasEvent e in t.EventCollection) + { + if(e.Type.Equals(EcasEventIDs.UpdatedUIState)) bUIStateUpd = true; + } + } + + if(bUIStateUpd) + { + string str = KPRes.Event + ": '" + KPRes.UpdatedUIState + "'." + + MessageService.NewParagraph + KPRes.TriggerEventTypeUnknown + + MessageService.NewParagraph + KPRes.MoreInfo + ":" + + MessageService.NewLine; + string strUrl = AppHelp.GetOnlineUrl(AppDefs.HelpTopics.TriggerUIStateUpd, null); + + string strVtd = str + VistaTaskDialog.CreateLink(strUrl, strUrl); + + VistaTaskDialog vtd = new VistaTaskDialog(); + vtd.AddButton((int)DialogResult.Cancel, KPRes.Ok, null); + vtd.Content = strVtd; + vtd.DefaultButtonID = (int)DialogResult.Cancel; + vtd.EnableHyperlinks = true; + vtd.SetIcon(VtdIcon.Warning); + vtd.WindowTitle = PwDefs.ShortProductName; + + if(!vtd.ShowDialog()) + MessageService.ShowWarning(str + strUrl); + } + } + } + + [XmlRoot("TriggerCollection")] + public sealed class EcasTriggerContainer + { + private List m_vTriggers = new List(); + [XmlArrayItem("Trigger")] + public List Triggers + { + get { return m_vTriggers; } + set + { + if(value == null) throw new ArgumentNullException("value"); + m_vTriggers = value; + } + } + + public EcasTriggerContainer() { } + } +} diff --git a/src/KeePass/Ecas/EcasUtil.cs b/src/KeePass/Ecas/EcasUtil.cs new file mode 100644 index 0000000..17ee5e7 --- /dev/null +++ b/src/KeePass/Ecas/EcasUtil.cs @@ -0,0 +1,527 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +using KeePass.Ecas; +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util.Spr; + +using KeePassLib; +using KeePassLib.Utility; + +namespace KeePass.Ecas +{ + public enum EcasTypeDxMode // Type data exchange modes + { + None = 0, + Selection, // DX with the type UI control (combobox) + ParamsTag // Get type from the parameters control + } + + public static class EcasUtil + { + public static readonly uint StdCompareEqual = 0; + public static readonly uint StdCompareNotEqual = 1; + public static readonly uint StdCompareLesser = 2; + public static readonly uint StdCompareLesserEqual = 3; + public static readonly uint StdCompareGreater = 4; + public static readonly uint StdCompareGreaterEqual = 5; + + private static EcasEnum m_enumCompare = null; + public static EcasEnum StdCompare + { + get + { + if(m_enumCompare == null) + m_enumCompare = new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem(StdCompareEqual, "="), + new EcasEnumItem(StdCompareNotEqual, "<>"), + new EcasEnumItem(StdCompareLesser, "<"), + new EcasEnumItem(StdCompareLesserEqual, "<="), + new EcasEnumItem(StdCompareGreater, ">"), + new EcasEnumItem(StdCompareGreaterEqual, ">=") }); + + return m_enumCompare; + } + } + + public static readonly uint StdStringCompareEquals = 0; + public static readonly uint StdStringCompareContains = 1; + public static readonly uint StdStringCompareStartsWith = 2; + public static readonly uint StdStringCompareEndsWith = 3; + public static readonly uint StdStringCompareRegEx = 4; + + private static EcasEnum m_enumStringCompare = null; + public static EcasEnum StdStringCompare + { + get + { + if(m_enumStringCompare == null) + m_enumStringCompare = new EcasEnum(new EcasEnumItem[] { + new EcasEnumItem(StdStringCompareEquals, KPRes.EqualsOp), + new EcasEnumItem(StdStringCompareContains, KPRes.ContainsOp), + new EcasEnumItem(StdStringCompareStartsWith, KPRes.StartsWith), + new EcasEnumItem(StdStringCompareEndsWith, KPRes.EndsWith), + new EcasEnumItem(StdStringCompareRegEx, KPRes.MatchesRegEx) }); + + return m_enumStringCompare; + } + } + + public static string GetParamString(List vParams, int iIndex) + { + return GetParamString(vParams, iIndex, string.Empty); + } + + public static string GetParamString(List vParams, int iIndex, + bool bSprCompile) + { + return GetParamString(vParams, iIndex, bSprCompile, false); + } + + public static string GetParamString(List vParams, int iIndex, + bool bSprCompile, bool bSprForCommandLine) + { + string str = GetParamString(vParams, iIndex, string.Empty); + + if(bSprCompile && !string.IsNullOrEmpty(str)) + { + PwEntry pe = null; + try { pe = Program.MainForm.GetSelectedEntry(false); } + catch(Exception) { Debug.Assert(false); } + + PwDatabase pd = Program.MainForm.DocumentManager.SafeFindContainerOf(pe); + + // The trigger system does not update the UI itself, + // thus ignore state-changing placeholders + str = SprEngine.Compile(str, new SprContext(pe, pd, + (SprCompileFlags.All & ~SprCompileFlags.StateChanging), + false, bSprForCommandLine)); + } + + return str; + } + + public static string GetParamString(List vParams, int iIndex, + string strDefault) + { + if(vParams == null) { Debug.Assert(false); return strDefault; } + if(iIndex < 0) { Debug.Assert(false); return strDefault; } + if(iIndex >= vParams.Count) return strDefault; // No assert + + return vParams[iIndex]; + } + + public static bool GetParamBool(List vParams, int iIndex) + { + string str = GetParamString(vParams, iIndex, string.Empty); + return StrUtil.StringToBool(str); + } + + public static uint GetParamUInt(List vParams, int iIndex) + { + return GetParamUInt(vParams, iIndex, 0); + } + + public static uint GetParamUInt(List vParams, int iIndex, + uint uDefault) + { + string str = GetParamString(vParams, iIndex, string.Empty); + uint u; + if(uint.TryParse(str, out u)) return u; + return uDefault; + } + + public static uint GetParamEnum(List vParams, int iIndex, + uint uDefault, EcasEnum enumItems) + { + if(enumItems == null) { Debug.Assert(false); return uDefault; } + + string str = GetParamString(vParams, iIndex, null); + if(string.IsNullOrEmpty(str)) { Debug.Assert(false); return uDefault; } + + uint uID; + if(!uint.TryParse(str, out uID)) { Debug.Assert(false); return uDefault; } + + // Make sure the enumeration contains the value + if(enumItems.GetItemString(uID, null) == null) { Debug.Assert(false); return uDefault; } + + return uID; + } + + public static void ParametersToDataGridView(DataGridView dg, + IEcasParameterized p, IEcasObject objDefaults) + { + if(dg == null) throw new ArgumentNullException("dg"); + if(p == null) throw new ArgumentNullException("p"); + if(p.Parameters == null) throw new ArgumentException(); + if(objDefaults == null) throw new ArgumentNullException("objDefaults"); + if(objDefaults.Parameters == null) throw new ArgumentException(); + + dg.Rows.Clear(); + dg.Columns.Clear(); + + Color clrFG = dg.DefaultCellStyle.ForeColor; + Color clrBG = dg.DefaultCellStyle.BackColor; + + // https://sourceforge.net/p/keepass/bugs/1808/ + if(UIUtil.IsDarkColor(clrFG) == UIUtil.IsDarkColor(clrBG)) + clrFG = (UIUtil.IsDarkColor(clrBG) ? Color.White : Color.Black); + + Color clrValueBG = clrBG; + if(UIUtil.IsDarkColor(clrBG)) + clrValueBG = UIUtil.LightenColor(clrValueBG, 0.075); + else clrValueBG = UIUtil.DarkenColor(clrValueBG, 0.075); + + dg.ColumnHeadersVisible = false; + dg.RowHeadersVisible = false; + dg.GridColor = clrBG; + dg.BackgroundColor = clrBG; + dg.DefaultCellStyle.ForeColor = clrFG; + dg.DefaultCellStyle.BackColor = clrBG; + dg.DefaultCellStyle.SelectionForeColor = clrFG; + dg.DefaultCellStyle.SelectionBackColor = clrBG; + dg.AllowDrop = false; + dg.AllowUserToAddRows = false; + dg.AllowUserToDeleteRows = false; + dg.AllowUserToOrderColumns = false; + dg.AllowUserToResizeColumns = false; + dg.AllowUserToResizeRows = false; + // dg.EditMode: see below + dg.Tag = p; + + int nWidth = (dg.ClientSize.Width - UIUtil.GetVScrollBarWidth()); + dg.Columns.Add("Name", KPRes.FieldName); + dg.Columns.Add("Value", KPRes.FieldValue); + dg.Columns[0].Width = (nWidth / 2); + dg.Columns[1].Width = (nWidth / 2); + + bool bUseDefaults = true; + if(objDefaults.Type == null) { Debug.Assert(false); } // Optimistic + else if(p.Type == null) { Debug.Assert(false); } // Optimistic + else if(!objDefaults.Type.Equals(p.Type)) bUseDefaults = false; + + for(int i = 0; i < p.Parameters.Length; ++i) + { + EcasParameter ep = p.Parameters[i]; + + dg.Rows.Add(); + DataGridViewRow row = dg.Rows[dg.Rows.Count - 1]; + DataGridViewCellCollection cc = row.Cells; + + Debug.Assert(cc.Count == 2); + cc[0].Value = ep.Name; + cc[0].ReadOnly = true; + + string strParam = (bUseDefaults ? EcasUtil.GetParamString( + objDefaults.Parameters, i) : string.Empty); + + DataGridViewCell c = null; + switch(ep.Type) + { + case EcasValueType.String: + c = new DataGridViewTextBoxCell(); + c.Value = strParam; + break; + + case EcasValueType.Bool: + c = new DataGridViewCheckBoxCell(false); + c.Value = StrUtil.StringToBool(strParam); + break; + + case EcasValueType.EnumStrings: + DataGridViewComboBoxCell cmb = new DataGridViewComboBoxCell(); + cmb.Sorted = false; + cmb.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton; + int iFound = -1; + for(int e = 0; e < ep.EnumValues.ItemCount; ++e) + { + EcasEnumItem eei = ep.EnumValues.Items[e]; + cmb.Items.Add(eei.Name); + if(eei.ID.ToString() == strParam) iFound = e; + } + if(iFound >= 0) cmb.Value = ep.EnumValues.Items[iFound].Name; + else if(ep.EnumValues.ItemCount > 0) cmb.Value = ep.EnumValues.Items[0].Name; + else { Debug.Assert(false); } + c = cmb; + break; + + case EcasValueType.Int64: + c = new DataGridViewTextBoxCell(); + c.Value = FilterTypeI64(strParam); + break; + + case EcasValueType.UInt64: + c = new DataGridViewTextBoxCell(); + c.Value = FilterTypeU64(strParam); + break; + + default: + Debug.Assert(false); + break; + } + + if(c != null) + { + cc[1] = c; + cc[1].ReadOnly = false; + } + else cc[1].ReadOnly = true; + + cc[1].Style.ForeColor = clrFG; + cc[1].Style.BackColor = clrValueBG; + cc[1].Style.SelectionForeColor = clrFG; + cc[1].Style.SelectionBackColor = clrValueBG; + } + + // Perform postponed setting of EditMode (cannot set it earlier + // due to a Mono bug on FreeBSD); + // https://sourceforge.net/p/keepass/discussion/329220/thread/cb8270e2/ + dg.EditMode = DataGridViewEditMode.EditOnEnter; + } + + public static void DataGridViewToParameters(DataGridView dg, IEcasObject objOut, + IEcasParameterized eTypeInfo) + { + if(dg == null) throw new ArgumentNullException("dg"); + if(objOut == null) throw new ArgumentNullException("objOut"); + // if(vParamDesc == null) throw new ArgumentNullException("vParamDesc"); + // if(dg.Rows.Count != vParamDesc.Length) { Debug.Assert(false); return; } + + objOut.Parameters.Clear(); + + bool bTypeInfoValid = ((eTypeInfo != null) && (eTypeInfo.Parameters.Length == + dg.Rows.Count)); + + for(int i = 0; i < dg.RowCount; ++i) + { + DataGridViewCell c = dg.Rows[i].Cells[1]; + object oValue = c.Value; + string strValue = ((oValue != null) ? oValue.ToString() : string.Empty); + + if(bTypeInfoValid && (eTypeInfo.Parameters[i].EnumValues != null) && + (c is DataGridViewComboBoxCell)) + { + objOut.Parameters.Add(eTypeInfo.Parameters[i].EnumValues.GetItemID( + strValue, 0).ToString()); + } + else objOut.Parameters.Add(strValue); + } + } + + public static bool UpdateDialog(EcasObjectType objType, ComboBox cmbTypes, + DataGridView dgvParams, IEcasObject o, bool bGuiToInternal, + EcasTypeDxMode dxType) + { + bool bResult = true; + + try + { + if(bGuiToInternal) + { + IEcasParameterized eTypeInfo = null; + + if(dxType == EcasTypeDxMode.Selection) + { + string strSel = (cmbTypes.SelectedItem as string); + if(!string.IsNullOrEmpty(strSel)) + { + if(objType == EcasObjectType.Event) + { + eTypeInfo = Program.EcasPool.FindEvent(strSel); + o.Type = eTypeInfo.Type; + } + else if(objType == EcasObjectType.Condition) + { + eTypeInfo = Program.EcasPool.FindCondition(strSel); + o.Type = eTypeInfo.Type; + } + else if(objType == EcasObjectType.Action) + { + eTypeInfo = Program.EcasPool.FindAction(strSel); + o.Type = eTypeInfo.Type; + } + else { Debug.Assert(false); } + } + } + else if(dxType == EcasTypeDxMode.ParamsTag) + { + IEcasParameterized p = (dgvParams.Tag as IEcasParameterized); + if((p != null) && (p.Type != null)) + { + eTypeInfo = p; + o.Type = eTypeInfo.Type; + } + else { Debug.Assert(false); } + } + + EcasUtil.DataGridViewToParameters(dgvParams, o, eTypeInfo); + } + else // Internal to GUI + { + if(dxType == EcasTypeDxMode.Selection) + { + if(o.Type.Equals(PwUuid.Zero)) + cmbTypes.SelectedIndex = 0; + else + { + int i = -1; + if(objType == EcasObjectType.Event) + i = cmbTypes.FindString(Program.EcasPool.FindEvent(o.Type).Name); + else if(objType == EcasObjectType.Condition) + i = cmbTypes.FindString(Program.EcasPool.FindCondition(o.Type).Name); + else if(objType == EcasObjectType.Action) + i = cmbTypes.FindString(Program.EcasPool.FindAction(o.Type).Name); + else { Debug.Assert(false); } + + if(i >= 0) cmbTypes.SelectedIndex = i; + else { Debug.Assert(false); } + } + } + else { Debug.Assert(dxType != EcasTypeDxMode.ParamsTag); } + + IEcasParameterized t = null; + if(objType == EcasObjectType.Event) + t = Program.EcasPool.FindEvent(cmbTypes.SelectedItem as string); + else if(objType == EcasObjectType.Condition) + t = Program.EcasPool.FindCondition(cmbTypes.SelectedItem as string); + else if(objType == EcasObjectType.Action) + t = Program.EcasPool.FindAction(cmbTypes.SelectedItem as string); + else { Debug.Assert(false); } + + if(t != null) EcasUtil.ParametersToDataGridView(dgvParams, t, o); + } + } + catch(Exception e) { MessageService.ShowWarning(e); bResult = false; } + + return bResult; + } + + public static string ParametersToString(IEcasObject ecasObj, + EcasParameter[] vParamInfo) + { + if(ecasObj == null) throw new ArgumentNullException("ecasObj"); + if(ecasObj.Parameters == null) throw new ArgumentException(); + + bool bParamInfoValid = true; + if((vParamInfo == null) || (ecasObj.Parameters.Count > vParamInfo.Length)) + { + Debug.Assert(false); + bParamInfoValid = false; + } + + StringBuilder sb = new StringBuilder(); + + EcasCondition eCond = (ecasObj as EcasCondition); + if(eCond != null) + { + if(eCond.Negate) sb.Append(KPRes.Not); + } + + for(int i = 0; i < ecasObj.Parameters.Count; ++i) + { + string strParam = ecasObj.Parameters[i]; + string strAppend; + + if(bParamInfoValid) + { + EcasValueType t = vParamInfo[i].Type; + if(t == EcasValueType.String) + strAppend = strParam; + else if(t == EcasValueType.Bool) + strAppend = (StrUtil.StringToBool(strParam) ? KPRes.Yes : KPRes.No); + else if(t == EcasValueType.EnumStrings) + { + uint uEnumID; + if(!uint.TryParse(strParam, out uEnumID)) { Debug.Assert(false); } + EcasEnum ee = vParamInfo[i].EnumValues; + if(ee != null) strAppend = ee.GetItemString(uEnumID, string.Empty); + else { Debug.Assert(false); strAppend = strParam; } + } + else if(t == EcasValueType.Int64) + strAppend = FilterTypeI64(strParam); + else if(t == EcasValueType.UInt64) + strAppend = FilterTypeU64(strParam); + else { Debug.Assert(false); strAppend = strParam; } + } + else strAppend = strParam; + + if(string.IsNullOrEmpty(strAppend)) continue; + string strAppTrimmed = strAppend.Trim(); + if(strAppTrimmed.Length == 0) continue; + if(sb.Length > 0) sb.Append(", "); + sb.Append(strAppTrimmed); + } + + return sb.ToString(); + } + + public static bool CompareStrings(string x, string y, uint uCompareType) + { + if(x == null) { Debug.Assert(false); return false; } + if(y == null) { Debug.Assert(false); return false; } + + if(uCompareType == EcasUtil.StdStringCompareEquals) + return x.Equals(y, StrUtil.CaseIgnoreCmp); + if(uCompareType == EcasUtil.StdStringCompareContains) + return (x.IndexOf(y, StrUtil.CaseIgnoreCmp) >= 0); + if(uCompareType == EcasUtil.StdStringCompareStartsWith) + return x.StartsWith(y, StrUtil.CaseIgnoreCmp); + if(uCompareType == EcasUtil.StdStringCompareEndsWith) + return x.EndsWith(y, StrUtil.CaseIgnoreCmp); + if(uCompareType == EcasUtil.StdStringCompareRegEx) + { + try { return Regex.IsMatch(x, y, RegexOptions.IgnoreCase); } + catch(Exception) { Debug.Assert(false); } + return false; + } + + Debug.Assert(false); // Unknown compare type + return false; + } + + private static string FilterTypeI64(string str) + { + if(string.IsNullOrEmpty(str)) return string.Empty; + + long i64; + if(long.TryParse(str, out i64)) return i64.ToString(); + + return string.Empty; + } + + private static string FilterTypeU64(string str) + { + if(string.IsNullOrEmpty(str)) return string.Empty; + + ulong u64; + if(ulong.TryParse(str, out u64)) return u64.ToString(); + + return string.Empty; + } + } +} diff --git a/src/KeePass/Ecas/EcasValueType.cs b/src/KeePass/Ecas/EcasValueType.cs new file mode 100644 index 0000000..2e876bd --- /dev/null +++ b/src/KeePass/Ecas/EcasValueType.cs @@ -0,0 +1,33 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; + +namespace KeePass.Ecas +{ + public enum EcasValueType + { + None = 0, + String = 1, + Bool = 2, + EnumStrings = 3, + Int64 = 4, + UInt64 = 5 + } +} diff --git a/src/KeePass/Ecas/IEcasObject.cs b/src/KeePass/Ecas/IEcasObject.cs new file mode 100644 index 0000000..491f0af --- /dev/null +++ b/src/KeePass/Ecas/IEcasObject.cs @@ -0,0 +1,43 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePassLib; + +namespace KeePass.Ecas +{ + public enum EcasObjectType + { + None = 0, + Event = 1, + Condition = 2, + Action = 3 + } + + public interface IEcasObject + { + PwUuid Type { get; set; } + string TypeString { get; set; } + + List Parameters { get; set; } + } +} diff --git a/src/KeePass/Ecas/IEcasParameterized.cs b/src/KeePass/Ecas/IEcasParameterized.cs new file mode 100644 index 0000000..eb1c30e --- /dev/null +++ b/src/KeePass/Ecas/IEcasParameterized.cs @@ -0,0 +1,34 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +using KeePassLib; + +namespace KeePass.Ecas +{ + public interface IEcasParameterized + { + PwUuid Type { get; } + + EcasParameter[] Parameters { get; } + } +} diff --git a/src/KeePass/Forms/AboutForm.Designer.cs b/src/KeePass/Forms/AboutForm.Designer.cs new file mode 100644 index 0000000..4f89253 --- /dev/null +++ b/src/KeePass/Forms/AboutForm.Designer.cs @@ -0,0 +1,206 @@ +namespace KeePass.Forms +{ + partial class AboutForm + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Windows Form-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.m_bannerImage = new System.Windows.Forms.PictureBox(); + this.m_lblCopyright = new System.Windows.Forms.Label(); + this.m_lblOsi = new System.Windows.Forms.Label(); + this.m_lblGpl = new System.Windows.Forms.Label(); + this.m_linkHomepage = new System.Windows.Forms.LinkLabel(); + this.m_linkHelp = new System.Windows.Forms.LinkLabel(); + this.m_linkLicense = new System.Windows.Forms.LinkLabel(); + this.m_linkAcknowledgements = new System.Windows.Forms.LinkLabel(); + this.m_linkDonate = new System.Windows.Forms.LinkLabel(); + this.m_btnOK = new System.Windows.Forms.Button(); + this.m_lvComponents = new KeePass.UI.CustomListViewEx(); + ((System.ComponentModel.ISupportInitialize)(this.m_bannerImage)).BeginInit(); + this.SuspendLayout(); + // + // m_bannerImage + // + this.m_bannerImage.Dock = System.Windows.Forms.DockStyle.Top; + this.m_bannerImage.Location = new System.Drawing.Point(0, 0); + this.m_bannerImage.Name = "m_bannerImage"; + this.m_bannerImage.Size = new System.Drawing.Size(424, 60); + this.m_bannerImage.TabIndex = 0; + this.m_bannerImage.TabStop = false; + // + // m_lblCopyright + // + this.m_lblCopyright.Location = new System.Drawing.Point(10, 72); + this.m_lblCopyright.Name = "m_lblCopyright"; + this.m_lblCopyright.Size = new System.Drawing.Size(402, 15); + this.m_lblCopyright.TabIndex = 0; + this.m_lblCopyright.Text = "<>"; + // + // m_lblOsi + // + this.m_lblOsi.Location = new System.Drawing.Point(10, 95); + this.m_lblOsi.Name = "m_lblOsi"; + this.m_lblOsi.Size = new System.Drawing.Size(402, 15); + this.m_lblOsi.TabIndex = 1; + this.m_lblOsi.Text = "KeePass is OSI Certified Open Source Software."; + // + // m_lblGpl + // + this.m_lblGpl.Location = new System.Drawing.Point(10, 118); + this.m_lblGpl.Name = "m_lblGpl"; + this.m_lblGpl.Size = new System.Drawing.Size(402, 27); + this.m_lblGpl.TabIndex = 2; + this.m_lblGpl.Text = "The program is distributed under the terms of the GNU General Public License v2 o" + + "r later."; + // + // m_linkHomepage + // + this.m_linkHomepage.AutoSize = true; + this.m_linkHomepage.Location = new System.Drawing.Point(10, 154); + this.m_linkHomepage.Name = "m_linkHomepage"; + this.m_linkHomepage.Size = new System.Drawing.Size(91, 13); + this.m_linkHomepage.TabIndex = 3; + this.m_linkHomepage.TabStop = true; + this.m_linkHomepage.Text = "KeePass Website"; + this.m_linkHomepage.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkHomepage); + // + // m_linkHelp + // + this.m_linkHelp.AutoSize = true; + this.m_linkHelp.Location = new System.Drawing.Point(213, 154); + this.m_linkHelp.Name = "m_linkHelp"; + this.m_linkHelp.Size = new System.Drawing.Size(29, 13); + this.m_linkHelp.TabIndex = 5; + this.m_linkHelp.TabStop = true; + this.m_linkHelp.Text = "Help"; + this.m_linkHelp.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkHelpFile); + // + // m_linkLicense + // + this.m_linkLicense.AutoSize = true; + this.m_linkLicense.Location = new System.Drawing.Point(10, 176); + this.m_linkLicense.Name = "m_linkLicense"; + this.m_linkLicense.Size = new System.Drawing.Size(44, 13); + this.m_linkLicense.TabIndex = 6; + this.m_linkLicense.TabStop = true; + this.m_linkLicense.Text = "License"; + this.m_linkLicense.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkLicenseFile); + // + // m_linkAcknowledgements + // + this.m_linkAcknowledgements.AutoSize = true; + this.m_linkAcknowledgements.Location = new System.Drawing.Point(107, 154); + this.m_linkAcknowledgements.Name = "m_linkAcknowledgements"; + this.m_linkAcknowledgements.Size = new System.Drawing.Size(100, 13); + this.m_linkAcknowledgements.TabIndex = 4; + this.m_linkAcknowledgements.TabStop = true; + this.m_linkAcknowledgements.Text = "Acknowledgements"; + this.m_linkAcknowledgements.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkAcknowledgements); + // + // m_linkDonate + // + this.m_linkDonate.AutoSize = true; + this.m_linkDonate.Location = new System.Drawing.Point(107, 176); + this.m_linkDonate.Name = "m_linkDonate"; + this.m_linkDonate.Size = new System.Drawing.Size(42, 13); + this.m_linkDonate.TabIndex = 7; + this.m_linkDonate.TabStop = true; + this.m_linkDonate.Text = "Donate"; + this.m_linkDonate.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.OnLinkDonate); + // + // m_btnOK + // + this.m_btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.m_btnOK.Location = new System.Drawing.Point(337, 315); + this.m_btnOK.Name = "m_btnOK"; + this.m_btnOK.Size = new System.Drawing.Size(75, 23); + this.m_btnOK.TabIndex = 9; + this.m_btnOK.Text = "OK"; + this.m_btnOK.UseVisualStyleBackColor = true; + // + // m_lvComponents + // + this.m_lvComponents.FullRowSelect = true; + this.m_lvComponents.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.m_lvComponents.Location = new System.Drawing.Point(13, 202); + this.m_lvComponents.MultiSelect = false; + this.m_lvComponents.Name = "m_lvComponents"; + this.m_lvComponents.ShowItemToolTips = true; + this.m_lvComponents.Size = new System.Drawing.Size(398, 102); + this.m_lvComponents.TabIndex = 8; + this.m_lvComponents.UseCompatibleStateImageBehavior = false; + this.m_lvComponents.View = System.Windows.Forms.View.Details; + this.m_lvComponents.ItemActivate += new System.EventHandler(this.OnComponentShow); + // + // AboutForm + // + this.AcceptButton = this.m_btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.m_btnOK; + this.ClientSize = new System.Drawing.Size(424, 350); + this.Controls.Add(this.m_lvComponents); + this.Controls.Add(this.m_btnOK); + this.Controls.Add(this.m_linkDonate); + this.Controls.Add(this.m_linkAcknowledgements); + this.Controls.Add(this.m_linkLicense); + this.Controls.Add(this.m_linkHelp); + this.Controls.Add(this.m_linkHomepage); + this.Controls.Add(this.m_lblGpl); + this.Controls.Add(this.m_lblOsi); + this.Controls.Add(this.m_lblCopyright); + this.Controls.Add(this.m_bannerImage); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutForm"; + this.ShowInTaskbar = false; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "About KeePass"; + this.Load += new System.EventHandler(this.OnFormLoad); + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.OnFormClosed); + ((System.ComponentModel.ISupportInitialize)(this.m_bannerImage)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PictureBox m_bannerImage; + private System.Windows.Forms.Label m_lblCopyright; + private System.Windows.Forms.Label m_lblOsi; + private System.Windows.Forms.Label m_lblGpl; + private System.Windows.Forms.LinkLabel m_linkHomepage; + private System.Windows.Forms.LinkLabel m_linkHelp; + private System.Windows.Forms.LinkLabel m_linkLicense; + private System.Windows.Forms.LinkLabel m_linkAcknowledgements; + private System.Windows.Forms.LinkLabel m_linkDonate; + private System.Windows.Forms.Button m_btnOK; + private KeePass.UI.CustomListViewEx m_lvComponents; + } +} \ No newline at end of file diff --git a/src/KeePass/Forms/AboutForm.cs b/src/KeePass/Forms/AboutForm.cs new file mode 100644 index 0000000..ae8cd71 --- /dev/null +++ b/src/KeePass/Forms/AboutForm.cs @@ -0,0 +1,286 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +using KeePass.App; +using KeePass.DataExchange; +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; + +using KeePassLib; +using KeePassLib.Utility; + +namespace KeePass.Forms +{ + public partial class AboutForm : Form, IGwmWindow + { + private CustomContextMenuStripEx m_ctxComponents = null; + + public bool CanCloseWithoutDataLoss { get { return true; } } + + public AboutForm() + { + InitializeComponent(); + GlobalWindowManager.InitializeForm(this); + } + + private void OnFormLoad(object sender, EventArgs e) + { + GlobalWindowManager.AddWindow(this, this); + + string strVersion = GetMainVersion(); + + string strTitle = PwDefs.ProductName; + string strDesc = KPRes.Version + " " + strVersion; + + Icon icoSc = AppIcons.Get(AppIconType.Main, new Size( + DpiUtil.ScaleIntX(48), DpiUtil.ScaleIntY(48)), Color.Empty); + BannerFactory.CreateBannerEx(this, m_bannerImage, icoSc.ToBitmap(), + strTitle, strDesc); + this.Icon = AppIcons.Default; + + Debug.Assert(!m_lblCopyright.AutoSize); // For RTL support + m_lblCopyright.Text = PwDefs.Copyright + "."; + + try { BuildComponentsList(strVersion); } + catch(Exception) { Debug.Assert(false); } + + UIUtil.SetExplorerTheme(m_lvComponents, false); + UIUtil.ResizeColumns(m_lvComponents, true); + BuildComponentsContextMenu(); + + UIUtil.SetFocus(m_btnOK, this); + } + + private void OnFormClosed(object sender, FormClosedEventArgs e) + { + m_lvComponents.ContextMenuStrip = null; + if(m_ctxComponents != null) + { + m_ctxComponents.Dispose(); + m_ctxComponents = null; + } + + GlobalWindowManager.RemoveWindow(this); + } + + private static string GetMainVersion() + { + StringBuilder sb = new StringBuilder(); + sb.Append(PwDefs.VersionString); + + if(Program.IsDevelopmentSnapshot()) + { + sb.Append(" - Dev."); + + try + { + FileInfo fi = new FileInfo(WinUtil.GetExecutable()); + string strDate = fi.LastWriteTimeUtc.ToString("yyMMdd"); + + sb.Append(' '); + sb.Append(strDate); + } + catch(Exception) { Debug.Assert(false); } + } + + const string strParamPlh = @"{PARAM}"; + string strBits = KPRes.BitsA; + if(strBits.IndexOf(strParamPlh) >= 0) + { + sb.Append(" ("); + sb.Append(strBits.Replace(strParamPlh, (IntPtr.Size * 8).ToString())); + sb.Append(')'); + } + else { Debug.Assert(false); } + + return sb.ToString(); + } + + private void BuildComponentsList(string strMainVersion) + { + string strValueColumn = KPRes.Version + "/" + KPRes.Status; + if(Regex.IsMatch(strValueColumn, "\\s")) + strValueColumn = KPRes.Version + " / " + KPRes.Status; + + m_lvComponents.Columns.Add(KPRes.Component, 100); + m_lvComponents.Columns.Add(strValueColumn, 100); + + string strExe = WinUtil.GetExecutable(); + string strDir = UrlUtil.GetFileDirectory(strExe, true, false); + + AddComponentItem(PwDefs.ShortProductName, strMainVersion, strExe); + + string strXsl = UrlUtil.EnsureTerminatingSeparator(strDir + + AppDefs.XslFilesDir, false); + bool b = File.Exists(strXsl + AppDefs.XslFileHtmlFull); + b &= File.Exists(strXsl + AppDefs.XslFileHtmlLight); + b &= File.Exists(strXsl + AppDefs.XslFileHtmlTabular); + AddComponentItem(KPRes.XslStylesheetsKdbx, (b ? KPRes.Installed : + KPRes.NotInstalled), (b ? strXsl : null)); + + b = KdbFile.IsLibraryInstalled(); + string strVer = (b ? (KdbManager.KeePassVersionString + " - 0x" + + KdbManager.LibraryBuild.ToString("X4")) : KPRes.NotInstalled); + string strPath = null; + if(b) + { + string str = strDir + ((IntPtr.Size == 4) ? KdbManager.DllFile32 : + KdbManager.DllFile64); + if(File.Exists(str)) strPath = str; + else { Debug.Assert(false); } // Somewhere else? + } + AddComponentItem(KPRes.KeePassLibCLong, strVer, strPath); + } + + private void AddComponentItem(string strName, string strVersion, string strPath) + { + if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } + if(strVersion == null) { Debug.Assert(false); strVersion = string.Empty; } + + ListViewItem lvi = new ListViewItem(strName); + lvi.SubItems.Add(strVersion); + + if(!string.IsNullOrEmpty(strPath)) + { + lvi.ToolTipText = strName + MessageService.NewLine + strPath; + lvi.Tag = strPath; + } + + m_lvComponents.Items.Add(lvi); + } + + private void BuildComponentsContextMenu() + { + m_ctxComponents = new CustomContextMenuStripEx(); + m_ctxComponents.SuspendLayout(); + + ToolStripMenuItem tsmiShow = new ToolStripMenuItem(KPRes.ShowWithFileManager, + Properties.Resources.B16x16_Folder_Yellow_Open); + tsmiShow.Click += this.OnComponentShow; + m_ctxComponents.Items.Add(tsmiShow); + + m_ctxComponents.Items.Add(new ToolStripSeparator()); + + ToolStripMenuItem tsmiCopyVersion = new ToolStripMenuItem( + KPRes.CopyObject.Replace(@"{PARAM}", m_lvComponents.Columns[1].Text), + Properties.Resources.B16x16_EditCopy); + tsmiCopyVersion.Click += this.OnComponentCopyVersion; + m_ctxComponents.Items.Add(tsmiCopyVersion); + + ToolStripMenuItem tsmiCopyPath = new ToolStripMenuItem( + KPRes.CopyObject.Replace(@"{PARAM}", KPRes.Path), + Properties.Resources.B16x16_EditCopyLink); + tsmiCopyPath.Click += this.OnComponentCopyTag; + m_ctxComponents.Items.Add(tsmiCopyPath); + + m_ctxComponents.Opening += delegate(object sender, CancelEventArgs e) + { + ListViewItem lviSel = GetSelectedComponent(); + bool bSel = (lviSel != null); + bool bTag = (bSel && (lviSel.Tag != null)); + + tsmiShow.Enabled = bTag; + tsmiCopyVersion.Enabled = bSel; + tsmiCopyPath.Enabled = bTag; + }; + + m_ctxComponents.ResumeLayout(true); + m_lvComponents.ContextMenuStrip = m_ctxComponents; + } + + private void OnLinkHomepage(object sender, LinkLabelLinkClickedEventArgs e) + { + WinUtil.OpenUrl(PwDefs.HomepageUrl, null); + Close(); + } + + private void OnLinkHelpFile(object sender, LinkLabelLinkClickedEventArgs e) + { + AppHelp.ShowHelp(null, null); + Close(); + } + + private void OnLinkLicenseFile(object sender, LinkLabelLinkClickedEventArgs e) + { + AppHelp.ShowHelp(AppDefs.HelpTopics.License, null, true); + Close(); + } + + private void OnLinkAcknowledgements(object sender, LinkLabelLinkClickedEventArgs e) + { + AppHelp.ShowHelp(AppDefs.HelpTopics.Acknowledgements, null, true); + Close(); + } + + private void OnLinkDonate(object sender, LinkLabelLinkClickedEventArgs e) + { + WinUtil.OpenUrl(PwDefs.DonationsUrl, null); + Close(); + } + + private ListViewItem GetSelectedComponent() + { + ListView.SelectedListViewItemCollection lvsic = m_lvComponents.SelectedItems; + if((lvsic == null) || (lvsic.Count != 1)) return null; + return lvsic[0]; + } + + private void OnComponentShow(object sender, EventArgs e) + { + ListViewItem lvi = GetSelectedComponent(); + if(lvi == null) { Debug.Assert(false); return; } + + string strPath = (lvi.Tag as string); + if(string.IsNullOrEmpty(strPath)) return; + + if(File.Exists(strPath)) + WinUtil.ShowFileInFileManager(strPath, true); + else WinUtil.OpenUrlDirectly(strPath); + } + + private void OnComponentCopyVersion(object sender, EventArgs e) + { + ListViewItem lvi = GetSelectedComponent(); + if(lvi == null) { Debug.Assert(false); return; } + + string str = (lvi.SubItems[1].Text ?? string.Empty); + ClipboardUtil.Copy(str, false, false, null, null, this.Handle); + } + + private void OnComponentCopyTag(object sender, EventArgs e) + { + ListViewItem lvi = GetSelectedComponent(); + if(lvi == null) { Debug.Assert(false); return; } + + string str = ((lvi.Tag as string) ?? string.Empty); + ClipboardUtil.Copy(str, false, false, null, null, this.Handle); + } + } +} diff --git a/src/KeePass/Forms/AboutForm.resx b/src/KeePass/Forms/AboutForm.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/src/KeePass/Forms/AboutForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/KeePass/Forms/AutoTypeCtxForm.Designer.cs b/src/KeePass/Forms/AutoTypeCtxForm.Designer.cs new file mode 100644 index 0000000..f79cb9c --- /dev/null +++ b/src/KeePass/Forms/AutoTypeCtxForm.Designer.cs @@ -0,0 +1,173 @@ +namespace KeePass.Forms +{ + partial class AutoTypeCtxForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.m_bannerImage = new System.Windows.Forms.PictureBox(); + this.m_lblText = new System.Windows.Forms.Label(); + this.m_btnCancel = new System.Windows.Forms.Button(); + this.m_lvItems = new KeePass.UI.CustomListViewEx(); + this.m_pnlTop = new System.Windows.Forms.Panel(); + this.m_pnlBottom = new System.Windows.Forms.Panel(); + this.m_btnTools = new System.Windows.Forms.Button(); + this.m_pnlMiddle = new System.Windows.Forms.Panel(); + ((System.ComponentModel.ISupportInitialize)(this.m_bannerImage)).BeginInit(); + this.m_pnlTop.SuspendLayout(); + this.m_pnlBottom.SuspendLayout(); + this.m_pnlMiddle.SuspendLayout(); + this.SuspendLayout(); + // + // m_bannerImage + // + this.m_bannerImage.Dock = System.Windows.Forms.DockStyle.Top; + this.m_bannerImage.Location = new System.Drawing.Point(0, 0); + this.m_bannerImage.Name = "m_bannerImage"; + this.m_bannerImage.Size = new System.Drawing.Size(579, 60); + this.m_bannerImage.TabIndex = 0; + this.m_bannerImage.TabStop = false; + // + // m_lblText + // + this.m_lblText.Dock = System.Windows.Forms.DockStyle.Fill; + this.m_lblText.Location = new System.Drawing.Point(9, 11); + this.m_lblText.Name = "m_lblText"; + this.m_lblText.Size = new System.Drawing.Size(561, 30); + this.m_lblText.TabIndex = 0; + this.m_lblText.Text = "<>"; + // + // m_btnCancel + // + this.m_btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.m_btnCancel.Dock = System.Windows.Forms.DockStyle.Right; + this.m_btnCancel.Location = new System.Drawing.Point(492, 6); + this.m_btnCancel.Name = "m_btnCancel"; + this.m_btnCancel.Size = new System.Drawing.Size(75, 23); + this.m_btnCancel.TabIndex = 1; + this.m_btnCancel.Text = "Cancel"; + this.m_btnCancel.UseVisualStyleBackColor = true; + // + // m_lvItems + // + this.m_lvItems.Activation = System.Windows.Forms.ItemActivation.OneClick; + this.m_lvItems.Dock = System.Windows.Forms.DockStyle.Fill; + this.m_lvItems.FullRowSelect = true; + this.m_lvItems.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.m_lvItems.HideSelection = false; + this.m_lvItems.HotTracking = true; + this.m_lvItems.HoverSelection = true; + this.m_lvItems.Location = new System.Drawing.Point(12, 0); + this.m_lvItems.MultiSelect = false; + this.m_lvItems.Name = "m_lvItems"; + this.m_lvItems.ShowItemToolTips = true; + this.m_lvItems.Size = new System.Drawing.Size(555, 219); + this.m_lvItems.TabIndex = 0; + this.m_lvItems.UseCompatibleStateImageBehavior = false; + this.m_lvItems.View = System.Windows.Forms.View.Details; + this.m_lvItems.ItemActivate += new System.EventHandler(this.OnListItemActivate); + this.m_lvItems.Click += new System.EventHandler(this.OnListClick); + // + // m_pnlTop + // + this.m_pnlTop.Controls.Add(this.m_lblText); + this.m_pnlTop.Dock = System.Windows.Forms.DockStyle.Top; + this.m_pnlTop.Location = new System.Drawing.Point(0, 60); + this.m_pnlTop.Name = "m_pnlTop"; + this.m_pnlTop.Padding = new System.Windows.Forms.Padding(9, 11, 9, 3); + this.m_pnlTop.Size = new System.Drawing.Size(579, 44); + this.m_pnlTop.TabIndex = 2; + // + // m_pnlBottom + // + this.m_pnlBottom.Controls.Add(this.m_btnTools); + this.m_pnlBottom.Controls.Add(this.m_btnCancel); + this.m_pnlBottom.Dock = System.Windows.Forms.DockStyle.Bottom; + this.m_pnlBottom.Location = new System.Drawing.Point(0, 323); + this.m_pnlBottom.Name = "m_pnlBottom"; + this.m_pnlBottom.Padding = new System.Windows.Forms.Padding(12, 6, 12, 12); + this.m_pnlBottom.Size = new System.Drawing.Size(579, 41); + this.m_pnlBottom.TabIndex = 1; + // + // m_btnTools + // + this.m_btnTools.Dock = System.Windows.Forms.DockStyle.Left; + this.m_btnTools.Location = new System.Drawing.Point(12, 6); + this.m_btnTools.Name = "m_btnTools"; + this.m_btnTools.Size = new System.Drawing.Size(75, 23); + this.m_btnTools.TabIndex = 0; + this.m_btnTools.Text = "&Options"; + this.m_btnTools.UseVisualStyleBackColor = true; + this.m_btnTools.Click += new System.EventHandler(this.OnBtnTools); + // + // m_pnlMiddle + // + this.m_pnlMiddle.Controls.Add(this.m_lvItems); + this.m_pnlMiddle.Dock = System.Windows.Forms.DockStyle.Fill; + this.m_pnlMiddle.Location = new System.Drawing.Point(0, 104); + this.m_pnlMiddle.Name = "m_pnlMiddle"; + this.m_pnlMiddle.Padding = new System.Windows.Forms.Padding(12, 0, 12, 0); + this.m_pnlMiddle.Size = new System.Drawing.Size(579, 219); + this.m_pnlMiddle.TabIndex = 0; + // + // AutoTypeCtxForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.m_btnCancel; + this.ClientSize = new System.Drawing.Size(579, 364); + this.Controls.Add(this.m_pnlMiddle); + this.Controls.Add(this.m_pnlBottom); + this.Controls.Add(this.m_pnlTop); + this.Controls.Add(this.m_bannerImage); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AutoTypeCtxForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "<>"; + this.Load += new System.EventHandler(this.OnFormLoad); + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.OnFormClosed); + this.Resize += new System.EventHandler(this.OnFormResize); + ((System.ComponentModel.ISupportInitialize)(this.m_bannerImage)).EndInit(); + this.m_pnlTop.ResumeLayout(false); + this.m_pnlBottom.ResumeLayout(false); + this.m_pnlMiddle.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.PictureBox m_bannerImage; + private System.Windows.Forms.Label m_lblText; + private KeePass.UI.CustomListViewEx m_lvItems; + private System.Windows.Forms.Button m_btnCancel; + private System.Windows.Forms.Panel m_pnlTop; + private System.Windows.Forms.Panel m_pnlBottom; + private System.Windows.Forms.Panel m_pnlMiddle; + private System.Windows.Forms.Button m_btnTools; + } +} \ No newline at end of file diff --git a/src/KeePass/Forms/AutoTypeCtxForm.cs b/src/KeePass/Forms/AutoTypeCtxForm.cs new file mode 100644 index 0000000..2c60136 --- /dev/null +++ b/src/KeePass/Forms/AutoTypeCtxForm.cs @@ -0,0 +1,282 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +using KeePass.App; +using KeePass.App.Configuration; +using KeePass.Resources; +using KeePass.UI; +using KeePass.Util; + +using KeePassLib; + +namespace KeePass.Forms +{ + public partial class AutoTypeCtxForm : Form + { + private List m_lCtxs = null; + private ImageList m_ilIcons = null; + + private string m_strInitialFormRect = string.Empty; + private string m_strInitialColWidths = string.Empty; + private int m_nBannerWidth = -1; + private bool m_bCanShowPasswords = true; + + private CustomContextMenuStripEx m_ctxTools = null; + private ToolStripMenuItem m_tsmiColumns = null; + + private AutoTypeCtx m_atcSel = null; + public AutoTypeCtx SelectedCtx + { + get { return m_atcSel; } + } + + public void InitEx(List lCtxs, ImageList ilIcons) + { + m_lCtxs = lCtxs; + m_ilIcons = UIUtil.CloneImageList(ilIcons, true); + } + + public AutoTypeCtxForm() + { + InitializeComponent(); + GlobalWindowManager.InitializeForm(this); + } + + private void OnFormLoad(object sender, EventArgs e) + { + Size sz = this.ClientSize; + this.MinimumSize = new Size((int)(0.949f * (float)sz.Width), + (int)(0.824f * (float)sz.Height)); + + GlobalWindowManager.AddWindow(this); + + Debug.Assert(!m_lblText.AutoSize); // For RTL support + m_lblText.Text = KPRes.AutoTypeEntrySelectionDescLong2; + + this.Text = KPRes.AutoTypeEntrySelection; + this.Icon = AppIcons.Default; + + m_strInitialFormRect = UIUtil.SetWindowScreenRectEx(this, + Program.Config.UI.AutoTypeCtxRect); + + UIUtil.SetExplorerTheme(m_lvItems, true); + + if(m_ilIcons != null) m_lvItems.SmallImageList = m_ilIcons; + else { Debug.Assert(false); m_ilIcons = new ImageList(); } + + m_bCanShowPasswords = AppPolicy.Current.UnhidePasswords; + + RecreateEntryList(); + + string strColWidths = Program.Config.UI.AutoTypeCtxColumnWidths; + if(strColWidths.Length > 0) UIUtil.SetColumnWidths(m_lvItems, strColWidths); + m_strInitialColWidths = UIUtil.GetColumnWidths(m_lvItems); + + ProcessResize(); + BringToFront(); + Activate(); + UIUtil.SetFocus(m_lvItems, this, true); + } + + private void OnFormClosed(object sender, FormClosedEventArgs e) + { + string strColWidths = UIUtil.GetColumnWidths(m_lvItems); + if(strColWidths != m_strInitialColWidths) + Program.Config.UI.AutoTypeCtxColumnWidths = strColWidths; + + string strRect = UIUtil.GetWindowScreenRect(this); + if(strRect != m_strInitialFormRect) // Don't overwrite "" + Program.Config.UI.AutoTypeCtxRect = strRect; + + DestroyToolsContextMenu(); + + if(m_ilIcons != null) + { + m_lvItems.SmallImageList = null; // Detach event handlers + m_ilIcons.Dispose(); + m_ilIcons = null; + } + + GlobalWindowManager.RemoveWindow(this); + } + + private void RecreateEntryList() + { + long lFlags = Program.Config.UI.AutoTypeCtxFlags; + + if(!m_bCanShowPasswords) + lFlags &= ~(long)AceAutoTypeCtxFlags.ColPassword; + + UIUtil.CreateEntryList(m_lvItems, m_lCtxs, (AceAutoTypeCtxFlags)lFlags, + m_ilIcons); + } + + private void ProcessResize() + { + if(m_lCtxs == null) return; // TrlUtil or design mode + + string strSub = KPRes.AutoTypeEntrySelectionDescShort; + int n = m_lCtxs.Count; + if(n == 1) strSub = KPRes.SearchEntriesFound1 + "."; + else if(n <= 0) + { + strSub = KPRes.SearchEntriesFound + "."; + strSub = strSub.Replace(@"{PARAM}", "0"); + } + + BannerFactory.UpdateBanner(this, m_bannerImage, + Properties.Resources.B48x48_KGPG_Key2, KPRes.AutoTypeEntrySelection, + strSub, ref m_nBannerWidth); + } + + private bool GetSelectedEntry() + { + ListView.SelectedListViewItemCollection slvic = m_lvItems.SelectedItems; + if(slvic.Count == 1) + { + m_atcSel = (slvic[0].Tag as AutoTypeCtx); + return (m_atcSel != null); + } + + return false; + } + + private void ProcessItemSelection() + { + if(this.DialogResult == DialogResult.OK) return; // Already closing + + if(GetSelectedEntry()) this.DialogResult = DialogResult.OK; + } + + private void OnListItemActivate(object sender, EventArgs e) + { + ProcessItemSelection(); + } + + // The item activation handler has a slight delay when clicking an + // item, thus as a performance optimization we additionally handle + // item clicks + private void OnListClick(object sender, EventArgs e) + { + ProcessItemSelection(); + } + + private void OnFormResize(object sender, EventArgs e) + { + ProcessResize(); + } + + private void DestroyToolsContextMenu() + { + if(m_ctxTools == null) return; + + foreach(ToolStripItem tsi in m_tsmiColumns.DropDownItems) + tsi.Click -= this.OnToggleColumn; + + m_tsmiColumns = null; + m_ctxTools.Dispose(); + m_ctxTools = null; + } + + private void RecreateToolsContextMenu() + { + DestroyToolsContextMenu(); + + m_ctxTools = new CustomContextMenuStripEx(); + m_tsmiColumns = new ToolStripMenuItem(KPRes.Columns); + m_ctxTools.Items.Add(m_tsmiColumns); + + long lFlags = Program.Config.UI.AutoTypeCtxFlags; + + ToolStripMenuItem tsmi = new ToolStripMenuItem(KPRes.Title); + UIUtil.SetChecked(tsmi, true); + tsmi.Tag = AceAutoTypeCtxFlags.ColTitle; + tsmi.Click += this.OnToggleColumn; + tsmi.Enabled = false; + m_tsmiColumns.DropDownItems.Add(tsmi); + + tsmi = new ToolStripMenuItem(KPRes.UserName); + UIUtil.SetChecked(tsmi, ((lFlags & (long)AceAutoTypeCtxFlags.ColUserName) != 0)); + tsmi.Tag = AceAutoTypeCtxFlags.ColUserName; + tsmi.Click += this.OnToggleColumn; + m_tsmiColumns.DropDownItems.Add(tsmi); + + tsmi = new ToolStripMenuItem(KPRes.Password); + UIUtil.SetChecked(tsmi, (((lFlags & (long)AceAutoTypeCtxFlags.ColPassword) != 0) && + m_bCanShowPasswords)); + tsmi.Tag = AceAutoTypeCtxFlags.ColPassword; + tsmi.Click += this.OnToggleColumn; + if(!m_bCanShowPasswords) tsmi.Enabled = false; + m_tsmiColumns.DropDownItems.Add(tsmi); + + tsmi = new ToolStripMenuItem(KPRes.Url); + UIUtil.SetChecked(tsmi, ((lFlags & (long)AceAutoTypeCtxFlags.ColUrl) != 0)); + tsmi.Tag = AceAutoTypeCtxFlags.ColUrl; + tsmi.Click += this.OnToggleColumn; + m_tsmiColumns.DropDownItems.Add(tsmi); + + tsmi = new ToolStripMenuItem(KPRes.Notes); + UIUtil.SetChecked(tsmi, ((lFlags & (long)AceAutoTypeCtxFlags.ColNotes) != 0)); + tsmi.Tag = AceAutoTypeCtxFlags.ColNotes; + tsmi.Click += this.OnToggleColumn; + m_tsmiColumns.DropDownItems.Add(tsmi); + + tsmi = new ToolStripMenuItem(KPRes.Sequence + " - " + KPRes.Comments); + UIUtil.SetChecked(tsmi, ((lFlags & (long)AceAutoTypeCtxFlags.ColSequenceComments) != 0)); + tsmi.Tag = AceAutoTypeCtxFlags.ColSequenceComments; + tsmi.Click += this.OnToggleColumn; + m_tsmiColumns.DropDownItems.Add(tsmi); + + tsmi = new ToolStripMenuItem(KPRes.Sequence); + UIUtil.SetChecked(tsmi, ((lFlags & (long)AceAutoTypeCtxFlags.ColSequence) != 0)); + tsmi.Tag = AceAutoTypeCtxFlags.ColSequence; + tsmi.Click += this.OnToggleColumn; + m_tsmiColumns.DropDownItems.Add(tsmi); + } + + private void OnToggleColumn(object sender, EventArgs e) + { + ToolStripMenuItem tsmi = (sender as ToolStripMenuItem); + if(tsmi == null) { Debug.Assert(false); return; } + + AceAutoTypeCtxFlags f = (AceAutoTypeCtxFlags)tsmi.Tag; + long lFlags = Program.Config.UI.AutoTypeCtxFlags; + + lFlags ^= (long)f; + lFlags |= (long)AceAutoTypeCtxFlags.ColTitle; // Enforce title + + Program.Config.UI.AutoTypeCtxFlags = lFlags; + RecreateEntryList(); + } + + private void OnBtnTools(object sender, EventArgs e) + { + RecreateToolsContextMenu(); + m_ctxTools.ShowEx(m_btnTools); + } + } +} diff --git a/src/KeePass/Forms/AutoTypeCtxForm.resx b/src/KeePass/Forms/AutoTypeCtxForm.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/src/KeePass/Forms/AutoTypeCtxForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/KeePass/Forms/CharPickerForm.Designer.cs b/src/KeePass/Forms/CharPickerForm.Designer.cs new file mode 100644 index 0000000..cef35d5 --- /dev/null +++ b/src/KeePass/Forms/CharPickerForm.Designer.cs @@ -0,0 +1,269 @@ +namespace KeePass.Forms +{ + partial class CharPickerForm + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Windows Form-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.m_btnOK = new System.Windows.Forms.Button(); + this.m_btnCancel = new System.Windows.Forms.Button(); + this.m_bannerImage = new System.Windows.Forms.PictureBox(); + this.m_lblChars = new System.Windows.Forms.Label(); + this.m_lblIndex = new System.Windows.Forms.Label(); + this.m_lblSelChars = new System.Windows.Forms.Label(); + this.m_tbSelected = new KeePass.UI.SecureTextBoxEx(); + this.m_cbHideChars = new System.Windows.Forms.CheckBox(); + this.m_pnlSelect = new System.Windows.Forms.Panel(); + this.m_pnlBottom = new System.Windows.Forms.Panel(); + this.m_pnlBottomRight = new System.Windows.Forms.Panel(); + this.m_pnlTop = new System.Windows.Forms.Panel(); + this.m_pnlTopLeft = new System.Windows.Forms.Panel(); + this.m_pnlLeft = new System.Windows.Forms.Panel(); + this.m_pnlRight = new System.Windows.Forms.Panel(); + this.m_pnlMiddleTopSpacer = new System.Windows.Forms.Panel(); + ((System.ComponentModel.ISupportInitialize)(this.m_bannerImage)).BeginInit(); + this.m_pnlBottom.SuspendLayout(); + this.m_pnlBottomRight.SuspendLayout(); + this.m_pnlTop.SuspendLayout(); + this.m_pnlTopLeft.SuspendLayout(); + this.m_pnlLeft.SuspendLayout(); + this.m_pnlRight.SuspendLayout(); + this.m_pnlMiddleTopSpacer.SuspendLayout(); + this.SuspendLayout(); + // + // m_btnOK + // + this.m_btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.m_btnOK.Location = new System.Drawing.Point(8, 5); + this.m_btnOK.Name = "m_btnOK"; + this.m_btnOK.Size = new System.Drawing.Size(75, 23); + this.m_btnOK.TabIndex = 0; + this.m_btnOK.Text = "OK"; + this.m_btnOK.UseVisualStyleBackColor = true; + this.m_btnOK.Click += new System.EventHandler(this.OnBtnOK); + // + // m_btnCancel + // + this.m_btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.m_btnCancel.Location = new System.Drawing.Point(89, 5); + this.m_btnCancel.Name = "m_btnCancel"; + this.m_btnCancel.Size = new System.Drawing.Size(75, 23); + this.m_btnCancel.TabIndex = 1; + this.m_btnCancel.Text = "Cancel"; + this.m_btnCancel.UseVisualStyleBackColor = true; + this.m_btnCancel.Click += new System.EventHandler(this.OnBtnCancel); + // + // m_bannerImage + // + this.m_bannerImage.Dock = System.Windows.Forms.DockStyle.Top; + this.m_bannerImage.Location = new System.Drawing.Point(0, 0); + this.m_bannerImage.Name = "m_bannerImage"; + this.m_bannerImage.Size = new System.Drawing.Size(628, 60); + this.m_bannerImage.TabIndex = 3; + this.m_bannerImage.TabStop = false; + // + // m_lblChars + // + this.m_lblChars.AutoSize = true; + this.m_lblChars.Location = new System.Drawing.Point(0, 6); + this.m_lblChars.Name = "m_lblChars"; + this.m_lblChars.Size = new System.Drawing.Size(56, 13); + this.m_lblChars.TabIndex = 0; + this.m_lblChars.Text = "Character:"; + // + // m_lblIndex + // + this.m_lblIndex.AutoSize = true; + this.m_lblIndex.Location = new System.Drawing.Point(0, 30); + this.m_lblIndex.Name = "m_lblIndex"; + this.m_lblIndex.Size = new System.Drawing.Size(47, 13); + this.m_lblIndex.TabIndex = 1; + this.m_lblIndex.Text = "Position:"; + // + // m_lblSelChars + // + this.m_lblSelChars.AutoSize = true; + this.m_lblSelChars.Location = new System.Drawing.Point(12, 15); + this.m_lblSelChars.Name = "m_lblSelChars"; + this.m_lblSelChars.Size = new System.Drawing.Size(36, 13); + this.m_lblSelChars.TabIndex = 0; + this.m_lblSelChars.Text = "Word:"; + // + // m_tbSelected + // + this.m_tbSelected.Dock = System.Windows.Forms.DockStyle.Top; + this.m_tbSelected.Location = new System.Drawing.Point(0, 12); + this.m_tbSelected.Name = "m_tbSelected"; + this.m_tbSelected.Size = new System.Drawing.Size(508, 20); + this.m_tbSelected.TabIndex = 0; + // + // m_cbHideChars + // + this.m_cbHideChars.Appearance = System.Windows.Forms.Appearance.Button; + this.m_cbHideChars.Location = new System.Drawing.Point(5, 10); + this.m_cbHideChars.Name = "m_cbHideChars"; + this.m_cbHideChars.Size = new System.Drawing.Size(32, 23); + this.m_cbHideChars.TabIndex = 0; + this.m_cbHideChars.Text = "***"; + this.m_cbHideChars.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.m_cbHideChars.UseVisualStyleBackColor = true; + this.m_cbHideChars.CheckedChanged += new System.EventHandler(this.OnHideCharsCheckedChanged); + // + // m_pnlSelect + // + this.m_pnlSelect.Dock = System.Windows.Forms.DockStyle.Fill; + this.m_pnlSelect.Location = new System.Drawing.Point(71, 8); + this.m_pnlSelect.Name = "m_pnlSelect"; + this.m_pnlSelect.Size = new System.Drawing.Size(545, 52); + this.m_pnlSelect.TabIndex = 1; + // + // m_pnlBottom + // + this.m_pnlBottom.Controls.Add(this.m_pnlBottomRight); + this.m_pnlBottom.Dock = System.Windows.Forms.DockStyle.Bottom; + this.m_pnlBottom.Location = new System.Drawing.Point(0, 175); + this.m_pnlBottom.Name = "m_pnlBottom"; + this.m_pnlBottom.Size = new System.Drawing.Size(628, 40); + this.m_pnlBottom.TabIndex = 0; + // + // m_pnlBottomRight + // + this.m_pnlBottomRight.Controls.Add(this.m_btnCancel); + this.m_pnlBottomRight.Controls.Add(this.m_btnOK); + this.m_pnlBottomRight.Dock = System.Windows.Forms.DockStyle.Right; + this.m_pnlBottomRight.Location = new System.Drawing.Point(452, 0); + this.m_pnlBottomRight.Name = "m_pnlBottomRight"; + this.m_pnlBottomRight.Size = new System.Drawing.Size(176, 40); + this.m_pnlBottomRight.TabIndex = 0; + // + // m_pnlTop + // + this.m_pnlTop.Controls.Add(this.m_pnlSelect); + this.m_pnlTop.Controls.Add(this.m_pnlTopLeft); + this.m_pnlTop.Dock = System.Windows.Forms.DockStyle.Top; + this.m_pnlTop.Location = new System.Drawing.Point(0, 60); + this.m_pnlTop.Name = "m_pnlTop"; + this.m_pnlTop.Padding = new System.Windows.Forms.Padding(12, 8, 12, 8); + this.m_pnlTop.Size = new System.Drawing.Size(628, 68); + this.m_pnlTop.TabIndex = 1; + // + // m_pnlTopLeft + // + this.m_pnlTopLeft.Controls.Add(this.m_lblChars); + this.m_pnlTopLeft.Controls.Add(this.m_lblIndex); + this.m_pnlTopLeft.Dock = System.Windows.Forms.DockStyle.Left; + this.m_pnlTopLeft.Location = new System.Drawing.Point(12, 8); + this.m_pnlTopLeft.Name = "m_pnlTopLeft"; + this.m_pnlTopLeft.Size = new System.Drawing.Size(59, 52); + this.m_pnlTopLeft.TabIndex = 0; + // + // m_pnlLeft + // + this.m_pnlLeft.Controls.Add(this.m_lblSelChars); + this.m_pnlLeft.Dock = System.Windows.Forms.DockStyle.Left; + this.m_pnlLeft.Location = new System.Drawing.Point(0, 128); + this.m_pnlLeft.Name = "m_pnlLeft"; + this.m_pnlLeft.Size = new System.Drawing.Size(71, 47); + this.m_pnlLeft.TabIndex = 2; + // + // m_pnlRight + // + this.m_pnlRight.Controls.Add(this.m_cbHideChars); + this.m_pnlRight.Dock = System.Windows.Forms.DockStyle.Right; + this.m_pnlRight.Location = new System.Drawing.Point(579, 128); + this.m_pnlRight.Name = "m_pnlRight"; + this.m_pnlRight.Size = new System.Drawing.Size(49, 47); + this.m_pnlRight.TabIndex = 4; + // + // m_pnlMiddleTopSpacer + // + this.m_pnlMiddleTopSpacer.Controls.Add(this.m_tbSelected); + this.m_pnlMiddleTopSpacer.Dock = System.Windows.Forms.DockStyle.Top; + this.m_pnlMiddleTopSpacer.Location = new System.Drawing.Point(71, 128); + this.m_pnlMiddleTopSpacer.Name = "m_pnlMiddleTopSpacer"; + this.m_pnlMiddleTopSpacer.Padding = new System.Windows.Forms.Padding(0, 12, 0, 0); + this.m_pnlMiddleTopSpacer.Size = new System.Drawing.Size(508, 41); + this.m_pnlMiddleTopSpacer.TabIndex = 3; + // + // CharPickerForm + // + this.AcceptButton = this.m_btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.m_btnCancel; + this.ClientSize = new System.Drawing.Size(628, 215); + this.Controls.Add(this.m_pnlMiddleTopSpacer); + this.Controls.Add(this.m_pnlRight); + this.Controls.Add(this.m_pnlLeft); + this.Controls.Add(this.m_pnlTop); + this.Controls.Add(this.m_pnlBottom); + this.Controls.Add(this.m_bannerImage); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CharPickerForm"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "<>"; + this.Load += new System.EventHandler(this.OnFormLoad); + this.SizeChanged += new System.EventHandler(this.OnFormSizeChanged); + this.Shown += new System.EventHandler(this.OnFormShown); + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.OnFormClosed); + this.Resize += new System.EventHandler(this.OnFormResize); + ((System.ComponentModel.ISupportInitialize)(this.m_bannerImage)).EndInit(); + this.m_pnlBottom.ResumeLayout(false); + this.m_pnlBottomRight.ResumeLayout(false); + this.m_pnlTop.ResumeLayout(false); + this.m_pnlTopLeft.ResumeLayout(false); + this.m_pnlTopLeft.PerformLayout(); + this.m_pnlLeft.ResumeLayout(false); + this.m_pnlLeft.PerformLayout(); + this.m_pnlRight.ResumeLayout(false); + this.m_pnlMiddleTopSpacer.ResumeLayout(false); + this.m_pnlMiddleTopSpacer.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button m_btnOK; + private System.Windows.Forms.Button m_btnCancel; + private System.Windows.Forms.PictureBox m_bannerImage; + private System.Windows.Forms.Label m_lblChars; + private System.Windows.Forms.Label m_lblIndex; + private System.Windows.Forms.Label m_lblSelChars; + private KeePass.UI.SecureTextBoxEx m_tbSelected; + private System.Windows.Forms.CheckBox m_cbHideChars; + private System.Windows.Forms.Panel m_pnlSelect; + private System.Windows.Forms.Panel m_pnlBottom; + private System.Windows.Forms.Panel m_pnlBottomRight; + private System.Windows.Forms.Panel m_pnlTop; + private System.Windows.Forms.Panel m_pnlTopLeft; + private System.Windows.Forms.Panel m_pnlLeft; + private System.Windows.Forms.Panel m_pnlRight; + private System.Windows.Forms.Panel m_pnlMiddleTopSpacer; + } +} \ No newline at end of file diff --git a/src/KeePass/Forms/CharPickerForm.cs b/src/KeePass/Forms/CharPickerForm.cs new file mode 100644 index 0000000..e7fb155 --- /dev/null +++ b/src/KeePass/Forms/CharPickerForm.cs @@ -0,0 +1,351 @@ +/* + KeePass Password Safe - The Open-Source Password Manager + Copyright (C) 2003-2023 Dominik Reichl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +using KeePass.App; +using KeePass.App.Configuration; +using KeePass.Native; +using KeePass.Resources; +using KeePass.UI; + +using KeePassLib; +using KeePassLib.Security; +using KeePassLib.Utility; + +using NativeLib = KeePassLib.Native.NativeLib; + +namespace KeePass.Forms +{ + public partial class CharPickerForm : Form + { + private ProtectedString m_psWord = null; + private ProtectedString m_psSelected = ProtectedString.Empty; + + private List