diff --git a/.gitignore b/.gitignore
index 4c4a9fbb..e6bb527a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
node_modules/**
test/e2e-app-template/www/certificates/*.cer
+test/e2e-app-template/www/certificates/*.pkcs
tags
.zedstate
npm-debug.log
diff --git a/package.json b/package.json
index 22d5991e..9c00c42c 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "2.0.9",
"description": "Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning",
"scripts": {
- "updatecert": "node ./scripts/update-test-cert.js",
+ "updatecert": "node ./scripts/update-e2e-server-cert.js && node ./scripts/update-e2e-client-cert.js",
"buildbrowser": "./scripts/build-test-app.sh --browser",
"testandroid": "npm run updatecert && ./scripts/build-test-app.sh --android --emulator && ./scripts/test-app.sh --android --emulator",
"testios": "npm run updatecert && ./scripts/build-test-app.sh --ios --emulator && ./scripts/test-app.sh --ios --emulator",
diff --git a/scripts/update-e2e-client-cert.js b/scripts/update-e2e-client-cert.js
new file mode 100644
index 00000000..8d826d07
--- /dev/null
+++ b/scripts/update-e2e-client-cert.js
@@ -0,0 +1,29 @@
+const fs = require('fs');
+const https = require('https');
+const path = require('path');
+
+const SOURCE_URL = 'https://badssl.com/certs/badssl.com-client.p12';
+const TARGET_PATH = path.join(__dirname, '../test/e2e-app-template/www/certificates/badssl-client-cert.pkcs');
+
+const downloadPkcsContainer = (source, target) => new Promise((resolve, reject) => {
+ const file = fs.createWriteStream(target);
+
+ const req = https.get(source, response => {
+ response.pipe(file)
+ resolve(target);
+ });
+
+ req.on('error', error => {
+ return reject(error)
+ });
+
+ req.end();
+});
+
+console.log(`Updating client certificate from ${SOURCE_URL}`);
+
+downloadPkcsContainer(SOURCE_URL, TARGET_PATH)
+ .catch(error => {
+ console.error(`Updating client certificate failed: ${error}`);
+ process.exit(1);
+ });
diff --git a/scripts/update-test-cert.js b/scripts/update-e2e-server-cert.js
similarity index 81%
rename from scripts/update-test-cert.js
rename to scripts/update-e2e-server-cert.js
index c4df08c5..ca8c49a7 100644
--- a/scripts/update-test-cert.js
+++ b/scripts/update-e2e-server-cert.js
@@ -30,13 +30,11 @@ const getCert = hostname => new Promise((resolve, reject) => {
req.end();
});
-console.log(`Updating test certificate from ${SOURCE_HOST}`);
+console.log(`Updating server certificate from ${SOURCE_HOST}`);
getCert(SOURCE_HOST)
- .then(cert => {
- fs.writeFileSync(TARGET_PATH, cert.raw);
- })
+ .then(cert => fs.writeFileSync(TARGET_PATH, cert.raw))
.catch(error => {
- console.error(`Updating test cert failed: ${error}`);
+ console.error(`Updating server certificate failed: ${error}`);
process.exit(1);
});
diff --git a/src/android/com/silkimen/cordovahttp/CordovaClientAuth.java b/src/android/com/silkimen/cordovahttp/CordovaClientAuth.java
index 54c781aa..b01ac936 100644
--- a/src/android/com/silkimen/cordovahttp/CordovaClientAuth.java
+++ b/src/android/com/silkimen/cordovahttp/CordovaClientAuth.java
@@ -6,11 +6,15 @@
import android.security.KeyChainAliasCallback;
import android.util.Log;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URI;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
import org.apache.cordova.CallbackContext;
@@ -21,17 +25,22 @@ class CordovaClientAuth implements Runnable, KeyChainAliasCallback {
private static final String TAG = "Cordova-Plugin-HTTP";
private String mode;
- private String filePath;
+ private String aliasString;
+ private byte[] rawPkcs;
+ private String pkcsPassword;
private Activity activity;
private Context context;
private TLSConfiguration tlsConfiguration;
private CallbackContext callbackContext;
- public CordovaClientAuth(final String mode, final String filePath, final Activity activity, final Context context,
- final TLSConfiguration configContainer, final CallbackContext callbackContext) {
+ public CordovaClientAuth(final String mode, final String aliasString, final byte[] rawPkcs,
+ final String pkcsPassword, final Activity activity, final Context context, final TLSConfiguration configContainer,
+ final CallbackContext callbackContext) {
this.mode = mode;
- this.filePath = filePath;
+ this.aliasString = aliasString;
+ this.rawPkcs = rawPkcs;
+ this.pkcsPassword = pkcsPassword;
this.activity = activity;
this.tlsConfiguration = configContainer;
this.context = context;
@@ -41,15 +50,45 @@ public CordovaClientAuth(final String mode, final String filePath, final Activit
@Override
public void run() {
if ("systemstore".equals(this.mode)) {
+ this.loadFromSystemStore();
+ } else if ("buffer".equals(this.mode)) {
+ this.loadFromBuffer();
+ } else {
+ this.disableClientAuth();
+ }
+ }
+
+ private void loadFromSystemStore() {
+ if (this.aliasString == null) {
KeyChain.choosePrivateKeyAlias(this.activity, this, null, null, null, -1, null);
- } else if ("file".equals(this.mode)) {
- this.callbackContext.error("Not implemented, yet");
} else {
- this.tlsConfiguration.setKeyManagers(null);
+ this.alias(this.aliasString);
+ }
+ }
+
+ private void loadFromBuffer() {
+ try {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12");
+ String keyManagerFactoryAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(keyManagerFactoryAlgorithm);
+ ByteArrayInputStream stream = new ByteArrayInputStream(this.rawPkcs);
+
+ keyStore.load(stream, this.pkcsPassword.toCharArray());
+ keyManagerFactory.init(keyStore, this.pkcsPassword.toCharArray());
+
+ this.tlsConfiguration.setKeyManagers(keyManagerFactory.getKeyManagers());
this.callbackContext.success();
+ } catch (Exception e) {
+ Log.e(TAG, "Couldn't load given PKCS12 container for authentication", e);
+ this.callbackContext.error("Couldn't load given PKCS12 container for authentication");
}
}
+ private void disableClientAuth() {
+ this.tlsConfiguration.setKeyManagers(null);
+ this.callbackContext.success();
+ }
+
@Override
public void alias(final String alias) {
try {
@@ -63,10 +102,12 @@ public void alias(final String alias) {
this.tlsConfiguration.setKeyManagers(new KeyManager[] { keyManager });
- this.callbackContext.success();
+ this.callbackContext.success(alias);
} catch (Exception e) {
- Log.e(TAG, "Couldn't load private key and certificate pair for authentication", e);
- this.callbackContext.error("Couldn't load private key and certificate pair for authentication");
+ Log.e(TAG, "Couldn't load private key and certificate pair with given alias \"" + alias + "\" for authentication",
+ e);
+ this.callbackContext.error(
+ "Couldn't load private key and certificate pair with given alias \"" + alias + "\" for authentication");
}
}
}
diff --git a/src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java b/src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java
index 4f242db0..06af0260 100644
--- a/src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java
+++ b/src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java
@@ -13,6 +13,7 @@
import org.json.JSONObject;
import android.util.Log;
+import android.util.Base64;
import javax.net.ssl.TrustManagerFactory;
@@ -149,8 +150,11 @@ private boolean setServerTrustMode(final JSONArray args, final CallbackContext c
}
private boolean setClientAuthMode(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
- CordovaClientAuth runnable = new CordovaClientAuth(args.getString(0), args.getString(1), this.cordova.getActivity(),
- this.cordova.getActivity().getApplicationContext(), this.tlsConfiguration, callbackContext);
+ byte[] pkcs = args.isNull(2) ? null : Base64.decode(args.getString(2), Base64.DEFAULT);
+
+ CordovaClientAuth runnable = new CordovaClientAuth(args.getString(0), args.isNull(1) ? null : args.getString(1),
+ pkcs, args.getString(3), this.cordova.getActivity(), this.cordova.getActivity().getApplicationContext(),
+ this.tlsConfiguration, callbackContext);
cordova.getThreadPool().execute(runnable);
diff --git a/src/android/com/silkimen/http/TLSConfiguration.java b/src/android/com/silkimen/http/TLSConfiguration.java
index 33c86343..c33df6c1 100644
--- a/src/android/com/silkimen/http/TLSConfiguration.java
+++ b/src/android/com/silkimen/http/TLSConfiguration.java
@@ -2,19 +2,13 @@
import java.io.IOException;
import java.security.GeneralSecurityException;
-import java.security.KeyStore;
import java.security.SecureRandom;
-import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
import com.silkimen.http.TLSSocketFactory;
diff --git a/test/e2e-app-template/www/index.js b/test/e2e-app-template/www/index.js
index 67582445..04d0a637 100644
--- a/test/e2e-app-template/www/index.js
+++ b/test/e2e-app-template/www/index.js
@@ -3,17 +3,17 @@ const app = {
lastResult: null,
- initialize: function() {
+ initialize: function () {
document.getElementById('nextBtn').addEventListener('click', app.onNextBtnClick);
},
- printResult: function(prefix, content) {
+ printResult: function (prefix, content) {
const text = prefix + ': ' + JSON.stringify(content);
document.getElementById('resultTextarea').value += text;
},
- reject: function(content) {
+ reject: function (content) {
document.getElementById('statusInput').value = 'finished';
app.printResult('result - rejected', content);
@@ -23,7 +23,7 @@ const app = {
};
},
- resolve: function(content) {
+ resolve: function (content) {
document.getElementById('statusInput').value = 'finished';
app.printResult('result - resolved', content);
@@ -33,7 +33,7 @@ const app = {
};
},
- throw: function(error) {
+ throw: function (error) {
document.getElementById('statusInput').value = 'finished';
app.printResult('result - throwed', error.message);
@@ -43,11 +43,11 @@ const app = {
};
},
- getResult: function(cb) {
+ getResult: function (cb) {
cb(app.lastResult);
},
- runTest: function(index) {
+ runTest: function (index) {
const testDefinition = tests[index];
const titleText = app.testIndex + ': ' + testDefinition.description;
const expectedText = 'expected - ' + testDefinition.expected;
@@ -57,32 +57,88 @@ const app = {
document.getElementById('resultTextarea').value = '';
document.getElementById('descriptionLbl').innerText = titleText;
- try {
- testDefinition.func(app.resolve, app.reject);
- } catch (error) {
- app.throw(error);
- }
- },
+ const onSuccessFactory = function (cbChain) {
+ return function () {
+ cbChain.shift()(cbChain);
+ }
+ };
- onBeforeTest: function(testIndex, cb) {
- app.lastResult = null;
+ const onFailFactory = function (prefix) {
+ return function (errorMessage) {
+ app.reject(prefix + ': ' + errorMessage);
+ }
+ };
+
+ const onThrowedHandler = function (prefix, error) {
+ app.throw(new Error(prefix + ': ' + error.message));
+ };
- if (hooks && hooks.onBeforeEachTest) {
- return hooks.onBeforeEachTest(function() {
- const testDefinition = tests[testIndex];
+ const execBeforeEachTest = function (cbChain) {
+ const prefix = 'in before each hook';
- if (testDefinition.before) {
- testDefinition.before(cb);
- } else {
- cb();
+ try {
+ if (!hooks || !hooks.onBeforeEachTest) {
+ return onSuccessFactory(cbChain)();
}
- });
- } else {
- cb();
- }
+
+ hooks.onBeforeEachTest(
+ onSuccessFactory(cbChain),
+ onFailFactory(prefix)
+ );
+ } catch (error) {
+ onThrowedHandler(prefix, error);
+ }
+ };
+
+ const execBeforeTest = function (cbChain) {
+ const prefix = 'in before hook';
+
+ try {
+ if (!testDefinition.before) {
+ return onSuccessFactory(cbChain)();
+ }
+
+ testDefinition.before(
+ onSuccessFactory(cbChain),
+ onFailFactory(prefix)
+ );
+ } catch (error) {
+ onThrowedHandler(prefix, error);
+ }
+ };
+
+ const execTest = function () {
+ try {
+ testDefinition.func(app.resolve, app.reject);
+ } catch (error) {
+ app.throw(error);
+ }
+ };
+
+ onSuccessFactory([execBeforeEachTest, execBeforeTest, execTest])();
+ },
+
+ onBeforeTest: function (testIndex, resolve, reject) {
+ const runBeforeEachTest = function (resolve, reject) {
+ if (!hooks || !hooks.onBeforeEachTest) return resolve();
+
+ hooks.onBeforeEachTest(resolve, reject);
+ };
+
+ const runBeforeTest = function (testIndex, resolve, reject) {
+ if (!tests[testIndex].before) return resolve();
+
+ tests[testIndex].before(resolve, reject);
+ };
+
+ app.lastResult = null;
+
+ runBeforeEachTest(function () {
+ runBeforeTest(testIndex, resolve);
+ }, reject);
},
- onFinishedAllTests: function() {
+ onFinishedAllTests: function () {
const titleText = 'No more tests';
const expectedText = 'You have run all available tests.';
@@ -91,13 +147,11 @@ const app = {
document.getElementById('descriptionLbl').innerText = titleText;
},
- onNextBtnClick: function() {
+ onNextBtnClick: function () {
app.testIndex += 1;
if (app.testIndex < tests.length) {
- app.onBeforeTest(app.testIndex, function() {
- app.runTest(app.testIndex);
- });
+ app.runTest(app.testIndex);
} else {
app.onFinishedAllTests();
}
diff --git a/test/e2e-specs.js b/test/e2e-specs.js
index 361793b4..d1df44c7 100644
--- a/test/e2e-specs.js
+++ b/test/e2e-specs.js
@@ -1,24 +1,42 @@
const hooks = {
- onBeforeEachTest: function(done) {
+ onBeforeEachTest: function (resolve, reject) {
cordova.plugin.http.clearCookies();
- helpers.setDefaultServerTrustMode(done);
+ helpers.setDefaultServerTrustMode(function () {
+ // @TODO: not ready yet
+ // helpers.setNoneClientAuthMode(resolve, reject);
+ resolve();
+ }, reject);
}
};
const helpers = {
- setDefaultServerTrustMode: function(done) { cordova.plugin.http.setServerTrustMode('default', done, done); },
- setNoCheckServerTrustMode: function(done) { cordova.plugin.http.setServerTrustMode('nocheck', done, done); },
- setPinnedServerTrustMode: function(done) { cordova.plugin.http.setServerTrustMode('pinned', done, done); },
- setJsonSerializer: function(done) { done(cordova.plugin.http.setDataSerializer('json')); },
- setUtf8StringSerializer: function(done) { done(cordova.plugin.http.setDataSerializer('utf8')); },
- setUrlEncodedSerializer: function(done) { done(cordova.plugin.http.setDataSerializer('urlencoded')); },
- getWithXhr: function(done, url) {
+ setDefaultServerTrustMode: function (resolve, reject) { cordova.plugin.http.setServerTrustMode('default', resolve, reject); },
+ setNoCheckServerTrustMode: function (resolve, reject) { cordova.plugin.http.setServerTrustMode('nocheck', resolve, reject); },
+ setPinnedServerTrustMode: function (resolve, reject) { cordova.plugin.http.setServerTrustMode('pinned', resolve, reject); },
+ setNoneClientAuthMode: function (resolve, reject) { cordova.plugin.http.setClientAuthMode('none', resolve, reject); },
+ setBufferClientAuthMode: function (resolve, reject) {
+ helpers.getWithXhr(function(pkcs) {
+ cordova.plugin.http.setClientAuthMode('buffer', {
+ rawPkcs: pkcs,
+ pkcsPassword: 'badssl.com'
+ }, resolve, reject);
+ }, './certificates/badssl-client-cert.pkcs', 'arraybuffer');
+ },
+ setJsonSerializer: function (resolve) { resolve(cordova.plugin.http.setDataSerializer('json')); },
+ setUtf8StringSerializer: function (resolve) { resolve(cordova.plugin.http.setDataSerializer('utf8')); },
+ setUrlEncodedSerializer: function (resolve) { resolve(cordova.plugin.http.setDataSerializer('urlencoded')); },
+ getWithXhr: function (done, url, type) {
var xhr = new XMLHttpRequest();
- xhr.addEventListener('load', function() {
- done(this.responseText);
+ xhr.addEventListener('load', function () {
+ if (!type || type === 'text') {
+ done(this.responseText);
+ } else {
+ done(this.response);
+ }
});
+ xhr.responseType = type;
xhr.open('GET', url);
xhr.send();
},
@@ -26,7 +44,7 @@ const helpers = {
window.resolveLocalFileSystemURL(cordova.file.cacheDirectory, function (directoryEntry) {
directoryEntry.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) {
fileEntry.createWriter(function (fileWriter) {
- var blob = new Blob([ content ], { type: 'text/plain' });
+ var blob = new Blob([content], { type: 'text/plain' });
fileWriter.onwriteend = done;
fileWriter.onerror = done;
@@ -38,16 +56,16 @@ const helpers = {
};
const messageFactory = {
- sslTrustAnchor: function() { return 'TLS connection could not be established: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.' },
- invalidCertificate: function(domain) { return 'The certificate for this server is invalid. You might be connecting to a server that is pretending to be “' + domain + '” which could put your confidential information at risk.' }
+ sslTrustAnchor: function () { return 'TLS connection could not be established: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.' },
+ invalidCertificate: function (domain) { return 'The certificate for this server is invalid. You might be connecting to a server that is pretending to be “' + domain + '” which could put your confidential information at risk.' }
}
const tests = [
{
description: 'should reject self signed cert (GET)',
expected: 'rejected: {"status":-2, ...',
- func: function(resolve, reject) { cordova.plugin.http.get('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
- validationFunc: function(driver, result, targetInfo) {
+ func: function (resolve, reject) { cordova.plugin.http.get('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
+ validationFunc: function (driver, result, targetInfo) {
result.type.should.be.equal('rejected');
result.data.should.be.eql({ status: -2, error: targetInfo.isAndroid ? messageFactory.sslTrustAnchor() : messageFactory.invalidCertificate('self-signed.badssl.com') });
}
@@ -55,8 +73,8 @@ const tests = [
{
description: 'should reject self signed cert (PUT)',
expected: 'rejected: {"status":-2, ...',
- func: function(resolve, reject) { cordova.plugin.http.put('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result, targetInfo) {
+ func: function (resolve, reject) { cordova.plugin.http.put('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result, targetInfo) {
result.type.should.be.equal('rejected');
result.data.should.be.eql({ status: -2, error: targetInfo.isAndroid ? messageFactory.sslTrustAnchor() : messageFactory.invalidCertificate('self-signed.badssl.com') });
}
@@ -64,8 +82,8 @@ const tests = [
{
description: 'should reject self signed cert (POST)',
expected: 'rejected: {"status":-2, ...',
- func: function(resolve, reject) { cordova.plugin.http.post('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result, targetInfo) {
+ func: function (resolve, reject) { cordova.plugin.http.post('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result, targetInfo) {
result.type.should.be.equal('rejected');
result.data.should.be.eql({ status: -2, error: targetInfo.isAndroid ? messageFactory.sslTrustAnchor() : messageFactory.invalidCertificate('self-signed.badssl.com') });
}
@@ -73,8 +91,8 @@ const tests = [
{
description: 'should reject self signed cert (PATCH)',
expected: 'rejected: {"status":-2, ...',
- func: function(resolve, reject) { cordova.plugin.http.patch('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result, targetInfo) {
+ func: function (resolve, reject) { cordova.plugin.http.patch('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result, targetInfo) {
result.type.should.be.equal('rejected');
result.data.should.be.eql({ status: -2, error: targetInfo.isAndroid ? messageFactory.sslTrustAnchor() : messageFactory.invalidCertificate('self-signed.badssl.com') });
}
@@ -82,8 +100,8 @@ const tests = [
{
description: 'should reject self signed cert (DELETE)',
expected: 'rejected: {"status":-2, ...',
- func: function(resolve, reject) { cordova.plugin.http.delete('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
- validationFunc: function(driver, result, targetInfo) {
+ func: function (resolve, reject) { cordova.plugin.http.delete('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
+ validationFunc: function (driver, result, targetInfo) {
result.type.should.be.equal('rejected');
result.data.should.be.eql({ status: -2, error: targetInfo.isAndroid ? messageFactory.sslTrustAnchor() : messageFactory.invalidCertificate('self-signed.badssl.com') });
}
@@ -92,8 +110,8 @@ const tests = [
description: 'should accept bad cert (GET)',
expected: 'resolved: {"status":200, ...',
before: helpers.setNoCheckServerTrustMode,
- func: function(resolve, reject) { cordova.plugin.http.get('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.get('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.should.include({ status: 200 });
}
@@ -102,8 +120,8 @@ const tests = [
description: 'should accept bad cert (PUT)',
expected: 'rejected: {"status":405, ... // will be rejected because PUT is not allowed',
before: helpers.setNoCheckServerTrustMode,
- func: function(resolve, reject) { cordova.plugin.http.put('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.put('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('rejected');
result.data.should.include({ status: 405 });
}
@@ -112,8 +130,8 @@ const tests = [
description: 'should accept bad cert (POST)',
expected: 'rejected: {"status":405, ... // will be rejected because POST is not allowed',
before: helpers.setNoCheckServerTrustMode,
- func: function(resolve, reject) { cordova.plugin.http.post('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.post('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('rejected');
result.data.should.include({ status: 405 });
}
@@ -122,8 +140,8 @@ const tests = [
description: 'should accept bad cert (PATCH)',
expected: 'rejected: {"status":405, ... // will be rejected because PATCH is not allowed',
before: helpers.setNoCheckServerTrustMode,
- func: function(resolve, reject) { cordova.plugin.http.patch('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.patch('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('rejected');
result.data.should.include({ status: 405 });
}
@@ -132,8 +150,8 @@ const tests = [
description: 'should accept bad cert (DELETE)',
expected: 'rejected: {"status":405, ... // will be rejected because DELETE is not allowed',
before: helpers.setNoCheckServerTrustMode,
- func: function(resolve, reject) { cordova.plugin.http.delete('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.delete('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('rejected');
result.data.should.include({ status: 405 });
}
@@ -142,8 +160,8 @@ const tests = [
description: 'should fetch data from http://httpbin.org/ (GET)',
expected: 'resolved: {"status":200, ...',
before: helpers.setNoCheckServerTrustMode,
- func: function(resolve, reject) { cordova.plugin.http.get('http://httpbin.org/', {}, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.get('http://httpbin.org/', {}, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.should.include({ status: 200 });
}
@@ -152,8 +170,8 @@ const tests = [
description: 'should send JSON object correctly (POST)',
expected: 'resolved: {"status": 200, "data": "{\\"json\\":\\"test\\": \\"testString\\"}\" ...',
before: helpers.setJsonSerializer,
- func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).json.should.eql({ test: 'testString' });
}
@@ -162,8 +180,8 @@ const tests = [
description: 'should send JSON object correctly (PUT)',
expected: 'resolved: {"status": 200, "data": "{\\"json\\":\\"test\\": \\"testString\\"}\" ...',
before: helpers.setJsonSerializer,
- func: function(resolve, reject) { cordova.plugin.http.put('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.put('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).json.should.eql({ test: 'testString' });
}
@@ -172,8 +190,8 @@ const tests = [
description: 'should send JSON object correctly (PATCH)',
expected: 'resolved: {"status": 200, "data": "{\\"json\\":\\"test\\": \\"testString\\"}\" ...',
before: helpers.setJsonSerializer,
- func: function(resolve, reject) { cordova.plugin.http.patch('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.patch('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).json.should.eql({ test: 'testString' });
}
@@ -182,39 +200,39 @@ const tests = [
description: 'should send JSON array correctly (POST) #26',
expected: 'resolved: {"status": 200, "data": "[ 1, 2, 3 ]\" ...',
before: helpers.setJsonSerializer,
- func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', [ 1, 2, 3 ], {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', [1, 2, 3], {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
- JSON.parse(result.data.data).json.should.eql([ 1, 2, 3 ]);
+ JSON.parse(result.data.data).json.should.eql([1, 2, 3]);
}
},
{
description: 'should send JSON array correctly (PUT) #26',
expected: 'resolved: {"status": 200, "data": "[ 1, 2, 3 ]\" ...',
before: helpers.setJsonSerializer,
- func: function(resolve, reject) { cordova.plugin.http.put('http://httpbin.org/anything', [ 1, 2, 3 ], {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.put('http://httpbin.org/anything', [1, 2, 3], {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
- JSON.parse(result.data.data).json.should.eql([ 1, 2, 3 ]);
+ JSON.parse(result.data.data).json.should.eql([1, 2, 3]);
}
},
{
description: 'should send JSON array correctly (PATCH) #26',
expected: 'resolved: {"status": 200, "data": "[ 1, 2, 3 ]\" ...',
before: helpers.setJsonSerializer,
- func: function(resolve, reject) { cordova.plugin.http.patch('http://httpbin.org/anything', [ 1, 2, 3 ], {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.patch('http://httpbin.org/anything', [1, 2, 3], {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.data.should.be.a('string');
- JSON.parse(result.data.data).json.should.eql([ 1, 2, 3 ]);
+ JSON.parse(result.data.data).json.should.eql([1, 2, 3]);
}
},
{
description: 'should send url encoded data correctly (POST) #41',
expected: 'resolved: {"status": 200, "data": "{\\"form\\":\\"test\\": \\"testString\\"}\" ...',
before: helpers.setUrlEncodedSerializer,
- func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).form.should.eql({ test: 'testString' });
}
@@ -223,8 +241,8 @@ const tests = [
description: 'should send url encoded data correctly (PUT)',
expected: 'resolved: {"status": 200, "data": "{\\"form\\":\\"test\\": \\"testString\\"}\" ...',
before: helpers.setUrlEncodedSerializer,
- func: function(resolve, reject) { cordova.plugin.http.put('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.put('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).form.should.eql({ test: 'testString' });
}
@@ -233,8 +251,8 @@ const tests = [
description: 'should send url encoded data correctly (PATCH)',
expected: 'resolved: {"status": 200, "data": "{\\"form\\":\\"test\\": \\"testString\\"}\" ...',
before: helpers.setUrlEncodedSerializer,
- func: function(resolve, reject) { cordova.plugin.http.patch('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.patch('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).form.should.eql({ test: 'testString' });
}
@@ -242,8 +260,8 @@ const tests = [
{
description: 'should resolve correct URL after redirect (GET) #33',
expected: 'resolved: {"status": 200, url: "http://httpbin.org/anything", ...',
- func: function(resolve, reject) { cordova.plugin.http.get('http://httpbin.org/redirect-to?url=http://httpbin.org/anything', {}, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.get('http://httpbin.org/redirect-to?url=http://httpbin.org/anything', {}, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.url.should.be.equal('http://httpbin.org/anything');
}
@@ -251,12 +269,12 @@ const tests = [
{
description: 'should download a file from given URL to given path in local filesystem',
expected: 'resolved: {"content": "\\n\\n" ...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
var sourceUrl = 'http://httpbin.org/xml';
var targetPath = cordova.file.cacheDirectory + 'test.xml';
- cordova.plugin.http.downloadFile(sourceUrl, {}, {}, targetPath, function(entry) {
- helpers.getWithXhr(function(content) {
+ cordova.plugin.http.downloadFile(sourceUrl, {}, {}, targetPath, function (entry) {
+ helpers.getWithXhr(function (content) {
resolve({
sourceUrl: sourceUrl,
targetPath: targetPath,
@@ -267,7 +285,7 @@ const tests = [
}, targetPath);
}, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.name.should.be.equal('test.xml');
result.data.content.should.be.equal("\n\n\n\n\n\n \n \n Wake up to WonderWidgets!\n \n\n \n \n Overview\n - Why WonderWidgets are great
\n \n - Who buys WonderWidgets
\n \n\n");
@@ -276,17 +294,17 @@ const tests = [
{
description: 'should upload a file from given path in local filesystem to given URL #27',
expected: 'resolved: {"status": 200, "data": "files": {"test-file.txt": "I am a dummy file. I am used ...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
var fileName = 'test-file.txt';
var fileContent = 'I am a dummy file. I am used for testing purposes!';
var sourcePath = cordova.file.cacheDirectory + fileName;
var targetUrl = 'http://httpbin.org/post';
- helpers.writeToFile(function() {
+ helpers.writeToFile(function () {
cordova.plugin.http.uploadFile(targetUrl, {}, {}, sourcePath, fileName, resolve, reject);
}, fileName, fileContent);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
var fileName = 'test-file.txt';
var fileContent = 'I am a dummy file. I am used for testing purposes!';
@@ -302,10 +320,10 @@ const tests = [
{
description: 'should encode HTTP array params correctly (GET) #45',
expected: 'resolved: {"status": 200, "data": "{\\"url\\":\\"http://httpbin.org/get?myArray[]=val1&myArray[]=val2&myArray[]=val3\\"}\" ...',
- func: function(resolve, reject) {
- cordova.plugin.http.get('http://httpbin.org/get', { myArray: [ 'val1', 'val2', 'val3' ], myString: 'testString' }, {}, resolve, reject);
+ func: function (resolve, reject) {
+ cordova.plugin.http.get('http://httpbin.org/get', { myArray: ['val1', 'val2', 'val3'], myString: 'testString' }, {}, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.data.should.be.a('string');
@@ -318,10 +336,10 @@ const tests = [
{
description: 'should throw on non-string values in local header object #54',
expected: 'throwed: {"message": "advanced-http: header values must be strings"}',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.get('http://httpbin.org/get', {}, { myTestHeader: 1 }, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('throwed');
result.message.should.be.equal('advanced-http: header values must be strings');
}
@@ -329,10 +347,10 @@ const tests = [
{
description: 'should throw an error while setting non-string value as global header #54',
expected: 'throwed: "advanced-http: header values must be strings"',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.setHeader('myTestHeader', 2);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('throwed');
result.message.should.be.equal('advanced-http: header values must be strings');
}
@@ -340,10 +358,10 @@ const tests = [
{
description: 'should accept content-type "application/xml" #58',
expected: 'resolved: {"status": 200, ...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.get('http://httpbin.org/xml', {}, {}, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.status.should.be.equal(200);
}
@@ -351,12 +369,12 @@ const tests = [
{
description: 'should send programmatically set cookies correctly (GET)',
expected: 'resolved: {"status": 200, ...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.setCookie('http://httpbin.org/get', 'myCookie=myValue');
cordova.plugin.http.setCookie('http://httpbin.org/get', 'mySecondCookie=mySecondValue');
cordova.plugin.http.get('http://httpbin.org/get', {}, {}, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.data.should.be.a('string');
@@ -370,13 +388,13 @@ const tests = [
{
description: 'should not send any cookies after running "clearCookies" (GET) #59',
expected: 'resolved: {"status": 200, "data": "{\"headers\": {\"Cookie\": \"\"...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.setCookie('http://httpbin.org/get', 'myCookie=myValue');
cordova.plugin.http.setCookie('http://httpbin.org/get', 'mySecondCookie=mySecondValue');
cordova.plugin.http.clearCookies();
cordova.plugin.http.get('http://httpbin.org/get', {}, {}, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.data.should.be.a('string');
@@ -389,15 +407,15 @@ const tests = [
{
description: 'should send programmatically set cookies correctly (DOWNLOAD) #57',
expected: 'resolved: {"content":{"cookies":{"myCookie":"myValue ...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
var sourceUrl = 'http://httpbin.org/cookies';
var targetPath = cordova.file.cacheDirectory + 'cookies.json';
cordova.plugin.http.setCookie('http://httpbin.org/get', 'myCookie=myValue');
cordova.plugin.http.setCookie('http://httpbin.org/get', 'mySecondCookie=mySecondValue');
- cordova.plugin.http.downloadFile(sourceUrl, {}, {}, targetPath, function(entry) {
- helpers.getWithXhr(function(content) {
+ cordova.plugin.http.downloadFile(sourceUrl, {}, {}, targetPath, function (entry) {
+ helpers.getWithXhr(function (content) {
resolve({
sourceUrl: sourceUrl,
targetPath: targetPath,
@@ -408,7 +426,7 @@ const tests = [
}, targetPath);
}, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.name.should.be.equal('cookies.json');
result.data.content.should.be.a('string');
@@ -423,10 +441,10 @@ const tests = [
description: 'should send UTF-8 encoded raw string correctly (POST) #34',
expected: 'resolved: {"status": 200, "data": "{\\"data\\": \\"this is a test string\\"...',
before: helpers.setUtf8StringSerializer,
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.post('http://httpbin.org/anything', 'this is a test string', {}, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).data.should.be.equal('this is a test string');
}
@@ -434,10 +452,10 @@ const tests = [
{
description: 'should encode spaces in query string (params object) correctly (GET) #71',
expected: 'resolved: {"status": 200, "data": "{\\"args\\": \\"query param\\": \\"and value with spaces\\"...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.get('http://httpbin.org/get', { 'query param': 'and value with spaces' }, {}, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).args['query param'].should.be.equal('and value with spaces');
}
@@ -445,10 +463,10 @@ const tests = [
{
description: 'should decode latin1 (iso-8859-1) encoded body correctly (GET) #72',
expected: 'resolved: {"status": 200, "data": " ...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.get('http://www.columbia.edu/kermit/latin1.html', {}, {}, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.data.should.include('[¡] 161 10/01 241 A1 INVERTED EXCLAMATION MARK\n[¢] 162 10/02 242 A2 CENT SIGN');
}
@@ -456,10 +474,10 @@ const tests = [
{
description: 'should return empty body string correctly (GET)',
expected: 'resolved: {"status": 200, "data": "" ...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.get('http://httpbin.org/stream/0', {}, {}, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.data.should.be.equal('');
}
@@ -468,10 +486,10 @@ const tests = [
description: 'should pin SSL cert correctly (GET)',
expected: 'resolved: {"status": 200 ...',
before: helpers.setPinnedServerTrustMode,
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.get('https://httpbin.org', {}, {}, resolve, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.status.should.be.equal(200);
}
@@ -480,10 +498,10 @@ const tests = [
description: 'should reject when pinned cert does not match received server cert (GET)',
expected: 'rejected: {"status": -2 ...',
before: helpers.setPinnedServerTrustMode,
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
cordova.plugin.http.get('https://sha512.badssl.com/', {}, {}, resolve, reject);
},
- validationFunc: function(driver, result, targetInfo) {
+ validationFunc: function (driver, result, targetInfo) {
result.type.should.be.equal('rejected');
result.data.should.be.eql({ status: -2, error: targetInfo.isAndroid ? messageFactory.sslTrustAnchor() : messageFactory.invalidCertificate('sha512.badssl.com') });
}
@@ -492,18 +510,18 @@ const tests = [
description: 'should send deeply structured JSON object correctly (POST) #65',
expected: 'resolved: {"status": 200, "data": "{\\"data\\": \\"{\\\\"outerObj\\\\":{\\\\"innerStr\\\\":\\\\"testString\\\\",\\\\"innerArr\\\\":[1,2,3]}}\\" ...',
before: helpers.setJsonSerializer,
- func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { outerObj: { innerStr: 'testString', innerArr: [1, 2, 3] }}, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { outerObj: { innerStr: 'testString', innerArr: [1, 2, 3] } }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
- JSON.parse(result.data.data).json.should.eql({ outerObj: { innerStr: 'testString', innerArr: [1, 2, 3] }});
+ JSON.parse(result.data.data).json.should.eql({ outerObj: { innerStr: 'testString', innerArr: [1, 2, 3] } });
}
},
{
description: 'should override header "content-type" correctly (POST) #78',
expected: 'resolved: {"status": 200, "headers": "{\\"Content-Type\\": \\"text/plain\\" ...',
before: helpers.setJsonSerializer,
- func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', {}, { 'Content-Type': 'text/plain' }, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', {}, { 'Content-Type': 'text/plain' }, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).headers['Content-Type'].should.be.equal('text/plain');
}
@@ -511,8 +529,8 @@ const tests = [
{
description: 'should handle error during file download correctly (DOWNLOAD) #83',
expected: 'rejected: {"status": 403, "error": "There was an error downloading the file" ...',
- func: function(resolve, reject) { cordova.plugin.http.downloadFile('http://httpbin.org/status/403', {}, {}, cordova.file.tempDirectory + 'testfile.txt', resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.downloadFile('http://httpbin.org/status/403', {}, {}, cordova.file.tempDirectory + 'testfile.txt', resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('rejected');
result.data.status.should.be.equal(403);
result.data.error.should.be.equal('There was an error downloading the file');
@@ -521,8 +539,8 @@ const tests = [
{
description: 'should handle gzip encoded response correctly',
expected: 'resolved: {"status": 200, "headers": "{\\"Content-Encoding\\": \\"gzip\\" ...',
- func: function(resolve, reject) { cordova.plugin.http.get('http://httpbin.org/gzip', {}, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.get('http://httpbin.org/gzip', {}, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.status.should.be.equal(200);
JSON.parse(result.data.data).gzipped.should.be.equal(true);
@@ -532,8 +550,8 @@ const tests = [
description: 'should send empty string correctly',
expected: 'resolved: {"status": 200, "data": "{\\"json\\":\\"\\" ...',
before: helpers.setUtf8StringSerializer,
- func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', '', {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', '', {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).data.should.be.equal('');
}
@@ -542,8 +560,8 @@ const tests = [
description: 'shouldn\'t escape forward slashes #184',
expected: 'resolved: {"status": 200, "data": "{\\"json\\":\\"/\\" ...',
before: helpers.setJsonSerializer,
- func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { testString: '/' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { testString: '/' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).json.testString.should.be.equal('/');
}
@@ -551,8 +569,8 @@ const tests = [
{
description: 'should not double encode spaces in url path #195',
expected: 'resolved: {"status": 200, "data": "{\\"url\\":\\"https://httpbin.org/anything/containing spaces in url\\" ...',
- func: function(resolve, reject) { cordova.plugin.http.get('https://httpbin.org/anything/containing%20spaces%20in%20url', {}, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.get('https://httpbin.org/anything/containing%20spaces%20in%20url', {}, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).url.should.be.equal('https://httpbin.org/anything/containing spaces in url');
}
@@ -560,8 +578,8 @@ const tests = [
{
description: 'should encode spaces in url query correctly',
expected: 'resolved: {"status": 200, "data": "{\\"url\\":\\"https://httpbin.org/anything?query key=very long query value with spaces\\" ...',
- func: function(resolve, reject) { cordova.plugin.http.get('https://httpbin.org/anything', { 'query key': 'very long query value with spaces' }, {}, resolve, reject); },
- validationFunc: function(driver, result) {
+ func: function (resolve, reject) { cordova.plugin.http.get('https://httpbin.org/anything', { 'query key': 'very long query value with spaces' }, {}, resolve, reject); },
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
JSON.parse(result.data.data).url.should.be.equal('https://httpbin.org/anything?query key=very long query value with spaces');
}
@@ -569,12 +587,12 @@ const tests = [
{
description: 'should download a file from given HTTPS URL to given path in local filesystem #197',
expected: 'resolved: {"content": "\\n\\n" ...',
- func: function(resolve, reject) {
+ func: function (resolve, reject) {
var sourceUrl = 'https://httpbin.org/xml';
var targetPath = cordova.file.cacheDirectory + 'test.xml';
- cordova.plugin.http.downloadFile(sourceUrl, {}, {}, targetPath, function(entry) {
- helpers.getWithXhr(function(content) {
+ cordova.plugin.http.downloadFile(sourceUrl, {}, {}, targetPath, function (entry) {
+ helpers.getWithXhr(function (content) {
resolve({
sourceUrl: sourceUrl,
targetPath: targetPath,
@@ -585,12 +603,23 @@ const tests = [
}, targetPath);
}, reject);
},
- validationFunc: function(driver, result) {
+ validationFunc: function (driver, result) {
result.type.should.be.equal('resolved');
result.data.name.should.be.equal('test.xml');
result.data.content.should.be.equal("\n\n\n\n\n\n \n \n Wake up to WonderWidgets!\n \n\n \n \n Overview\n - Why WonderWidgets are great
\n \n - Who buys WonderWidgets
\n \n\n");
}
- }
+ },
+ // @TODO: not ready yet
+ // {
+ // description: 'should authenticate correctly when client cert auth is configured with a PKCS12 container',
+ // expected: 'resolved: {"status": 200, ...',
+ // before: helpers.setBufferClientAuthMode,
+ // func: function (resolve, reject) { cordova.plugin.http.get('https://client.badssl.com/', {}, {}, resolve, reject); },
+ // validationFunc: function (driver, result) {
+ // result.type.should.be.equal('resolved');
+ // result.data.data.should.include('TLS handshake');
+ // }
+ // }
];
if (typeof module !== 'undefined' && module.exports) {
diff --git a/test/js-specs.js b/test/js-specs.js
index c7aa4379..a5fef7ec 100644
--- a/test/js-specs.js
+++ b/test/js-specs.js
@@ -261,4 +261,69 @@ describe('Common helpers', function () {
helpers.getCookieHeader('http://ilkimen.net').should.eql({ Cookie: 'cookie=value' });
});
});
+
+ describe('checkClientAuthOptions()', function () {
+ const jsUtil = require('../www/js-util');
+ const messages = require('../www/messages');
+ const helpers = require('../www/helpers')(jsUtil, null, messages);
+
+ it('returns options object with empty values when mode is "none" and no options are given', () => {
+ helpers.checkClientAuthOptions('none').should.eql({
+ alias: null,
+ pkcsPath: '',
+ pkcsPassword: ''
+ });
+ });
+
+ it('returns options object with empty values when mode is "none" and random options are given', () => {
+ helpers.checkClientAuthOptions('none', {
+ alias: 'myAlias',
+ pkcsPath: 'myPath'
+ }).should.eql({
+ alias: null,
+ pkcsPath: '',
+ pkcsPassword: ''
+ });
+ });
+
+ it('throws an error when mode is "systemstore" and alias is not a string or undefined', () => {
+ (() => helpers.checkClientAuthOptions('systemstore', { alias: 1 }))
+ .should.throw(messages.INVALID_CLIENT_AUTH_ALIAS);
+
+ (() => helpers.checkClientAuthOptions('systemstore', { alias: undefined }))
+ .should.not.throw();
+ });
+
+ it('returns an object with null alias when mode is "systemstore" and no options object is given', () => {
+ helpers.checkClientAuthOptions('systemstore').should.eql({
+ alias: null,
+ pkcsPath: '',
+ pkcsPassword: ''
+ });
+ });
+
+ it('throws an error when mode is "file" and pkcsPath is not a string', () => {
+ (() => helpers.checkClientAuthOptions('file', {
+ pkcsPath: undefined,
+ pkcsPassword: 'password'
+ })).should.throw(messages.INVALID_CLIENT_AUTH_PKCS_PATH);
+
+ (() => helpers.checkClientAuthOptions('file', {
+ pkcsPath: 1,
+ pkcsPassword: 'password'
+ })).should.throw(messages.INVALID_CLIENT_AUTH_PKCS_PATH);
+ });
+
+ it('throws an error when mode is "file" and pkcsPassword is not a string', () => {
+ (() => helpers.checkClientAuthOptions('file', {
+ pkcsPath: 'path',
+ pkcsPassword: undefined
+ })).should.throw(messages.INVALID_CLIENT_AUTH_PKCS_PASSWORD);
+
+ (() => helpers.checkClientAuthOptions('file', {
+ pkcsPath: 'path',
+ pkcsPassword: 1
+ })).should.throw(messages.INVALID_CLIENT_AUTH_PKCS_PASSWORD);
+ });
+ });
})
diff --git a/www/helpers.js b/www/helpers.js
index a9acc60c..2a7a0149 100644
--- a/www/helpers.js
+++ b/www/helpers.js
@@ -1,7 +1,7 @@
module.exports = function init(jsUtil, cookieHandler, messages) {
var validSerializers = ['urlencoded', 'json', 'utf8'];
var validCertModes = ['default', 'nocheck', 'pinned', 'legacy'];
- var validClientAuthModes = ['none', 'systemstore', 'file'];
+ var validClientAuthModes = ['none', 'systemstore', 'buffer'];
var validHttpMethods = ['get', 'put', 'post', 'patch', 'head', 'delete', 'upload', 'download'];
var interface = {
@@ -9,6 +9,7 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
checkSerializer: checkSerializer,
checkSSLCertMode: checkSSLCertMode,
checkClientAuthMode: checkClientAuthMode,
+ checkClientAuthOptions: checkClientAuthOptions,
checkForBlacklistedHeaderKey: checkForBlacklistedHeaderKey,
checkForInvalidHeaderValue: checkForInvalidHeaderValue,
injectCookieHandler: injectCookieHandler,
@@ -105,6 +106,54 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
return checkForValidStringValue(validClientAuthModes, mode, messages.INVALID_CLIENT_AUTH_MODE);
}
+ function checkClientAuthOptions(mode, options) {
+ options = options || {};
+
+ // none
+ if (mode === validClientAuthModes[0]) {
+ return {
+ alias: null,
+ rawPkcs: null,
+ pkcsPassword: ''
+ };
+ }
+
+ if (jsUtil.getTypeOf(options) !== 'Object') {
+ throw new Error(messages.INVALID_CLIENT_AUTH_OPTIONS);
+ }
+
+ // systemstore
+ if (mode === validClientAuthModes[1]) {
+ if (jsUtil.getTypeOf(options.alias) !== 'String'
+ && jsUtil.getTypeOf(options.alias) !== 'Undefined') {
+ throw new Error(messages.INVALID_CLIENT_AUTH_ALIAS);
+ }
+
+ return {
+ alias: jsUtil.getTypeOf(options.alias) === 'Undefined' ? null : options.alias,
+ rawPkcs: null,
+ pkcsPassword: ''
+ };
+ }
+
+ // buffer
+ if (mode === validClientAuthModes[2]) {
+ if (jsUtil.getTypeOf(options.rawPkcs) !== 'ArrayBuffer') {
+ throw new Error(messages.INVALID_CLIENT_AUTH_RAW_PKCS);
+ }
+
+ if (jsUtil.getTypeOf(options.pkcsPassword) !== 'String') {
+ throw new Error(messages.INVALID_CLIENT_AUTH_PKCS_PASSWORD);
+ }
+
+ return {
+ alias: null,
+ rawPkcs: options.rawPkcs,
+ pkcsPassword: options.pkcsPassword
+ }
+ }
+ }
+
function checkForBlacklistedHeaderKey(key) {
if (key.toLowerCase() === 'cookie') {
throw new Error(messages.ADDING_COOKIES_NOT_SUPPORTED);
diff --git a/www/js-util.js b/www/js-util.js
index a86da8bb..b41a255e 100644
--- a/www/js-util.js
+++ b/www/js-util.js
@@ -4,6 +4,8 @@ module.exports = {
switch (Object.prototype.toString.call(object)) {
case '[object Array]':
return 'Array';
+ case '[object ArrayBuffer]':
+ return 'ArrayBuffer';
case '[object Boolean]':
return 'Boolean';
case '[object Function]':
diff --git a/www/messages.js b/www/messages.js
index 25a76d0d..3f788a7c 100644
--- a/www/messages.js
+++ b/www/messages.js
@@ -7,6 +7,10 @@ module.exports = {
INVALID_DATA_SERIALIZER: 'advanced-http: invalid serializer, supported serializers are:',
INVALID_SSL_CERT_MODE: 'advanced-http: invalid SSL cert mode, supported modes are:',
INVALID_CLIENT_AUTH_MODE: 'advanced-http: invalid client certificate authentication mode, supported modes are:',
+ INVALID_CLIENT_AUTH_OPTIONS: 'advanced-http: invalid client certificate authentication options, needs to be an object',
+ INVALID_CLIENT_AUTH_ALIAS: 'advanced-http: invalid client certificate alias, needs to be a string or undefined',
+ INVALID_CLIENT_AUTH_RAW_PKCS: 'advanced-http: invalid PKCS12 container, needs to be an array buffer',
+ INVALID_CLIENT_AUTH_PKCS_PASSWORD: 'advanced-http: invalid PKCS12 container password, needs to be a string',
INVALID_HEADERS_VALUE: 'advanced-http: header values must be strings',
INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value',
INVALID_PARAMS_VALUE: 'advanced-http: invalid params object, needs to be an object with strings'
diff --git a/www/public-interface.js b/www/public-interface.js
index aae6fa0b..bfbbfb61 100644
--- a/www/public-interface.js
+++ b/www/public-interface.js
@@ -98,22 +98,23 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
}
function setClientAuthMode() {
- // filePath is an optional param
var mode = arguments[0];
+ var options = null;
var success = arguments[1];
var failure = arguments[2];
- var filePath = null;
if (arguments.length === 4) {
- mode = arguments[0];
- filePath = arguments[1];
+ options = arguments[1];
success = arguments[2];
failure = arguments[3];
}
+ mode = helpers.checkClientAuthMode(mode);
+ options = helpers.checkClientAuthOptions(mode, options);
+
helpers.handleMissingCallbacks(success, failure);
- return exec(success, failure, 'CordovaHttpPlugin', 'setClientAuthMode', [helpers.checkClientAuthMode(mode), filePath]);
+ return exec(success, failure, 'CordovaHttpPlugin', 'setClientAuthMode', [mode, options.alias, options.rawPkcs, options.pkcsPassword]);
}
function disableRedirect(disable, success, failure) {