/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.template.soy.passes; import static com.google.template.soy.parsepasses.contextautoesc.ContentSecurityPolicyPass.CSP_NONCE_VARIABLE_NAME; import com.google.template.soy.basetree.Node; import com.google.template.soy.basetree.NodeVisitor; import com.google.template.soy.error.ErrorReporter; import com.google.template.soy.error.SoyErrorKind; import com.google.template.soy.exprtree.VarDefn; import com.google.template.soy.exprtree.VarDefn.Kind; import com.google.template.soy.exprtree.VarRefNode; import com.google.template.soy.soytree.SoyNode; import com.google.template.soy.soytree.SoyTreeUtils; import com.google.template.soy.soytree.TemplateNode; import com.google.template.soy.soytree.defn.TemplateParam; /** * A visitor that checks for certain misuses of template parameters: * * <ul> * <li>There should be no explicit use of injected parameters called {@code csp_nonce}. These * should all be inserted by the soy compiler as part of the content security pass. * </ul> * * <p>TODO(lukes): add a check for unresolved globals that match params. */ final class CheckInvalidParamsVisitor { private static final SoyErrorKind IJ_CSP_NONCE_REFERENCE = SoyErrorKind.of( "Found a use of the injected parameter ''csp_nonce''. This parameter is reserved " + "by the Soy compiler for Content Security Policy support."); private final ErrorReporter errorReporter; CheckInvalidParamsVisitor(ErrorReporter errorReporter) { this.errorReporter = errorReporter; } void exec(SoyNode node) { // Search for injected params named 'csp_nonce'. This includes: // * @inject params // * $ij references SoyTreeUtils.visitAllNodes( node, new NodeVisitor<Node, Boolean>() { @Override public Boolean exec(Node node) { if (node instanceof TemplateNode) { TemplateNode template = (TemplateNode) node; for (TemplateParam param : template.getAllParams()) { if (param.isInjected() && param.name().equals(CSP_NONCE_VARIABLE_NAME)) { errorReporter.report(node.getSourceLocation(), IJ_CSP_NONCE_REFERENCE); } } } if (node instanceof VarRefNode) { VarDefn defn = ((VarRefNode) node).getDefnDecl(); if (defn.kind() == Kind.IJ_PARAM && defn.name().equals(CSP_NONCE_VARIABLE_NAME)) { errorReporter.report(node.getSourceLocation(), IJ_CSP_NONCE_REFERENCE); } } return true; // keep going } }); } }