1 /*
2 * Sybase Hybrid App version 2.3.4
3 * Sybase PhoneGap HTTPS proxy
4 *
5 * https-proxy.js
6 * This file will not be regenerated, so it is possible to modify it, but it
7 * is not recommended.
8 *
9 * Copyright (c) 2013 Sybase Inc. All rights reserved.
10 */
11
12 /**
13 * Holds PhoneGap HTTP(S) proxy JavaScript
14 * @namespace
15 */
16 (function (window, undefined) {
17 if (!window.HttpsConnection) {
18 window.HttpsConnection = {};
19 }
20
21 var HttpsConnection = window.HttpsConnection;
22
23 /**
24 * Constant definitions for registration methods
25 */
26
27 /**
28 * Constant indicating the operation failed with unknown error. Used in {@link anonymous.sendRequestErrorCBParameter}
29 * @type number
30 */
31 HttpsConnection.ERR_UNKNOWN = -1;
32 /**
33 * Constant indicating the operation has invalid parameter. Used in {@link anonymous.sendRequestErrorCBParameter}
34 * @type number
35 */
36 HttpsConnection.ERR_INVALID_PARAMETER_VALUE = -2;
37 /**
38 * Constant indicating the operation failed because of missing parameter. Used in {@link anonymous.sendRequestErrorCBParameter}
39 * @type number
40 */
41 HttpsConnection.ERR_MISSING_PARAMETER = -3;
42 /**
43 * Constant indicating there is no such cordova action for the current service. Used in {@link anonymous.sendRequestErrorCBParameter}
44 * @type number
45 */
46 HttpsConnection.ERR_NO_SUCH_ACTION = -100;
47 /**
48 * Constant indicating certificate from file keystore is not supported on current platform. Used in {@link anonymous.sendRequestErrorCBParameter}
49 * @type number
50 */
51 HttpsConnection.ERR_FILE_CERTIFICATE_SOURCE_UNSUPPORTED = -101;
52 /**
53 * Constant indicating certificate from system keystore is not supported on current platform. Used in {@link anonymous.sendRequestErrorCBParameter}
54 * @type number
55 */
56 HttpsConnection.ERR_SYSTEM_CERTIFICATE_SOURCE_UNSUPPORTED = -102;
57 /**
58 * Constant indicating certificate from Afaria server is not supported on current platform. Used in {@link anonymous.sendRequestErrorCBParameter}
59 * @type number
60 */
61 HttpsConnection.ERR_AFARIA_CERTIFICATE_SOURCE_UNSUPPORTED = -103;
62 /**
63 * Constant indicating the certificate with given alias could not be found. Used in {@link anonymous.sendRequestErrorCBParameter}
64 * @type number
65 */
66 HttpsConnection.ERR_CERTIFICATE_ALIAS_NOT_FOUND = -104;
67 /**
68 * Constant indicating the certificate file could not be found. Used in {@link anonymous.sendRequestErrorCBParameter}
69 * @type number
70 */
71 HttpsConnection.ERR_CERTIFICATE_FILE_NOT_EXIST = -105;
72 /**
73 * Constant indicating incorrect certificate file format. Used in {@link anonymous.sendRequestErrorCBParameter}
74 * @type number
75 */
76 HttpsConnection.ERR_CERTIFICATE_INVALID_FILE_FORMAT = -106;
77 /**
78 * Constant indicating failed in getting certificate. Used in {@link anonymous.sendRequestErrorCBParameter}
79 * @type number
80 */
81 HttpsConnection.ERR_GET_CERTIFICATE_FAILED = -107;
82 /**
83 * Constant indicating the provided certificate failed validation on server side. Used in {@link anonymous.sendRequestErrorCBParameter}
84 * @type number
85 */
86 HttpsConnection.ERR_CLIENT_CERTIFICATE_VALIDATION = -108;
87 /**
88 * Constant indicating the server certificate failed validation on client side. Used in {@link anonymous.sendRequestErrorCB}
89 * @type number
90 */
91 HttpsConnection.ERR_SERVER_CERTIFICATE_VALIDATION = -109;
92 /**
93 * Constant indicating the server request failed. Used in {@link anonymous.sendRequestErrorCB}
94 * @type number
95 */
96 HttpsConnection.ERR_SERVER_REQUEST_FAILED = -110;
97 /**
98 * Constant indicating timeout error while connecting to the server. Used in {@link anonymous.sendRequestErrorCB}
99 * @type number
100 */
101 HttpsConnection.ERR_HTTP_TIMEOUT = -120;
102
103 /**
104 * Create certificate source description object for certificates from a keystore file.
105 * <b> Not supported on Blackberry platform </b>
106 * @class
107 * @memberOf HttpsConnection
108 * @public
109 * @param {string} Path Path of the keystore file. For iOS client, it first tries to load the
110 * relative file path from application's Documents folder; if it fails, then tries
111 * to load the file path from application's main bundle. In addition, before trying
112 * to load the certificate from file system, iOS client first checks whether the
113 * specified certificate key already exists in the key store, if so, it just loads
114 * the existing certificate from key store, instead of loading the certificate from
115 * file system.
116 * @param {string} Password Password of the keystore.
117 * @param {string} CertificateKey An unique key that will be used to locate the certificate.
118 */
119 HttpsConnection.CertificateFromFile = function (Path, Password, CertificateKey) {
120 this.Source = "FILE";
121 this.Path = Path;
122 this.Password = Password;
123 this.CertificateKey = CertificateKey;
124 };
125
126 /**
127 * Create certificate source description object for certificates from Afaria.
128 * @class
129 * @memberOf HttpsConnection
130 * @public
131 * @param {string} CN Common Name (CN) for CA/SCEP protocol. For iOS, the retrieved certificate is
132 * stored in the key store with the common name as the certificate key, the
133 * following requests for the same common name will just load the saved certificate
134 * from key store, instead of sending a new request to Afaria server.
135 * @param {string} [ChallengeCode] Challenge code for CA/SCEP protocol.
136 */
137 HttpsConnection.CertificateFromAfaria = function (CN, ChallengeCode) {
138 this.Source = "AFARIA";
139 this.CN = CN;
140 this.ChallengeCode = ChallengeCode;
141 };
142
143 /**
144 * Create certificate source description object for certificates from system keystore (Keystore in BB, Keychain in iOS and Android).
145 * The certificateKey is not used on the BB platform. BB will prompt the user to select a certificate if a certificate was not already
146 * used for the server connection.
147 * @class
148 * @memberOf HttpsConnection
149 * @public
150 * @param {string} CertificateKey An unique key that will be used to locate the certificate. Not used in BB platform.
151 */
152 HttpsConnection.CertificateFromStore = function (CertificateKey) {
153 this.Source = "SYSTEM";
154 this.CertificateKey = CertificateKey;
155 };
156
157 HttpsConnection.MSG_MISSING_PARAMETER = "Missing a required parameter: ";
158 HttpsConnection.MSG_INVALID_PARAMETER_VALUE = "Invalid Parameter Value for parameter: ";
159
160 /**
161 * @private
162 * @param {Object} [certSource] Certificate description object. It can be one of {@link HttpsConnection.CertificateFromFile},
163 * {@link HttpsConnection.CertificateFromStore}, or {@link HttpsConnection.CertificateFromAfaria}.
164 * @param {anonymous.sendRequestErrorCB} errorCB Callback method upon failure.
165 */
166 HttpsConnection.validateCertSource = function(certSource, errorCB) {
167 if (!certSource) {
168 // The certificate is not present, so just ignore it.
169 return true;
170 }
171
172 // errorCB required.
173 // First check this one. We may need it to return errors
174 if (errorCB && (typeof errorCB !== "function")) {
175 console.log("HttpsConnection Error: errorCB is not a function");
176 return false;
177 }
178
179 try {
180 // First check whether it is an object
181 if (typeof certSource !== "object") {
182 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "certSource"});
183 return false;
184 }
185
186 if (certSource.Source === "FILE") {
187 if (!certSource.Path) {
188 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_MISSING_PARAMETER + "keystore path"});
189 return false;
190 }
191
192 if (typeof certSource.Path !== "string") {
193 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "keystore path"});
194 return false;
195 }
196
197 if (!certSource.Password) {
198 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_MISSING_PARAMETER + "keystore password"});
199 return false;
200 }
201
202 if (typeof certSource.Password !== "string") {
203 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "keystore password"});
204 return false;
205 }
206
207 if (!certSource.CertificateKey) {
208 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_MISSING_PARAMETER + "certificate key"});
209 return false;
210 }
211
212 if (typeof certSource.CertificateKey !== "string") {
213 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "certificate key"});
214 return false;
215 }
216 } else if (certSource.Source === "SYSTEM") {
217 if (!certSource.CertificateKey) {
218 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_MISSING_PARAMETER + "certificate key"});
219 return false;
220 }
221
222 if (typeof certSource.CertificateKey !== "string") {
223 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "certificate key"});
224 return false;
225 }
226 } else if (certSource.Source === "AFARIA") {
227 if (!certSource.CN) {
228 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_MISSING_PARAMETER + "common name"});
229 return false;
230 }
231
232 if (typeof certSource.CN !== "string") {
233 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "common name"});
234 return false;
235 }
236
237 if (!certSource.ChallengeCode) {
238 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_MISSING_PARAMETER + "Afaria challenge code"});
239 return false;
240 }
241
242 if (typeof certSource.ChallengeCode !== "string") {
243 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "Afaria challenge code"});
244 return false;
245 }
246 } else {
247 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "certSource"});
248 return false;
249 }
250
251 return true;
252 } catch (ex) {
253 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "certSource"});
254 }
255 };
256
257 /**
258 * Send a HTTP(S) request to a remote server.
259 * @memberOf HttpsConnection
260 * @public
261 * @param {string} method Standard HTTP request method name.
262 * @param {string} url The http url with format http(s)://[user:password]@hostname[:port]/path.
263 * @param {Object} header HTTP header to be sent to server. This is an Object. Can be null.
264 * @param {string} requestBody Data to be sent to server with the request. It’s a string value. Can be null.
265 * @param {anonymous.sendRequestSuccessCB} successCB Callback method upon success.
266 * @param {anonymous.sendRequestErrorCB} errorCB Callback method upon failure.
267 * @param {string} [user] User ID for basic authentication.
268 * @param {string} [password] User password for basic authentication.
269 * @param {number} [timeout] Timeout setting in seconds.
270 * @param {Object} [certSource] Certificate description object. It can be one of {@link HttpsConnection.CertificateFromFile},
271 * {@link HttpsConnection.CertificateFromStore}, or {@link HttpsConnection.CertificateFromAfaria}.
272 * @returns {anonymous.abort} A JavaScript function object to cancel the operation.
273 * @example
274 * // To send a post request to server, call the method
275 * HttpsConnection.sendRequest("POST", "http://www.google.com", null, "THIS IS THE BODY", function (data) {
276 * alert("Status: " + JSON.stringify(data.status));
277 * alert("Headers: " + JSON.stringify(data.headers));
278 * alert("Response: " + JSON.stringify(data.response));
279 * }, function (data) {
280 * alert("Failed: " + JSON.stringify(data));}};
281 * // To send a post request to server with headers, call the method
282 * HttpsConnection.sendRequest("POST", url, {HeaderName : "Header value"}, "THIS IS THE BODY", successCB, errorCB);
283 * // To send a post request to server with basic authentication, call the method
284 * HttpsConnection.sendRequest("POST", url, headers, "THIS IS THE BODY", successCB, errorCB, "username", "password");
285 * // To send a post request to server with mutual authentication, call the method
286 * HttpsConnection.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null,
287 * null, 0, new CertificateFromFile("/mnt/sdcard/my.keystore", "password", "mykey"));
288 */
289 HttpsConnection.sendRequest = function (method, url, header, requestBody, successCB, errorCB, user, password, timeout, certSource){
290
291 // errorCB required.
292 // First check this one. We may need it to return errors
293 if (!errorCB || (typeof errorCB !== "function")) {
294 console.log("HttpsConnection Error: errorCB is not a function");
295 // if error callback is invalid, throw an exception to notify the caller
296 throw new Error("HttpsConnection Error: errorCB is not a function");
297 return;
298 }
299
300 // method required
301 if (!method) {
302 console.log("HttpsConnection Error: method is required");
303 errorCB({errorCode : HttpsConnection.ERR_MISSING_PARAMETER, description : HttpsConnection.MSG_MISSING_PARAMETER + "method"});
304 return;
305 }
306
307 // We only support GET, POST, HEAD, PUT, DELETE method
308 if (method !== "GET" && method !== "POST" && method !== "HEAD" && method !== "PUT" && method !== "DELETE") {
309 console.log("Invalid Parameter Value for parameter: " + method);
310 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "method"});
311 return;
312 }
313
314 // url required
315 if (!url) {
316 console.log("HttpsConnection Error: url is required");
317 errorCB({errorCode : HttpsConnection.ERR_MISSING_PARAMETER, description : HttpsConnection.MSG_MISSING_PARAMETER + "url"});
318 return;
319 }
320
321 // successCB required
322 if (!successCB) {
323 console.log("HttpsConnection Error: successCB is required");
324 errorCB({errorCode : HttpsConnection.ERR_MISSING_PARAMETER, description : HttpsConnection.MSG_MISSING_PARAMETER + "successCB"});
325 return;
326 }
327
328 if (typeof successCB !== "function") {
329 console.log("HttpsConnection Error: successCB is not a function");
330 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "successCB"});
331 return;
332 }
333
334 if (user && typeof user !== "string") {
335 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "user"});
336 return;
337 }
338
339 if (password && typeof password !== "string") {
340 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "password"});
341 return;
342 }
343
344 if (timeout && typeof timeout !== "number") {
345 errorCB({errorCode : HttpsConnection.ERR_INVALID_PARAMETER_VALUE, description : HttpsConnection.MSG_INVALID_PARAMETER_VALUE + "timeout"});
346 return;
347 }
348
349 if (!HttpsConnection.validateCertSource(certSource, errorCB)) {
350 return;
351 }
352
353 try {
354 var client = new HttpsConnection.Client(method, url, header, requestBody, successCB, errorCB, user, password, timeout, certSource);
355 return client.send();
356 } catch (ex){
357 errorCB({errorCode : HttpsConnection.ERR_UNKNOWN, description : ex.message});
358 }
359 };
360
361 /**
362 * Send a HTTP(S) GET request to a remote server.
363 * @memberOf HttpsConnection
364 * @public
365 * @param {string} url The http url with format http(s)://[user:password]@hostname[:port]/path.
366 * @param {Object} header HTTP header to be sent to server. This is an Object. Can be null.
367 * @param {anonymous.sendRequestSuccessCB} successCB Callback method upon success.
368 * @param {anonymous.sendRequestErrorCB} [errorCB] Callback method upon failure.
369 * @param {string} [user] User ID for basic authentication.
370 * @param {string} [password] User password for basic authentication.
371 * @param {number} [timeout] Timeout setting in seconds.
372 * @param {Object} [certSource] Certificate description object. It can be one of {@link HttpsConnection.CertificateFromFile},
373 * {@link HttpsConnection.CertificateFromStore}, or {@link HttpsConnection.CertificateFromAfaria}.
374 * @returns {anonymous.abort} A JavaScript function object to cancel the operation.
375 * @example
376 * // To send a get request to server, call the method
377 * HttpsConnection.get("http://www.google.com", null, function (data) {
378 * alert("Status: " + JSON.stringify(data.status));
379 * alert("Headers: " + JSON.stringify(data.headers));
380 * if (data.responseText){
381 * alert("Response: " + JSON.stringify(data.responseText));
382 * }
383 * },
384 * function (error) {
385 * alert("Failed: " + JSON.stringify(error));
386 * }};
387 * // To send a get request to server with headers, call the method
388 * HttpsConnection.get(url, {HeaderName : "Header value"}, successCB, errorCB);
389 * // To send a get request to server with basic authentication, call the method
390 * HttpsConnection.get(url, headers, successCB, errorCB, "username", "password");
391 * // To send a get request to server with mutual authentication, call the method
392 * HttpsConnection.get("https://hostname", headers, successCB, errorCB, null, null, 0,
393 * new CertificateFromFile("/mnt/sdcard/my.p12", "password", "mykey"));
394 */
395 HttpsConnection.get = function (url, header, successCB, errorCB, user, password, timeout, certSource){
396 return HttpsConnection.sendRequest("GET", url, header, null, successCB, errorCB, user, password, timeout, certSource);
397 };
398
399 /**
400 * Delete cached certificate from keychain. iOS client will always try the cached certificate first if it is available before requesting the certificate from
401 * afaria server or loading the certificate from file system. In case the cached certificate is no longer valid, use this method to delete it from keychain
402 * <b> Only supported by iOS platform </b>
403 * @memberOf HttpsConnection
404 * @public
405 * @param {anonymous.sendRequestSuccessCB} successCB Callback method upon success.
406 * @param {anonymous.sendRequestErrorCB} [errorCB] Callback method upon failure.
407 * @param {string} certificateKey The key of the certificate to be deleted.
408 */
409 HttpsConnection.deleteCertificateFromStore = function (successCB, errorCB, certificateKey) {
410 cordova.exec(successCB, errorCB, "HttpsProxy", "deleteCertificateFromStore", [certificateKey]);
411 };
412
413
414 /**
415 * @private
416 * @param {string} method Standard HTTP request method name.
417 * @param {string} url The http url with format http(s)://[user:password]@hostname[:port]/path.
418 * @param {Object} header HTTP header to be sent to server. This is an Object. Can be null.
419 * @param {string} requestBody Data to be sent to server with the request. It’s a string value. Can be null.
420 * @param {anonymous.sendRequestSuccessCB} successCB Callback method upon success.
421 * @param {anonymous.sendRequestErrorCB} errorCB Callback method upon failure.
422 * @param {string} [user] User ID for basic authentication.
423 * @param {string} [password] User password for basic authentication.
424 * @param {number} [timeout] Timeout setting in seconds.
425 * @param {Object} [certSource] Certificate description object. It can be one of {@link HttpsConnection.CertificateFromFile},
426 * {@link HttpsConnection.CertificateFromStore}, or {@link HttpsConnection.CertificateFromAfaria}.
427 * @returns {anonymous.abort} A JavaScript function object to cancel the operation.
428 */
429 HttpsConnection.Client = function ( method, url, header, requestBody, successCB, errorCB, user, password, timeout, certSource )
430 {
431 //ios plugin parameter does not support object type, convert Header and CertSource to JSON string
432 if (device.platform === "iOS" || (device.platform && device.platform.indexOf("iP") === 0 ))
433 {
434 if (header) {
435 header = JSON.stringify(header);
436 }
437 if (certSource) {
438 certSource = JSON.stringify(certSource);
439 }
440 }
441
442 this.Method = method;
443 this.Url = url;
444 this.Header = header;
445 this.RequestBody = requestBody;
446 this.SuccessCB = successCB;
447 this.ErrorCB = errorCB;
448 this.User = user;
449 this.Password = password;
450 this.Timeout = timeout;
451 this.CertSource = certSource;
452 this.IsAbort = false;
453
454 this.abort = function ()
455 {
456 this.IsAbort = true;
457 };
458
459 this.send = function ()
460 {
461 var args = [this.Method, this.Url, this.Header, this.RequestBody, this.User, this.Password, this.Timeout, this.CertSource];
462
463 var me = this;
464
465 var successCallBack = function(data)
466 {
467 if (me.IsAbort === true)
468 {
469 return;
470 }
471
472 successCB(data);
473 };
474
475 var errorCallBack = function(data)
476 {
477 if (me.IsAbort === true)
478 {
479 return;
480 }
481
482 errorCB(data);
483 };
484
485 cordova.exec(successCallBack, errorCallBack, "HttpsProxy", "sendRequest", args);
486
487 return this.abort;
488 };
489 };
490
491 })(this);
492
493 /**
494 * Used to group anonymous objects and callback functions used as method parameters. Methods and fields in this
495 * namespace cannot be instantiated. Used for API docs generation only.
496 * @namespace
497 */
498 anonymous = (typeof anonymous === "undefined" || !anonymous) ? {} : anonymous; // SUP 'namespace'
499
500 /**
501 * Callback function that will be invoked HttpsConnection.get()/sendRequest() succeeded.
502 *
503 * @name anonymous.sendRequestSuccessCB
504 *
505 * @param {anonymous.sendRequestSuccessCBParameter} data The response data object.
506 * @function
507 */
508
509 /**
510 * Callback function that will be invoked HttpsConnection.get()/sendRequest() failed.
511 *
512 * @name anonymous.sendRequestErrorCB
513 * @param {anonymous.sendRequestErrorCBParameter} data The error object.
514 * @function
515 */
516
517 /**
518 * Object used in {@link anonymous.sendRequestSuccessCB} function.
519 * @class
520 * @name anonymous.sendRequestSuccessCBParameter
521 * @property {number} status The HTTP status code
522 * @property {object} headers An object that contains headerKey = value pairs.
523 * @property {string} [responseText] The text response. This parameter is present only if the response is a text response.
524 * @property {string} [responseBase64] Base64 encoded representation of the binary response. This parameter is included only
525 * if the response is a binary response.
526 * @property {object} [clientError] An optional object that contains the authentication error. It is an object of {@link anonymous.sendRequestErrorCBParameter}.
527 */
528
529 /**
530 * Object used in {@link anonymous.sendRequestErrorCB} function.
531 * @class
532 * @name anonymous.sendRequestErrorCBParameter
533 * @property {number} errorCode Predefined error code
534 * @property {string} description The description of the error
535 * @property {number} [nativeErrorCode] The native error code reported from Afaria, device, etc (optional)
536 */
537
538
539 /**
540 * JavaScript function to abort the HTTP(S) request
541 *
542 * @name anonymous.abort
543 *
544 * @function
545 */
546