Repository: hyperledger/quilt
Pull request #395 (2019-12-05 15:39:32)

expand decoding exception #378
Signed-off-by: Ian Simpson <ian.g.simpson@gmail.com>

codecov[bot]: # [Codecov](https://codecov.io/gh/hyperledger/quilt/pull/395?src=pr&el=h1) Report
> Merging [#395](https://codecov.io/gh/hyperledger/quilt/pull/395?src=pr&el=desc) into [master](https://codecov.io/gh/hyperledger/quilt/commit/731401ec79c9e40cc41135e9d28b0127fc95eb73?src=pr&el=desc) will **decrease** coverage by `0.13%`.
> The diff coverage is `25%`.

[![Impacted file tree graph](https://codecov.io/gh/hyperledger/quilt/pull/395/graphs/tree.svg?width=650&token=XEfCq6zC6W&height=150&src=pr)](https://codecov.io/gh/hyperledger/quilt/pull/395?src=pr&el=tree)

```diff
@@             Coverage Diff              @@
##             master     #395      +/-   ##
============================================
- Coverage     82.41%   82.28%   -0.14%     
  Complexity      826      826              
============================================
  Files           249      249              
  Lines          3742     3748       +6     
  Branches        228      229       +1     
============================================
  Hits           3084     3084              
- Misses          562      567       +5     
- Partials         96       97       +1
```


| [Impacted Files](https://codecov.io/gh/hyperledger/quilt/pull/395?src=pr&el=tree) | Coverage Δ | Complexity Δ | |
|---|---|---|---|
| [...edger/stream/receiver/StatelessStreamReceiver.java](https://codecov.io/gh/hyperledger/quilt/pull/395/diff?src=pr&el=tree#diff-c3RyZWFtLXBhcmVudC9zdHJlYW0tcmVjZWl2ZXIvc3JjL21haW4vamF2YS9vcmcvaW50ZXJsZWRnZXIvc3RyZWFtL3JlY2VpdmVyL1N0YXRlbGVzc1N0cmVhbVJlY2VpdmVyLmphdmE=) | `89.1% <25%> (-5.63%)` | `14 <0> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/hyperledger/quilt/pull/395?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/hyperledger/quilt/pull/395?src=pr&el=footer). Last update [731401e...1f715c9](https://codecov.io/gh/hyperledger/quilt/pull/395?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/stream-parent/stream-receiver/src/main/java/org/interledger/stream/receiver/StatelessStreamReceiver.java b/stream-parent/stream-receiver/src/main/java/org/interledger/stream/receiver/StatelessStreamReceiver.java
index 7c9e943..0fd1dbe 100644
--- a/stream-parent/stream-receiver/src/main/java/org/interledger/stream/receiver/StatelessStreamReceiver.java
+++ b/stream-parent/stream-receiver/src/main/java/org/interledger/stream/receiver/StatelessStreamReceiver.java
@@ -89,12 +89,19 @@ public class StatelessStreamReceiver implements StreamReceiver {
         .deriveSecretFromAddress(serverSecretSupplier, preparePacket.getDestination());
     final SharedSecret streamSharedSecret = SharedSecret.of(spspSharedSecret.key());
 
-    // Try to parse the STREAM data from the payload.
-    final byte[] streamPacketBytes = streamEncryptionService.decrypt(streamSharedSecret, preparePacket.getData());
     final StreamPacket streamPacket;
     try {
+      if (preparePacket.getData().length == 0) {
+        return InterledgerRejectPacket.builder()
+          .code(InterledgerErrorCode.F06_UNEXPECTED_PAYMENT)
+          .message("No STREAM packet bytes available to decrypt")
+          .triggeredBy(receiverAddress)
+          .build();
+      }
+      // Try to parse the STREAM data from the payload.
+      final byte[] streamPacketBytes = streamEncryptionService.decrypt(streamSharedSecret, preparePacket.getData());
       streamPacket = streamCodecContext.read(StreamPacket.class, new ByteArrayInputStream(streamPacketBytes));
-    } catch (IOException e) {
+    } catch (Exception e) {
       logger.error(
           "Unable to decrypt packet. preparePacket={} receiverAddress={} error={}",
           preparePacket, receiverAddress, e


Test patch:
diff --git a/stream-parent/stream-receiver/src/test/java/org/interledger/stream/receiver/StatelessStreamReceiverTest.java b/stream-parent/stream-receiver/src/test/java/org/interledger/stream/receiver/StatelessStreamReceiverTest.java
index 9b8d930..f8be1cc 100644
--- a/stream-parent/stream-receiver/src/test/java/org/interledger/stream/receiver/StatelessStreamReceiverTest.java
+++ b/stream-parent/stream-receiver/src/test/java/org/interledger/stream/receiver/StatelessStreamReceiverTest.java
@@ -347,7 +347,35 @@ public class StatelessStreamReceiverTest {
   }
 
   @Test
-  public void receiveMoneyWithSequencTooHighForSafeEncryption() throws Exception {
+  public void receiveMoneyWithEmptyStreamPacketRejects() throws Exception {
+    this.connectionDetails = streamConnectionGenerator.generateConnectionDetails(serverSecretSupplier, CLIENT_ADDRESS);
+
+    streamReceiver = new StatelessStreamReceiver(
+      serverSecretSupplier, streamConnectionGenerator, streamEncryptionService, StreamCodecContextFactory.oer()
+    );
+
+    InterledgerPreparePacket prepare = InterledgerPreparePacket.builder()
+      .destination(connectionDetails.destinationAddress())
+      .amount(UnsignedLong.valueOf(100L))
+      .expiresAt(Instant.EPOCH)
+      .data(new byte[0])
+      .executionCondition(InterledgerCondition.of(new byte[32]))
+      .build();
+
+    this.streamReceiver.receiveMoney(prepare, CLIENT_ADDRESS, DENOMINATION).handle(
+      fulfillPacket -> {
+        throw new RuntimeException("should have rejected");
+      },
+      rejectPacket -> assertThat(rejectPacket).extracting("code", "message", "triggeredBy")
+        .containsExactly(
+          InterledgerErrorCode.F06_UNEXPECTED_PAYMENT,
+          "No STREAM packet bytes available to decrypt",
+          Optional.of(CLIENT_ADDRESS)
+        ));
+  }
+
+  @Test
+  public void receiveMoneyWithSequenceTooHighForSafeEncryption() throws Exception {
 
     streamReceiver = new StatelessStreamReceiver(
         serverSecretSupplier, streamConnectionGenerator, streamEncryptionService, StreamCodecContextFactory.oer()