aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/dev/msfjarvis/aps/data/repo
diff options
context:
space:
mode:
authorHarsh Shandilya <me@msfjarvis.dev>2020-12-05 06:07:18 +0530
committerGitHub <noreply@github.com>2020-12-05 06:07:18 +0530
commit5e66d99c852ea67a88b650c03b0e8d55e83eccde (patch)
treeaee323a08253fe7b863976eff92a1bd412bd1430 /app/src/main/java/dev/msfjarvis/aps/data/repo
parent8eb55f18a11d6b2f155c7c9d48ca833313ee13db (diff)
downloadHardenedPass-5e66d99c852ea67a88b650c03b0e8d55e83eccde.tar.gz
HardenedPass-5e66d99c852ea67a88b650c03b0e8d55e83eccde.zip
Refactor package structure (#1233)
* idea: default test runner to Gradle * Kick off package structure revamp * Reparent all classes under dev.msfjarvis.aps Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Diffstat (limited to 'app/src/main/java/dev/msfjarvis/aps/data/repo')
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/data/repo/PasswordRepository.kt243
1 files changed, 243 insertions, 0 deletions
diff --git a/app/src/main/java/dev/msfjarvis/aps/data/repo/PasswordRepository.kt b/app/src/main/java/dev/msfjarvis/aps/data/repo/PasswordRepository.kt
new file mode 100644
index 00000000..fecdba86
--- /dev/null
+++ b/app/src/main/java/dev/msfjarvis/aps/data/repo/PasswordRepository.kt
@@ -0,0 +1,243 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+package dev.msfjarvis.aps.data.repo
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.core.content.edit
+import com.github.michaelbull.result.getOrElse
+import com.github.michaelbull.result.onFailure
+import com.github.michaelbull.result.runCatching
+import dev.msfjarvis.aps.Application
+import dev.msfjarvis.aps.data.password.PasswordItem
+import dev.msfjarvis.aps.util.settings.PasswordSortOrder
+import dev.msfjarvis.aps.util.settings.PreferenceKeys
+import dev.msfjarvis.aps.util.extensions.getString
+import dev.msfjarvis.aps.util.extensions.sharedPrefs
+import java.io.File
+import java.io.FileFilter
+import java.nio.file.Files
+import java.nio.file.LinkOption
+import org.eclipse.jgit.api.Git
+import org.eclipse.jgit.lib.Repository
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder
+import org.eclipse.jgit.transport.RefSpec
+import org.eclipse.jgit.transport.RemoteConfig
+import org.eclipse.jgit.transport.URIish
+import org.eclipse.jgit.util.FS
+import org.eclipse.jgit.util.FS_POSIX_Java6
+
+object PasswordRepository {
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private class FS_POSIX_Java6_with_optional_symlinks : FS_POSIX_Java6() {
+
+ override fun supportsSymlinks() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+
+ override fun isSymLink(file: File) = Files.isSymbolicLink(file.toPath())
+
+ override fun readSymLink(file: File) = Files.readSymbolicLink(file.toPath()).toString()
+
+ override fun createSymLink(source: File, target: String) {
+ val sourcePath = source.toPath()
+ if (Files.exists(sourcePath, LinkOption.NOFOLLOW_LINKS))
+ Files.delete(sourcePath)
+ Files.createSymbolicLink(sourcePath, File(target).toPath())
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private class Java7FSFactory : FS.FSFactory() {
+
+ override fun detect(cygwinUsed: Boolean?): FS {
+ return FS_POSIX_Java6_with_optional_symlinks()
+ }
+ }
+
+ private var repository: Repository? = null
+ private val settings by lazy(LazyThreadSafetyMode.NONE) { Application.instance.sharedPrefs }
+ private val filesDir
+ get() = Application.instance.filesDir
+
+ /**
+ * Returns the git repository
+ *
+ * @param localDir needed only on the creation
+ * @return the git repository
+ */
+ @JvmStatic
+ fun getRepository(localDir: File?): Repository? {
+ if (repository == null && localDir != null) {
+ val builder = FileRepositoryBuilder()
+ repository = runCatching {
+ builder.run {
+ gitDir = localDir
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ fs = Java7FSFactory().detect(null)
+ }
+ readEnvironment()
+ }.build()
+ }.getOrElse { e ->
+ e.printStackTrace()
+ null
+ }
+ }
+ return repository
+ }
+
+ @JvmStatic
+ val isInitialized: Boolean
+ get() = repository != null
+
+ @JvmStatic
+ fun isGitRepo(): Boolean {
+ if (repository != null) {
+ return repository!!.objectDatabase.exists()
+ }
+ return false
+ }
+
+ @JvmStatic
+ @Throws(Exception::class)
+ fun createRepository(localDir: File) {
+ localDir.delete()
+
+ Git.init().setDirectory(localDir).call()
+ getRepository(localDir)
+ }
+
+ // TODO add multiple remotes support for pull/push
+ @JvmStatic
+ fun addRemote(name: String, url: String, replace: Boolean = false) {
+ val storedConfig = repository!!.config
+ val remotes = storedConfig.getSubsections("remote")
+
+ if (!remotes.contains(name)) {
+ runCatching {
+ val uri = URIish(url)
+ val refSpec = RefSpec("+refs/head/*:refs/remotes/$name/*")
+
+ val remoteConfig = RemoteConfig(storedConfig, name)
+ remoteConfig.addFetchRefSpec(refSpec)
+ remoteConfig.addPushRefSpec(refSpec)
+ remoteConfig.addURI(uri)
+ remoteConfig.addPushURI(uri)
+
+ remoteConfig.update(storedConfig)
+
+ storedConfig.save()
+ }.onFailure { e ->
+ e.printStackTrace()
+ }
+ } else if (replace) {
+ runCatching {
+ val uri = URIish(url)
+
+ val remoteConfig = RemoteConfig(storedConfig, name)
+ // remove the first and eventually the only uri
+ if (remoteConfig.urIs.size > 0) {
+ remoteConfig.removeURI(remoteConfig.urIs[0])
+ }
+ if (remoteConfig.pushURIs.size > 0) {
+ remoteConfig.removePushURI(remoteConfig.pushURIs[0])
+ }
+
+ remoteConfig.addURI(uri)
+ remoteConfig.addPushURI(uri)
+
+ remoteConfig.update(storedConfig)
+
+ storedConfig.save()
+ }.onFailure { e ->
+ e.printStackTrace()
+ }
+ }
+ }
+
+ @JvmStatic
+ fun closeRepository() {
+ if (repository != null) repository!!.close()
+ repository = null
+ }
+
+ @JvmStatic
+ fun getRepositoryDirectory(): File {
+ return if (settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)) {
+ val externalRepo = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO)
+ if (externalRepo != null)
+ File(externalRepo)
+ else
+ File(filesDir.toString(), "/store")
+ } else {
+ File(filesDir.toString(), "/store")
+ }
+ }
+
+ @JvmStatic
+ fun initialize(): Repository? {
+ val dir = getRepositoryDirectory()
+ // uninitialize the repo if the dir does not exist or is absolutely empty
+ settings.edit {
+ if (!dir.exists() || !dir.isDirectory || requireNotNull(dir.listFiles()).isEmpty()) {
+ putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)
+ } else {
+ putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true)
+ }
+ }
+
+ // create the repository static variable in PasswordRepository
+ return getRepository(File(dir.absolutePath + "/.git"))
+ }
+
+ /**
+ * Gets the .gpg files in a directory
+ *
+ * @param path the directory path
+ * @return the list of gpg files in that directory
+ */
+ @JvmStatic
+ fun getFilesList(path: File?): ArrayList<File> {
+ if (path == null || !path.exists()) return ArrayList()
+
+ val directories = (path.listFiles(FileFilter { pathname -> pathname.isDirectory })
+ ?: emptyArray()).toList()
+ val files = (path.listFiles(FileFilter { pathname -> pathname.extension == "gpg" })
+ ?: emptyArray()).toList()
+
+ val items = ArrayList<File>()
+ items.addAll(directories)
+ items.addAll(files)
+
+ return items
+ }
+
+ /**
+ * Gets the passwords (PasswordItem) in a directory
+ *
+ * @param path the directory path
+ * @return a list of password items
+ */
+ @JvmStatic
+ fun getPasswords(path: File, rootDir: File, sortOrder: PasswordSortOrder): ArrayList<PasswordItem> {
+ // We need to recover the passwords then parse the files
+ val passList = getFilesList(path).also { it.sortBy { f -> f.name } }
+ val passwordList = ArrayList<PasswordItem>()
+ val showHidden = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false)
+
+ if (passList.size == 0) return passwordList
+ if (!showHidden) {
+ passList.filter { !it.isHidden }.toCollection(passList.apply { clear() })
+ }
+ passList.forEach { file ->
+ passwordList.add(if (file.isFile) {
+ PasswordItem.newPassword(file.name, file, rootDir)
+ } else {
+ PasswordItem.newCategory(file.name, file, rootDir)
+ })
+ }
+ passwordList.sortWith(sortOrder.comparator)
+ return passwordList
+ }
+}