forked from loafle/openapi-generator-original
[core] Templating: limit compilation to supported extensions and constrain target paths (#6598)
This commit is contained in:
parent
91ea6a17d9
commit
a6d30cac9d
@ -45,6 +45,16 @@ public interface TemplatingEngineAdapter {
|
||||
*/
|
||||
String[] getFileExtensions();
|
||||
|
||||
/**
|
||||
* Determine if the adapter handles compilation of the file
|
||||
* @param filename The template filename
|
||||
*
|
||||
* @return True if the file should be compiled by this adapter, else false.
|
||||
*/
|
||||
default boolean handlesFile(String filename) {
|
||||
return filename != null && filename.length() > 0 && Arrays.stream(getFileExtensions()).anyMatch(i -> filename.endsWith("." + i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles a template into a string
|
||||
*
|
||||
@ -65,9 +75,10 @@ public interface TemplatingEngineAdapter {
|
||||
* @param templateFile The original target filename
|
||||
* @return True if the template is available in the template search path, false if it can not be found
|
||||
*/
|
||||
@SuppressWarnings({"java:S2093"}) // ignore java:S2093 because we have double-assignment to the closeable
|
||||
default boolean templateExists(TemplatingExecutor generator, String templateFile) {
|
||||
return Arrays.stream(getFileExtensions()).anyMatch(ext -> {
|
||||
int idx = templateFile.lastIndexOf(".");
|
||||
int idx = templateFile.lastIndexOf('.');
|
||||
String baseName;
|
||||
if (idx > 0 && idx < templateFile.length() - 1) {
|
||||
baseName = templateFile.substring(0, idx);
|
||||
|
@ -913,6 +913,11 @@ public class DefaultGenerator implements Generator {
|
||||
File target = new File(adjustedOutputFilename);
|
||||
if (ignoreProcessor.allowsFile(target)) {
|
||||
if (shouldGenerate) {
|
||||
Path outDir = java.nio.file.Paths.get(this.config.getOutputDir()).toAbsolutePath();
|
||||
Path absoluteTarget = target.toPath().toAbsolutePath();
|
||||
if (!absoluteTarget.startsWith(outDir)) {
|
||||
throw new RuntimeException(String.format(Locale.ROOT, "Target files must be generated within the output directory; absoluteTarget=%s outDir=%s", absoluteTarget, outDir));
|
||||
}
|
||||
return this.templateProcessor.write(templateData,templateName, target);
|
||||
} else {
|
||||
this.templateProcessor.skip(target.toPath(), String.format(Locale.ROOT, "Skipped by %s options supplied by user.", skippedByOption));
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.openapitools.codegen;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openapitools.codegen.api.TemplatePathLocator;
|
||||
import org.openapitools.codegen.api.TemplateProcessor;
|
||||
@ -12,14 +13,8 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@ -59,6 +54,10 @@ public class TemplateManager implements TemplatingExecutor, TemplateProcessor {
|
||||
throw new TemplateNotFoundException(name);
|
||||
}
|
||||
|
||||
if (name == null || name.contains("..")) {
|
||||
throw new IllegalArgumentException("Template location must be constrained to template directory.");
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
@ -104,7 +103,12 @@ public class TemplateManager implements TemplatingExecutor, TemplateProcessor {
|
||||
* @param name The location of the template
|
||||
* @return The raw template contents
|
||||
*/
|
||||
@SuppressWarnings({"java:S112"})
|
||||
// ignored rule java:S112 as RuntimeException is used to match previous exception type
|
||||
public String readTemplate(String name) {
|
||||
if (name == null || name.contains("..")) {
|
||||
throw new IllegalArgumentException("Template location must be constrained to template directory.");
|
||||
}
|
||||
try {
|
||||
Reader reader = getTemplateReader(name);
|
||||
if (reader == null) {
|
||||
@ -118,15 +122,12 @@ public class TemplateManager implements TemplatingExecutor, TemplateProcessor {
|
||||
throw new RuntimeException("can't load template " + name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("squid:S2095")
|
||||
// ignored rule as used in the CLI and it's required to return a reader
|
||||
@SuppressWarnings({"squid:S2095", "java:S112"})
|
||||
// ignored rule squid:S2095 as used in the CLI and it's required to return a reader
|
||||
// ignored rule java:S112 as RuntimeException is used to match previous exception type
|
||||
public Reader getTemplateReader(String name) {
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = this.getClass().getClassLoader().getResourceAsStream(getCPResourcePath(name));
|
||||
if (is == null) {
|
||||
is = new FileInputStream(new File(name)); // May throw but never return a null value
|
||||
}
|
||||
InputStream is = getInputStream(name);
|
||||
return new InputStreamReader(is, StandardCharsets.UTF_8);
|
||||
} catch (FileNotFoundException e) {
|
||||
LOGGER.error(e.getMessage());
|
||||
@ -134,6 +135,18 @@ public class TemplateManager implements TemplatingExecutor, TemplateProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getInputStream(String name) throws FileNotFoundException {
|
||||
InputStream is;
|
||||
is = this.getClass().getClassLoader().getResourceAsStream(getCPResourcePath(name));
|
||||
if (is == null) {
|
||||
if (name == null || name.contains("..")) {
|
||||
throw new IllegalArgumentException("Template location must be constrained to template directory.");
|
||||
}
|
||||
is = new FileInputStream(new File(name)); // May throw but never return a null value
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes data to a compiled template
|
||||
*
|
||||
@ -145,18 +158,32 @@ public class TemplateManager implements TemplatingExecutor, TemplateProcessor {
|
||||
*/
|
||||
@Override
|
||||
public File write(Map<String, Object> data, String template, File target) throws IOException {
|
||||
String templateContent = this.engineAdapter.compileTemplate(this, data, template);
|
||||
return writeToFile(target.getPath(), templateContent);
|
||||
if (this.engineAdapter.handlesFile(template)) {
|
||||
// Only pass files with valid endings through template engine
|
||||
String templateContent = this.engineAdapter.compileTemplate(this, data, template);
|
||||
return writeToFile(target.getPath(), templateContent);
|
||||
} else {
|
||||
// Do a straight copy of the file if not listed as supported by the template engine.
|
||||
InputStream is;
|
||||
try {
|
||||
// look up the file using the same template resolution logic the adapters would use.
|
||||
String fullTemplatePath = getFullTemplateFile(template);
|
||||
is = getInputStream(fullTemplatePath);
|
||||
} catch (TemplateNotFoundException ex) {
|
||||
is = new FileInputStream(Paths.get(template).toFile());
|
||||
}
|
||||
return writeToFile(target.getAbsolutePath(), IOUtils.toByteArray(is));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignore(Path path, String context) {
|
||||
LOGGER.info("Ignored {} ({})", path.toString(), context);
|
||||
LOGGER.info("Ignored {} ({})", path, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skip(Path path, String context) {
|
||||
LOGGER.info("Skipped {} ({})", path.toString(), context);
|
||||
LOGGER.info("Skipped {} ({})", path, context);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,23 +216,23 @@ public class TemplateManager implements TemplatingExecutor, TemplateProcessor {
|
||||
try {
|
||||
tempFile = writeToFileRaw(tempFilename, contents);
|
||||
if (!filesEqual(tempFile, outputFile)) {
|
||||
LOGGER.info("writing file " + filename);
|
||||
LOGGER.info("writing file {}", filename);
|
||||
Files.move(tempFile.toPath(), outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
tempFile = null;
|
||||
} else {
|
||||
LOGGER.info("skipping unchanged file " + filename);
|
||||
LOGGER.info("skipping unchanged file {}", filename);
|
||||
}
|
||||
} finally {
|
||||
if (tempFile != null && tempFile.exists()) {
|
||||
try {
|
||||
tempFile.delete();
|
||||
Files.delete(tempFile.toPath());
|
||||
} catch (Exception ex) {
|
||||
LOGGER.error("Error removing temporary file " + tempFile, ex);
|
||||
LOGGER.error("Error removing temporary file {}", tempFile, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("writing file " + filename);
|
||||
LOGGER.info("writing file {}", filename);
|
||||
outputFile = writeToFileRaw(filename, contents);
|
||||
}
|
||||
|
||||
@ -216,7 +243,7 @@ public class TemplateManager implements TemplatingExecutor, TemplateProcessor {
|
||||
// Use Paths.get here to normalize path (for Windows file separator, space escaping on Linux/Mac, etc)
|
||||
File output = Paths.get(filename).toFile();
|
||||
if (this.options.isSkipOverwrite() && output.exists()) {
|
||||
LOGGER.info("skip overwrite of file " + filename);
|
||||
LOGGER.info("skip overwrite of file {}", filename);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,11 @@ import java.util.Locale;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
public class TemplatingEngineLoader {
|
||||
private TemplatingEngineLoader() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
@SuppressWarnings({"java:S112"}) // ignore java:S112 as generic RuntimeException is acceptable here
|
||||
public static TemplatingEngineAdapter byIdentifier(String id) {
|
||||
ServiceLoader<TemplatingEngineAdapter> loader = ServiceLoader.load(TemplatingEngineAdapter.class, TemplatingEngineLoader.class.getClassLoader());
|
||||
|
||||
@ -37,7 +42,7 @@ public class TemplatingEngineLoader {
|
||||
// Attempt to load skipping SPI
|
||||
return (TemplatingEngineAdapter) Class.forName(id).getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format(Locale.ROOT, "Couldn't load template engine adapter %s. Available options: \n%s", id, sb.toString()), e);
|
||||
throw new RuntimeException(String.format(Locale.ROOT, "Couldn't load template engine adapter %s. Available options: %n%s", id, sb.toString()), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,35 +129,35 @@ public class PhpLumenServerCodegen extends AbstractPhpCodegen {
|
||||
supportingFiles.add(new SupportingFile("storage_logs_gitignore", srcBasePath + File.separator + "storage" + File.separator + "framework" + File.separator + "views", ".gitignore"));
|
||||
supportingFiles.add(new SupportingFile("storage_framework_cache_gitignore", srcBasePath + File.separator + "storage" + File.separator + "framework" + File.separator + "cache", ".gitignore"));
|
||||
supportingFiles.add(new SupportingFile("storage_logs_gitignore", srcBasePath + File.separator + "storage" + File.separator + "framework" + File.separator + "cache" + File.separator + "data", ".gitignore"));
|
||||
supportingFiles.add(new SupportingFile("artisan", srcBasePath, "artisan"));
|
||||
supportingFiles.add(new SupportingFile("artisan.mustache", srcBasePath, "artisan"));
|
||||
supportingFiles.add(new SupportingFile("composer.mustache", srcBasePath, "composer.json"));
|
||||
supportingFiles.add(new SupportingFile("readme.md", srcBasePath, "readme.md"));
|
||||
supportingFiles.add(new SupportingFile("User.php", srcBasePath + File.separator + "app", "User.php"));
|
||||
supportingFiles.add(new SupportingFile("Kernel.php", srcBasePath + File.separator + "app" + File.separator + "Console", "Kernel.php"));
|
||||
supportingFiles.add(new SupportingFile("User.php.mustache", srcBasePath + File.separator + "app", "User.php"));
|
||||
supportingFiles.add(new SupportingFile("Kernel.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Console", "Kernel.php"));
|
||||
supportingFiles.add(new SupportingFile(".gitkeep", srcBasePath + File.separator + "app" + File.separator + "Console" + File.separator + "Commands", ".gitkeep"));
|
||||
supportingFiles.add(new SupportingFile("Event.php", srcBasePath + File.separator + "app" + File.separator + "Events", "Event.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleEvent.php", srcBasePath + File.separator + "app" + File.separator + "Events", "ExampleEvent.php"));
|
||||
supportingFiles.add(new SupportingFile("Handler.php", srcBasePath + File.separator + "app" + File.separator + "Exceptions", "Handler.php"));
|
||||
supportingFiles.add(new SupportingFile("Controller.php", srcBasePath + File.separator + "app" + File.separator + "Http" + File.separator + "Controllers" + File.separator, "Controller.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleController.php", srcBasePath + File.separator + "app" + File.separator + "Http" + File.separator + "Controllers" + File.separator, "ExampleController.php"));
|
||||
supportingFiles.add(new SupportingFile("Authenticate.php", srcBasePath + File.separator + "app" + File.separator + "Http" + File.separator + "Middleware" + File.separator, "Authenticate.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleMiddleware.php", srcBasePath + File.separator + "app" + File.separator + "Http" + File.separator + "Middleware" + File.separator, "ExampleMiddleware.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleJob.php", srcBasePath + File.separator + "app" + File.separator + "Jobs", "ExampleJob.php"));
|
||||
supportingFiles.add(new SupportingFile("Job.php", srcBasePath + File.separator + "app" + File.separator + "Jobs", "Job.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleListener.php", srcBasePath + File.separator + "app" + File.separator + "Listeners", "ExampleListener.php"));
|
||||
supportingFiles.add(new SupportingFile("AppServiceProvider.php", srcBasePath + File.separator + "app" + File.separator + "Providers", "AppServiceProvider.php"));
|
||||
supportingFiles.add(new SupportingFile("AuthServiceProvider.php", srcBasePath + File.separator + "app" + File.separator + "Providers", "AuthServiceProvider.php"));
|
||||
supportingFiles.add(new SupportingFile("EventServiceProvider.php", srcBasePath + File.separator + "app" + File.separator + "Providers", "EventServiceProvider.php"));
|
||||
supportingFiles.add(new SupportingFile("app.php", srcBasePath + File.separator + "bootstrap", "app.php"));
|
||||
supportingFiles.add(new SupportingFile("ModelFactory.php", srcBasePath + File.separator + "database" + File.separator + "factories", "ModelFactory.php"));
|
||||
supportingFiles.add(new SupportingFile("Event.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Events", "Event.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleEvent.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Events", "ExampleEvent.php"));
|
||||
supportingFiles.add(new SupportingFile("Handler.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Exceptions", "Handler.php"));
|
||||
supportingFiles.add(new SupportingFile("Controller.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Http" + File.separator + "Controllers" + File.separator, "Controller.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleController.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Http" + File.separator + "Controllers" + File.separator, "ExampleController.php"));
|
||||
supportingFiles.add(new SupportingFile("Authenticate.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Http" + File.separator + "Middleware" + File.separator, "Authenticate.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleMiddleware.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Http" + File.separator + "Middleware" + File.separator, "ExampleMiddleware.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleJob.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Jobs", "ExampleJob.php"));
|
||||
supportingFiles.add(new SupportingFile("Job.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Jobs", "Job.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleListener.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Listeners", "ExampleListener.php"));
|
||||
supportingFiles.add(new SupportingFile("AppServiceProvider.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Providers", "AppServiceProvider.php"));
|
||||
supportingFiles.add(new SupportingFile("AuthServiceProvider.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Providers", "AuthServiceProvider.php"));
|
||||
supportingFiles.add(new SupportingFile("EventServiceProvider.php.mustache", srcBasePath + File.separator + "app" + File.separator + "Providers", "EventServiceProvider.php"));
|
||||
supportingFiles.add(new SupportingFile("app.php.mustache", srcBasePath + File.separator + "bootstrap", "app.php"));
|
||||
supportingFiles.add(new SupportingFile("ModelFactory.php.mustache", srcBasePath + File.separator + "database" + File.separator + "factories", "ModelFactory.php"));
|
||||
supportingFiles.add(new SupportingFile(".gitkeep", srcBasePath + File.separator + "database" + File.separator + "migrations", ".gitkeep"));
|
||||
supportingFiles.add(new SupportingFile("DatabaseSeeder.php", srcBasePath + File.separator + "database" + File.separator + "seeds", "DatabaseSeeder.php"));
|
||||
supportingFiles.add(new SupportingFile("DatabaseSeeder.php.mustache", srcBasePath + File.separator + "database" + File.separator + "seeds", "DatabaseSeeder.php"));
|
||||
supportingFiles.add(new SupportingFile(".htaccess", srcBasePath + File.separator + "public", ".htaccess"));
|
||||
supportingFiles.add(new SupportingFile("index.php", srcBasePath + File.separator + "public", "index.php"));
|
||||
supportingFiles.add(new SupportingFile("index.php.mustache", srcBasePath + File.separator + "public", "index.php"));
|
||||
supportingFiles.add(new SupportingFile(".gitkeep", srcBasePath + File.separator + "resources" + File.separator + "views", ".gitkeep"));
|
||||
supportingFiles.add(new SupportingFile("routes.mustache", srcBasePath + File.separator + "routes", "web.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleTest.php", srcBasePath + File.separator + "tests", "ExampleTest.php"));
|
||||
supportingFiles.add(new SupportingFile("TestCase.php", srcBasePath + File.separator + "tests", "TestCase.php"));
|
||||
supportingFiles.add(new SupportingFile("ExampleTest.php.mustache", srcBasePath + File.separator + "tests", "ExampleTest.php"));
|
||||
supportingFiles.add(new SupportingFile("TestCase.php.mustache", srcBasePath + File.separator + "tests", "TestCase.php"));
|
||||
supportingFiles.add(new SupportingFile("editorconfig", srcBasePath, ".editorconfig"));
|
||||
supportingFiles.add(new SupportingFile("styleci", srcBasePath, ".styleci.yml"));
|
||||
supportingFiles.add(new SupportingFile("phpunit.xml", srcBasePath, "phpunit.xml"));
|
||||
|
@ -236,7 +236,8 @@ public class PythonBluePlanetServerCodegen extends AbstractPythonConnexionServer
|
||||
|
||||
@Override
|
||||
public String modelDocFileFolder() {
|
||||
return (outputFolder + File.separator + modelDocPath).replace('.', File.separatorChar);
|
||||
// character replaces should _only_ occur on paths we define. Don't replace on outputFolder (which is supplied by the user and should always be considered correct)
|
||||
return outputFolder + File.separator + modelDocPath.replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,13 +35,17 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class HandlebarsEngineAdapter extends AbstractTemplatingEngineAdapter {
|
||||
static Logger LOGGER = LoggerFactory.getLogger(HandlebarsEngineAdapter.class);
|
||||
static final Logger LOGGER = LoggerFactory.getLogger(HandlebarsEngineAdapter.class);
|
||||
private final String[] extensions = new String[]{"handlebars", "hbs"};
|
||||
|
||||
// We use this as a simple lookup for valid file name extensions. This adapter will inspect .mustache (built-in) and infer the relevant handlebars filename
|
||||
private final String[] canCompileFromExtensions = new String[]{".handlebars",".hbs",".mustache"};
|
||||
|
||||
/**
|
||||
* Provides an identifier used to load the adapter. This could be a name, uuid, or any other string.
|
||||
*
|
||||
@ -71,7 +75,7 @@ public class HandlebarsEngineAdapter extends AbstractTemplatingEngineAdapter {
|
||||
|
||||
Handlebars handlebars = new Handlebars(loader);
|
||||
handlebars.registerHelperMissing((obj, options) -> {
|
||||
LOGGER.warn(String.format(Locale.ROOT, "Unregistered helper name '%s', processing template:\n%s", options.helperName, options.fn.text()));
|
||||
LOGGER.warn(String.format(Locale.ROOT, "Unregistered helper name '%s', processing template:%n%s", options.helperName, options.fn.text()));
|
||||
return "";
|
||||
});
|
||||
handlebars.registerHelper("json", Jackson2Helper.INSTANCE);
|
||||
@ -82,6 +86,7 @@ public class HandlebarsEngineAdapter extends AbstractTemplatingEngineAdapter {
|
||||
return tmpl.apply(context);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"java:S108"})
|
||||
public TemplateSource findTemplate(TemplatingExecutor generator, String templateFile) {
|
||||
String[] possibilities = getModifiedFileLocation(templateFile);
|
||||
for (String file : possibilities) {
|
||||
@ -104,5 +109,17 @@ public class HandlebarsEngineAdapter extends AbstractTemplatingEngineAdapter {
|
||||
public String[] getFileExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the adapter handles compilation of the file
|
||||
*
|
||||
* @param filename The template filename
|
||||
* @return True if the file should be compiled by this adapter, else false.
|
||||
*/
|
||||
@Override
|
||||
public boolean handlesFile(String filename) {
|
||||
// disallow any extension-only files like ".hbs" or ".mustache", and only consider a file compilable if it's handlebars or mustache (from which we later infer the handlebars filename)
|
||||
return Arrays.stream(canCompileFromExtensions).anyMatch(suffix -> !suffix.equalsIgnoreCase(filename) && filename.endsWith(suffix));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ public class MustacheEngineAdapter implements TemplatingEngineAdapter {
|
||||
return "mustache";
|
||||
}
|
||||
|
||||
public String[] extensions = new String[]{"mustache"};
|
||||
private final String[] extensions = new String[]{"mustache"};
|
||||
Mustache.Compiler compiler = Mustache.compiler();
|
||||
|
||||
/**
|
||||
@ -61,6 +61,7 @@ public class MustacheEngineAdapter implements TemplatingEngineAdapter {
|
||||
return tmpl.execute(bundle);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"java:S108"}) // catch-all is expected, and is later thrown
|
||||
public Reader findTemplate(TemplatingExecutor generator, String name) {
|
||||
for (String extension : extensions) {
|
||||
try {
|
||||
@ -69,12 +70,6 @@ public class MustacheEngineAdapter implements TemplatingEngineAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
// support files without targeted extension (e.g. .gitignore, README.md), etc.
|
||||
try {
|
||||
return new StringReader(generator.getFullTemplateContents(name));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
throw new TemplateNotFoundException(name);
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ impl Request {
|
||||
let mut path = self.path;
|
||||
for (k, v) in self.path_params {
|
||||
// replace {id} with the value of the id path param
|
||||
{{=<% %>=}}path = path.replace(&format!("{{{}}}", k), &v);<%={{ }}=%>
|
||||
path = path.replace(&format!("{{{}}}", k), &v);
|
||||
}
|
||||
|
||||
for (k, v) in self.header_params {
|
||||
|
@ -47,6 +47,15 @@ public class TemplateManagerTest {
|
||||
assertEquals(manager.getFullTemplateContents("simple.mustache"), "{{name}} and {{age}}");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Template location must be constrained to template directory\\.")
|
||||
public void loadTemplateContentsThrowsForEscapingTemplates(){
|
||||
TemplateManagerOptions opts = new TemplateManagerOptions(false,false);
|
||||
TemplateManager manager = new TemplateManager(opts, mustacheEngineAdapter, new TemplatePathLocator[]{ locator });
|
||||
|
||||
manager.getFullTemplateContents("../simple.mustache");
|
||||
fail("Expected an exception that did not occur");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readTemplate(){
|
||||
TemplateManagerOptions opts = new TemplateManagerOptions(false,false);
|
||||
@ -71,6 +80,15 @@ public class TemplateManagerTest {
|
||||
assertTrue(manager.getTemplateReader("templating/templates/simple.mustache") instanceof InputStreamReader);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Template location must be constrained to template directory\\.")
|
||||
public void getTemplateReaderThrowsForEscapingTemplates(){
|
||||
TemplateManagerOptions opts = new TemplateManagerOptions(false,false);
|
||||
TemplateManager manager = new TemplateManager(opts, mustacheEngineAdapter, new TemplatePathLocator[]{ locator });
|
||||
|
||||
manager.getTemplateReader("../templating/templates/simple.mustache");
|
||||
fail("Expected an exception that did not occur");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeViaMustacheAdapter() throws IOException {
|
||||
TemplateManagerOptions opts = new TemplateManagerOptions(false,false);
|
||||
@ -91,6 +109,28 @@ public class TemplateManagerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeUsingMustacheAdapterSkipsNonMustache() throws IOException {
|
||||
TemplateManagerOptions opts = new TemplateManagerOptions(false,false);
|
||||
TemplateManager manager = new TemplateManager(opts, mustacheEngineAdapter, new TemplatePathLocator[]{ locator });
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("this", "this");
|
||||
data.put("that", "1234");
|
||||
|
||||
Path target = Files.createTempDirectory("test-templatemanager");
|
||||
try {
|
||||
File output = new File(target.toFile(), ".gitignore");
|
||||
File written = manager.write(data, ".gitignore", output);
|
||||
assertEquals(Files.readAllLines(written.toPath()).get(0), "# Should not escape {{this}} or that: {{{that}}}");
|
||||
|
||||
output = new File(target.toFile(), "README.md");
|
||||
written = manager.write(data, "README.md", output);
|
||||
assertEquals(Files.readAllLines(written.toPath()).get(0), "This should not escape `{{this}}` or `{{{that}}}` or `{{name}} counts{{#each numbers}} {{.}}{{/each}}`");
|
||||
} finally {
|
||||
target.toFile().delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipOverwriteViaOption() throws IOException {
|
||||
TemplateManagerOptions opts = new TemplateManagerOptions(false,true);
|
||||
@ -186,4 +226,26 @@ public class TemplateManagerTest {
|
||||
target.toFile().delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeUsingHandlebarsAdapterSkipsNonHandlebars() throws IOException {
|
||||
TemplateManagerOptions opts = new TemplateManagerOptions(false,false);
|
||||
TemplateManager manager = new TemplateManager(opts, handlebarsEngineAdapter, new TemplatePathLocator[]{ locator });
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("this", "this");
|
||||
data.put("that", "1234");
|
||||
|
||||
Path target = Files.createTempDirectory("test-templatemanager");
|
||||
try {
|
||||
File output = new File(target.toFile(), ".gitignore");
|
||||
File written = manager.write(data, ".gitignore", output);
|
||||
assertEquals(Files.readAllLines(written.toPath()).get(0), "# Should not escape {{this}} or that: {{{that}}}");
|
||||
|
||||
output = new File(target.toFile(), "README.md");
|
||||
written = manager.write(data, "README.md", output);
|
||||
assertEquals(Files.readAllLines(written.toPath()).get(0), "This should not escape `{{this}}` or `{{{that}}}` or `{{name}} counts{{#each numbers}} {{.}}{{/each}}`");
|
||||
} finally {
|
||||
target.toFile().delete();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package org.openapitools.codegen.templating;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class HandlebarsEngineAdapterTest {
|
||||
@Test(dataProvider = "handlesFileExpectations")
|
||||
public void checkHandleFiles(String input, boolean shouldHandle, String message) {
|
||||
HandlebarsEngineAdapter adapter = new HandlebarsEngineAdapter();
|
||||
boolean handles = adapter.handlesFile(input);
|
||||
assertEquals(handles, shouldHandle, message);
|
||||
}
|
||||
|
||||
@DataProvider(name = "handlesFileExpectations")
|
||||
public Object[][] handlesFileExpectations() {
|
||||
// input, shouldHandle, message
|
||||
return new Object[][]{
|
||||
{"api.handlebars", true, "Expected to support handlebars extension"},
|
||||
{"api.hbs", true, "Expected to support hbs extension"},
|
||||
{"model.handlebars", true, "Expected to support handlebars extension"},
|
||||
{"model.hbs", true, "Expected to support hbs extension"},
|
||||
{"libraries/some/api.handlebars", true, "Expected to support handlebars extension for libraries"},
|
||||
{"libraries/some/api.hbs", true, "Expected to support hbs extension for libraries"},
|
||||
{"api.mustache", true, "Expected to support inferring handlebars extension from a mustache input"},
|
||||
{"model.mustache", true, "Expected to support inferring handlebars extension from a mustache input"},
|
||||
{"libraries/some/api.mustache", true, "Expected to support inferring handlebars extension from a mustache input for libraries"},
|
||||
{"libraries/some/model.mustache", true, "Expected to support inferring handlebars extension from a mustache input for libraries"},
|
||||
{".hbs", false, "Should not consider .hbs a valid file to process"},
|
||||
{".handlebars", false, "Should not consider .handlebars a valid file to process"},
|
||||
{".gitignore", false, "Should not attempt to handle .gitignore"},
|
||||
{"README.md", false, "Should not attempt to handle non-handlebars extensions (other than mustache)"}
|
||||
};
|
||||
}
|
||||
}
|
1
modules/openapi-generator/src/test/resources/templating/templates/.gitignore
vendored
Normal file
1
modules/openapi-generator/src/test/resources/templating/templates/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
# Should not escape {{this}} or that: {{{that}}}
|
@ -0,0 +1 @@
|
||||
This should not escape `{{this}}` or `{{{that}}}` or `{{name}} counts{{#each numbers}} {{.}}{{/each}}`
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
@ -68,12 +68,12 @@
|
||||
@if (Route::has('login'))
|
||||
<div class="top-right links">
|
||||
@auth
|
||||
<a href="">Home</a>
|
||||
<a href="{{ url('/home') }}">Home</a>
|
||||
@else
|
||||
<a href="">Login</a>
|
||||
<a href="{{ route('login') }}">Login</a>
|
||||
|
||||
@if (Route::has('register'))
|
||||
<a href="">Register</a>
|
||||
<a href="{{ route('register') }}">Register</a>
|
||||
@endif
|
||||
@endauth
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user