// Copyright (c) 2017 The Go Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
package safehtml
import (
"fmt"
"regexp"
"sort"
"strings"
"flag"
"github.com/google/safehtml/internal/safehtmlutil"
)
// A TrustedResourceURL is an immutable string-like type referencing the
// application’s own, trusted resources. It can be used to safely load scripts,
// CSS and other sensitive resources without the risk of untrusted code execution.
// For example, it is unsafe to insert a plain string in a
//
//
//
// context since the URL may originate from untrusted user input and the
// script it is pointing to may thus be controlled by an attacker. It is,
// however, safe to use a TrustedResourceURL since its value is known to never
// have left application control.
//
// In order to ensure that an attacker cannot influence the TrustedResourceURL
// value, a TrustedResourceURL can only be instantiated from compile-time
// constant string literals, command-line flags or a combination of the two,
// but never from arbitrary string values potentially representing untrusted user input.
//
// Additionally, TrustedResourceURLs can be serialized and passed along within
// the application via protocol buffers. It is the application’s responsibility
// to ensure that the protocol buffers originate from within the application
// itself and not from an external entity outside its trust domain.
//
// Note that TrustedResourceURLs can also use absolute paths (starting with '/')
// and relative paths. This allows the same binary to be used for different
// hosts without hard-coding the hostname in a string literal.
type TrustedResourceURL struct {
// We declare a TrustedResourceURL not as a string but as a struct wrapping a string
// to prevent construction of TrustedResourceURL values through string conversion.
str string
}
// TrustedResourceURLWithParams constructs a new TrustedResourceURL with the
// given key-value pairs added as query parameters.
//
// Map entries with empty keys or values are ignored. The order of appended
// keys is guaranteed to be stable but may differ from the order in input.
func TrustedResourceURLWithParams(t TrustedResourceURL, params map[string]string) TrustedResourceURL {
url := t.str
var fragment string
if i := strings.IndexByte(url, '#'); i != -1 {
// The fragment identifier component will always appear at the end
// of the URL after the query segment. It is therefore safe to
// trim the fragment from the tail of the URL and re-append it after
// all query parameters have been added.
// See https://tools.ietf.org/html/rfc3986#appendix-A.
fragment = url[i:]
url = url[:i]
}
sep := "?"
if i := strings.IndexRune(url, '?'); i != -1 {
// The first "?" in a URL indicates the start of the query component.
// See https://tools.ietf.org/html/rfc3986#section-3.4
if i == len(url)-1 {
sep = ""
} else {
sep = "&"
}
}
stringParams := make([]string, 0, len(params))
for k, v := range params {
if k == "" || v == "" {
continue
}
stringParam := safehtmlutil.QueryEscapeURL(k) + "=" + safehtmlutil.QueryEscapeURL(v)
stringParams = append(stringParams, stringParam)
}
if len(stringParams) > 0 {
sort.Strings(stringParams)
url += sep + strings.Join(stringParams, "&")
}
return TrustedResourceURL{url + fragment}
}
// TrustedResourceURLFromConstant constructs a TrustedResourceURL with its underlying
// URL set to the given url, which must be an untyped string constant.
//
// No runtime validation or sanitization is performed on url; being under
// application control, it is simply assumed to comply with the TrustedResourceURL type
// contract.
func TrustedResourceURLFromConstant(url stringConstant) TrustedResourceURL {
return TrustedResourceURL{string(url)}
}
// TrustedResourceURLFormatFromConstant constructs a TrustedResourceURL from a
// format string, which must be an untyped string constant, and string arguments.
//
// Arguments are specified as a map of labels, which must contain only alphanumeric
// and '_' runes, to string values. Each `%{