Skip to content

Commit

Permalink
symmetric encryption initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
heinzelotto committed Apr 12, 2020
1 parent 2953456 commit 90b975e
Show file tree
Hide file tree
Showing 15 changed files with 374 additions and 16 deletions.
3 changes: 3 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ dependencies {
// Resolves DuplicatePlatformClasses lint error
exclude group: 'org.apache.httpcomponents', module: 'httpclient'
}

// Encryption
implementation "org.bouncycastle:bcpg-jdk15on:1.65"
}

repositories {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/orgzly/android/BookName.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
public class BookName {
private static final String TAG = BookName.class.getName();

private static final Pattern PATTERN = Pattern.compile("(.*)\\.(org)(\\.txt)?$");
private static final Pattern PATTERN = Pattern.compile("(.*)\\.(org)(\\.txt)?(\\.gpg)?$");
private static final Pattern SKIP_PATTERN = Pattern.compile("^\\.#.*");

private final String mFileName;
Expand Down
78 changes: 65 additions & 13 deletions app/src/main/java/com/orgzly/android/data/DataRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import com.orgzly.org.parser.OrgParser
import com.orgzly.org.parser.OrgParserWriter
import com.orgzly.org.utils.StateChangeLogic
import java.io.*
import java.lang.IllegalStateException
import java.util.*
import java.util.concurrent.Callable
import javax.inject.Inject
Expand Down Expand Up @@ -82,7 +81,13 @@ class DataRepository @Inject constructor(

val fileName = BookName.getFileName(context, book)

val loadedBook = loadBookFromRepo(book.linkRepo.id, book.linkRepo.type, book.linkRepo.url, fileName)
val loadedBook = loadBookFromRepo(
book.linkRepo.id,
book.linkRepo.type,
book.linkRepo.url,
fileName)

val id = loadedBook!!.book.id;

setBookLastActionAndSyncStatus(loadedBook!!.book.id, BookAction.forNow(
BookAction.Type.INFO,
Expand Down Expand Up @@ -148,27 +153,48 @@ class DataRepository @Inject constructor(
bookView: BookView,
@Suppress("UNUSED_PARAMETER") format: BookFormat) {

val uploadedBook: VersionedRook
var uploadedBook: VersionedRook? = null

val repo = getRepoInstance(repoEntity.id, repoEntity.type, repoEntity.url)

val tmpFile = getTempBookFile()
val tmpFileEncrypted = getTempBookFile()
try {
/* Write to temporary file. */
NotesOrgExporter(this).exportBook(bookView.book, tmpFile)

val (toStoreFile, toStoreFileName) =
if (repo.isEncryptionEnabled) {
val inFile: InputStream = BufferedInputStream(FileInputStream(tmpFile))
val outFile: OutputStream = BufferedOutputStream(FileOutputStream(tmpFileEncrypted))

try {
MiscUtils.pgpEncrypt(inFile, outFile, fileName, repo.encryptionPassphrase)
} finally {
inFile.close()
outFile.close()
}

Pair(tmpFileEncrypted, MiscUtils.ensureGpgExtensionFileName(fileName))
} else {
// remove possible .gpg extension left over from a previous encrypted sync
// ?maybe move this logic to BookView.getFileName()
Pair(tmpFile, MiscUtils.ensureNoGpgExtensionFileName(fileName))
}

/* Upload to repo. */
uploadedBook = repo.storeBook(tmpFile, fileName)
uploadedBook = repo.storeBook(toStoreFile, toStoreFileName)

} finally {
/* Delete temporary file. */
tmpFile.delete()
tmpFileEncrypted.delete()
}

updateBookLinkAndSync(bookView.book.id, uploadedBook)

updateBookIsModified(bookView.book.id, false)

if (uploadedBook != null) {
updateBookLinkAndSync(bookView.book.id, uploadedBook)
updateBookIsModified(bookView.book.id, false)
}
}

@Throws(IOException::class)
Expand Down Expand Up @@ -1546,22 +1572,48 @@ class DataRepository @Inject constructor(

@Throws(IOException::class)
fun loadBookFromRepo(repoId: Long, repoType: RepoType, repoUrl: String, fileName: String): BookView? {
val book: BookView?
var book: BookView? = null

val repo = getRepoInstance(repoId, repoType, repoUrl)

val tmpFile = getTempBookFile()
val tmpFileDecrypted = getTempBookFile()
try {
/* Download from repo. */
val vrook = repo.retrieveBook(fileName, tmpFile)
// ensure that we don't try to decrypt .org files or interpret .org.gpg as plaintext
// problem if both 'nb.org' and 'nb.org.gpg' exist. probably some other mechanism that
// runs at a higher level that here should be made aware and responsible of .pgp extensions
val toRecvFileName = if (repo.isEncryptionEnabled) {
MiscUtils.ensureGpgExtensionFileName(fileName)
} else {
MiscUtils.ensureNoGpgExtensionFileName(fileName)
}
val vrook = repo.retrieveBook(toRecvFileName, tmpFile)

val plaintextBookFile: File =
if (repo.isEncryptionEnabled) {
val inFile: InputStream = BufferedInputStream(FileInputStream(tmpFile))
val outFile: OutputStream = BufferedOutputStream(FileOutputStream(tmpFileDecrypted))

try {
MiscUtils.pgpDecrypt(inFile, outFile, repo.encryptionPassphrase)
} finally {
inFile.close()
outFile.close()
}

val bookName = BookName.fromFileName(fileName)
tmpFileDecrypted
} else {
tmpFile
}

/* Store from file to Shelf. */
book = loadBookFromFile(bookName.name, bookName.format, tmpFile, vrook)
val bookName = BookName.fromFileName(toRecvFileName)

/* Store from file to Shelf. */
book = loadBookFromFile(bookName.name, bookName.format, plaintextBookFile, vrook)
} finally {
tmpFile.delete()
tmpFileDecrypted.delete()
}

return book
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/com/orgzly/android/repos/ContentRepo.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ public Uri getUri() {
return repoUri;
}

@Override
public boolean isEncryptionEnabled() { return false; }

@Override
public String getEncryptionPassphrase() { return null; }

@Override
public List<VersionedRook> getBooks() throws IOException {
List<VersionedRook> result = new ArrayList<>();
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/com/orgzly/android/repos/DatabaseRepo.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ public Uri getUri() {
return repoUri;
}

@Override
public boolean isEncryptionEnabled() { return false; }

@Override
public String getEncryptionPassphrase() { return null; }

@Override
public List<VersionedRook> getBooks() {
return dbRepo.getBooks(repoId, repoUri);
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/com/orgzly/android/repos/DirectoryRepo.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ public List<VersionedRook> getBooks() {
return result;
}

@Override
public boolean isEncryptionEnabled() { return false; }

@Override
public String getEncryptionPassphrase() { return null; }

@Override
public VersionedRook retrieveBook(String fileName, File destinationFile) throws IOException {
Uri uri = repoUri.buildUpon().appendPath(fileName).build();
Expand Down
14 changes: 14 additions & 0 deletions app/src/main/java/com/orgzly/android/repos/DropboxRepo.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ public class DropboxRepo implements SyncRepo {
public static final String SCHEME = "dropbox";

private final Uri repoUri;
private final boolean encryptionEnabled;
private final String encryptionPassphrase;
private final DropboxClient client;

public DropboxRepo(RepoWithProps repoWithProps, Context context) {
this.repoUri = Uri.parse(repoWithProps.getRepo().getUrl());
this.encryptionEnabled = repoWithProps.getProps().containsKey("pgpPassphrase");
this.encryptionPassphrase = repoWithProps.getProps().get("pgpPassphrase");
this.client = new DropboxClient(context, repoWithProps.getRepo().getId());
}

Expand All @@ -41,6 +45,16 @@ public List<VersionedRook> getBooks() throws IOException {
return client.getBooks(repoUri);
}

@Override
public boolean isEncryptionEnabled() {
return this.encryptionEnabled;
}

@Override
public String getEncryptionPassphrase() {
return this.encryptionPassphrase;
}

@Override
public VersionedRook retrieveBook(String fileName, File file) throws IOException {
return client.download(repoUri, fileName, file);
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/com/orgzly/android/repos/GitRepo.java
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,12 @@ public Uri getUri() {
return preferences.remoteUri();
}

@Override
public boolean isEncryptionEnabled() { return false; }

@Override
public String getEncryptionPassphrase() { return null; }

public void delete(Uri deleteUri) throws IOException {
// FIXME: finish me
throw new IOException("Don't do that");
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/com/orgzly/android/repos/MockRepo.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ public Uri getUri() {
return databaseRepo.getUri();
}

@Override
public boolean isEncryptionEnabled() { return false; }

@Override
public String getEncryptionPassphrase() { return null; }

@Override
public List<VersionedRook> getBooks() throws IOException {
SystemClock.sleep(SLEEP_FOR_GET_BOOKS);
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/com/orgzly/android/repos/SyncRepo.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ public interface SyncRepo {
*/
List<VersionedRook> getBooks() throws IOException;

/**
* Whether this repo shall be treated as containing encrypted files.
*/
boolean isEncryptionEnabled();

/**
* The PGP passphrase to use for cryptography operations on files in this repo.
*/
String getEncryptionPassphrase();

/**
* Download the latest available revision of the book and store its content to {@code File}.
*/
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/com/orgzly/android/repos/WebdavRepo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,14 @@ class WebdavRepo(
return uri
}

override fun isEncryptionEnabled(): Boolean {
return false
}

override fun getEncryptionPassphrase(): String? {
return null
}

override fun getBooks(): MutableList<VersionedRook> {
val url = uri.toUrl()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import android.text.method.HideReturnsTransformationMethod
import android.text.method.PasswordTransformationMethod
import android.view.Menu
import android.view.MenuItem
import android.widget.EditText
Expand All @@ -30,6 +32,7 @@ import com.orgzly.android.util.LogUtils
import com.orgzly.android.util.MiscUtils
import com.orgzly.android.util.UriUtils
import com.orgzly.databinding.ActivityRepoDropboxBinding
import kotlinx.android.synthetic.main.activity_repo_dropbox.view.*
import javax.inject.Inject


Expand Down Expand Up @@ -90,6 +93,12 @@ class DropboxRepoActivity : CommonActivity() {
val path = Uri.parse(repoWithProps.repo.url).path

binding.activityRepoDropboxDirectory.setText(path)

val encryption = repoWithProps.props.get("pgpPassphrase")

encryption?.also {
binding.activityRepoDropboxEncryptionPassphrase.setText(it)
}
}
}

Expand Down Expand Up @@ -202,6 +211,13 @@ class DropboxRepoActivity : CommonActivity() {

val url = UriUtils.uriFromPath(DropboxRepo.SCHEME, directory).toString()

val propsMap = if (!binding.activityRepoDropboxEncryptionPassphrase.text.isNullOrEmpty()) {
val passphrase = binding.activityRepoDropboxEncryptionPassphrase.text.toString()
mapOf("pgpPassphrase" to passphrase)
} else {
emptyMap()
}

val repo = try {
viewModel.validate(RepoType.DROPBOX, url)
} catch (e: Exception) {
Expand All @@ -211,7 +227,7 @@ class DropboxRepoActivity : CommonActivity() {
return
}

viewModel.saveRepo(RepoType.DROPBOX, repo.uri.toString())
viewModel.saveRepo(RepoType.DROPBOX, repo.uri.toString(), propsMap)
}

private fun toggleLinkAfterConfirmation() {
Expand Down
Loading

0 comments on commit 90b975e

Please sign in to comment.