Skip to content

Commit 90b975e

Browse files
committed
symmetric encryption initial version
1 parent 2953456 commit 90b975e

15 files changed

Lines changed: 374 additions & 16 deletions

File tree

app/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ dependencies {
181181
// Resolves DuplicatePlatformClasses lint error
182182
exclude group: 'org.apache.httpcomponents', module: 'httpclient'
183183
}
184+
185+
// Encryption
186+
implementation "org.bouncycastle:bcpg-jdk15on:1.65"
184187
}
185188

186189
repositories {

app/src/main/java/com/orgzly/android/BookName.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
public class BookName {
1919
private static final String TAG = BookName.class.getName();
2020

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

2424
private final String mFileName;

app/src/main/java/com/orgzly/android/data/DataRepository.kt

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ import com.orgzly.org.parser.OrgParser
5252
import com.orgzly.org.parser.OrgParserWriter
5353
import com.orgzly.org.utils.StateChangeLogic
5454
import java.io.*
55-
import java.lang.IllegalStateException
5655
import java.util.*
5756
import java.util.concurrent.Callable
5857
import javax.inject.Inject
@@ -82,7 +81,13 @@ class DataRepository @Inject constructor(
8281

8382
val fileName = BookName.getFileName(context, book)
8483

85-
val loadedBook = loadBookFromRepo(book.linkRepo.id, book.linkRepo.type, book.linkRepo.url, fileName)
84+
val loadedBook = loadBookFromRepo(
85+
book.linkRepo.id,
86+
book.linkRepo.type,
87+
book.linkRepo.url,
88+
fileName)
89+
90+
val id = loadedBook!!.book.id;
8691

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

151-
val uploadedBook: VersionedRook
156+
var uploadedBook: VersionedRook? = null
152157

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

155160
val tmpFile = getTempBookFile()
161+
val tmpFileEncrypted = getTempBookFile()
156162
try {
157163
/* Write to temporary file. */
158164
NotesOrgExporter(this).exportBook(bookView.book, tmpFile)
159165

166+
val (toStoreFile, toStoreFileName) =
167+
if (repo.isEncryptionEnabled) {
168+
val inFile: InputStream = BufferedInputStream(FileInputStream(tmpFile))
169+
val outFile: OutputStream = BufferedOutputStream(FileOutputStream(tmpFileEncrypted))
170+
171+
try {
172+
MiscUtils.pgpEncrypt(inFile, outFile, fileName, repo.encryptionPassphrase)
173+
} finally {
174+
inFile.close()
175+
outFile.close()
176+
}
177+
178+
Pair(tmpFileEncrypted, MiscUtils.ensureGpgExtensionFileName(fileName))
179+
} else {
180+
// remove possible .gpg extension left over from a previous encrypted sync
181+
// ?maybe move this logic to BookView.getFileName()
182+
Pair(tmpFile, MiscUtils.ensureNoGpgExtensionFileName(fileName))
183+
}
184+
160185
/* Upload to repo. */
161-
uploadedBook = repo.storeBook(tmpFile, fileName)
186+
uploadedBook = repo.storeBook(toStoreFile, toStoreFileName)
162187

163188
} finally {
164189
/* Delete temporary file. */
165190
tmpFile.delete()
191+
tmpFileEncrypted.delete()
166192
}
167193

168-
updateBookLinkAndSync(bookView.book.id, uploadedBook)
169-
170-
updateBookIsModified(bookView.book.id, false)
171-
194+
if (uploadedBook != null) {
195+
updateBookLinkAndSync(bookView.book.id, uploadedBook)
196+
updateBookIsModified(bookView.book.id, false)
197+
}
172198
}
173199

174200
@Throws(IOException::class)
@@ -1546,22 +1572,48 @@ class DataRepository @Inject constructor(
15461572

15471573
@Throws(IOException::class)
15481574
fun loadBookFromRepo(repoId: Long, repoType: RepoType, repoUrl: String, fileName: String): BookView? {
1549-
val book: BookView?
1575+
var book: BookView? = null
15501576

15511577
val repo = getRepoInstance(repoId, repoType, repoUrl)
15521578

15531579
val tmpFile = getTempBookFile()
1580+
val tmpFileDecrypted = getTempBookFile()
15541581
try {
15551582
/* Download from repo. */
1556-
val vrook = repo.retrieveBook(fileName, tmpFile)
1583+
// ensure that we don't try to decrypt .org files or interpret .org.gpg as plaintext
1584+
// problem if both 'nb.org' and 'nb.org.gpg' exist. probably some other mechanism that
1585+
// runs at a higher level that here should be made aware and responsible of .pgp extensions
1586+
val toRecvFileName = if (repo.isEncryptionEnabled) {
1587+
MiscUtils.ensureGpgExtensionFileName(fileName)
1588+
} else {
1589+
MiscUtils.ensureNoGpgExtensionFileName(fileName)
1590+
}
1591+
val vrook = repo.retrieveBook(toRecvFileName, tmpFile)
1592+
1593+
val plaintextBookFile: File =
1594+
if (repo.isEncryptionEnabled) {
1595+
val inFile: InputStream = BufferedInputStream(FileInputStream(tmpFile))
1596+
val outFile: OutputStream = BufferedOutputStream(FileOutputStream(tmpFileDecrypted))
1597+
1598+
try {
1599+
MiscUtils.pgpDecrypt(inFile, outFile, repo.encryptionPassphrase)
1600+
} finally {
1601+
inFile.close()
1602+
outFile.close()
1603+
}
15571604

1558-
val bookName = BookName.fromFileName(fileName)
1605+
tmpFileDecrypted
1606+
} else {
1607+
tmpFile
1608+
}
15591609

1560-
/* Store from file to Shelf. */
1561-
book = loadBookFromFile(bookName.name, bookName.format, tmpFile, vrook)
1610+
val bookName = BookName.fromFileName(toRecvFileName)
15621611

1612+
/* Store from file to Shelf. */
1613+
book = loadBookFromFile(bookName.name, bookName.format, plaintextBookFile, vrook)
15631614
} finally {
15641615
tmpFile.delete()
1616+
tmpFileDecrypted.delete()
15651617
}
15661618

15671619
return book

app/src/main/java/com/orgzly/android/repos/ContentRepo.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ public Uri getUri() {
6262
return repoUri;
6363
}
6464

65+
@Override
66+
public boolean isEncryptionEnabled() { return false; }
67+
68+
@Override
69+
public String getEncryptionPassphrase() { return null; }
70+
6571
@Override
6672
public List<VersionedRook> getBooks() throws IOException {
6773
List<VersionedRook> result = new ArrayList<>();

app/src/main/java/com/orgzly/android/repos/DatabaseRepo.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ public Uri getUri() {
4141
return repoUri;
4242
}
4343

44+
@Override
45+
public boolean isEncryptionEnabled() { return false; }
46+
47+
@Override
48+
public String getEncryptionPassphrase() { return null; }
49+
4450
@Override
4551
public List<VersionedRook> getBooks() {
4652
return dbRepo.getBooks(repoId, repoUri);

app/src/main/java/com/orgzly/android/repos/DirectoryRepo.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ public List<VersionedRook> getBooks() {
109109
return result;
110110
}
111111

112+
@Override
113+
public boolean isEncryptionEnabled() { return false; }
114+
115+
@Override
116+
public String getEncryptionPassphrase() { return null; }
117+
112118
@Override
113119
public VersionedRook retrieveBook(String fileName, File destinationFile) throws IOException {
114120
Uri uri = repoUri.buildUpon().appendPath(fileName).build();

app/src/main/java/com/orgzly/android/repos/DropboxRepo.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ public class DropboxRepo implements SyncRepo {
1414
public static final String SCHEME = "dropbox";
1515

1616
private final Uri repoUri;
17+
private final boolean encryptionEnabled;
18+
private final String encryptionPassphrase;
1719
private final DropboxClient client;
1820

1921
public DropboxRepo(RepoWithProps repoWithProps, Context context) {
2022
this.repoUri = Uri.parse(repoWithProps.getRepo().getUrl());
23+
this.encryptionEnabled = repoWithProps.getProps().containsKey("pgpPassphrase");
24+
this.encryptionPassphrase = repoWithProps.getProps().get("pgpPassphrase");
2125
this.client = new DropboxClient(context, repoWithProps.getRepo().getId());
2226
}
2327

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

48+
@Override
49+
public boolean isEncryptionEnabled() {
50+
return this.encryptionEnabled;
51+
}
52+
53+
@Override
54+
public String getEncryptionPassphrase() {
55+
return this.encryptionPassphrase;
56+
}
57+
4458
@Override
4559
public VersionedRook retrieveBook(String fileName, File file) throws IOException {
4660
return client.download(repoUri, fileName, file);

app/src/main/java/com/orgzly/android/repos/GitRepo.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,12 @@ public Uri getUri() {
298298
return preferences.remoteUri();
299299
}
300300

301+
@Override
302+
public boolean isEncryptionEnabled() { return false; }
303+
304+
@Override
305+
public String getEncryptionPassphrase() { return null; }
306+
301307
public void delete(Uri deleteUri) throws IOException {
302308
// FIXME: finish me
303309
throw new IOException("Don't do that");

app/src/main/java/com/orgzly/android/repos/MockRepo.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ public Uri getUri() {
4444
return databaseRepo.getUri();
4545
}
4646

47+
@Override
48+
public boolean isEncryptionEnabled() { return false; }
49+
50+
@Override
51+
public String getEncryptionPassphrase() { return null; }
52+
4753
@Override
4854
public List<VersionedRook> getBooks() throws IOException {
4955
SystemClock.sleep(SLEEP_FOR_GET_BOOKS);

app/src/main/java/com/orgzly/android/repos/SyncRepo.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ public interface SyncRepo {
2727
*/
2828
List<VersionedRook> getBooks() throws IOException;
2929

30+
/**
31+
* Whether this repo shall be treated as containing encrypted files.
32+
*/
33+
boolean isEncryptionEnabled();
34+
35+
/**
36+
* The PGP passphrase to use for cryptography operations on files in this repo.
37+
*/
38+
String getEncryptionPassphrase();
39+
3040
/**
3141
* Download the latest available revision of the book and store its content to {@code File}.
3242
*/

0 commit comments

Comments
 (0)