Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate SSH keys on the device #963

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,15 @@ dependencies {

implementation "io.github.rburgst:okhttp-digest:$versions.okhttp_digest"

// Git sync over SSH
implementation "org.eclipse.jgit:org.eclipse.jgit:$versions.jgit"
implementation "org.eclipse.jgit:org.eclipse.jgit.ssh.jsch:$versions.jgit"
implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache:$versions.jgit") {
// Resolves DuplicatePlatformClasses lint error
exclude group: 'org.apache.sshd', module: 'sshd-osgi'
}
implementation 'androidx.security:security-crypto:1.1.0-alpha03'
implementation 'androidx.biometric:biometric-ktx:1.2.0-alpha04'

}

repositories {
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@
android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
</activity>

<activity
android:name=".android.ui.SshKeygenActivity"
android:windowSoftInputMode="stateAlwaysHidden">
</activity>

<activity
android:name=".android.ui.repo.webdav.WebdavRepoActivity"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/com/orgzly/android/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,7 @@ public static Context getAppContext() {
public static void setCurrentActivity(CommonActivity currentCommonActivity) {
currentActivity = currentCommonActivity;
}

public static CommonActivity getCurrentActivity() { return currentActivity; }

}
4 changes: 4 additions & 0 deletions app/src/main/java/com/orgzly/android/AppIntent.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public class AppIntent {

public static final String ACTION_SHOW_SNACKBAR = "com.orgzly.intent.action.SHOW_SNACKBAR";

public static final String ACTION_REJECT_REMOTE_HOST_KEY = "com.orgzly.intent.action.REJECT_REMOTE_HOST_KEY";
public static final String ACTION_ACCEPT_REMOTE_HOST_KEY = "com.orgzly.intent.action.ACCEPT_REMOTE_HOST_KEY";
public static final String ACTION_ACCEPT_AND_STORE_REMOTE_HOST_KEY = "com.orgzly.intent.action.ACCEPT_AND_STORE_REMOTE_HOST_KEY";

public static final String EXTRA_MESSAGE = "com.orgzly.intent.extra.MESSAGE";
public static final String EXTRA_BOOK_ID = "com.orgzly.intent.extra.BOOK_ID";
public static final String EXTRA_BOOK_PREFACE = "com.orgzly.intent.extra.BOOK_PREFACE";
Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/com/orgzly/android/NotificationChannels.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ object NotificationChannels {
const val REMINDERS = "reminders"
const val SYNC_PROGRESS = "sync-progress"
const val SYNC_FAILED = "sync-failed"
const val SYNC_PROMPT = "sync-prompt"

@JvmStatic
fun createAll(context: Context) {
Expand All @@ -28,6 +29,7 @@ object NotificationChannels {
createForReminders(context)
createForSyncProgress(context)
createForSyncFailed(context)
createForSyncPrompt(context)
}
}

Expand Down Expand Up @@ -111,4 +113,25 @@ object NotificationChannels {

context.getNotificationManager().createNotificationChannel(channel)
}

@RequiresApi(Build.VERSION_CODES.O)
private fun createForSyncPrompt(context: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return
}

val id = SYNC_PROMPT
val name = "Sync prompt"
val description = "Display sync prompt"
val importance = NotificationManager.IMPORTANCE_HIGH

val channel = NotificationChannel(id, name, importance)

channel.description = description

channel.setShowBadge(false)

val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
mNotificationManager.createNotificationChannel(channel)
}
}
96 changes: 58 additions & 38 deletions app/src/main/java/com/orgzly/android/git/GitFileSynchronizer.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.orgzly.android.git;

import static com.orgzly.android.ui.AppSnackbarUtils.showSnackbar;

import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.util.Log;

import androidx.annotation.NonNull;

import com.orgzly.R;
import com.orgzly.android.App;
import com.orgzly.android.util.MiscUtils;

Expand All @@ -14,14 +18,14 @@
import org.eclipse.jgit.api.MergeResult;
import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.TransportCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.treewalk.TreeWalk;

import java.io.File;
Expand All @@ -33,14 +37,18 @@
import java.util.TimeZone;

public class GitFileSynchronizer {
private static String TAG = GitFileSynchronizer.class.getSimpleName();
private final static String TAG = GitFileSynchronizer.class.getSimpleName();

private final Git git;
private final GitPreferences preferences;
private final Context context;
private final Activity currentActivity = App.getCurrentActivity();

private Git git;
private GitPreferences preferences;

public GitFileSynchronizer(Git g, GitPreferences prefs) {
git = g;
preferences = prefs;
context = App.getAppContext();
}

private GitTransportSetter transportSetter() {
Expand All @@ -67,12 +75,17 @@ public void retrieveLatestVersionOfFile(
MiscUtils.copyFile(repoDirectoryFile(repositoryPath), destination);
}

private void fetch() throws GitAPIException {
transportSetter()
.setTransport(git.fetch()
.setRemote(preferences.remoteName())
.setRemoveDeletedRefs(true))
.call();
private void fetch() throws IOException {
try {
transportSetter()
.setTransport(git.fetch()
.setRemote(preferences.remoteName())
.setRemoveDeletedRefs(true))
.call();
} catch (GitAPIException e) {
e.printStackTrace();
throw new IOException(e.getMessage());
}
}

public void checkoutSelected() throws GitAPIException {
Expand All @@ -93,22 +106,6 @@ public boolean mergeWithRemote() throws IOException {
return false;
}

public boolean mergeAndPushToRemote() throws IOException {
boolean success = mergeWithRemote();
if (success) try {
transportSetter().setTransport(git.push().setRemote(preferences.remoteName())).call();
} catch (GitAPIException e) {}
return success;
}

public void updateAndCommitFileFromRevision(
File sourceFile, String repositoryPath,
ObjectId fileRevision, RevCommit revision) throws IOException {
ensureRepoIsClean();
if (updateAndCommitFileFromRevision(sourceFile, repositoryPath, fileRevision))
return;
}

private String getShortHash(ObjectId hash) {
String shortHash = hash.getName();
try {
Expand Down Expand Up @@ -140,8 +137,8 @@ public boolean updateAndCommitFileFromRevisionAndMerge(
try {
git.branchDelete().setBranchNames(mergeBranch).call();
} catch (GitAPIException e) {}
Boolean mergeSucceeded = true;
Boolean doCleanup = false;
boolean mergeSucceeded = true;
boolean doCleanup = false;
try {
RevCommit mergeTarget = currentHead();
// Try to use the branch "orgzly-pre-sync-marker" to find a good point for branching off.
Expand Down Expand Up @@ -239,16 +236,38 @@ public void tryPushIfHeadDiffersFromRemote() {
}

public void tryPush() {
final TransportCommand pushCommand = transportSetter().setTransport(
final var pushCommand = transportSetter().setTransport(
git.push().setRemote(preferences.remoteName()));
final Object monitor = new Object();

App.EXECUTORS.diskIO().execute(() -> {
try {
pushCommand.call();
Iterable<PushResult> results = (Iterable<PushResult>) pushCommand.call();
// org.eclipse.jgit.api.PushCommand swallows some errors without throwing exceptions.
if (!results.iterator().next().getMessages().isEmpty()) {
if (currentActivity != null) {
showSnackbar(currentActivity, results.iterator().next().getMessages());
}
}
synchronized (monitor) {
monitor.notify();
}
} catch (GitAPIException e) {
e.printStackTrace();
if (currentActivity != null) {
showSnackbar(
currentActivity,
String.format("Failed to push to remote: %s", e.getMessage())
);
}
}
});
synchronized (monitor) {
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

private void gitResetMerge() throws IOException, GitAPIException {
Expand All @@ -274,7 +293,11 @@ public void setBranchAndGetLatest() throws IOException {
// Point a "marker" branch to the current head, so that we know a good starting commit
// for merge conflict branches.
git.branchCreate().setName("orgzly-pre-sync-marker").setForce(true).call();
fetch();
} catch (GitAPIException e) {
throw new IOException(context.getString(R.string.git_sync_error_failed_set_marker_branch));
}
fetch();
try {
RevCommit current = currentHead();
RevCommit mergeTarget = getCommit(
String.format("%s/%s", preferences.remoteName(), git.getRepository().getBranch()));
Expand All @@ -290,8 +313,7 @@ public void setBranchAndGetLatest() throws IOException {
}
}
} catch (GitAPIException e) {
e.printStackTrace();
throw new IOException("Failed to update from remote");
throw new IOException(e.getMessage());
}
}

Expand Down Expand Up @@ -348,7 +370,7 @@ public void addAndCommitNewFile(File sourceFile, String repositoryPath) throws I
updateAndCommitFile(sourceFile, repositoryPath);
}

private RevCommit updateAndCommitFile(
private void updateAndCommitFile(
File sourceFile, String repositoryPath) throws IOException {
File destinationFile = repoDirectoryFile(repositoryPath);
MiscUtils.copyFile(sourceFile, destinationFile);
Expand All @@ -359,7 +381,6 @@ private RevCommit updateAndCommitFile(
} catch (GitAPIException e) {
throw new IOException("Failed to commit changes.");
}
return currentHead();
}

private void commit(String message) throws GitAPIException {
Expand Down Expand Up @@ -414,9 +435,8 @@ public boolean isEmptyRepo() throws IOException{
}

public ObjectId getFileRevision(String pathString, RevCommit commit) throws IOException {
ObjectId objectId = TreeWalk.forPath(
return TreeWalk.forPath(
git.getRepository(), pathString, commit.getTree()).getObjectId(0);
return objectId;
}

public boolean fileMatchesInRevisions(String pathString, RevCommit start, RevCommit end)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ public GitTransportSetter createTransportSetter() {
return new HTTPSTransportSetter(username, password);
} else {
// assume SSH, since ssh:// usually isn't specified as the scheme when cloning via SSH.
String sshKeyPath = repoPreferences.getStringValueWithGlobalDefault(
R.string.pref_key_git_ssh_key_path, "orgzly");
return new GitSSHKeyTransportSetter(sshKeyPath);
return new GitSshKeyTransportSetter();
}
}

Expand Down

This file was deleted.

Loading