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 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
Loading