Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

impr(android): implement TLSv3 support #11195

Merged
merged 12 commits into from
Sep 18, 2019
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public class NetworkModule extends KrollModule
public static final int TLS_VERSION_1_1 = 2;
@Kroll.constant
public static final int TLS_VERSION_1_2 = 3;
@Kroll.constant
public static final int TLS_VERSION_1_3 = 4;

@Kroll.constant
public static final int PROGRESS_UNKNOWN = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ public class TiSocketFactory extends SSLSocketFactory
private SSLContext sslContext;
private String tlsVersion;
private static final String TAG = "TiSocketFactory";
private static final boolean JELLYBEAN_OR_GREATER = (Build.VERSION.SDK_INT >= 16);
private static final boolean JELLYBEAN_OR_GREATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
private static final boolean Q_OR_GREATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
private static final String TLS_VERSION_1_3_PROTOCOL = "TLSv1.3";
private static final String TLS_VERSION_1_2_PROTOCOL = "TLSv1.2";
private static final String TLS_VERSION_1_1_PROTOCOL = "TLSv1.1";
private static final String TLS_VERSION_1_0_PROTOCOL = "TLSv1";
Expand All @@ -43,9 +45,17 @@ public TiSocketFactory(KeyManager[] keyManagers, TrustManager[] trustManagers, i
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
{
super();
//super(null,null,null,null,null,null);
switch (protocol) {

// Select appropriate default based on Android version.
if (protocol == NetworkModule.TLS_DEFAULT) {
if (Q_OR_GREATER) {
protocol = NetworkModule.TLS_VERSION_1_3;
} else if (JELLYBEAN_OR_GREATER) {
protocol = NetworkModule.TLS_VERSION_1_2;
}
}

switch (protocol) {
case NetworkModule.TLS_VERSION_1_0:
tlsVersion = TLS_VERSION_1_0_PROTOCOL;
enabledProtocols = new String[] { TLS_VERSION_1_0_PROTOCOL };
Expand All @@ -59,18 +69,17 @@ public TiSocketFactory(KeyManager[] keyManagers, TrustManager[] trustManagers, i
enabledProtocols =
new String[] { TLS_VERSION_1_0_PROTOCOL, TLS_VERSION_1_1_PROTOCOL, TLS_VERSION_1_2_PROTOCOL };
break;
case NetworkModule.TLS_VERSION_1_3:
tlsVersion = TLS_VERSION_1_3_PROTOCOL;
enabledProtocols = new String[] { TLS_VERSION_1_0_PROTOCOL, TLS_VERSION_1_1_PROTOCOL,
TLS_VERSION_1_2_PROTOCOL, TLS_VERSION_1_3_PROTOCOL };
break;
default:
Log.e(TAG, "Incorrect TLS version was set in HTTPClient. Reverting to default TLS version.");
case NetworkModule.TLS_DEFAULT:
if (JELLYBEAN_OR_GREATER) {
tlsVersion = TLS_VERSION_1_2_PROTOCOL;
enabledProtocols =
new String[] { TLS_VERSION_1_0_PROTOCOL, TLS_VERSION_1_1_PROTOCOL, TLS_VERSION_1_2_PROTOCOL };
} else {
tlsVersion = TLS_VERSION_1_0_PROTOCOL;
enabledProtocols = new String[] { TLS_VERSION_1_0_PROTOCOL };
Log.i(TAG, tlsVersion + " protocol is being used. It is a less-secure version.");
}
tlsVersion = TLS_VERSION_1_0_PROTOCOL;
enabledProtocols = new String[] { TLS_VERSION_1_0_PROTOCOL };
Log.i(TAG, tlsVersion + " protocol is being used. It is a less-secure version.");
break;
}

Expand Down
5 changes: 5 additions & 0 deletions apidoc/Titanium/Network/HTTPClient.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ description: |
<td>4.1+</td>
<td>5.0+</td>
</tr>
<tr>
<th align="left">TLS 1.3</th>
<td>10.0+</td>
<td>12.2+</td>
</tr>
</tbody>
</table>

Expand Down
8 changes: 8 additions & 0 deletions apidoc/Titanium/Network/Network.yml
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,14 @@ properties:
platforms: [android, iphone, ipad]
osver: {android: {min: "4.1"}, ios: {min: "5.0"}}

- name: TLS_VERSION_1_3
summary: Constant value specifying TLS version 1.3 for SSL.
type: Number
permission: read-only
since: {android: "8.3.0", iphone: "8.3.0", ipad: "8.3.0"}
platforms: [android, iphone, ipad]
osver: {android: {min: "10.0"}, ios: {min: "12.2"}}

- name: PROGRESS_UNKNOWN
summary: Constant value specifying that the progress of a download can not be calculated.
type: Number
Expand Down
35 changes: 35 additions & 0 deletions tests/Resources/ti.network.httpclient.addontest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Appcelerator Titanium Mobile
* Copyright (c) 2019 Axway, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
/* eslint-env mocha */
/* eslint no-unused-expressions: "off" */
'use strict';
var should = require('./utilities/assertions');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ tests/Resources/ti.network.httpclient.addontest.js line 10 – 'should' is assigned a value but never used. (no-unused-vars)


describe('Titanium.Network.HTTPClient', function () {
this.timeout(6e4);

it.android('TLSv3 support', function (finish) {
// Only supported on Android 10+
if (parseInt(Ti.Platform.version.split('.')[0]) < 10) {
return finish();
}

const client = Ti.Network.createHTTPClient({
onload: e => {
const html = e.source.responseText;
if (html.includes('protocol_ssl3">Yes')) {
finish();
}
},
onerror:
e => { finish(new Error('Could not determine TLSv3 support.')); },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ tests/Resources/ti.network.httpclient.addontest.js line 29 – 'e' is defined but never used. Allowed unused args must match /^_.+/u. (no-unused-vars)

timeout: 8000
});
client.open('GET', 'https://ssllabs.com/ssltest/viewMyClient.html');
client.send();
});
});
97 changes: 97 additions & 0 deletions tests/Resources/ti.network.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Appcelerator Titanium Mobile
* Copyright (c) 2011-Present by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
/* eslint-env mocha */
/* eslint no-unused-expressions: "off" */
'use strict';
var should = require('./utilities/assertions');

describe('Titanium.Network', function () {

// Constants
var NETWORK_TYPES = [ 'NETWORK_LAN', 'NETWORK_MOBILE', 'NETWORK_NONE', 'NETWORK_UNKNOWN', 'NETWORK_WIFI' ],
NOTIFICATION_TYPES = [ 'NOTIFICATION_TYPE_ALERT', 'NOTIFICATION_TYPE_BADGE', 'NOTIFICATION_TYPE_NEWSSTAND', 'NOTIFICATION_TYPE_SOUND' ],
TLS_VERSIONS = [ 'TLS_VERSION_1_0', 'TLS_VERSION_1_1', 'TLS_VERSION_1_2', 'TLS_VERSION_1_3' ],
i;
// TODO Test that each group has unique values!
for (i = 0; i < NETWORK_TYPES.length; i++) {
it(NETWORK_TYPES[i], function () { // eslint-disable-line no-loop-func
should(Ti.Network).have.constant(NETWORK_TYPES[i]).which.is.a.Number;
});
}
for (i = 0; i < NOTIFICATION_TYPES.length; i++) {
// iOS-specific properties
it.ios(NOTIFICATION_TYPES[i], function () { // eslint-disable-line no-loop-func
should(Ti.Network).have.constant(NOTIFICATION_TYPES[i]).which.is.a.Number;
});
}
for (i = 0; i < TLS_VERSIONS.length; i++) {
// FIXME Fails on Android and iOS for some reason! They say they're undefined, not Number
// FIXME Windows fails to find the property up the prototype chain in utilities/assertions, line 33
it.allBroken(TLS_VERSIONS[i], function () { // eslint-disable-line no-loop-func
should(Ti.Network).have.constant(TLS_VERSIONS[i]).which.is.a.Number;
});
}

it('PROGRESS_UNKNOWN', function () {
should(Ti.Network).have.constant('PROGRESS_UNKNOWN').which.is.a.Number;
});

// Properties
it('apiName', function () {
should(Ti.Network).have.a.readOnlyProperty('apiName').which.is.a.String;
should(Ti.Network.apiName).be.eql('Ti.Network');
});

it('networkType', function () {
should(Ti.Network).have.a.readOnlyProperty('networkType').which.is.a.Number;
// Has to be one of the defined constants
should([ Ti.Network.NETWORK_LAN,
Ti.Network.NETWORK_MOBILE,
Ti.Network.NETWORK_NONE,
Ti.Network.NETWORK_UNKNOWN,
Ti.Network.NETWORK_WIFI ].indexOf(Ti.Network.networkType)).not.eql(-1);
});

it('networkTypeName', function () {
should(Ti.Network).have.a.readOnlyProperty('networkTypeName').which.is.a.String;
if (Ti.Network.networkType == Ti.Network.NETWORK_LAN) { // eslint-disable-line eqeqeq
Ti.Network.networkTypeName.should.eql('LAN');
} else if (Ti.Network.networkType == Ti.Network.NETWORK_MOBILE) { // eslint-disable-line eqeqeq
Ti.Network.networkTypeName.should.eql('MOBILE');
} else if (Ti.Network.networkType == Ti.Network.NETWORK_NONE) { // eslint-disable-line eqeqeq
Ti.Network.networkTypeName.should.eql('NONE');
} else if (Ti.Network.networkType == Ti.Network.NETWORK_UNKNOWN) { // eslint-disable-line eqeqeq
Ti.Network.networkTypeName.should.eql('UNKNOWN');
} else if (Ti.Network.networkType == Ti.Network.NETWORK_WIFI) { // eslint-disable-line eqeqeq
Ti.Network.networkTypeName.should.eql('WIFI');
}
});

it('online', function () {
should(Ti.Network).have.a.readOnlyProperty('online').which.is.a.Boolean;
});

// Methods
// These seem to "intermittently" be unefined on Windows!
it.windowsBroken('encodeURIComponent()', function () {
var text;
should(Ti.Network.encodeURIComponent).be.a.Function;
text = Ti.Network.encodeURIComponent('Look what I found! I like this:');
text.should.eql('Look%20what%20I%20found!%20I%20like%20this%3A');
});

it.windowsBroken('decodeURIComponent()', function () {
var text;
should(Ti.Network.decodeURIComponent).be.a.Function;
text = Ti.Network.decodeURIComponent('Look%20what%20I%20found!%20I%20like%20this%3A');
text.should.eql('Look what I found! I like this:');
});

it('createHTTPClient()', function () {
should(Ti.Network.createHTTPClient).be.a.Function;
});
});