Skip to content

Commit

Permalink
Upgrade to jni/jnigen 0.14.0 (#1707)
Browse files Browse the repository at this point in the history
  • Loading branch information
brianquinlan authored Feb 5, 2025
1 parent c7cc4f8 commit 2e1a9a6
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 22 deletions.
4 changes: 2 additions & 2 deletions pkgs/ok_http/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

- `OkHttpClient` now receives an `OkHttpClientConfiguration` to configure the client on a per-call basis.
- `OkHttpClient` supports setting four types of timeouts: [`connectTimeout`](https://square.github.io/okhttp/5.x/okhttp/okhttp3/-ok-http-client/-builder/connect-timeout.html), [`readTimeout`](https://square.github.io/okhttp/5.x/okhttp/okhttp3/-ok-http-client/-builder/read-timeout.html), [`writeTimeout`](https://square.github.io/okhttp/5.x/okhttp/okhttp3/-ok-http-client/-builder/write-timeout.html), and [`callTimeout`](https://square.github.io/okhttp/5.x/okhttp/okhttp3/-ok-http-client/-builder/call-timeout.html), using the `OkHttpClientConfiguration`.
- Upgrade to `jni` 0.13.0
- Upgrade to `jnigen` 0.13.1
- Upgrade to `jni` 0.14.0
- Upgrade to `jnigen` 0.14.0
- `OKHttpClient` supports client certificates.

## 0.1.0
Expand Down
20 changes: 20 additions & 0 deletions pkgs/ok_http/example/integration_test/certificate_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ void main() async {
expect(chain[0].getType()!.toDartString(), 'X.509');
});

test('no key', () async {
final certBytes =
await loadCertificateBytes('test_certs/server_chain.p12');
expect(
() => loadPrivateKeyAndCertificateChainFromPKCS12(
certBytes, 'dartdart'),
throwsA(isA<ArgumentError>()
.having((e) => e.message, 'toString', contains('no key'))));
});

test('no chain', () async {
final certBytes =
await loadCertificateBytes('test_certs/server_key.p12');
expect(
() => loadPrivateKeyAndCertificateChainFromPKCS12(
certBytes, 'dartdart'),
throwsA(isA<ArgumentError>().having((e) => e.message, 'toString',
contains('no certificate chain'))));
});

test('bad password', () async {
final certBytes =
await loadCertificateBytes('test_certs/test-combined.p12');
Expand Down
41 changes: 23 additions & 18 deletions pkgs/ok_http/lib/src/ok_http_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ import 'package:jni/jni.dart';
import 'jni/bindings.dart' as bindings;
import 'jni/bindings.dart' show PrivateKey, X509Certificate;

extension on List<int> {
JByteArray toJByteArray() => JByteArray(length)..setRange(0, length, this);
}

class _JavaIOException extends IOException {
final String _message;
_JavaIOException(JniException e) : _message = e.message;
Expand Down Expand Up @@ -154,14 +150,20 @@ Future<String?> choosePrivateKeyAlias({
}
try {
keyStore.load(
bindings.ByteArrayInputStream(pkcs12Data.toJByteArray()), jPassword);
bindings.ByteArrayInputStream(JByteArray.from(pkcs12Data)), jPassword);
} on JniException catch (e) {
if (e.message.contains('java.io.IOException')) {
throw _JavaIOException(e);
}
}

assert(keyStore.size() == 1, 'unexpected KeyStore size: ${keyStore.size()}');
if (keyStore.size() == 0) {
throw ArgumentError('no key in PKC12 data', 'pkcs12Data');
}

if (keyStore.size() > 1) {
throw ArgumentError('multiple entries in PKC12 data', 'pkcs12Data');
}

final aliases = keyStore.aliases()!;
final jAlias = aliases.nextElement()!;
Expand All @@ -175,11 +177,17 @@ Future<String?> choosePrivateKeyAlias({
throw ArgumentError('no certificate chain in PKC12 data', 'pkcs12Data');
}

// TODO: Add `isA` type checks when
// https://github.com/dart-lang/native/pull/1943 is released.
if (!pk.isA(PrivateKey.type)) {
throw ArgumentError('certificate key is not a PrivateKey', 'pkcs12Data');
}

final certificates =
jCertificates.map((c) => c!.as(X509Certificate.type)).toList();
final certificates = jCertificates.map((c) {
if (c == null || !c.isA(X509Certificate.type)) {
throw ArgumentError(
'certificate chain contains non-X509 certificates', 'pkcs12Data');
}
return c.as(X509Certificate.type);
}).toList();
return (pk.as(PrivateKey.type), certificates);
}

Expand Down Expand Up @@ -241,14 +249,11 @@ class OkHttpClient extends BaseClient {
final trustManagers = JArray(bindings.TrustManager.nullableType, 1);

if (clientPrivateKey != null && clientCertificateChain != null) {
// TODO: Switch to `JArray.of` when package:jnigen 0.20 is released.
// This does not work if `clientCertificateChain` is empty list.
final chain = JArray.filled(
clientCertificateChain.length, clientCertificateChain[0])
..setRange(0, clientCertificateChain.length, clientCertificateChain);
final foo = bindings.FixedResponseX509ExtendedKeyManager(
final chain =
JArray.of(bindings.X509Certificate.type, clientCertificateChain);
final keyManager = bindings.FixedResponseX509ExtendedKeyManager(
chain, clientPrivateKey, 'DUMMY'.toJString());
keyManagers = JArray.filled(1, foo.as(bindings.KeyManager.type),
keyManagers = JArray.filled(1, keyManager.as(bindings.KeyManager.type),
E: bindings.KeyManager.type);
}

Expand Down Expand Up @@ -357,7 +362,7 @@ class OkHttpClient extends BaseClient {
// So, we need to handle this case separately.
bindings.RequestBody? okReqBody;
if (requestMethod != 'GET' && requestMethod != 'HEAD') {
okReqBody = bindings.RequestBody.create$10(requestBody.toJByteArray());
okReqBody = bindings.RequestBody.create$10(JByteArray.from(requestBody));
}

reqBuilder.method(
Expand Down
4 changes: 2 additions & 2 deletions pkgs/ok_http/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ dependencies:
sdk: flutter
http: ^1.2.1
http_profile: ^0.1.0
jni: ^0.13.0
jni: ^0.14.0
plugin_platform_interface: ^2.0.2
web_socket: ^0.1.5

dev_dependencies:
dart_flutter_team_lints: ^3.0.0
jnigen: ^0.13.1
jnigen: ^0.14.0

flutter:
plugin:
Expand Down

0 comments on commit 2e1a9a6

Please sign in to comment.