Support Android share-driven credential lookup

This commit is contained in:
Joe Julian
2026-04-23 20:51:39 -07:00
parent 515eb730f0
commit 14c9bc72f6
6 changed files with 229 additions and 2 deletions
@@ -20,6 +20,9 @@ import java.util.ArrayList;
public final class SharedVaultImportActivity extends Activity {
private static final String TAG = "KeePassGOImport";
private static final String DEFAULT_NAME = "shared-vault.kdbx";
private static final String PENDING_SHARED_VAULT = "pending-shared-vault.kdbx";
private static final String PENDING_SHARED_VAULT_NAME = "pending-shared-vault-name.txt";
private static final String PENDING_SHARED_LOOKUP = "pending-shared-lookup.txt";
@Override
protected void onCreate(Bundle state) {
@@ -40,6 +43,16 @@ public final class SharedVaultImportActivity extends Activity {
private void handleIntent(Intent intent) {
logIntent(intent);
String sharedLookup = resolveSharedLookup(intent);
if (!sharedLookup.isEmpty()) {
try {
persistPendingLookup(sharedLookup);
Log.i(TAG, "queued shared lookup target");
} catch (IOException | RuntimeException err) {
Log.e(TAG, "failed to queue shared lookup target", err);
}
return;
}
Uri uri = resolveSharedUri(intent);
if (uri == null) {
Log.i(TAG, "no shared vault URI on intent");
@@ -86,12 +99,35 @@ public final class SharedVaultImportActivity extends Activity {
return null;
}
private String resolveSharedLookup(Intent intent) {
if (intent == null) {
return "";
}
String action = intent.getAction();
if (Intent.ACTION_SEND.equals(action) && "text/plain".equalsIgnoreCase(intent.getType())) {
CharSequence extraText = intent.getCharSequenceExtra(Intent.EXTRA_TEXT);
if (extraText != null) {
return extraText.toString().trim();
}
}
if (Intent.ACTION_VIEW.equals(action)) {
Uri data = intent.getData();
if (data != null) {
String scheme = data.getScheme();
if ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) {
return data.toString();
}
}
}
return "";
}
private void persistPendingImport(Uri uri) throws IOException {
File dir = new File(getFilesDir(), "keepassgo");
if (!dir.exists() && !dir.mkdirs()) {
throw new IOException("failed to create " + dir.getAbsolutePath());
}
File pendingFile = new File(dir, "pending-shared-vault.kdbx");
File pendingFile = new File(dir, PENDING_SHARED_VAULT);
try (InputStream in = openSharedInputStream(uri)) {
if (in == null) {
throw new IOException("failed to open shared vault stream");
@@ -105,12 +141,23 @@ public final class SharedVaultImportActivity extends Activity {
}
}
File nameFile = new File(dir, "pending-shared-vault-name.txt");
File nameFile = new File(dir, PENDING_SHARED_VAULT_NAME);
try (FileOutputStream out = new FileOutputStream(nameFile, false)) {
out.write(resolveDisplayName(uri).getBytes(StandardCharsets.UTF_8));
}
}
private void persistPendingLookup(String lookup) throws IOException {
File dir = new File(getFilesDir(), "keepassgo");
if (!dir.exists() && !dir.mkdirs()) {
throw new IOException("failed to create " + dir.getAbsolutePath());
}
File pendingFile = new File(dir, PENDING_SHARED_LOOKUP);
try (FileOutputStream out = new FileOutputStream(pendingFile, false)) {
out.write(lookup.getBytes(StandardCharsets.UTF_8));
}
}
private InputStream openSharedInputStream(Uri uri) throws IOException {
if ("file".equalsIgnoreCase(uri.getScheme())) {
String path = uri.getPath();