Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: fixed language param of code macro

...

Assets can also be referenced directly in templates. Two binding prefixes exist for this: "asset:" and "context:". The "asset:" prefix can obtain assets from the classpath (the default) or from the web context (by specifying the "context:" domain explicitly):

Code Block
java
languagejava

<img src="${asset:context:image/tapestry_banner.gif}" alt="Banner"/>

...

Because accessing context assets is so common, the "context:" binding prefix was introduced:

Code Block
java
languagejava

<img src="${context:image/tapestry_banner.gif}" alt="Banner"/>

...

Components learn about assets via injection. The @Inject annotation allows Assets to be injected into components as read-only properties. The path to the resource is specified using the Path annotation:

Code Block
java
languagejava

@Inject
@Path("context:images/tapestry_banner.gif")
private Asset banner;

...

You can use relative paths with domains (if you omit the prefix):

Code Block
java
languagejava

@Inject
@Path("../edit.png")
private Asset icon;

...

Symbols inside the annotation value are expanded. This allows you to define a symbol and reference it as part of the path. For example, you could contribute a symbol named "skin.root" as "context:skins/basic" and then reference an asset from within it:

Code Block
java
languagejava

@Inject
@Path("${skin.root}/style.css")
private Asset style;

...

  • Your Login page exposes a classpath asset, icon.png.
  • A malicious client copies the URL, /assets/1.0.0/app/pages/icon.png,

    Wiki Markup
    {footnote}This would indicate that the Login page is actually inside a library, which is unlikely. More likely, {{icon.png}} is a context asset and the malicious user guessed the path for {{Login.class}} by looking at the Tapestry source code.{footnote}

    and changes the file name to Login.class.

  • The client decompiles the class file and spots your secret emergency password: goodbye security!

    Wiki Markup
    {footnote}Never create such back doors, of course!{footnote}

Fortunately, this can't happen. Files with extension ".class" are secured; they must be accompanied in the URL with a query parameter that is the MD5 hash of the file's contents. If the query parameter is absent, or doesn't match the actual file's content, the request is rejected.

When your code exposes an Asset, the URL will automatically include the query parameter if the file type is secured. The malicious user is locked out of access to the files

Wiki Markup
{footnote}Unless they already have the files so that they can generate the MD5 checksum ... to get access to the files they already have.{footnote}

.

 

By default, Tapestry secures file extensions ".class', ".tml" and ".properties". The list can be extended by contributing to the ResourceDigestGenerator service:

Code Block
languagejava
titleAppModule.java (partial)java

public static void contributeResourceDigestGenerator(Configuration<String> configuration)
{
    configuration.add("xyz");
}

...

By default, this service does nothing. You should include a third-party library, for example the tapestry-yuicompressor project, which makes it possible to minimize CSS and JavaScript files.

Code Block
languagexml
titlepom.xml (partial)
langxml

<dependency>
    <groupId>org.apache.tapestry</groupId>
    <artifactId>tapestry-yuicompressor</artifactId>
    <version>5.3.1</version>
</dependency>

By adding this dependency, all your JavaScript and CSS files will be minimized when PRODUCTION_MODE=true. You can force the minimization of these files, by changing the value of the constant SymbolConstants.MINIFICATION_ENABLED in your module class (usually AppModule.java):

Code Block
languagejava
titleAppModule.java (partial)

@Contribute(SymbolProvider.class)
@ApplicationDefaults
public static void contributeApplicationDefaults(MappedConfiguration<String, String> configuration)
{
    configuration.add(SymbolConstants.MINIFICATION_ENABLED, "true");
}

If you want to add your own minimizer for particular types of assets, you can contribute to the ResourceMinimizer service. The service configuration maps the MIME-TYPE of your resource to an implementation of the ResourceMinimizer interface.

Code Block
languagejava
titleAppModule.java (partial)

@Contribute(ResourceMinimizer.class)
@Primary
public static void contributeMinimizers(MappedConfiguration<String, ResourceMinimizer> configuration)
{
    configuration.addInstance("text/coffeescript", CoffeeScriptMinimizer.class);
}

 

 

Wiki Markup
{display-footnotes}