From 0f0d1994e589b4f2b2603c882f52c79e2307a4f7 Mon Sep 17 00:00:00 2001 From: Nosweh <62889203+Nosweh@users.noreply.github.com> Date: Fri, 28 Aug 2020 17:31:40 +0200 Subject: [PATCH] Add Activity to view the Git commit log (#1056) --- CHANGELOG.md | 2 +- app/src/main/AndroidManifest.xml | 4 ++ .../java/com/zeapo/pwdstore/PasswordStore.kt | 1 + .../zeapo/pwdstore/git/GitConfigActivity.kt | 68 ++++++++++++++----- .../com/zeapo/pwdstore/git/log/GitCommit.kt | 18 +++++ .../zeapo/pwdstore/git/log/GitLogActivity.kt | 38 +++++++++++ .../zeapo/pwdstore/git/log/GitLogAdapter.kt | 56 +++++++++++++++ .../com/zeapo/pwdstore/git/log/GitLogModel.kt | 53 +++++++++++++++ .../com/zeapo/pwdstore/utils/Extensions.kt | 23 +++++++ .../main/res/layout/activity_git_config.xml | 40 ++++++----- app/src/main/res/layout/activity_git_log.xml | 22 ++++++ .../main/res/layout/git_log_row_layout.xml | 45 ++++++++++++ app/src/main/res/values-de/strings.xml | 2 + app/src/main/res/values-es/strings.xml | 2 - app/src/main/res/values-fr/strings.xml | 2 - app/src/main/res/values-pt-rBR/strings.xml | 2 - app/src/main/res/values-ru/strings.xml | 2 - app/src/main/res/values/strings.xml | 14 ++-- 18 files changed, 342 insertions(+), 52 deletions(-) create mode 100644 app/src/main/java/com/zeapo/pwdstore/git/log/GitCommit.kt create mode 100644 app/src/main/java/com/zeapo/pwdstore/git/log/GitLogActivity.kt create mode 100644 app/src/main/java/com/zeapo/pwdstore/git/log/GitLogAdapter.kt create mode 100644 app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt create mode 100644 app/src/main/res/layout/activity_git_log.xml create mode 100644 app/src/main/res/layout/git_log_row_layout.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index a0067ecb..96ecff35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Allow sorting by recently used - Add [Bromite](https://www.bromite.org/) and [Ungoogled Chromium](https://git.droidware.info/wchen342/ungoogled-chromium-android) to supported browsers list for Autofill +- Add ability to view the Git commit log ### Changed @@ -17,7 +18,6 @@ All notable changes to this project will be documented in this file. ### Fixed -- Password creation UI will scroll if it does not fit on the screen - Git server protocol and authentication mode are only updated when explicitly saved - Remember HTTPS password during a sync operation diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index dae4466b..cbacda10 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -65,6 +65,10 @@ android:label="@string/title_activity_git_config" android:windowSoftInputMode="adjustResize" /> + + () { + + private val model = GitLogModel() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val inflater = LayoutInflater.from(parent.context) + val binding = GitLogRowLayoutBinding.inflate(inflater, parent, false) + return ViewHolder(binding) + } + + override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { + val commit = model.get(position) + if (commit == null) { + e { "There is no git commit for view holder at position $position." } + return + } + viewHolder.bind(commit) + } + + override fun getItemCount() = model.size + + class ViewHolder(private val binding: GitLogRowLayoutBinding) : RecyclerView.ViewHolder(binding.root) { + + fun bind(commit: GitCommit) = with(binding) { + gitLogRowMessage.text = commit.shortMessage + gitLogRowHash.text = shortHash(commit.hash) + gitLogRowTime.text = stringFrom(commit.time) + } + } +} diff --git a/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt new file mode 100644 index 00000000..22c1ec78 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt @@ -0,0 +1,53 @@ +/* + * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package com.zeapo.pwdstore.git.log + +import com.github.ajalt.timberkt.e +import com.zeapo.pwdstore.utils.PasswordRepository +import com.zeapo.pwdstore.utils.hash +import com.zeapo.pwdstore.utils.time +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.revwalk.RevCommit + +private fun commits(): Iterable { + val repo = PasswordRepository.getRepository(null) + if (repo == null) { + e { "Could not access git repository" } + return listOf() + } + return try { + Git(repo).log().call() + } catch (exc: Exception) { + e(exc) { "Failed to obtain git commits" } + listOf() + } +} + +/** + * Provides [GitCommit]s from a git-log of the password git repository. + * + * All commits are acquired on the first request to this object. + */ +class GitLogModel { + + // All commits are acquired here at once. Acquiring the commits in batches would not have been + // entirely sensible because the amount of computation required to obtain commit number n from + // the log includes the amount of computation required to obtain commit number n-1 from the log. + // This is because the commit graph is walked from HEAD to the last commit to obtain. + // Additionally, tests with 1000 commits in the log have not produced a significant delay in the + // user experience. + private val cache: MutableList by lazy { + commits().map { + GitCommit(it.hash, it.shortMessage, it.authorIdent.name, it.time) + }.toMutableList() + } + val size = cache.size + + fun get(index: Int): GitCommit? { + if (index >= size) e { "Cannot get git commit with index $index. There are only $size." } + return cache.getOrNull(index) + } +} diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt b/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt index 561b8d99..edc01776 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt +++ b/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt @@ -28,6 +28,9 @@ import com.zeapo.pwdstore.git.GitCommandExecutor import com.zeapo.pwdstore.git.operation.GitOperation import com.zeapo.pwdstore.utils.PasswordRepository.Companion.getRepositoryDirectory import java.io.File +import java.util.Date +import org.eclipse.jgit.lib.ObjectId +import org.eclipse.jgit.revwalk.RevCommit const val OPENPGP_PROVIDER = "org.sufficientlysecure.keychain" @@ -162,3 +165,23 @@ val Context.autofillManager: AutofillManager? fun File.isInsideRepository(): Boolean { return canonicalPath.contains(getRepositoryDirectory().canonicalPath) } + +/** + * Unique SHA-1 hash of this commit as hexadecimal string. + * + * @see RevCommit.id + */ +val RevCommit.hash: String + get() = ObjectId.toString(id) + +/** + * Time this commit was made with second precision. + * + * @see RevCommit.commitTime + */ +val RevCommit.time: Date + get() { + val epochSeconds = commitTime.toLong() + val epochMilliseconds = epochSeconds * 1000 + return Date(epochMilliseconds) + } diff --git a/app/src/main/res/layout/activity_git_config.xml b/app/src/main/res/layout/activity_git_config.xml index df1874a9..1d495250 100644 --- a/app/src/main/res/layout/activity_git_config.xml +++ b/app/src/main/res/layout/activity_git_config.xml @@ -17,7 +17,7 @@ android:id="@+id/username_input_layout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_margin="8dp" + android:layout_margin="@dimen/normal_margin" android:hint="@string/git_user_name_hint" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -35,7 +35,7 @@ android:id="@+id/email_input_layout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_margin="8dp" + android:layout_margin="@dimen/normal_margin" android:hint="@string/git_user_email" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/username_input_layout"> @@ -52,7 +52,7 @@ android:id="@+id/save_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_margin="8dp" + android:layout_margin="@dimen/normal_margin" android:text="@string/crypto_save" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/email_input_layout" /> @@ -62,45 +62,43 @@ style="@style/TextAppearance.MaterialComponents.Headline5" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_margin="8dp" - android:text="@string/hackish_tools" + android:layout_margin="@dimen/normal_margin" + android:text="@string/git_tools" android:textSize="24sp" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/save_button" /> - - + tools:text="HEAD status" /> + + + app:layout_constraintTop_toBottomOf="@+id/git_log" /> diff --git a/app/src/main/res/layout/activity_git_log.xml b/app/src/main/res/layout/activity_git_log.xml new file mode 100644 index 00000000..96b28487 --- /dev/null +++ b/app/src/main/res/layout/activity_git_log.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/main/res/layout/git_log_row_layout.xml b/app/src/main/res/layout/git_log_row_layout.xml new file mode 100644 index 00000000..5a29f241 --- /dev/null +++ b/app/src/main/res/layout/git_log_row_layout.xml @@ -0,0 +1,45 @@ + + + + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index fd94c8a9..d5abea1a 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -11,6 +11,7 @@ Ordner löschen Abbruch Repository Informationen + Commit-Log Bitte klone oder erstelle ein neues Repository, bevor du versuchst ein Passwort hinzuzufügen oder jegliche Synchronisation-Operation durchführst. Verschieben @@ -121,6 +122,7 @@ Synchronisiere Repository Git Pull Git Push + Commit-Log anzeigen Zeige das Password Soll das entschlüsselte Passwort sichtbar sein? Dies deaktiviert nicht das Kopieren. Zeige weiteren Inhalt diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ff04cf3e..03e153e9 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -178,7 +178,5 @@ El envío fue rechazado por el servidor, la razón: Ocurrió un error durante el envío: Recordar contraseñagit (inseguro) - Hackish tools Abortar rebase - Hash del commit diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9f9e1768..db98bfd8 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -178,6 +178,4 @@ Pousser au dépôt distant sans avance rapide rejetée. Vérifiez la variable receive.denyNonFastForwards dans le fichier de configuration du répertoire de destination. Une erreur s\'est produite lors de l\'opération de poussée: Se rappeler de la phrase secrète dans la configuration de l\'application (peu sûr) - Outils de hack - Commettre la clé diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index a7f3e046..2e07190a 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -248,10 +248,8 @@ Limpar a frase secreta salva para chave SSH local Limpar senha HTTPS salva Lembrar senha da chave - Ferramentas de hackers Abortar rebase e realizar push do novo branch Hard reset no branch remoto - Commit hash Falha ao conectar ao serviço de API SSH do OpenKeychain. Nenhum provedor de API SSH encontrado. O OpenKeychain está instalado? SSH API pendente falhou diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3fab8cf9..d1fbc215 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -233,10 +233,8 @@ Удаленный репозиторий отклонил запись изменений без быстрой перемотки вперед. Проверьте переменную receive.denyNonFastForwards в файле конфигурации репозитория назначения. В хоте операции записи изменений возникла ошибка: Заполнить парольную фразу в конфигурации приложнеия (небезопасно) - Костыльные инструменты Прервать перебазирование и записать изменения в новую ветку Полный сброс до состояния удаленной ветки - Хэш-сумма изменений Ошибка при подключении к сервису OpenKeychain SSH API Не найдено SSH API провайдеров. OpenKeychain установлен? Ожидаемое намерение SSH API не удалось diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a6e33047..72d4d5db 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,6 +20,7 @@ Cancel Repository information Git configuration + Commit log Please clone or create a new repository below before trying to add a password or running any synchronization operation. @@ -117,8 +118,8 @@ Repository - Edit git server settings - Git utils + Edit Git server settings + Local Git config & utilities Import SSH key Generate SSH key pair View generated public SSH key @@ -217,6 +218,7 @@ Pull from remote Push to remote Everything up-to-date + Show commit log Show the password Control the visibility of the passwords once decrypted. This does not disable copying to clipboard. Show extra content @@ -281,10 +283,12 @@ Clear saved passphrase for local SSH key Clear saved HTTPS password Remember key passphrase - Hackish tools + Utilities Abort rebase and push new branch Hard reset to remote branch - Commit hash + On branch %1$s + HEAD detached at %1$s + Unable to locate HEAD Failed to connect to OpenKeychain SSH API service. No SSH API provider found. Is OpenKeychain installed? SSH API pending intent failed @@ -393,6 +397,6 @@ A file by that name already exists A folder by that name already exists - Digits/Symbols (d/s) + Digits/Symbols (d/s) ds