Skip to content
Merged
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
4 changes: 2 additions & 2 deletions ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

[ballerina]
dependencies-toml-version = "2"
distribution-version = "2201.12.0"
distribution-version = "2201.13.0-20250924-081800-3dae8c03"

[[package]]
org = "ballerina"
Expand Down Expand Up @@ -107,7 +107,7 @@ modules = [
[[package]]
org = "ballerina"
name = "time"
version = "2.7.0"
version = "2.8.0"
dependencies = [
{org = "ballerina", name = "jballerina.java"}
]
Expand Down
16 changes: 16 additions & 0 deletions ballerina/tests/encrypt_decrypt_pgp_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,19 @@ isolated function testNegativeEncryptAndDecryptStreamWithPgpInvalidPassphrase()
test:assertFail("Should return a crypto Error");
}
}

@test:Config
isolated function testInputStreamWithoutCloseForPgpEncrypt() returns error? {
byte[] passphrase = "qCr3bv@5mj5n4eY".toBytes();
string[] names = ["alice", "charlie"];
stream<byte[], error?> inputStream = from string name in names
select name.toString().toBytes();
stream<byte[], error?> encryptedStream = check encryptStreamAsPgp(inputStream, PGP_PUBLIC_KEY_PATH);
stream<byte[], error?> decryptStreamAsPgp = check decryptStreamFromPgp(encryptedStream, PGP_PRIVATE_KEY_PATH, passphrase);
byte[] actualBytes = [];
check from byte[] bytes in decryptStreamAsPgp
do {
actualBytes.push(...bytes);
};
test:assertEquals(check string:fromBytes(actualBytes), "alicecharlie");
}
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- [Update OIDS of NIST approved post quantum algorithms](https://github.com/ballerina-platform/ballerina-library/issues/7678)
- [Optimize hardcoded IV detection using semantic model reference counting](https://github.com/ballerina-platform/ballerina-library/issues/8257)

### Fixed
- [Implement optional close method check for BStream](https://github.com/ballerina-platform/ballerina-library/issues/8288)

## [2.8.0] - 2025-02-11

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
package io.ballerina.stdlib.crypto;

import io.ballerina.runtime.api.Environment;
import io.ballerina.runtime.api.types.MethodType;
import io.ballerina.runtime.api.types.ObjectType;
import io.ballerina.runtime.api.types.Type;
import io.ballerina.runtime.api.utils.StringUtils;
import io.ballerina.runtime.api.values.BArray;
import io.ballerina.runtime.api.values.BError;
Expand All @@ -27,6 +30,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Objects;

/**
Expand All @@ -48,10 +52,22 @@ public class BallerinaInputStream extends InputStream {
private final BStream ballerinaStream;
private ByteBuffer buffer = null;
private boolean endOfStream = false;
private final boolean hasCloseMethod;

public BallerinaInputStream(Environment environment, BStream ballerinaStream) {
this.ballerinaStream = ballerinaStream;
this.environment = environment;

// Implementing a close method for a Ballerina stream is optional
// There is no Ballerina runtime API to check if the stream has a close method
// So accessing the iterator object type methods to check if it has a close method
Type iteratorType = ballerinaStream.getIteratorObj().getOriginalType();
if (iteratorType instanceof ObjectType iteratorObjectType) {
MethodType[] methods = iteratorObjectType.getMethods();
hasCloseMethod = Arrays.stream(methods).anyMatch(method -> method.getName().equals(BAL_STREAM_CLOSE));
} else {
hasCloseMethod = false;
}
}

@Override
Expand All @@ -71,6 +87,9 @@ public int read() throws IOException {

@Override
public void close() throws IOException {
if (!hasCloseMethod) {
return;
}
Object result = callBalStreamMethod(BAL_STREAM_CLOSE);
if (result instanceof BError bError) {
throw new IOException((bError).getMessage());
Expand Down
Loading