diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2eb2e2c..91ff045d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## 2.6.3 (2020-01-12) + +### Added + +- Support Argon2id KDF [#5778] +- Support XMLv2 key files [#5798] + +### Changed + +- Improve CSV Import/Export, include time fields and TOTP [#5346] +- Support empty area dragging of the application window [#5860] +- Display default Auto-Type sequence in preview pane [#5654] +- Remove strict length limit on generated passwords [#5748] +- Hide key file path by default when unlocking database [#5779] +- Document browser extension use with Edge in managed mode [#5692] +- Windows: Prevent clipboard history and cloud sync [#5853] +- macOS: Update the application icon to Big Sur styling [#5851] + +### Fixed + +- Re-select previously selected entry on database unlock [#5559] +- Properly save special character choice in password generator [#5610] +- Fix crash in browser integration with multiple similar entries [#5653] +- Remove offset on username field in classic theme [#5788] +- Ensure entry history is copied when drag/dropping entries and groups [#5817] +- Close modal dialogs when database is locked [#5820] +- Prevent crash when KeeShare modifies an entry that is currently being edited [#5827] +- Improve preview of entry attributes [#5834] +- Always activate/focus database open dialog preventing mistype [#5878] +- Reports: fix calculation of average password length [#5862] +- Linux: Delay startup on login to correct tray icon issues [#5724] + ## 2.6.2 (2020-10-21) ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index 84d05e593..f456b9dcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,7 @@ endif() set(KEEPASSXC_VERSION_MAJOR "2") set(KEEPASSXC_VERSION_MINOR "6") -set(KEEPASSXC_VERSION_PATCH "2") +set(KEEPASSXC_VERSION_PATCH "3") set(KEEPASSXC_VERSION "${KEEPASSXC_VERSION_MAJOR}.${KEEPASSXC_VERSION_MINOR}.${KEEPASSXC_VERSION_PATCH}") set(OVERRIDE_VERSION "" CACHE STRING "Override the KeePassXC Version for Snapshot builds") diff --git a/docs/topics/BrowserPlugin.adoc b/docs/topics/BrowserPlugin.adoc index 0331eda7f..380daf1a5 100644 --- a/docs/topics/BrowserPlugin.adoc +++ b/docs/topics/BrowserPlugin.adoc @@ -23,6 +23,10 @@ You can download the KeePassXC-Browser extension from your web browser. To downl 2. Click the button to install/add the extension to the browser. Accept any confirmation dialogs. +// tag::advanced[] +NOTE: When Microsoft Edge is installed as a managed application, system administrators are required to deploy a custom native messaging configuration. Instructions for this are found in the advanced section below. +// end::advanced[] + === Configure KeePassXC-Browser To start using KeePassXC-Browser, you must configure it so that it can communicate with the KeePassXC application on your desktop. @@ -104,5 +108,38 @@ WARNING: We do not recommend changing any of these settings as they may break th .Advanced browser settings image::browser_advanced_settings.png[] + +=== Advanced Setup +==== Managed Microsoft Edge on Windows +1. Deploy *org.keepassxc.keepassxc_browser_edge.json* to, for example, `C:\ProgramData\KeepassXC` on all managed platforms. ++ +---- +{ + "allowed_origins": [ + "chrome-extension://pdffhmdngciaglkoonimfcmckehcpafo/" + ], + "description": "KeePassXC integration with native messaging support", + "name": "org.keepassxc.keepassxc_browser", + "path": "C:\\Program Files\\KeePassXC\\keepassxc-proxy.exe", + "type": "stdio" +} +---- + +2. Configure GPO options (registry result): ++ +---- +Windows Registry Editor Version 5.00 +[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Edge\NativeMessagingHosts\org.keepassxc.keepassxc_browser] +@="C:\ProgramData\KeepassXC\org.keepassxc.keepassxc_browser_edge.json" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge] +"NativeMessagingUserLevelHosts"=dword:00000000 + +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallAllowlist] +"1"="pdffhmdngciaglkoonimfcmckehcpafo" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\NativeMessagingAllowlist] +"1"="org.keepassxc.keepassxc_browser" +---- // end::advanced[] // end::content[] diff --git a/share/linux/org.keepassxc.KeePassXC.appdata.xml b/share/linux/org.keepassxc.KeePassXC.appdata.xml index 84d52f279..135b37b78 100644 --- a/share/linux/org.keepassxc.KeePassXC.appdata.xml +++ b/share/linux/org.keepassxc.KeePassXC.appdata.xml @@ -50,6 +50,33 @@ + + +
    +
  • Support Argon2id KDF [#5778]
  • +
  • Support XMLv2 key files [#5798]
  • +
  • Improve CSV Import/Export, include time fields and TOTP [#5346]
  • +
  • Support empty area dragging of the application window [#5860]
  • +
  • Display default Auto-Type sequence in preview pane [#5654]
  • +
  • Remove strict length limit on generated passwords [#5748]
  • +
  • Hide key file path by default when unlocking database [#5779]
  • +
  • Document browser extension use with Edge in managed mode [#5692]
  • +
  • Windows: Prevent clipboard history and cloud sync [#5853]
  • +
  • macOS: Update the application icon to Big Sur styling [#5851]
  • +
  • Re-select previously selected entry on database unlock [#5559]
  • +
  • Properly save special character choice in password generator [#5610]
  • +
  • Fix crash in browser integration with multiple similar entries [#5653]
  • +
  • Remove offset on username field in classic theme [#5788]
  • +
  • Ensure entry history is copied when drag/dropping entries and groups [#5817]
  • +
  • Close modal dialogs when database is locked [#5820]
  • +
  • Prevent crash when KeeShare modifies an entry that is currently being edited [#5827]
  • +
  • Improve preview of entry attributes [#5834]
  • +
  • Always activate/focus database open dialog preventing mistype [#5878]
  • +
  • Reports: fix calculation of average password length [#5862]
  • +
  • Linux: Delay startup on login to correct tray icon issues [#5724]
  • +
+
+
    diff --git a/share/macosx/keepassxc.ai b/share/macosx/keepassxc.ai new file mode 100755 index 000000000..cea3b65c0 Binary files /dev/null and b/share/macosx/keepassxc.ai differ diff --git a/share/macosx/keepassxc.icns b/share/macosx/keepassxc.icns index 02baec7d4..c5125d782 100644 Binary files a/share/macosx/keepassxc.icns and b/share/macosx/keepassxc.icns differ diff --git a/share/macosx/keepassxc.iconset/icon_128x128.png b/share/macosx/keepassxc.iconset/icon_128x128.png new file mode 100755 index 000000000..7512796d4 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_128x128.png differ diff --git a/share/macosx/keepassxc.iconset/icon_128x128@2x.png b/share/macosx/keepassxc.iconset/icon_128x128@2x.png new file mode 100755 index 000000000..3c00e0e8c Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_128x128@2x.png differ diff --git a/share/macosx/keepassxc.iconset/icon_16x16.png b/share/macosx/keepassxc.iconset/icon_16x16.png new file mode 100755 index 000000000..ca6823954 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_16x16.png differ diff --git a/share/macosx/keepassxc.iconset/icon_16x16@2x.png b/share/macosx/keepassxc.iconset/icon_16x16@2x.png new file mode 100755 index 000000000..47af8eb1b Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_16x16@2x.png differ diff --git a/share/macosx/keepassxc.iconset/icon_256x256.png b/share/macosx/keepassxc.iconset/icon_256x256.png new file mode 100755 index 000000000..3c00e0e8c Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_256x256.png differ diff --git a/share/macosx/keepassxc.iconset/icon_256x256@2x.png b/share/macosx/keepassxc.iconset/icon_256x256@2x.png new file mode 100755 index 000000000..1c6e2a094 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_256x256@2x.png differ diff --git a/share/macosx/keepassxc.iconset/icon_32x32.png b/share/macosx/keepassxc.iconset/icon_32x32.png new file mode 100755 index 000000000..47af8eb1b Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_32x32.png differ diff --git a/share/macosx/keepassxc.iconset/icon_32x32@2x.png b/share/macosx/keepassxc.iconset/icon_32x32@2x.png new file mode 100755 index 000000000..63c9847c4 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_32x32@2x.png differ diff --git a/share/macosx/keepassxc.iconset/icon_512x512.png b/share/macosx/keepassxc.iconset/icon_512x512.png new file mode 100755 index 000000000..1c6e2a094 Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_512x512.png differ diff --git a/share/macosx/keepassxc.iconset/icon_512x512@2x.png b/share/macosx/keepassxc.iconset/icon_512x512@2x.png new file mode 100755 index 000000000..68e4a3dce Binary files /dev/null and b/share/macosx/keepassxc.iconset/icon_512x512@2x.png differ diff --git a/share/translations/keepassx_da.ts b/share/translations/keepassx_da.ts index fdfc959e1..a36f1e721 100644 --- a/share/translations/keepassx_da.ts +++ b/share/translations/keepassx_da.ts @@ -245,7 +245,7 @@ (restart program to activate) - + (genstart program for at aktivere) Minimize window after unlocking database diff --git a/share/translations/keepassx_de.ts b/share/translations/keepassx_de.ts index 6ddaf1da0..5ce76a2b5 100644 --- a/share/translations/keepassx_de.ts +++ b/share/translations/keepassx_de.ts @@ -233,7 +233,7 @@ Check for updates at application startup once per week - Bei Programmstartstart wöchentlich auf Updates prüfen + Bei Programmstart wöchentlich auf Updates prüfen Include beta releases when checking for updates diff --git a/share/translations/keepassx_en.ts b/share/translations/keepassx_en.ts index 35cb0f686..9940e1105 100644 --- a/share/translations/keepassx_en.ts +++ b/share/translations/keepassx_en.ts @@ -1114,6 +1114,14 @@ chrome-laptop. Column %1 + + TOTP + TOTP + + + Icon + Icon + CsvParserModel @@ -1218,20 +1226,6 @@ Backup database located at %2 Refresh Refresh - - Legacy key file format - Legacy key file format - - - You are using a legacy key file format which may become -unsupported in the future. - -Please consider generating a new key file. - You are using a legacy key file format which may become -unsupported in the future. - -Please consider generating a new key file. - Don't show this warning again Don't show this warning again @@ -1357,6 +1351,14 @@ If you do not have a key file, please leave the field empty. Select hardware key… + + Old key file format + + + + You are using an old key file format which KeePassXC may<br>stop supporting in the future.<br><br>Please consider generating a new key file by going to:<br><strong>Database / Database Security / Change Key File.</strong><br> + + DatabaseSettingWidgetMetaData @@ -2324,6 +2326,15 @@ Disable safe saves and try again? [PROTECTED] Press Reveal to view or edit + + Invalid Entry + + + + An external merge operation has invalidated this entry. +Unfortunately, any changes made have been lost. + + EditEntryWidgetAdvanced @@ -3464,11 +3475,6 @@ Are you sure to add this file? [PROTECTED] [PROTECTED] - - <b>%1</b>: %2 - attributes line - <b>%1</b>: %2 - Enabled Enabled @@ -3489,6 +3495,15 @@ Are you sure to add this file? Advanced Advanced + + Default Sequence + + + + <tr><td><b>%1</b>:</td><td>%2</td></tr> + attributes line + + EntryURLModel @@ -3522,23 +3537,8 @@ Are you sure to add this file? - - FdoSecrets::Item - - Entry "%1" from database "%2" was used by %3 - - - FdoSecrets::Service - - %n Entry(s) was used by %1 - %1 is the name of an application - - - - - Failed to register DBus service at %1.<br/> @@ -4362,10 +4362,6 @@ If this reoccurs, then your database file may be corrupt. <p>You can add a key file containing random bytes for additional security.</p><p>You must keep it secret and never lose it or you will be locked out!</p> <p>You can add a key file containing random bytes for additional security.</p><p>You must keep it secret and never lose it or you will be locked out!</p> - - Legacy key file format - Legacy key file format - Error loading the key file '%1' Message: %2 @@ -4434,10 +4430,11 @@ Are you sure you want to continue with this file? - You are using a legacy key file format which may become -unsupported in the future. - -Generate a new key file in the database security settings. + Old key file format + + + + You selected a key file in an old format which KeePassXC<br>may stop supporting in the future.<br><br>Please consider generating a new key file instead. @@ -5780,16 +5777,6 @@ Expect some bugs and minor issues, this version is not meant for production use. Perform advanced analysis on the password. Perform advanced analysis on the password. - - WARNING: You are using a legacy key file format which may become -unsupported in the future. - -Please consider generating a new key file. - WARNING: You are using a legacy key file format which may become -unsupported in the future. - -Please consider generating a new key file. - @@ -6180,10 +6167,6 @@ Available commands: %1: (row, col) %2,%3 %1: (row, col) %2,%3 - - Argon2 (KDBX 4 – recommended) - Argon2 (KDBX 4 – recommended) - AES-KDF (KDBX 4) AES-KDF (KDBX 4) @@ -6760,10 +6743,6 @@ Kernel: %3 %4 AES (%1 rounds) - - Argon2 (%1 rounds, %2 KB) - - AES 256-bit @@ -6800,6 +6779,45 @@ Kernel: %3 %4 path to a custom local config file + + WARNING: You are using an old key file format which KeePassXC may +stop supporting in the future. + +Please consider generating a new key file. + + + + Argon2%1 (%2 rounds, %3 KB) + + + + Argon2d (KDBX 4 – recommended) + + + + Argon2id (KDBX 4) + + + + TOTP + TOTP + + + Icon + Icon + + + Unsupported key file version: %1 + + + + Checksum mismatch! Key file may be corrupt. + + + + Unexpected key file data! Key file may be corrupt. + + QtIOCompressor diff --git a/share/translations/keepassx_en_US.ts b/share/translations/keepassx_en_US.ts index 907226d80..7fb1fed78 100644 --- a/share/translations/keepassx_en_US.ts +++ b/share/translations/keepassx_en_US.ts @@ -2454,7 +2454,7 @@ Disable safe saves and try again? EditEntryWidgetBrowser These settings affect to the entry's behaviour with the browser extension. - These settings affect to the entry's behavior with the browser extension. + These settings affect the browser extension’s behavior with regard to this database entry. General @@ -2470,7 +2470,7 @@ Disable safe saves and try again? Additional URL's - Additional URL's + Additional URLs Add diff --git a/share/translations/keepassx_es.ts b/share/translations/keepassx_es.ts index 224bfeec2..685bf6ec9 100644 --- a/share/translations/keepassx_es.ts +++ b/share/translations/keepassx_es.ts @@ -229,7 +229,7 @@ Remember database key files and security dongles - Recordar los últimos ficheros claves y los «dongle» de seguridad + Recuerde los archivos de clave de la base de datos y los «dongle» de seguridad Check for updates at application startup once per week @@ -1177,7 +1177,7 @@ Copia de seguridad de base de datos ubicada en %2 Recycle Bin - Papelera + Papelera de reciclaje Passwords @@ -1204,7 +1204,7 @@ Copia de seguridad de base de datos ubicada en %2 DatabaseOpenWidget Key File: - Fichero clave: + Fichero Clave: Refresh @@ -1258,7 +1258,7 @@ Considere generar un nuevo fichero clave. Hardware key slot selection - Selección de ranura de clave hardware + Selección de ranura de llave por hardware Browse for key file @@ -1274,11 +1274,11 @@ Considere generar un nuevo fichero clave. Hardware Key: - Clave hardware: + Llave por hardware: Hardware key help - Ayuda de clave hardware + Ayuda de la llave por hardware TouchID for Quick Unlock @@ -1317,7 +1317,7 @@ Para prevenir que aparezca este error, debe ir a «Configuración de base de dat <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> <p>Click for more information...</p> - <p>Puede usar una clave de seguridad hardware como <strong>YubiKey</strong> o <strong>OnlyKey</strong> con ranuras configuradas para HMAC-SHA1.</p> + <p>Puede usar una llave de seguridad por hardware como <strong>YubiKey</strong> o <strong>OnlyKey</strong> con ranuras configuradas para HMAC-SHA1.</p> <p>Clic para más información...</p> @@ -1352,15 +1352,15 @@ Si no tiene un fichero clave, deje el campo vacío. Detecting hardware keys… - Detectando claves hardware... + Detectando llaves por hardware... No hardware keys detected - No se detectaron claves hardware + No se detectaron llaves por hardware Select hardware key… - Seleccionar clave hardware... + Seleccionar llave por hardware... @@ -1589,7 +1589,7 @@ Are you sure you want to continue without a password? Key Derivation Function: - Función de derivación de la llave: + Función de derivación de la clave: Transform rounds: @@ -1670,7 +1670,7 @@ Si conserva este número, ¡su base de datos puede tardar horas o días (o inclu You are using a very low number of key transform rounds with AES-KDF. If you keep this number, your database may be too easy to crack! - Está utilizando una cantidad muy baja de rondas de transformación de llave con AES-KDF. + Está utilizando un número muy bajo de rondas de transformación de clave con AES-KDF. Si conserva este número, ¡su base de datos puede ser muy fácil de descifrar! @@ -1680,7 +1680,7 @@ Si conserva este número, ¡su base de datos puede ser muy fácil de descifrar!< Failed to transform key with new KDF parameters; KDF unchanged. - Error al transformar la llave con nuevos parámetros KDF; KDF sin cambios. + Error al transformar la clave con nuevos parámetros KDF; KDF sin cambios. MiB @@ -1710,7 +1710,7 @@ Si conserva este número, ¡su base de datos puede ser muy fácil de descifrar!< Key derivation function - Función de derivación de la llave + Función de derivación de la clave Transform rounds @@ -2000,7 +2000,7 @@ Esto es definitivamente un error, por favor repórtelo a los desarrolladores. Do you really want to move %n entry(s) to the recycle bin? - ¿Desea mover %n apunte a la papelera?¿Desea mover %n apuntes a la papelera? + ¿Desea mover %n apunte a la papelera?¿Desea mover %n apuntes a la papelera de reciclaje? Execute command? @@ -2137,11 +2137,11 @@ Disable safe saves and try again? Move group to recycle bin? - ¿Mover grupo a la papelera? + ¿Mover grupo a la papelera de reciclaje? Do you really want to move the group "%1" to the recycle bin? - ¿Desea mover el grupo «%1» a la papelera? + ¿Desea mover el grupo «%1» a la papelera de reciclaje? Successfully merged the database files. @@ -2642,7 +2642,7 @@ Disable safe saves and try again? Add key to agent when database is opened/unlocked - Añadir llave al agente cuando la base de datos se abre/desbloquea + Añadir clave al agente cuando la base de datos se abre/desbloquea Comment @@ -2687,7 +2687,7 @@ Disable safe saves and try again? Require user confirmation when this key is used - Requiere confirmación del usuario cuando se usa esta llave + Requiere confirmación del usuario cuando se usa esta clave Remove key from agent after specified seconds @@ -2958,7 +2958,7 @@ Las extensiones soportadas son: %1. %n icon(s) already exist in the database - El icono %n ya existe en la base de datosLos %n iconos ya existen en la base de datos + El icono %n ya existe en la base de datosLos %n icono(s) ya existe(n) en la base de datos The following icon(s) failed: @@ -2966,7 +2966,7 @@ Las extensiones soportadas son: %1. This icon is used by %n entry(s), and will be replaced by the default icon. Are you sure you want to delete it? - Este icono es usado en %1 apunte, y será remplazado por el icono por defecto. ¿Está seguro que desea eliminarlo?Este icono es usado en %1 apuntes, y será remplazado por el icono predeterminado. ¿Está seguro que desea eliminarlo? + Este icono es usado en %1 apunte, y será remplazado por el icono por defecto. ¿Está seguro que desea eliminarlo?Este icono es usado en %n apunte(s), y será remplazado por el icono predeterminado. ¿Está seguro que desea eliminarlo? You can enable the DuckDuckGo website icon service under Tools -> Settings -> Security @@ -3203,9 +3203,9 @@ Your database may get very large and reduce performance. Are you sure to add this file? %1 es un fichero grande (%2 MB). -Tu base de datos puede vovlerse muy grande y reducir el rendimiento. +Su base de datos puede vovlerse muy grande y reducir el rendimiento. -¿Estás seguro de añadir este fichero? +¿Está seguro de añadir este fichero? Confirm Attachment @@ -3724,7 +3724,7 @@ Si ocurre nuevamente entonces su archivo de base de datos puede estar corrupto.< Unsupported key derivation function (KDF) or invalid parameters - Función de derivación de cerradura no admitida (KDF) o parámetros no válidos + Función de derivación de clave no admitida (KDF) o parámetros no válidos Legacy header fields found in KDBX4 file. @@ -4118,7 +4118,7 @@ Linea %2, columna %3 Key transformation failed - Error en la transformación de la llave + Error en la transformación de la clave Invalid group field type number @@ -4317,7 +4317,7 @@ Si ocurre nuevamente entonces su archivo de base de datos puede estar corrupto.< Key File - Fichero clave + Fichero Clave <p>You can add a key file containing random bytes for additional security.</p><p>You must keep it secret and never lose it or you will be locked out!</p> @@ -4325,7 +4325,7 @@ Si ocurre nuevamente entonces su archivo de base de datos puede estar corrupto.< Legacy key file format - Formato de archivo llave heredado + Formato de archivo fichero clave heredado Error loading the key file '%1' @@ -4355,7 +4355,7 @@ Mensaje: %2 Select a key file - Seleccione un archivo llave + Seleccionar un fichero clave Key file selection @@ -4829,11 +4829,11 @@ Espere algunos errores y problemas menores, esta versión no está destinada par Show Toolbar - Mostrar barra de herrameintas + Mostrar barra de herramientas Show Preview Panel - Mostrar panel de previsualizción + Mostrar panel de previsualización Don't show again for this version @@ -5115,7 +5115,7 @@ Espere algunos errores y problemas menores, esta versión no está destinada par OpenSSHKey Invalid key file, expecting an OpenSSH key - Archivo llave no válido, esperando una llave de OpenSSH + Fichero clave no válido, esperando una clave de OpenSSH PEM boundary mismatch @@ -5579,7 +5579,7 @@ Espere algunos errores y problemas menores, esta versión no está destinada par Empty - Vacío + Vaciar Remove @@ -6791,7 +6791,7 @@ Núcleo: %3 %4 Hover over reason to show additional details. Double-click entries to edit. - Pasar por encima de la razón para mostrar detalles adicionales. Doble clic para editar. + Pasar por encima del motivo para mostrar detalles adicionales. Doble clic para editar. Bad @@ -6850,7 +6850,7 @@ Núcleo: %3 %4 Reason - Razón + Motivo Edit Entry... @@ -7087,7 +7087,7 @@ Núcleo: %3 %4 Agent refused this identity. Possible reasons include: - El agente rechazó esta identidad. Las posibles razones incluyen: + El agente rechazó esta identidad. Los posibles motivos incluyen: The key has already been added. @@ -7569,7 +7569,7 @@ Núcleo: %3 %4 TotpDialog Timed Password - Contraseña cronometrada + Contraseña temporizada 000000 @@ -7581,7 +7581,7 @@ Núcleo: %3 %4 Expires in <b>%n</b> second(s) - Caduca en <b>%n</b> segundo(s)Caduca en <b>%n</b> segundo (s) + Caduca en <b>%n</b> segundoCaduca en <b>%n</b> segundos @@ -7601,7 +7601,7 @@ Núcleo: %3 %4 Closing in %1 seconds. - Cernado en %1 segundos. + Cerrando en %1 segundos. @@ -7807,19 +7807,19 @@ Ejemplo: JBSWY3DPEHPK3PXP Hardware key is currently in use. - La clave hardware está actualmente en uso. + La llave por hardware está actualmente en uso. Could not find hardware key with serial number %1. Please plug it in to continue. - No se puede encontrar hardware con número de serie %1. Conéctelo para continuar. + No se puede encontrar llave por hardware con número de serie %1. Conéctelo para continuar. Hardware key timed out waiting for user interaction. - La clave hardware expiró esperando interacción del usuario. + La llave por hardware expiró esperando interacción del usuario. A USB error ocurred when accessing the hardware key: %1 - Ha ocurrido un error USB al acceder a la clave hardware: %1 + Ha ocurrido un error USB al acceder a la llave por hardware: %1 Failed to complete a challenge-response, the specific error was: %1 @@ -7846,23 +7846,23 @@ Ejemplo: JBSWY3DPEHPK3PXP Hardware key slot selection - Selección de ranura de clave hardware + Selección de ranura de llave por hardware Could not find any hardware keys! - ¡No se puede encontrar ninguna clave hardware! + ¡No se puede encontrar ninguna llave por hardware! Selected hardware key slot does not support challenge-response! - ¡La ranura de la clave hardware seleccionada no soporta reto-respuesta! + ¡La ranura de la llave por hardware seleccionada no soporta reto-respuesta! Detecting hardware keys… - Detectando claves hardware... + Detectando llaves por hardware... No hardware keys detected - No se detectaron claves hardware + No se detectaron llaves por hardware \ No newline at end of file diff --git a/share/translations/keepassx_fi.ts b/share/translations/keepassx_fi.ts index 4b6b57133..1931493e9 100644 --- a/share/translations/keepassx_fi.ts +++ b/share/translations/keepassx_fi.ts @@ -137,7 +137,7 @@ You must restart the application to set the new language. Would you like to restart now? - + Ohjelma täytyy käynnistää uudelleen, jotta uusi kieli voidaan ottaa käyttöön. Haluatko käynnistää uudelleen nyt? @@ -342,15 +342,15 @@ Automatically save when locking database - + Tallenna automaattisesti, kun tietokanta lukitaan Automatically save non-data changes when locking database - + Tallenna automaattisesti asetukset jotka eivät liity varsinaisiin tietoihin, kun tietokanta lukitaan Tray icon type - + Ilmoitusalueen ikonin tyyppi @@ -4849,23 +4849,23 @@ Bugeja ja ongelmia voi esiintyä. Tämä versio ei ole tarkoitettu päivittäise Perform Auto-Type Sequence - + Suorita automaattisyötön sekvenssi {USERNAME} - + {USERNAME} {USERNAME}{ENTER} - + {USERNAME}{ENTER} {PASSWORD} - + {PASSWORD} {PASSWORD}{ENTER} - + {PASSWORD}{ENTER} diff --git a/share/translations/keepassx_fr.ts b/share/translations/keepassx_fr.ts index 8dab361ae..55b29d7a4 100644 --- a/share/translations/keepassx_fr.ts +++ b/share/translations/keepassx_fr.ts @@ -330,15 +330,15 @@ Auto-Type typing delay: - Vitesse de remplissage de la saisie automatique : + Vitesse de remplissage de la saisie automatique : Global Auto-Type shortcut: - Raccourci de la saisie automatique : + Raccourci de la saisie automatique : Auto-Type start delay: - Délai de démarrage de la saisie automatique : + Délai de démarrage de la saisie automatique : Automatically save when locking database @@ -439,11 +439,11 @@ Require password repeat when it is visible - Demander de confirmer le mot de passe lorsque celui-ci est visible + Exiger la confirmation du mot de passe s’il est visible Hide passwords when editing them - Cacher les mots de passe pendant leur modification + Cacher les mots de passe lors de leur modification Use placeholder for empty password fields @@ -564,11 +564,11 @@ BrowserAccessControlDialog KeePassXC - Browser Access Request - Requiert l’accès à KeePassXC-Browser + KeePassXC-Browser - Requête d'accès au navigateur %1 is requesting access to the following entries: - %1 demande l’accès aux entrées suivantes : + %1 demande l’accès aux entrées suivantes : Remember access to checked entries @@ -892,7 +892,7 @@ chrome-laptop Browser type: - Type de navigateur : + Type de navigateur : Toolbar button style @@ -900,7 +900,7 @@ chrome-laptop Config Location: - Emplacement de configuration : + Emplacement de configuration : Custom browser location field @@ -2764,7 +2764,7 @@ Désactiver les enregistrements sécurisés et ressayer ? KeeShare unsigned container - Conteneur KeeShare non signé + Conteneur KeeShare non signé KeeShare signed container @@ -4135,7 +4135,7 @@ Ligne %2, colonne %3 Incorrect group creation time field size - Taille du champ "date du la création du groupe" incorrect. + Taille du champ « date du la création du groupe » incorrect. Incorrect group modification time field size @@ -4151,7 +4151,7 @@ Ligne %2, colonne %3 Incorrect group icon field size - Taille du champ "icône du groupe" incorrect. + Taille du champ « icône du groupe » incorrect. Incorrect group level field size @@ -4911,11 +4911,11 @@ Attendez-vous à des bogues et des problèmes mineurs. Cette version n’est pas Overwriting %1 [%2] - Écrasement de %1 [%2] + Remplacement de %1 [%2] older entry merged from database "%1" - ancienne entrée fusionnée de la base de données "%1" + ancienne entrée fusionnée de la base de données « %1 » Adding backup for older target %1 [%2] @@ -5065,7 +5065,7 @@ Attendez-vous à des bogues et des problèmes mineurs. Cette version n’est pas Unable to process clearText in place - Impossible d’activer le traitement de ClearText + Impossible d’appliquer l'amélioration ClearText Expected %1 bytes of clear-text, found %2 @@ -5282,7 +5282,7 @@ Attendez-vous à des bogues et des problèmes mineurs. Cette version n’est pas Character Types - Types de caractères: + Types de caractères Numbers @@ -5326,7 +5326,7 @@ Attendez-vous à des bogues et des problèmes mineurs. Cette version n’est pas Password Quality: %1 - Qualité du mot de passe : %1 + Qualité du mot de passe : %1 Poor @@ -5382,7 +5382,7 @@ Attendez-vous à des bogues et des problèmes mineurs. Cette version n’est pas Add non-hex letters to "do not include" list - Ajouter les lettres non-hexadécimales à la liste "Ne pas inclure" + Ajouter les lettres non-hexadécimales à la liste « Ne pas inclure » Hex @@ -5815,7 +5815,7 @@ Commandes proposées : malformed string - chaîne de caractères malformée + chaîne de caractères incorrecte missing closing quote @@ -5889,7 +5889,7 @@ Commandes proposées : Successfully added entry %1. - Ajouté avec succès l’entrée %1. + L’entrée %1 a bien été ajoutée. Invalid timeout value %1. @@ -6091,7 +6091,7 @@ Commandes proposées : Error reading merge file: %1 - Erreur lors de la lecture du fichier fusionner : + Erreur lors de la lecture du fichier à fusionner : %1 @@ -6104,11 +6104,11 @@ Commandes proposées : Successfully recycled entry %1. - Entrée %1 recyclée avec succès. + L'entrée %1 a bien été recyclée. Successfully deleted entry %1. - Supprimé l’entrée %1 avec succès. + L’entrée %1 a bien été supprimée. Show the entry's current TOTP. @@ -6128,7 +6128,7 @@ Commandes proposées : %1: (row, col) %2,%3 - %1: (ligne,colonne) %2,%3 + %1 : (ligne, colonne) %2, %3 Argon2 (KDBX 4 – recommended) @@ -6174,7 +6174,7 @@ Commandes proposées : No key is set. Aborting database creation. - Aucune clé définie. Abandon de la création de la base de données. + Aucune clé définie. La création de la base de données a été abandonnée. Failed to save the database: %1. @@ -6186,11 +6186,11 @@ Commandes proposées : Creating KeyFile %1 failed: %2 - Creation du fichier clé %1 échoué : %2 + Impossible de créer le fichier clé %1 : %2 Loading KeyFile %1 failed: %2 - Chargement du fichier clé %1 échoué : %2 + Impossible de charger le fichier clé %1 : %2 Path of the entry to remove. @@ -6366,7 +6366,7 @@ Noyau : %3 %4 Failed to open HIBP file %1: %2 - Échec de l’ouverture du fichier HIBP %1 : %2 + Impossible d'ouvrir le fichier HIBP %1 : %2 Evaluating database entries against HIBP file, this will take a while... @@ -6728,7 +6728,7 @@ Noyau : %3 %4 ChaCha20 256-bit - ChaCha20 : 256 bits {20 256 à ?} + ChaCha20 : 256 bits {20 256 à ?} Benchmark %1 delay @@ -7272,7 +7272,7 @@ Noyau : %3 %4 Key: - Clé : + Clé : Generate @@ -7357,7 +7357,7 @@ Noyau : %3 %4 The exported certificate is not the same as the one in use. Do you want to export the current certificate? - Le certificat exporté est différent de celui en cours d’utilisation. Souhaitez-vous exporter le certificat actuel ? + Le certificat exporté est différent de celui en cours d’utilisation. Souhaitez-vous exporter le certificat actuel  ? Signer: @@ -7565,7 +7565,7 @@ Noyau : %3 %4 TotpDialog Timed Password - Mot de passe programmé + Mot de passe planifié 000000 @@ -7633,7 +7633,7 @@ Noyau : %3 %4 Code size: - Taille du code : + Taille du code : Secret Key: @@ -7701,7 +7701,7 @@ Exemple : JBSWY3DPEHPK3PXP Update Error! - Erreur de mise à jour ! + Erreur lors de mise à jour ! An error occurred in retrieving update information. @@ -7729,7 +7729,7 @@ Exemple : JBSWY3DPEHPK3PXP You're up-to-date! - Votre version est à jour ! + Votre version est à jour ! KeePassXC %1 is currently the newest version available diff --git a/share/translations/keepassx_hr_HR.ts b/share/translations/keepassx_hr_HR.ts new file mode 100644 index 000000000..fa654915c --- /dev/null +++ b/share/translations/keepassx_hr_HR.ts @@ -0,0 +1,7829 @@ + + + AboutDialog + + About KeePassXC + Informacije o KeePassXC-u + + + About + O programu + + + Report bugs at: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> + Prijavite greške na: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> + + + KeePassXC is distributed under the terms of the GNU General Public License (GPL) version 2 or (at your option) version 3. + KeePassXC je distribuiran pod uvjetima GNU opće javne licence (GPL) verzija 2 ili (po vašoj želji) verzija 3. + + + Contributors + Suradnici + + + <a href="https://github.com/keepassxreboot/keepassxc/graphs/contributors">See Contributions on GitHub</a> + <a href="https://github.com/keepassxreboot/keepassxc/graphs/contributors">Pogledajte doprinose na GitHub-u</a> + + + Debug Info + Informacije za otklanjanje pogrešaka + + + Include the following information whenever you report a bug: + Priložite slijedeće informacije prilikom prijave greške: + + + Copy to clipboard + Kopiraj u međuspremnik + + + Project Maintainers: + Održavatelji projekta: + + + Special thanks from the KeePassXC team go to debfx for creating the original KeePassX. + Posebne zahvale KeePassXC tima idu debfx-u za stvaranje izvornog KeePassX-a. + + + + AgentSettingsWidget + + Use OpenSSH for Windows instead of Pageant + Koristi OpenSSH za Windows umjesto Pageant-a. + + + Enable SSH Agent integration + Omogući integraciju SSH agenta + + + SSH_AUTH_SOCK value + SSH_AUTH_SOCK vrijednost + + + SSH_AUTH_SOCK override + SSH_AUTH_SOCK nadjačanje + + + (empty) + (prazno) + + + No SSH Agent socket available. Either make sure SSH_AUTH_SOCK environment variable exists or set an override. + Nema dostupnog SSH Agenta. Ili potvrdite postojanje SSH_AUTH_SOCK vrijednosti okruženja ili podesite nadjačanje. + + + SSH Agent connection is working! + SSH Agent veza radi! + + + + ApplicationSettingsWidget + + Application Settings + Postavke aplikacije + + + General + Općenito + + + Security + Sigurnost + + + Access error for config file %1 + Pogreška pristupa za konfiguracijsku datoteku %1 + + + Icon only + Samo ikone + + + Text only + Samo tekst + + + Text beside icon + Tekst uz ikone + + + Text under icon + Tekst ispod ikona + + + Follow style + Prati stil + + + Reset Settings? + Poništi Postavke? + + + Are you sure you want to reset all general and security settings to default? + Želite li zaista vratiti sve opće i sigurnosne postavke na zadano? + + + Monochrome (light) + Jednobojna(svijetla) + + + Monochrome (dark) + Jednobojna(tamna) + + + Colorful + Raznobojna + + + You must restart the application to set the new language. Would you like to restart now? + Morate ponovo pokrenuti aplikaciju kako biste postavili novi jezik. Želite li ju ponovo pokrenuti sada? + + + + ApplicationSettingsWidgetGeneral + + Basic Settings + Osnovne Postavke + + + Startup + Pokretanje + + + Start only a single instance of KeePassXC + Pokreni samo jedan primjer KeePassXC-a + + + Minimize window at application startup + Smanji prozor prilikom pokretanja aplikacije + + + File Management + Upravljanje Datotekama + + + Backup database file before saving + Napravi sigurnosnu kopiju datoteke baze podataka prije spremanja + + + Automatically save after every change + Automatski spremi poslije svake izmjene + + + Automatically reload the database when modified externally + Automatski iznova otvori bazu podataka kada je modificirana izvana + + + Entry Management + Upravljanje Stavkama + + + Use group icon on entry creation + Koristi ikonu grupe pri stvaranju stavki + + + Minimize instead of app exit + Smanji aplikaciju umjesto izlaženje + + + Show a system tray icon + Prikaži ikonu sistemske ladice + + + Hide window to system tray when minimized + Sakrij prozor u sistemsku ladicu kada je smanjen + + + Auto-Type + Automatsko-tipkanje + + + Use entry title to match windows for global Auto-Type + Upotrijebi naziv stavke za podudaranje prozora pri globalnom Auto-tipkanju + + + Use entry URL to match windows for global Auto-Type + Upotrijebi URL stavke za podudaranje prozora pri globalnom Auto-tipkanju + + + Always ask before performing Auto-Type + Uvijek pitaj prije izvođenja Auto-tipkanja + + + ms + Milliseconds + ms + + + Movable toolbar + Pokretna alatna traka + + + Remember previously used databases + Zapamti prethodno korištene baze podataka + + + Load previously open databases on startup + Učitaj prethodno otvorene baze podataka pri pokretanju + + + Remember database key files and security dongles + Zapamti datoteku ključa i hardverske ključeve baze podataka + + + Check for updates at application startup once per week + Provjeri dostupnost dopuna pri pokretanju aplikacije jednom tjedno + + + Include beta releases when checking for updates + Obuhvati beta izdanja tokom provjere za nadopune + + + Language: + Jezik: + + + (restart program to activate) + (ponovo pokrenite program za aktivaciju) + + + Minimize window after unlocking database + Smanji prozor nakon otključavanja baze podataka + + + Minimize when opening a URL + Smanji prilikom otvaranja ULR-a + + + Hide window when copying to clipboard + Sakrij prozor prilikom kopiranja u međuspremnik + + + Minimize + Smanji + + + Drop to background + Spusti u pozadinu + + + Favicon download timeout: + Istek vremena za preuzimanje favikona: + + + Website icon download timeout in seconds + Istek vremena za preuzimanje ikona mrežnih stranica u sekundama + + + sec + Seconds + sek + + + Toolbar button style + Stil gumba alatne trake + + + Language selection + Odabir jezika + + + Global auto-type shortcut + Globalni prečac auto-tipkanja + + + Auto-type character typing delay milliseconds + Auto-tipkanje odgoda pisanja znakova milisekunde + + + Auto-type start delay milliseconds + Auto-tipkanje odgoda pokretanja milisekunde + + + Automatically launch KeePassXC at system startup + Automatski pokreni KeePassXC pri pokretanju sustava + + + Safely save database files (disable if experiencing problems with Dropbox, etc.) + Sigurno spremi datoteke baze podataka (onemogućite ako imate problema sa Dropbox-om i sl.) + + + User Interface + Korisničko Sučelje + + + Toolbar button style: + Stil gumba alatne trake: + + + Use monospaced font for notes + Koristi font fiksne širine za bilješke + + + Tray icon type: + Vrsta ikone ladice: + + + Reset settings to default… + Vrati postavke na zadano... + + + Auto-Type typing delay: + Auto-tipkanje odgoda pisanja: + + + Global Auto-Type shortcut: + Globalni Auto-tipkanje prečac: + + + Auto-Type start delay: + Auto-tipkanje odgoda pokretanja: + + + Automatically save when locking database + Automatski spremi prilikom zaključavanja baze podataka + + + Automatically save non-data changes when locking database + Automatski sačuvaj bespodatkovne izmjene prilikom zaključavanja baze podataka + + + Tray icon type + Vrsta ikone ladice + + + + ApplicationSettingsWidgetSecurity + + Timeouts + Istek vremena + + + Clear clipboard after + Obriši međuspremnik nakon + + + sec + Seconds + sek + + + Lock databases after inactivity of + Zaključaj bazu podataka nakon neaktivnosti od + + + min + min + + + Forget TouchID after inactivity of + Zaboravi TouchID nakon neaktivnosti od + + + Convenience + Pogodnost + + + Lock databases when session is locked or lid is closed + Zaključaj bazu podataka kada je sesija zaključana ili poklopac zatvoren + + + Forget TouchID when session is locked or lid is closed + Zaboravi TouchID kada je sesija zaključanja ili je poklopac zatvoren + + + Lock databases after minimizing the window + Zaključaj baze podataka nakon smanjenja prozora + + + Re-lock previously locked database after performing Auto-Type + Ponovo zaključaj prethodno zaključanu bazu podataka nakon izvođenja Auto-Tipkanja + + + Hide passwords in the entry preview panel + Sakrij lozinke na ploči za pregled stavki + + + Hide entry notes by default + Sakrij bilješke stavki pod zadano + + + Privacy + Privatnost + + + Use DuckDuckGo service to download website icons + Koristi DuckDuckGo usluge za preuzimanje ikona mrežnih stranica + + + Clipboard clear seconds + Brisanje međuspremnika sekunde + + + Touch ID inactivity reset + Ponovo pokretanje TouchID nakon neaktivnosti + + + Database lock timeout seconds + Istek vremena za zaključavanje baze podataka u sekundama + + + min + Minutes + min + + + Clear search query after + Obriši upite pretage nakon + + + Require password repeat when it is visible + Zahtijevaj ponavljanje lozinke kada je vidljiva + + + Hide passwords when editing them + Sakrij lozinke tokom uređivanja + + + Use placeholder for empty password fields + Koristi rezervirana mjesta za prazna polja lozinki + + + + AutoType + + Couldn't find an entry that matches the window title: + Stavku koja odgovara naslovu prozora nije moguće naći: + + + Auto-Type - KeePassXC + Auto-Tipkanje - KeePassXC + + + Auto-Type + Automatsko-tipkanje + + + The Syntax of your Auto-Type statement is incorrect! + Sintaksa Vaše Auto-Tipkane izjave je netočna! + + + This Auto-Type command contains a very long delay. Do you really want to proceed? + Ova Auto-Tipkana naredba sadrži vrlo dugo kašnjenje. Želite li zaista nastaviti? + + + This Auto-Type command contains very slow key presses. Do you really want to proceed? + Ova Auto-Tipkana naredba sadrži vrlo spore pritiske tipki. Želite li zaista nastaviti? + + + This Auto-Type command contains arguments which are repeated very often. Do you really want to proceed? + Ova Auto-Tipkana naredba sadrži argumente koji se često ponavljaju. Želite li zaista nastaviti? + + + Permission Required + Potrebna Dozvola + + + KeePassXC requires the Accessibility permission in order to perform entry level Auto-Type. If you already granted permission, you may have to restart KeePassXC. + KeePassXC zahtijeva dozvolu Pristupačnosti kako bi izvršio Auto-Tipkanje stavki . Ako ste mu već dali dozvolu, možda ćete morati ponovno pokrenuti KeePassXC. + + + + AutoTypeAssociationsModel + + Window + Prozor + + + Sequence + Redoslijed + + + Default sequence + Zadani redoslijed + + + + AutoTypeMatchModel + + Group + Grupa + + + Title + Naslov + + + Username + Korisničko ime + + + Sequence + Redoslijed + + + + AutoTypeMatchView + + Copy &username + Kopiraj &korisničko ime + + + Copy &password + Kopiraj &lozinku + + + + AutoTypePlatformMac + + Permission Required + Potrebna Dozvola + + + KeePassXC requires the Accessibility and Screen Recorder permission in order to perform global Auto-Type. Screen Recording is necessary to use the window title to find entries. If you already granted permission, you may have to restart KeePassXC. + KeePassXC zahtijeva dozvolu Pristupačnosti i Snimača Zaslona kako bi izvršio globalno Auto-Tipkanje. Snimanje Zaslona je potrebno za korištenje naslova prozora pri pronalaženju stavki. Ako ste mu već dali dozvolu, možda ćete morati ponovno pokrenuti KeePassXC. + + + + AutoTypeSelectDialog + + Auto-Type - KeePassXC + Auto-Tipkanje - KeePassXC + + + Select entry to Auto-Type: + Odaberite stavku za Auto-Tipkanje + + + Search... + Traži... + + + + BrowserAccessControlDialog + + KeePassXC - Browser Access Request + KeePassXC - Zahtjev za Pristup Pregledniku + + + %1 is requesting access to the following entries: + %1 zahtijeva pristup sljedećim stavkama: + + + Remember access to checked entries + Zapamti pristup označenim stavkama + + + Remember + Zapamti + + + Allow access to entries + Dopusti pristup stavkama + + + Allow Selected + Dopusti Odabrane + + + Deny All + Odbij Sve + + + Disable for this site + Onemogući za ovu stranicu + + + + BrowserEntrySaveDialog + + KeePassXC-Browser Save Entry + Spremi Stavku KeePassXC-Preglednika + + + Ok + Ok + + + Cancel + Otkaži + + + You have multiple databases open. +Please select the correct database for saving credentials. + Imate više otvorenih baza podataka. +Odaberite ispravnu bazu podataka za spremanje vjerodajnica. + + + + BrowserService + + KeePassXC: New key association request + KeePassXC: Novi zahtjev za udruženje ključa + + + Save and allow access + Spremi i omogući pristup + + + KeePassXC: Overwrite existing key? + KeePassXC: Presnimi postojeći ključ? + + + A shared encryption key with the name "%1" already exists. +Do you want to overwrite it? + Zajednički ključ za šifriranje s nazivom "%1" već postoji. +Želite li ga pesnimiti? + + + KeePassXC: Update Entry + KeePassXC: Dopuni Stavku + + + Do you want to update the information in %1 - %2? + Želite li nadopuniti informacije u %1 - %2? + + + Abort + Prekini + + + Converting attributes to custom data… + Pretvaranje svojstava u prilagođene podatke... + + + KeePassXC: Converted KeePassHTTP attributes + KeePassXC: Pretvorena KeePassHTTP svojstva + + + Successfully converted attributes from %1 entry(s). +Moved %2 keys to custom data. + Uspješno pretvorena svojstva od %1 stavke(i). +%2 ključa premještena u prilagođene podatke. + + + Successfully moved %n keys to custom data. + Uspješno premješten %n ključ u prilagođene podatke.Uspješno premještena %n ključa u prilagođene podatke.Uspješno premješteno %n ključeva u prilagođene podatke. + + + KeePassXC: No entry with KeePassHTTP attributes found! + KeePassXC: Nema stavki s KeePassHTTP svojstvima! + + + The active database does not contain an entry with KeePassHTTP attributes. + Aktivna baza podataka nema stavke sa KeePassHTTP svojstvom. + + + KeePassXC: Legacy browser integration settings detected + KeePassXC: Otkrivene zastarjele postavke integracije preglednika + + + KeePassXC: Create a new group + KeePassXC: Stvori novu grupu + + + A request for creating a new group "%1" has been received. +Do you want to create this group? + + Zaprimljen je zahtjev za stvaranje nove grupe "%1". +Želite li stvoriti ovu grupu? + + + + Your KeePassXC-Browser settings need to be moved into the database settings. +This is necessary to maintain your current browser connections. +Would you like to migrate your existing settings now? + Vaše KeePassXC postavke preglednika potrebno je premjestiti u postavke baze podataka. +To je potrebno za održavanje trenutnih veza preglednika. +Želite li premjestiti postojeće postavke sada? + + + Don't show this warning again + Nemoj više prikazivati ovo upozorenje. + + + You have received an association request for the following database: +%1 + +Give the connection a unique name or ID, for example: +chrome-laptop. + Dobilii ste zahtjev udruženja za sljedeću bazu podataka: +%1 + +Dajte vezi jedinstveno ime ili ID, na primjer: +chrome-laptop. + + + + BrowserSettingsWidget + + Dialog + Dijalog + + + This is required for accessing your databases with KeePassXC-Browser + Ovo je potrebno za pristup vašim bazama podataka pomoću KeePassXC-Preglednika + + + Enable browser integration + Omogući integraciju preglednika + + + General + Općentio + + + Browsers installed as snaps are currently not supported. + Preglednici instalirani kao snap-ovi trenutno nisu podržani. + + + Enable integration for these browsers: + Omogućite integraciju za ove preglednike: + + + Vivaldi + Vivaldi + + + &Edge + &Edge + + + Firefox + Firefox + + + Tor Browser + Tor Browser + + + Brave + Brave + + + Google Chrome + Google Chrome + + + Chromium + Chromium + + + Show a notification when credentials are requested + Credentials mean login data requested via browser extension + Prikaži obavijest kada se zatraže podaci za prijavu + + + Request to unlock the database if it is locked + Zatraži otključavanje baze podataka ako je zaključana + + + Only entries with the same scheme (http://, https://, ...) are returned. + Vraćene su samo stavke s istom shemom (http://, https://, ...). + + + Match URL scheme (e.g., https://...) + Uskladi shemu URL-a(npr. https://...) + + + Only returns the best matches for a specific URL instead of all entries for the whole domain. + Vraća samo najbolja podudaranja za određeni URL, umjesto svih stavki za cijelu domene. + + + Return only best-matching credentials + Vrati samo najprikladnije podatke za prijavu + + + Returns expired credentials. String [expired] is added to the title. + Vraća istekle podatke za prijavu. Znakovni niz [istekao] se dodaje naslovu. + + + Allow returning expired credentials + Dopusti vraćanje podataka kojima je istekao rok + + + All databases connected to the extension will return matching credentials. + Sve baze podataka povezane s proširenjem vratit će odgovarajuće podatke za prijavu. + + + Search in all opened databases for matching credentials + Credentials mean login data requested via browser extension + Traži odgovarajuće podatke za prijavu u svim otvorenim bazama podataka + + + Sort matching credentials by title + Credentials mean login data requested via browser extension + Sortiraj odgovarajuće podatke za prijavu po naslovu + + + Sort matching credentials by username + Credentials mean login data requested via browser extension + Sortiraj odgovarajuće podatke za prijavu po korisničkom imenu + + + Advanced + Napredno + + + Never ask before accessing credentials + Credentials mean login data requested via browser extension + Nikad ne pitaj prije nego što zatražite pristup podacima za prijavu + + + Never ask before updating credentials + Credentials mean login data requested via browser extension + Nikad ne pitaj prije nego što ažurirate podataka za prijavu + + + Do not ask permission for HTTP Basic Auth + An extra HTTP Basic Auth setting + Nemoj tražiti dozvolu za HTTP Basic Auth + + + Automatically creating or updating string fields is not supported. + Automatsko stvaranje ili nadopunjavanje polja znakovnih nizova nije podržano. + + + Return advanced string fields which start with "KPH: " + Vratite napredna polja znakovnog niza koji počinje s "KPH: " + + + Don't display the popup suggesting migration of legacy KeePassHTTP settings. + Nemoj prikazivati skočni zaslon koji predlaže migraciju zastarjelih postavki KeePassHTTP-a. + + + Do not prompt for KeePassHTTP settings migration. + Ne prikazuj podsjetnik za migriranje zastarjelih postavki KeePassHTTP-a. + + + Updates KeePassXC or keepassxc-proxy binary path automatically to native messaging scripts on startup. + Prilikom pokretanja automatski ažuriraj binarnu putanju KeePassXC-a ili keepassxc-proxy-a u izvorne skripte za slanje poruka. + + + Update native messaging manifest files at startup + + + + Use a custom proxy location if you installed a proxy manually. + Koristi prilagođenu lokaciju proxy-a ako ste ručno instalirali proxy. + + + Use a custom proxy location: + Meant is the proxy for KeePassXC-Browser + Koristi prilagođenu lokaciju proxy-a: + + + Custom proxy location field + Polje prilagođene lokacije proxy-a + + + Browser for custom proxy file + Preglednik za prilagođenu proxy datoteku + + + Browse... + Button for opening file dialog + Pretraživanje... + + + Use a custom browser configuration location: + Koristi prilagođenu lokaciju konfiguracije preglednika: + + + Browser type: + Vrsta preglednika: + + + Toolbar button style + Stil gumba alatne trake + + + Config Location: + Lokacija konfiguracije: + + + Custom browser location field + Prilagođeno polje lokacije preglednika + + + ~/.custom/config/Mozilla/native-messaging-hosts/ + ~/.custom/config/Mozilla/native-messaging-hosts/ + + + Browse for custom browser path + + + + Custom extension ID: + Prilagođena ID proširenja: + + + Custom extension ID + Prilagođena ID proširenja + + + Due to Snap sandboxing, you must run a script to enable browser integration.<br />You can obtain this script from %1 + Zbog Snap-ovog odvojenog pokrretanja, morate pokrenuti skriptu kako biste omogućili integraciju preglednika.<br />Tu skriptu možete dobiti od %1 + + + KeePassXC-Browser is needed for the browser integration to work. <br />Download it for %1 and %2 and %3. %4 + KeePassXC-Preglednik potreban je za funkcioniranje integracije preglednika. <br />Preuzmite ga na %1 i %2 i %3. %4 + + + Please see special instructions for browser extension use below + + + + <b>Error:</b> The custom proxy location cannot be found!<br/>Browser integration WILL NOT WORK without the proxy application. + <b>Pogreška:</b> Prilagođena lokacija proxy-a nije pronađena!<br/>Integracija preglednika NEĆE FUNKCIONIRATI bez proxy aplikacije. + + + <b>Warning:</b> The following options can be dangerous! + <b>Upozorenje:</b> Sljedeće opcije mogu biti opasne! + + + Executable Files + Izvršne datoteke + + + All Files + Sve datoteke + + + Select custom proxy location + Odaberite prilagođenu lokaciju proxy-a + + + Select native messaging host folder location + + + + + CloneDialog + + Clone Options + Opcije Kloniranja + + + Append ' - Clone' to title + Dodataj ' - Klon' naslovu + + + Replace username and password with references + + + + Copy history + Povijesti kopiranja + + + + CsvImportWidget + + Import CSV fields + Uvezi CSV polja + + + filename + ime datoteke + + + size, rows, columns + veličina, redovi, stupci + + + Encoding + Kodiranje + + + Codec + Kodek + + + Text is qualified by + + + + Fields are separated by + + + + Comments start with + + + + Consider '\' an escape character + + + + Preview + Pregled + + + Imported from CSV file + Uvezeno iz CSV datoteke + + + Original data: + Izvorni podaci: + + + Error + Pogreška + + + Error(s) detected in CSV file! + Greška(e) otkrivena u CSV datoteci! + + + [%n more message(s) skipped] + [%n poruka preskočena][još %n poruke preskočeno][još %n poruka preskočeno] + + + CSV import: writer has errors: +%1 + + + + Text qualification + + + + Field separation + + + + Number of header lines to discard + + + + CSV import preview + Pregled CSV uvoza + + + Column Association + + + + Last Modified + Posljednja izmjena + + + Password + Lozinka + + + Created + Stvoreno + + + Notes + Bilješke + + + Title + Naslov + + + Group + Grupa + + + URL + URL + + + Username + Korisničko ime + + + Header lines skipped + Linije zaglavlje preskočene + + + First line has field names + Prva linija ima nazive polja + + + Not Present + Nije prisutno + + + Column %1 + Stupac %1 + + + + CsvParserModel + + %n column(s) + %n stupac%n stupaca%n stupaca + + + %1, %2, %3 + file info: bytes, rows, columns + %1, %2, %3 + + + %n byte(s) + %n bajt%n bajta%n bajtova + + + %n row(s) + %n redak%n retka%n redova + + + + Database + + File %1 does not exist. + Datoteka %1 ne postoji. + + + Unable to open file %1. + Datoteku %1 nije moguće otvoriti. + + + Error while reading the database: %1 + Pogreška tijekom čitanja baze podataka: %1 + + + File cannot be written as it is opened in read-only mode. + + + + Key not transformed. This is a bug, please report it to the developers! + + + + %1 +Backup database located at %2 + %1 +Sigurnosna kopija baza podataka nalazi se na %2 + + + Could not save, database does not point to a valid file. + + + + Could not save, database file is read-only. + + + + Database file has unmerged changes. + Datoteka baze podataka ima nesjedinjene promjene. + + + Recycle Bin + Koš za smeće + + + Passwords + Root group name + Lozinke + + + Database save is already in progress. + Spremanje baze podataka je u toku. + + + Could not save, database has not been initialized! + + + + + DatabaseOpenDialog + + Unlock Database - KeePassXC + Otključaj bazu podataka - KeePassXC + + + + DatabaseOpenWidget + + Key File: + Datoteka ključa: + + + Refresh + Osvježi + + + Legacy key file format + Zastarjeli format datoteke ključa + + + You are using a legacy key file format which may become +unsupported in the future. + +Please consider generating a new key file. + Koristite zastarjeli format datoteke ključa koji može postati +nepodržan u budućnosti. + +Razmislite o generiranju nove datoteke ključa. + + + Don't show this warning again + Nemoj više pokazivati ovo upozorenje. + + + All files + Sve datoteke + + + Key files + Datoteke ključeva + + + Select key file + Odaberite datoteku ključa + + + Failed to open key file: %1 + Otvaranja datoteke ključa nije uspjelo: %1 + + + Unlock KeePassXC Database + Otključaj bazu podataka KeePassXC + + + Enter Password: + Unesite lozinku: + + + Password field + Polje lozinke + + + Hardware key slot selection + + + + Browse for key file + Potraži datoteku ključa + + + Browse... + Pretraživanje... + + + Refresh hardware tokens + Osvježi hardverske tokene + + + Hardware Key: + Hardverski ključ: + + + Hardware key help + Hardverski ključ pomoć + + + TouchID for Quick Unlock + TouchID za Brzo Otključavanje + + + Clear + Obriši + + + Clear Key File + Obriši datoteku ključa + + + Unlock failed and no password given + + + + Unlocking the database failed and you did not enter a password. +Do you want to retry with an "empty" password instead? + +To prevent this error from appearing, you must go to "Database Settings / Security" and reset your password. + + + + Retry with empty password + + + + Enter Additional Credentials (if any): + Unesite dodatne vjerodajnice (ako ih ima): + + + <p>You can use a hardware security key such as a <strong>YubiKey</strong> or <strong>OnlyKey</strong> with slots configured for HMAC-SHA1.</p> +<p>Click for more information...</p> + <p>Možete koristiti hardverski sigurnosni ključ kao što <strong>je YubiKey</strong> <strong>ili OnlyKey</strong> s utorima podešenim za HMAC-SHA1.</p> +<p>Kliknite za više informacija...</p> + + + Key file help + Datoteka ključa pomoć + + + ? + ? + + + Cannot use database file as key file + Nije moguće koristiti datoteku baze podataka kao datoteku ključa + + + You cannot use your database file as a key file. +If you do not have a key file, please leave the field empty. + Ne možete koristiti datoteku baze podataka kao datoteku ključa. +Ako nemate datoteku ključa, ostavite polje prazno. + + + <p>In addition to a password, you can use a secret file to enhance the security of your database. This file can be generated in your database's security settings.</p><p>This is <strong>not</strong> your *.kdbx database file!<br>If you do not have a key file, leave this field empty.</p><p>Click for more information...</p> + <p>Uz lozinke, možete koristiti tajnu datoteku kako biste poboljšali sigurnost svoje baze podataka. Ta se datoteka može proizvesti u sigurnosnim postavkama baze podataka.</p><p>Ovo nije <strong>Vaša</strong> *.kdbx datoteka baze podataka!<br>Ako nemate datoteku ključa, ostavite ovo polje prazno.</p><p>Kliknite za više informacija...</p> + + + Key file to unlock the database + Datoteka ključa za otključavanje baze podataka + + + Please touch the button on your YubiKey! + Molimo prritisnite gumb na svom YubiKey! + + + Detecting hardware keys… + Otkrivanje hardverskih ključeva... + + + No hardware keys detected + Nijedan hardverski ključ otkrivene + + + Select hardware key… + Odaberite hardverski ključ... + + + + DatabaseSettingWidgetMetaData + + Passwords + Lozinke + + + + DatabaseSettingsDialog + + Advanced Settings + Napredne Postavke + + + General + Generalno + + + Security + Sigurnost + + + Encryption Settings + Postavke Šifriranja + + + Browser Integration + Integracija preglednika + + + Database Credentials + Vjerodajnice baze podataka + + + + DatabaseSettingsWidgetBrowser + + KeePassXC-Browser settings + KeePassXC-Postavke preglednika + + + Stored keys + Spremljeni ključevi + + + Remove + Ukloni + + + Delete the selected key? + Izbriši odabrani ključ? + + + Do you really want to delete the selected key? +This may prevent connection to the browser plugin. + Želite li zaista izbrisati odabrani ključ? +To može spriječiti vezu sa priključkom preglednika + + + Key + Ključ + + + Value + Vrijednost + + + Enable Browser Integration to access these settings. + Omogući Integraciji Preglednika pristup ovim postavkama + + + Disconnect all browsers + Odspoji sve preglednike... + + + Do you really want to disconnect all browsers? +This may prevent connection to the browser plugin. + Želite li zaista odspojiti sve preglednike? +To može spriječiti vezu sa priključkom preglednika. + + + KeePassXC: No keys found + KeePassXC: Nijedan ključ nije pronađen + + + No shared encryption keys found in KeePassXC settings. + Nijedni dijeljeni ključevi za šifriranje nisu prronađeni u KeePassXC postavkama. + + + KeePassXC: Removed keys from database + KeePassXC: Uklonjeni ključevi iz baze podataka + + + Successfully removed %n encryption key(s) from KeePassXC settings. + Uspješno uklonjen %n ključ za šifriranje iz KeePassXC postavki.Uspješno uklonjena %n ključa za šifriranje iz KeePassXC postavki.Uspješno uklonjeno %n ključeva za šifriranje iz KeePassXC postavki. + + + Forget all site-specific settings on entries + + + + Do you really want forget all site-specific settings on every entry? +Permissions to access entries will be revoked. + Želite li zaista zaboraviti sve specifične postavke stranice za svaku stavku? +Dozvole za pristup stavkama bit će opozvane. + + + Removing stored permissions… + Uklanjanje pohranjenih dozvola... + + + Abort + Prekini + + + KeePassXC: Removed permissions + KeePassXC: Uklonjene dozvole + + + Successfully removed permissions from %n entry(s). + Uspješno uklonjena dozvola od %n stavke.Uspješno uklonjene dozvole od %n stavke.Uspješno uklonjene dozvole od %n stavki. + + + KeePassXC: No entry with permissions found! + KeePassXC: Nijedna stavka sa dozvolama nije pronađena! + + + The active database does not contain an entry with permissions. + Aktivna baza podataka nema stavki sa dozvolama. + + + Move KeePassHTTP attributes to custom data + Premjesti KeePassHTTP svojstva u prilagođene podatke + + + Do you really want to move all legacy browser integration data to the latest standard? +This is necessary to maintain compatibility with the browser plugin. + + + + Stored browser keys + Pohranjeni ključevi preglednika + + + Remove selected key + Ukloni odabrani ključ + + + Move KeePassHTTP attributes to KeePassXC-Browser custom data + Premjesti KeePassHTTP svojstva u prilagođene podatke KeePassXC-Preglednik-a + + + Refresh database root group ID + Osvježi ID izvorne grupe baze podataka + + + Created + Stvorio + + + Refresh database ID + Osvježi ID baze podataka + + + Do you really want refresh the database ID? +This is only necessary if your database is a copy of another and the browser extension cannot connect. + Želite li zaista osvježiti ID baze podataka? +To je potrebno samo ako je vaša baza podataka kopija druge i dodaci preglednika se ne mogu povezati. + + + + DatabaseSettingsWidgetDatabaseKey + + Add additional protection... + + + + No password set + Lozinka nije postavljena + + + WARNING! You have not set a password. Using a database without a password is strongly discouraged! + +Are you sure you want to continue without a password? + UPOZORENJE! Niste postavili lozinku. Korištenje baze podataka bez lozinke nije preporučeno + +Želite li zaista nastaviti bez lozinke? + + + Continue without password + Nastavi bez lozinke + + + No encryption key added + Nijedan ključ za šifriranje nije dodan + + + You must add at least one encryption key to secure your database! + Morate dodati barem jedan ključ za šifriranje kako biste osigurali svoju bazu podataka! + + + Unknown error + Nepoznata pogreška + + + Failed to change database credentials + Neuspjela promjena vjerodajnica baze podataka + + + + DatabaseSettingsWidgetEncryption + + Encryption Algorithm: + Algoritam šifriranja: + + + AES: 256 Bit (default) + AES: 256 Bit (zadano) + + + Twofish: 256 Bit + Twofish: 256 Bit + + + Key Derivation Function: + + + + Transform rounds: + + + + Memory Usage: + + + + Parallelism: + Paralelizam: + + + Decryption Time: + Vrijeme dešifriranja: + + + ?? s + ?? s + + + Change + Promijni + + + Higher values offer more protection, but opening the database will take longer. + Veće vrijednosti nude veću zaštitu, ali otvaranje baze podataka trajat će dulje. + + + Database format: + Format baze podataka: + + + This is only important if you need to use your database with other programs. + Ovo je važno samo ako trebate koristiti svoju bazu podataka s drugim programima. + + + KDBX 4.0 (recommended) + KDBX 4.0 (preporučeno) + + + KDBX 3.1 + KDBX 3.1 + + + unchanged + Database decryption time is unchanged + nepromijenjeno + + + Number of rounds too high + Key transformation rounds + + + + You are using a very high number of key transform rounds with Argon2. + +If you keep this number, your database may take hours or days (or even longer) to open! + + + + Understood, keep number + + + + Cancel + Otkaži + + + Number of rounds too low + Key transformation rounds + + + + You are using a very low number of key transform rounds with AES-KDF. + +If you keep this number, your database may be too easy to crack! + + + + KDF unchanged + KDF nepromijenjen + + + Failed to transform key with new KDF parameters; KDF unchanged. + + + + MiB + Abbreviation for Mebibytes (KDF settings) + Baza BazaMiB + + + thread(s) + Threads for parallel execution (KDF settings) + konac(e) konac(e)Nit(i) + + + Change existing decryption time + + + + Decryption time in seconds + Vrijeme dešifriranja u sekundama + + + Database format + Format baze podataka + + + Encryption algorithm + Algoritam šifriranja + + + Key derivation function + + + + Transform rounds + + + + Memory usage + Iskorištenost memorije + + + Parallelism + Paralelizam + + + ?? ms + ?? ms + + + ? s + ? s + + + + DatabaseSettingsWidgetFdoSecrets + + Exposed Entries + Izložene stavke + + + Don't expose this database + Ne izlaži ovu bazu podataka + + + Expose entries under this group: + Izložene stavke unutar ove grupe: + + + Enable Secret Service to access these settings. + Omogućite Tajnu Službu za pristup ovim postavkama. + + + + DatabaseSettingsWidgetGeneral + + Database Meta Data + Meta Podaci Baze Podataka + + + Database name: + Naziv baze podataka: + + + Database description: + Opis baze podataka: + + + Default username: + Zadano korisničko ime: + + + History Settings + Postavke povijesti + + + Max. history items: + + + + Max. history size: + + + + MiB + MiB + + + Use recycle bin + Koristi koš za smeće + + + Additional Database Settings + Dodatne Postavke Baze Podataka + + + Database name field + Polje naziva baze podataka + + + Database description field + Polje opisa baze podataka + + + Default username field + Polje zadanog korisničkog imena + + + Maximum number of history items per entry + + + + Maximum size of history per entry + + + + Delete Recycle Bin + Izbriši koš za smeće + + + Do you want to delete the current recycle bin and all its contents? +This action is not reversible. + Želite li izbrisati trenutni koš za smeće i sav njezin sadržaj? +Ovu radnju nije moguće povratit. + + + (old) + (staro) + + + Enable compression (recommended) + Omogući sažimanje (preporučeno) + + + + DatabaseSettingsWidgetKeeShare + + Sharing + Dijeljenje + + + Breadcrumb + + + + Type + Vrsta + + + Path + Put + + + Last Signer + + + + Certificates + Certifikati + + + > + Breadcrumb separator + > + + + + DatabaseSettingsWidgetMetaDataSimple + + Database Name: + Naziv baze podataka: + + + Description: + Opis: + + + Database name field + Polje naziva baze podataka + + + Database description field + Polje opisa baze podataka + + + + DatabaseTabWidget + + KeePass 2 Database + KeePass 2 Baza Podataka + + + All files + Sve datoteke + + + Open database + Otvori Bazu Podataka + + + CSV file + CSV datoteka + + + Merge database + Sjedini baze podataka + + + Open KeePass 1 database + Otvori KeePass 1 bazu podataka + + + KeePass 1 database + KeePass 1 Baza podataka + + + Export database to CSV file + Izvezi bazu podataka u CSV datoteku + + + Writing the CSV file failed. + Pisanje CSV datoteke nije uspjelo. + + + Database creation error + Pogreška pri stvaranju baze podataka + + + The created database has no key or KDF, refusing to save it. +This is definitely a bug, please report it to the developers. + Stvorena baza podataka nema ključ ili KDF, odbijam ju spremiti. +Ovo je definitivno pogreška, molimo prijavite to programerima. + + + Select CSV file + Odaberite CSV datoteku + + + New Database + Nova Baza Podataka + + + %1 [New Database] + Database tab name modifier + %1 [Nova Baza Podataka] + + + %1 [Locked] + Database tab name modifier + %1 [Zaključano] + + + %1 [Read-only] + Database tab name modifier + %1 [Samo za čitanje] + + + Failed to open %1. It either does not exist or is not accessible. + Otvoranje %1 nije uspjelo. Ili ne postoji ili nije dostupno. + + + Export database to HTML file + Izvezi bazu podataka u HTML datoteku + + + HTML file + HTML datoteka + + + Writing the HTML file failed. + Pisanje HTML datoteke nije uspjelo. + + + Export Confirmation + Potvrda izvoza + + + You are about to export your database to an unencrypted file. This will leave your passwords and sensitive information vulnerable! Are you sure you want to continue? + + + + Open OPVault + Otvori OPVault + + + + DatabaseWidget + + Searching... + Pretraživanje... + + + Do you really want to delete the entry "%1" for good? + Želite li zaista izbrisati stavku "%1"? + + + Do you really want to move entry "%1" to the recycle bin? + Želite li zaista premjestiti stavku "%1" u koš za smeće? + + + Do you really want to move %n entry(s) to the recycle bin? + Želite li zaista premjestiti %n stavku u koš za smeće?Želite li zaista premjestiti %n stavke u koš za smeće?Želite li zaista premjestiti %n stavki u koš za smeće? + + + Execute command? + Izvrši naredbu? + + + Do you really want to execute the following command?<br><br>%1<br> + Želite li zaista izvršiti sljedeću naredbu?<br><br>%1<br> + + + Remember my choice + Zapamti moj izbora. + + + Do you really want to delete the group "%1" for good? + Želite li zaista izbrisati grupu "%1"? + + + No current database. + Nema trenutne baze podataka. + + + No source database, nothing to do. + Nema izvorne baze podataka, nema ništa za raditi. + + + Search Results (%1) + Rezultati pretraživanja (%1) + + + No Results + Nema rezultata + + + File has changed + Datoteka se promijenila + + + The database file has changed. Do you want to load the changes? + Datoteka baze podataka se promijenila. Želite li učitati promjene? + + + Merge Request + Zahtjev za spajanje + + + The database file has changed and you have unsaved changes. +Do you want to merge your changes? + Datoteka baze podataka se promijenila i imate nespremljene promjene. +Želite li sjediniti svoje promjene? + + + Empty recycle bin? + Isprazni koš za smeće? + + + Are you sure you want to permanently delete everything from your recycle bin? + + + + Do you really want to delete %n entry(s) for good? + Želite li zaista izbrisati %n stavku zauvijek?Želite li zaista izbrisati %n stavke zauvijek?Želite li zaista izbrisati %n stavki zauvijek? + + + Delete entry(s)? + Izbrisati unose(e)?Izbrisati unose(e)?Izbriši stavku(e)? + + + Move entry(s) to recycle bin? + Premjestiti unos(e) u koš za smeće?Premjestiti unos(e) u koš za smeće?Premjestiti stavku(e) u koš za smeće? + + + Lock Database? + Zaključaj Baza Podataka? + + + You are editing an entry. Discard changes and lock anyway? + Uređujete stavku. Svejedno odbaci promjene i zaključaj? + + + "%1" was modified. +Save changes? + "%1" je izmijenjen. +Spremi promjene? + + + Database was modified. +Save changes? + Baza podataka je izmijenjena. +Spremi promjene? + + + Save changes? + Spremi promjene? + + + Could not open the new database file while attempting to autoreload. +Error: %1 + + + + Disable safe saves? + Onemogući sigurno spremanje? + + + KeePassXC has failed to save the database multiple times. This is likely caused by file sync services holding a lock on the save file. +Disable safe saves and try again? + + + + Passwords + Lozinke + + + Save database as + Spremi bazu podataka kao + + + KeePass 2 Database + KeePass 2 Baza Podataka + + + Replace references to entry? + + + + Entry "%1" has %2 reference(s). Do you want to overwrite references with values, skip this entry, or delete anyway? + + + + Delete group + Izbriši grupu + + + Move group to recycle bin? + Premjesti grupu u koš za smeće? + + + Do you really want to move the group "%1" to the recycle bin? + Želite li zaista premjestiti grupu "%1" u koš za smeće? + + + Successfully merged the database files. + Uspješno spojene datoteke baze podataka. + + + Database was not modified by merge operation. + Baza podataka nije izmijenjena operacijom sjedinjenja. + + + Shared group... + Zajednička grupa... + + + Writing the database failed: %1 + + + + This database is opened in read-only mode. Autosave is disabled. + + + + Save database backup + + + + Could not find database file: %1 + + + + + EditEntryWidget + + Entry + Stavka + + + Advanced + Napredno + + + Icon + Ikona + + + Auto-Type + Auto-tipkanje + + + Properties + Svojstva + + + History + Povijest + + + SSH Agent + SSH Agent + + + n/a + n/d + + + (encrypted) + (šifrirano) + + + Select private key + Odaberite privatni ključ + + + Entry history + Povjest stavki + + + Add entry + Dodaj stavku + + + Edit entry + Uredi stavku + + + New attribute + Novo svojstvo + + + Are you sure you want to remove this attribute? + Jeste li sigurni da želite ukloniti ovo svojstvo? + + + Tomorrow + Sutra + + + %n week(s) + %n tjedan%n tjedana%n tjedana + + + %n month(s) + %n mjesec%n mjeseca%n mjeseci + + + Entry updated successfully. + Stavka uspješno nadopunjena. + + + New attribute %1 + Novo svojstvo %1 + + + %n year(s) + %n godina%n godine%n godina + + + Confirm Removal + Potvrdi brisanje + + + Browser Integration + Integracija preglednika + + + <empty URL> + <empty URL> + + + Are you sure you want to remove this URL? + Želite li zaista ukloniti ovaj URL? + + + Reveal + Otkrij + + + Hide + Sakrij + + + Unsaved Changes + Nespremljene promjene + + + Would you like to save changes to this entry? + Želite li spremiti promjene u ovom stavku? + + + [PROTECTED] Press Reveal to view or edit + [ZAŠTIĆENO] Pritisnite Otkrij za prikaz ili uređivanje + + + + EditEntryWidgetAdvanced + + Additional attributes + Dodatna svojstava + + + Add + Dodaj + + + Remove + Ukloni + + + Edit Name + Uredi naziv + + + Protect + Zaštiti + + + Reveal + Otkrij + + + Attachments + Privitci + + + Foreground Color: + Prednja boja: + + + Background Color: + Pozadinska boja: + + + Attribute selection + Odabir svojstava + + + Attribute value + Vrijednost svojstva + + + Add a new attribute + Dodaj novo svojstvo + + + Remove selected attribute + Ukloni odabrana svojstva + + + Edit attribute name + Uredi ime svojstva + + + Toggle attribute protection + Uključi / isključi zaštitu svojstava + + + Show a protected attribute + Prikaži zaštićena svojstva + + + Foreground color selection + Odabir prednje boje + + + Background color selection + Odabir pozadinske boje + + + <html><head/><body><p>If checked, the entry will not appear in reports like Health Check and HIBP even if it doesn't match the quality requirements (e. g. password entropy or re-use). You can set the check mark if the password is beyond your control (e. g. if it needs to be a four-digit PIN) to prevent it from cluttering the reports.</p></body></html> + + + + Exclude from database reports + Izostavi iz izvješća baze podataka + + + + EditEntryWidgetAutoType + + Enable Auto-Type for this entry + Omogućite Auto-Tipkanje za ovu stavku + + + Window Associations + + + + + + + + + + - + - + + + Window title: + Naslov prozora: + + + Use a specific sequence for this association: + Koristi specifičan redoslijed za ovu asocijaciju: + + + Custom Auto-Type sequence + Prilagođen redoslijed Auto-Tipkanja + + + Open Auto-Type help webpage + + + + Existing window associations + + + + Add new window association + + + + Remove selected window association + + + + You can use an asterisk (*) to match everything + + + + Set the window association title + Postavite naslov za asociranja prozora + + + You can use an asterisk to match everything + + + + Custom Auto-Type sequence for this window + Prilagođen redoslijed Auto-Tipkanja za ovaj prozor + + + Inherit default Auto-Type sequence from the group + Naslijedi zadani redoslijed Auto-Tipkanja od grupe + + + Use custom Auto-Type sequence: + Koristi pilagođen redoslijed Auto-Tipkanja: + + + + EditEntryWidgetBrowser + + These settings affect to the entry's behaviour with the browser extension. + + + + General + Generalno + + + Skip Auto-Submit for this entry + + + + Hide this entry from the browser extension + Sakrij ovu stavku od proširenja preglednika + + + Additional URL's + Dodatni URL-ovi + + + Add + Dodaj + + + Remove + Ukloni + + + Edit + Uredi + + + Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. + Samo pošaljite ovu postavku pregledniku za HTTP Auth dijaloge. Ako je omogućeno, normalni obrasci za prijavu neće prikazati ovu stavku za odabir. + + + Use this entry only with HTTP Basic Auth + Koristi ovu stavku samo s HTTP Basic Auth + + + + EditEntryWidgetHistory + + Show + Prikaži + + + Restore + Vrati + + + Delete + Izbriši + + + Delete all + Obriši sve + + + Entry history selection + Odabir povijesti stavke + + + Show entry at selected history state + Prikaži stavku u odabranom trenutku povijesti + + + Restore entry to selected history state + Vrati stavku u odabranom trenutku vremena + + + Delete selected history state + + + + Delete all history + Obriši svu povijest + + + + EditEntryWidgetMain + + URL: + URL: + + + Password: + Lozinka: + + + Title: + Naslov: + + + Presets + + + + Toggle the checkbox to reveal the notes section. + + + + Username: + Korisničko ime: + + + Url field + Polje URL-a + + + Download favicon for URL + Preuzmi favikonu za URL + + + Password field + Polje lozinke + + + Toggle notes visible + Uključi / Isključi vidljivost bilješki + + + Expiration field + + + + Expiration Presets + + + + Expiration presets + + + + Notes field + Polje bilješki + + + Title field + Polje naslova + + + Username field + Polje korisničkog imena + + + Toggle expiration + Uključi / Isključi rok trajanja + + + Notes: + Bilješke: + + + https://example.com + https://example.com + + + Expires: + Ističe: + + + + EditEntryWidgetSSHAgent + + Form + Obrazac + + + Remove key from agent after + + + + seconds + sekunde + + + Fingerprint + Otisak + + + Remove key from agent when database is closed/locked + Ukloni ključ iz agenta kada je baza podataka zatvorena/zaključana + + + Public key + Javni ključ + + + Add key to agent when database is opened/unlocked + Dodajte ključ agentu kada se baza podataka otvori/otključa + + + Comment + Komentar + + + Decrypt + Dešifriraj + + + n/a + n/d + + + Copy to clipboard + Kopiraj u predmemoriju + + + Private key + Privatni ključ + + + External file + Vanjska datoteka + + + Browse... + Button for opening file dialog + Pretraživanje... + + + Attachment + Privitak + + + Add to agent + Dodaj agentu + + + Remove from agent + Ukloni iz agenta + + + Require user confirmation when this key is used + Zahtijevaj potvrdu korisnika kada se ovaj ključ koristi + + + Remove key from agent after specified seconds + + + + Browser for key file + Preglednik za datoteku ključa + + + External key file + + + + Select attachment file + + + + + EditGroupWidget + + Group + Grupa + + + Icon + Ikona + + + Properties + Svojstva + + + Add group + Dodaj grupu + + + Edit group + Uredi grupu + + + Enable + Omogući + + + Disable + Onemogući + + + Inherit from parent group (%1) + + + + Entry has unsaved changes + Stavka ima nespremljene promjene + + + + EditGroupWidgetKeeShare + + Type: + Vrsta: + + + Path: + Put: + + + Password: + Lozinka: + + + Inactive + Neaktivna + + + KeeShare unsigned container + + + + KeeShare signed container + + + + Select import source + + + + Select export target + + + + Select import/export file + + + + Clear + Obriši + + + Import + Uvezi + + + Export + Izvezi + + + Synchronize + Sinkroniziraj + + + Your KeePassXC version does not support sharing this container type. +Supported extensions are: %1. + Vaša KeePassXC verzija ne podržava dijeljenje ove vrste spremnika. +Podržana proširenja su: %1. + + + %1 is already being exported by this database. + + + + %1 is already being imported by this database. + + + + %1 is being imported and exported by different groups in this database. + + + + KeeShare is currently disabled. You can enable import/export in the application settings. + KeeShare is a proper noun + + + + Database export is currently disabled by application settings. + + + + Database import is currently disabled by application settings. + + + + Sharing mode field + + + + Path to share file field + + + + Password field + Polje lozinke + + + Clear fields + Obriši polja + + + Browse for share file + Potraži zajedničku datoteku + + + Browse... + Pretraživanje... + + + + EditGroupWidgetMain + + Name field + Polje naziva + + + Notes field + Polje bilješki + + + Toggle expiration + Uključi / Isključi rok trajanja + + + Auto-Type toggle for this and sub groups + + + + Expiration field + + + + Search toggle for this and sub groups + + + + Default auto-type sequence field + Polje zadanog redoslijeda auto-tipkanja + + + Expires: + Ističe: + + + Use default Auto-Type sequence of parent group + Koristi zadani redoslijed Auto-Tipkanja nadređene grupe + + + Auto-Type: + Auto-Tipkanje + + + Search: + Pretraživanje: + + + Notes: + Bilješke: + + + Name: + Naziv: + + + Set default Auto-Type sequence + Postavi zadani redoslijeda auto-tipkanja + + + + EditWidgetIcons + + Add custom icon + Dodaj prilagođenu ikonu + + + Delete custom icon + Obriši prilagođenu ikonu + + + Download favicon + Preuzmi favikone + + + Unable to fetch favicon. + + + + Images + Slike + + + All files + Sve datoteke + + + Confirm Delete + Potvrdi Brisanje + + + Select Image(s) + Odabir slike(a) + + + Successfully loaded %1 of %n icon(s) + Uspješno učitana %1 od %n ikoneUspješno učitane %1 od %n ikoneUspješno učitano %1 od %n ikona + + + No icons were loaded + Nijedna ikona nije učitana + + + %n icon(s) already exist in the database + %n ikona već postoji u bazi podataka%n ikone već postoje u bazi podataka%n ikona već postoji u bazi podataka + + + The following icon(s) failed: + + + + This icon is used by %n entry(s), and will be replaced by the default icon. Are you sure you want to delete it? + Ovu ikonu koristi %n stavka stoga će biti zamijenjena zadanom ikona. Želite li zaista ju izbrisati?Ovu ikonu koristi %n stavke stoga će biti zamijenjene zadanom ikona. Želite li zaista ju izbrisati?Ovu ikonu koristi %n stavki stoga će biti zamijenjene zadanim ikona. Želite li zaista ju izbrisati? + + + You can enable the DuckDuckGo website icon service under Tools -> Settings -> Security + + + + Download favicon for URL + Preuzmi favikonu za URL + + + Apply selected icon to subgroups and entries + + + + Also apply to child groups + + + + Also apply to child entries + + + + Also apply to all children + + + + Existing icon selected. + + + + Use default icon + Koristi zadanu ikonu + + + Use custom icon + Koristi prilagođenu ikonu + + + Apply icon to... + + + + Apply to this group only + + + + + EditWidgetProperties + + Created: + Stvoreno: + + + Modified: + Izmijenjeno: + + + Accessed: + Pristupljeno: + + + Uuid: + Uuid: + + + Plugin Data + + + + Remove + Ukloni + + + Delete plugin data? + + + + Do you really want to delete the selected plugin data? +This may cause the affected plugins to malfunction. + + + + Key + Ključ + + + Value + Vrijednost + + + Datetime created + Datum i vrijeme stvaranja + + + Datetime modified + Datum i vrijeme izmijene + + + Datetime accessed + Datum i vrijeme pristupanja + + + Unique ID + Jedinstveni ID + + + Plugin data + Podaci priključka + + + Remove selected plugin data + Ukloni odabrane podataka priključka + + + + Entry + + %1 - Clone + %1 - Klon + + + + EntryAttachmentsModel + + Name + Naziv + + + Size + Veličina + + + + EntryAttachmentsWidget + + Form + Obrazac + + + Add + Dodaj + + + Remove + Ukloni + + + Open + Otvori + + + Save + Spremi + + + Select files + Odaberi datoteke + + + Are you sure you want to remove %n attachment(s)? + Želite li zaista ukloniti %n privitak?Želite li zaista ukloniti %n privitaka?Želite li zaista ukloniti %n privitaka? + + + Save attachments + Spremi privitke + + + Unable to create directory: +%1 + + + + Are you sure you want to overwrite the existing file "%1" with the attachment? + + + + Confirm overwrite + + + + Unable to save attachments: +%1 + + + + Unable to open attachment: +%1 + + + + Unable to open attachments: +%1 + + + + Confirm remove + + + + Unable to open file(s): +%1 + + + + Attachments + Privitci + + + Add new attachment + Dodaj novi privitak + + + Remove selected attachment + Ukloni odabrani privitak + + + Open selected attachment + Otvori odabrani privitak + + + Save selected attachment to disk + Spremi odabrani privitak na disk + + + %1 is a big file (%2 MB). +Your database may get very large and reduce performance. + +Are you sure to add this file? + + + + Confirm Attachment + + + + + EntryAttributesModel + + Name + Naziv + + + + EntryHistoryModel + + Last modified + Posljednja izmjena + + + Title + Naslov + + + Username + Korisničko ime + + + URL + URL + + + + EntryModel + + Ref: + Reference abbreviation + + + + Group + Grupa + + + Title + Naslov + + + Username + Korisničko ime + + + URL + URL + + + Never + Nikad + + + Password + Lozinka + + + Notes + Bilješke + + + Expires + Ističe + + + Created + Stvorio + + + Modified + Izmijenjeno + + + Accessed + Pristupljeno + + + Attachments + Privitci + + + Size + Veličina + + + Group name + Naziv grupe + + + Entry title + Ime stavke + + + Entry notes + Bilješke stavke + + + Entry expires at + Stavka ističe u + + + Creation date + Datum stvaranja + + + Last modification date + Datum zadnje izmjene + + + Last access date + Datum zadnjeg pristupa + + + Attached files + Priložene datoteke + + + Entry size + Veličina stavke + + + Has attachments + Ima privitke + + + Has TOTP one-time password + Ima TOTP jednokratnu lozinku + + + + EntryPreviewWidget + + Close + Zatvori + + + General + Generalno + + + Username + Korisničko ime + + + Password + Lozinka + + + Expiration + Rok trajanja + + + URL + URL + + + Attributes + Svojstva + + + Attachments + Privitci + + + Notes + Bilješke + + + Autotype + Auto-Tipkanje + + + Window + Prozor + + + Sequence + Redoslijed + + + Searching + Pretraživanje + + + Search + Traži + + + Clear + Obriši + + + Never + Nikad + + + [PROTECTED] + [ZAŠTIĆENO] + + + <b>%1</b>: %2 + attributes line + <b>%1</b>: %2 + + + Enabled + Omogućeno + + + Disabled + Onemogući + + + Share + Podijeli + + + Display current TOTP value + Prikaži trenutnu TOTP vrijednosti + + + Advanced + Napredno + + + + EntryURLModel + + Invalid URL + Nevaljan URL + + + + EntryView + + Customize View + + + + Hide Usernames + Sakrij korisnička imena + + + Hide Passwords + Sakrij Lozinke + + + Fit to window + + + + Fit to contents + + + + Reset to defaults + Vrati na zadano... + + + Has attachments + Entry attachment icon toggle + Ima privitke + + + Has TOTP + Entry TOTP icon toggle + Ima TOTP + + + + FdoSecrets::Item + + Entry "%1" from database "%2" was used by %3 + + + + + FdoSecrets::Service + + %n Entry(s) was used by %1 + %1 is the name of an application + + + + Failed to register DBus service at %1.<br/> + + + + + FdoSecrets::SettingsDatabaseModel + + File Name + Naziv Datoteke + + + Group + Grupa + + + Manage + + + + Unlock to show + Otključajte za prikaz + + + None + Nijedan + + + + FdoSecrets::SettingsSessionModel + + Application + Aplikacija + + + Manage + + + + + FdoSecretsPlugin + + <b>Fdo Secret Service:</b> %1 + + + + Unknown + Unknown PID + Nepoznat + + + Unknown + Unknown executable path + Nepoznat + + + <i>PID: %1, Executable: %2</i> + <i>PID: 1234, Executable: /path/to/exe</i> + + + + Another secret service is running (%1).<br/>Please stop/remove it before re-enabling the Secret Service Integration. + + + + + Group + + [empty] + group has no children + [prazno] + + + + HibpDownloader + + Online password validation failed + + + + + IconDownloaderDialog + + Download Favicons + Preuzmi Favikone + + + Cancel + Otkaži + + + Having trouble downloading icons? +You can enable the DuckDuckGo website icon service in the security section of the application settings. + + + + Close + Zatvori + + + URL + URL + + + Status + Status + + + Please wait, processing entry list... + + + + Downloading... + Preuzimanje... + + + Ok + Ok + + + Already Exists + Već Postoji + + + Download Failed + Preuzimanje nije uspjelo + + + Downloading favicons (%1/%2)... + Preuzimanje favikona (%1/%2)... + + + + KMessageWidget + + &Close + &Zatvori + + + Close message + + + + + Kdbx3Reader + + missing database headers + + + + Header doesn't match hash + + + + Invalid header id size + + + + Invalid header field length + + + + Invalid header data length + + + + Invalid credentials were provided, please try again. +If this reoccurs, then your database file may be corrupt. + + + + Unable to calculate database key + + + + Unable to issue challenge-response: %1 + + + + + Kdbx3Writer + + Unable to issue challenge-response: %1 + + + + Unable to calculate database key + + + + + Kdbx4Reader + + missing database headers + + + + Invalid header checksum size + + + + Header SHA256 mismatch + + + + Unknown cipher + + + + Invalid header id size + + + + Invalid header field length + + + + Invalid header data length + + + + Failed to open buffer for KDF parameters in header + + + + Unsupported key derivation function (KDF) or invalid parameters + + + + Legacy header fields found in KDBX4 file. + Zastarjela polja zaglavlje pronađena u KDBX4 datoteci. + + + Invalid inner header id size + + + + Invalid inner header field length + + + + Invalid inner header binary size + + + + Unsupported KeePass variant map version. + Translation: variant map = data structure for storing meta data + + + + Invalid variant map entry name length + Translation: variant map = data structure for storing meta data + + + + Invalid variant map entry name data + Translation: variant map = data structure for storing meta data + + + + Invalid variant map entry value length + Translation: variant map = data structure for storing meta data + + + + Invalid variant map entry value data + Translation comment: variant map = data structure for storing meta data + + + + Invalid variant map Bool entry value length + Translation: variant map = data structure for storing meta data + + + + Invalid variant map Int32 entry value length + Translation: variant map = data structure for storing meta data + + + + Invalid variant map UInt32 entry value length + Translation: variant map = data structure for storing meta data + + + + Invalid variant map Int64 entry value length + Translation: variant map = data structure for storing meta data + + + + Invalid variant map UInt64 entry value length + Translation: variant map = data structure for storing meta data + + + + Invalid variant map entry type + Translation: variant map = data structure for storing meta data + + + + Invalid variant map field type size + Translation: variant map = data structure for storing meta data + + + + Invalid credentials were provided, please try again. +If this reoccurs, then your database file may be corrupt. + + + + (HMAC mismatch) + + + + Unable to calculate database key: %1 + + + + + Kdbx4Writer + + Invalid symmetric cipher algorithm. + + + + Invalid symmetric cipher IV size. + IV = Initialization Vector for symmetric cipher + + + + Failed to serialize KDF parameters variant map + Translation comment: variant map = data structure for storing meta data + + + + Unable to calculate database key: %1 + + + + + KdbxReader + + Unsupported cipher + + + + Invalid compression flags length + + + + Unsupported compression algorithm + + + + Invalid master seed size + + + + Invalid transform seed size + + + + Invalid transform rounds size + + + + Invalid start bytes size + + + + Invalid random stream id size + + + + Invalid inner random stream cipher + + + + Not a KeePass database. + Nije KeePass baza podataka. + + + The selected file is an old KeePass 1 database (.kdb). + +You can import it by clicking on Database > 'Import KeePass 1 database...'. +This is a one-way migration. You won't be able to open the imported database with the old KeePassX 0.4 version. + + + + Unsupported KeePass 2 database version. + + + + Invalid cipher uuid length: %1 (length=%2) + + + + Unable to parse UUID: %1 + + + + Failed to read database file. + + + + + KdbxXmlReader + + XML parsing failure: %1 + + + + No root group + + + + Missing icon uuid or data + + + + Missing custom data key or value + + + + Multiple group elements + + + + Null group uuid + + + + Invalid group icon number + + + + Invalid EnableAutoType value + + + + Invalid EnableSearching value + + + + No group uuid found + + + + Null DeleteObject uuid + + + + Missing DeletedObject uuid or time + + + + Null entry uuid + + + + Invalid entry icon number + + + + History element in history entry + + + + No entry uuid found + + + + History element with different uuid + + + + Duplicate custom attribute found + Pronađen duplikat prilagođenog svojstva + + + Entry string key or value missing + + + + Entry binary key or value missing + + + + Auto-type association window or sequence missing + Asocirani prozor ili redoslijed Auto-Tipkanja nedostaje + + + Invalid bool value + + + + Invalid date time value + Nevažeća vrijednost datuma i vremena + + + Invalid color value + + + + Invalid color rgb part + + + + Invalid number value + + + + Invalid uuid value + + + + Unable to decompress binary + Translator meant is a binary data inside an entry + + + + XML error: +%1 +Line %2, column %3 + + + + + KeeAgentSettings + + Invalid KeeAgent settings file structure. + + + + Private key is an attachment but no attachments provided. + + + + Private key is empty + + + + File too large to be a private key + + + + Failed to open private key + Otvaranja privatnog ključa nije uspjelo + + + + KeePass1OpenWidget + + Unable to open the database. + + + + Import KeePass1 Database + + + + + KeePass1Reader + + Unable to read keyfile. + + + + Not a KeePass database. + Nije KeePass baza podataka. + + + Unsupported encryption algorithm. + + + + Unsupported KeePass database version. + + + + Unable to read encryption IV + IV = Initialization Vector for symmetric cipher + + + + Invalid number of groups + + + + Invalid number of entries + + + + Invalid content hash size + + + + Invalid transform seed size + + + + Invalid number of transform rounds + + + + Unable to construct group tree + + + + Root + Izvor + + + Key transformation failed + + + + Invalid group field type number + + + + Invalid group field size + + + + Read group field data doesn't match size + + + + Incorrect group id field size + + + + Incorrect group creation time field size + + + + Incorrect group modification time field size + + + + Incorrect group access time field size + + + + Incorrect group expiry time field size + + + + Incorrect group icon field size + + + + Incorrect group level field size + + + + Invalid group field type + + + + Missing group id or level + + + + Missing entry field type number + + + + Invalid entry field size + + + + Read entry field data doesn't match size + + + + Invalid entry uuid field size + + + + Invalid entry group id field size + + + + Invalid entry icon field size + + + + Invalid entry creation time field size + + + + Invalid entry modification time field size + + + + Invalid entry expiry time field size + + + + Invalid entry field type + + + + unable to seek to content position + + + + Invalid credentials were provided, please try again. +If this reoccurs, then your database file may be corrupt. + + + + Unable to calculate database key + + + + + KeeShare + + Invalid sharing reference + + + + Inactive share %1 + + + + Imported from %1 + Uvezeno iz %1 + + + Exported to %1 + + + + Synchronized with %1 + + + + Import is disabled in settings + + + + Export is disabled in settings + + + + Inactive share + + + + Imported from + + + + Exported to + + + + Synchronized with + + + + + KeyComponentWidget + + Key Component + + + + Key Component Description + + + + Cancel + Otkaži + + + Key Component set, click to change or remove + + + + Add %1 + Add a key component + Dodaj %1 + + + Change %1 + Change a key component + Promijeni %1 + + + Remove %1 + Remove a key component + Ukloni %1 + + + %1 set, click to change or remove + Change or remove a key component + + + + + KeyFileEditWidget + + Generate + Proizvedi + + + Key File + Datoteka ključa + + + <p>You can add a key file containing random bytes for additional security.</p><p>You must keep it secret and never lose it or you will be locked out!</p> + + + + Legacy key file format + Zastarjeli format datoteke ključa + + + Error loading the key file '%1' +Message: %2 + + + + Key files + Datoteke ključeva + + + All files + Sve datoteke + + + Create Key File... + Stvori Datoteku Ključa... + + + Error creating key file + + + + Unable to create key file: %1 + + + + Select a key file + Odaberite datoteku ključa + + + Key file selection + Odabir datoteke ključa + + + Browse for key file + Potraži datoteku ključa + + + Browse... + Pretraživanje... + + + Generate a new key file + Proizvedi novu datoteku ključa + + + Note: Do not use a file that may change as that will prevent you from unlocking your database! + + + + Invalid Key File + + + + You cannot use the current database as its own keyfile. Please choose a different file or generate a new key file. + Ne možete koristiti trenutnu bazu podataka kao vlastitu datoteku ključa. Odaberite drugu datoteku ili prozvedite novu datoteku ključa . + + + Suspicious Key File + + + + The chosen key file looks like a password database file. A key file must be a static file that never changes or you will lose access to your database forever. +Are you sure you want to continue with this file? + Odabrana datoteka ključa nalikuje datoteki baze podataka lozinki. Ključna datoteka mora biti statična datoteka koja se nikada ne mijenja ili ćete zauvijek izgubiti pristup svojoj bazi podataka. +Želite li zaista nastaviti s ovom datotekom? + + + You are using a legacy key file format which may become +unsupported in the future. + +Generate a new key file in the database security settings. + Koristite zastarjeli format datoteke ključa koji može postati +nepodržan u budućnosti. + +Proizvedite novu datoteku ključa u sigurnosnim postavkama baze podataka. + + + + MainWindow + + &Database + &Baza Podataka + + + &Help + &Pomoć + + + &Groups + &Grupe + + + &Tools + &Alati + + + &Quit + &Izlaz + + + &About + O programu + + + Database settings + Postavke baze podataka + + + Copy username to clipboard + Kopiraj korisničkog imena u međuspremnik + + + Copy password to clipboard + Kopiraj lozinku u međuspremnik + + + &Settings + &Postavke + + + &Title + &Naslov + + + Copy title to clipboard + Kopiraj naslov u međuspremnik + + + &URL + &URL + + + Copy URL to clipboard + Kopiraj URL-a u međuspremnik + + + &Notes + &Bilješke + + + Copy notes to clipboard + Kopiraj bilješke u međuspremnik + + + Copy &TOTP + Kopiraj &TOTP + + + E&mpty recycle bin + + + + Clear history + Obriši povijest + + + Access error for config file %1 + Pogreška pristupa za konfiguracijsku datoteku %1 + + + Settings + Postavke + + + Toggle window + + + + Quit KeePassXC + Izađi iz KeePassXC-a + + + Please touch the button on your YubiKey! + Molimo prritisnite gumb na svom YubiKey! + + + WARNING: You are using an unstable build of KeePassXC! +There is a high risk of corruption, maintain a backup of your databases. +This version is not meant for production use. + + + + &Donate + &Donirajte + + + WARNING: Your Qt version may cause KeePassXC to crash with an On-Screen Keyboard! +We recommend you use the AppImage available on our downloads page. + + + + &Import + &Uvezi + + + Create a new database + Stvari novu bazu podataka + + + Merge from another KDBX database + Sjedini iz druge KDBX baze podataka + + + Add a new entry + Dodaj novu stavku + + + View or edit entry + Pogledaj ili uredi stavku + + + Add a new group + Dodaj novu grupu + + + Perform &Auto-Type + Izvrši &Auto-Tipkanje + + + Open &URL + Otvori &URL + + + Import a KeePass 1 database + Uvezi KeePass 1 bazu podataka + + + Import a CSV file + Uvezi CSV datoteku + + + NOTE: You are using a pre-release version of KeePassXC! +Expect some bugs and minor issues, this version is not meant for production use. + + + + Check for updates on startup? + + + + Would you like KeePassXC to check for updates on startup? + + + + You can always check for updates manually from the application menu. + + + + &Export + &Izvezi + + + Sort &A-Z + Sortiraj &A-Ž + + + Sort &Z-A + Sortiraj &Ž-A + + + &Password Generator + &Proizvođač Lozinki + + + Import a 1Password Vault + Uvezi 1Password Sef + + + &Getting Started + &Prvi Koraci + + + &User Guide + &Korisnički vodič + + + &Keyboard Shortcuts + + + + &Recent Databases + &Nedavne Baze Podataka + + + &Entries + &Stavke + + + Copy Att&ribute + + + + TOTP + TOTP + + + View + + + + Theme + Tema + + + &Check for Updates + + + + &Open Database… + + + + &Save Database + &Spremi Bazu Podataka + + + &Close Database + + + + &New Database… + + + + &Merge From Database… + &Sjedini iz Baze Podataka... + + + &New Entry… + &Nova Stavka... + + + &Edit Entry… + &Uredi Stavku... + + + &Delete Entry… + + + + &New Group… + &Nova Grupa... + + + &Edit Group… + &Uredi Grupu... + + + &Delete Group… + + + + Download All &Favicons… + Preuzmi Sve &Favikone... + + + Sa&ve Database As… + + + + Database &Security… + + + + Database &Reports... + + + + Statistics, health check, etc. + + + + &Database Settings… + + + + &Clone Entry… + + + + Move u&p + + + + Move entry one step up + + + + Move do&wn + + + + Move entry one step down + + + + Copy &Username + Kopiraj &Korisničko ime + + + Copy &Password + + + + Download &Favicon + Preuzmi&Favikonu + + + &Lock Databases + + + + &CSV File… + + + + &HTML File… + + + + KeePass 1 Database… + + + + 1Password Vault… + + + + CSV File… + + + + Show TOTP + Prikaži TOTP + + + Show QR Code + Prikaži QR Kod + + + Set up TOTP… + + + + Report a &Bug + + + + Open Getting Started Guide + + + + &Online Help + + + + Go to online documentation + + + + Open User Guide + Otvori Korisnički Vodič + + + Save Database Backup... + + + + Add key to SSH Agent + + + + Remove key from SSH Agent + + + + Compact Mode + + + + Automatic + Automatska + + + Light + Svijetla + + + Dark + Tamna + + + Classic (Platform-native) + Klasična (ovisno o platformi) + + + Show Toolbar + Prikaži Alatnu traku + + + Show Preview Panel + Prikaži ploču za pregled + + + Don't show again for this version + Nemoj više prikazivati ovu verziju + + + Restart Application? + Ponovno Pokreni Aplikaciju? + + + You must restart the application to apply this setting. Would you like to restart now? + Morate ponovno pokrenuti aplikaciju da biste primijenili tu postavku. Želite li ju ponovno pokrenuti sada? + + + Perform Auto-Type Sequence + Izvrši redoslijed Auto-Tipkanja + + + {USERNAME} + + + + {USERNAME}{ENTER} + + + + {PASSWORD} + + + + {PASSWORD}{ENTER} + + + + + ManageDatabase + + Database settings + Postavke baze podataka + + + Edit database settings + + + + Unlock database + Otključaj bazu podataka + + + Unlock database to show more information + Otključajte bazu podataka kako biste vidjeli više informacija + + + Lock database + Zaključaj bazu podataka + + + + ManageSession + + Disconnect + Odspoji + + + Disconnect this application + Odspoji ovu aplikaciju + + + + Merger + + Creating missing %1 [%2] + + + + Relocating %1 [%2] + + + + Overwriting %1 [%2] + + + + older entry merged from database "%1" + starija stavka sjedinjena iz baze podataka "%1" + + + Adding backup for older target %1 [%2] + + + + Adding backup for older source %1 [%2] + + + + Reapplying older target entry on top of newer source %1 [%2] + + + + Reapplying older source entry on top of newer target %1 [%2] + + + + Synchronizing from newer source %1 [%2] + + + + Synchronizing from older source %1 [%2] + + + + Deleting child %1 [%2] + + + + Deleting orphan %1 [%2] + + + + Changed deleted objects + + + + Adding missing icon %1 + + + + Removed custom data %1 [%2] + + + + Adding custom data %1 [%2] + + + + + NewDatabaseWizard + + Create a new KeePassXC database... + Stvoi novu KeePassXC bazu podataka... + + + Root + Root group + Izvor + + + + NewDatabaseWizardPage + + WizardPage + + + + Here you can adjust the database encryption settings. Don't worry, you can change them later in the database settings. + Ovdje možete podesiti postavke šifriranja baze podataka. Ne brinite, možete ih izmijeniti kasnije u postavkama baze podataka. + + + Advanced Settings + Napredne Postavke + + + Simple Settings + Osnovne Postavke + + + Encryption Settings + Postavke Šifriranja + + + + NewDatabaseWizardPageDatabaseKey + + Database Credentials + Vjerodajnice baze podataka + + + A set of credentials known only to you that protects your database. + + + + + NewDatabaseWizardPageEncryption + + Encryption Settings + Postavke Šifriranja + + + Here you can adjust the database encryption settings. Don't worry, you can change them later in the database settings. + Ovdje možete podesiti postavke šifriranja baze podataka. Ne brinite, možete ih izmijeniti kasnije u postavkama baze podataka. + + + + NewDatabaseWizardPageMetaData + + General Database Information + Osnovne Inforrmacije Baze Podataka + + + Please fill in the display name and an optional description for your new database: + Unesite ime za prikaz i opcionalan opis za Vašu novu bazu podataka: + + + + NixUtils + + Password Manager + Upravitelj Lozinki + + + + OpData01 + + Invalid OpData01, does not contain header + + + + Unable to read all IV bytes, wanted 16 but got %1 + + + + Unable to init cipher for opdata01: %1 + + + + Unable to read all HMAC signature bytes + + + + Malformed OpData01 due to a failed HMAC + + + + Unable to process clearText in place + + + + Expected %1 bytes of clear-text, found %2 + + + + + OpVaultOpenWidget + + Read Database did not produce an instance +%1 + + + + + OpVaultReader + + Directory .opvault must exist + + + + Directory .opvault must be readable + + + + Directory .opvault/default must exist + + + + Directory .opvault/default must be readable + + + + Unable to decode masterKey: %1 + + + + Unable to derive master key: %1 + + + + + OpenSSHKey + + Invalid key file, expecting an OpenSSH key + + + + PEM boundary mismatch + + + + Base64 decoding failed + + + + Key file way too small. + + + + Key file magic header id invalid + + + + Found zero keys + + + + Failed to read public key. + + + + Corrupted key file, reading private key failed + + + + No private key payload to decrypt + + + + Trying to run KDF without cipher + + + + Passphrase is required to decrypt this key + + + + Key derivation failed, key file corrupted? + + + + Decryption failed, wrong passphrase? + + + + Unexpected EOF while reading public key + + + + Unexpected EOF while reading private key + + + + Can't write public key as it is empty + + + + Unexpected EOF when writing public key + + + + Can't write private key as it is empty + + + + Unexpected EOF when writing private key + + + + Unsupported key type: %1 + Nepodržana vrsta ključa: %1 + + + Unknown cipher: %1 + + + + Cipher IV is too short for MD5 kdf + + + + Unknown KDF: %1 + Nepoznati KDF: %1 + + + Unknown key type: %1 + Nepoznata vrsta ključa: %1 + + + + PasswordEdit + + Passwords do not match + Lozinke se ne podudaraju + + + Passwords match so far + Lozinke se zasad podudaraju + + + Toggle Password (%1) + + + + Generate Password (%1) + Proizvedi Lozinku (%1) + + + Warning: Caps Lock enabled! + Upozorenje: Caps Lock uključen! + + + + PasswordEditWidget + + Enter password: + Unesite lozinku: + + + Confirm password: + Potvrdite lozinku: + + + Password + Lozinka + + + <p>A password is the primary method for securing your database.</p><p>Good passwords are long and unique. KeePassXC can generate one for you.</p> + <p>Lozinka je primarna metoda za osiguravanje baze podataka.</p><p>Dobre lozinke su duge i jedinstvene. KeePassXC ju može proizvesti za vas.</p> + + + Passwords do not match. + Lozinke se ne podudaraju. + + + Password field + Polje lozinke + + + Repeat password field + Ponavljanje polja lozinke + + + + PasswordGeneratorWidget + + %p% + %p% + + + strength + Password strength + jačina + + + entropy + entropija + + + Password + Lozinka + + + Character Types + Vrste znakova + + + Numbers + Brojevi + + + Extended ASCII + Prošireni ASCII + + + Exclude look-alike characters + Izostavi slične znakove + + + Pick characters from every group + Odaberi znakove iz svake grupe + + + &Length: + &Duljina: + + + Passphrase + Zaporku + + + Wordlist: + Popis riječi: + + + Word Separator: + + + + Close + Zatvori + + + Entropy: %1 bit + Entropija: %1 bit + + + Password Quality: %1 + Kvaliteta lozinke: %1 + + + Poor + Password quality + Bijedna + + + Weak + Password quality + Slaba + + + Good + Password quality + Dobra + + + Excellent + Password quality + Izvrsna + + + Switch to advanced mode + Prebaci na napredni način + + + Advanced + Napredno + + + Braces + Zagrade + + + Punctuation + Interpunkcije + + + Quotes + Navodnici + + + Logograms + Logogrami + + + Character set to exclude from generated password + Skup znakova za izostaviti iz proizvodnje lozinke + + + Do not include: + + + + Add non-hex letters to "do not include" list + + + + Hex + + + + Excluded characters: "0", "1", "l", "I", "O", "|", "﹒" + Izostavi znakove: "0", "1", "l", "I", "O", "|", "". + + + Generated password + Proizvedena lozinka + + + Upper-case letters + Velika slova + + + Lower-case letters + Mala slova + + + Special characters + Posebni znakovi + + + Math Symbols + Matematički simboli + + + Dashes and Slashes + Crtice i kose crte + + + Excluded characters + Izostavi znakove + + + Hex Passwords + Hex lozinke + + + Password length + Duljina lozinke + + + Word Case: + + + + Regenerate password + Ponovo proizvedi lozinku + + + Copy password + Kopiraj lozinku + + + lower case + mala slova + + + UPPER CASE + VELIKA SLOVA + + + Title Case + Početno slovo + + + Generate Password + Proizvedi lozinku + + + Also choose from: + + + + Additional characters to use for the generated password + Dodatni znakovi za korištenje pri proizvodnji lozinke + + + Additional characters + Dodatni znakovi + + + Word Count: + Broj riječi: + + + Esc + Esc + + + Apply Password + Primjeni Lozinku + + + Ctrl+S + Ctrl+S + + + Clear + Obriši + + + Regenerate password (%1) + Ponovo proizvedi lozinku (%1) + + + Special Characters + Posebni znakovi + + + + QApplication + + KeeShare + KeeShare + + + Statistics + Statistika + + + Very weak password + + + + Password entropy is %1 bits + Entropija lozinke je %1 bitova + + + Weak password + + + + Used in %1/%2 + + + + Password is used %1 times + + + + Password has expired + Lozinka je istekla + + + Password expiry was %1 + + + + Password is about to expire + Lozinka samo što nije istekla + + + Password expires in %1 days + Lozinka istječe u %1 dana + + + Password will expire soon + Lozinka će uskoro isteći + + + Password expires on %1 + Lozinka istječe na %1 + + + Health Check + + + + HIBP + HIBP + + + + QMessageBox + + Overwrite + + + + Delete + Izbriši + + + Move + Premjesti + + + Empty + Isprazni + + + Remove + Ukloni + + + Skip + Preskoči + + + Disable + Onemogući + + + Merge + Sjedini + + + Continue + Nastavi + + + + QObject + + Database not opened + Baza podataka nije otvorena + + + Database hash not available + + + + Client public key not received + + + + Cannot decrypt message + + + + Action cancelled or denied + + + + KeePassXC association failed, try again + + + + Encryption key is not recognized + Ključ za šifriranje nije prepoznat + + + Incorrect action + + + + Empty message received + + + + No URL provided + + + + No logins found + + + + Unknown error + Nepoznata pogreška + + + Add a new entry to a database. + + + + Path of the database. + + + + Key file of the database. + + + + path + + + + Username for the entry. + Korisničko ime za stavku. + + + username + korisničko ime + + + URL for the entry. + + + + URL + URL + + + Prompt for the entry's password. + + + + Generate a password for the entry. + Proizvedi lozinku za stavku. + + + length + duljina + + + Path of the entry to add. + + + + Path of the entry to clip. + clip = copy to clipboard + + + + Timeout in seconds before clearing the clipboard. + + + + Edit an entry. + Uredite stavku: + + + Title for the entry. + Naslov za stavku. + + + title + naslov + + + Path of the entry to edit. + + + + Estimate the entropy of a password. + Procijeni entropiju lozinke. + + + Password for which to estimate the entropy. + + + + Perform advanced analysis on the password. + + + + WARNING: You are using a legacy key file format which may become +unsupported in the future. + +Please consider generating a new key file. + UPOZORENJE: Koristite zastarjeli format datoteke ključa koji može postati +nepodržan u budućnosti. + +Razmislite o generiranju nove datoteke ključa. + + + + +Available commands: + + + +Dostupne naredbe: + + + + Name of the command to execute. + Naziv naredbe za izvršenje. + + + List database entries. + Nabroji stavke iz baze podataka. + + + Path of the group to list. Default is / + + + + Find entries quickly. + Brzo pronađi stavke + + + Search term. + Pojam za pretraživanje. + + + Merge two databases. + Sjedini dvije baze podataka. + + + Path of the database to merge from. + Put baze podataka iz koje se treba sjediniti. + + + Use the same credentials for both database files. + + + + Key file of the database to merge from. + Datoteka ključ baze podataka za spajanje. + + + Show an entry's information. + Prikaži informacije o stavci. + + + Names of the attributes to show. This option can be specified more than once, with each attribute shown one-per-line in the given order. If no attributes are specified, a summary of the default attributes is given. + Nazivi svojstava za prikazati. Ova opcija može određena više puta, sa svakim svojstvom prikazanim jednom po liniji u danom redoslijedu. Ako nijedno svojstvo nije navedeno, sažetak zadanih je dan. + + + attribute + svojstvo + + + Name of the entry to show. + Naziv stavke za prikazat. + + + NULL device + + + + error reading from device + + + + malformed string + + + + missing closing quote + + + + Group + Grupa + + + Title + Naslov + + + Username + Korisničko ime + + + Password + Lozinka + + + Notes + Bilješke + + + Last Modified + Posljednja izmjena + + + Created + Stvorio + + + Browser Integration + Integracija preglednika + + + SSH Agent + SSH Agent + + + Generate a new random diceware passphrase. + Proizvedi novu nasumičnu zaporku bacanjem kocke. + + + Word count for the diceware passphrase. + Broj riječi za zaporke bačene kockom. + + + Wordlist for the diceware generator. +[Default: EFF English] + Popis riječi za proizvođača bacanja kocki. +[Zadano: EFF Engleski] + + + Generate a new random password. + Proizvedi novu nasumičnu lozinku. + + + Could not create entry with path %1. + + + + Enter password for new entry: + Unesite lozinku za novu stavku: + + + Writing the database failed %1. + + + + Successfully added entry %1. + Uspješno dodana stavka %1. + + + Invalid timeout value %1. + Nevažeća vrijednost isteka vremena %1. + + + Entry %1 not found. + Stavka %1 nije pronađen. + + + Entry with path %1 has no TOTP set up. + + + + Clearing the clipboard in %1 second(s)... + Čišćenje međuspremnik u %1 sekundi(s)...Čišćenje međuspremnik u %1 sekundi(s)...Brisanje međuspremnik u %1 sekunde(i)... + + + Clipboard cleared! + Međuspremnik obrisan! + + + Silence password prompt and other secondary outputs. + + + + count + CLI parameter + + + + Could not find entry with path %1. + + + + Not changing any field for entry %1. + + + + Enter new password for entry: + + + + Writing the database failed: %1 + + + + Successfully edited entry %1. + + + + Length %1 + Duljina %1 + + + Entropy %1 + Entropija %1 + + + Log10 %1 + Log10 %1 + + + Multi-word extra bits %1 + + + + Type: Bruteforce + + + + Type: Dictionary + + + + Type: Dict+Leet + + + + Type: User Words + + + + Type: User+Leet + + + + Type: Repeated + + + + Type: Sequence + Vrsta: Redoslijed + + + Type: Spatial + + + + Type: Date + + + + Type: Bruteforce(Rep) + + + + Type: Dictionary(Rep) + + + + Type: Dict+Leet(Rep) + + + + Type: User Words(Rep) + + + + Type: User+Leet(Rep) + + + + Type: Repeated(Rep) + + + + Type: Sequence(Rep) + Vrsta: Redoslijed (Ponavljajući) + + + Type: Spatial(Rep) + + + + Type: Date(Rep) + + + + Type: Unknown%1 + + + + Entropy %1 (%2) + Entropija %1 (%2) + + + *** Password length (%1) != sum of length of parts (%2) *** + + + + Failed to load key file %1: %2 + + + + Length of the generated password + Duljina porizvedene lozinke + + + Use lowercase characters + Koristi mala slova + + + Use uppercase characters + Koristi velika slova + + + Use special characters + Koristi posebne znakove + + + Use extended ASCII + Koristi prošireni ASCII + + + Exclude character set + Izostavi skup znakova + + + chars + znak + + + Exclude similar looking characters + Izostavi slične znakove + + + Include characters from every selected group + + + + Recursively list the elements of the group. + + + + Cannot find group %1. + + + + Error reading merge file: +%1 + + + + Unable to save database to file : %1 + + + + Unable to save database to file: %1 + + + + Successfully recycled entry %1. + + + + Successfully deleted entry %1. + + + + Show the entry's current TOTP. + Prikaži trenutni TOTP stavke. + + + ERROR: unknown attribute %1. + POGREŠKA: nepoznato svojstvo %1. + + + No program defined for clipboard manipulation + + + + file empty + datoteka prazna + + + %1: (row, col) %2,%3 + %1: (redak, stupac) %2,%3 + + + Argon2 (KDBX 4 – recommended) + Argon2 (KDBX 4 – preporučeno) + + + AES-KDF (KDBX 4) + AES-KDF (KDBX 4) + + + AES-KDF (KDBX 3.1) + AES-KDF (KDBX 3.1) + + + Invalid Settings + TOTP + Nevažeće postavke + + + Invalid Key + TOTP + Nevažeći ključ + + + Message encryption failed. + + + + No groups found + Nijedna grupa nije pronađene + + + Create a new database. + Stvori novu bazu podataka. + + + File %1 already exists. + Datoteka %1 već postoji. + + + Loading the key file failed + + + + No key is set. Aborting database creation. + + + + Failed to save the database: %1. + + + + Successfully created new database. + Uspješno stvorena nova baza podataka. + + + Creating KeyFile %1 failed: %2 + + + + Loading KeyFile %1 failed: %2 + + + + Path of the entry to remove. + + + + Existing single-instance lock file is invalid. Launching new instance. + + + + The lock file could not be created. Single-instance mode disabled. + + + + KeePassXC - cross-platform password manager + + + + filenames of the password databases to open (*.kdbx) + + + + path to a custom config file + + + + key file of the database + + + + read password of the database from stdin + + + + Parent window handle + + + + Another instance of KeePassXC is already running. + + + + Fatal error while testing the cryptographic functions. + + + + KeePassXC - Error + KeePassXC - Pogreška + + + Database password: + Lozinka baze podataka: + + + Cannot create new group + + + + Deactivate password key for the database. + + + + Displays debugging information. + + + + Deactivate password key for the database to merge from. + + + + Version %1 + Verzija %1 + + + Build Type: %1 + Vrsta gradnje: %1 + + + Revision: %1 + Revizija: %1 + + + Distribution: %1 + Distribucija: %1 + + + Debugging mode is disabled. + + + + Debugging mode is enabled. + Način za otklanjanje pogrešaka je omogućen. + + + Operating system: %1 +CPU architecture: %2 +Kernel: %3 %4 + + + + Auto-Type + Auto-tipkanje + + + KeeShare (signed and unsigned sharing) + + + + KeeShare (only signed sharing) + + + + KeeShare (only unsigned sharing) + + + + YubiKey + YubiKey + + + TouchID + TouchID + + + None + Nijedan + + + Enabled extensions: + Omogućena proširenja: + + + Cryptographic libraries: + + + + Cannot generate a password and prompt at the same time! + Nemoguće je proizvesti i zatražiti lozinku istovremeno! + + + Adds a new group to a database. + + + + Path of the group to add. + + + + Group %1 already exists! + Grupa %1 već postoji! + + + Group %1 not found. + Grupa %1 nije pronađena. + + + Successfully added group %1. + Uspješno dodana grupa %1. + + + Check if any passwords have been publicly leaked. FILENAME must be the path of a file listing SHA-1 hashes of leaked passwords in HIBP format, as available from https://haveibeenpwned.com/Passwords. + + + + FILENAME + + + + Analyze passwords for weaknesses and problems. + + + + Failed to open HIBP file %1: %2 + Otvaranja HIBP datoteke nije uspjelo %1: %2 + + + Evaluating database entries against HIBP file, this will take a while... + + + + Close the currently opened database. + + + + Display this help. + + + + slot + utor + + + Invalid word count %1 + Nevažeći broj riječi %1 + + + The word list is too small (< 1000 items) + + + + Exit interactive mode. + + + + Exports the content of a database to standard output in the specified format. + + + + Unable to export database to XML: %1 + + + + Unsupported format %1 + Nepodržan format %1 + + + Use numbers + Koristi brojeva + + + Invalid password length %1 + Nevažeća duljina lozinke %1 + + + Display command help. + Pogledaj pomoć za naredbe. + + + Available commands: + Dostupne naredbe: + + + Import the contents of an XML database. + Uvezite sadržaj XML baze podataka. + + + Path of the XML database export. + + + + Path of the new database. + + + + Successfully imported database. + Uspješno uvezena baza podataka. + + + Unknown command %1 + Nepoznata naredba %1 + + + Flattens the output to single lines. + + + + Only print the changes detected by the merge operation. + + + + Yubikey slot for the second database. + + + + Successfully merged %1 into %2. + Uspješno sjedinio %1 u %2. + + + Database was not modified by merge operation. + Baza podataka nije izmijenjena operacijom spajanja. + + + Moves an entry to a new group. + + + + Path of the entry to move. + + + + Path of the destination group. + + + + Could not find group with path %1. + + + + Entry is already in group %1. + + + + Successfully moved entry %1 to group %2. + + + + Open a database. + Otvori bazu podataka. + + + Path of the group to remove. + + + + Cannot remove root group from database. + + + + Successfully recycled group %1. + + + + Successfully deleted group %1. + + + + Failed to open database file %1: not found + + + + Failed to open database file %1: not a plain file + + + + Failed to open database file %1: not readable + + + + Enter password to unlock %1: + + + + Invalid YubiKey slot %1 + + + + Enter password to encrypt database (optional): + + + + HIBP file, line %1: parse error + + + + Secret Service Integration + + + + User name + Korisničko ime + + + Password for '%1' has been leaked %2 time(s)! + + + + Invalid password generator after applying all options + + + + Show the protected attributes in clear text. + Prikaži zaštićena svojstva u čitljivom tekstu. + + + Browser Plugin Failure + + + + Could not save the native messaging script file for %1. + + + + Copy the given attribute to the clipboard. Defaults to "password" if not specified. + + + + Copy the current TOTP to the clipboard (equivalent to "-a totp"). + + + + Copy an entry's attribute to the clipboard. + Kopirajte svojstvo stavke u međuspremnik. + + + ERROR: Please specify one of --attribute or --totp, not both. + POGREŠKA: Navedite jedan od --svojstvo ili --totp, a ne oboje. + + + ERROR: attribute %1 is ambiguous, it matches %2. + POGREŠKA: svojstvo %1 je dvosmisleno, odgovara %2. + + + Attribute "%1" not found. + Svojstvo "%1" nije pronađeno. + + + Entry's "%1" attribute copied to the clipboard! + Svojstvo "%1" stavke kopirano u međuspremnik! + + + Yubikey slot and optional serial used to access the database (e.g., 1:7370001). + + + + slot[:serial] + + + + Target decryption time in MS for the database. + + + + time + vrijeme + + + Set the key file for the database. + Postavite datoteku ključa za bazu podataka. + + + Set a password for the database. + Postavite lozinku za bazu podataka. + + + Invalid decryption time %1. + + + + Target decryption time must be between %1 and %2. + + + + Failed to set database password. + + + + Benchmarking key derivation function for %1ms delay. + + + + Setting %1 rounds for key derivation function. + + + + error while setting database key derivation settings. + + + + Format to use when exporting. Available choices are 'xml' or 'csv'. Defaults to 'xml'. + + + + Unable to import XML database: %1 + + + + Show a database's information. + Prikaži informacije o bazi podataka. + + + UUID: + UUID: + + + Name: + Naziv: + + + Description: + Opis: + + + Cipher: + + + + KDF: + KDF: + + + Recycle bin is enabled. + Koš za smeće je omogućen. + + + Recycle bin is not enabled. + Koš za smeće nije omogućen. + + + Invalid command %1. + + + + Invalid YubiKey serial %1 + + + + Please touch the button on your YubiKey to continue… + + + + Do you want to create a database with an empty password? [y/N]: + + + + Repeat password: + Ponovite lozinku: + + + Error: Passwords do not match. + Pogreška: Lozinke se ne podudaraju. + + + All clipping programs failed. Tried %1 + + + + + AES (%1 rounds) + + + + Argon2 (%1 rounds, %2 KB) + + + + AES 256-bit + AES 256-bit + + + Twofish 256-bit + Twofish 256-bit + + + ChaCha20 256-bit + ChaCha20: 256-bit {20 256-?} + + + Benchmark %1 delay + + + + %1 ms + milliseconds + %1 ms%1 ms%1 ms + + + %1 s + seconds + %1 s%1 s%1 s + + + + QtIOCompressor + + Internal zlib error when compressing: + + + + Error writing to underlying device: + + + + Error opening underlying device: + + + + Error reading data from underlying device: + + + + Internal zlib error when decompressing: + + + + + QtIOCompressor::open + + The gzip format not supported in this version of zlib. + + + + Internal zlib error: + + + + + ReportsWidgetHealthcheck + + Also show entries that have been excluded from reports + Prikaži stavke koje su zostavljene iz izvješća + + + Hover over reason to show additional details. Double-click entries to edit. + Zadržite pokazivač iznad razloga da biste prikazali dodatne pojedinosti. Dvaput kliknite stavke za uređivanje. + + + Bad + Password quality + + + + Bad — password must be changed + + + + Poor + Password quality + bijedna + + + Poor — password should be changed + + + + Weak + Password quality + Slaba + + + Weak — consider changing the password + + + + (Excluded) + (Izuzeto) + + + This entry is being excluded from reports + Ova stavka će biti izuzeta iz izvješća + + + Please wait, health data is being calculated... + + + + Congratulations, everything is healthy! + + + + Title + Naslov + + + Path + Put + + + Score + + + + Reason + Razlog + + + Edit Entry... + Uredi Stavku... + + + Exclude from reports + Izuzmi iz izvješća + + + + ReportsWidgetHibp + + CAUTION: This report requires sending information to the Have I Been Pwned online service (https://haveibeenpwned.com). If you proceed, your database passwords will be cryptographically hashed and the first five characters of those hashes will be sent securely to this service. Your database remains secure and cannot be reconstituted from this information. However, the number of passwords you send and your IP address will be exposed to this service. + + + + Perform Online Analysis + + + + Also show entries that have been excluded from reports + Prikaži stavke koje su zostavljene iz izvješća + + + This build of KeePassXC does not have network functions. Networking is required to check your passwords against Have I Been Pwned databases. + + + + Congratulations, no exposed passwords! + + + + Title + Naslov + + + Path + Put + + + Password exposed… + Lozinka izložena... + + + (Excluded) + (Izuzeto) + + + This entry is being excluded from reports + Ova stavka će biti izuzeta iz izvješća + + + once + jednom + + + up to 10 times + do 10 puta + + + up to 100 times + do 100 puta + + + up to 1000 times + do 1000 puta + + + up to 10,000 times + do 10,000 puta + + + up to 100,000 times + do 100,000 puta + + + up to a million times + do milijun puta + + + millions of times + milijune puta + + + Edit Entry... + Uredi Stavku... + + + Exclude from reports + Izuzmi iz izvješća + + + + ReportsWidgetStatistics + + Hover over lines with error icons for further information. + + + + Name + Naziv + + + Value + Vrijednost + + + Please wait, database statistics are being calculated... + + + + Database name + Naziv baze podataka + + + Description + Opis + + + Location + Lokacija + + + Last saved + + + + Unsaved changes + + + + yes + da + + + no + ne + + + The database was modified, but the changes have not yet been saved to disk. + Baza podataka je izmijenjena, ali promjene još nisu spremljene na disk. + + + Number of groups + Broj grupa + + + Number of entries + Broj stavki + + + Number of expired entries + + + + The database contains entries that have expired. + + + + Unique passwords + Unikatne Lozinke + + + Non-unique passwords + Neunikatne lozinke + + + More than 10% of passwords are reused. Use unique passwords when possible. + Više of 10% lozinki je više puta upotrebljeno. Koistite unikatne lozinke ako je to moguće. + + + Maximum password reuse + + + + Some passwords are used more than three times. Use unique passwords when possible. + + + + Number of short passwords + + + + Recommended minimum password length is at least 8 characters. + Minimalna preporučena duljina lozinke je barem 8 znakova. + + + Number of weak passwords + + + + Recommend using long, randomized passwords with a rating of 'good' or 'excellent'. + + + + Entries excluded from reports + Stavke izuzete iz izvješća + + + Excluding entries from reports, e. g. because they are known to have a poor password, isn't necessarily a problem but you should keep an eye on them. + + + + Average password length + Prosječna duljina lozinke + + + %1 characters + + + + Average password length is less than ten characters. Longer passwords provide more security. + + + + + SSHAgent + + Agent connection failed. + + + + Agent protocol error. + + + + No agent running, cannot add identity. + + + + No agent running, cannot remove identity. + + + + Agent refused this identity. Possible reasons include: + + + + The key has already been added. + + + + Restricted lifetime is not supported by the agent (check options). + + + + A confirmation request is not supported by the agent (check options). + + + + Key identity ownership conflict. Refusing to add. + + + + No agent running, cannot list identities. + + + + + SearchHelpWidget + + Search Help + + + + Search terms are as follows: [modifiers][field:]["]term["] + + + + Every search term must match (ie, logical AND) + + + + Modifiers + Parametri + + + exclude term from results + izostavi pojam iz rezultata + + + match term exactly + + + + use regex in term + + + + Fields + + + + Term Wildcards + + + + match anything + + + + match one + + + + logical OR + + + + Examples + Primjeri + + + + SearchWidget + + Search + Traži + + + Clear + Obriši + + + Limit search to selected group + + + + Search Help + + + + Search (%1)... + Search placeholder text, %1 is the keyboard shortcut + + + + Case sensitive + + + + + SettingsWidgetFdoSecrets + + Options + Opcije + + + Enable KeepassXC Freedesktop.org Secret Service integration + + + + General + Generalno + + + Show notification when credentials are requested + Prikaži obavijest kada se zatraže podaci za prijavu + + + <html><head/><body><p>If recycle bin is enabled for the database, entries will be moved to recycle bin directly. Otherwise, they will be deleted without confirmation.</p><p>You will still be prompted if any entries are referenced by others.</p></body></html> + + + + Exposed database groups: + + + + Authorization + + + + These applications are currently connected: + + + + Don't confirm when entries are deleted by clients + + + + <b>Error:</b> Failed to connect to DBus. Please check your DBus setup. + + + + <b>Warning:</b> + <b>Upozorenje:</b> + + + Save current changes to activate the plugin and enable editing of this section. + + + + + SettingsWidgetKeeShare + + Active + Aktivni + + + Allow export + Dopusti izvoz + + + Allow import + Dopusti uvoz + + + Own certificate + + + + Fingerprint: + + + + Certificate: + + + + Signer + + + + Key: + Ključ: + + + Generate + Proizvedi + + + Import + Uvezi + + + Export + Izvezi + + + Imported certificates + Uvezeni certifikat + + + Trust + + + + Ask + Pitaj + + + Untrust + + + + Remove + Ukloni + + + Path + Put + + + Status + Status + + + Fingerprint + Otisak + + + Certificate + + + + Trusted + + + + Untrusted + + + + Unknown + Nepoznat + + + key.share + Filetype for KeeShare key + + + + KeeShare key file + KeeShare datoteka ključa + + + All files + Sve datoteke + + + Select path + + + + Exporting changed certificate + + + + The exported certificate is not the same as the one in use. Do you want to export the current certificate? + + + + Signer: + + + + Allow KeeShare imports + Dopusti uvoz KeeShare-a + + + Allow KeeShare exports + Dopusti izvoz KeeShare-a + + + Only show warnings and errors + Prikaži samo upozorenja i pogreške + + + Key + Ključ + + + Signer name field + + + + Generate new certificate + Proizvedi novi cerrtifikat + + + Import existing certificate + + + + Export own certificate + + + + Known shares + + + + Trust selected certificate + + + + Ask whether to trust the selected certificate every time + + + + Untrust selected certificate + + + + Remove selected certificate + + + + + ShareExport + + Overwriting signed share container is not supported - export prevented + + + + Could not write export container (%1) + + + + Could not embed signature: Could not open file to write (%1) + + + + Could not embed signature: Could not write file (%1) + + + + Could not embed database: Could not open file to write (%1) + + + + Could not embed database: Could not write file (%1) + + + + Overwriting unsigned share container is not supported - export prevented + + + + Could not write export container + + + + Unexpected export error occurred + + + + + ShareImport + + Import from container without signature + + + + We cannot verify the source of the shared container because it is not signed. Do you really want to import from %1? + + + + Import from container with certificate + + + + Do you want to trust %1 with the fingerprint of %2 from %3? + + + + Not this time + Ovaj put ne + + + Never + Nikad + + + Always + Uvijek + + + Just this time + Samo ovaj put + + + Signed share container are not supported - import prevented + + + + File is not readable + Datoteka nije čitljiva + + + Invalid sharing container + + + + Untrusted import prevented + + + + Successful signed import + + + + Unsigned share container are not supported - import prevented + + + + Successful unsigned import + + + + File does not exist + Datoteka ne postoji + + + Unknown share container type + + + + + ShareObserver + + Import from %1 failed (%2) + Uvoz iz %1 nije uspio (%2) + + + Import from %1 successful (%2) + Uvoz iz %1 uspješan (%2) + + + Imported from %1 + Uvezeno iz %1 + + + Export to %1 failed (%2) + Izvoz u %1 nije uspio (%2) + + + Export to %1 successful (%2) + Izvoz u %1 uspješan (%2) + + + Export to %1 + Izvezi u %1 + + + Multiple import source path to %1 in %2 + + + + Conflicting export target path %1 in %2 + + + + + TotpDialog + + Timed Password + + + + 000000 + 000000 + + + Copy + Kopiraj + + + Expires in <b>%n</b> second(s) + Istječe za <b>%n</b> sekunduIstječe za <b>%n</b> sekundeIstječe za <b>%n</b> sekundi + + + + TotpExportSettingsDialog + + Copy + Kopiraj + + + NOTE: These TOTP settings are custom and may not work with other authenticators. + TOTP QR code dialog warning + + + + There was an error creating the QR code. + + + + Closing in %1 seconds. + + + + + TotpSetupDialog + + Setup TOTP + + + + Default RFC 6238 token settings + + + + Steam token settings + + + + Use custom settings + + + + Custom Settings + + + + Time step: + + + + sec + Seconds + sek + + + Code size: + + + + Secret Key: + Tajni ključ: + + + Secret key must be in Base32 format + + + + Secret key field + + + + Algorithm: + Algoritam: + + + Time step field + + + + digits + znamenke + + + Invalid TOTP Secret + + + + You have entered an invalid secret key. The key must be in Base32 format. +Example: JBSWY3DPEHPK3PXP + + + + Confirm Remove TOTP Settings + + + + Are you sure you want to delete TOTP settings for this entry? + + + + + URLEdit + + Invalid URL + Nevaljan URL + + + + UpdateCheckDialog + + Checking for updates + Provjera dopuna + + + Checking for updates... + Provjera dopuna... + + + Close + Zatvori + + + Update Error! + + + + An error occurred in retrieving update information. + + + + Please try again later. + + + + Software Update + + + + A new version of KeePassXC is available! + Nova vezija KeePassXC-a je dostupna! + + + KeePassXC %1 is now available — you have %2. + + + + Download it at keepassxc.org + + + + You're up-to-date! + + + + KeePassXC %1 is currently the newest version available + + + + + WelcomeWidget + + Start storing your passwords securely in a KeePassXC database + + + + Create new database + Stvori novu bazu podataka + + + Open existing database + Otvori postojeću bazu podataka + + + Import from KeePass 1 + Uvezi iz KeePass 1 + + + Import from CSV + + + + Recent databases + Nedavne baze podataka + + + Welcome to KeePassXC %1 + Dobrodošli u KeePassXC-e %1 + + + Import from 1Password + Uvezi iz 1Password + + + Open a recent database + Otvori nedavnu bazu podataka + + + + YubiKey + + %1 [%2] Configured Slot - %3 + + + + %1 [%2] Challenge Response - Slot %3 - %4 + + + + Press + + + + Passive + + + + %1 Invalid slot specified - %2 + + + + The YubiKey interface has not been initialized. + YubiKey sučelje nije pokrenuto. + + + Hardware key is currently in use. + Hardverski ključ je trenutno u uporabi. + + + Could not find hardware key with serial number %1. Please plug it in to continue. + + + + Hardware key timed out waiting for user interaction. + + + + A USB error ocurred when accessing the hardware key: %1 + Došlo je do USB greške prilikom pristupa hardverskom ključu: %1 + + + Failed to complete a challenge-response, the specific error was: %1 + + + + + YubiKeyEditWidget + + Refresh + Osvježi + + + YubiKey Challenge-Response + + + + <p>If you own a <a href="https://www.yubico.com/">YubiKey</a>, you can use it for additional security.</p><p>The YubiKey requires one of its slots to be programmed as <a href="https://www.yubico.com/products/services-software/personalization-tools/challenge-response/">HMAC-SHA1 Challenge-Response</a>.</p> + + + + Refresh hardware tokens + Osvježi hardverske tokene + + + Hardware key slot selection + + + + Could not find any hardware keys! + Nijedan hardverski ključ nije pronađen! + + + Selected hardware key slot does not support challenge-response! + + + + Detecting hardware keys… + Otkrivanje hardverskih ključeva... + + + No hardware keys detected + Nijedan hardverski ključ otkrivene + + + \ No newline at end of file diff --git a/share/translations/keepassx_hu.ts b/share/translations/keepassx_hu.ts index 838245164..51fcffa44 100644 --- a/share/translations/keepassx_hu.ts +++ b/share/translations/keepassx_hu.ts @@ -3032,7 +3032,7 @@ Támogatott kiterjesztések: %1. Plugin Data - Beépülő adati + Beépülő adatai Remove @@ -3085,7 +3085,7 @@ Ez a kijelölt bővítmény hibás működését eredményezheti. Entry %1 - Clone - %1 – Klónozás + %1 – Klón @@ -4851,19 +4851,19 @@ Néhány hiba és kisebb nehézségek várhatóak, ezért ez a verzió nem aján {USERNAME} - + {FELHASZNÁLÓNÉV} {USERNAME}{ENTER} - + {FELHASZNÁLÓNÉV}{ENTER} {PASSWORD} - + {JELSZÓ} {PASSWORD}{ENTER} - + {JELSZÓ}{ENTER} @@ -5510,7 +5510,7 @@ Néhány hiba és kisebb nehézségek várhatóak, ezért ez a verzió nem aján Very weak password - Nagy gyenge jelszó + Nagyon gyenge jelszó Password entropy is %1 bits diff --git a/share/translations/keepassx_nl_NL.ts b/share/translations/keepassx_nl_NL.ts index 8c3b480cc..c639d3b09 100644 --- a/share/translations/keepassx_nl_NL.ts +++ b/share/translations/keepassx_nl_NL.ts @@ -350,7 +350,7 @@ Tray icon type - + Systeemvak-pictogram @@ -4852,19 +4852,19 @@ Wil je KeePassXC nu opnieuw opstarten? {USERNAME} - + {GEBRUIKERSNAAM} {USERNAME}{ENTER} - + {GEBRUIKERSNAAM}{ENTER} {PASSWORD} - + {WACHTWOORD} {PASSWORD}{ENTER} - + {WACHTWOORD}{ENTER} diff --git a/share/translations/keepassx_ru.ts b/share/translations/keepassx_ru.ts index 503ae1b9f..e2dd0a501 100644 --- a/share/translations/keepassx_ru.ts +++ b/share/translations/keepassx_ru.ts @@ -11,7 +11,7 @@ Report bugs at: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> - Сообщать об ошибках: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> + Сообщить об <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">ошибках</a> по https://github.com KeePassXC is distributed under the terms of the GNU General Public License (GPL) version 2 or (at your option) version 3. @@ -19,11 +19,11 @@ Contributors - Авторы + Соавторы <a href="https://github.com/keepassxreboot/keepassxc/graphs/contributors">See Contributions on GitHub</a> - <a href="https://github.com/keepassxreboot/keepassxc/graphs/contributors">Посмотреть вклад на GitHub</a> + <a href="https://github.com/keepassxreboot/keepassxc/graphs/contributors">Посмотреть соавторов на GitHub</a> Debug Info @@ -2368,7 +2368,7 @@ Disable safe saves and try again? <html><head/><body><p>If checked, the entry will not appear in reports like Health Check and HIBP even if it doesn't match the quality requirements (e. g. password entropy or re-use). You can set the check mark if the password is beyond your control (e. g. if it needs to be a four-digit PIN) to prevent it from cluttering the reports.</p></body></html> - + <html><head/><body><p>При включении, запись не появится в отчетах (например, Проверки безопасности или HIBP), даже если она не соответствует требованиям к качеству (энтропия, переиспользование). Можно включить этот параметр, если вы не можете контролировать этот пароль (например, 4-значные пин-кодыж), чтобы не засорять отчет.</p></body></html> Exclude from database reports @@ -2482,7 +2482,7 @@ Disable safe saves and try again? Only send this setting to the browser for HTTP Auth dialogs. If enabled, normal login forms will not show this entry for selection. - + Отправлять эту настройку только браузерным диалогам для HTTP Auth. Если включено, обычные формы авторизации не покажут запись среди вариантов выбора. Use this entry only with HTTP Basic Auth @@ -6709,7 +6709,7 @@ Kernel: %3 %4 All clipping programs failed. Tried %1 - + Ни одна программа копирования не сработала. Пробовали %1 AES (%1 rounds) @@ -6847,7 +6847,7 @@ Kernel: %3 %4 Reason - Причика + Причина Edit Entry... diff --git a/share/translations/keepassx_sk.ts b/share/translations/keepassx_sk.ts index 9627aa343..e9b2cc8bf 100644 --- a/share/translations/keepassx_sk.ts +++ b/share/translations/keepassx_sk.ts @@ -137,7 +137,7 @@ You must restart the application to set the new language. Would you like to restart now? - + Musíte reštartovať aplikáciu, aby sa tieto zmeny prejavili. Chcete ju reštartovať teraz? @@ -342,15 +342,15 @@ Automatically save when locking database - + Pri zamknutí databázy automaticky uložiť Automatically save non-data changes when locking database - + Pri zamknutí databázy automaticky uložiť nedátové zmeny Tray icon type - + Typ ikona oznamovacej oblasti @@ -956,7 +956,7 @@ chrome-laptop. Select native messaging host folder location - + Vyberte umiestnenie zložky hostiteľa správe medzi prehliadačom a KeePassXC @@ -4854,23 +4854,23 @@ Očakávajte chyby a menšie problémy, táto verzia nie je určená na produkč Perform Auto-Type Sequence - + Vykonať Automatické vypĺňanie {USERNAME} - + {POUŽÍVATEĽ} {USERNAME}{ENTER} - + {POUŽÍVATEĽ}{ENTER} {PASSWORD} - + {HESLO} {PASSWORD}{ENTER} - + {HESLO}{ENTER} @@ -6571,7 +6571,7 @@ Jadro: %3 %4 Could not save the native messaging script file for %1. - + Nemožno uložiť súbor skriptu správ medzi prehliadačom a KeePassXC (native messaging) pre %1. Copy the given attribute to the clipboard. Defaults to "password" if not specified. diff --git a/share/translations/keepassx_zh_CN.ts b/share/translations/keepassx_zh_CN.ts index bbd521b00..d52116c12 100644 --- a/share/translations/keepassx_zh_CN.ts +++ b/share/translations/keepassx_zh_CN.ts @@ -3127,7 +3127,7 @@ This may cause the affected plugins to malfunction. Are you sure you want to remove %n attachment(s)? - 您确定要删除 %n 个附件吗? + 您确定要删除所选附件吗? Save attachments diff --git a/share/translations/keepassx_zh_TW.ts b/share/translations/keepassx_zh_TW.ts index aa9a421af..052710c78 100644 --- a/share/translations/keepassx_zh_TW.ts +++ b/share/translations/keepassx_zh_TW.ts @@ -4853,19 +4853,19 @@ Expect some bugs and minor issues, this version is not meant for production use. {USERNAME} - + {USERNAME} {USERNAME}{ENTER} - + {USERNAME}{ENTER} {PASSWORD} - + {PASSWORD} {PASSWORD}{ENTER} - + {PASSWORD}{ENTER} diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 90a369d35..898382171 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: keepassxc -version: 2.6.2 +version: 2.6.3 grade: stable summary: Community-driven port of the Windows application “KeePass Password Safe” description: | diff --git a/src/browser/BrowserService.cpp b/src/browser/BrowserService.cpp index 9cb2e2729..5e1173df4 100644 --- a/src/browser/BrowserService.cpp +++ b/src/browser/BrowserService.cpp @@ -321,7 +321,7 @@ QString BrowserService::storeKey(const QString& key) do { QInputDialog keyDialog; - connect(m_currentDatabaseWidget, SIGNAL(databaseLocked()), &keyDialog, SLOT(reject())); + connect(m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), &keyDialog, SLOT(reject())); keyDialog.setWindowTitle(tr("KeePassXC: New key association request")); keyDialog.setLabelText(tr("You have received an association request for the following database:\n%1\n\n" "Give the connection a unique name or ID, for example:\nchrome-laptop.") @@ -745,7 +745,7 @@ BrowserService::sortEntries(QList& pwEntries, const QString& siteUrlStr, // Sort same priority entries by Title or UserName auto entries = priorities.values(key); std::sort(entries.begin(), entries.end(), [&sortField](Entry* left, Entry* right) { - return QString::localeAwareCompare(left->attribute(sortField), right->attribute(sortField)); + return QString::localeAwareCompare(left->attribute(sortField), right->attribute(sortField)) < 0; }); results << entries; if (browserSettings()->bestMatchOnly() && !results.isEmpty()) { @@ -772,7 +772,7 @@ QList BrowserService::confirmEntries(QList& pwEntriesToConfirm, updateWindowState(); BrowserAccessControlDialog accessControlDialog; - connect(m_currentDatabaseWidget, SIGNAL(databaseLocked()), &accessControlDialog, SLOT(reject())); + connect(m_currentDatabaseWidget, SIGNAL(databaseLockRequested()), &accessControlDialog, SLOT(reject())); connect(&accessControlDialog, &BrowserAccessControlDialog::disableAccess, [&](QTableWidgetItem* item) { auto entry = pwEntriesToConfirm[item->row()]; diff --git a/src/cli/Import.cpp b/src/cli/Import.cpp index 930158988..148ee5285 100644 --- a/src/cli/Import.cpp +++ b/src/cli/Import.cpp @@ -83,7 +83,7 @@ int Import::execute(const QStringList& arguments) QString errorMessage; Database db; - db.setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2)); + db.setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)); db.setKey(key); if (!db.import(xmlExportPath, &errorMessage)) { diff --git a/src/cli/Utils.cpp b/src/cli/Utils.cpp index e25ffe02d..d35300b4b 100644 --- a/src/cli/Utils.cpp +++ b/src/cli/Utils.cpp @@ -132,9 +132,9 @@ namespace Utils return {}; } - if (fileKey->type() != FileKey::Hashed) { - err << QObject::tr("WARNING: You are using a legacy key file format which may become\n" - "unsupported in the future.\n\n" + if (fileKey->type() != FileKey::KeePass2XMLv2 && fileKey->type() != FileKey::Hashed) { + err << QObject::tr("WARNING: You are using an old key file format which KeePassXC may\n" + "stop supporting in the future.\n\n" "Please consider generating a new key file.") << endl; } diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 81f856ff5..72b48283a 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -36,8 +36,6 @@ const int Entry::ResolveMaximumDepth = 10; const QString Entry::AutoTypeSequenceUsername = "{USERNAME}{ENTER}"; const QString Entry::AutoTypeSequencePassword = "{PASSWORD}{ENTER}"; -Entry::CloneFlags Entry::DefaultCloneFlags = Entry::CloneNewUuid | Entry::CloneResetTimeInfo; - Entry::Entry() : m_attributes(new EntryAttributes(this)) , m_attachments(new EntryAttachments(this)) @@ -465,7 +463,8 @@ void Entry::setTotp(QSharedPointer settings) m_data.totpSettings.reset(); } else { m_data.totpSettings = std::move(settings); - auto text = Totp::writeSettings(m_data.totpSettings, title(), username()); + auto text = Totp::writeSettings( + m_data.totpSettings, resolveMultiplePlaceholders(title()), resolveMultiplePlaceholders(username())); if (m_data.totpSettings->format != Totp::StorageFormat::LEGACY) { m_attributes->set(Totp::ATTRIBUTE_OTP, text, true); } else { @@ -493,6 +492,15 @@ QSharedPointer Entry::totpSettings() const return m_data.totpSettings; } +QString Entry::totpSettingsString() const +{ + if (m_data.totpSettings) { + return Totp::writeSettings( + m_data.totpSettings, resolveMultiplePlaceholders(title()), resolveMultiplePlaceholders(username()), true); + } + return {}; +} + void Entry::setUuid(const QUuid& uuid) { Q_ASSERT(!uuid.isNull()); diff --git a/src/core/Entry.h b/src/core/Entry.h index 27df86596..83c8eeb1d 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -106,6 +106,7 @@ public: QString notes() const; QString attribute(const QString& key) const; QString totp() const; + QString totpSettingsString() const; QSharedPointer totpSettings() const; int size() const; @@ -159,6 +160,8 @@ public: CloneNewUuid = 1, // generate a random uuid for the clone CloneResetTimeInfo = 2, // set all TimeInfo attributes to the current time CloneIncludeHistory = 4, // clone the history items + CloneDefault = CloneNewUuid | CloneResetTimeInfo, + CloneCopy = CloneNewUuid | CloneResetTimeInfo | CloneIncludeHistory, CloneRenameTitle = 8, // add "-Clone" after the original title CloneUserAsRef = 16, // Add the user as a reference to the original entry ClonePassAsRef = 32, // Add the password as a reference to the original entry @@ -208,7 +211,6 @@ public: static const int ResolveMaximumDepth; static const QString AutoTypeSequenceUsername; static const QString AutoTypeSequencePassword; - static CloneFlags DefaultCloneFlags; /** * Creates a duplicate of this entry except that the returned entry isn't @@ -216,7 +218,7 @@ public: * Note that you need to copy the custom icons manually when inserting the * new entry into another database. */ - Entry* clone(CloneFlags flags = DefaultCloneFlags) const; + Entry* clone(CloneFlags flags = CloneDefault) const; void copyDataFrom(const Entry* other); QString maskPasswordPlaceholders(const QString& str) const; Entry* resolveReference(const QString& str) const; diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 56e545bf6..45e44bff0 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -36,9 +36,6 @@ const int Group::DefaultIconNumber = 48; const int Group::RecycleBinIconNumber = 43; const QString Group::RootAutoTypeSequence = "{USERNAME}{TAB}{PASSWORD}{ENTER}"; -Group::CloneFlags Group::DefaultCloneFlags = - Group::CloneNewUuid | Group::CloneResetTimeInfo | Group::CloneIncludeEntries; - Group::Group() : m_customData(new CustomData(this)) , m_updateTimeinfo(true) diff --git a/src/core/Group.h b/src/core/Group.h index 4bea8e4eb..2997abe17 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -56,6 +56,7 @@ public: CloneNewUuid = 1, // generate a random uuid for the clone CloneResetTimeInfo = 2, // set all TimeInfo attributes to the current time CloneIncludeEntries = 4, // clone the group entries + CloneDefault = CloneNewUuid | CloneResetTimeInfo | CloneIncludeEntries, }; Q_DECLARE_FLAGS(CloneFlags, CloneFlag) @@ -108,7 +109,6 @@ public: static const int DefaultIconNumber; static const int RecycleBinIconNumber; - static CloneFlags DefaultCloneFlags; static const QString RootAutoTypeSequence; Group* findChildByName(const QString& name); @@ -157,8 +157,8 @@ public: QSet customIconsRecursive() const; QList usernamesRecursive(int topN = -1) const; - Group* clone(Entry::CloneFlags entryFlags = Entry::DefaultCloneFlags, - CloneFlags groupFlags = DefaultCloneFlags) const; + Group* clone(Entry::CloneFlags entryFlags = Entry::CloneDefault, + Group::CloneFlags groupFlags = Group::CloneDefault) const; void copyDataFrom(const Group* other); QString print(bool recursive = false, bool flatten = false, int depth = 0); diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp index 4f54ac1d3..fb9f28bd9 100644 --- a/src/crypto/Crypto.cpp +++ b/src/crypto/Crypto.cpp @@ -73,7 +73,7 @@ QString Crypto::debugInfo() Q_ASSERT(Crypto::initialized()); QString debugInfo = QObject::tr("Cryptographic libraries:").append("\n"); - debugInfo.append(" libgcrypt ").append(m_backendVersion).append("\n"); + debugInfo.append("- libgcrypt ").append(m_backendVersion).append("\n"); return debugInfo; } diff --git a/src/crypto/kdf/Argon2Kdf.cpp b/src/crypto/kdf/Argon2Kdf.cpp index 31995fdd0..cc23def83 100644 --- a/src/crypto/kdf/Argon2Kdf.cpp +++ b/src/crypto/kdf/Argon2Kdf.cpp @@ -29,8 +29,9 @@ * a 256-bit salt is generated each time the database is saved, the tag length is 256 bits, no secret key * or associated data. KeePass uses the latest version of Argon2, v1.3. */ -Argon2Kdf::Argon2Kdf() - : Kdf::Kdf(KeePass2::KDF_ARGON2) +Argon2Kdf::Argon2Kdf(Type type) + : Kdf::Kdf(KeePass2::KDF_ARGON2D) + , m_type(type) , m_version(0x13) , m_memory(1 << 16) , m_parallelism(static_cast(QThread::idealThreadCount())) @@ -54,6 +55,16 @@ bool Argon2Kdf::setVersion(quint32 version) return false; } +Argon2Kdf::Type Argon2Kdf::type() const +{ + return m_type; +} + +void Argon2Kdf::setType(Type type) +{ + m_type = type; +} + quint64 Argon2Kdf::memory() const { return m_memory; @@ -133,7 +144,11 @@ bool Argon2Kdf::processParameters(const QVariantMap& p) QVariantMap Argon2Kdf::writeParameters() { QVariantMap p; - p.insert(KeePass2::KDFPARAM_UUID, KeePass2::KDF_ARGON2.toRfc4122()); + if (type() == Type::Argon2d) { + p.insert(KeePass2::KDFPARAM_UUID, KeePass2::KDF_ARGON2D.toRfc4122()); + } else { + p.insert(KeePass2::KDFPARAM_UUID, KeePass2::KDF_ARGON2ID.toRfc4122()); + } p.insert(KeePass2::KDFPARAM_ARGON2_VERSION, version()); p.insert(KeePass2::KDFPARAM_ARGON2_PARALLELISM, parallelism()); p.insert(KeePass2::KDFPARAM_ARGON2_MEMORY, memory() * 1024); @@ -158,18 +173,20 @@ bool Argon2Kdf::transform(const QByteArray& raw, QByteArray& result) const { result.clear(); result.resize(32); - return transformKeyRaw(raw, seed(), version(), rounds(), memory(), parallelism(), result); + return transformKeyRaw(raw, seed(), version(), type(), rounds(), memory(), parallelism(), result); } bool Argon2Kdf::transformKeyRaw(const QByteArray& key, const QByteArray& seed, quint32 version, + Type type, quint32 rounds, quint64 memory, quint32 parallelism, QByteArray& result) { // Time Cost, Mem Cost, Threads/Lanes, Password, length, Salt, length, out, length + int rc = argon2_hash(rounds, memory, parallelism, @@ -181,7 +198,7 @@ bool Argon2Kdf::transformKeyRaw(const QByteArray& key, result.size(), nullptr, 0, - Argon2_d, + type == Type::Argon2d ? Argon2_d : Argon2_id, version); if (rc != ARGON2_OK) { qWarning("Argon2 error: %s", argon2_error_message(rc)); @@ -205,7 +222,7 @@ int Argon2Kdf::benchmarkImpl(int msec) const timer.start(); int rounds = 4; - if (transformKeyRaw(key, seed, version(), rounds, memory(), parallelism(), key)) { + if (transformKeyRaw(key, seed, version(), type(), rounds, memory(), parallelism(), key)) { return static_cast(rounds * (static_cast(msec) / timer.elapsed())); } @@ -214,5 +231,6 @@ int Argon2Kdf::benchmarkImpl(int msec) const QString Argon2Kdf::toString() const { - return QObject::tr("Argon2 (%1 rounds, %2 KB)").arg(QString::number(rounds()), QString::number(memory())); + return QObject::tr("Argon2%1 (%2 rounds, %3 KB)") + .arg(type() == Type::Argon2d ? "d" : "id", QString::number(rounds()), QString::number(memory())); } diff --git a/src/crypto/kdf/Argon2Kdf.h b/src/crypto/kdf/Argon2Kdf.h index 6a16ee96e..b3a8c49b3 100644 --- a/src/crypto/kdf/Argon2Kdf.h +++ b/src/crypto/kdf/Argon2Kdf.h @@ -23,7 +23,13 @@ class Argon2Kdf : public Kdf { public: - Argon2Kdf(); + enum class Type + { + Argon2d, + Argon2id + }; + + Argon2Kdf(Type type); bool processParameters(const QVariantMap& p) override; QVariantMap writeParameters() override; @@ -32,6 +38,8 @@ public: quint32 version() const; bool setVersion(quint32 version); + Type type() const; + void setType(Type type); quint64 memory() const; bool setMemory(quint64 kibibytes); quint32 parallelism() const; @@ -41,6 +49,7 @@ public: protected: int benchmarkImpl(int msec) const override; + Type m_type; quint32 m_version; quint64 m_memory; quint32 m_parallelism; @@ -49,6 +58,7 @@ private: Q_REQUIRED_RESULT static bool transformKeyRaw(const QByteArray& key, const QByteArray& seed, quint32 version, + Type type, quint32 rounds, quint64 memory, quint32 parallelism, diff --git a/src/format/CsvExporter.cpp b/src/format/CsvExporter.cpp index 98fc6fdc8..281b94761 100644 --- a/src/format/CsvExporter.cpp +++ b/src/format/CsvExporter.cpp @@ -67,6 +67,10 @@ QString CsvExporter::exportHeader() addColumn(header, "Password"); addColumn(header, "URL"); addColumn(header, "Notes"); + addColumn(header, "TOTP"); + addColumn(header, "Icon"); + addColumn(header, "Last Modified"); + addColumn(header, "Created"); return header + QString("\n"); } @@ -88,6 +92,10 @@ QString CsvExporter::exportGroup(const Group* group, QString groupPath) addColumn(line, entry->password()); addColumn(line, entry->url()); addColumn(line, entry->notes()); + addColumn(line, entry->totpSettingsString()); + addColumn(line, QString::number(entry->iconNumber())); + addColumn(line, entry->timeInfo().lastModificationTime().toString(Qt::ISODate)); + addColumn(line, entry->timeInfo().creationTime().toString(Qt::ISODate)); line.append("\n"); response.append(line); diff --git a/src/format/KeePass2.cpp b/src/format/KeePass2.cpp index dc50ca001..bf5bb1cae 100644 --- a/src/format/KeePass2.cpp +++ b/src/format/KeePass2.cpp @@ -30,7 +30,8 @@ const QUuid KeePass2::CIPHER_CHACHA20 = QUuid("d6038a2b-8b6f-4cb5-a524-339a31dbb const QUuid KeePass2::KDF_AES_KDBX3 = QUuid("c9d9f39a-628a-4460-bf74-0d08c18a4fea"); const QUuid KeePass2::KDF_AES_KDBX4 = QUuid("7c02bb82-79a7-4ac0-927d-114a00648238"); -const QUuid KeePass2::KDF_ARGON2 = QUuid("ef636ddf-8c29-444b-91f7-a9a403e30a0c"); +const QUuid KeePass2::KDF_ARGON2D = QUuid("ef636ddf-8c29-444b-91f7-a9a403e30a0c"); +const QUuid KeePass2::KDF_ARGON2ID = QUuid("9e298b19-56db-4773-b23d-fc3ec6f0a1e6"); const QByteArray KeePass2::INNER_STREAM_SALSA20_IV("\xe8\x30\x09\x4b\x97\x20\x5d\x2a"); @@ -53,7 +54,8 @@ const QList> KeePass2::CIPHERS{ qMakePair(KeePass2::CIPHER_CHACHA20, QObject::tr("ChaCha20 256-bit"))}; const QList> KeePass2::KDFS{ - qMakePair(KeePass2::KDF_ARGON2, QObject::tr("Argon2 (KDBX 4 – recommended)")), + qMakePair(KeePass2::KDF_ARGON2D, QObject::tr("Argon2d (KDBX 4 – recommended)")), + qMakePair(KeePass2::KDF_ARGON2ID, QObject::tr("Argon2id (KDBX 4)")), qMakePair(KeePass2::KDF_AES_KDBX4, QObject::tr("AES-KDF (KDBX 4)")), qMakePair(KeePass2::KDF_AES_KDBX3, QObject::tr("AES-KDF (KDBX 3.1)"))}; @@ -109,8 +111,11 @@ QSharedPointer KeePass2::uuidToKdf(const QUuid& uuid) if (uuid == KDF_AES_KDBX4) { return QSharedPointer::create(); } - if (uuid == KDF_ARGON2) { - return QSharedPointer::create(); + if (uuid == KDF_ARGON2D) { + return QSharedPointer::create(Argon2Kdf::Type::Argon2d); + } + if (uuid == KDF_ARGON2ID) { + return QSharedPointer::create(Argon2Kdf::Type::Argon2id); } return {}; diff --git a/src/format/KeePass2.h b/src/format/KeePass2.h index d18db3578..abb24a800 100644 --- a/src/format/KeePass2.h +++ b/src/format/KeePass2.h @@ -53,7 +53,8 @@ namespace KeePass2 extern const QUuid KDF_AES_KDBX3; extern const QUuid KDF_AES_KDBX4; - extern const QUuid KDF_ARGON2; + extern const QUuid KDF_ARGON2D; + extern const QUuid KDF_ARGON2ID; extern const QByteArray INNER_STREAM_SALSA20_IV; diff --git a/src/format/OpVaultReader.cpp b/src/format/OpVaultReader.cpp index a64b009de..dab08bd82 100644 --- a/src/format/OpVaultReader.cpp +++ b/src/format/OpVaultReader.cpp @@ -72,7 +72,7 @@ Database* OpVaultReader::readDatabase(QDir& opdataDir, const QString& password) key->addKey(QSharedPointer::create(password)); QScopedPointer db(new Database()); - db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2)); + db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)); db->setCipher(KeePass2::CIPHER_AES256); db->setKey(key, true, false); db->metadata()->setName(vaultName); diff --git a/src/gui/AboutDialog.cpp b/src/gui/AboutDialog.cpp index b97d62590..7c89b8804 100644 --- a/src/gui/AboutDialog.cpp +++ b/src/gui/AboutDialog.cpp @@ -59,6 +59,7 @@ static const QString aboutContributors = R"(
  • Kernellinux
  • Micha Ober
  • PublicByte
  • +
  • Clayton Casciato

Notable Code Contributions:

    @@ -86,7 +87,6 @@ static const QString aboutContributors = R"(

Patreon Supporters:

    -
  • Igor Zinovik
  • Alexanderjb
  • Richard Ames
  • SLmanDR
  • @@ -94,7 +94,7 @@ static const QString aboutContributors = R"(
  • Tyler Gass
  • Nuutti Toivola
  • Gregory Werbin
  • -
  • Lionel Laské
  • +
  • Lionel Laské
  • Ivar
  • Darren
  • Brad
  • diff --git a/src/gui/Clipboard.cpp b/src/gui/Clipboard.cpp index ddd07f29f..ab4a84cf0 100644 --- a/src/gui/Clipboard.cpp +++ b/src/gui/Clipboard.cpp @@ -59,7 +59,12 @@ void Clipboard::setText(const QString& text, bool clear) clipboard->setMimeData(mime, QClipboard::Clipboard); #else mime->setText(text); +#ifdef Q_OS_LINUX mime->setData("x-kde-passwordManagerHint", QByteArrayLiteral("secret")); +#endif +#ifdef Q_OS_WIN + mime->setData("ExcludeClipboardContentFromMonitorProcessing", QByteArrayLiteral("1")); +#endif clipboard->setMimeData(mime, QClipboard::Clipboard); if (clipboard->supportsSelection()) { diff --git a/src/gui/DatabaseOpenDialog.cpp b/src/gui/DatabaseOpenDialog.cpp index e7194b7e2..eaa8877ee 100644 --- a/src/gui/DatabaseOpenDialog.cpp +++ b/src/gui/DatabaseOpenDialog.cpp @@ -20,12 +20,19 @@ #include "DatabaseWidget.h" #include "core/Database.h" +#ifdef Q_OS_WIN +#include +#endif + DatabaseOpenDialog::DatabaseOpenDialog(QWidget* parent) : QDialog(parent) , m_view(new DatabaseOpenWidget(this)) { setWindowTitle(tr("Unlock Database - KeePassXC")); setWindowFlags(Qt::Dialog | Qt::WindowStaysOnTopHint); +#ifdef Q_OS_WIN + QWindowsWindowFunctions::setWindowActivationBehavior(QWindowsWindowFunctions::AlwaysActivateWindow); +#endif connect(m_view, SIGNAL(dialogFinished(bool)), this, SLOT(complete(bool))); auto* layout = new QVBoxLayout(); layout->setMargin(0); diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index b48f86365..b42555738 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -165,6 +165,7 @@ void DatabaseOpenWidget::clearForms() m_ui->editPassword->setText(""); m_ui->editPassword->setShowPassword(false); m_ui->keyFileLineEdit->clear(); + m_ui->keyFileLineEdit->setShowPassword(false); m_ui->checkTouchID->setChecked(false); m_ui->challengeResponseCombo->clear(); m_db.reset(); @@ -301,12 +302,14 @@ QSharedPointer DatabaseOpenWidget::buildDatabaseKey() m_ui->messageWidget->showMessage(tr("Failed to open key file: %1").arg(errorMsg), MessageWidget::Error); return {}; } - if (key->type() != FileKey::Hashed && !config()->get(Config::Messages_NoLegacyKeyFileWarning).toBool()) { + if (key->type() != FileKey::KeePass2XMLv2 && key->type() != FileKey::Hashed + && !config()->get(Config::Messages_NoLegacyKeyFileWarning).toBool()) { QMessageBox legacyWarning; - legacyWarning.setWindowTitle(tr("Legacy key file format")); - legacyWarning.setText(tr("You are using a legacy key file format which may become\n" - "unsupported in the future.\n\n" - "Please consider generating a new key file.")); + legacyWarning.setWindowTitle(tr("Old key file format")); + legacyWarning.setText(tr("You are using an old key file format which KeePassXC may
    " + "stop supporting in the future.

    " + "Please consider generating a new key file by going to:
    " + "Database / Database Security / Change Key File.
    ")); legacyWarning.setIcon(QMessageBox::Icon::Warning); legacyWarning.addButton(QMessageBox::Ok); legacyWarning.setDefaultButton(QMessageBox::Ok); @@ -355,7 +358,7 @@ void DatabaseOpenWidget::reject() void DatabaseOpenWidget::browseKeyFile() { - QString filters = QString("%1 (*);;%2 (*.key)").arg(tr("All files"), tr("Key files")); + QString filters = QString("%1 (*);;%2 (*.keyx; *.key)").arg(tr("All files"), tr("Key files")); if (!config()->get(Config::RememberLastKeyFiles).toBool()) { fileDialog()->setNextForgetDialog(); } @@ -378,6 +381,7 @@ void DatabaseOpenWidget::browseKeyFile() void DatabaseOpenWidget::clearKeyFileText() { m_ui->keyFileLineEdit->clear(); + m_ui->keyFileLineEdit->setShowPassword(false); } void DatabaseOpenWidget::pollHardwareKey() diff --git a/src/gui/DatabaseOpenWidget.ui b/src/gui/DatabaseOpenWidget.ui index eef4a2ed2..167f4b7d4 100644 --- a/src/gui/DatabaseOpenWidget.ui +++ b/src/gui/DatabaseOpenWidget.ui @@ -406,7 +406,7 @@ 0 - + 0 @@ -416,6 +416,9 @@ Key file to unlock the database + + QLineEdit::Password + true diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 505e7f0ba..28d3aedd7 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -216,7 +216,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) #ifdef WITH_XC_SSHAGENT if (sshAgent()->isEnabled()) { - connect(this, SIGNAL(databaseLockRequested()), sshAgent(), SLOT(databaseLocked())); + connect(this, SIGNAL(databaseLocked()), sshAgent(), SLOT(databaseLocked())); connect(this, SIGNAL(databaseUnlocked()), sshAgent(), SLOT(databaseUnlocked())); } #endif @@ -437,6 +437,7 @@ void DatabaseWidget::showTotp() } auto totpDialog = new TotpDialog(this, currentEntry); + connect(this, &DatabaseWidget::databaseLockRequested, totpDialog, &TotpDialog::close); totpDialog->open(); } @@ -460,6 +461,7 @@ void DatabaseWidget::setupTotp() auto setupTotpDialog = new TotpSetupDialog(this, currentEntry); connect(setupTotpDialog, SIGNAL(totpUpdated()), SIGNAL(entrySelectionChanged())); + connect(this, &DatabaseWidget::databaseLockRequested, setupTotpDialog, &TotpSetupDialog::close); setupTotpDialog->open(); } @@ -701,6 +703,7 @@ void DatabaseWidget::showTotpKeyQrCode() auto currentEntry = currentSelectedEntry(); if (currentEntry) { auto totpDisplayDialog = new TotpExportSettingsDialog(this, currentEntry); + connect(this, &DatabaseWidget::databaseLockRequested, totpDisplayDialog, &TotpExportSettingsDialog::close); totpDisplayDialog->open(); } } @@ -1081,6 +1084,9 @@ void DatabaseWidget::loadDatabase(bool accepted) replaceDatabase(openWidget->database()); switchToMainView(); processAutoOpen(); + restoreGroupEntryFocus(m_groupBeforeLock, m_entryBeforeLock); + m_groupBeforeLock = QUuid(); + m_entryBeforeLock = QUuid(); m_saveAttempts = 0; emit databaseUnlocked(); if (config()->get(Config::MinimizeAfterUnlock).toBool()) { @@ -1528,6 +1534,11 @@ bool DatabaseWidget::lock() emit databaseLockRequested(); + // ignore event if we are active and a modal dialog is still open (such as a message box or file dialog) + if (isVisible() && QApplication::activeModalWidget()) { + return false; + } + clipboard()->clearCopiedText(); if (isEditWidgetModified()) { diff --git a/src/gui/EditWidget.cpp b/src/gui/EditWidget.cpp index 72742b5ac..fbd07a82e 100644 --- a/src/gui/EditWidget.cpp +++ b/src/gui/EditWidget.cpp @@ -74,6 +74,18 @@ void EditWidget::addPage(const QString& labelText, const QIcon& icon, QWidget* w m_ui->categoryList->addCategory(labelText, icon); } +bool EditWidget::hasPage(QWidget* widget) +{ + for (int i = 0; i < m_ui->stackedWidget->count(); i++) { + auto* scrollArea = qobject_cast(m_ui->stackedWidget->widget(i)); + if (scrollArea && scrollArea->widget() == widget) { + return true; + } + } + + return false; +} + void EditWidget::setPageHidden(QWidget* widget, bool hidden) { int index = -1; diff --git a/src/gui/EditWidget.h b/src/gui/EditWidget.h index 361961f76..c4997abae 100644 --- a/src/gui/EditWidget.h +++ b/src/gui/EditWidget.h @@ -42,6 +42,7 @@ public: ~EditWidget(); void addPage(const QString& labelText, const QIcon& icon, QWidget* widget); + bool hasPage(QWidget* widget); void setPageHidden(QWidget* widget, bool hidden); void setCurrentPage(int index); void setHeadline(const QString& text); diff --git a/src/gui/EntryPreviewWidget.cpp b/src/gui/EntryPreviewWidget.cpp index 1dc05c3b7..45a71a348 100644 --- a/src/gui/EntryPreviewWidget.cpp +++ b/src/gui/EntryPreviewWidget.cpp @@ -286,14 +286,18 @@ void EntryPreviewWidget::updateEntryAdvancedTab() setTabEnabled(m_ui->entryTabWidget, m_ui->entryAdvancedTab, hasAttributes || hasAttachments); if (hasAttributes) { - QString attributesText; + QString attributesText(""); for (const QString& key : customAttributes) { - QString value = m_currentEntry->attributes()->value(key); + QString value; if (m_currentEntry->attributes()->isProtected(key)) { value = "" + tr("[PROTECTED]") + ""; + } else { + value = m_currentEntry->attributes()->value(key).toHtmlEscaped(); + value.replace('\n', QLatin1String("
    ")); } - attributesText.append(tr("%1: %2", "attributes line").arg(key, value).append("
    ")); + attributesText.append(tr("", "attributes line").arg(key, value)); } + attributesText.append("
    %1:%2
    "); m_ui->entryAttributesEdit->setText(attributesText); } @@ -303,6 +307,8 @@ void EntryPreviewWidget::updateEntryAdvancedTab() void EntryPreviewWidget::updateEntryAutotypeTab() { Q_ASSERT(m_currentEntry); + + m_ui->entrySequenceLabel->setText(m_currentEntry->effectiveAutoTypeSequence()); m_ui->entryAutotypeTree->clear(); QList items; const AutoTypeAssociations* autotypeAssociations = m_currentEntry->autoTypeAssociations(); @@ -314,7 +320,7 @@ void EntryPreviewWidget::updateEntryAutotypeTab() } m_ui->entryAutotypeTree->addTopLevelItems(items); - setTabEnabled(m_ui->entryTabWidget, m_ui->entryAutotypeTab, !items.isEmpty()); + setTabEnabled(m_ui->entryTabWidget, m_ui->entryAutotypeTab, m_currentEntry->autoTypeEnabled()); } void EntryPreviewWidget::updateGroupHeaderLine() diff --git a/src/gui/EntryPreviewWidget.ui b/src/gui/EntryPreviewWidget.ui index d78b04a43..961e75505 100644 --- a/src/gui/EntryPreviewWidget.ui +++ b/src/gui/EntryPreviewWidget.ui @@ -705,6 +705,62 @@ Autotype + + + + + 0 + + + 0 + + + 0 + + + 5 + + + + + + 0 + 0 + + + + + 75 + true + + + + Default Sequence + + + Qt::AlignRight|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + sequence + + + Qt::AlignLeft|Qt::AlignVCenter + + + + + + diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index f3a6e5831..d1eb1fe17 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -497,6 +497,14 @@ MainWindow::MainWindow() connect(m_ui->actionOnlineHelp, SIGNAL(triggered()), SLOT(openOnlineHelp())); connect(m_ui->actionKeyboardShortcuts, SIGNAL(triggered()), SLOT(openKeyboardShortcuts())); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + // Install event filter for empty-area drag + auto* eventFilter = new MainWindowEventFilter(this); + m_ui->menubar->installEventFilter(eventFilter); + m_ui->toolBar->installEventFilter(eventFilter); + m_ui->tabWidget->tabBar()->installEventFilter(eventFilter); +#endif + #ifdef Q_OS_MACOS setUnifiedTitleAndToolBarOnMac(true); #endif @@ -519,6 +527,11 @@ MainWindow::MainWindow() m_ui->actionGroupDownloadFavicons->setVisible(false); m_ui->actionEntryDownloadIcon->setVisible(false); #endif +#ifndef WITH_XC_DOCS + m_ui->actionGettingStarted->setVisible(false); + m_ui->actionUserGuide->setVisible(false); + m_ui->actionKeyboardShortcuts->setVisible(false); +#endif // clang-format off connect(m_ui->tabWidget, SIGNAL(messageGlobal(QString,MessageWidget::MessageType)), @@ -743,7 +756,9 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) m_ui->actionGroupSortDesc->setEnabled(groupSelected && currentGroupHasChildren); m_ui->actionGroupEmptyRecycleBin->setVisible(recycleBinSelected); m_ui->actionGroupEmptyRecycleBin->setEnabled(recycleBinSelected); +#ifdef WITH_XC_NETWORKING m_ui->actionGroupDownloadFavicons->setVisible(!recycleBinSelected); +#endif m_ui->actionGroupDownloadFavicons->setEnabled(groupSelected && currentGroupHasEntries && !recycleBinSelected); m_ui->actionDatabaseSecurity->setEnabled(true); @@ -1529,11 +1544,6 @@ void MainWindow::toggleWindow() void MainWindow::lockDatabasesAfterInactivity() { - // ignore event if a modal dialog is open (such as a message box or file dialog) - if (QApplication::activeModalWidget()) { - return; - } - m_ui->tabWidget->lockDatabases(); } @@ -1754,3 +1764,44 @@ void MainWindow::initViewMenu() config()->set(Config::GUI_HidePasswords, checked); }); } + +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + +MainWindowEventFilter::MainWindowEventFilter(QObject* parent) + : QObject(parent) +{ +} + +/** + * MainWindow event filter to initiate empty-area drag on the toolbar, menubar, and tabbar. + */ +bool MainWindowEventFilter::eventFilter(QObject* watched, QEvent* event) +{ + auto* mainWindow = getMainWindow(); + if (!mainWindow || !mainWindow->m_ui) { + return QObject::eventFilter(watched, event); + } + + if (event->type() == QEvent::MouseButtonPress) { + if (watched == mainWindow->m_ui->menubar) { + mainWindow->windowHandle()->startSystemMove(); + // Continue processing events, so menus keep working. + return false; + } else if (watched == mainWindow->m_ui->toolBar) { + if (!mainWindow->m_ui->toolBar->isMovable() || mainWindow->m_ui->toolBar->cursor() != Qt::SizeAllCursor) { + mainWindow->windowHandle()->startSystemMove(); + return false; + } + } else if (watched == mainWindow->m_ui->tabWidget->tabBar()) { + auto* m = static_cast(event); + if (mainWindow->m_ui->tabWidget->tabBar()->tabAt(m->pos()) == -1) { + mainWindow->windowHandle()->startSystemMove(); + return true; + } + } + } + + return QObject::eventFilter(watched, event); +} + +#endif diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index bfbb53538..7db347fbd 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -35,6 +35,7 @@ namespace Ui class InactivityTimer; class SearchWidget; +class MainWindowEventFilter; class MainWindow : public QMainWindow { @@ -181,8 +182,21 @@ private: QTimer m_updateCheckTimer; QTimer m_trayIconTriggerTimer; QSystemTrayIcon::ActivationReason m_trayIconTriggerReason; + + friend class MainWindowEventFilter; }; +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) +class MainWindowEventFilter : public QObject +{ + Q_OBJECT + +public: + explicit MainWindowEventFilter(QObject* parent); + bool eventFilter(QObject* watched, QEvent* event) override; +}; +#endif + /** * Return instance of MainWindow created on app load * non-gui instances will return nullptr diff --git a/src/gui/PasswordGeneratorWidget.cpp b/src/gui/PasswordGeneratorWidget.cpp index 2dc643df2..4be78fce9 100644 --- a/src/gui/PasswordGeneratorWidget.cpp +++ b/src/gui/PasswordGeneratorWidget.cpp @@ -173,9 +173,9 @@ void PasswordGeneratorWidget::saveSettings() config()->set(Config::PasswordGenerator_AdvancedMode, m_ui->buttonAdvancedMode->isChecked()); if (m_ui->buttonAdvancedMode->isChecked()) { - config()->set(Config::PasswordGenerator_SpecialChars, m_ui->checkBoxSpecialChars->isChecked()); - } else { config()->set(Config::PasswordGenerator_Logograms, m_ui->checkBoxSpecialChars->isChecked()); + } else { + config()->set(Config::PasswordGenerator_SpecialChars, m_ui->checkBoxSpecialChars->isChecked()); } config()->set(Config::PasswordGenerator_Braces, m_ui->checkBoxBraces->isChecked()); config()->set(Config::PasswordGenerator_Punctuation, m_ui->checkBoxPunctuation->isChecked()); diff --git a/src/gui/PasswordGeneratorWidget.ui b/src/gui/PasswordGeneratorWidget.ui index 81964a517..d2b2f703b 100644 --- a/src/gui/PasswordGeneratorWidget.ui +++ b/src/gui/PasswordGeneratorWidget.ui @@ -259,9 +259,6 @@ QProgressBar::chunk { 1 - - 128 - 20 diff --git a/src/gui/TotpDialog.cpp b/src/gui/TotpDialog.cpp index 871c2863c..c348b3f27 100644 --- a/src/gui/TotpDialog.cpp +++ b/src/gui/TotpDialog.cpp @@ -31,10 +31,7 @@ TotpDialog::TotpDialog(QWidget* parent, Entry* entry) , m_ui(new Ui::TotpDialog()) , m_entry(entry) { - if (!m_entry->hasTotp()) { - close(); - return; - } + setAttribute(Qt::WA_DeleteOnClose); m_ui->setupUi(this); @@ -42,14 +39,11 @@ TotpDialog::TotpDialog(QWidget* parent, Entry* entry) resetCounter(); updateProgressBar(); - connect(parent, SIGNAL(databaseLocked()), SLOT(close())); connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateProgressBar())); connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateSeconds())); m_totpUpdateTimer.start(m_step * 10); updateTotp(); - setAttribute(Qt::WA_DeleteOnClose); - new QShortcut(QKeySequence(QKeySequence::Copy), this, SLOT(copyToClipboard())); m_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Copy")); diff --git a/src/gui/TotpExportSettingsDialog.cpp b/src/gui/TotpExportSettingsDialog.cpp index f73b9877a..cee9fc824 100644 --- a/src/gui/TotpExportSettingsDialog.cpp +++ b/src/gui/TotpExportSettingsDialog.cpp @@ -59,7 +59,6 @@ TotpExportSettingsDialog::TotpExportSettingsDialog(DatabaseWidget* parent, Entry connect(m_buttonBox, SIGNAL(rejected()), SLOT(close())); connect(m_buttonBox, SIGNAL(accepted()), SLOT(copyToClipboard())); connect(m_timer, SIGNAL(timeout()), SLOT(autoClose())); - connect(parent, SIGNAL(lockedDatabase()), SLOT(close())); new QShortcut(QKeySequence(QKeySequence::Copy), this, SLOT(copyToClipboard())); diff --git a/src/gui/csvImport/CsvImportWidget.cpp b/src/gui/csvImport/CsvImportWidget.cpp index 01fd5fc89..e78e9f94a 100644 --- a/src/gui/csvImport/CsvImportWidget.cpp +++ b/src/gui/csvImport/CsvImportWidget.cpp @@ -27,6 +27,7 @@ #include "format/KeePass2Writer.h" #include "gui/MessageBox.h" #include "gui/MessageWidget.h" +#include "totp/totp.h" // I wanted to make the CSV import GUI future-proof, so if one day you need a new field, // all you have to do is add a field to m_columnHeader, and the GUI will follow: @@ -39,7 +40,8 @@ CsvImportWidget::CsvImportWidget(QWidget* parent) , m_comboModel(new QStringListModel(this)) , m_columnHeader(QStringList() << QObject::tr("Group") << QObject::tr("Title") << QObject::tr("Username") << QObject::tr("Password") << QObject::tr("URL") << QObject::tr("Notes") - << QObject::tr("Last Modified") << QObject::tr("Created")) + << QObject::tr("TOTP") << QObject::tr("Icon") << QObject::tr("Last Modified") + << QObject::tr("Created")) , m_fieldSeparatorList(QStringList() << "," << ";" << "-" @@ -54,7 +56,7 @@ CsvImportWidget::CsvImportWidget(QWidget* parent) m_ui->messageWidget->setHidden(true); m_combos << m_ui->groupCombo << m_ui->titleCombo << m_ui->usernameCombo << m_ui->passwordCombo << m_ui->urlCombo - << m_ui->notesCombo << m_ui->lastModifiedCombo << m_ui->createdCombo; + << m_ui->notesCombo << m_ui->totpCombo << m_ui->iconCombo << m_ui->lastModifiedCombo << m_ui->createdCombo; for (auto combo : m_combos) { combo->setModel(m_comboModel); @@ -206,17 +208,38 @@ void CsvImportWidget::writeDatabase() entry->setUrl(m_parserModel->data(m_parserModel->index(r, 4)).toString()); entry->setNotes(m_parserModel->data(m_parserModel->index(r, 5)).toString()); - TimeInfo timeInfo; if (m_parserModel->data(m_parserModel->index(r, 6)).isValid()) { - qint64 lastModified = m_parserModel->data(m_parserModel->index(r, 6)).toString().toLongLong(); - if (lastModified) { - timeInfo.setLastModificationTime(Clock::datetimeUtc(lastModified * 1000)); + auto totp = Totp::parseSettings(m_parserModel->data(m_parserModel->index(r, 6)).toString()); + entry->setTotp(totp); + } + + bool ok; + int icon = m_parserModel->data(m_parserModel->index(r, 7)).toInt(&ok); + if (ok) { + entry->setIcon(icon); + } + + TimeInfo timeInfo; + if (m_parserModel->data(m_parserModel->index(r, 8)).isValid()) { + auto datetime = m_parserModel->data(m_parserModel->index(r, 8)).toString(); + if (datetime.contains(QRegularExpression("^\\d+$"))) { + timeInfo.setLastModificationTime(Clock::datetimeUtc(datetime.toLongLong() * 1000)); + } else { + auto lastModified = QDateTime::fromString(datetime, Qt::ISODate); + if (lastModified.isValid()) { + timeInfo.setLastModificationTime(lastModified); + } } } - if (m_parserModel->data(m_parserModel->index(r, 7)).isValid()) { - qint64 created = m_parserModel->data(m_parserModel->index(r, 7)).toString().toLongLong(); - if (created) { - timeInfo.setCreationTime(Clock::datetimeUtc(created * 1000)); + if (m_parserModel->data(m_parserModel->index(r, 9)).isValid()) { + auto datetime = m_parserModel->data(m_parserModel->index(r, 9)).toString(); + if (datetime.contains(QRegularExpression("^\\d+$"))) { + timeInfo.setCreationTime(Clock::datetimeUtc(datetime.toLongLong() * 1000)); + } else { + auto created = QDateTime::fromString(datetime, Qt::ISODate); + if (created.isValid()) { + timeInfo.setCreationTime(created); + } } } entry->setTimeInfo(timeInfo); diff --git a/src/gui/csvImport/CsvImportWidget.ui b/src/gui/csvImport/CsvImportWidget.ui index 1c268fd9d..d3364cb4c 100644 --- a/src/gui/csvImport/CsvImportWidget.ui +++ b/src/gui/csvImport/CsvImportWidget.ui @@ -96,21 +96,8 @@ - - - - - 50 - false - - - - Last Modified - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + @@ -126,13 +113,13 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 2 + - - - - - + + 50 @@ -140,28 +127,21 @@ - Created + Username Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 2 + - - - - - 50 - false - - - - Notes - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + + + + @@ -177,6 +157,9 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 2 + @@ -196,9 +179,12 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 2 + - + @@ -212,10 +198,16 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 2 + - - + + + + + 50 @@ -223,30 +215,106 @@ - Username + Notes Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 2 + - - - - - - - - - - - + + + + + 50 + false + + + + TOTP + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 2 + + + + + + + + + + + + + + 50 + false + + + + Created + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 2 + + + + + + + + 50 + false + + + + Last Modified + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 2 + + - + + + + + + + 50 + false + + + + Icon + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 2 + + + + + @@ -682,10 +750,6 @@ titleCombo usernameCombo passwordCombo - urlCombo - notesCombo - lastModifiedCombo - createdCombo comboBoxCodec comboBoxTextQualifier comboBoxFieldSeparator diff --git a/src/gui/databasekey/KeyFileEditWidget.cpp b/src/gui/databasekey/KeyFileEditWidget.cpp index e0486ae07..2fb0b3de2 100644 --- a/src/gui/databasekey/KeyFileEditWidget.cpp +++ b/src/gui/databasekey/KeyFileEditWidget.cpp @@ -47,12 +47,12 @@ bool KeyFileEditWidget::addToCompositeKey(QSharedPointer key) return false; } - if (fileKey->type() != FileKey::Hashed) { + if (fileKey->type() != FileKey::KeePass2XMLv2 && fileKey->type() != FileKey::Hashed) { QMessageBox::warning(getMainWindow(), - tr("Legacy key file format"), - tr("You are using a legacy key file format which may become\n" - "unsupported in the future.\n\n" - "Generate a new key file in the database security settings."), + tr("Old key file format"), + tr("You selected a key file in an old format which KeePassXC
    " + "may stop supporting in the future.

    " + "Please consider generating a new key file instead."), QMessageBox::Ok); } @@ -96,7 +96,7 @@ void KeyFileEditWidget::createKeyFile() if (!m_compEditWidget) { return; } - QString filters = QString("%1 (*.key);;%2 (*)").arg(tr("Key files"), tr("All files")); + QString filters = QString("%1 (*.keyx; *.key);;%2 (*)").arg(tr("Key files"), tr("All files")); QString fileName = fileDialog()->getSaveFileName(this, tr("Create Key File..."), QString(), filters); if (!fileName.isEmpty()) { @@ -119,7 +119,7 @@ void KeyFileEditWidget::browseKeyFile() if (!m_compEditWidget) { return; } - QString filters = QString("%1 (*.key);;%2 (*)").arg(tr("Key files"), tr("All files")); + QString filters = QString("%1 (*.keyx; *.key);;%2 (*)").arg(tr("Key files"), tr("All files")); QString fileName = fileDialog()->getOpenFileName(this, tr("Select a key file"), QString(), filters); if (QFileInfo(fileName).canonicalFilePath() == m_parent->getDatabase()->canonicalFilePath()) { diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp index cc57e453a..2df1f28f0 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp @@ -43,7 +43,7 @@ DatabaseSettingsWidgetEncryption::DatabaseSettingsWidgetEncryption(QWidget* pare connect(m_ui->memorySpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryChanged(int))); connect(m_ui->parallelismSpinBox, SIGNAL(valueChanged(int)), this, SLOT(parallelismChanged(int))); - m_ui->compatibilitySelection->addItem(tr("KDBX 4.0 (recommended)"), KeePass2::KDF_ARGON2.toByteArray()); + m_ui->compatibilitySelection->addItem(tr("KDBX 4.0 (recommended)"), KeePass2::KDF_ARGON2D.toByteArray()); m_ui->compatibilitySelection->addItem(tr("KDBX 3.1"), KeePass2::KDF_AES_KDBX3.toByteArray()); m_ui->decryptionTimeSlider->setMinimum(Kdf::MIN_ENCRYPTION_TIME / 100); m_ui->decryptionTimeSlider->setMaximum(Kdf::MAX_ENCRYPTION_TIME / 100); @@ -75,6 +75,9 @@ DatabaseSettingsWidgetEncryption::~DatabaseSettingsWidgetEncryption() { } +#define IS_ARGON2(uuid) (uuid == KeePass2::KDF_ARGON2D || uuid == KeePass2::KDF_ARGON2ID) +#define IS_AES_KDF(uuid) (uuid == KeePass2::KDF_AES_KDBX3 || uuid == KeePass2::KDF_AES_KDBX4) + void DatabaseSettingsWidgetEncryption::initialize() { Q_ASSERT(m_db); @@ -85,7 +88,7 @@ void DatabaseSettingsWidgetEncryption::initialize() bool isDirty = false; if (!m_db->kdf()) { - m_db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2)); + m_db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)); isDirty = true; } if (!m_db->key()) { @@ -175,7 +178,7 @@ void DatabaseSettingsWidgetEncryption::loadKdfParameters() } m_ui->transformRoundsSpinBox->setValue(kdf->rounds()); - if (m_db->kdf()->uuid() == KeePass2::KDF_ARGON2) { + if (IS_ARGON2(m_db->kdf()->uuid())) { auto argon2Kdf = kdf.staticCast(); m_ui->memorySpinBox->setValue(static_cast(argon2Kdf->memory()) / (1 << 10)); m_ui->parallelismSpinBox->setValue(argon2Kdf->parallelism()); @@ -188,13 +191,10 @@ void DatabaseSettingsWidgetEncryption::updateKdfFields() { QUuid id = m_db->kdf()->uuid(); - bool memoryVisible = (id == KeePass2::KDF_ARGON2); - m_ui->memoryUsageLabel->setVisible(memoryVisible); - m_ui->memorySpinBox->setVisible(memoryVisible); - - bool parallelismVisible = (id == KeePass2::KDF_ARGON2); - m_ui->parallelismLabel->setVisible(parallelismVisible); - m_ui->parallelismSpinBox->setVisible(parallelismVisible); + m_ui->memoryUsageLabel->setVisible(IS_ARGON2(id)); + m_ui->memorySpinBox->setVisible(IS_ARGON2(id)); + m_ui->parallelismLabel->setVisible(IS_ARGON2(id)); + m_ui->parallelismSpinBox->setVisible(IS_ARGON2(id)); } void DatabaseSettingsWidgetEncryption::activateChangeDecryptionTime() @@ -253,7 +253,7 @@ bool DatabaseSettingsWidgetEncryption::save() m_db->metadata()->customData()->remove(CD_DECRYPTION_TIME_PREFERENCE_KEY); // first perform safety check for KDF rounds - if (kdf->uuid() == KeePass2::KDF_ARGON2 && m_ui->transformRoundsSpinBox->value() > 10000) { + if (IS_ARGON2(kdf->uuid()) && m_ui->transformRoundsSpinBox->value() > 10000) { QMessageBox warning; warning.setIcon(QMessageBox::Warning); warning.setWindowTitle(tr("Number of rounds too high", "Key transformation rounds")); @@ -266,8 +266,7 @@ bool DatabaseSettingsWidgetEncryption::save() if (warning.clickedButton() != ok) { return false; } - } else if ((kdf->uuid() == KeePass2::KDF_AES_KDBX3 || kdf->uuid() == KeePass2::KDF_AES_KDBX4) - && m_ui->transformRoundsSpinBox->value() < 100000) { + } else if (IS_AES_KDF(kdf->uuid()) && m_ui->transformRoundsSpinBox->value() < 100000) { QMessageBox warning; warning.setIcon(QMessageBox::Warning); warning.setWindowTitle(tr("Number of rounds too low", "Key transformation rounds")); @@ -286,7 +285,7 @@ bool DatabaseSettingsWidgetEncryption::save() // Save kdf parameters kdf->setRounds(m_ui->transformRoundsSpinBox->value()); - if (kdf->uuid() == KeePass2::KDF_ARGON2) { + if (IS_ARGON2(kdf->uuid())) { auto argon2Kdf = kdf.staticCast(); argon2Kdf->setMemory(static_cast(m_ui->memorySpinBox->value()) * (1 << 10)); argon2Kdf->setParallelism(static_cast(m_ui->parallelismSpinBox->value())); @@ -317,7 +316,7 @@ void DatabaseSettingsWidgetEncryption::benchmarkTransformRounds(int millisecs) // Create a new kdf with the current parameters auto kdf = KeePass2::uuidToKdf(QUuid(m_ui->kdfComboBox->currentData().toByteArray())); kdf->setRounds(m_ui->transformRoundsSpinBox->value()); - if (kdf->uuid() == KeePass2::KDF_ARGON2) { + if (IS_ARGON2(kdf->uuid())) { auto argon2Kdf = kdf.staticCast(); if (!argon2Kdf->setMemory(static_cast(m_ui->memorySpinBox->value()) * (1 << 10))) { m_ui->memorySpinBox->setValue(static_cast(argon2Kdf->memory() / (1 << 10))); @@ -402,7 +401,7 @@ void DatabaseSettingsWidgetEncryption::updateFormatCompatibility(int index, bool auto kdf = KeePass2::uuidToKdf(kdfUuid); m_db->setKdf(kdf); - if (kdf->uuid() == KeePass2::KDF_ARGON2) { + if (IS_ARGON2(kdf->uuid())) { auto argon2Kdf = kdf.staticCast(); // Default to 64 MiB of memory and 2 threads // these settings are safe for desktop and mobile devices diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 680243280..c4de82973 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -178,9 +178,6 @@ void EditEntryWidget::setupMain() m_mainUi->expirePresets->setMenu(createPresetsMenu()); connect(m_mainUi->expirePresets->menu(), SIGNAL(triggered(QAction*)), this, SLOT(useExpiryPreset(QAction*))); - - // HACK: Align username text with other line edits. Qt does not let you do this with an application stylesheet. - m_mainUi->usernameComboBox->lineEdit()->setStyleSheet("padding-left: 8px;"); } void EditEntryWidget::setupAdvanced() @@ -268,9 +265,8 @@ void EditEntryWidget::setupAutoType() #ifdef WITH_XC_BROWSER void EditEntryWidget::setupBrowser() { - m_browserUi->setupUi(m_browserWidget); - if (config()->get(Config::Browser_Enabled).toBool()) { + m_browserUi->setupUi(m_browserWidget); addPage(tr("Browser Integration"), Resources::instance()->icon("internet-web-browser"), m_browserWidget); m_additionalURLsDataModel->setEntryAttributes(m_entryAttributes); m_browserUi->additionalURLsView->setModel(m_additionalURLsDataModel); @@ -935,35 +931,44 @@ void EditEntryWidget::setForms(Entry* entry, bool restore) #endif #ifdef WITH_XC_BROWSER - if (m_customData->contains(BrowserService::OPTION_SKIP_AUTO_SUBMIT)) { - // clang-format off - m_browserUi->skipAutoSubmitCheckbox->setChecked(m_customData->value(BrowserService::OPTION_SKIP_AUTO_SUBMIT) == TRUE_STR); - // clang-format on - } else { - m_browserUi->skipAutoSubmitCheckbox->setChecked(false); + if (config()->get(Config::Browser_Enabled).toBool()) { + if (!hasPage(m_browserWidget)) { + setupBrowser(); + } + + if (m_customData->contains(BrowserService::OPTION_SKIP_AUTO_SUBMIT)) { + // clang-format off + m_browserUi->skipAutoSubmitCheckbox->setChecked(m_customData->value(BrowserService::OPTION_SKIP_AUTO_SUBMIT) == TRUE_STR); + // clang-format on + } else { + m_browserUi->skipAutoSubmitCheckbox->setChecked(false); + } + + if (m_customData->contains(BrowserService::OPTION_HIDE_ENTRY)) { + m_browserUi->hideEntryCheckbox->setChecked(m_customData->value(BrowserService::OPTION_HIDE_ENTRY) + == TRUE_STR); + } else { + m_browserUi->hideEntryCheckbox->setChecked(false); + } + + if (m_customData->contains(BrowserService::OPTION_ONLY_HTTP_AUTH)) { + m_browserUi->onlyHttpAuthCheckbox->setChecked(m_customData->value(BrowserService::OPTION_ONLY_HTTP_AUTH) + == TRUE_STR); + } else { + m_browserUi->onlyHttpAuthCheckbox->setChecked(false); + } + + m_browserUi->addURLButton->setEnabled(!m_history); + m_browserUi->removeURLButton->setEnabled(false); + m_browserUi->editURLButton->setEnabled(false); + m_browserUi->additionalURLsView->setEditTriggers(editTriggers); + + if (m_additionalURLsDataModel->rowCount() != 0) { + m_browserUi->additionalURLsView->setCurrentIndex(m_additionalURLsDataModel->index(0, 0)); + } } - if (m_customData->contains(BrowserService::OPTION_HIDE_ENTRY)) { - m_browserUi->hideEntryCheckbox->setChecked(m_customData->value(BrowserService::OPTION_HIDE_ENTRY) == TRUE_STR); - } else { - m_browserUi->hideEntryCheckbox->setChecked(false); - } - - if (m_customData->contains(BrowserService::OPTION_ONLY_HTTP_AUTH)) { - m_browserUi->onlyHttpAuthCheckbox->setChecked(m_customData->value(BrowserService::OPTION_ONLY_HTTP_AUTH) - == TRUE_STR); - } else { - m_browserUi->onlyHttpAuthCheckbox->setChecked(false); - } - - m_browserUi->addURLButton->setEnabled(!m_history); - m_browserUi->removeURLButton->setEnabled(false); - m_browserUi->editURLButton->setEnabled(false); - m_browserUi->additionalURLsView->setEditTriggers(editTriggers); - - if (m_additionalURLsDataModel->rowCount() != 0) { - m_browserUi->additionalURLsView->setCurrentIndex(m_additionalURLsDataModel->index(0, 0)); - } + setPageHidden(m_browserWidget, !config()->get(Config::Browser_Enabled).toBool()); #endif m_editWidgetProperties->setFields(entry->timeInfo(), entry->uuid()); @@ -997,6 +1002,15 @@ bool EditEntryWidget::commitEntry() return true; } + // HACK: Check that entry pointer is still valid, see https://github.com/keepassxreboot/keepassxc/issues/5722 + if (!m_entry) { + QMessageBox::information(this, + tr("Invalid Entry"), + tr("An external merge operation has invalidated this entry.\n" + "Unfortunately, any changes made have been lost.")); + return true; + } + // Check Auto-Type validity early if (!AutoType::verifyAutoTypeSyntax(m_autoTypeUi->sequenceEdit->text())) { return false; diff --git a/src/gui/group/GroupModel.cpp b/src/gui/group/GroupModel.cpp index e61410334..5feb8d6fe 100644 --- a/src/gui/group/GroupModel.cpp +++ b/src/gui/group/GroupModel.cpp @@ -262,13 +262,13 @@ bool GroupModel::dropMimeData(const QMimeData* data, targetDb->metadata()->copyCustomIcons(customIcons, sourceDb->metadata()); // Always clone the group across db's to reset UUIDs - group = dragGroup->clone(); + group = dragGroup->clone(Entry::CloneDefault | Entry::CloneIncludeHistory); if (action == Qt::MoveAction) { // Remove the original group from the sourceDb delete dragGroup; } } else if (action == Qt::CopyAction) { - group = dragGroup->clone(); + group = dragGroup->clone(Entry::CloneCopy); } group->setParent(parentGroup, row); @@ -303,13 +303,13 @@ bool GroupModel::dropMimeData(const QMimeData* data, targetDb->metadata()->addCustomIcon(customIcon, sourceDb->metadata()->customIcon(customIcon)); } - // Always clone the entry across db's to reset the UUID - entry = dragEntry->clone(); + // Reset the UUID when moving across db boundary + entry = dragEntry->clone(Entry::CloneDefault | Entry::CloneIncludeHistory); if (action == Qt::MoveAction) { delete dragEntry; } } else if (action == Qt::CopyAction) { - entry = dragEntry->clone(); + entry = dragEntry->clone(Entry::CloneCopy); } entry->setGroup(parentGroup); diff --git a/src/gui/osutils/nixutils/NixUtils.cpp b/src/gui/osutils/nixutils/NixUtils.cpp index b252458e5..769166fe0 100644 --- a/src/gui/osutils/nixutils/NixUtils.cpp +++ b/src/gui/osutils/nixutils/NixUtils.cpp @@ -104,10 +104,12 @@ void NixUtils::setLaunchAtStartup(bool enable) << QStringLiteral("StartupNotify=true") << '\n' << QStringLiteral("Terminal=false") << '\n' << QStringLiteral("Type=Application") << '\n' - << QStringLiteral("Version=1.0") << "true" << '\n' + << QStringLiteral("Version=1.0") << '\n' << QStringLiteral("Categories=Utility;Security;Qt;") << '\n' << QStringLiteral("MimeType=application/x-keepass2;") << '\n' - << QStringLiteral("X-GNOME-Autostart-enabled=true") << endl; + << QStringLiteral("X-GNOME-Autostart-enabled=true") << '\n' + << QStringLiteral("X-GNOME-Autostart-Delay=2") << '\n' + << QStringLiteral("X-KDE-autostart-after=panel") << endl; desktopFile.close(); } else if (isLaunchAtStartupEnabled()) { QFile::remove(getAutostartDesktopFilename()); diff --git a/src/gui/reports/ReportsWidgetStatistics.cpp b/src/gui/reports/ReportsWidgetStatistics.cpp index 400d82f29..976124a42 100644 --- a/src/gui/reports/ReportsWidgetStatistics.cpp +++ b/src/gui/reports/ReportsWidgetStatistics.cpp @@ -58,7 +58,8 @@ namespace // Get average password length int averagePwdLength() const { - return m_passwords.empty() ? 0 : pwdTotalLen / m_passwords.size(); + const auto nPwds = nPwdsUnique + nPwdsReused; + return nPwds == 0 ? 0 : std::round(pwdTotalLen / double(nPwds)); } // Get max number of password reuse (=how many entries diff --git a/src/gui/styles/base/BaseStyle.cpp b/src/gui/styles/base/BaseStyle.cpp index 104e1d4d9..98ce08f4d 100644 --- a/src/gui/styles/base/BaseStyle.cpp +++ b/src/gui/styles/base/BaseStyle.cpp @@ -4775,7 +4775,11 @@ QRect BaseStyle::subElementRect(SubElement sr, const QStyleOption* opt, const QW } case SE_LineEditContents: { QRect r = QCommonStyle::subElementRect(sr, opt, w); - int pad = Phantom::dpiScaled(Phantom::LineEdit_ContentsHPad); + int pad = Phantom::LineEdit_ContentsHPad; + if (w && qobject_cast(w->parentWidget())) { + pad += 3; + } + pad = Phantom::dpiScaled(pad); return r.adjusted(pad, 0, -pad, 0); } default: diff --git a/src/gui/styles/base/classicstyle.qss b/src/gui/styles/base/classicstyle.qss index 653edd5bb..2d856a3cf 100644 --- a/src/gui/styles/base/classicstyle.qss +++ b/src/gui/styles/base/classicstyle.qss @@ -13,3 +13,7 @@ DatabaseWidget #SearchBanner, DatabaseWidget #KeeShareBanner { border: 1px solid rgb(190, 190, 190); padding: 2px; } + +QLineEdit { + padding-left: 2px; +} diff --git a/src/keeshare/ShareObserver.cpp b/src/keeshare/ShareObserver.cpp index 6fd629b4c..f74e800a0 100644 --- a/src/keeshare/ShareObserver.cpp +++ b/src/keeshare/ShareObserver.cpp @@ -186,23 +186,29 @@ void ShareObserver::handleDatabaseChanged() void ShareObserver::handleFileUpdated(const QString& path) { - const Result result = importShare(path); - if (!result.isValid()) { - return; + if (!m_inFileUpdate) { + QTimer::singleShot(100, this, [this, path] { + const Result result = importShare(path); + m_inFileUpdate = false; + if (!result.isValid()) { + return; + } + QStringList success; + QStringList warning; + QStringList error; + if (result.isError()) { + error << tr("Import from %1 failed (%2)").arg(result.path, result.message); + } else if (result.isWarning()) { + warning << tr("Import from %1 failed (%2)").arg(result.path, result.message); + } else if (result.isInfo()) { + success << tr("Import from %1 successful (%2)").arg(result.path, result.message); + } else { + success << tr("Imported from %1").arg(result.path); + } + notifyAbout(success, warning, error); + }); + m_inFileUpdate = true; } - QStringList success; - QStringList warning; - QStringList error; - if (result.isError()) { - error << tr("Import from %1 failed (%2)").arg(result.path, result.message); - } else if (result.isWarning()) { - warning << tr("Import from %1 failed (%2)").arg(result.path, result.message); - } else if (result.isInfo()) { - success << tr("Import from %1 successful (%2)").arg(result.path, result.message); - } else { - success << tr("Imported from %1").arg(result.path); - } - notifyAbout(success, warning, error); } ShareObserver::Result ShareObserver::importShare(const QString& path) diff --git a/src/keeshare/ShareObserver.h b/src/keeshare/ShareObserver.h index b98d58981..8b881142d 100644 --- a/src/keeshare/ShareObserver.h +++ b/src/keeshare/ShareObserver.h @@ -83,6 +83,7 @@ private: QMap, KeeShareSettings::Reference> m_groupToReference; QMap> m_shareToGroup; QMap> m_fileWatchers; + bool m_inFileUpdate = false; }; #endif // KEEPASSXC_SHAREOBSERVER_H diff --git a/src/keys/FileKey.cpp b/src/keys/FileKey.cpp index 6142d58d7..2ac52ae69 100644 --- a/src/keys/FileKey.cpp +++ b/src/keys/FileKey.cpp @@ -64,9 +64,10 @@ FileKey::~FileKey() * removed in a future version. * * @param device input device + * @param errorMsg error message in case of fatal failure * @return true if key file was loaded successfully */ -bool FileKey::load(QIODevice* device) +bool FileKey::load(QIODevice* device, QString* errorMsg) { m_type = None; @@ -75,32 +76,33 @@ bool FileKey::load(QIODevice* device) return false; } - if (device->size() == 0) { + if (device->size() == 0 || !device->reset()) { return false; } - // try different legacy key file formats - if (!device->reset()) { - return false; - } - if (loadXml(device)) { - m_type = KeePass2XML; + // load XML key file v1 or v2 + QString xmlError; + if (loadXml(device, &xmlError)) { return true; } - if (!device->reset()) { + if (!device->reset() || !xmlError.isEmpty()) { + if (errorMsg) { + *errorMsg = xmlError; + } return false; } + + // try legacy key file formats if (loadBinary(device)) { - m_type = FixedBinary; return true; } if (!device->reset()) { return false; } + if (loadHex(device)) { - m_type = FixedBinaryHex; return true; } @@ -109,7 +111,6 @@ bool FileKey::load(QIODevice* device) return false; } if (loadHashed(device)) { - m_type = Hashed; return true; } @@ -145,10 +146,14 @@ bool FileKey::load(const QString& fileName, QString* errorMsg) } return false; } - bool result = load(&file); + bool result = load(&file, errorMsg); file.close(); + if (errorMsg && !errorMsg->isEmpty()) { + return false; + } + if (file.error()) { result = false; if (errorMsg) { @@ -171,16 +176,64 @@ QByteArray FileKey::rawKey() const } /** - * Generate a new key file from random bytes. + * Generate a new key file with random bytes. * * @param device output device * @param number of random bytes to generate */ -void FileKey::create(QIODevice* device, int size) +void FileKey::createRandom(QIODevice* device, int size) { device->write(randomGen()->randomArray(size)); } +/** + * Generate a new key file in the KeePass2 XML format v2. + * + * @param device output device + * @param number of random bytes to generate + */ +void FileKey::createXMLv2(QIODevice* device, int size) +{ + QXmlStreamWriter w(device); + w.setAutoFormatting(true); + w.setAutoFormattingIndent(4); + w.writeStartDocument(); + + w.writeStartElement("KeyFile"); + + w.writeStartElement("Meta"); + w.writeTextElement("Version", "2.0"); + w.writeEndElement(); + + w.writeStartElement("Key"); + w.writeStartElement("Data"); + + QByteArray key = randomGen()->randomArray(size); + CryptoHash hash(CryptoHash::Sha256); + hash.addData(key); + QByteArray result = hash.result().left(4); + key = key.toHex().toUpper(); + + w.writeAttribute("Hash", result.toHex().toUpper()); + w.writeCharacters("\n "); + for (int i = 0; i < key.size(); ++i) { + // Pretty-print hex value (not strictly necessary, but nicer to read and KeePass2 does it) + if (i != 0 && i % 32 == 0) { + w.writeCharacters("\n "); + } else if (i != 0 && i % 8 == 0) { + w.writeCharacters(" "); + } + w.writeCharacters(QChar(key[i])); + } + sodium_memzero(key.data(), static_cast(key.capacity())); + w.writeCharacters("\n "); + + w.writeEndElement(); + w.writeEndElement(); + + w.writeEndDocument(); +} + /** * Create a new key file from random bytes. * @@ -189,7 +242,7 @@ void FileKey::create(QIODevice* device, int size) * @param number of random bytes to generate * @return true on successful creation */ -bool FileKey::create(const QString& fileName, QString* errorMsg, int size) +bool FileKey::create(const QString& fileName, QString* errorMsg) { QFile file(fileName); if (!file.open(QFile::WriteOnly)) { @@ -198,7 +251,11 @@ bool FileKey::create(const QString& fileName, QString* errorMsg, int size) } return false; } - create(&file, size); + if (fileName.endsWith(".keyx")) { + createXMLv2(&file); + } else { + createRandom(&file); + } file.close(); file.setPermissions(QFile::ReadUser); @@ -218,87 +275,86 @@ bool FileKey::create(const QString& fileName, QString* errorMsg, int size) * * @param device input device * @return true on success - * @deprecated */ -bool FileKey::loadXml(QIODevice* device) +bool FileKey::loadXml(QIODevice* device, QString* errorMsg) { QXmlStreamReader xmlReader(device); - if (!xmlReader.error() && xmlReader.readNextStartElement()) { - if (xmlReader.name() != "KeyFile") { - return false; - } - } else { + if (xmlReader.error()) { + return false; + } + if (xmlReader.readNextStartElement() && xmlReader.name() != "KeyFile") { return false; } - bool correctMeta = false; - QByteArray data; + struct + { + QString version; + QByteArray hash; + QByteArray data; + } keyFileData; while (!xmlReader.error() && xmlReader.readNextStartElement()) { if (xmlReader.name() == "Meta") { - correctMeta = loadXmlMeta(xmlReader); + while (!xmlReader.error() && xmlReader.readNextStartElement()) { + if (xmlReader.name() == "Version") { + keyFileData.version = xmlReader.readElementText(); + if (keyFileData.version.startsWith("1.0")) { + m_type = KeePass2XML; + } else if (keyFileData.version == "2.0") { + m_type = KeePass2XMLv2; + } else { + if (errorMsg) { + *errorMsg = QObject::tr("Unsupported key file version: %1").arg(keyFileData.version); + } + return false; + } + } + } } else if (xmlReader.name() == "Key") { - data = loadXmlKey(xmlReader); + while (!xmlReader.error() && xmlReader.readNextStartElement()) { + if (xmlReader.name() == "Data") { + keyFileData.hash = QByteArray::fromHex(xmlReader.attributes().value("Hash").toLatin1()); + QByteArray rawData = xmlReader.readElementText().simplified().replace(" ", "").toLatin1(); + + if (keyFileData.version.startsWith("1.0") && Tools::isBase64(rawData)) { + keyFileData.data = QByteArray::fromBase64(rawData); + } else if (keyFileData.version == "2.0" && Tools::isHex(rawData)) { + keyFileData.data = QByteArray::fromHex(rawData); + + CryptoHash hash(CryptoHash::Sha256); + hash.addData(keyFileData.data); + QByteArray result = hash.result().left(4); + if (keyFileData.hash != result) { + if (errorMsg) { + *errorMsg = QObject::tr("Checksum mismatch! Key file may be corrupt."); + } + return false; + } + } else { + if (errorMsg) { + *errorMsg = QObject::tr("Unexpected key file data! Key file may be corrupt."); + } + return false; + } + + sodium_memzero(rawData.data(), static_cast(rawData.capacity())); + } + } } } bool ok = false; - if (!xmlReader.error() && correctMeta && !data.isEmpty()) { - std::memcpy(m_key, data.data(), std::min(SHA256_SIZE, data.size())); + if (!xmlReader.error() && !keyFileData.data.isEmpty()) { + std::memcpy(m_key, keyFileData.data.data(), std::min(SHA256_SIZE, keyFileData.data.size())); ok = true; } - sodium_memzero(data.data(), static_cast(data.capacity())); + sodium_memzero(keyFileData.data.data(), static_cast(keyFileData.data.capacity())); return ok; } -/** - * Load meta data from legacy KeePass 2 XML key file. - * - * @param xmlReader input XML reader - * @return true on success - * @deprecated - */ -bool FileKey::loadXmlMeta(QXmlStreamReader& xmlReader) -{ - bool correctVersion = false; - - while (!xmlReader.error() && xmlReader.readNextStartElement()) { - if (xmlReader.name() == "Version") { - if (xmlReader.readElementText() == "1.00") { - correctVersion = true; - } - } - } - - return correctVersion; -} - -/** - * Load base64 key data from legacy KeePass 2 XML key file. - * - * @param xmlReader input XML reader - * @return true on success - * @deprecated - */ -QByteArray FileKey::loadXmlKey(QXmlStreamReader& xmlReader) -{ - QByteArray data; - - while (!xmlReader.error() && xmlReader.readNextStartElement()) { - if (xmlReader.name() == "Data") { - QByteArray rawData = xmlReader.readElementText().toLatin1(); - if (Tools::isBase64(rawData)) { - data = QByteArray::fromBase64(rawData); - } - } - } - - return data; -} - /** * Load fixed 32-bit binary key file. * @@ -315,11 +371,12 @@ bool FileKey::loadBinary(QIODevice* device) QByteArray data; if (!Tools::readAllFromDevice(device, data) || data.size() != 32) { return false; - } else { - std::memcpy(m_key, data.data(), std::min(SHA256_SIZE, data.size())); - sodium_memzero(data.data(), static_cast(data.capacity())); - return true; } + + std::memcpy(m_key, data.data(), std::min(SHA256_SIZE, data.size())); + sodium_memzero(data.data(), static_cast(data.capacity())); + m_type = FixedBinary; + return true; } /** @@ -354,6 +411,7 @@ bool FileKey::loadHex(QIODevice* device) std::memcpy(m_key, key.data(), std::min(SHA256_SIZE, key.size())); sodium_memzero(key.data(), static_cast(key.capacity())); + m_type = FixedBinaryHex; return true; } @@ -379,6 +437,7 @@ bool FileKey::loadHashed(QIODevice* device) std::memcpy(m_key, result.data(), std::min(SHA256_SIZE, result.size())); sodium_memzero(result.data(), static_cast(result.capacity())); + m_type = Hashed; return true; } diff --git a/src/keys/FileKey.h b/src/keys/FileKey.h index 290a04af0..540dde7d2 100644 --- a/src/keys/FileKey.h +++ b/src/keys/FileKey.h @@ -35,25 +35,25 @@ public: None, Hashed, KeePass2XML, + KeePass2XMLv2, FixedBinary, FixedBinaryHex }; FileKey(); ~FileKey() override; - bool load(QIODevice* device); + bool load(QIODevice* device, QString* errorMsg = nullptr); bool load(const QString& fileName, QString* errorMsg = nullptr); QByteArray rawKey() const override; Type type() const; - static void create(QIODevice* device, int size = 128); - static bool create(const QString& fileName, QString* errorMsg = nullptr, int size = 128); + static void createRandom(QIODevice* device, int size = 128); + static void createXMLv2(QIODevice* device, int size = 32); + static bool create(const QString& fileName, QString* errorMsg = nullptr); private: static constexpr int SHA256_SIZE = 32; - bool loadXml(QIODevice* device); - bool loadXmlMeta(QXmlStreamReader& xmlReader); - QByteArray loadXmlKey(QXmlStreamReader& xmlReader); + bool loadXml(QIODevice* device, QString* errorMsg = nullptr); bool loadBinary(QIODevice* device); bool loadHex(QIODevice* device); bool loadHashed(QIODevice* device); diff --git a/tests/TestCli.cpp b/tests/TestCli.cpp index 348afb670..80af58bad 100644 --- a/tests/TestCli.cpp +++ b/tests/TestCli.cpp @@ -928,10 +928,10 @@ void TestCli::testExport() setInput("a"); execCmd(exportCmd, {"export", "-f", "csv", m_dbFile->fileName()}); QByteArray csvHeader = m_stdout->readLine(); - QCOMPARE(csvHeader, QByteArray("\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\"\n")); + QVERIFY(csvHeader.contains(QByteArray("\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\""))); QByteArray csvData = m_stdout->readAll(); QVERIFY(csvData.contains(QByteArray( - "\"NewDatabase\",\"Sample Entry\",\"User Name\",\"Password\",\"http://www.somesite.com/\",\"Notes\"\n"))); + "\"NewDatabase\",\"Sample Entry\",\"User Name\",\"Password\",\"http://www.somesite.com/\",\"Notes\""))); // test invalid format setInput("a"); diff --git a/tests/TestCsvExporter.cpp b/tests/TestCsvExporter.cpp index 63ba11488..8e7e6021d 100644 --- a/tests/TestCsvExporter.cpp +++ b/tests/TestCsvExporter.cpp @@ -23,11 +23,13 @@ #include "crypto/Crypto.h" #include "format/CsvExporter.h" +#include "totp/totp.h" QTEST_GUILESS_MAIN(TestCsvExporter) const QString TestCsvExporter::ExpectedHeaderLine = - QString("\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\"\n"); + QString("\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\",\"TOTP\",\"Icon\",\"Last " + "Modified\",\"Created\"\n"); void TestCsvExporter::init() { @@ -57,17 +59,23 @@ void TestCsvExporter::testExport() entry->setPassword("Test Password"); entry->setUrl("http://test.url"); entry->setNotes("Test Notes"); + entry->setTotp(Totp::createSettings("DFDF", Totp::DEFAULT_DIGITS, Totp::DEFAULT_STEP)); + entry->setIcon(5); QBuffer buffer; QVERIFY(buffer.open(QIODevice::ReadWrite)); m_csvExporter->exportDatabase(&buffer, m_db); + auto exported = QString::fromUtf8(buffer.buffer()); QString expectedResult = QString() .append(ExpectedHeaderLine) .append("\"Passwords/Test Group Name\",\"Test Entry Title\",\"Test Username\",\"Test " - "Password\",\"http://test.url\",\"Test Notes\"\n"); + "Password\",\"http://test.url\",\"Test Notes\""); - QCOMPARE(QString::fromUtf8(buffer.buffer().constData()), expectedResult); + QVERIFY(exported.startsWith(expectedResult)); + exported.remove(expectedResult); + QVERIFY(exported.contains("otpauth://")); + QVERIFY(exported.contains(",\"5\",")); } void TestCsvExporter::testEmptyDatabase() @@ -95,10 +103,9 @@ void TestCsvExporter::testNestedGroups() QBuffer buffer; QVERIFY(buffer.open(QIODevice::ReadWrite)); m_csvExporter->exportDatabase(&buffer, m_db); - - QCOMPARE( - QString::fromUtf8(buffer.buffer().constData()), + auto exported = QString::fromUtf8(buffer.buffer()); + QVERIFY(exported.startsWith( QString() .append(ExpectedHeaderLine) - .append("\"Passwords/Test Group Name/Test Sub Group Name\",\"Test Entry Title\",\"\",\"\",\"\",\"\"\n")); + .append("\"Passwords/Test Group Name/Test Sub Group Name\",\"Test Entry Title\",\"\",\"\",\"\",\"\""))); } diff --git a/tests/TestKdbx4.cpp b/tests/TestKdbx4.cpp index 51784f062..46eaacc84 100644 --- a/tests/TestKdbx4.cpp +++ b/tests/TestKdbx4.cpp @@ -42,8 +42,8 @@ int main(int argc, char* argv[]) void TestKdbx4Argon2::initTestCaseImpl() { - m_xmlDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2))); - m_kdbxSourceDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2))); + m_xmlDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D))); + m_kdbxSourceDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D))); } QSharedPointer @@ -108,7 +108,7 @@ void TestKdbx4Argon2::readKdbx(const QString& path, void TestKdbx4Argon2::writeKdbx(QIODevice* device, Database* db, bool& hasError, QString& errorString) { if (db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3) { - db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2))); + db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D))); } KeePass2Writer writer; hasError = writer.writeDatabase(device, db); @@ -213,26 +213,32 @@ void TestKdbx4Argon2::testFormat400Upgrade_data() auto constexpr kdbx3 = KeePass2::FILE_VERSION_3_1 & KeePass2::FILE_VERSION_CRITICAL_MASK; auto constexpr kdbx4 = KeePass2::FILE_VERSION_4 & KeePass2::FILE_VERSION_CRITICAL_MASK; - QTest::newRow("Argon2 + AES") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_AES256 << false << kdbx4; - QTest::newRow("AES-KDF + AES") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << false << kdbx4; - QTest::newRow("AES-KDF (legacy) + AES") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << false << kdbx3; - QTest::newRow("Argon2 + AES + CustomData") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_AES256 << true << kdbx4; - QTest::newRow("AES-KDF + AES + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << true << kdbx4; - QTest::newRow("AES-KDF (legacy) + AES + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << true << kdbx4; + QTest::newRow("Argon2d + AES") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_AES256 << false << kdbx4; + QTest::newRow("Argon2id + AES") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_AES256 << false << kdbx4; + QTest::newRow("AES-KDF + AES") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << false << kdbx4; + QTest::newRow("AES-KDF (legacy) + AES") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << false << kdbx3; + QTest::newRow("Argon2d + AES + CustomData") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_AES256 << true << kdbx4; + QTest::newRow("Argon2id + AES + CustomData") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_AES256 << true << kdbx4; + QTest::newRow("AES-KDF + AES + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << true << kdbx4; + QTest::newRow("AES-KDF (legacy) + AES + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << true << kdbx4; - QTest::newRow("Argon2 + ChaCha20") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_CHACHA20 << false << kdbx4; - QTest::newRow("AES-KDF + ChaCha20") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_CHACHA20 << false << kdbx4; - QTest::newRow("AES-KDF (legacy) + ChaCha20") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_CHACHA20 << false << kdbx3; - QTest::newRow("Argon2 + ChaCha20 + CustomData") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_CHACHA20 << true << kdbx4; - QTest::newRow("AES-KDF + ChaCha20 + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_CHACHA20 << true << kdbx4; - QTest::newRow("AES-KDF (legacy) + ChaCha20 + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_CHACHA20 << true << kdbx4; + QTest::newRow("Argon2d + ChaCha20") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_CHACHA20 << false << kdbx4; + QTest::newRow("Argon2id + ChaCha20") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_CHACHA20 << false << kdbx4; + QTest::newRow("AES-KDF + ChaCha20") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_CHACHA20 << false << kdbx4; + QTest::newRow("AES-KDF (legacy) + ChaCha20") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_CHACHA20 << false << kdbx3; + QTest::newRow("Argon2d + ChaCha20 + CustomData") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_CHACHA20 << true << kdbx4; + QTest::newRow("Argon2id + ChaCha20 + CustomData") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_CHACHA20 << true << kdbx4; + QTest::newRow("AES-KDF + ChaCha20 + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_CHACHA20 << true << kdbx4; + QTest::newRow("AES-KDF (legacy) + ChaCha20 + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_CHACHA20 << true << kdbx4; - QTest::newRow("Argon2 + Twofish") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_TWOFISH << false << kdbx4; - QTest::newRow("AES-KDF + Twofish") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_TWOFISH << false << kdbx4; - QTest::newRow("AES-KDF (legacy) + Twofish") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_TWOFISH << false << kdbx3; - QTest::newRow("Argon2 + Twofish + CustomData") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_TWOFISH << true << kdbx4; - QTest::newRow("AES-KDF + Twofish + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_TWOFISH << true << kdbx4; - QTest::newRow("AES-KDF (legacy) + Twofish + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_TWOFISH << true << kdbx4; + QTest::newRow("Argon2d + Twofish") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_TWOFISH << false << kdbx4; + QTest::newRow("Argon2id + Twofish") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_TWOFISH << false << kdbx4; + QTest::newRow("AES-KDF + Twofish") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_TWOFISH << false << kdbx4; + QTest::newRow("AES-KDF (legacy) + Twofish") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_TWOFISH << false << kdbx3; + QTest::newRow("Argon2d + Twofish + CustomData") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_TWOFISH << true << kdbx4; + QTest::newRow("Argon2id + Twofish + CustomData") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_TWOFISH << true << kdbx4; + QTest::newRow("AES-KDF + Twofish + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_TWOFISH << true << kdbx4; + QTest::newRow("AES-KDF (legacy) + Twofish + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_TWOFISH << true << kdbx4; } // clang-format on @@ -270,7 +276,7 @@ void TestKdbx4Argon2::testUpgradeMasterKeyIntegrity() } else if (upgradeAction == "kdf-aes-kdbx3") { db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_AES_KDBX3))); } else if (upgradeAction == "kdf-argon2") { - db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2))); + db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D))); } else if (upgradeAction == "kdf-aes-kdbx4") { db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_AES_KDBX4))); } else if (upgradeAction == "public-customdata") { diff --git a/tests/TestKeePass2Format.cpp b/tests/TestKeePass2Format.cpp index b0217c942..2aa3948ae 100644 --- a/tests/TestKeePass2Format.cpp +++ b/tests/TestKeePass2Format.cpp @@ -809,7 +809,7 @@ QSharedPointer TestKeePass2Format::fastKdf(QSharedPointer kdf) const { kdf->setRounds(1); - if (kdf->uuid() == KeePass2::KDF_ARGON2) { + if (kdf->uuid() == KeePass2::KDF_ARGON2D) { kdf->processParameters({{KeePass2::KDFPARAM_ARGON2_MEMORY, 1024}, {KeePass2::KDFPARAM_ARGON2_PARALLELISM, 1}}); } diff --git a/tests/TestKeys.cpp b/tests/TestKeys.cpp index d25a2bca8..cbbaae398 100644 --- a/tests/TestKeys.cpp +++ b/tests/TestKeys.cpp @@ -69,22 +69,36 @@ void TestKeys::testComposite() void TestKeys::testFileKey() { QFETCH(FileKey::Type, type); - QFETCH(QString, typeString); + QFETCH(QString, keyExt); + QFETCH(bool, fileKeyOk); - QString name = QString("FileKey").append(typeString); + QString name = QString("FileKey").append(QTest::currentDataTag()); KeePass2Reader reader; QString dbFilename = QString("%1/%2.kdbx").arg(QString(KEEPASSX_TEST_DATA_DIR), name); - QString keyFilename = QString("%1/%2.key").arg(QString(KEEPASSX_TEST_DATA_DIR), name); + QString keyFilename = QString("%1/%2.%3").arg(QString(KEEPASSX_TEST_DATA_DIR), name, keyExt); auto compositeKey = QSharedPointer::create(); auto fileKey = QSharedPointer::create(); - QVERIFY(fileKey->load(keyFilename)); - QCOMPARE(fileKey->rawKey().size(), 32); - + QString error; + QVERIFY(fileKey->load(keyFilename, &error) == fileKeyOk); + QVERIFY(error.isEmpty() == fileKeyOk); QCOMPARE(fileKey->type(), type); + // Test for same behaviour on code path without error parameter + auto fileKeyNoErrorParam = QSharedPointer::create(); + QVERIFY(fileKeyNoErrorParam->load(keyFilename) == fileKeyOk); + QCOMPARE(fileKeyNoErrorParam->type(), type); + + QCOMPARE(fileKey->rawKey(), fileKeyNoErrorParam->rawKey()); + + if (!fileKeyOk) { + return; + } + + QCOMPARE(fileKey->rawKey().size(), 32); + compositeKey->addKey(fileKey); auto db = QSharedPointer::create(); @@ -97,12 +111,16 @@ void TestKeys::testFileKey() void TestKeys::testFileKey_data() { QTest::addColumn("type"); - QTest::addColumn("typeString"); - QTest::newRow("Xml") << FileKey::KeePass2XML << QString("Xml"); - QTest::newRow("XmlBrokenBase64") << FileKey::Hashed << QString("XmlBrokenBase64"); - QTest::newRow("Binary") << FileKey::FixedBinary << QString("Binary"); - QTest::newRow("Hex") << FileKey::FixedBinaryHex << QString("Hex"); - QTest::newRow("Hashed") << FileKey::Hashed << QString("Hashed"); + QTest::addColumn("keyExt"); + QTest::addColumn("fileKeyOk"); + QTest::newRow("Xml") << FileKey::KeePass2XML << QString("key") << true; + QTest::newRow("XmlBrokenBase64") << FileKey::KeePass2XML << QString("key") << false; + QTest::newRow("XmlV2") << FileKey::KeePass2XMLv2 << QString("keyx") << true; + QTest::newRow("XmlV2HashFail") << FileKey::KeePass2XMLv2 << QString("keyx") << false; + QTest::newRow("XmlV2BrokenHex") << FileKey::KeePass2XMLv2 << QString("keyx") << false; + QTest::newRow("Binary") << FileKey::FixedBinary << QString("key") << true; + QTest::newRow("Hex") << FileKey::FixedBinaryHex << QString("key") << true; + QTest::newRow("Hashed") << FileKey::Hashed << QString("key") << true; } // clang-format on @@ -111,12 +129,12 @@ void TestKeys::testCreateFileKey() QBuffer keyBuffer1; keyBuffer1.open(QBuffer::ReadWrite); - FileKey::create(&keyBuffer1, 128); + FileKey::createRandom(&keyBuffer1, 128); QCOMPARE(keyBuffer1.size(), 128); QBuffer keyBuffer2; keyBuffer2.open(QBuffer::ReadWrite); - FileKey::create(&keyBuffer2, 64); + FileKey::createRandom(&keyBuffer2, 64); QCOMPARE(keyBuffer2.size(), 64); } @@ -127,7 +145,7 @@ void TestKeys::testCreateAndOpenFileKey() QBuffer keyBuffer; keyBuffer.open(QBuffer::ReadWrite); - FileKey::create(&keyBuffer); + FileKey::createRandom(&keyBuffer); keyBuffer.reset(); auto fileKey = QSharedPointer::create(); @@ -166,7 +184,7 @@ void TestKeys::testFileKeyHash() QBuffer keyBuffer; keyBuffer.open(QBuffer::ReadWrite); - FileKey::create(&keyBuffer); + FileKey::createRandom(&keyBuffer); CryptoHash cryptoHash(CryptoHash::Sha256); cryptoHash.addData(keyBuffer.data()); diff --git a/tests/data/FileKeyXmlV2.kdbx b/tests/data/FileKeyXmlV2.kdbx new file mode 100644 index 000000000..4b13c2ec1 Binary files /dev/null and b/tests/data/FileKeyXmlV2.kdbx differ diff --git a/tests/data/FileKeyXmlV2.keyx b/tests/data/FileKeyXmlV2.keyx new file mode 100644 index 000000000..ef38d4a89 --- /dev/null +++ b/tests/data/FileKeyXmlV2.keyx @@ -0,0 +1,12 @@ + + + + 2.0 + + + + A7007945 D07D54BA 28DF6434 1B4500FC + 9750DFB1 D36ADA2D 9C32DC19 4C7AB01B + + + \ No newline at end of file diff --git a/tests/data/FileKeyXmlV2BrokenHex.kdbx b/tests/data/FileKeyXmlV2BrokenHex.kdbx new file mode 100644 index 000000000..5a7e7355e Binary files /dev/null and b/tests/data/FileKeyXmlV2BrokenHex.kdbx differ diff --git a/tests/data/FileKeyXmlV2BrokenHex.keyx b/tests/data/FileKeyXmlV2BrokenHex.keyx new file mode 100644 index 000000000..a52803832 --- /dev/null +++ b/tests/data/FileKeyXmlV2BrokenHex.keyx @@ -0,0 +1,12 @@ + + + + 2.0 + + + + X7007945 D07D54BA 28DF6434 1B4500FC + 9750DFB1 D36ADA2D 9C32DC19 4C7AB01B + + + \ No newline at end of file diff --git a/tests/data/FileKeyXmlV2HashFail.kdbx b/tests/data/FileKeyXmlV2HashFail.kdbx new file mode 100644 index 000000000..9044b1288 Binary files /dev/null and b/tests/data/FileKeyXmlV2HashFail.kdbx differ diff --git a/tests/data/FileKeyXmlV2HashFail.keyx b/tests/data/FileKeyXmlV2HashFail.keyx new file mode 100644 index 000000000..a52e96f18 --- /dev/null +++ b/tests/data/FileKeyXmlV2HashFail.keyx @@ -0,0 +1,12 @@ + + + + 2.0 + + + + A7007945 D07D54BA 28DF6434 1B4500FC + 9750DFB1 D36ADA2D 9C32DC19 4C7AB01B + + + \ No newline at end of file diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index c79de84bb..2463f13f6 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -29,14 +29,18 @@ #include #include #include +#include #include #include #include +#include #include #include +#include #include #include #include +#include #include "config-keepassx-tests.h" #include "core/Bootstrap.h" @@ -142,6 +146,9 @@ void TestGui::init() fileDialog()->setNextFileName(m_dbFilePath); triggerAction("actionDatabaseOpen"); + QApplication::processEvents(); + + m_dbWidget = m_tabWidget->currentDatabaseWidget(); auto* databaseOpenWidget = m_tabWidget->currentDatabaseWidget()->findChild("databaseOpenWidget"); QVERIFY(databaseOpenWidget); auto* editPassword = databaseOpenWidget->findChild("editPassword"); @@ -151,8 +158,10 @@ void TestGui::init() QTest::keyClicks(editPassword, "a"); QTest::keyClick(editPassword, Qt::Key_Enter); - m_dbWidget = m_tabWidget->currentDatabaseWidget(); + QTRY_VERIFY(!m_dbWidget->isLocked()); m_db = m_dbWidget->database(); + + QApplication::processEvents(); } // Every test ends with closing the temp database without saving @@ -302,7 +311,7 @@ void TestGui::testCreateDatabase() // check key and encryption QCOMPARE(m_db->key()->keys().size(), 2); QCOMPARE(m_db->kdf()->rounds(), 2); - QCOMPARE(m_db->kdf()->uuid(), KeePass2::KDF_ARGON2); + QCOMPARE(m_db->kdf()->uuid(), KeePass2::KDF_ARGON2D); QCOMPARE(m_db->cipher(), KeePass2::CIPHER_AES256); auto compositeKey = QSharedPointer::create(); compositeKey->addKey(QSharedPointer::create("test")); @@ -1146,24 +1155,45 @@ void TestGui::testEntryPlaceholders() void TestGui::testDragAndDropEntry() { - auto* entryView = m_dbWidget->findChild("entryView"); - auto* groupView = m_dbWidget->findChild("groupView"); - QAbstractItemModel* groupModel = groupView->model(); + auto entryView = m_dbWidget->findChild("entryView"); + auto groupView = m_dbWidget->findChild("groupView"); + auto groupModel = qobject_cast(groupView->model()); QModelIndex sourceIndex = entryView->model()->index(0, 1); QModelIndex targetIndex = groupModel->index(0, 0, groupModel->index(0, 0)); QVERIFY(sourceIndex.isValid()); QVERIFY(targetIndex.isValid()); + auto targetGroup = groupModel->groupFromIndex(targetIndex); QMimeData mimeData; QByteArray encoded; QDataStream stream(&encoded, QIODevice::WriteOnly); - Entry* entry = entryView->entryFromIndex(sourceIndex); + + auto entry = entryView->entryFromIndex(sourceIndex); stream << entry->group()->database()->uuid() << entry->uuid(); mimeData.setData("application/x-keepassx-entry", encoded); + // Test Copy, UUID should change, history remain + QVERIFY(groupModel->dropMimeData(&mimeData, Qt::CopyAction, -1, 0, targetIndex)); + // Find the copied entry + auto newEntry = targetGroup->findEntryByPath(entry->title()); + QVERIFY(newEntry); + QVERIFY(entry->uuid() != newEntry->uuid()); + QCOMPARE(entry->historyItems().count(), newEntry->historyItems().count()); + + encoded.clear(); + entry = entryView->entryFromIndex(sourceIndex); + auto history = entry->historyItems().count(); + auto uuid = entry->uuid(); + stream << entry->group()->database()->uuid() << entry->uuid(); + mimeData.setData("application/x-keepassx-entry", encoded); + + // Test Move, entry pointer should remain the same + QCOMPARE(entry->group()->name(), QString("NewDatabase")); QVERIFY(groupModel->dropMimeData(&mimeData, Qt::MoveAction, -1, 0, targetIndex)); QCOMPARE(entry->group()->name(), QString("General")); + QCOMPARE(entry->uuid(), uuid); + QCOMPARE(entry->historyItems().count(), history); } void TestGui::testDragAndDropGroup() @@ -1484,6 +1514,163 @@ void TestGui::testTrayRestoreHide() trayIcon->activated(QSystemTrayIcon::DoubleClick); QTRY_VERIFY(!m_mainWindow->isVisible()); + + // Ensure window is visible at the end + trayIcon->activated(QSystemTrayIcon::DoubleClick); + QTRY_VERIFY(m_mainWindow->isVisible()); +} + +void TestGui::testAutoType() +{ + // Clear entries from root group to guarantee order + for (Entry* entry : m_db->rootGroup()->entries()) { + m_db->rootGroup()->removeEntry(entry); + } + Tools::wait(150); + + // 1. Create an entry with Auto-Type disabled + + // 1.a) Click the new entry button and set the title + auto* entryNewAction = m_mainWindow->findChild("actionEntryNew"); + QVERIFY(entryNewAction->isEnabled()); + + auto* toolBar = m_mainWindow->findChild("toolBar"); + QVERIFY(toolBar); + + QWidget* entryNewWidget = toolBar->widgetForAction(entryNewAction); + QVERIFY(entryNewWidget->isVisible()); + QVERIFY(entryNewWidget->isEnabled()); + + QTest::mouseClick(entryNewWidget, Qt::LeftButton); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + + auto* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); + QVERIFY(editEntryWidget); + + auto* titleEdit = editEntryWidget->findChild("titleEdit"); + QVERIFY(titleEdit); + + QTest::keyClicks(titleEdit, "1. Entry With Disabled Auto-Type"); + + auto* usernameComboBox = editEntryWidget->findChild("usernameComboBox"); + QVERIFY(usernameComboBox); + + QTest::mouseClick(usernameComboBox, Qt::LeftButton); + QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); + + // 1.b) Uncheck Auto-Type checkbox + editEntryWidget->setCurrentPage(3); + auto* enableAutoTypeButton = editEntryWidget->findChild("enableButton"); + QVERIFY(enableAutoTypeButton); + QVERIFY(enableAutoTypeButton->isVisible()); + QVERIFY(enableAutoTypeButton->isEnabled()); + + enableAutoTypeButton->click(); + QVERIFY(!enableAutoTypeButton->isChecked()); + + // 1.c) Save changes + editEntryWidget->setCurrentPage(0); + auto* editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); + + // 2. Create an entry with default/inherited Auto-Type sequence + + // 2.a) Click the new entry button and set the title + QTest::mouseClick(entryNewWidget, Qt::LeftButton); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QTest::keyClicks(titleEdit, "2. Entry With Default Auto-Type Sequence"); + QTest::mouseClick(usernameComboBox, Qt::LeftButton); + QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); + + // 2.b) Confirm AutoType is enabled and default + editEntryWidget->setCurrentPage(3); + QVERIFY(enableAutoTypeButton->isChecked()); + auto* inheritSequenceButton = editEntryWidget->findChild("inheritSequenceButton"); + QVERIFY(inheritSequenceButton->isChecked()); + + // 2.c) Save changes + editEntryWidget->setCurrentPage(0); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); + + // 3. Create an entry with custom Auto-Type sequence + + // 3.a) Click the new entry button and set the title + QTest::mouseClick(entryNewWidget, Qt::LeftButton); + QCOMPARE(m_dbWidget->currentMode(), DatabaseWidget::Mode::EditMode); + QTest::keyClicks(titleEdit, "3. Entry With Custom Auto-Type Sequence"); + QTest::mouseClick(usernameComboBox, Qt::LeftButton); + QTest::keyClicks(usernameComboBox, "AutocompletionUsername"); + + // 3.b) Confirm AutoType is enabled and set custom sequence + editEntryWidget->setCurrentPage(3); + QVERIFY(enableAutoTypeButton->isChecked()); + auto* customSequenceButton = editEntryWidget->findChild("customSequenceButton"); + QTest::mouseClick(customSequenceButton, Qt::LeftButton); + QVERIFY(customSequenceButton->isChecked()); + QVERIFY(!inheritSequenceButton->isChecked()); + auto* sequenceEdit = editEntryWidget->findChild("sequenceEdit"); + QVERIFY(sequenceEdit); + sequenceEdit->setFocus(); + QTRY_VERIFY(sequenceEdit->hasFocus()); + QTest::keyClicks(sequenceEdit, "{USERNAME}{TAB}{TAB}{PASSWORD}{ENTER}"); + + // 3.c) Save changes + editEntryWidget->setCurrentPage(0); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); + QApplication::processEvents(); + + // Check total number of entries matches expected + auto* entryView = m_dbWidget->findChild("entryView"); + QVERIFY(entryView); + QTRY_COMPARE(entryView->model()->rowCount(), 3); + + // Sort entries by title + entryView->sortByColumn(1, Qt::AscendingOrder); + + // Select first entry + entryView->selectionModel()->clearSelection(); + QModelIndex entryIndex = entryView->model()->index(0, 0); + entryView->selectionModel()->select(entryIndex, QItemSelectionModel::Rows | QItemSelectionModel::Select); + + auto* entryPreviewWidget = m_dbWidget->findChild("previewWidget"); + QVERIFY(entryPreviewWidget->isVisible()); + + // Check that the Autotype tab in entry preview pane is disabled for entry with disabled Auto-Type + auto* entryAutotypeTab = entryPreviewWidget->findChild("entryAutotypeTab"); + QVERIFY(!entryAutotypeTab->isEnabled()); + + // Check that Auto-Type is disabled in the actual entry model as well + Entry* entry = entryView->entryFromIndex(entryIndex); + QVERIFY(!entry->autoTypeEnabled()); + + // Select second entry + entryView->selectionModel()->clearSelection(); + entryIndex = entryView->model()->index(1, 0); + entryView->selectionModel()->select(entryIndex, QItemSelectionModel::Rows | QItemSelectionModel::Select); + QVERIFY(entryPreviewWidget->isVisible()); + + // Check that the Autotype tab in entry preview pane is enabled for entry with default Auto-Type sequence; + QVERIFY(entryAutotypeTab->isEnabled()); + + // Check that Auto-Type is enabled in the actual entry model as well + entry = entryView->entryFromIndex(entryIndex); + QVERIFY(entry->autoTypeEnabled()); + + // Select third entry + entryView->selectionModel()->clearSelection(); + entryIndex = entryView->model()->index(2, 0); + entryView->selectionModel()->select(entryIndex, QItemSelectionModel::Rows | QItemSelectionModel::Select); + QVERIFY(entryPreviewWidget->isVisible()); + + // Check that the Autotype tab in entry preview pane is enabled for entry with custom Auto-Type sequence + QVERIFY(entryAutotypeTab->isEnabled()); + + // Check that Auto-Type is enabled in the actual entry model as well + entry = entryView->entryFromIndex(entryIndex); + QVERIFY(entry->autoTypeEnabled()); + + // De-select third entry + entryView->selectionModel()->clearSelection(); } int TestGui::addCannedEntries() diff --git a/tests/gui/TestGui.h b/tests/gui/TestGui.h index 8d82e021e..5bfc04265 100644 --- a/tests/gui/TestGui.h +++ b/tests/gui/TestGui.h @@ -68,6 +68,7 @@ private slots: void testDatabaseLocking(); void testDragAndDropKdbxFiles(); void testSortGroups(); + void testAutoType(); void testTrayRestoreHide(); private: