From 5edf42254d7421fe1105c6cc39e65347f6ccd02c Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 1 Apr 2025 15:10:04 +0200 Subject: [PATCH 01/13] this is an experiment to use GnuTlsStream (the ftpcredentials.xml have some hardcoded credentials for a public FTP server for testing). Unfortunately, the app restarts when loading the native libraries for GnuTLS. --- src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs | 2 ++ src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj | 1 + src/keepass2android-app/Resources/layout/ftpcredentials.xml | 6 +++--- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs b/src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs index 06a2b115..b6226829 100644 --- a/src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/NetFtpFileStorage.cs @@ -8,6 +8,7 @@ using Android.Content; using Android.OS; using FluentFTP; using FluentFTP.Exceptions; +using FluentFTP.GnuTLS; using KeePassLib; using KeePassLib.Serialization; using KeePassLib.Utility; @@ -139,6 +140,7 @@ namespace keepass2android.Io var settings = ConnectionSettings.FromIoc(ioc); FtpClient client = new FtpClient(); + client.Config.CustomStream = typeof(GnuTlsStream); client.Config.RetryAttempts = 3; if ((settings.Username.Length > 0) || (settings.Password.Length > 0)) client.Credentials = new NetworkCredential(settings.Username, settings.Password); diff --git a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj index e518e764..066e3729 100644 --- a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj +++ b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj @@ -10,6 +10,7 @@ + diff --git a/src/keepass2android-app/Resources/layout/ftpcredentials.xml b/src/keepass2android-app/Resources/layout/ftpcredentials.xml index 7a01e925..bc27b173 100644 --- a/src/keepass2android-app/Resources/layout/ftpcredentials.xml +++ b/src/keepass2android-app/Resources/layout/ftpcredentials.xml @@ -15,7 +15,7 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:singleLine="true" - android:text="" + android:text="ftp.dlptest.com" android:layout_weight="1" android:inputType="textWebEmailAddress" android:hint="@string/hint_sftp_host" /> @@ -46,7 +46,7 @@ android:layout_height="wrap_content" android:singleLine="true" android:inputType="textWebEmailAddress" - android:text="" + android:text="dlpuser" android:hint="@string/hint_username" /> From aec9441de4299475ae5849abd1239c16ed651175 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 8 Apr 2025 15:26:04 +0200 Subject: [PATCH 02/13] update FluentFTP --- src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj index 066e3729..af0e5d8b 100644 --- a/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj +++ b/src/Kp2aBusinessLogic/Kp2aBusinessLogic.csproj @@ -9,7 +9,7 @@ - + From ba7b02cd1ecd10033018ee4ef208b2b51a46e2f3 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 8 Apr 2025 15:46:38 +0200 Subject: [PATCH 03/13] remove testing credentials --- src/keepass2android-app/Resources/layout/ftpcredentials.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/keepass2android-app/Resources/layout/ftpcredentials.xml b/src/keepass2android-app/Resources/layout/ftpcredentials.xml index bc27b173..7a01e925 100644 --- a/src/keepass2android-app/Resources/layout/ftpcredentials.xml +++ b/src/keepass2android-app/Resources/layout/ftpcredentials.xml @@ -15,7 +15,7 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:singleLine="true" - android:text="ftp.dlptest.com" + android:text="" android:layout_weight="1" android:inputType="textWebEmailAddress" android:hint="@string/hint_sftp_host" /> @@ -46,7 +46,7 @@ android:layout_height="wrap_content" android:singleLine="true" android:inputType="textWebEmailAddress" - android:text="dlpuser" + android:text="" android:hint="@string/hint_username" /> From 48899ba9a0b15854c4ac7137fe65f62a5d214f43 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 9 Jul 2025 01:34:39 +0200 Subject: [PATCH 04/13] New translations strings.xml (Portuguese, Brazilian) --- .../Resources/values-pt-rBR/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml index 0f52392e..df8d1a72 100644 --- a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml +++ b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml @@ -93,6 +93,8 @@ Desabilitar o Desbloqueio Biométrico Habilitar o Desbloqueio de Biométrico completo Habilitar o Desbloqueio de Biométrico para o QuickUnlock + Desbloqueio rápido baseado em senha não disponível + O desbloqueio rápido usando uma parte da sua senha está bloqueado porque o bloqueio da tela não está ativado no seu dispositivo. Esse comportamento é para protegê -lo caso alguém o veja entrando na sua chave de desbloqueio rápido. Desbloqueio por impressão digital falhou: Chave para desencriptação foi invalidada pelo sistema Android. Isto costuma acontecer se for adicionada uma nova impressão digital ao sistema ou se os parâmetros de segurança forem alterados. Desbloqueio da base de dados falhado: Chave composta inválida. O desbloqueio por impressão digital foi desativado porque aparentemente a chave mestra arquivada não é válida. Por favor, reative o Desbloquear com Impressão Digital para a nova senha mestre. @@ -321,6 +323,7 @@ Digite o código QuickUnlock: Desbloqueio Rápido! Fechar banco de dados + Ativar bloqueio de tela Habilitar Desbloqueio Rápido por padrão Define se o Desbloqueio Rápido está habilitado por padrão ou não. Proteger a exibição da base de dados @@ -722,6 +725,11 @@ Notificação para simplificar o acesso à entrada selecionada. Fechar banco de dados após três tentativas de desbloqueio biométrico falhadas. Alerta! Autenticação biométrica pode ser invalidada pelo Android, por exemplo: depois de adicionar uma nova digital nas configurações do seu dispositivo. Esteja certo de sempre saber como desbloquear com sua senha mestra! + + Estimativa aprimorada da qualidade da senha, considerando a maioria das senhas populares. + Block password-based QuickUnlock (for security reasons) if the device does not have a screen lock activated. + Update network security configuration to disable clear-text transfer. + Atualizado de Xamarin Android para .NET 8 Atualizado para o Target SDK 34 From 4b2d2ef7689aa9469ac179bdff43e4ea2906846c Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 9 Jul 2025 02:47:52 +0200 Subject: [PATCH 05/13] New translations strings.xml (Portuguese, Brazilian) --- src/keepass2android-app/Resources/values-pt-rBR/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml index df8d1a72..bc8b05b7 100644 --- a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml +++ b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml @@ -727,8 +727,8 @@ Alerta! Autenticação biométrica pode ser invalidada pelo Android, por exemplo: depois de adicionar uma nova digital nas configurações do seu dispositivo. Esteja certo de sempre saber como desbloquear com sua senha mestra! Estimativa aprimorada da qualidade da senha, considerando a maioria das senhas populares. - Block password-based QuickUnlock (for security reasons) if the device does not have a screen lock activated. - Update network security configuration to disable clear-text transfer. + Bloqueia o desbloqueio rápido baseado em senha (por motivos de segurança) se o dispositivo não tiver uma trava de tela ativada. + Atualize a configuração de segurança de rede para desativar a transferência de texto não criptografado. Atualizado de Xamarin Android para .NET 8 From 60d8900473d0e8168847d6b919a247c9b25b5f0a Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 9 Jul 2025 11:40:00 +0200 Subject: [PATCH 06/13] New translations strings.xml (Greek) --- src/keepass2android-app/Resources/values-el/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android-app/Resources/values-el/strings.xml b/src/keepass2android-app/Resources/values-el/strings.xml index ba806ef4..46af533f 100644 --- a/src/keepass2android-app/Resources/values-el/strings.xml +++ b/src/keepass2android-app/Resources/values-el/strings.xml @@ -319,6 +319,7 @@ Εισάγετε τον κωδικό QuickUnlock: QuickUnlock! Κλείσιμο βάσης δεδομένων + Ενεργοποίηση κλειδώματος οθόνης Ενεργοποίηση QuickUnlock εξ ορισμού Ορίζει αν το QuickUnlock είναι ενεργό εξ ορισμού ή όχι. Προστασία προβολής βάσης δεδομένων From 0636f687aca69380d1a81a20b5b5d9eb0a421555 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 9 Jul 2025 13:58:02 +0200 Subject: [PATCH 07/13] New translations strings.xml (Greek) --- .../Resources/values-el/strings.xml | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/keepass2android-app/Resources/values-el/strings.xml b/src/keepass2android-app/Resources/values-el/strings.xml index 46af533f..9600d615 100644 --- a/src/keepass2android-app/Resources/values-el/strings.xml +++ b/src/keepass2android-app/Resources/values-el/strings.xml @@ -93,6 +93,8 @@ Απενεργοποίηση βιομετρικού ξεκλειδώματος Ενεργοποίηση πλήρους βιομετρικού ξεκλειδώματος Ενεργοποίηση βιομετρικού ξεκλειδώματος για QuickUnlock + Το QuickUnlock βασισμένο σε συνθηματικό δεν είναι διαθέσιμο. + Το QuickUnlock που χρησιμοποιεί ένα τμήμα του συνθηματικού έχει αποκλειστεί, επειδή το κλείδωμα οθόνης είναι απενεργοποιημένο στη συσκευή σας. Αυτό σας προστατεύει σε περίπτωση που κάποιος σας παρακολουθεί όταν εισάγετε το QuickUnlock. Αποτυχία βιομετρικού ξεκλειδώματος. Το κλειδί αποκρυπτογράφησης ακυρώθηκε από το Android. Αυτό συμβαίνει συνήθως αν αλλάξει η βιομετρική αυθεντικοποίηση ή οι ρυθμίσεις ασφάλειας. Το ξεκλείδωμα της βάσης δεδομένων απέτυχε: άκυρο σύνθετο κλειδί. Το βιομετρικό ξεκλείδωμα απενεργοποιήθηκε επειδή το αποθηκευμένο πρωτεύον συνθηματικό δεν είναι πλέον έγκυρο. Ενεργοποιήστε ξανά το βιομετρικό ξεκλείδωμα για το νέο πρωτεύον συνθηματικό. @@ -251,7 +253,6 @@ Εξαίρεση παρόμοιων χαρακτήρων Προφίλ Εισάγετε το όνομα του προφίλ που θα αποθηκευτεί. Εισάγετε ένα υπάρχον όνομα για αντικατάσταση. - Αριθμός λέξεων συνθηματικής φράσης Διαχωριστικό λέξεων Συνθηματικό @@ -333,7 +334,7 @@ Απόκρυψη μήκους QuickUnlock Αν ενεργοποιηθεί, αποκρύπτει το μήκος του κωδικού QuickUnlock στη σχετική οθόνη. Κλειδί QuickUnlock από τη βάση δεδομένων - Εάν η ενεργή βάση δεδομένων περιέχει μια καταχώριση με τίτλο QuickUnlock στην ομάδα ρίζας της, ο κωδικός πρόσβασης αυτής της καταχώρισης χρησιμοποιείται ως κωδικός QuickUnlock. + Εάν η ενεργή βάση δεδομένων περιέχει μια καταχώριση με τίτλο QuickUnlock στην ομάδα ρίζας της, το συνθηματικό αυτής της καταχώρισης χρησιμοποιείται ως κωδικός QuickUnlock. Αποτυχία QuickUnlock: λανθασμένο συνθηματικό! Αποθήκευση συνημμένου Επιλέξτε πού θα αποθηκεύσετε το συνημμένο. @@ -428,7 +429,7 @@ Άνοιγμα ρυθμίσεων Το Keepass2Android μπορεί να εμφανίζει μια ειδοποίηση συστήματος ενόσω η βάση δεδομένων σας παραμένει ξεκλείδωτη. Για να λειτουργήσει αυτό, χορηγήστε την άδεια. Δεν με νοιάζει - Το αρχείο δεν είναι πλέον προσπελάσιμο στο Keepass2Android. Είτε διαγράφτηκε ή ανακηθηκαν τα δικαιώματα πρόσβασης. Δοκιμάστε να ξανα-ανοίξετε το αρχείο, πχ με Αλλαγή βάσης δεδομένων. + Το αρχείο δεν είναι πλέον προσπελάσιμο στο Keepass2Android. Είτε διαγράφτηκε ή ανακλήθηκαν τα δικαιώματα πρόσβασης. Δοκιμάστε να ξανανοίξετε το αρχείο, πχ με Αλλαγή βάσης δεδομένων. Προ-φόρτωση αρχείου βάσης δεδομένων Ξεκίνημα φόρτωσης στο παρασκήνιο ή λήψη του αρχείου της βάσης δεδομένων κατά την εισαγωγή του συνθηματικού. Συγχρονισμός μετά το QuickUnlock @@ -715,14 +716,19 @@ Ειδοποιήσεις Ειδοποίηση για απλοποιημένη πρόσβαση στην τρέχουσα καταχώριση. Κλείσιμο της βάσης δεδομένων μετά από 3 ανεπιτυχείς προσπάθειες βιομετρικού ξεκλειδώματος. - Προσοχή! Ο βιομετρικός έλεγχος ταυτότητας μπορεί να ακυρωθεί από το Android, π.χ. μετά την προσθήκη ενός νέου δακτυλικού αποτυπώματος στις ρυθμίσεις της συσκευής σας. Βεβαιωθείτε ότι ξέρετε πάντα πώς να ξεκλειδώσετε με τον κύριο κωδικό πρόσβασης! + Προσοχή! Ο βιομετρικός έλεγχος ταυτότητας μπορεί να ακυρωθεί από το Android, π.χ. μετά την προσθήκη ενός νέου δακτυλικού αποτυπώματος στις ρυθμίσεις της συσκευής σας. Βεβαιωθείτε ότι ξέρετε πάντα πώς να ξεκλειδώσετε με το κύριο συνθηματικό! + + Βελτιωμένη εκτίμηση της ποιότητας του συνθηματικού που λαμβάνει υπόψη τα πιο δημοφιλή συνθηματικά + Αποκλεισμός του QuickUnlock βασισμένου στο συνθηματικό (για λόγους ασφαλείας), εάν η συσκευή δεν έχει ενεργοποιημένο το κλείδωμα οθόνης. + Ενημερώστε τις ρυθμίσεις ασφαλείας δικτύου για να απενεργοποιήσετε τη μεταφορά ορατού κειμένου. + Αναβαθμίστηκε από Xamarin Android σε .ΝΕΤ 8 Αναβαθμίστηκε στοχεύοντας το SDK 34 Αναβαθμίστηκε σε διεπαφή χρήστη Material 3 Βελτιώστε την αυτόματη συμπλήρωση για να εργαστείτε με Compose Apps Διόρθωση ονόματος host στην αυτόματη συμπλήρωση και αναζήτηση - Διόρθωση προβλήματος με τη γεννήτρια κωδικού πρόσβασης + Διόρθωση προβλήματος με τη γεννήτρια συνθηματικών Αναβαθμίστηκε το OneDrive SDK στην έκδοση 5.68 @@ -748,12 +754,12 @@ Βελτίωση της υλοποίησης FTP και SFTP Προσθήκη πρόσβασης σε πλήρες pCloud Επιτρέπει την επιλογή γλώσσας συστήματος στο μενού της γλώσσας - Διόρθωση προβλήματος με την απομνημόνευση Keyfile + ερώτηση για τον τύπο του κωδικού πρόσβασης + Διόρθωση προβλήματος με την απομνημόνευση Keyfile + ερώτηση για το συνθηματικό Διόρθωση σφάλματος για απότομα κλεισίματα εφαρμογής και μη αναμενόμενες αποσυνδέσεις Μετάβαση σε νέα υλοποίηση SFTP, υποστηρίζοντας σύγχρονους αλγόριθμους δημόσιου κλειδιού όπως rsa-sha2-256 - Μαρκάρισμα κωδικών πρόσβασης ως ευαίσθητοι κατά την αντιγραφή στο πρόχειρο (Android 13) + Μαρκάρισμα των συνθηματικών ως ευαίσθητα κατά την αντιγραφή στο πρόχειρο (Android 13) Βελτιώσεις Autofill @@ -774,7 +780,7 @@ Προστέθηκε υποστήριξη για τη μορφή αρχείου KDBX 4.1 που εισήχθη στο KeePass 2.48 Προστέθηκε ο διάλογος ρύθμισης ρυθμίσεων TOTP για τις καταχωρίσεις - Βελτιωμένη γεννήτρια κωδικού πρόσβασης: Προστέθηκε υποστήριξη συνθηματικής φράσης, περισσότερες επιλογές, προφίλ και εκτίμηση ισχύος κωδικού πρόσβασης + Βελτιωμένη γεννήτρια συνθηματικών: Προστέθηκε υποστήριξη συνθηματικής φράσης, περισσότερες επιλογές, προφίλ και εκτίμηση ισχύος κωδικού πρόσβασης Βελτιώσεις στην αυτόματη συμπλήρωση (σταθερό αναδυόμενο παράθυρο δεν εμφανίζεται στο Chrome, καλύτερη υποστήριξη υποτομέα) Βελτιώσεις στην υλοποίηση του OneDrive: δεν υπάρχει πλέον όριο μεγέθους, ούτε περιττές αιτήσεις ελέγχου ταυτότητας Προστέθηκε επιλογή για να επιλέξετε το φωτεινό/σκούρο θέμα από τις ρυθμίσεις του συστήματος, συμπεριλαμβανομένων των νυχτερινών πλάνων, απαιτεί Android 10+ @@ -884,7 +890,7 @@ Δεν σχετίζεται το web domain %1$s με την εφαρμογή %2$s Το Keepass2Android ανίχνευσε βιομετρικό εξοπλισμό. Θέλετε να ενεργοποιήσετε βιομετρικό ξεκλείδωμα για αυτή τη βάση δεδομένων; Να επιτρέπονται οι ειδοποιήσεις - Το Keepass2Android μπορεί να εμφανίσει ειδοποιήσεις με κουμπιά για να αντιγράψετε τιμές, όπως κωδικούς πρόσβασης και TOTP στο πρόχειρο, ή για να εμφανιστεί το ενσωματωμένο πληκτρολόγιο. Αυτό είναι χρήσιμο για να μεταφέρετε τιμές σε άλλες εφαρμογές, χωρίς να μεταβείτε σε Keepass2Android επανειλημμένα. Θέλετε να ενεργοποιήσετε αυτές τις ειδοποιήσεις; + Το Keepass2Android μπορεί να εμφανίσει ειδοποιήσεις με κουμπιά για να αντιγράψετε τιμές, όπως συνθηματικά και TOTP στο πρόχειρο, ή για να εμφανιστεί το ενσωματωμένο πληκτρολόγιο. Αυτό είναι χρήσιμο για να μεταφέρετε τιμές σε άλλες εφαρμογές, χωρίς να μεταβείτε σε Keepass2Android επανειλημμένα. Θέλετε να ενεργοποιήσετε αυτές τις ειδοποιήσεις; Να επιτρέπονται οι ειδοποιήσεις Απενεργοποιήστε αυτό το χαρακτηριστικό Όχι τώρα @@ -910,4 +916,8 @@ Εναλλαγή πίσω όταν πατήσετε αποστολή / λήψη / ολοκλήρωση Η σάρωση QR κώδικα απαιτεί Google Play Services. Παρακαλώ εγκαταστήστε ή ενημερώστε τις Google Play Services στη συσκευή σας. Ρυθμίσεις πληκτρολογίου Android + Σημείωση: Έχετε ενεργοποιήσει στις Ρυθμίσεις - Εφαρμογή - Πρόσβαση στα συνθηματικά - Εναλλαγή πληκτρολογίου - Αυτόματη εναλλαγή πληκτρολογίου, αλλά φαίνεται ότι δεν έχει ρυθμιστεί σωστά. + Σημείωση: Έχετε ενεργοποιήσει στις Ρυθμίσεις - Εφαρμογή - Πρόσβαση στα συνθηματικά - Λειτουργία αυτόματης συμπλήρωσης - Αυτόματη συμπλήρωση για καταχωρίσεις TOTP. Αυτό μπορεί να προκαλέσει την εμφάνιση αυτού του παραθύρου όταν ανοίγετε μια καταχώριση με TOTP. + Σημείωση: Έχετε ενεργοποιήσει στις Ρυθμίσεις - Εφαρμογή - Ασφάλεια - Χρήση του ενσωματωμένου στο Keepass2Android πληκτρολογίου. Αυτό μπορεί να προκαλέσει την εμφάνιση αυτού του παραθύρου όταν ανοίγετε την εφαρμογή ή επεξεργάζεστε μια καταχώριση. + Σημείωση: Έχετε ενεργοποιήσει στις Ρυθμίσεις - Εφαρμογή - Πρόσβαση στα συνθηματικά - Εναλλαγή πληκτρολογίου - Εναλλαγή πληκτρολογίου. Αυτό μπορεί να προκαλέσει την εμφάνιση αυτού του παραθύρου κατά την αναζήτηση μιας καταχώρισης από το πρόγραμμα περιήγησης. From 16ff81cf8121dad1d0bb2a7257d0b240c682e3fc Mon Sep 17 00:00:00 2001 From: PhilippC Date: Mon, 14 Jul 2025 10:57:07 +0200 Subject: [PATCH 08/13] New translations strings.xml (Czech) --- src/keepass2android-app/Resources/values-cs/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/keepass2android-app/Resources/values-cs/strings.xml b/src/keepass2android-app/Resources/values-cs/strings.xml index 4b2dc52c..553f382d 100644 --- a/src/keepass2android-app/Resources/values-cs/strings.xml +++ b/src/keepass2android-app/Resources/values-cs/strings.xml @@ -93,6 +93,8 @@ Zakázat Biometrické odemknutí Povolit plné Biometrické odemknutí Povolit Biometrické odemknutí pro Rychlé odemknutí + Rychlé odemknutí pomocí hesla není k dispozici + Funkce Rychlé odemknutí pomocí části hesla je blokována, protože na vašem zařízení není aktivováno zamykání obrazovky. Toto opatření slouží k vaší ochraně pro případ, že by někdo sledoval zadávání klíče pro Rychlé odemknutí. Biometrické odemknutí selhalo. Dešifrovací klíč byl zneplatněn systémem Android. To se obvykle stává, pokud došlo ke změně biometrického ověření nebo bylo změněno bezpečnostní nastavení. Odemknutí databáze se nezdařilo: neplatný složený klíč. Biometrické odemknutí bylo zakázáno z důvodu pravděpodobného vypršení platnosti hlavního hesla. Prosím, povolte znovu Biometrické odemknutí pro nové hlavní heslo. @@ -319,6 +321,7 @@ Vložte kód Rychlého odemknutí: Rychlé odemknutí Zavřít databázi + Povolit zámek obrazovky Ve výchozím nastavení povolit Rychlé odemknutí Určuje, zda je Rychlé odemknutí ve výchozím nastavení povoleno nebo ne. Chránit zobrazení databáze @@ -718,6 +721,11 @@ Upozornění pro usnadnění přístupu k momentálně zvolené položce. Zavřít databázi po třech neúspěšných pokusech o odemknutí. Varování! Biometrické ověření může být zneplatněno Androidem, např. po přidání nového otisku prstu do nastavení zařízení. Ujistěte se, že vždy víte, jak odemknout pomocí hlavního hesla! + + Vylepšené hodnocení kvality hesel založené na nejčastěji používaných heslech. + Pokud zařízení nemá aktivovaný zámek obrazovky, blokuje se funkce Rychlé odemknutí pomocí hesla (z bezpečnostních důvodů). + Aktualizovat konfiguraci zabezpečení sítě pro vypnutí přenosu textu v nešifrované podobě. + Aktualizováno z Xamarin Android na .net 8 Aktualizováno na Target SDK 34 From 3e6d86c206e52bbae6b83d50d06fddc57ba6be46 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 15 Jul 2025 09:10:41 +0200 Subject: [PATCH 09/13] correctly check if an item is a folder or file. closes https://github.com/PhilippC/keepass2android/issues/2589 --- .../javafilestorage/WebDavStorage.java | 5 ++- .../webdav/PropfindXmlParser.java | 38 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java index 26710fdf..fd3b6386 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java @@ -290,7 +290,10 @@ public class WebDavStorage extends JavaFileStorageBase { e.sizeInBytes = -1; } } - e.isDirectory = r.href.endsWith("/"); + + e.isDirectory = r.href.endsWith("/") || okprop.IsCollection; + + e.displayName = okprop.DisplayName; if (e.displayName == null) diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/webdav/PropfindXmlParser.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/webdav/PropfindXmlParser.java index 59ed2034..f424fb27 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/webdav/PropfindXmlParser.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/webdav/PropfindXmlParser.java @@ -57,6 +57,8 @@ public class PropfindXmlParser public String DisplayName; public String LastModified; public String ContentLength; + + public boolean IsCollection; } public String status; public Prop prop; @@ -191,6 +193,8 @@ public class PropfindXmlParser continue; } String name = parser.getName(); + String namespace = parser.getNamespace(); + android.util.Log.d("PARSE", "4name = " + name); if (name.equals("getcontentlength")) @@ -200,6 +204,9 @@ public class PropfindXmlParser prop.LastModified = readText(parser); } else if (name.equals("displayname")) { prop.DisplayName = readText(parser); + } else if (name.equals("resourcetype") && namespace.equals(ns)) { + // We found the tag + prop.IsCollection = readResourceType(parser); } else { skip(parser); } @@ -208,6 +215,37 @@ public class PropfindXmlParser return prop; } + private boolean readResourceType(XmlPullParser parser) throws IOException, XmlPullParserException { + boolean isCollection = false; + parser.require(XmlPullParser.START_TAG, ns, "resourcetype"); + + while (parser.next() != XmlPullParser.END_TAG) { + + if (parser.getEventType() != XmlPullParser.START_TAG) { + continue; + } + String name = parser.getName(); + String namespace = parser.getNamespace(); + + if (name.equals("collection") && namespace.equals(ns)) { + // We found , so it's a folder + isCollection = true; + // Since is usually an empty tag, just consume it. + // It might contain text if there's whitespace, so consume text then end tag. + if (parser.next() == XmlPullParser.TEXT) { + parser.nextTag(); // Move to the end tag + } + parser.require(XmlPullParser.END_TAG, ns, "collection"); + } else { + // Skip any other unexpected tags within + skip(parser); + } + } + // After reading all children of , ensure we are at its END_TAG + parser.require(XmlPullParser.END_TAG, ns, "resourcetype"); + return isCollection; + } + private void skip(XmlPullParser parser) throws XmlPullParserException, IOException { android.util.Log.d("PARSE", "skipping " + parser.getName()); From 913222d7cb799274f3ddf9ef569f92aa3c01787b Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 15 Jul 2025 11:07:40 +0200 Subject: [PATCH 10/13] allow chunked uploads, closes https://github.com/PhilippC/keepass2android/issues/2777 --- src/Kp2aBusinessLogic/IKp2aApp.cs | 4 ++ .../Io/DropboxFileStorage.cs | 5 +- src/Kp2aBusinessLogic/Io/JavaFileStorage.cs | 2 +- src/Kp2aBusinessLogic/Io/WebDavFileStorage.cs | 25 +++++++-- .../javafilestorage/WebDavStorage.java | 56 ++++++++++++++++++- src/keepass2android-app/FileSelectHelper.cs | 15 +++-- .../Resources/values/config.xml | 1 + .../Resources/values/strings.xml | 3 + .../Resources/xml/pref_app_file_handling.xml | 9 +++ src/keepass2android-app/app/App.cs | 23 ++++++-- 10 files changed, 125 insertions(+), 18 deletions(-) diff --git a/src/Kp2aBusinessLogic/IKp2aApp.cs b/src/Kp2aBusinessLogic/IKp2aApp.cs index 9a8357f8..6e4e9c1f 100644 --- a/src/Kp2aBusinessLogic/IKp2aApp.cs +++ b/src/Kp2aBusinessLogic/IKp2aApp.cs @@ -140,6 +140,10 @@ namespace keepass2android #endif + int WebDavChunkedUploadSize + { + get; + } } } \ No newline at end of file diff --git a/src/Kp2aBusinessLogic/Io/DropboxFileStorage.cs b/src/Kp2aBusinessLogic/Io/DropboxFileStorage.cs index 4ad64472..0f354a5c 100644 --- a/src/Kp2aBusinessLogic/Io/DropboxFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/DropboxFileStorage.cs @@ -15,7 +15,9 @@ namespace keepass2android.Io { get { return false; } } - } + + static public bool IsConfigured => !string.IsNullOrEmpty(AppKey) && !string.IsNullOrEmpty(AppSecret); + } public partial class DropboxAppFolderFileStorage: JavaFileStorage { @@ -29,6 +31,7 @@ namespace keepass2android.Io get { return false; } } + static public bool IsConfigured => !string.IsNullOrEmpty(AppKey) && !string.IsNullOrEmpty(AppSecret); } } diff --git a/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs b/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs index e526928e..2c39e594 100644 --- a/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/JavaFileStorage.cs @@ -123,7 +123,7 @@ namespace keepass2android.Io } - public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction) + public virtual IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction) { return new JavaFileStorageWriteTransaction(IocToPath(ioc), useFileTransaction, this); } diff --git a/src/Kp2aBusinessLogic/Io/WebDavFileStorage.cs b/src/Kp2aBusinessLogic/Io/WebDavFileStorage.cs index 6cce6119..2d80e18a 100644 --- a/src/Kp2aBusinessLogic/Io/WebDavFileStorage.cs +++ b/src/Kp2aBusinessLogic/Io/WebDavFileStorage.cs @@ -6,10 +6,12 @@ using System.Text; using Android.App; using Android.Content; using Android.OS; +using Android.Preferences; using Android.Runtime; using Android.Views; using Android.Widget; #if !NoNet && !EXCLUDE_JAVAFILESTORAGE + using Keepass2android.Javafilestorage; #endif using KeePassLib.Serialization; @@ -19,9 +21,15 @@ namespace keepass2android.Io #if !NoNet && !EXCLUDE_JAVAFILESTORAGE public class WebDavFileStorage: JavaFileStorage { - public WebDavFileStorage(IKp2aApp app) : base(new Keepass2android.Javafilestorage.WebDavStorage(app.CertificateErrorHandler), app) - { - } + private readonly IKp2aApp _app; + private readonly WebDavStorage baseWebdavStorage; + + public WebDavFileStorage(IKp2aApp app, int chunkSize) : base(new Keepass2android.Javafilestorage.WebDavStorage(app.CertificateErrorHandler, chunkSize), app) + { + _app = app; + baseWebdavStorage = (WebDavStorage)Jfs; + + } public override IEnumerable SupportedProtocols { @@ -75,6 +83,15 @@ namespace keepass2android.Io } return base.IocToPath(ioc); } - } + + + public override IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction) + { + baseWebdavStorage.SetUploadChunkSize(_app.WebDavChunkedUploadSize); + return base.OpenWriteTransaction(ioc, useFileTransaction); + } + } + + #endif } \ No newline at end of file diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java index fd3b6386..37960f2d 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java @@ -15,7 +15,10 @@ import com.burgstaller.okhttp.basic.BasicAuthenticator; import com.burgstaller.okhttp.digest.CachingAuthenticator; import com.burgstaller.okhttp.digest.DigestAuthenticator; + +import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.UnsupportedEncodingException; @@ -44,23 +47,33 @@ import keepass2android.javafilestorage.webdav.DecoratedTrustManager; import keepass2android.javafilestorage.webdav.PropfindXmlParser; import keepass2android.javafilestorage.webdav.WebDavUtil; import okhttp3.MediaType; +import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.internal.tls.OkHostnameVerifier; +import okio.BufferedSink; public class WebDavStorage extends JavaFileStorageBase { private final ICertificateErrorHandler mCertificateErrorHandler; private Context appContext; - public WebDavStorage(ICertificateErrorHandler certificateErrorHandler) + int chunkSize; + + public WebDavStorage(ICertificateErrorHandler certificateErrorHandler, int chunkSize) { + this.chunkSize = chunkSize; mCertificateErrorHandler = certificateErrorHandler; } + public void setUploadChunkSize(int chunkSize) + { + this.chunkSize = chunkSize; + } + public String buildFullPath(String url, String username, String password) throws UnsupportedEncodingException { String scheme = url.substring(0, url.indexOf("://")); url = url.substring(scheme.length() + 3); @@ -189,11 +202,49 @@ public class WebDavStorage extends JavaFileStorageBase { try { ConnectionInfo ci = splitStringToConnectionInfo(path); + + RequestBody requestBody; + if (chunkSize > 0) + { + // use chunked upload + requestBody = new RequestBody() { + @Override + public MediaType contentType() { + return MediaType.parse("application/binary"); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + try (InputStream in = new ByteArrayInputStream(data)) { + byte[] buffer = new byte[chunkSize]; + int read; + while ((read = in.read(buffer)) != -1) { + sink.write(buffer, 0, read); + sink.flush(); + } + } + } + + @Override + public long contentLength() { + return -1; // use chunked upload + } + }; + } + else + { + requestBody = new MultipartBody.Builder() + .addPart(RequestBody.create(data, MediaType.parse("application/binary"))) + .build(); + } + + Request request = new Request.Builder() .url(new URL(ci.URL)) - .put(RequestBody.create(MediaType.parse("application/binary"), data)) + .put(requestBody) .build(); + //TODO consider writeTransactional //TODO check for error @@ -522,3 +573,4 @@ public class WebDavStorage extends JavaFileStorageBase { } } + diff --git a/src/keepass2android-app/FileSelectHelper.cs b/src/keepass2android-app/FileSelectHelper.cs index 911b5300..3b480b7a 100644 --- a/src/keepass2android-app/FileSelectHelper.cs +++ b/src/keepass2android-app/FileSelectHelper.cs @@ -9,7 +9,9 @@ using System.Text; using Android.App; using Android.Content; +using Android.Content.Res; using Android.OS; +using Android.Preferences; using Android.Runtime; using Android.Views; using Android.Widget; @@ -319,7 +321,7 @@ namespace keepass2android View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.httpcredentials, null); if (!defaultPath.EndsWith(_schemeSeparator)) { - var webdavStorage = new Keepass2android.Javafilestorage.WebDavStorage(App.Kp2a.CertificateErrorHandler); + var webdavStorage = CreateWebdavStorage(activity); var connInfo = webdavStorage.SplitStringToConnectionInfo(defaultPath); dlgContents.FindViewById(Resource.Id.http_url).Text = connInfo.Url; dlgContents.FindViewById(Resource.Id.http_user).Text = connInfo.Username; @@ -339,7 +341,7 @@ namespace keepass2android string scheme = defaultPath.Substring(0, defaultPath.IndexOf(_schemeSeparator, StringComparison.Ordinal)); if (host.Contains(_schemeSeparator) == false) host = scheme + _schemeSeparator + host; - string httpPath = new Keepass2android.Javafilestorage.WebDavStorage(null).BuildFullPath(host, user, + string httpPath = CreateWebdavStorage(activity).BuildFullPath(host, user, password); onStartBrowse(httpPath); }); @@ -353,7 +355,12 @@ namespace keepass2android #endif } - private void ShowFtpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath) + private static WebDavStorage CreateWebdavStorage(Activity activity) + { + return new WebDavStorage(App.Kp2a.CertificateErrorHandler, App.Kp2a.WebDavChunkedUploadSize); + } + + private void ShowFtpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath) { #if !NoNet MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity); @@ -518,7 +525,7 @@ namespace keepass2android string scheme = defaultPath.Substring(0,defaultPath.IndexOf(_schemeSeparator, StringComparison.Ordinal)); if (host.Contains(_schemeSeparator) == false) host = scheme + _schemeSeparator + host; - string httpPath = new Keepass2android.Javafilestorage.WebDavStorage(null).BuildFullPath(WebDavFileStorage.Owncloud2Webdav(host, subtype == "owncloud" ? WebDavFileStorage.owncloudPrefix : WebDavFileStorage.nextcloudPrefix), user, + string httpPath = CreateWebdavStorage(activity).BuildFullPath(WebDavFileStorage.Owncloud2Webdav(host, subtype == "owncloud" ? WebDavFileStorage.owncloudPrefix : WebDavFileStorage.nextcloudPrefix), user, password); onStartBrowse(httpPath); }); diff --git a/src/keepass2android-app/Resources/values/config.xml b/src/keepass2android-app/Resources/values/config.xml index e5c3a97c..db3582ec 100644 --- a/src/keepass2android-app/Resources/values/config.xml +++ b/src/keepass2android-app/Resources/values/config.xml @@ -209,6 +209,7 @@ ShowUnlockedNotification true + 65536 PreloadDatabaseEnabled true diff --git a/src/keepass2android-app/Resources/values/strings.xml b/src/keepass2android-app/Resources/values/strings.xml index 6c4f3c87..70a93d18 100644 --- a/src/keepass2android-app/Resources/values/strings.xml +++ b/src/keepass2android-app/Resources/values/strings.xml @@ -729,6 +729,9 @@ Notification to simplify access to the currently selected entry. Close database after three failed biometric unlock attempts. Warning! Biometric authentication can be invalidated by Android, e.g. after adding a new fingerprint in your device settings. Make sure you always know how to unlock with your master password! + Chunk size for WebDav upload + Size of chunks when uploading to WebDav servers in bytes. Use 0 to disable chunked upload. + Improved password quality estimation by considering most popular passwords. diff --git a/src/keepass2android-app/Resources/xml/pref_app_file_handling.xml b/src/keepass2android-app/Resources/xml/pref_app_file_handling.xml index 98b85e90..196ab621 100644 --- a/src/keepass2android-app/Resources/xml/pref_app_file_handling.xml +++ b/src/keepass2android-app/Resources/xml/pref_app_file_handling.xml @@ -45,6 +45,14 @@ android:title="@string/UseFileTransactions_title" android:key="@string/UseFileTransactions_key" /> + + + \ No newline at end of file diff --git a/src/keepass2android-app/app/App.cs b/src/keepass2android-app/app/App.cs index db78a794..77c4df72 100644 --- a/src/keepass2android-app/app/App.cs +++ b/src/keepass2android-app/app/App.cs @@ -836,8 +836,8 @@ namespace keepass2android new AndroidContentStorage(LocaleManager.LocalizedAppContext), #if !EXCLUDE_JAVAFILESTORAGE #if !NoNet - new DropboxFileStorage(LocaleManager.LocalizedAppContext, this), - new DropboxAppFolderFileStorage(LocaleManager.LocalizedAppContext, this), + DropboxFileStorage.IsConfigured ? new DropboxFileStorage(LocaleManager.LocalizedAppContext, this) : null, + DropboxAppFolderFileStorage.IsConfigured ? new DropboxAppFolderFileStorage(LocaleManager.LocalizedAppContext, this): null, GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(LocaleManager.LocalizedAppContext)==ConnectionResult.Success ? new GoogleDriveFileStorage(LocaleManager.LocalizedAppContext, this) : null, GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(LocaleManager.LocalizedAppContext)==ConnectionResult.Success ? new GoogleDriveAppDataFileStorage(LocaleManager.LocalizedAppContext, this) : null, new OneDriveFileStorage(this), @@ -846,8 +846,8 @@ namespace keepass2android new OneDrive2AppFolderFileStorage(), new SftpFileStorage(LocaleManager.LocalizedAppContext, this, IsFtpDebugEnabled()), new NetFtpFileStorage(LocaleManager.LocalizedAppContext, this, IsFtpDebugEnabled), - new WebDavFileStorage(this), - new PCloudFileStorage(LocaleManager.LocalizedAppContext, this), + new WebDavFileStorage(this, WebDavChunkedUploadSize), + new PCloudFileStorage(LocaleManager.LocalizedAppContext, this), new PCloudFileStorageAll(LocaleManager.LocalizedAppContext, this), new MegaFileStorage(App.Context), //new LegacyWebDavStorage(this), @@ -1333,6 +1333,18 @@ namespace keepass2android } } + + + public int WebDavChunkedUploadSize + { + get + { + return int.Parse(PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext) + .GetString("WebDavChunkedUploadSize_str", + LocaleManager.LocalizedAppContext.Resources + .GetInteger(Resource.Integer.WebDavChunkedUploadSize_default).ToString())); + } + } } @@ -1458,8 +1470,7 @@ namespace keepass2android { Kp2aLog.LogUnexpectedError(e.Exception); } - - } + } } From d04d455fbdb06f61e14f45b2ea47926e867d2815 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 15 Jul 2025 12:00:05 +0200 Subject: [PATCH 11/13] add missing changelog for 1.13 --- src/keepass2android-app/ChangeLog.cs | 2 ++ src/keepass2android-app/Manifests/AndroidManifest_net.xml | 2 +- src/keepass2android-app/Manifests/AndroidManifest_nonet.xml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/keepass2android-app/ChangeLog.cs b/src/keepass2android-app/ChangeLog.cs index 6c8c5537..1c1a3723 100644 --- a/src/keepass2android-app/ChangeLog.cs +++ b/src/keepass2android-app/ChangeLog.cs @@ -31,6 +31,8 @@ namespace keepass2android MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ctx); builder.SetTitle(ctx.GetString(Resource.String.ChangeLog_title)); List changeLog = new List{ + BuildChangelogString(ctx, new List{Resource.Array.ChangeLog_1_13}, "1.13"), + BuildChangelogString(ctx, new List{Resource.Array.ChangeLog_1_12 #if !NoNet ,Resource.Array.ChangeLog_1_12_net diff --git a/src/keepass2android-app/Manifests/AndroidManifest_net.xml b/src/keepass2android-app/Manifests/AndroidManifest_net.xml index 3bfabf63..4cd481a7 100644 --- a/src/keepass2android-app/Manifests/AndroidManifest_net.xml +++ b/src/keepass2android-app/Manifests/AndroidManifest_net.xml @@ -1,6 +1,6 @@  Date: Tue, 15 Jul 2025 12:18:45 +0200 Subject: [PATCH 12/13] add support for transactional upload --- .../javafilestorage/WebDavStorage.java | 66 ++++++++++++++++++- .../javafilestoragetest2/MainActivity.java | 8 +-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java index 37960f2d..fb8ec597 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/WebDavStorage.java @@ -1,6 +1,7 @@ package keepass2android.javafilestorage; import android.content.Context; +import java.math.BigInteger; import android.content.Intent; import android.net.Uri; @@ -27,6 +28,7 @@ import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; @@ -194,11 +196,73 @@ public class WebDavStorage extends JavaFileStorageBase { return client; } + public void renameOrMoveWebDavResource(String sourcePath, String destinationPath, boolean overwrite) throws Exception { + + ConnectionInfo sourceCi = splitStringToConnectionInfo(sourcePath); + ConnectionInfo destinationCi = splitStringToConnectionInfo(destinationPath); + + Request.Builder requestBuilder = new Request.Builder() + .url(new URL(sourceCi.URL)) + .method("MOVE", null) // "MOVE" is the HTTP method + .header("Destination", destinationCi.URL); // New URI for the resource + + // Add Overwrite header + if (overwrite) { + requestBuilder.header("Overwrite", "T"); // 'T' for true + } else { + requestBuilder.header("Overwrite", "F"); // 'F' for false + } + + Request request = requestBuilder.build(); + + Response response = getClient(sourceCi).newCall(request).execute(); + + // Check the status code + if (response.isSuccessful()) { + // WebDAV MOVE can return 201 (Created) if a new resource was created at dest, + // or 204 (No Content) if moved to a pre-existing destination (e.g., just renamed). + // A 200 OK might also be returned by some servers, though 201/204 are more common. + + } + else + { + throw new Exception("Rename/Move failed for " + sourceCi.URL + " to " + destinationCi.URL + ": " + response.code() + " " + response.message()); + } + } + + public static String generateRandomHexString(int length) { + SecureRandom secureRandom = new SecureRandom(); + // Generate enough bytes to ensure we can get the desired number of hex characters. + // Each byte converts to two hex characters. + // For 8 hex characters, we need 4 bytes. + int numBytes = (int) Math.ceil(length / 2.0); + byte[] randomBytes = new byte[numBytes]; + secureRandom.nextBytes(randomBytes); + + // Convert the byte array to a hexadecimal string + // BigInteger(1, randomBytes) treats the byte array as a positive number. + // toString(16) converts it to a hexadecimal string. + String hexString = new BigInteger(1, randomBytes).toString(16); + + // Pad with leading zeros if necessary (e.g., if the generated number is small) + // and then take the first 'length' characters. + // Using String.format to ensure leading zeros if the hexString is shorter. + return String.format("%0" + length + "d", new BigInteger(hexString, 16)).substring(0, length); + } @Override public void uploadFile(String path, byte[] data, boolean writeTransactional) throws Exception { + if (writeTransactional) + { + String randomSuffix = ".tmp." + generateRandomHexString(8); + uploadFile(path + randomSuffix, data, false); + renameOrMoveWebDavResource(path+randomSuffix, path, true); + return; + } + + try { ConnectionInfo ci = splitStringToConnectionInfo(path); @@ -245,8 +309,6 @@ public class WebDavStorage extends JavaFileStorageBase { .build(); - //TODO consider writeTransactional - //TODO check for error Response response = getClient(ci).newCall(request).execute(); checkStatus(response); diff --git a/src/java/JavaFileStorageTest-AS/app/src/main/java/com/crocoapps/javafilestoragetest2/MainActivity.java b/src/java/JavaFileStorageTest-AS/app/src/main/java/com/crocoapps/javafilestoragetest2/MainActivity.java index 1c81a604..5e8fcc35 100644 --- a/src/java/JavaFileStorageTest-AS/app/src/main/java/com/crocoapps/javafilestoragetest2/MainActivity.java +++ b/src/java/JavaFileStorageTest-AS/app/src/main/java/com/crocoapps/javafilestoragetest2/MainActivity.java @@ -548,7 +548,7 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag //storageToTest = new GoogleDriveAppDataFileStorage(); - /*storageToTest = new WebDavStorage(new ICertificateErrorHandler() { + storageToTest = new WebDavStorage(new ICertificateErrorHandler() { @Override public boolean onValidationError(String error) { return false; @@ -558,12 +558,12 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag public boolean alwaysFailOnValidationError() { return false; } - }); -*/ + }, 64*1024); + //storageToTest = new DropboxV2Storage(ctx,"4ybka4p4a1027n6", "1z5lv528un9nre8", !simulateRestart); //storageToTest = new DropboxFileStorage(ctx,"4ybka4p4a1027n6", "1z5lv528un9nre8", !simulateRestart); //storageToTest = new DropboxAppFolderFileStorage(ctx,"ax0268uydp1ya57", "3s86datjhkihwyc", true); - storageToTest = new GoogleDriveFullFileStorage(); + // storageToTest = new GoogleDriveFullFileStorage(); return storageToTest; From 057a7e2f7afd4dfeae0108860683c12dd1839978 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 15 Jul 2025 13:12:18 +0200 Subject: [PATCH 13/13] another nonet fix --- src/keepass2android-app/FileSelectHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/keepass2android-app/FileSelectHelper.cs b/src/keepass2android-app/FileSelectHelper.cs index 3b480b7a..176f780c 100644 --- a/src/keepass2android-app/FileSelectHelper.cs +++ b/src/keepass2android-app/FileSelectHelper.cs @@ -354,12 +354,12 @@ namespace keepass2android dialog.Show(); #endif } - +#if !NoNet private static WebDavStorage CreateWebdavStorage(Activity activity) { return new WebDavStorage(App.Kp2a.CertificateErrorHandler, App.Kp2a.WebDavChunkedUploadSize); } - +#endif private void ShowFtpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath) { #if !NoNet