Skip to content

Commit 90857e8

Browse files
authored
Merge pull request #3245 from wing328/security_fix_javascript
[Javascript] better code injection handling for Javascript API client
2 parents acc2849 + 8e43f7c commit 90857e8

File tree

119 files changed

+3932
-243
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

119 files changed

+3932
-243
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ samples/server-generator/scalatra/target
4141
samples/server-generator/scalatra/output/.history
4242

4343
# nodejs
44-
**/node_modules/
44+
**/node_modules
4545
samples/server-generator/node/output/node_modules
4646
samples/server/petstore/nodejs/node_modules
4747
samples/server/petstore/nodejs-server/node_modules
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/sh
2+
3+
SCRIPT="$0"
4+
5+
while [ -h "$SCRIPT" ] ; do
6+
ls=`ls -ld "$SCRIPT"`
7+
link=`expr "$ls" : '.*-> \(.*\)$'`
8+
if expr "$link" : '/.*' > /dev/null; then
9+
SCRIPT="$link"
10+
else
11+
SCRIPT=`dirname "$SCRIPT"`/"$link"
12+
fi
13+
done
14+
15+
if [ ! -d "${APP_DIR}" ]; then
16+
APP_DIR=`dirname "$SCRIPT"`/..
17+
APP_DIR=`cd "${APP_DIR}"; pwd`
18+
fi
19+
20+
executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar"
21+
22+
if [ ! -f "$executable" ]
23+
then
24+
mvn clean package
25+
fi
26+
27+
# if you've executed sbt assembly previously it will use that instead.
28+
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
29+
ags="$@ generate -t modules/swagger-codegen/src/main/resources/Javascript -i modules/swagger-codegen/src/test/resources/2_0/petstore-security-test.yaml -l javascript -o samples/client/petstore-security-test/javascript"
30+
31+
java -DappName=PetstoreClient $JAVA_OPTS -jar $executable $ags

modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavascriptClientCodegen.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,21 +240,21 @@ public void preprocessSwagger(Swagger swagger) {
240240
Info info = swagger.getInfo();
241241
if (StringUtils.isBlank(projectName) && info.getTitle() != null) {
242242
// when projectName is not specified, generate it from info.title
243-
projectName = dashize(info.getTitle());
243+
projectName = sanitizeName(dashize(info.getTitle()));
244244
}
245245
if (StringUtils.isBlank(projectVersion)) {
246246
// when projectVersion is not specified, use info.version
247-
projectVersion = info.getVersion();
247+
projectVersion = escapeUnsafeCharacters(escapeQuotationMark(info.getVersion()));
248248
}
249249
if (projectDescription == null) {
250250
// when projectDescription is not specified, use info.description
251-
projectDescription = info.getDescription();
251+
projectDescription = sanitizeName(info.getDescription());
252252
}
253253
if (additionalProperties.get(PROJECT_LICENSE_NAME) == null) {
254254
// when projectLicense is not specified, use info.license
255255
if (info.getLicense() != null) {
256256
License license = info.getLicense();
257-
additionalProperties.put(PROJECT_LICENSE_NAME, license.getName());
257+
additionalProperties.put(PROJECT_LICENSE_NAME, sanitizeName(license.getName()));
258258
}
259259
}
260260
}
@@ -1032,4 +1032,16 @@ public String toEnumValue(String value, String datatype) {
10321032
}
10331033
}
10341034

1035+
1036+
@Override
1037+
public String escapeQuotationMark(String input) {
1038+
// remove ', " to avoid code injection
1039+
return input.replace("\"", "").replace("'", "");
1040+
}
1041+
1042+
@Override
1043+
public String escapeUnsafeCharacters(String input) {
1044+
return input.replace("*/", "");
1045+
}
1046+
10351047
}

modules/swagger-codegen/src/main/resources/Javascript/api.mustache

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,41 @@
22
{{=< >=}}(function(root, factory) {
33
if (typeof define === 'function' && define.amd) {
44
// AMD. Register as an anonymous module.
5-
define(['<#invokerPackage><invokerPackage>/</invokerPackage>ApiClient'<#imports>, '<#invokerPackage><invokerPackage>/</invokerPackage><#modelPackage><modelPackage>/</modelPackage><import>'</imports>], factory);
5+
define(['<#invokerPackage><&invokerPackage>/</invokerPackage>ApiClient'<#imports>, '<#invokerPackage><&invokerPackage>/</invokerPackage><#modelPackage><&modelPackage>/</modelPackage><import>'</imports>], factory);
66
} else if (typeof module === 'object' && module.exports) {
77
// CommonJS-like environments that support module.exports, like Node.
8-
module.exports = factory(require('../ApiClient')<#imports>, require('../<#modelPackage><modelPackage>/</modelPackage><import>')</imports>);
8+
module.exports = factory(require('../ApiClient')<#imports>, require('../<#modelPackage><&modelPackage>/</modelPackage><import>')</imports>);
99
} else {
1010
// Browser globals (root is window)
11-
if (!root.<moduleName>) {
12-
root.<moduleName> = {};
11+
if (!root.<&moduleName>) {
12+
root.<&moduleName> = {};
1313
}
14-
root.<moduleName>.<classname> = factory(root.<moduleName>.ApiClient<#imports>, root.<moduleName>.<import></imports>);
14+
root.<&moduleName>.<&classname> = factory(root.<&moduleName>.ApiClient<#imports>, root.<&moduleName>.<import></imports>);
1515
}
1616
}(this, function(ApiClient<#imports>, <import></imports>) {
1717
'use strict';
1818
1919
<#emitJSDoc> /**
2020
* <baseName> service.
21-
* @module <#invokerPackage><invokerPackage>/</invokerPackage><#apiPackage><apiPackage>/</apiPackage><classname>
21+
* @module <#invokerPackage><&invokerPackage>/</invokerPackage><#apiPackage><&apiPackage>/</apiPackage><classname>
2222
* @version <projectVersion>
2323
*/
2424
2525
/**
26-
* Constructs a new <classname>. <#description>
26+
* Constructs a new <&classname>. <#description>
2727
* <description></description>
28-
* @alias module:<#invokerPackage><invokerPackage>/</invokerPackage><#apiPackage><apiPackage>/</apiPackage><classname>
28+
* @alias module:<#invokerPackage><&invokerPackage>/</invokerPackage><#apiPackage><apiPackage>/</apiPackage><classname>
2929
* @class
30-
* @param {module:<#invokerPackage><invokerPackage>/</invokerPackage>ApiClient} apiClient Optional API client implementation to use,
31-
* default to {@link module:<#invokerPackage><invokerPackage>/</invokerPackage>ApiClient#instance} if unspecified.
30+
* @param {module:<#invokerPackage><&invokerPackage>/</invokerPackage>ApiClient} apiClient Optional API client implementation to use,
31+
* default to {@link module:<#invokerPackage><&invokerPackage>/</invokerPackage>ApiClient#instance} if unspecified.
3232
*/
3333
</emitJSDoc> var exports = function(apiClient) {
3434
this.apiClient = apiClient || ApiClient.instance;
3535
3636
<#operations><#operation><#emitJSDoc><^usePromises>
3737
/**
38-
* Callback function to receive the result of the <nickname> operation.
39-
* @callback module:<#invokerPackage><invokerPackage>/</invokerPackage><#apiPackage><apiPackage>/</apiPackage><classname>~<nickname>Callback
38+
* Callback function to receive the result of the <operationId> operation.
39+
* @callback module:<#invokerPackage><invokerPackage>/</invokerPackage><#apiPackage><apiPackage>/</apiPackage><classname>~<operationId>Callback
4040
* @param {String} error Error message, if any.
4141
* @param <#vendorExtensions.x-jsdoc-type><&vendorExtensions.x-jsdoc-type> data The data returned by the service call.</vendorExtensions.x-jsdoc-type><^vendorExtensions.x-jsdoc-type>data This operation does not return a value.</vendorExtensions.x-jsdoc-type>
4242
* @param {String} response The complete HTTP response.
@@ -48,16 +48,16 @@
4848
* @param <&vendorExtensions.x-jsdoc-type> <paramName> <description></required></allParams><#hasOptionalParams>
4949
* @param {Object} opts Optional parameters<#allParams><^required>
5050
* @param <&vendorExtensions.x-jsdoc-type> opts.<paramName> <description><#defaultValue> (default to <.>)</defaultValue></required></allParams></hasOptionalParams><^usePromises>
51-
* @param {module:<#invokerPackage><invokerPackage>/</invokerPackage><#apiPackage><apiPackage>/</apiPackage><classname>~<nickname>Callback} callback The callback function, accepting three arguments: error, data, response</usePromises><#returnType>
51+
* @param {module:<#invokerPackage><&invokerPackage>/</invokerPackage><#apiPackage><&apiPackage>/</apiPackage><&classname>~<operationId>Callback} callback The callback function, accepting three arguments: error, data, response</usePromises><#returnType>
5252
* data is of type: <&vendorExtensions.x-jsdoc-type></returnType>
5353
*/
54-
</emitJSDoc> this.<nickname> = function(<vendorExtensions.x-codegen-argList>) {<#hasOptionalParams>
54+
</emitJSDoc> this.<operationId> = function(<vendorExtensions.x-codegen-argList>) {<#hasOptionalParams>
5555
opts = opts || {};</hasOptionalParams>
5656
var postBody = <#bodyParam><#required><paramName></required><^required>opts['<paramName>']</required></bodyParam><^bodyParam>null</bodyParam>;
5757
<#allParams><#required>
5858
// verify the required parameter '<paramName>' is set
5959
if (<paramName> == undefined || <paramName> == null) {
60-
throw "Missing the required parameter '<paramName>' when calling <nickname>";
60+
throw "Missing the required parameter '<paramName>' when calling <operationId>";
6161
}
6262
</required></allParams>
6363

modules/swagger-codegen/src/main/resources/Javascript/partial_model_generic.mustache

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,20 @@ exports.prototype['{{baseName}}'] = {{#defaultValue}}{{{defaultValue}}}{{/defaul
9696
}
9797

9898
{{/vars}}{{/emitModelMethods}}
99-
{{#vars}}{{#isEnum}}{{>partial_model_inner_enum}}{{/isEnum}}{{#items.isEnum}}{{#items}}
100-
{{>partial_model_inner_enum}}{{/items}}*/{{/items.isEnum}}{{/vars}}
99+
{{#vars}}
100+
{{#isEnum}}
101+
{{^isContainer}}
102+
{{>partial_model_inner_enum}}
103+
{{/isContainer}}
104+
{{/isEnum}}
105+
{{#items.isEnum}}
106+
{{#items}}
107+
{{^isContainer}}
108+
{{>partial_model_inner_enum}}
109+
{{/isContainer}}
110+
{{/items}}
111+
{{/items.isEnum}}
112+
{{/vars}}
101113

102114
return exports;
103115
{{/model}}{{/models}}}));

modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,13 +1101,15 @@ definitions:
11011101
type: array
11021102
items:
11031103
$ref: '#/definitions/ReadOnlyFirst'
1104-
array_of_enum:
1105-
type: array
1106-
items:
1107-
type: string
1108-
enum:
1109-
- UPPER
1110-
- lower
1104+
# commented out the below test case for array of enum for the time being
1105+
# as not all language can handle it
1106+
#array_of_enum:
1107+
# type: array
1108+
# items:
1109+
# type: string
1110+
# enum:
1111+
# - UPPER
1112+
# - lower
11111113
NumberOnly:
11121114
type: object
11131115
properties:
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Swagger Codegen Ignore
2+
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen
3+
4+
# Use this file to prevent files from being overwritten by the generator.
5+
# The patterns follow closely to .gitignore or .dockerignore.
6+
7+
# As an example, the C# client generator defines ApiClient.cs.
8+
# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
9+
#ApiClient.cs
10+
11+
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
12+
#foo/*/qux
13+
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
14+
15+
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
16+
#foo/**/qux
17+
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
18+
19+
# You can also negate patterns with an exclamation (!).
20+
# For example, you can ignore all files in a docs folder with the file extension .md:
21+
#docs/*.md
22+
# Then explicitly reverse the ignore rule for a single file:
23+
#!docs/README.md
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
language: node_js
2+
node_js:
3+
- "6"
4+
- "6.1"
5+
- "5"
6+
- "5.11"
7+

0 commit comments

Comments
 (0)