BackupOperation extends BaseOperation<BackupKeyringParcel> { @NonNull public ExportResult execute(@NonNull BackupKeyringParcel backupInput, @Nullable CryptoInputParcel cryptoInput) { return execute(backupInput, cryptoInput, null); } BackupOperation(Context context, KeyRepository keyRepository, Progressable
            progressable);  BackupOperation(Context context, KeyRepository keyRepository,
                           Progressable progressable, AtomicBoolean cancelled); @NonNull ExportResult execute(@NonNull BackupKeyringParcel backupInput, @Nullable CryptoInputParcel cryptoInput); @NonNull ExportResult execute(@NonNull BackupKeyringParcel backupInput, @Nullable CryptoInputParcel cryptoInput,
                                OutputStream outputStream);  }
@Test public void testExportUnencrypted() throws Exception { ContentResolver mockResolver = mock(ContentResolver.class); Uri fakeOutputUri = Uri.parse("content: ByteArrayOutputStream outStream1 = new ByteArrayOutputStream(); when(mockResolver.openOutputStream(fakeOutputUri)).thenReturn(outStream1); Application spyApplication = spy(RuntimeEnvironment.application); when(spyApplication.getContentResolver()).thenReturn(mockResolver); BackupOperation op = new BackupOperation(spyApplication, KeyWritableRepository.create(RuntimeEnvironment.application), null); BackupKeyringParcel parcel = BackupKeyringParcel.create( new long[] { mStaticRing1.getMasterKeyId() }, false, false, true, fakeOutputUri); ExportResult result = op.execute(parcel, null); verify(mockResolver).openOutputStream(fakeOutputUri); assertTrue("export must succeed", result.success()); TestingUtils.assertArrayEqualsPrefix("exported data must start with ascii armor header", "-----BEGIN PGP PUBLIC KEY BLOCK-----\n".getBytes(), outStream1.toByteArray()); TestingUtils.assertArrayEqualsSuffix("exported data must end with ascii armor header", "-----END PGP PUBLIC KEY BLOCK-----\n".getBytes(), outStream1.toByteArray()); { IteratorWithIOThrow<UncachedKeyRing> unc = UncachedKeyRing.fromStream(new ByteArrayInputStream(outStream1.toByteArray())); assertTrue("export must have one key", unc.hasNext()); UncachedKeyRing ring = unc.next(); Assert.assertEquals("exported key has correct masterkeyid", mStaticRing1.getMasterKeyId(), ring.getMasterKeyId()); assertFalse("export must have exactly one key", unc.hasNext()); } }
@Test public void testExportEncrypted() throws Exception { Application spyApplication; ContentResolver mockResolver = mock(ContentResolver.class); Uri fakePipedUri, fakeOutputUri; ByteArrayOutputStream outStream; { fakePipedUri = Uri.parse("content: PipedInputStream pipedInStream = new PipedInputStream(8192); PipedOutputStream pipedOutStream = new PipedOutputStream(pipedInStream); when(mockResolver.openOutputStream(fakePipedUri)).thenReturn(pipedOutStream); when(mockResolver.openInputStream(fakePipedUri)).thenReturn(pipedInStream); when(mockResolver.insert(eq(TemporaryFileProvider.CONTENT_URI), any(ContentValues.class))) .thenReturn(fakePipedUri); fakeOutputUri = Uri.parse("content: outStream = new ByteArrayOutputStream(); when(mockResolver.openOutputStream(fakeOutputUri)).thenReturn(outStream); spyApplication = spy(RuntimeEnvironment.application); when(spyApplication.getContentResolver()).thenReturn(mockResolver); } Passphrase passphrase = new Passphrase("abcde"); { BackupOperation op = new BackupOperation(spyApplication, KeyWritableRepository.create(RuntimeEnvironment.application), null); BackupKeyringParcel parcel = BackupKeyringParcel.create( new long[] { mStaticRing1.getMasterKeyId() }, false, true, true, fakeOutputUri); CryptoInputParcel inputParcel = CryptoInputParcel.createCryptoInputParcel(passphrase); ExportResult result = op.execute(parcel, inputParcel); verify(mockResolver).openOutputStream(fakePipedUri); verify(mockResolver).openInputStream(fakePipedUri); verify(mockResolver).openOutputStream(fakeOutputUri); assertTrue("export must succeed", result.success()); TestingUtils.assertArrayEqualsPrefix("exported data must start with ascii armor header", "-----BEGIN PGP MESSAGE-----\n".getBytes(), outStream.toByteArray()); } { PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application, KeyWritableRepository.create(RuntimeEnvironment.application), null); PgpDecryptVerifyInputParcel input = PgpDecryptVerifyInputParcel.builder() .setAllowSymmetricDecryption(true) .setInputBytes(outStream.toByteArray()) .build(); { DecryptVerifyResult result = op.execute(input, CryptoInputParcel.createCryptoInputParcel()); assertTrue("decryption must return pending without passphrase", result.isPending()); Assert.assertTrue("should contain pending passphrase log entry", result.getLog().containsType(LogType.MSG_DC_PENDING_PASSPHRASE)); } { DecryptVerifyResult result = op.execute(input, CryptoInputParcel.createCryptoInputParcel(new Passphrase("bad"))); assertFalse("decryption must fail with bad passphrase", result.success()); Assert.assertTrue("should contain bad passphrase log entry", result.getLog().containsType(LogType.MSG_DC_ERROR_SYM_PASSPHRASE)); } DecryptVerifyResult result = op.execute(input, CryptoInputParcel.createCryptoInputParcel(passphrase)); assertTrue("decryption must succeed with passphrase", result.success()); assertEquals("backup filename should be backup_keyid.pub.asc", "backup_" + KeyFormattingUtils.convertKeyIdToHex(mStaticRing1.getMasterKeyId()) + ".pub.asc", result.getDecryptionMetadata().getFilename()); assertEquals("mime type for pgp keys must be correctly detected", "application/pgp-keys", result.getDecryptionMetadata().getMimeType()); TestingUtils.assertArrayEqualsPrefix("exported data must start with ascii armor header", "-----BEGIN PGP PUBLIC KEY BLOCK-----\n".getBytes(), result.getOutputBytes()); TestingUtils.assertArrayEqualsSuffix("exported data must end with ascii armor header", "-----END PGP PUBLIC KEY BLOCK-----\n".getBytes(), result.getOutputBytes()); { IteratorWithIOThrow<UncachedKeyRing> unc = UncachedKeyRing.fromStream(new ByteArrayInputStream(result.getOutputBytes())); assertTrue("export must have one key", unc.hasNext()); UncachedKeyRing ring = unc.next(); Assert.assertEquals("exported key has correct masterkeyid", mStaticRing1.getMasterKeyId(), ring.getMasterKeyId()); assertFalse("export must have exactly one key", unc.hasNext()); } } }