Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const handlebarsPlugin = () => ({
enumerator: true,
escapeComment: true,
escapeDescription: true,
escapeSingleQuotedString: true,
camelCase: true,
},
});
Expand Down
8 changes: 4 additions & 4 deletions src/templates/client.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ import { {{{name}}}{{{@root.postfix}}} } from './services/{{{name}}}{{{@root.pos
{
provide: OpenAPI,
useValue: {
BASE: OpenAPI?.BASE ?? '{{{server}}}',
VERSION: OpenAPI?.VERSION ?? '{{{version}}}',
BASE: OpenAPI?.BASE ?? '{{{escapeSingleQuotedString server}}}',
VERSION: OpenAPI?.VERSION ?? '{{{escapeSingleQuotedString version}}}',
WITH_CREDENTIALS: OpenAPI?.WITH_CREDENTIALS ?? false,
CREDENTIALS: OpenAPI?.CREDENTIALS ?? 'include',
TOKEN: OpenAPI?.TOKEN,
Expand Down Expand Up @@ -61,8 +61,8 @@ export class {{{clientName}}} {

constructor(config?: Partial<OpenAPIConfig>, HttpRequest: HttpRequestConstructor = {{{httpRequest}}}) {
this.request = new HttpRequest({
BASE: config?.BASE ?? '{{{server}}}',
VERSION: config?.VERSION ?? '{{{version}}}',
BASE: config?.BASE ?? '{{{escapeSingleQuotedString server}}}',
VERSION: config?.VERSION ?? '{{{escapeSingleQuotedString version}}}',
WITH_CREDENTIALS: config?.WITH_CREDENTIALS ?? false,
CREDENTIALS: config?.CREDENTIALS ?? 'include',
TOKEN: config?.TOKEN,
Expand Down
4 changes: 2 additions & 2 deletions src/templates/core/OpenAPI.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export type OpenAPIConfig = {
};

export const OpenAPI: OpenAPIConfig = {
BASE: '{{{server}}}',
VERSION: '{{{version}}}',
BASE: '{{{escapeSingleQuotedString server}}}',
VERSION: '{{{escapeSingleQuotedString version}}}',
WITH_CREDENTIALS: false,
CREDENTIALS: 'include',
TOKEN: undefined,
Expand Down
16 changes: 8 additions & 8 deletions src/templates/exportService.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -88,39 +88,39 @@ export class {{{name}}}{{{@root.postfix}}} {
{{/equals}}
{{/if}}
method: '{{{method}}}',
url: '{{{path}}}',
url: '{{{escapeSingleQuotedString path}}}',
{{#if parametersPath}}
path: {
{{#each parametersPath}}
'{{{prop}}}': {{{name}}},
'{{{escapeSingleQuotedString prop}}}': {{{name}}},
{{/each}}
},
{{/if}}
{{#if parametersCookie}}
cookies: {
{{#each parametersCookie}}
'{{{prop}}}': {{{name}}},
'{{{escapeSingleQuotedString prop}}}': {{{name}}},
{{/each}}
},
{{/if}}
{{#if parametersHeader}}
headers: {
{{#each parametersHeader}}
'{{{prop}}}': {{{name}}},
'{{{escapeSingleQuotedString prop}}}': {{{name}}},
{{/each}}
},
{{/if}}
{{#if parametersQuery}}
query: {
{{#each parametersQuery}}
'{{{prop}}}': {{{name}}},
'{{{escapeSingleQuotedString prop}}}': {{{name}}},
{{/each}}
},
{{/if}}
{{#if parametersForm}}
formData: {
{{#each parametersForm}}
'{{{prop}}}': {{{name}}},
'{{{escapeSingleQuotedString prop}}}': {{{name}}},
{{/each}}
},
{{/if}}
Expand All @@ -132,11 +132,11 @@ export class {{{name}}}{{{@root.postfix}}} {
body: {{{parametersBody.name}}},
{{/equals}}
{{#if parametersBody.mediaType}}
mediaType: '{{{parametersBody.mediaType}}}',
mediaType: '{{{escapeSingleQuotedString parametersBody.mediaType}}}',
{{/if}}
{{/if}}
{{#if responseHeader}}
responseHeader: '{{{responseHeader}}}',
responseHeader: '{{{escapeSingleQuotedString responseHeader}}}',
{{/if}}
{{#if errors}}
errors: {
Expand Down
18 changes: 18 additions & 0 deletions src/utils/registerHandlebarHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,24 @@ export const registerHandlebarHelpers = (root: {
return value.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\${/g, '\\${');
});

// Several templates interpolate spec-derived strings (the request path,
// a server URL, a parameter/header/media-type name, a schema
// type/format/pattern) directly into a single-quoted JS string literal,
// e.g. `url: '{{{path}}}'`. Without escaping, a single quote in that
// value closes the string literal early and the remainder is evaluated
// as live JS: a spec path of `/x'+require('fs').writeFileSync(...)+'`
// becomes `url: '/x'+require('fs').writeFileSync(...)+'',`, which
// executes whenever the generated code runs (as soon as the containing
// module is imported, for module-level fields like a server URL, or on
// every call, for per-request fields like the path). Escape backslashes
// and single quotes so the value can only ever be interpreted as string
// data.
Handlebars.registerHelper('escapeSingleQuotedString', function (value: unknown): string {
return String(value ?? '')
.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'");
});

Handlebars.registerHelper('camelCase', function (value: string): string {
return camelCase(value);
});
Expand Down