Comparing version 0.6.0 to 0.6.1
@@ -0,1 +1,26 @@ | ||
0.6.1 / 2014-12-20 | ||
================== | ||
* [ENHANCEMENT] Allow logging of received `XML` prior to parsing and processing it, which allows better debugging of incoming`XML`. (#524) | ||
* [ENHANCEMENT] Add support for importing external `wsdl`. (#523) | ||
* [FIX] Use correct namespaces for elements which consist of an array. (#522) | ||
* [FIX] Use correct namespaces for elements which have a different base namespace. (#521) | ||
* [FIX] Don't throw an `Error` when `typeElement` is undefined in `ExtensionElement#description` method. (#515) | ||
* [FIX] Only supply `nonce` when a password digest is used to avoid `schema` validation errors. (#496) | ||
* [FIX] Allow `wsdl:documentation` element under `wsdl:message`. (#508) | ||
* [FIX] Use correct namespaces in sequences with imported elements. (#502) | ||
* [FIX] Ignore default `tns` and disabled default `tns` specification in first element of the body. (#506) | ||
* [ENHANCEMENT] Define `$xml` to pass plain `XML` object. (#485) | ||
The `$xml` key is used to pass an `XML` Object to the request without adding a namespace or parsing the string. | ||
* [FIX] Updated '#extend' method to avoid overriding properties and ensure the 'inheritance' of `<xsd:extension base=...>` usage. (#493) | ||
0.6.0 / 2014-10-29 | ||
@@ -2,0 +27,0 @@ ================= |
@@ -29,6 +29,13 @@ "use strict"; | ||
// nonce = base64 ( sha1 ( created + random ) ) | ||
var nHash = crypto.createHash('sha1'); | ||
nHash.update(created + Math.random()); | ||
var nonce = nHash.digest('base64'); | ||
var password; | ||
if(this._passwordType === 'PasswordText') { | ||
password = "<wsse:Password>" + this._password + "</wsse:Password>"; | ||
} else { | ||
// nonce = base64 ( sha1 ( created + random ) ) | ||
var nHash = crypto.createHash('sha1'); | ||
nHash.update(created + Math.random()); | ||
var nonce = nHash.digest('base64'); | ||
password = "<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" + passwordDigest(nonce, created, this._password) + "</wsse:Password>" + | ||
"<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + nonce + "</wsse:Nonce>"; | ||
} | ||
@@ -42,8 +49,3 @@ return "<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + | ||
"<wsse:Username>" + this._username + "</wsse:Username>" + | ||
(this._passwordType === 'PasswordText' ? | ||
"<wsse:Password>" + this._password + "</wsse:Password>" | ||
: | ||
"<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" + passwordDigest(nonce, created, this._password) + "</wsse:Password>" | ||
) + | ||
"<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + nonce + "</wsse:Nonce>" + | ||
password + | ||
"<wsu:Created>" + created + "</wsu:Created>" + | ||
@@ -50,0 +52,0 @@ "</wsse:UsernameToken>" + |
@@ -103,2 +103,5 @@ /* | ||
try { | ||
if (typeof self.log === 'function') { | ||
self.log("received", xml); | ||
} | ||
self._process(xml, req.url, function(result) { | ||
@@ -108,3 +111,2 @@ res.write(result); | ||
if (typeof self.log === 'function') { | ||
self.log("received", xml); | ||
self.log("replied", result); | ||
@@ -111,0 +113,0 @@ } |
135
lib/wsdl.js
@@ -76,8 +76,17 @@ /* | ||
/** | ||
* What we want is to copy properties from one object to another one and avoid | ||
* properties overriding. This way we ensure the 'inheritance' of | ||
* <xsd:extension base=...> usage. | ||
* | ||
* NB: 'Element' (and subtypes) don't have any prototyped properties: there's | ||
* no need to process a 'hasOwnProperties' call, we should just iterate over the | ||
* keys. | ||
*/ | ||
function extend(base, obj) { | ||
for (var key in obj) { | ||
if (!obj.hasOwnProperty(key)) { | ||
Object.keys(obj).forEach(function(key) { | ||
if(!base.hasOwnProperty(key)) | ||
base[key] = obj[key]; | ||
} | ||
} | ||
}); | ||
return base; | ||
@@ -127,5 +136,7 @@ } | ||
this.valueKey = options.valueKey || '$value'; | ||
this.xmlKey = options.xmlKey || '$xml'; | ||
this.ignoredNamespaces = options.ignoredNamespaces || []; | ||
} else { | ||
this.valueKey = '$value'; | ||
this.xmlKey = '$xml'; | ||
this.ignoredNamespaces = []; | ||
@@ -537,2 +548,6 @@ } | ||
for (i = 0; part = this.children[i]; i++) { | ||
if (part.name === 'documentation') { | ||
// <wsdl:documentation can be present under <wsdl:message> | ||
continue; | ||
} | ||
assert(part.name === 'part', 'Expected part element'); | ||
@@ -772,4 +787,6 @@ nsName = splitNSName(part.$type); | ||
var base = typeElement.description(definitions, xmlns); | ||
extend(desc, base); | ||
if (typeElement) { | ||
var base = typeElement.description(definitions, xmlns); | ||
extend(desc, base); | ||
} | ||
} | ||
@@ -1035,4 +1052,6 @@ } | ||
WSDL.prototype.ignoredNamespaces = ['tns', 'targetNamespace', 'typedNamespace']; | ||
WSDL.prototype._ignoredSchemaNamespaces = ['tns', 'xs', 'xsd']; | ||
WSDL.prototype.valueKey = '$value'; | ||
WSDL.prototype.xmlKey = '$xml'; | ||
@@ -1056,2 +1075,3 @@ WSDL.prototype._initializeOptions = function (options) { | ||
this.options.valueKey = options.valueKey || this.valueKey; | ||
this.options.xmlKey = options.xmlKey || this.xmlKey; | ||
}; | ||
@@ -1082,4 +1102,7 @@ | ||
} | ||
self.definitions.schemas[include.namespace || wsdl.definitions.$targetNamespace] = deepMerge(self.definitions.schemas[include.namespace || wsdl.definitions.$targetNamespace], wsdl.definitions); | ||
if(wsdl.definitions instanceof DefinitionsElement){ | ||
_.merge(self.definitions, wsdl.definitions); | ||
}else{ | ||
self.definitions.schemas[include.namespace || wsdl.definitions.$targetNamespace] = deepMerge(self.definitions.schemas[include.namespace || wsdl.definitions.$targetNamespace], wsdl.definitions); | ||
} | ||
self._processNextInclude(includes, function(err) { | ||
@@ -1112,2 +1135,33 @@ callback(err); | ||
/** | ||
* Returns true if a schema namespace needs to be ignored. | ||
* | ||
* @method shouldIgnoreNamespace | ||
* @param {Object} schema The parsed WSDL Schema object. | ||
*/ | ||
WSDL.prototype.shouldIgnoreNamespace = function(schema) { | ||
if (schema && typeof schema.xmlns === 'object') { | ||
// get the keys from schema.xmlns object (something like xs, xsd or custom) | ||
var schemaXmlns = Object.keys(schema.xmlns); | ||
var schemaXmlnsLength = schemaXmlns.length; | ||
if (schemaXmlnsLength > 0) { | ||
var count = 0; | ||
// loop through the keys | ||
for (var key in schemaXmlns) { | ||
var xmlns = schemaXmlns[key]; | ||
// if the key exists in the default ignoredSchemaNamespaces, add it to the count | ||
if (this._ignoredSchemaNamespaces.indexOf(xmlns) > -1) { | ||
count++; | ||
} | ||
} | ||
// if the count is equal to the length, don't add the namespace | ||
if(count === schemaXmlnsLength) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}; | ||
WSDL.prototype.toXML = function() { | ||
@@ -1384,2 +1438,8 @@ return this.xml || ''; | ||
var parentNamespace = namespace ? namespace.parent : undefined; | ||
if(parentNamespace) { | ||
//we got the parentNamespace for our array. setting the namespace-variable back to the current namespace string | ||
namespace = namespace.current; | ||
} | ||
var soapHeader = !schema; | ||
@@ -1389,2 +1449,3 @@ var qualified = schema && schema.$elementFormDefault === 'qualified'; | ||
var prefixNamespace = (namespace || qualified) && namespace !== 'xmlns'; | ||
var isNamespaceIgnored = this.shouldIgnoreNamespace(schema); | ||
@@ -1394,3 +1455,3 @@ var xmlnsAttrib = ''; | ||
if (prefixNamespace) { | ||
if (prefixNamespace && (!isNamespaceIgnored || this.ignoredNamespaces.indexOf(namespace) === -1)) { | ||
// resolve the prefix namespace | ||
@@ -1411,3 +1472,3 @@ xmlnsAttrib += ' xmlns:' + namespace + '="' + xmlns + '"'; | ||
var ns = ''; | ||
if (prefixNamespace && ((qualified || first) || soapHeader)) { | ||
if (prefixNamespace && ((qualified || first) || soapHeader) && (!isNamespaceIgnored || this.ignoredNamespaces.indexOf(namespace) === -1)) { | ||
// prefix element | ||
@@ -1419,6 +1480,8 @@ ns = namespace.indexOf(":") === -1 ? namespace + ':' : namespace; | ||
for (var i = 0, item; item = obj[i]; i++) { | ||
var arrayAttr = self.processAttributes(item); | ||
parts.push(['<', ns, name, arrayAttr, xmlnsAttrib, '>'].join('')); | ||
parts.push(self.objectToXML(item, name, namespace, xmlns, false, null, null, ancXmlns)); | ||
parts.push(['</', ns, name, '>'].join('')); | ||
var arrayAttr = self.processAttributes(item), | ||
correctOuterNamespace = parentNamespace || ns; //using the parent namespace if given | ||
parts.push(['<', correctOuterNamespace, name, arrayAttr, xmlnsAttrib, '>'].join('')); | ||
parts.push(self.objectToXML(item, name, namespace, xmlns, false, null, parameterTypeObject, ancXmlns)); | ||
parts.push(['</', correctOuterNamespace, name, '>'].join('')); | ||
} | ||
@@ -1431,2 +1494,6 @@ } else if (typeof obj === 'object') { | ||
} | ||
//Its the value of a xml object. Return it directly. | ||
if (name === self.options.xmlKey){ | ||
return obj[name]; | ||
} | ||
//Its the value of an item. Return it directly. | ||
@@ -1453,2 +1520,6 @@ if (name === self.options.valueKey) { | ||
if (childParameterTypeObject && childParameterTypeObject.$type && (childParameterTypeObject.$type.indexOf('xsd') === -1)) { | ||
if(childParameterTypeObject.$baseNameSpace) { //this element has a base with another namespace (the correct one) | ||
ns = childParameterTypeObject.$baseNameSpace + ':'; | ||
} | ||
var childParameterType = childParameterTypeObject.$type; | ||
@@ -1471,2 +1542,19 @@ | ||
var completeChildParameterTypeObject = self.findChildParameterObjectFromSchema(childName, childXmlns) || childParameterTypeObject; | ||
for(var ignoredNamespacesIndex = 0, ignoredNamespacesLength = this.ignoredNamespaces.length; ignoredNamespacesIndex < ignoredNamespacesLength; ignoredNamespacesIndex++) { | ||
if(this.ignoredNamespaces[ignoredNamespacesIndex] === childNamespace) { | ||
childNamespace = namespace; | ||
break; | ||
} | ||
} | ||
if(Array.isArray(child)) { | ||
//for arrays, we need to remember the current namespace | ||
childNamespace = { | ||
current: childNamespace, | ||
parent: ns | ||
}; | ||
} | ||
value = self.objectToXML(child, name, childNamespace, childXmlns, false, childXmlnsAttrib, completeChildParameterTypeObject, ancXmlns); | ||
@@ -1560,3 +1648,3 @@ } else if (obj[self.options.attributesKey] && obj[self.options.attributesKey].xsi_type) { //if parent object has complex type defined and child not found in parent | ||
if(parameterTypeObj.$lookupTypes && Array.isArray(parameterTypeObj.$lookupTypes)) { | ||
if(parameterTypeObj.$lookupTypes && Array.isArray(parameterTypeObj.$lookupTypes && parameterTypeObj.$lookupTypes.length)) { | ||
var types = parameterTypeObj.$lookupTypes; | ||
@@ -1584,2 +1672,19 @@ | ||
} | ||
if(child.$base) { | ||
var childNameSpace = child.$base.substr(0, child.$base.indexOf(':')), | ||
childXmlns = this.definitions.xmlns[childNameSpace]; | ||
var foundBase = this.findChildParameterObjectFromSchema(child.$base.substr(child.$base.indexOf(':') + 1), childXmlns); | ||
if (foundBase) { | ||
found = this.findChildParameterObject(foundBase, childName); | ||
if (found) { | ||
found.$baseNameSpace = childNameSpace; | ||
found.$type = childNameSpace + ':' + childName; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
@@ -1586,0 +1691,0 @@ } |
{ | ||
"name": "soap", | ||
"version": "0.6.0", | ||
"version": "0.6.1", | ||
"description": "A minimal node SOAP client", | ||
@@ -5,0 +5,0 @@ "engines": { |
@@ -187,3 +187,3 @@ # Soap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] | ||
``` | ||
+#### Options (optional) | ||
#### Options (optional) | ||
- Accepts any option that the request module accepts, see [here.](https://github.com/mikeal/request) | ||
@@ -218,3 +218,3 @@ - For example, you could set a timeout of 5 seconds on the request like this: | ||
## Handling XML Attributes and Value (wsdlOptions). | ||
## Handling XML Attributes, Value and XML (wsdlOptions). | ||
Sometimes it is necessary to override the default behaviour of `node-soap` in order to deal with the special requirements | ||
@@ -226,7 +226,7 @@ of your code base or a third library you use. Therefore you can use the `wsdlOptions` Object, which is passed in the | ||
attributesKey: 'theAttrs', | ||
valueKey: 'theVal' | ||
valueKey: 'theVal', | ||
xmlKey: 'theXml' | ||
} | ||
``` | ||
If nothing (or an empty Object `{}`) is passed to the `#createClient()` method, the `node-soap` defaults (`attributesKey: 'attributes'` | ||
and `valueKey: '$value'`) are used. | ||
If nothing (or an empty Object `{}`) is passed to the `#createClient()` method, the `node-soap` defaults (`attributesKey: 'attributes'`, `valueKey: '$value'` and `xmlKey: '$xml'`) are used. | ||
@@ -248,2 +248,32 @@ ###Overriding the `value` key | ||
###Overriding the `xml` key | ||
As `valueKey`, `node-soap` uses `$xml` as key. The xml key is used to pass XML Object without adding namespace or parsing the string. | ||
Example : | ||
```javascript | ||
dom = { | ||
$xml: '<parentnode type="type"><childnode></childnode></parentnode>' | ||
}; | ||
``` | ||
```xml | ||
<tns:dom> | ||
<parentnode type="type"> | ||
<childnode></childnode> | ||
</parentnode> | ||
</tns:dom> | ||
``` | ||
You can define your own `xmlKey` by passing it in the `wsdl_options` to the createClient call like so: | ||
```javascript | ||
var wsdlOptions = { | ||
xmlKey: 'theXml' | ||
}; | ||
soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) { | ||
// your code | ||
}); | ||
``` | ||
###Overriding the `attributes` key | ||
@@ -250,0 +280,0 @@ You can achieve attributes like: |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
115341
30
2230
365
2