From a8d769f9ae54cb7d0d48901b2d2a1f1fa010dd10 Mon Sep 17 00:00:00 2001 From: psamanoelton Date: Fri, 3 Apr 2026 13:41:39 -0600 Subject: [PATCH 1/8] Updated bazel version to 7.7.0 --- .bazelignore | 2 ++ .bazelrc | 1 + .bazelversion | 2 +- .gitattributes | 9 +++++++++ WORKSPACE | 32 +++++++++++++++++++++++++++++--- tensorboard/defs/defs.bzl | 4 ++++ 6 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 .bazelignore diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 00000000000..a1fd437354a --- /dev/null +++ b/.bazelignore @@ -0,0 +1,2 @@ +.bazel-user-root +.bazelisk-home diff --git a/.bazelrc b/.bazelrc index 393e2a552e3..9aaab2c286f 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,3 +1,4 @@ +common --noenable_bzlmod common --experimental_repo_remote_exec # from TensorFlow # Use C++ backing implementations for Python proto parsing and deserialization, diff --git a/.bazelversion b/.bazelversion index f22d756da39..1985849fb58 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -6.5.0 +7.7.0 diff --git a/.gitattributes b/.gitattributes index 752a9642c09..75e06739b02 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,10 @@ +* text=auto +*.bzl text eol=lf +*.sh text eol=lf +.bazel* text eol=lf +BUILD text eol=lf +BUILD.bazel text eol=lf +WORKSPACE text eol=lf +MODULE.bazel text eol=lf + third_party/rust/** -diff -merge linguist-generated=true diff --git a/WORKSPACE b/WORKSPACE index 67e90a09156..f32147cd650 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -18,10 +18,10 @@ versions.check( # Preemptively assume the next Bazel major version will break us, since historically they do, # and provide a clean error message in that case. Since the maximum version is inclusive rather # than exclusive, we set it to the 999th patch release of the current major version. - maximum_bazel_version = "6.999.0", + maximum_bazel_version = "7.999.0", # Keep this version in sync with: # * The BAZEL environment variable defined in .github/workflows/ci.yml, which is used for CI and nightly builds. - minimum_bazel_version = "6.5.0", + minimum_bazel_version = "7.7.0", ) http_archive( @@ -85,16 +85,21 @@ load("@build_bazel_rules_nodejs//:index.bzl", "yarn_install") yarn_install( name = "npm", - data = [ + # Under Bazel 7.7.0 on this stack, invoking patch-package from the + # repository rule is fragile. Apply the existing git-format patches + # directly in yarn_install instead. + post_install_patches = [ "//patches:@angular+build-tooling+0.0.0-7d103b83a07f132629592fc9918ce17d42a5e382.patch", "//patches:@bazel+concatjs+5.7.0.patch", ], + patch_args = ["-p1"], # "Some rules only work by referencing labels nested inside npm packages # and therefore require turning off exports_directories_only." # This includes "ts_library". # See: https://github.com/bazelbuild/rules_nodejs/wiki/Migrating-to-5.0#exports_directories_only exports_directories_only = False, package_json = "//:package.json", + package_json_remove = ["scripts.postinstall"], yarn_lock = "//:yarn.lock", ) @@ -169,6 +174,27 @@ http_archive( ], ) +# gRPC 1.48.2 still pins Apple rules that are too old for Bazel 7.x. +# Predeclare Bazel-7-compatible versions so grpc_deps()/grpc_extra_deps() reuse +# them instead of pulling their own older copies. +http_archive( + name = "build_bazel_rules_apple", + sha256 = "b4df908ec14868369021182ab191dbd1f40830c9b300650d5dc389e0b9266c8d", + urls = [ + "http://mirror.tensorflow.org/github.com/bazelbuild/rules_apple/releases/download/3.5.1/rules_apple.3.5.1.tar.gz", + "https://github.com/bazelbuild/rules_apple/releases/download/3.5.1/rules_apple.3.5.1.tar.gz", + ], +) + +http_archive( + name = "build_bazel_apple_support", + sha256 = "1ae6fcf983cff3edab717636f91ad0efff2e5ba75607fdddddfd6ad0dbdfaf10", + urls = [ + "http://mirror.tensorflow.org/github.com/bazelbuild/apple_support/releases/download/1.24.5/apple_support.1.24.5.tar.gz", + "https://github.com/bazelbuild/apple_support/releases/download/1.24.5/apple_support.1.24.5.tar.gz", + ], +) + load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps") grpc_deps() diff --git a/tensorboard/defs/defs.bzl b/tensorboard/defs/defs.bzl index 3f3ac904f29..32b9a9aa889 100644 --- a/tensorboard/defs/defs.bzl +++ b/tensorboard/defs/defs.bzl @@ -234,6 +234,10 @@ def tf_ng_web_test_suite(name, deps = [], **kwargs): deps = [ "%s_bundle" % name, ], + # rules_nodejs passes this through to rules_webtesting. An empty dict + # avoids forwarding a stray None-valued attribute to web_test under + # Bazel 7.7.0 with the currently pinned rules_webtesting stack. + browser_overrides = {}, ) def tf_svg_bundle(name, srcs, out): From 865671fb3d517f0e3fb068c750ab39606314f2da Mon Sep 17 00:00:00 2001 From: psamanoelton Date: Wed, 8 Apr 2026 10:41:33 -0600 Subject: [PATCH 2/8] update on protobuf 60 tests remaining to fix --- .bazelrc | 21 + WORKSPACE | 248 +++- patches/protobuf_6_31_1_java_export.patch | 49 + patches/rules_cc_protobuf.patch | 16 + patches/rules_closure_soy_cli.patch | 19 + tensorboard/compat/BUILD | 9 +- tensorboard/compat/__init__.py | 65 +- tensorboard/compat/compat_test.py | 33 + tensorboard/defs/protos.bzl | 66 +- tensorboard/manager.py | 38 + tensorboard/manager_test.py | 24 + tensorboard/pip_package/requirements.txt | 14 +- tensorboard/pip_package/requirements_dev.txt | 2 +- tensorboard/pip_package/test_pip_package.sh | 43 +- tensorboard/plugins/audio/summary.py | 10 +- tensorboard/plugins/histogram/summary.py | 22 +- tensorboard/plugins/image/summary.py | 10 +- tensorboard/plugins/scalar/summary.py | 15 +- tensorboard/plugins/text/summary.py | 15 +- third_party/compatibility_proxy/BUILD.bazel | 16 + third_party/compatibility_proxy/WORKSPACE | 1 + third_party/compatibility_proxy/proxy.bzl | 22 + third_party/protobuf_pip_deps/BUILD.bazel | 1 + third_party/protobuf_pip_deps/WORKSPACE | 1 + .../protobuf_pip_deps/requirements.bzl | 11 + .../protobuf_pip_deps_setuptools/BUILD.bazel | 5 + .../protobuf_pip_deps_setuptools/WORKSPACE | 1 + .../site-packages/.keep | 1 + third_party/repo.bzl | 91 ++ third_party/safe_html_types/BUILD.bazel | 16 + .../safe_html_types/META-INF/MANIFEST.MF | 6 + third_party/safe_html_types/WORKSPACE | 1 + .../common/html/types/BuilderUtils.java | 64 + .../html/types/CustomSafeUrlScheme.java | 227 ++++ .../com/google/common/html/types/Html.java | 120 ++ .../common/html/types/LegacyConversions.java | 84 ++ .../google/common/html/types/SafeHtml.java | 89 ++ .../common/html/types/SafeHtmlBuilder.java | 1079 +++++++++++++++++ .../common/html/types/SafeHtmlProto.java | 614 ++++++++++ .../html/types/SafeHtmlProtoOrBuilder.java | 41 + .../google/common/html/types/SafeHtmls.java | 198 +++ .../google/common/html/types/SafeScript.java | 101 ++ .../common/html/types/SafeScriptProto.java | 604 +++++++++ .../html/types/SafeScriptProtoOrBuilder.java | 41 + .../google/common/html/types/SafeScripts.java | 99 ++ .../google/common/html/types/SafeStyle.java | 146 +++ .../common/html/types/SafeStyleBuilder.java | 733 +++++++++++ .../common/html/types/SafeStyleProto.java | 604 +++++++++ .../html/types/SafeStyleProtoOrBuilder.java | 41 + .../common/html/types/SafeStyleSheet.java | 99 ++ .../html/types/SafeStyleSheetProto.java | 604 +++++++++ .../types/SafeStyleSheetProtoOrBuilder.java | 41 + .../common/html/types/SafeStyleSheets.java | 139 +++ .../google/common/html/types/SafeStyles.java | 102 ++ .../com/google/common/html/types/SafeUrl.java | 118 ++ .../common/html/types/SafeUrlProto.java | 606 +++++++++ .../html/types/SafeUrlProtoOrBuilder.java | 41 + .../google/common/html/types/SafeUrls.java | 259 ++++ .../common/html/types/TrustedResourceUrl.java | 85 ++ .../html/types/TrustedResourceUrlBuilder.java | 72 ++ .../html/types/TrustedResourceUrlProto.java | 606 +++++++++ .../TrustedResourceUrlProtoOrBuilder.java | 41 + .../html/types/TrustedResourceUrls.java | 109 ++ .../html/types/UncheckedConversions.java | 90 ++ .../common/html/types/package-info.java | 20 + .../html/types/testing/HtmlConversions.java | 193 +++ .../types/testing/assertions/Assertions.java | 51 + .../testing/assertions/package-info.java | 27 + .../html/types/testing/package-info.java | 27 + third_party/werkzeug.BUILD | 1 + 70 files changed, 8930 insertions(+), 178 deletions(-) create mode 100644 patches/protobuf_6_31_1_java_export.patch create mode 100644 patches/rules_cc_protobuf.patch create mode 100644 patches/rules_closure_soy_cli.patch create mode 100644 tensorboard/compat/compat_test.py create mode 100644 third_party/compatibility_proxy/BUILD.bazel create mode 100644 third_party/compatibility_proxy/WORKSPACE create mode 100644 third_party/compatibility_proxy/proxy.bzl create mode 100644 third_party/protobuf_pip_deps/BUILD.bazel create mode 100644 third_party/protobuf_pip_deps/WORKSPACE create mode 100644 third_party/protobuf_pip_deps/requirements.bzl create mode 100644 third_party/protobuf_pip_deps_setuptools/BUILD.bazel create mode 100644 third_party/protobuf_pip_deps_setuptools/WORKSPACE create mode 100644 third_party/protobuf_pip_deps_setuptools/site-packages/.keep create mode 100644 third_party/repo.bzl create mode 100644 third_party/safe_html_types/BUILD.bazel create mode 100644 third_party/safe_html_types/META-INF/MANIFEST.MF create mode 100644 third_party/safe_html_types/WORKSPACE create mode 100644 third_party/safe_html_types/com/google/common/html/types/BuilderUtils.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/CustomSafeUrlScheme.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/Html.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/LegacyConversions.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeHtml.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeHtmlBuilder.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeHtmlProto.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeHtmlProtoOrBuilder.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeHtmls.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeScript.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeScriptProto.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeScriptProtoOrBuilder.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeScripts.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeStyle.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeStyleBuilder.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeStyleProto.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeStyleProtoOrBuilder.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeStyleSheet.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeStyleSheetProto.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeStyleSheetProtoOrBuilder.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeStyleSheets.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeStyles.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeUrl.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeUrlProto.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeUrlProtoOrBuilder.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/SafeUrls.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/TrustedResourceUrl.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/TrustedResourceUrlBuilder.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/TrustedResourceUrlProto.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/TrustedResourceUrlProtoOrBuilder.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/TrustedResourceUrls.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/UncheckedConversions.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/package-info.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/testing/HtmlConversions.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/testing/assertions/Assertions.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/testing/assertions/package-info.java create mode 100644 third_party/safe_html_types/com/google/common/html/types/testing/package-info.java diff --git a/.bazelrc b/.bazelrc index 9aaab2c286f..51de0bbc3e9 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,6 +1,27 @@ common --noenable_bzlmod +common --enable_platform_specific_config common --experimental_repo_remote_exec # from TensorFlow # Use C++ backing implementations for Python proto parsing and deserialization, # which is much faster (~10x). build --define=use_fast_cpp_protos=true + +# TensorFlow 2.21 builds with C++17 across supported platforms, and protobuf +# 6.31.1 requires that language level. +common:linux --cxxopt=-std=c++17 +common:linux --host_cxxopt=-std=c++17 +common:macos --cxxopt=-std=c++17 +common:macos --host_cxxopt=-std=c++17 +common:windows --cxxopt=/std:c++17 +common:windows --host_cxxopt=/std:c++17 + +# Local shells and virtualenvs can leak Python import state into Bazel tests, +# which then import from the wrong environment instead of the test runfiles. +test --test_env=PYTHONPATH= +test --test_env=PYTHONHOME= +test --test_env=PYTHONSTARTUP= +test --test_env=PYTHONSAFEPATH= +test --test_env=PYTHONNOUSERSITE=1 +test --test_env=PYTHONUSERBASE= +test --test_env=BUILD_WORKSPACE_DIRECTORY= +test --test_env=BUILD_WORKING_DIRECTORY= diff --git a/WORKSPACE b/WORKSPACE index f32147cd650..051a01e8390 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,6 +1,9 @@ workspace(name = "org_tensorflow_tensorboard") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:java.bzl", "java_import_external") +load("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository") +load("//third_party:repo.bzl", "tb_http_archive", "tb_mirror_urls") http_archive( name = "bazel_skylib", @@ -35,6 +38,34 @@ load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories" web_test_repositories(omit_bazel_skylib = True) +http_archive( + name = "io_bazel_rules_go", + sha256 = "278b7ff5a826f3dc10f04feaf0b70d48b68748ccd512d7f98bf442077f043fe3", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", + ], +) + +load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") + +go_rules_dependencies() + +go_register_toolchains(version = "1.20.5") + +http_archive( + name = "bazel_gazelle", + sha256 = "29218f8e0cebe583643cbf93cae6f971be8a2484cdcfa1e45057658df8d54002", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.32.0/bazel-gazelle-v0.32.0.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.32.0/bazel-gazelle-v0.32.0.tar.gz", + ], +) + +load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") + +gazelle_dependencies() + # rules_python has to be placed before load("@io_bazel_rules_closure//closure:repositories.bzl") # in the dependencies list, otherwise we get "cannot load '@rules_python//python:py_xxx.bzl': no such file" http_archive( @@ -53,6 +84,8 @@ py_repositories() http_archive( name = "io_bazel_rules_closure", + patch_args = ["-p1"], + patches = ["//patches:rules_closure_soy_cli.patch"], sha256 = "ae060075a7c468eee42e6a08ddbb83f5a6663bdfdbd461261a465f4a3ae8598c", strip_prefix = "rules_closure-7f3d3351a8cc31fbaa403de7d35578683c17b447", urls = [ @@ -60,12 +93,95 @@ http_archive( ], ) +local_repository( + name = "com_google_common_html_types", + path = "third_party/safe_html_types", +) + +java_import_external( + name = "com_google_flogger_flogger", + licenses = ["notice"], + jar_urls = [ + "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/flogger/flogger/0.5.1/flogger-0.5.1.jar", + "https://repo1.maven.org/maven2/com/google/flogger/flogger/0.5.1/flogger-0.5.1.jar", + ], + jar_sha256 = "b5ecd1483e041197012786f749968a62063c1964d3ecfbf96ba92a95797bb8f5", +) + +java_import_external( + name = "com_google_flogger_google_extensions", + licenses = ["notice"], + jar_urls = [ + "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/flogger/google-extensions/0.5.1/google-extensions-0.5.1.jar", + "https://repo1.maven.org/maven2/com/google/flogger/google-extensions/0.5.1/google-extensions-0.5.1.jar", + ], + jar_sha256 = "8b0862cad85b9549f355fe383c6c63816d2f19529634e033ae06d0107ab110b9", + deps = ["@com_google_flogger_flogger"], +) + +java_import_external( + name = "com_google_flogger_flogger_system_backend", + licenses = ["notice"], + jar_urls = [ + "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/flogger/flogger-system-backend/0.5.1/flogger-system-backend-0.5.1.jar", + "https://repo1.maven.org/maven2/com/google/flogger/flogger-system-backend/0.5.1/flogger-system-backend-0.5.1.jar", + ], + jar_sha256 = "685de33b53eb313049bbeee7f4b7a80dd09e8e754e96b048a3edab2cebb36442", + deps = ["@com_google_flogger_flogger"], +) + +java_import_external( + name = "com_google_template_soy", + licenses = ["notice"], + jar_urls = [ + "https://repo1.maven.org/maven2/com/google/template/soy/2022-03-07/soy-2022-03-07.jar", + ], + jar_sha256 = "643440022e247ef8ad25bacb83ba099ccd2ae4b1fd078d9e9e3d3dd4af00411f", + deps = [ + "@args4j", + "@com_google_code_findbugs_jsr305", + "@com_google_code_gson", + "@com_google_flogger_flogger", + "@com_google_flogger_flogger_system_backend", + "@com_google_flogger_google_extensions", + "@com_google_common_html_types", + "@com_google_guava", + "@com_google_inject_extensions_guice_assistedinject", + "@com_google_inject_extensions_guice_multibindings", + "@com_google_inject_guice", + "@com_google_protobuf//:protobuf_java", + "@com_ibm_icu_icu4j", + "@javax_inject", + "@org_json", + "@org_ow2_asm", + "@org_ow2_asm_analysis", + "@org_ow2_asm_commons", + "@org_ow2_asm_util", + ], + extra_build_file_content = "\n".join([ + ("java_binary(\n" + + " name = \"%s\",\n" + + " main_class = \"com.google.template.soy.%s\",\n" + + " output_licenses = [\"unencumbered\"],\n" + + " runtime_deps = [\":com_google_template_soy\"],\n" + + ")\n") % (name, name) + for name in ( + "SoyParseInfoGenerator", + "SoyToJbcSrcCompiler", + "SoyToJsSrcCompiler", + "SoyToPySrcCompiler", + ) + ]), +) + load("@io_bazel_rules_closure//closure:repositories.bzl", "rules_closure_dependencies") rules_closure_dependencies( omit_bazel_skylib = True, + omit_com_google_common_html_types = True, omit_com_google_protobuf = True, omit_com_google_protobuf_js = True, + omit_com_google_template_soy = True, ) http_archive( @@ -138,71 +254,95 @@ sass_repositories() # high as the version of protobuf we depend on below, and we cannot increase the # version below without bumping the requirements.txt version. # -# TODO(#6185): Remove the TODO below once the TF constraint no longer applies. -# -# NOTE: This dependency currently cannot be advanced past 3.19.x. This is because -# TF is currently unable to use a runtime any greater than 3.19.x, see details here: -# https://github.com/tensorflow/tensorflow/blob/9d22f4a0a9499c8e10a4312503e63e0da35ccd94/tensorflow/tools/pip_package/setup.py#L100-L107 -# -# As a result of TF's constraint and the above <= requirement, 3.19.x is the most recent -# possible protoc we can use while remaining cross-compatible with TF. At the same time, -# 3.19.x is the minimum possible protoc that will generate compiled proto code that *is* -# compatible with protobuf runtimes >= 4, as discussed here: -# https://developers.google.com/protocol-buffers/docs/news/2022-05-06 -http_archive( +# TensorFlow 2.21 uses protobuf 6.31.1 in its own build and pip package +# constraints. Keep this Bazel-side protoc version aligned with that runtime +# floor so generated Python code and the ambient `protobuf` package remain +# compatible. +tb_http_archive( + name = "tb_rules_cc", + patch_file = ["//patches:rules_cc_protobuf.patch"], + repo_mapping = { + "@rules_cc": "@tb_rules_cc", + }, + sha256 = "4b12149a041ddfb8306a8fd0e904e39d673552ce82e4296e96fac9cbf0780e59", + strip_prefix = "rules_cc-0.1.0", + urls = tb_mirror_urls("https://github.com/bazelbuild/rules_cc/archive/refs/tags/0.1.0.tar.gz"), +) + +tb_http_archive( + name = "tb_rules_java", + sha256 = "b2519fabcd360529071ade8732f208b3755489ed7668b118f8f90985c0e51324", + strip_prefix = "rules_java-8.6.1", + urls = tb_mirror_urls("https://github.com/bazelbuild/rules_java/archive/refs/tags/8.6.1.tar.gz"), +) + +local_repository( + name = "compatibility_proxy", + path = "third_party/compatibility_proxy", +) + +local_repository( + name = "protobuf_pip_deps", + path = "third_party/protobuf_pip_deps", +) + +local_repository( + name = "protobuf_pip_deps_setuptools", + path = "third_party/protobuf_pip_deps_setuptools", +) + +load("@tb_rules_java//java:rules_java_deps.bzl", "rules_java_dependencies") + +tb_http_archive( + name = "com_google_absl", + repo_mapping = { + "@rules_cc": "@tb_rules_cc", + }, + sha256 = "d8ae9aa794a571ee39c77085ee69f1d4ac276212a7d99734974d95df7baa8d13", + strip_prefix = "abseil-cpp-9ac7062b1860d895fb5a8cbf58c3e9ef8f674b5f", + urls = tb_mirror_urls("https://github.com/abseil/abseil-cpp/archive/9ac7062b1860d895fb5a8cbf58c3e9ef8f674b5f.zip"), +) + +tb_http_archive( name = "com_google_protobuf", - sha256 = "9a301cf94a8ddcb380b901e7aac852780b826595075577bb967004050c835056", - strip_prefix = "protobuf-3.19.6", - urls = [ - "http://mirror.tensorflow.org/github.com/protocolbuffers/protobuf/archive/v3.19.6.tar.gz", - "https://github.com/protocolbuffers/protobuf/archive/v3.19.6.tar.gz", # 2022-09-29 - ], + patch_file = ["//patches:protobuf_6_31_1_java_export.patch"], + repo_mapping = { + "@abseil-cpp": "@com_google_absl", + "@rules_cc": "@tb_rules_cc", + "@rules_java": "@tb_rules_java", + }, + sha256 = "6e09bbc950ba60c3a7b30280210cd285af8d7d8ed5e0a6ed101c72aff22e8d88", + strip_prefix = "protobuf-6.31.1", + urls = tb_mirror_urls("https://github.com/protocolbuffers/protobuf/archive/refs/tags/v6.31.1.zip"), ) +rules_java_dependencies() + +load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") + +protobuf_deps() + # gRPC. # -# NOTE: The version used here must be cross-compatible with our protobuf version. -# As 2023-01-13, 1.48.2 is the most recent gRPC release that was still using a 3.19.x -# version of protobuf in its own builds (more recent releases move to 3.21.x). -http_archive( +# Keep this aligned with TensorFlow 2.21's Bazel-side gRPC dependency so the +# grpc plugin and protobuf repository stay on a known-compatible combination. +tb_http_archive( name = "com_github_grpc_grpc", - sha256 = "bdb8e98145469d58c69ab9f2c9e0bd838c2836a99b5760bc0ebf658623768f52", - strip_prefix = "grpc-1.48.2", - urls = [ - "http://mirror.tensorflow.org/github.com/grpc/grpc/archive/v1.48.2.tar.gz", - "https://github.com/grpc/grpc/archive/v1.48.2.tar.gz", # 2022-09-21 - ], -) - -# gRPC 1.48.2 still pins Apple rules that are too old for Bazel 7.x. -# Predeclare Bazel-7-compatible versions so grpc_deps()/grpc_extra_deps() reuse -# them instead of pulling their own older copies. -http_archive( - name = "build_bazel_rules_apple", - sha256 = "b4df908ec14868369021182ab191dbd1f40830c9b300650d5dc389e0b9266c8d", - urls = [ - "http://mirror.tensorflow.org/github.com/bazelbuild/rules_apple/releases/download/3.5.1/rules_apple.3.5.1.tar.gz", - "https://github.com/bazelbuild/rules_apple/releases/download/3.5.1/rules_apple.3.5.1.tar.gz", - ], + sha256 = "dd6a2fa311ba8441bbefd2764c55b99136ff10f7ea42954be96006a2723d33fc", + strip_prefix = "grpc-1.74.0", + urls = tb_mirror_urls("https://github.com/grpc/grpc/archive/refs/tags/v1.74.0.tar.gz"), ) -http_archive( - name = "build_bazel_apple_support", - sha256 = "1ae6fcf983cff3edab717636f91ad0efff2e5ba75607fdddddfd6ad0dbdfaf10", - urls = [ - "http://mirror.tensorflow.org/github.com/bazelbuild/apple_support/releases/download/1.24.5/apple_support.1.24.5.tar.gz", - "https://github.com/bazelbuild/apple_support/releases/download/1.24.5/apple_support.1.24.5.tar.gz", - ], +tb_http_archive( + name = "build_bazel_rules_swift", + sha256 = "9919ed1d8dae509645bfd380537ae6501528d8de971caebed6d5185b9970dc4d", + urls = tb_mirror_urls("https://github.com/bazelbuild/rules_swift/releases/download/2.1.1/rules_swift.2.1.1.tar.gz"), ) load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps") grpc_deps() -load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps") - -grpc_extra_deps() - http_archive( name = "rules_rust", sha256 = "08109dccfa5bbf674ff4dba82b15d40d85b07436b02e62ab27e0b894f45bb4a3", @@ -214,10 +354,10 @@ http_archive( ], ) -# WORKAROUND for rules_webtesting not declaring used com_github_gorilla_mux repo: -load("@io_bazel_rules_webtesting//web:go_repositories.bzl", "com_github_gorilla_mux") +load("@io_bazel_rules_webtesting//web:go_repositories.bzl", "go_internal_repositories", "go_repositories") -com_github_gorilla_mux() +go_repositories() +go_internal_repositories() # Please add all new dependencies in workspace.bzl. load("//third_party:workspace.bzl", "tensorboard_workspace") diff --git a/patches/protobuf_6_31_1_java_export.patch b/patches/protobuf_6_31_1_java_export.patch new file mode 100644 index 00000000000..b12a6e82675 --- /dev/null +++ b/patches/protobuf_6_31_1_java_export.patch @@ -0,0 +1,49 @@ +diff --git a/build_defs/java_opts.bzl b/build_defs/java_opts.bzl +--- a/build_defs/java_opts.bzl ++++ b/build_defs/java_opts.bzl +@@ -17,14 +17,5 @@ def protobuf_java_export(**kwargs): + def protobuf_java_export(**kwargs): + java_export( + javacopts = JAVA_RELEASE_OPTS, +- # https://github.com/bazelbuild/rules_jvm_external/issues/1245 +- javadocopts = [ +- "-notimestamp", +- "-use", +- "-quiet", +- "-Xdoclint:-missing", +- "-encoding", +- "UTF8", +- ], + **kwargs + ) +diff --git a/bazel/private/proto_library_rule.bzl b/bazel/private/proto_library_rule.bzl +--- a/bazel/private/proto_library_rule.bzl ++++ b/bazel/private/proto_library_rule.bzl +@@ -29,6 +29,9 @@ def _check_srcs_package(target_package, srcs): + for src in srcs: + if target_package != src.label.package: + fail("Proto source with label '%s' must be in same package as consuming rule." % src.label) ++ ++def _is_normalized(path): ++ return path == "" or paths.normalize(path) == path + + def _get_import_prefix(ctx): + """Gets and verifies import_prefix attribute if it is declared.""" +@@ -36,7 +39,7 @@ def _get_import_prefix(ctx): + + import_prefix = ctx.attr.import_prefix + +- if not paths.is_normalized(import_prefix): ++ if not _is_normalized(import_prefix): + fail("should be normalized (without uplevel references or '.' path segments)", attr = "import_prefix") + if paths.is_absolute(import_prefix): + fail("should be a relative path", attr = "import_prefix") +@@ -48,7 +51,7 @@ def _get_strip_import_prefix(ctx): + + strip_import_prefix = ctx.attr.strip_import_prefix + +- if not paths.is_normalized(strip_import_prefix): ++ if not _is_normalized(strip_import_prefix): + fail("should be normalized (without uplevel references or '.' path segments)", attr = "strip_import_prefix") + + if paths.is_absolute(strip_import_prefix): diff --git a/patches/rules_cc_protobuf.patch b/patches/rules_cc_protobuf.patch new file mode 100644 index 00000000000..e265d992eaa --- /dev/null +++ b/patches/rules_cc_protobuf.patch @@ -0,0 +1,16 @@ +diff --git a/cc/defs.bzl b/cc/defs.bzl +index 3448e77..9c298ab 100644 +--- a/cc/defs.bzl ++++ b/cc/defs.bzl +@@ -30,9 +30,11 @@ load("//cc/toolchains:cc_toolchain_suite.bzl", _cc_toolchain_suite = "cc_toolcha + load("//cc/toolchains:compiler_flag.bzl", _compiler_flag = "compiler_flag") + load("//cc/toolchains:fdo_prefetch_hints.bzl", _fdo_prefetch_hints = "fdo_prefetch_hints") + load("//cc/toolchains:fdo_profile.bzl", _fdo_profile = "fdo_profile") ++load("@com_google_protobuf//bazel:cc_proto_library.bzl", _protobuf_cc_proto_library = "cc_proto_library") + + # Rules + ++cc_proto_library = _protobuf_cc_proto_library + cc_library = _cc_library + cc_binary = _cc_binary + cc_test = _cc_test diff --git a/patches/rules_closure_soy_cli.patch b/patches/rules_closure_soy_cli.patch new file mode 100644 index 00000000000..1559d81ef68 --- /dev/null +++ b/patches/rules_closure_soy_cli.patch @@ -0,0 +1,19 @@ +diff --git a/closure/templates/closure_java_template_library.bzl b/closure/templates/closure_java_template_library.bzl +--- a/closure/templates/closure_java_template_library.bzl ++++ b/closure/templates/closure_java_template_library.bzl +@@ -133,7 +133,7 @@ def _soy_java_template_genrule_impl( + out_name = deps_flag_file_name, + targets = deps, +- flag = "--deps", ++ flag = "--depHeaders", + compatible_with = compatible_with, + ) + native.genrule( +@@ -145,7 +145,6 @@ def _soy_java_template_genrule_impl( + cmd = "$(location %s)" % soycompilerbin + + " --outputDirectory=$(@D)" + + " --javaPackage=" + java_package + + " --javaClassNameSource=filename" + +- " --allowExternalCalls=" + str(allow_external_calls) + + additional_flags + + # Include the sources and deps files as command line flags. diff --git a/tensorboard/compat/BUILD b/tensorboard/compat/BUILD index e04bc3eb312..e8a41382716 100644 --- a/tensorboard/compat/BUILD +++ b/tensorboard/compat/BUILD @@ -22,8 +22,15 @@ py_library( srcs = ["__init__.py"], srcs_version = "PY3", visibility = ["//visibility:public"], +) + +py_test( + name = "compat_test", + srcs = ["compat_test.py"], + srcs_version = "PY3", deps = [ - "//tensorboard:lazy", + ":compat", + "//tensorboard:expect_tensorflow_installed", ], ) diff --git a/tensorboard/compat/__init__.py b/tensorboard/compat/__init__.py index 6786669fe2d..5fade452fdb 100644 --- a/tensorboard/compat/__init__.py +++ b/tensorboard/compat/__init__.py @@ -15,31 +15,17 @@ """Compatibility interfaces for TensorBoard. This module provides logic for importing variations on the TensorFlow -APIs, as lazily loaded imports to help avoid circular dependency issues -and defer the search and loading of the module until necessary. +APIs while deferring the actual import work until callers request `tf` +or `tf2`. """ +import importlib -import tensorboard.lazy as _lazy - -@_lazy.lazy_load("tensorboard.compat.tf") -def tf(): - """Provide the root module of a TF-like API for use within TensorBoard. - - By default this is equivalent to `import tensorflow as tf`, but it can be used - in combination with //tensorboard/compat:tensorflow (to fall back to a stub TF - API implementation if the real one is not available) or with - //tensorboard/compat:no_tensorflow (to force unconditional use of the stub). - - Returns: - The root module of a TF-like API, if available. - - Raises: - ImportError: if a TF-like API is not available. - """ +def _resolve_tf(): + """Provide the root module of a TF-like API for use within TensorBoard.""" try: - from tensorboard.compat import notf # noqa: F401 + importlib.import_module("tensorboard.compat.notf") except ImportError: try: import tensorflow @@ -47,24 +33,31 @@ def tf(): return tensorflow except ImportError: pass - from tensorboard.compat import tensorflow_stub - - return tensorflow_stub - - -@_lazy.lazy_load("tensorboard.compat.tf2") -def tf2(): - """Provide the root module of a TF-2.0 API for use within TensorBoard. + return importlib.import_module("tensorboard.compat.tensorflow_stub") - Returns: - The root module of a TF-2.0 API, if available. - Raises: - ImportError: if a TF-2.0 API is not available. - """ - # Resolve the lazy `tf` compat API from earlier in this file and try to find - # tf.compat.v2. Don't check tf.__version__ since this is not always reliable - # if TF was built with tf_api_version!=2. +def _resolve_tf2(): + """Provide the root module of a TF-2.0 API for use within TensorBoard.""" + tf = __getattr__("tf") if hasattr(tf, "compat") and hasattr(tf.compat, "v2"): return tf.compat.v2 raise ImportError("cannot import tensorflow 2.0 API") + + +def __getattr__(name): + if name == "tf": + module = _resolve_tf() + globals()[name] = module + return module + if name == "tf2": + module = _resolve_tf2() + globals()[name] = module + return module + raise AttributeError("module %r has no attribute %r" % (__name__, name)) + + +def __dir__(): + return sorted(set(globals()) | {"tf", "tf2"}) + + +__all__ = ["tf", "tf2"] diff --git a/tensorboard/compat/compat_test.py b/tensorboard/compat/compat_test.py new file mode 100644 index 00000000000..d24bf315096 --- /dev/null +++ b/tensorboard/compat/compat_test.py @@ -0,0 +1,33 @@ +# Copyright 2026 The TensorFlow Authors. All Rights Reserved. +# +# 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. + +"""Tests for tensorboard.compat lazy exports.""" + +import unittest + + +class CompatTest(unittest.TestCase): + def test_tf_export(self): + from tensorboard.compat import tf + + self.assertTrue(hasattr(tf, "compat")) + + def test_tf2_export(self): + from tensorboard.compat import tf2 + + self.assertTrue(hasattr(tf2, "summary")) + + +if __name__ == "__main__": + unittest.main() diff --git a/tensorboard/defs/protos.bzl b/tensorboard/defs/protos.bzl index e1dbe485d32..1aac236dc8c 100644 --- a/tensorboard/defs/protos.bzl +++ b/tensorboard/defs/protos.bzl @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@com_google_protobuf//:protobuf.bzl", "proto_gen") -load("@rules_python//python:py_library.bzl", "py_library") +load("@com_google_protobuf//bazel:py_proto_library.bzl", "py_proto_library") +load("@com_github_grpc_grpc//bazel:protobuf.bzl", "well_known_proto_libs") +load("@com_github_grpc_grpc//bazel:python_rules.bzl", "py_grpc_library") # TODO(#6185): try to reduce the complexity in this rule. def tb_proto_library( @@ -25,66 +26,29 @@ def tb_proto_library( has_services = False, # The `exports` arg is unused here, but required internally for compatibility. exports = []): - outs_proto = _PyOuts(srcs, grpc = False) - outs_grpc = _PyOuts(srcs, grpc = True) if has_services else [] - outs_all = outs_proto + outs_grpc + proto_deps = [s + "_proto" for s in deps] + well_known_proto_libs() - # Dependencies we need to operate protoc (the protobuf compiler), including - # protoc itself, the intermediate generated proto output from the runtime - # bundled with protoc (to provide proto types used during the protoc code - # generation process itself), and the grpc plugin to protoc used for gRPC - # service generation. - protoc = "@com_google_protobuf//:protoc" - protoc_runtime_genproto = "@com_google_protobuf//:protobuf_python_genproto" - grpc_python_plugin = "//external:grpc_python_plugin" - - # Python generated code relies on a Python protobuf runtime to be present. - # The runtime version must be compatible (typically, >=) with the protoc - # that was used to generate the code. There is a runtime provided along - # with protoc as part of our build-time dependency on protobuf (the target - # is "@com_google_protobuf//:protobuf_python"), but we deliberately don't - # use it, because our tests may need to use a protobuf runtime that is - # higher than our protoc version in order to be compatible with generated - # protobuf code used by our dependencies (namely, TensorFlow). Instead, we - # rely on picking up protobuf ambiently from the virtual environment, the - # same way that it will behave when released in our pip package. - runtime = "//tensorboard:expect_protobuf_installed" - - proto_gen( - name = name + "_genproto", + native.proto_library( + name = name + "_proto", srcs = srcs, - deps = [s + "_genproto" for s in deps] + [protoc_runtime_genproto], - includes = [], - protoc = protoc, - gen_py = True, - outs = outs_all, + deps = proto_deps, + testonly = testonly, visibility = ["//visibility:public"], - plugin = grpc_python_plugin if has_services else None, - plugin_language = "grpc", ) - py_deps = [s + "_py_pb2" for s in deps] + [runtime] - py_library( + py_proto_library( name = name + "_py_pb2", - srcs = outs_proto, - imports = [], - srcs_version = "PY3", - deps = py_deps, + deps = [name + "_proto"], testonly = testonly, visibility = visibility, ) + if has_services: - py_library( + py_grpc_library( name = name + "_py_pb2_grpc", - srcs = outs_grpc, - imports = [], - srcs_version = "PY3", - deps = [name + "_py_pb2"] + py_deps, + srcs = [name + "_proto"], + deps = [name + "_py_pb2"], + grpc_library = "//tensorboard:expect_grpc_installed", testonly = testonly, visibility = visibility, ) - -def _PyOuts(srcs, grpc): - # Adapted from @com_google_protobuf//:protobuf.bzl. - ext = "_pb2.py" if not grpc else "_pb2_grpc.py" - return [s[:-len(".proto")] + ext for s in srcs] diff --git a/tensorboard/manager.py b/tensorboard/manager.py index 823735bd477..4d6ec770d0f 100644 --- a/tensorboard/manager.py +++ b/tensorboard/manager.py @@ -32,6 +32,29 @@ from tensorboard.util import tb_logging +_SUBPROCESS_ENV_DENYLIST = frozenset( + ( + "BUILD_WORKING_DIRECTORY", + "BUILD_WORKSPACE_DIRECTORY", + "JAVA_RUNFILES", + "PYTHONHOME", + "PYTHONPATH", + "PYTHONSAFEPATH", + "PYTHONSTARTUP", + "PYTHONUSERBASE", + "PYTHON_RUNFILES", + "RUNFILES", + "RUNFILES_DIR", + "RUNFILES_MANIFEST_FILE", + "RUNFILES_MANIFEST_ONLY", + "RUNFILES_REPO_MAPPING", + "TEST_BINARY", + "TEST_SRCDIR", + "TEST_WORKSPACE", + ) +) + + @dataclasses.dataclass(frozen=True) class TensorBoardInfo: """Holds the information about a running TensorBoard instance. @@ -385,6 +408,20 @@ class StartTimedOut: pid: int +def _subprocess_environ(): + """Create an environment for a managed TensorBoard subprocess. + + TensorBoard processes launched from Bazel tests should resolve their own + runfiles and Python import paths. Inheriting Bazel's test-only Python and + runfiles variables can make the child binary execute against the parent's + runfiles tree instead of its own. + """ + environ = os.environ.copy() + for key in _SUBPROCESS_ENV_DENYLIST: + environ.pop(key, None) + return environ + + def start(arguments, timeout=datetime.timedelta(seconds=60)): """Start a new TensorBoard instance, or reuse a compatible one. @@ -427,6 +464,7 @@ def start(arguments, timeout=datetime.timedelta(seconds=60)): try: p = subprocess.Popen( ["tensorboard" if explicit_tb is None else explicit_tb] + arguments, + env=_subprocess_environ(), stdout=stdout_fd, stderr=stderr_fd, ) diff --git a/tensorboard/manager_test.py b/tensorboard/manager_test.py index 6911398c515..e5659d1cf64 100644 --- a/tensorboard/manager_test.py +++ b/tensorboard/manager_test.py @@ -233,6 +233,30 @@ def test_arguments_list_vs_tuple_irrelevant(self): self.assertEqual(with_list, with_tuple) +class SubprocessEnvironTest(tb_test.TestCase): + def test_strips_bazel_and_python_path_state(self): + with mock.patch.dict( + os.environ, + { + "PATH": "/bin:/usr/bin", + "TMPDIR": "/tmp/tb", + "PYTHONPATH": "/tmp/runfiles", + "RUNFILES_DIR": "/tmp/runfiles", + "TEST_BINARY": "/tmp/test_binary", + "BUILD_WORKSPACE_DIRECTORY": "/tmp/workspace", + }, + clear=True, + ): + actual = manager._subprocess_environ() + + self.assertEqual(actual["PATH"], "/bin:/usr/bin") + self.assertEqual(actual["TMPDIR"], "/tmp/tb") + self.assertNotIn("PYTHONPATH", actual) + self.assertNotIn("RUNFILES_DIR", actual) + self.assertNotIn("TEST_BINARY", actual) + self.assertNotIn("BUILD_WORKSPACE_DIRECTORY", actual) + + class TensorBoardInfoIoTest(tb_test.TestCase): """Tests for `write_info_file`, `remove_info_file`, and `get_all`.""" diff --git a/tensorboard/pip_package/requirements.txt b/tensorboard/pip_package/requirements.txt index ac31021fbb8..d1f6726241e 100644 --- a/tensorboard/pip_package/requirements.txt +++ b/tensorboard/pip_package/requirements.txt @@ -17,22 +17,18 @@ absl-py >= 0.4 # NOTE: this version should be >= the grpc version in our WORKSPACE file. -grpcio >= 1.48.2 +grpcio >= 1.74.0, < 2.0 markdown >= 2.6.8 numpy >= 1.12.0 # NOTE: The packaging dependency was introduced in order to compare installed # package versions and conditionally use different supported kwargs -# (specifically the protobuf dependency). If we restrict protobuf >= 5.0.0 we -# can get rid of the packaging dependency. +# (specifically the protobuf dependency). packaging pillow # NOTE: this version must be >= the protoc version in our WORKSPACE file. -# At the same time, any constraints we specify here must allow at least some -# version to be installed that is also compatible with TensorFlow's constraints: -# https://github.com/tensorflow/tensorflow/blob/25adc4fccb4b0bb5a933eba1d246380e7b87d7f7/tensorflow/tools/pip_package/setup.py#L101 -# 4.24.0 had an issue that broke our tests, so we should avoid that release: -# https://github.com/protocolbuffers/protobuf/issues/13485 -protobuf >= 3.19.6, != 4.24.0 +# TensorFlow 2.21 requires protobuf >= 6.31.1, < 8.0.0, so keep our open-source +# runtime floor aligned with that range. +protobuf >= 6.31.1, < 8.0.0 setuptools >= 41.0.0 # Note: provides pkg_resources as well as setuptools tensorboard-data-server >= 0.7.0, < 0.8.0 werkzeug >= 1.0.1 diff --git a/tensorboard/pip_package/requirements_dev.txt b/tensorboard/pip_package/requirements_dev.txt index f9a7a3ae702..3f4d8559125 100644 --- a/tensorboard/pip_package/requirements_dev.txt +++ b/tensorboard/pip_package/requirements_dev.txt @@ -16,7 +16,7 @@ # Dependencies of TensorBoard used only for testing or development. # For tests -grpcio-testing==1.24.3 +grpcio-testing==1.74.0 pandas~=2.0 # For gfile S3 test boto3==1.9.86 diff --git a/tensorboard/pip_package/test_pip_package.sh b/tensorboard/pip_package/test_pip_package.sh index 1595bcd8601..99b05e0e3b1 100755 --- a/tensorboard/pip_package/test_pip_package.sh +++ b/tensorboard/pip_package/test_pip_package.sh @@ -119,9 +119,17 @@ smoke() ( virtualenv -q -p "${smoke_python}" "${smoke_venv}" cd "${smoke_venv}" - export VIRTUAL_ENV=venv + export VIRTUAL_ENV="${smoke_venv}" export PATH="${smoke_venv}/bin:${PATH}" unset PYTHON_HOME + # `bazel run` and the parent shell may export Python- and runfiles-related + # variables that make the smoke tests import from Bazel/workspace state + # instead of the freshly installed wheel in this virtualenv. + unset PYTHONPATH PYTHONSTARTUP PYTHONSAFEPATH PYTHONNOUSERSITE PYTHONUSERBASE + unset BUILD_WORKSPACE_DIRECTORY BUILD_WORKING_DIRECTORY + unset RUNFILES RUNFILES_DIR RUNFILES_MANIFEST_FILE RUNFILES_MANIFEST_ONLY + unset RUNFILES_REPO_MAPPING JAVA_RUNFILES PYTHON_RUNFILES + unset TEST_SRCDIR TEST_WORKSPACE TEST_BINARY BAZEL_TEST pip install -qU pip if [ -n "${tf_version}" ]; then @@ -131,10 +139,21 @@ smoke() ( pip install -qU "${wheels}"/*py"${py_major_version}"*.whl pip freeze # Log the results of pip installation + smoke_env() { + env -i \ + HOME="${HOME}" \ + LANG="${LANG:-C.UTF-8}" \ + LC_ALL="${LC_ALL:-C.UTF-8}" \ + PATH="${smoke_venv}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \ + TMPDIR="${TMPDIR:-/tmp}" \ + VIRTUAL_ENV="${smoke_venv}" \ + "$@" + } + # Test TensorBoard application [ -x ./bin/tensorboard ] # Ensure pip package included binary mkfifo pipe - tensorboard --port=0 --logdir=smokedir 2>pipe & + smoke_env ./bin/tensorboard --port=0 --logdir=smokedir 2>pipe & perl -ne 'print STDERR;/http:.*:(\d+)/ and print $1.v10 and exit 0' port curl -fs "http://localhost:$(cat port)" >index.html grep '/dev/null 2>&1 } if is_tf_2; then @@ -186,12 +205,14 @@ test_tf_summary() { import_attr="import tensorflow as tf; a = tf${1}.summary; a.write; a.scalar" import_as="import tensorflow${1}.summary as b; b.write; b.scalar" import_from="from tensorflow${1} import summary as c; c.write; c.scalar" - printf '%s\n' "${import_attr}" "${import_as}" "${import_from}" | python - - printf '%s\n' "${import_attr}" "${import_from}" "${import_as}" | python - - printf '%s\n' "${import_as}" "${import_attr}" "${import_from}" | python - - printf '%s\n' "${import_as}" "${import_from}" "${import_attr}" | python - - printf '%s\n' "${import_from}" "${import_attr}" "${import_as}" | python - - printf '%s\n' "${import_from}" "${import_as}" "${import_attr}" | python - + printf '%s\n' "${import_attr}" "${import_as}" "${import_from}" | smoke_env ./bin/python -I - + printf '%s\n' "${import_attr}" "${import_from}" "${import_as}" | smoke_env ./bin/python -I - + printf '%s\n' "${import_as}" "${import_attr}" "${import_from}" | smoke_env ./bin/python -I - + printf '%s\n' "${import_as}" "${import_from}" "${import_attr}" | smoke_env ./bin/python -I - + printf '%s\n' "${import_from}" "${import_attr}" "${import_as}" | smoke_env ./bin/python -I - + printf '%s\n' "${import_from}" "${import_as}" "${import_attr}" | smoke_env ./bin/python -I - } main "$@" + +printf >&2 'All smoke tests passed.' diff --git a/tensorboard/plugins/audio/summary.py b/tensorboard/plugins/audio/summary.py index 7f089b202e7..aa5b86d44a8 100644 --- a/tensorboard/plugins/audio/summary.py +++ b/tensorboard/plugins/audio/summary.py @@ -32,11 +32,17 @@ from tensorboard.util import encoder as encoder_util from tensorboard.plugins.audio import metadata -from tensorboard.plugins.audio import summary_v2 + + +def _summary_v2(): + from tensorboard.plugins.audio import summary_v2 + + return summary_v2 # Export V2 versions. -audio = summary_v2.audio +def audio(*args, **kwargs): + return _summary_v2().audio(*args, **kwargs) _LABELS_WARNING = ( diff --git a/tensorboard/plugins/histogram/summary.py b/tensorboard/plugins/histogram/summary.py index d804852f638..8a423961126 100644 --- a/tensorboard/plugins/histogram/summary.py +++ b/tensorboard/plugins/histogram/summary.py @@ -32,12 +32,24 @@ import numpy as np from tensorboard.plugins.histogram import metadata -from tensorboard.plugins.histogram import summary_v2 + + +def _summary_v2(): + from tensorboard.plugins.histogram import summary_v2 + + return summary_v2 + + +DEFAULT_BUCKET_COUNT = 30 # Export V3 versions. -histogram = summary_v2.histogram -histogram_pb = summary_v2.histogram_pb +def histogram(*args, **kwargs): + return _summary_v2().histogram(*args, **kwargs) + + +def histogram_pb(*args, **kwargs): + return _summary_v2().histogram_pb(*args, **kwargs) def _buckets(data, bucket_count=None): @@ -55,7 +67,7 @@ def _buckets(data, bucket_count=None): import tensorflow.compat.v1 as tf if bucket_count is None: - bucket_count = summary_v2.DEFAULT_BUCKET_COUNT + bucket_count = DEFAULT_BUCKET_COUNT with tf.name_scope( "buckets", values=[data, bucket_count] ), tf.control_dependencies( @@ -186,7 +198,7 @@ def pb(name, data, bucket_count=None, display_name=None, description=None): import tensorflow.compat.v1 as tf if bucket_count is None: - bucket_count = summary_v2.DEFAULT_BUCKET_COUNT + bucket_count = DEFAULT_BUCKET_COUNT data = np.array(data).flatten().astype(float) if data.size == 0: buckets = np.array([]).reshape((0, 3)) diff --git a/tensorboard/plugins/image/summary.py b/tensorboard/plugins/image/summary.py index d6e001c6422..c2cb928fde9 100644 --- a/tensorboard/plugins/image/summary.py +++ b/tensorboard/plugins/image/summary.py @@ -25,12 +25,18 @@ import numpy as np from tensorboard.plugins.image import metadata -from tensorboard.plugins.image import summary_v2 from tensorboard.util import encoder +def _summary_v2(): + from tensorboard.plugins.image import summary_v2 + + return summary_v2 + + # Export V2 versions. -image = summary_v2.image +def image(*args, **kwargs): + return _summary_v2().image(*args, **kwargs) def op( diff --git a/tensorboard/plugins/scalar/summary.py b/tensorboard/plugins/scalar/summary.py index fec5fdeef2d..cf3f166cd7f 100644 --- a/tensorboard/plugins/scalar/summary.py +++ b/tensorboard/plugins/scalar/summary.py @@ -22,12 +22,21 @@ import numpy as np from tensorboard.plugins.scalar import metadata -from tensorboard.plugins.scalar import summary_v2 + + +def _summary_v2(): + from tensorboard.plugins.scalar import summary_v2 + + return summary_v2 # Export V2 versions. -scalar = summary_v2.scalar -scalar_pb = summary_v2.scalar_pb +def scalar(*args, **kwargs): + return _summary_v2().scalar(*args, **kwargs) + + +def scalar_pb(*args, **kwargs): + return _summary_v2().scalar_pb(*args, **kwargs) def op(name, data, display_name=None, description=None, collections=None): diff --git a/tensorboard/plugins/text/summary.py b/tensorboard/plugins/text/summary.py index 915cb34e926..743df85a9df 100644 --- a/tensorboard/plugins/text/summary.py +++ b/tensorboard/plugins/text/summary.py @@ -16,12 +16,21 @@ from tensorboard.plugins.text import metadata -from tensorboard.plugins.text import summary_v2 + + +def _summary_v2(): + from tensorboard.plugins.text import summary_v2 + + return summary_v2 # Export V2 versions. -text = summary_v2.text -text_pb = summary_v2.text_pb +def text(*args, **kwargs): + return _summary_v2().text(*args, **kwargs) + + +def text_pb(*args, **kwargs): + return _summary_v2().text_pb(*args, **kwargs) def op(name, data, display_name=None, description=None, collections=None): diff --git a/third_party/compatibility_proxy/BUILD.bazel b/third_party/compatibility_proxy/BUILD.bazel new file mode 100644 index 00000000000..1f1683470ef --- /dev/null +++ b/third_party/compatibility_proxy/BUILD.bazel @@ -0,0 +1,16 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +exports_files( + ["proxy.bzl"], + visibility = ["@tb_rules_java//test:__pkg__"], +) + +bzl_library( + name = "proxy_bzl", + srcs = ["proxy.bzl"], + deps = [ + "@bazel_tools//tools:bzl_srcs", + "@tb_rules_java//java/private:native_bzl", + ], + visibility = ["//visibility:public"], +) diff --git a/third_party/compatibility_proxy/WORKSPACE b/third_party/compatibility_proxy/WORKSPACE new file mode 100644 index 00000000000..49d774266b9 --- /dev/null +++ b/third_party/compatibility_proxy/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "compatibility_proxy") diff --git a/third_party/compatibility_proxy/proxy.bzl b/third_party/compatibility_proxy/proxy.bzl new file mode 100644 index 00000000000..c4f93fa8c18 --- /dev/null +++ b/third_party/compatibility_proxy/proxy.bzl @@ -0,0 +1,22 @@ +"""Compatibility proxy for rules_java under Bazel 7.""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_jar = "http_jar") +load("@tb_rules_java//java/private:native.bzl", "NativeJavaInfo", "NativeJavaPluginInfo", "native_java_common") + +java_binary = native.java_binary +java_import = native.java_import +java_library = native.java_library +java_plugin = native.java_plugin +java_test = native.java_test + +java_package_configuration = native.java_package_configuration +java_runtime = native.java_runtime +java_toolchain = native.java_toolchain + +java_common = native_java_common +JavaInfo = NativeJavaInfo +JavaPluginInfo = NativeJavaPluginInfo +java_common_internal_compile = None +java_info_internal_merge = None + +http_jar = _http_jar diff --git a/third_party/protobuf_pip_deps/BUILD.bazel b/third_party/protobuf_pip_deps/BUILD.bazel new file mode 100644 index 00000000000..7222b7a1875 --- /dev/null +++ b/third_party/protobuf_pip_deps/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["requirements.bzl"]) diff --git a/third_party/protobuf_pip_deps/WORKSPACE b/third_party/protobuf_pip_deps/WORKSPACE new file mode 100644 index 00000000000..80879e6b55c --- /dev/null +++ b/third_party/protobuf_pip_deps/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "protobuf_pip_deps") diff --git a/third_party/protobuf_pip_deps/requirements.bzl b/third_party/protobuf_pip_deps/requirements.bzl new file mode 100644 index 00000000000..6928f53d186 --- /dev/null +++ b/third_party/protobuf_pip_deps/requirements.bzl @@ -0,0 +1,11 @@ +"""Minimal pip dependency shim for protobuf's Bazel build.""" + +def requirement(name): + if name == "numpy": + return "@org_tensorflow_tensorboard//tensorboard:expect_numpy_installed" + if name == "setuptools": + return "@protobuf_pip_deps_setuptools//:site_packages" + fail("Unsupported protobuf pip dependency: %s" % name) + +def install_deps(): + return None diff --git a/third_party/protobuf_pip_deps_setuptools/BUILD.bazel b/third_party/protobuf_pip_deps_setuptools/BUILD.bazel new file mode 100644 index 00000000000..d1ea5b160c6 --- /dev/null +++ b/third_party/protobuf_pip_deps_setuptools/BUILD.bazel @@ -0,0 +1,5 @@ +filegroup( + name = "site_packages", + srcs = glob(["site-packages/**"]), + visibility = ["//visibility:public"], +) diff --git a/third_party/protobuf_pip_deps_setuptools/WORKSPACE b/third_party/protobuf_pip_deps_setuptools/WORKSPACE new file mode 100644 index 00000000000..0ad533bd878 --- /dev/null +++ b/third_party/protobuf_pip_deps_setuptools/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "protobuf_pip_deps_setuptools") diff --git a/third_party/protobuf_pip_deps_setuptools/site-packages/.keep b/third_party/protobuf_pip_deps_setuptools/site-packages/.keep new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/third_party/protobuf_pip_deps_setuptools/site-packages/.keep @@ -0,0 +1 @@ + diff --git a/third_party/repo.bzl b/third_party/repo.bzl new file mode 100644 index 00000000000..24ee5d2932b --- /dev/null +++ b/third_party/repo.bzl @@ -0,0 +1,91 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# 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. + +"""Repository helpers for TensorBoard external dependencies.""" + +def tb_mirror_urls(url): + """Returns TensorFlow mirror plus origin URLs for an HTTPS source.""" + if not url.startswith("https://"): + return [url] + return [ + "https://storage.googleapis.com/mirror.tensorflow.org/%s" % url[8:], + url, + ] + +def _get_link_dict(ctx, link_files, build_file): + link_dict = {ctx.path(v): ctx.path(Label(k)) for k, v in link_files.items()} + if build_file: + link_dict[ctx.path("BUILD.bazel")] = ctx.path(Label(build_file)) + return link_dict + +def _tb_http_archive_impl(ctx): + link_dict = _get_link_dict(ctx, ctx.attr.link_files, ctx.attr.build_file) + + patch_files = ctx.attr.patch_file + for patch_file in patch_files: + if patch_file: + ctx.path(Label(patch_file)) + + ctx.download_and_extract( + url = ctx.attr.urls, + sha256 = ctx.attr.sha256, + type = ctx.attr.type, + stripPrefix = ctx.attr.strip_prefix, + ) + + for patch_file in patch_files: + patch_file = ctx.path(Label(patch_file)) if patch_file else None + if patch_file: + ctx.patch(patch_file, strip = 1) + + for dst, src in link_dict.items(): + ctx.delete(dst) + ctx.symlink(src, dst) + +_tb_http_archive = repository_rule( + implementation = _tb_http_archive_impl, + attrs = { + "sha256": attr.string(mandatory = True), + "urls": attr.string_list(mandatory = True), + "strip_prefix": attr.string(), + "type": attr.string(), + "patch_file": attr.string_list(), + "build_file": attr.string(), + "link_files": attr.string_dict(), + }, +) + +def tb_http_archive(name, sha256, urls, **kwargs): + """Downloads and creates Bazel repos for TensorBoard dependencies.""" + if len(urls) < 2: + fail("tb_http_archive(urls) must have redundant URLs.") + + if not any([mirror in urls[0] for mirror in ( + "mirror.tensorflow.org", + "mirror.bazel.build", + "storage.googleapis.com", + )]): + fail("The first entry of tb_http_archive(urls) must be a mirror URL.") + + if native.existing_rule(name): + print("\n\033[1;33mWarning:\033[0m skipping import of repository '" + + name + "' because it already exists.\n") + return + + _tb_http_archive( + name = name, + sha256 = sha256, + urls = urls, + **kwargs + ) diff --git a/third_party/safe_html_types/BUILD.bazel b/third_party/safe_html_types/BUILD.bazel new file mode 100644 index 00000000000..8f9dfefdab8 --- /dev/null +++ b/third_party/safe_html_types/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_java//java:defs.bzl", "java_library") + +package(default_visibility = ["//visibility:public"]) + +java_library( + name = "com_google_common_html_types", + srcs = glob(["com/google/common/html/types/*.java"]), + deps = [ + "@com_google_code_findbugs_jsr305", + "@com_google_errorprone_error_prone_annotations", + "@com_google_guava", + "@com_google_jsinterop_annotations", + "@com_google_protobuf//:protobuf_java", + "@javax_annotation_jsr250_api", + ], +) diff --git a/third_party/safe_html_types/META-INF/MANIFEST.MF b/third_party/safe_html_types/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..fdb42cceba7 --- /dev/null +++ b/third_party/safe_html_types/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +Archiver-Version: Plexus Archiver +Built-By: msamuel +Created-By: Apache Maven 3.5.0 +Build-Jdk: 1.8.0_144 + diff --git a/third_party/safe_html_types/WORKSPACE b/third_party/safe_html_types/WORKSPACE new file mode 100644 index 00000000000..444edc8e1ec --- /dev/null +++ b/third_party/safe_html_types/WORKSPACE @@ -0,0 +1 @@ +workspace(name = "com_google_common_html_types") diff --git a/third_party/safe_html_types/com/google/common/html/types/BuilderUtils.java b/third_party/safe_html_types/com/google/common/html/types/BuilderUtils.java new file mode 100644 index 00000000000..f0e8d3b7ad9 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/BuilderUtils.java @@ -0,0 +1,64 @@ +// **** GENERATED CODE, DO NOT MODIFY **** +// This file was generated via preprocessing from input: +// java/com/google/common/html/types/BuilderUtils.java.tpl +// *************************************** +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * 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.common.html.types; + +import com.google.common.annotations.GwtCompatible; +import com.google.common.escape.Escaper; +import com.google.common.escape.Escapers; +import javax.annotation.CheckReturnValue; + + +/** + * Static utility methods shared by safe-HTML types' factory and builder classes, such as + * {@link SafeHtmls}, {@link SafeHtmlBuilder}, etc. + */ +@CheckReturnValue +@GwtCompatible +final class BuilderUtils { + + private BuilderUtils() {} + + static String coerceToInterchangeValid(String text) { + // MOE elided code that uses a non-public library to make sure text only + // contains minimally-encoded Unicode scalar values that can appear in + // both HTML and XML. + return text; + + } + + static String escapeHtmlInternal(String s) { + return HTML_ESCAPER.escape(s); + + } + + // This is exactly what j.c.g.common.html.HtmlEscapers.htmlEscaper() does. However, depending on + // j.c.g.common.html is problematic because it has no android target, substantial internal only + // code, and it pulls a lot of other dependencies with it. + private static final Escaper HTML_ESCAPER = + Escapers.builder() + .addEscape('"', """) + // Note: "'" is not defined in HTML 4.01. + .addEscape('\'', "'") + .addEscape('&', "&") + .addEscape('<', "<") + .addEscape('>', ">") + .build(); +} diff --git a/third_party/safe_html_types/com/google/common/html/types/CustomSafeUrlScheme.java b/third_party/safe_html_types/com/google/common/html/types/CustomSafeUrlScheme.java new file mode 100644 index 00000000000..09010d736d6 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/CustomSafeUrlScheme.java @@ -0,0 +1,227 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: webutil/html/types/html.proto + +package com.google.common.html.types; + +/** + * Protobuf enum {@code webutil.html.types.CustomSafeUrlScheme} + */ +public enum CustomSafeUrlScheme + implements com.google.protobuf.ProtocolMessageEnum { + /** + *
+   * Schemes that are safe w.r.t. XSS but that may trigger other problematic
+   * actions when presented in the context of a "regular" link are not
+   * whitelisted by default but can still be converted to SafeUrl by
+   * whitelisting them explicitly in the SafeUrl sanitization API. In other
+   * words, the caller has to indicate that they're expecting to process
+   * such custom schemes.
+   * iOS Webview does not ask for confirmation before invoking 'tel', so
+   * unintentional or out-of-context clicks could result in unintended calling
+   * charges.
+   * 
+ * + * TEL = 0; + */ + TEL(0), + /** + * SMS = 1; + */ + SMS(1), + /** + *
+   * Similarly to 'tel' can result in unintended calling charges on iOS.
+   * 
+ * + * CALLTO = 2; + */ + CALLTO(2), + /** + * WTAI = 3; + */ + WTAI(3), + /** + *
+   * Can start a media stream, potentially triggering an exploit for
+   * Stagefright.
+   * 
+ * + * RTSP = 4; + */ + RTSP(4), + /** + *
+   * Can open Play Store dialog with 'Install' button, though will not
+   * automatically install an app.
+   * 
+ * + * MARKET = 5; + */ + MARKET(5), + /** + * GEO = 6; + */ + GEO(6), + /** + * SKYPE = 7; + */ + SKYPE(7), + /** + * WHATSAPP = 8; + */ + WHATSAPP(8), + /** + *
+   * Custom scheme for iBooks URIs. More background: b/32807272.
+   * 
+ * + * ITMS_BOOKS = 9; + */ + ITMS_BOOKS(9), + ; + + /** + *
+   * Schemes that are safe w.r.t. XSS but that may trigger other problematic
+   * actions when presented in the context of a "regular" link are not
+   * whitelisted by default but can still be converted to SafeUrl by
+   * whitelisting them explicitly in the SafeUrl sanitization API. In other
+   * words, the caller has to indicate that they're expecting to process
+   * such custom schemes.
+   * iOS Webview does not ask for confirmation before invoking 'tel', so
+   * unintentional or out-of-context clicks could result in unintended calling
+   * charges.
+   * 
+ * + * TEL = 0; + */ + public static final int TEL_VALUE = 0; + /** + * SMS = 1; + */ + public static final int SMS_VALUE = 1; + /** + *
+   * Similarly to 'tel' can result in unintended calling charges on iOS.
+   * 
+ * + * CALLTO = 2; + */ + public static final int CALLTO_VALUE = 2; + /** + * WTAI = 3; + */ + public static final int WTAI_VALUE = 3; + /** + *
+   * Can start a media stream, potentially triggering an exploit for
+   * Stagefright.
+   * 
+ * + * RTSP = 4; + */ + public static final int RTSP_VALUE = 4; + /** + *
+   * Can open Play Store dialog with 'Install' button, though will not
+   * automatically install an app.
+   * 
+ * + * MARKET = 5; + */ + public static final int MARKET_VALUE = 5; + /** + * GEO = 6; + */ + public static final int GEO_VALUE = 6; + /** + * SKYPE = 7; + */ + public static final int SKYPE_VALUE = 7; + /** + * WHATSAPP = 8; + */ + public static final int WHATSAPP_VALUE = 8; + /** + *
+   * Custom scheme for iBooks URIs. More background: b/32807272.
+   * 
+ * + * ITMS_BOOKS = 9; + */ + public static final int ITMS_BOOKS_VALUE = 9; + + + public final int getNumber() { + return value; + } + + /** + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static CustomSafeUrlScheme valueOf(int value) { + return forNumber(value); + } + + public static CustomSafeUrlScheme forNumber(int value) { + switch (value) { + case 0: return TEL; + case 1: return SMS; + case 2: return CALLTO; + case 3: return WTAI; + case 4: return RTSP; + case 5: return MARKET; + case 6: return GEO; + case 7: return SKYPE; + case 8: return WHATSAPP; + case 9: return ITMS_BOOKS; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static final com.google.protobuf.Internal.EnumLiteMap< + CustomSafeUrlScheme> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public CustomSafeUrlScheme findValueByNumber(int number) { + return CustomSafeUrlScheme.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + return getDescriptor().getValues().get(ordinal()); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return com.google.common.html.types.Html.getDescriptor().getEnumTypes().get(0); + } + + private static final CustomSafeUrlScheme[] VALUES = values(); + + public static CustomSafeUrlScheme valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private CustomSafeUrlScheme(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:webutil.html.types.CustomSafeUrlScheme) +} + diff --git a/third_party/safe_html_types/com/google/common/html/types/Html.java b/third_party/safe_html_types/com/google/common/html/types/Html.java new file mode 100644 index 00000000000..a0fdbd842e6 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/Html.java @@ -0,0 +1,120 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: webutil/html/types/html.proto + +package com.google.common.html.types; + +public final class Html { + private Html() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_webutil_html_types_SafeHtmlProto_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_webutil_html_types_SafeHtmlProto_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_webutil_html_types_SafeUrlProto_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_webutil_html_types_SafeUrlProto_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_webutil_html_types_TrustedResourceUrlProto_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_webutil_html_types_TrustedResourceUrlProto_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_webutil_html_types_SafeStyleProto_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_webutil_html_types_SafeStyleProto_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_webutil_html_types_SafeScriptProto_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_webutil_html_types_SafeScriptProto_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_webutil_html_types_SafeStyleSheetProto_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_webutil_html_types_SafeStyleSheetProto_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\035webutil/html/types/html.proto\022\022webutil" + + ".html.types\"R\n\rSafeHtmlProto\022A\n5private_" + + "do_not_access_or_else_safe_html_wrapped_" + + "value\030\002 \001(\tB\002\010\001\"L\n\014SafeUrlProto\022<\n4priva" + + "te_do_not_access_or_else_safe_url_wrappe" + + "d_value\030\003 \001(\t\"c\n\027TrustedResourceUrlProto" + + "\022H\n@private_do_not_access_or_else_truste" + + "d_resource_url_wrapped_value\030\004 \001(\t\"P\n\016Sa" + + "feStyleProto\022>\n6private_do_not_access_or" + + "_else_safe_style_wrapped_value\030\005 \001(\t\"V\n\017", + "SafeScriptProto\022C\n7private_do_not_access" + + "_or_else_safe_script_wrapped_value\030\006 \001(\t" + + "B\002\010\001\"_\n\023SafeStyleSheetProto\022H\nA SafeHtml is a string-like object that carries the security type contract that its value as a + * string will not cause untrusted script execution when evaluated as HTML in a browser. + * + *

Values of this type are guaranteed to be safe to use in HTML contexts, such as, assignment to + * the innerHTML DOM property, or interpolation into a HTML template in HTML PC_DATA context, in + * the sense that the use will not result in a Cross-Site-Scripting vulnerability. + */ +@CheckReturnValue +@Immutable +@JsType +public final class SafeHtml { + + /** The SafeHtml wrapping an empty string. */ + public static final SafeHtml EMPTY = new SafeHtml(""); + + private final String privateDoNotAccessOrElseSafeHtmlWrappedValue; + + SafeHtml(String html) { + if (html == null) { + throw new NullPointerException(); + } + this.privateDoNotAccessOrElseSafeHtmlWrappedValue = html; + } + + @Override + public int hashCode() { + return privateDoNotAccessOrElseSafeHtmlWrappedValue.hashCode() ^ 0x33b02fa9; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof SafeHtml)) { + return false; + } + SafeHtml that = (SafeHtml) other; + return this.privateDoNotAccessOrElseSafeHtmlWrappedValue.equals( + that.privateDoNotAccessOrElseSafeHtmlWrappedValue); + } + + /** + * Returns a debug representation of this value's underlying string, NOT the string representation + * of the SafeHtml. + * + *

Having {@code toString()} return a debug representation is intentional. This type has + * a GWT-compiled JavaScript version; JavaScript has no static typing and a distinct method + * method name provides a modicum of type-safety. + * + * @see #getSafeHtmlString + */ + @Override + public String toString() { + return "SafeHtml{" + privateDoNotAccessOrElseSafeHtmlWrappedValue + "}"; + } + + /** + * Returns this value's underlying string. See class documentation for what guarantees exist on + * the returned string. + */ + // NOTE(mlourenco): jslayout depends on this exact method name when generating code, be careful if + // changing it. + public String getSafeHtmlString() { + return privateDoNotAccessOrElseSafeHtmlWrappedValue; + } +} diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeHtmlBuilder.java b/third_party/safe_html_types/com/google/common/html/types/SafeHtmlBuilder.java new file mode 100644 index 00000000000..ea70d08ee90 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeHtmlBuilder.java @@ -0,0 +1,1079 @@ +// **** GENERATED CODE, DO NOT MODIFY **** +// This file was generated via preprocessing from input: +// java/com/google/common/html/types/SafeHtmlBuilder.java.tpl +// Please make changes to that file and run +// java/com/google/common/html/types/gen_srcs.sh +// to regenerate the .java files. +// *************************************** +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * 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.common.html.types; + +import static com.google.common.html.types.BuilderUtils.coerceToInterchangeValid; +import static com.google.common.html.types.BuilderUtils.escapeHtmlInternal; + +import com.google.common.annotations.GwtCompatible; +import com.google.errorprone.annotations.CompileTimeConstant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.annotation.CheckReturnValue; +import javax.annotation.Generated; +import javax.annotation.Nullable; +import javax.annotation.concurrent.NotThreadSafe; + +/** + * Builder for HTML elements which conform to the {@link SafeHtml} contract. Supports setting + * element name, individual attributes and content. + * + *

While this builder disallows some invalid HTML constructs (for example, void elements with + * content) it does not guarantee well-formed HTML (for example, attribute values are not strictly + * enforced if they pose no security risk). A large number of runtime failures are possible and it + * is therefore recommended to thoroughly unit test code using this builder. + */ +@Generated(value = "//java/com/google/common/html/types:gen_srcs.sh") +@GwtCompatible +@NotThreadSafe +public final class SafeHtmlBuilder { + // Keep these regular expressions compatible across Java and JavaScript native implementations. + // They are uncompiled because we couldn't depend on java.util.regex.Pattern or + // com.google.gwt.regexp.shared.RegExp + private static final String VALID_ELEMENT_NAMES_REGEXP = "[a-z0-9-]+"; + private static final String VALID_DATA_ATTRIBUTES_REGEXP = "data-[a-zA-Z-]+"; + + private static final Set UNSUPPORTED_ELEMENTS = + createUnmodifiableSet( + "applet", + "base", + "embed", + "math", + "meta", + "object", + "script", + "style", + "svg", + "template"); + + private static final Set VOID_ELEMENTS = + createUnmodifiableSet( + "area", "br", "col", "hr", "img", "input", "keygen", "link", "param", "source", "track", + "wbr"); + + private final String elementName; + /** We use LinkedHashMap to maintain attribute insertion order. */ + private final Map attributes = new LinkedHashMap<>(); + + private final List contents = new ArrayList<>(); + + private boolean useSlashOnVoid = false; + + private enum AttributeContract { + SAFE_URL, + TRUSTED_RESOURCE_URL + } + + /** Contract of the value currently assigned to the {@code href} attribute. */ + private AttributeContract hrefValueContract = AttributeContract.TRUSTED_RESOURCE_URL; + + /** + * Creates a builder for the given {@code elementName}, which must consist only of lowercase + * letters, digits and {@code -}. + * + *

If {@code elementName} is not a void element then the string representation of the builder + * is {@code [optional content]}. If {@code + * elementName} is a void element then the string representation is {@code }. Contents between the element's start and end tag can be set via, for example, + * {@code appendContent()}. + * + *

{@code embed}, {@code object}, {@code script}, {@code style}, {@code template} are not + * supported because their content has special semantics, and they can result the execution of + * code not under application control. Some of these have dedicated creation methods. + * + * @throws IllegalArgumentException if {@code elementName} contains invalid characters or is not + * supported + * @see http://whatwg.org/html/syntax.html#void-elements + */ + public SafeHtmlBuilder(@CompileTimeConstant final String elementName) { + if (elementName == null) { + throw new NullPointerException(); + } + if (!elementName.matches(VALID_ELEMENT_NAMES_REGEXP)) { + throw new IllegalArgumentException( + "Invalid element name \"" + + elementName + + "\". " + + "Only lowercase letters, numbers and '-' allowed."); + } + if (UNSUPPORTED_ELEMENTS.contains(elementName)) { + throw new IllegalArgumentException("Element \"" + elementName + "\" is not supported."); + } + this.elementName = elementName; + } + + /** + * Causes the builder to use a slash on the tag of a void element, emitting e.g. {@code
} + * instead of the default {@code
}. Slashes are required if rendering XHTML and optional in + * HTML 5. + * + *

This setting has no effect for non-void elements. + * + * @see http://www.w3.org/TR/html5/syntax.html#start-tags + */ + public SafeHtmlBuilder useSlashOnVoid() { + useSlashOnVoid = true; + return this; + } + /** These elements are whitelisted to use action with a SafeUrl value. */ + private static final Set ACTION_SAFE_URL_ELEMENT_WHITELIST = + createUnmodifiableSet("form"); + + /** + * Sets the {@code action} attribute for this element. + * + *

The attribute {@code action} with a {@code SafeUrl} value is allowed on these elements: + * + *

    + *
  • {@code form} + *
+ * + * @throws IllegalArgumentException if the {@code action} attribute with a {@code SafeUrl} value + * is not allowed on this element + */ + public SafeHtmlBuilder setAction(SafeUrl value) { + if (!ACTION_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"action\" with a SafeUrl value can only be used " + + "by one of the following elements: " + + ACTION_SAFE_URL_ELEMENT_WHITELIST); + } + return setAttribute("action", value.getSafeUrlString()); + } + + /** Sets the {@code align} attribute for this element. */ + public SafeHtmlBuilder setAlign(String value) { + return setAttribute("align", value); + } + + /** Sets the {@code alt} attribute for this element. */ + public SafeHtmlBuilder setAlt(String value) { + return setAttribute("alt", value); + } + + /** Sets the {@code autocapitalize} attribute for this element. */ + public SafeHtmlBuilder setAutocapitalize(String value) { + return setAttribute("autocapitalize", value); + } + + /** Sets the {@code autocomplete} attribute for this element. */ + public SafeHtmlBuilder setAutocomplete(String value) { + return setAttribute("autocomplete", value); + } + + /** Sets the {@code autofocus} attribute for this element. */ + public SafeHtmlBuilder setAutofocus(String value) { + return setAttribute("autofocus", value); + } + + /** Sets the {@code bgcolor} attribute for this element. */ + public SafeHtmlBuilder setBgcolor(String value) { + return setAttribute("bgcolor", value); + } + + /** Sets the {@code border} attribute for this element. */ + public SafeHtmlBuilder setBorder(String value) { + return setAttribute("border", value); + } + + /** Sets the {@code checked} attribute for this element. */ + public SafeHtmlBuilder setChecked(String value) { + return setAttribute("checked", value); + } + + /** These elements are whitelisted to use cite with a SafeUrl value. */ + private static final Set CITE_SAFE_URL_ELEMENT_WHITELIST = + createUnmodifiableSet("blockquote", "del", "ins", "q"); + + /** + * Sets the {@code cite} attribute for this element. + * + *

The attribute {@code cite} with a {@code SafeUrl} value is allowed on these elements: + * + *

    + *
  • {@code blockquote} + *
  • {@code del} + *
  • {@code ins} + *
  • {@code q} + *
+ * + * @throws IllegalArgumentException if the {@code cite} attribute with a {@code SafeUrl} value is + * not allowed on this element + */ + public SafeHtmlBuilder setCite(SafeUrl value) { + if (!CITE_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"cite\" with a SafeUrl value can only be used " + + "by one of the following elements: " + + CITE_SAFE_URL_ELEMENT_WHITELIST); + } + return setAttribute("cite", value.getSafeUrlString()); + } + + /** Sets the {@code class} attribute for this element. */ + public SafeHtmlBuilder setClass(String value) { + return setAttribute("class", value); + } + + /** Sets the {@code color} attribute for this element. */ + public SafeHtmlBuilder setColor(String value) { + return setAttribute("color", value); + } + + /** Sets the {@code cols} attribute for this element. */ + public SafeHtmlBuilder setCols(String value) { + return setAttribute("cols", value); + } + + /** Sets the {@code colspan} attribute for this element. */ + public SafeHtmlBuilder setColspan(String value) { + return setAttribute("colspan", value); + } + + /** Values that can be passed to {@link #setDir(DirValue)}. */ + public enum DirValue { + + /** Value of {@code auto}. */ + AUTO("auto"), + /** Value of {@code ltr}. */ + LTR("ltr"), + /** Value of {@code rtl}. */ + RTL("rtl"); + + private final String value; + + private DirValue(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + /** Sets the {@code dir} attribute for this element. */ + public SafeHtmlBuilder setDir(DirValue value) { + return setAttribute("dir", value.toString()); + } + + /** Sets the {@code disabled} attribute for this element. */ + public SafeHtmlBuilder setDisabled(String value) { + return setAttribute("disabled", value); + } + + /** Sets the {@code draggable} attribute for this element. */ + public SafeHtmlBuilder setDraggable(String value) { + return setAttribute("draggable", value); + } + + /** Sets the {@code face} attribute for this element. */ + public SafeHtmlBuilder setFace(String value) { + return setAttribute("face", value); + } + + /** Sets the {@code for} attribute for this element. */ + public SafeHtmlBuilder setFor(@CompileTimeConstant final String value) { + return setAttribute("for", value); + } + + /** + * Sets the {@code for} attribute for this element to a {@link CompileTimeConstant} {@code prefix} + * and a {@code value} joined by a hyphen. + * + * @throws IllegalArgumentException if {@code prefix} is an empty string + */ + public SafeHtmlBuilder setForWithPrefix(@CompileTimeConstant final String prefix, String value) { + if (prefix.trim().length() == 0) { + throw new IllegalArgumentException("Prefix cannot be empty string"); + } + return setAttribute("for", prefix + "-" + value); + } + + /** These elements are whitelisted to use formaction with a SafeUrl value. */ + private static final Set FORMACTION_SAFE_URL_ELEMENT_WHITELIST = + createUnmodifiableSet("button", "input"); + + /** + * Sets the {@code formaction} attribute for this element. + * + *

The attribute {@code formaction} with a {@code SafeUrl} value is allowed on these elements: + * + *

    + *
  • {@code button} + *
  • {@code input} + *
+ * + * @throws IllegalArgumentException if the {@code formaction} attribute with a {@code SafeUrl} + * value is not allowed on this element + */ + public SafeHtmlBuilder setFormaction(SafeUrl value) { + if (!FORMACTION_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"formaction\" with a SafeUrl value can only be used " + + "by one of the following elements: " + + FORMACTION_SAFE_URL_ELEMENT_WHITELIST); + } + return setAttribute("formaction", value.getSafeUrlString()); + } + + /** These elements are whitelisted to use formmethod with a String value. */ + private static final Set FORMMETHOD_STRING_ELEMENT_WHITELIST = + createUnmodifiableSet("button", "input"); + + /** + * Sets the {@code formmethod} attribute for this element. + * + *

The attribute {@code formmethod} with a {@code String} value is allowed on these elements: + * + *

    + *
  • {@code button} + *
  • {@code input} + *
+ * + * @throws IllegalArgumentException if the {@code formmethod} attribute with a {@code String} + * value is not allowed on this element + */ + public SafeHtmlBuilder setFormmethod(String value) { + if (!FORMMETHOD_STRING_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"formmethod\" with a String value can only be used " + + "by one of the following elements: " + + FORMMETHOD_STRING_ELEMENT_WHITELIST); + } + return setAttribute("formmethod", value); + } + + /** Sets the {@code frameborder} attribute for this element. */ + public SafeHtmlBuilder setFrameborder(String value) { + return setAttribute("frameborder", value); + } + + /** Sets the {@code height} attribute for this element. */ + public SafeHtmlBuilder setHeight(String value) { + return setAttribute("height", value); + } + + /** Sets the {@code hidden} attribute for this element. */ + public SafeHtmlBuilder setHidden(String value) { + return setAttribute("hidden", value); + } + + /** These elements are whitelisted to use href with a SafeUrl value. */ + private static final Set HREF_SAFE_URL_ELEMENT_WHITELIST = + createUnmodifiableSet("a", "area"); + /** + * On {@code link} elements, the {@code href} attribute may be set to {@code SafeUrl} values only + * for these values of the {@code rel} attribute. + */ + private static final Set LINK_HREF_SAFE_URL_REL_WHITELIST = + createUnmodifiableSet( + "alternate", + "author", + "bookmark", + "canonical", + "cite", + "help", + "icon", + "license", + "next", + "prefetch", + "prerender", + "prev", + "search", + "subresource"); + + /** + * Sets the {@code href} attribute for this element. + * + *

The attribute {@code href} with a {@code SafeUrl} value is allowed on these elements: + * + *

    + *
  • {@code a} + *
  • {@code area} + *
  • {@code link} + *
+ * + *

On {@code link} elements, {@code href} may only be set to a SafeUrl value if {@code rel} is + * one of the following values: + * + *

    + *
  • {@code alternate} + *
  • {@code author} + *
  • {@code bookmark} + *
  • {@code canonical} + *
  • {@code cite} + *
  • {@code help} + *
  • {@code icon} + *
  • {@code license} + *
  • {@code next} + *
  • {@code prefetch} + *
  • {@code prerender} + *
  • {@code prev} + *
  • {@code search} + *
  • {@code subresource} + *
+ * + * @throws IllegalArgumentException if the {@code href} attribute with a {@code SafeUrl} value is + * not allowed on this element + * @throws IllegalArgumentException if this a {@code link} element and the value of {@code rel} + * does not allow the SafeUrl contract on {@code href} + */ + public SafeHtmlBuilder setHref(SafeUrl value) { + if (!HREF_SAFE_URL_ELEMENT_WHITELIST.contains(elementName) && !elementName.equals("link")) { + throw new IllegalArgumentException( + "Attribute \"href\" with a SafeUrl value can only be used " + + "by one of the following elements: " + + HREF_SAFE_URL_ELEMENT_WHITELIST); + } + if (elementName.equals("link")) { + checkLinkDependentAttributes(attributes.get("rel"), AttributeContract.SAFE_URL); + } + hrefValueContract = AttributeContract.SAFE_URL; + return setAttribute("href", value.getSafeUrlString()); + } + + /** Sets the {@code href} attribute for this element. */ + public SafeHtmlBuilder setHref(TrustedResourceUrl value) { + hrefValueContract = AttributeContract.TRUSTED_RESOURCE_URL; + return setAttribute("href", value.getTrustedResourceUrlString()); + } + + /** These elements are whitelisted to use icon with a SafeUrl value. */ + private static final Set ICON_SAFE_URL_ELEMENT_WHITELIST = + createUnmodifiableSet("menuitem"); + + /** + * Sets the {@code icon} attribute for this element. + * + *

The attribute {@code icon} with a {@code SafeUrl} value is allowed on these elements: + * + *

    + *
  • {@code menuitem} + *
+ * + * @throws IllegalArgumentException if the {@code icon} attribute with a {@code SafeUrl} value is + * not allowed on this element + */ + public SafeHtmlBuilder setIcon(SafeUrl value) { + if (!ICON_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"icon\" with a SafeUrl value can only be used " + + "by one of the following elements: " + + ICON_SAFE_URL_ELEMENT_WHITELIST); + } + return setAttribute("icon", value.getSafeUrlString()); + } + + /** Sets the {@code id} attribute for this element. */ + public SafeHtmlBuilder setId(@CompileTimeConstant final String value) { + return setAttribute("id", value); + } + + /** + * Sets the {@code id} attribute for this element to a {@link CompileTimeConstant} {@code prefix} + * and a {@code value} joined by a hyphen. + * + * @throws IllegalArgumentException if {@code prefix} is an empty string + */ + public SafeHtmlBuilder setIdWithPrefix(@CompileTimeConstant final String prefix, String value) { + if (prefix.trim().length() == 0) { + throw new IllegalArgumentException("Prefix cannot be empty string"); + } + return setAttribute("id", prefix + "-" + value); + } + + /** Sets the {@code ismap} attribute for this element. */ + public SafeHtmlBuilder setIsmap(String value) { + return setAttribute("ismap", value); + } + + /** Sets the {@code label} attribute for this element. */ + public SafeHtmlBuilder setLabel(String value) { + return setAttribute("label", value); + } + + /** Sets the {@code lang} attribute for this element. */ + public SafeHtmlBuilder setLang(String value) { + return setAttribute("lang", value); + } + + /** Sets the {@code list} attribute for this element. */ + public SafeHtmlBuilder setList(@CompileTimeConstant final String value) { + return setAttribute("list", value); + } + + /** + * Sets the {@code list} attribute for this element to a {@link CompileTimeConstant} {@code + * prefix} and a {@code value} joined by a hyphen. + * + * @throws IllegalArgumentException if {@code prefix} is an empty string + */ + public SafeHtmlBuilder setListWithPrefix(@CompileTimeConstant final String prefix, String value) { + if (prefix.trim().length() == 0) { + throw new IllegalArgumentException("Prefix cannot be empty string"); + } + return setAttribute("list", prefix + "-" + value); + } + + /** Sets the {@code loop} attribute for this element. */ + public SafeHtmlBuilder setLoop(String value) { + return setAttribute("loop", value); + } + + /** Sets the {@code max} attribute for this element. */ + public SafeHtmlBuilder setMax(String value) { + return setAttribute("max", value); + } + + /** Sets the {@code maxlength} attribute for this element. */ + public SafeHtmlBuilder setMaxlength(String value) { + return setAttribute("maxlength", value); + } + + /** These elements are whitelisted to use media with a String value. */ + private static final Set MEDIA_STRING_ELEMENT_WHITELIST = + createUnmodifiableSet("link", "source"); + + /** + * Sets the {@code media} attribute for this element. + * + *

The attribute {@code media} with a {@code String} value is allowed on these elements: + * + *

    + *
  • {@code link} + *
  • {@code source} + *
+ * + * @throws IllegalArgumentException if the {@code media} attribute with a {@code String} value is + * not allowed on this element + */ + public SafeHtmlBuilder setMedia(String value) { + if (!MEDIA_STRING_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"media\" with a String value can only be used " + + "by one of the following elements: " + + MEDIA_STRING_ELEMENT_WHITELIST); + } + return setAttribute("media", value); + } + + /** These elements are whitelisted to use method with a String value. */ + private static final Set METHOD_STRING_ELEMENT_WHITELIST = createUnmodifiableSet("form"); + + /** + * Sets the {@code method} attribute for this element. + * + *

The attribute {@code method} with a {@code String} value is allowed on these elements: + * + *

    + *
  • {@code form} + *
+ * + * @throws IllegalArgumentException if the {@code method} attribute with a {@code String} value is + * not allowed on this element + */ + public SafeHtmlBuilder setMethod(String value) { + if (!METHOD_STRING_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"method\" with a String value can only be used " + + "by one of the following elements: " + + METHOD_STRING_ELEMENT_WHITELIST); + } + return setAttribute("method", value); + } + + /** Sets the {@code min} attribute for this element. */ + public SafeHtmlBuilder setMin(String value) { + return setAttribute("min", value); + } + + /** Sets the {@code multiple} attribute for this element. */ + public SafeHtmlBuilder setMultiple(String value) { + return setAttribute("multiple", value); + } + + /** Sets the {@code muted} attribute for this element. */ + public SafeHtmlBuilder setMuted(String value) { + return setAttribute("muted", value); + } + + /** Sets the {@code name} attribute for this element. */ + public SafeHtmlBuilder setName(@CompileTimeConstant final String value) { + return setAttribute("name", value); + } + + /** + * Sets the {@code name} attribute for this element to a {@link CompileTimeConstant} {@code + * prefix} and a {@code value} joined by a hyphen. + * + * @throws IllegalArgumentException if {@code prefix} is an empty string + */ + public SafeHtmlBuilder setNameWithPrefix(@CompileTimeConstant final String prefix, String value) { + if (prefix.trim().length() == 0) { + throw new IllegalArgumentException("Prefix cannot be empty string"); + } + return setAttribute("name", prefix + "-" + value); + } + + /** These elements are whitelisted to use pattern with a String value. */ + private static final Set PATTERN_STRING_ELEMENT_WHITELIST = + createUnmodifiableSet("input"); + + /** + * Sets the {@code pattern} attribute for this element. + * + *

The attribute {@code pattern} with a {@code String} value is allowed on these elements: + * + *

    + *
  • {@code input} + *
+ * + * @throws IllegalArgumentException if the {@code pattern} attribute with a {@code String} value + * is not allowed on this element + */ + public SafeHtmlBuilder setPattern(String value) { + if (!PATTERN_STRING_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"pattern\" with a String value can only be used " + + "by one of the following elements: " + + PATTERN_STRING_ELEMENT_WHITELIST); + } + return setAttribute("pattern", value); + } + + /** Sets the {@code placeholder} attribute for this element. */ + public SafeHtmlBuilder setPlaceholder(String value) { + return setAttribute("placeholder", value); + } + + /** These elements are whitelisted to use poster with a SafeUrl value. */ + private static final Set POSTER_SAFE_URL_ELEMENT_WHITELIST = + createUnmodifiableSet("video"); + + /** + * Sets the {@code poster} attribute for this element. + * + *

The attribute {@code poster} with a {@code SafeUrl} value is allowed on these elements: + * + *

    + *
  • {@code video} + *
+ * + * @throws IllegalArgumentException if the {@code poster} attribute with a {@code SafeUrl} value + * is not allowed on this element + */ + public SafeHtmlBuilder setPoster(SafeUrl value) { + if (!POSTER_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"poster\" with a SafeUrl value can only be used " + + "by one of the following elements: " + + POSTER_SAFE_URL_ELEMENT_WHITELIST); + } + return setAttribute("poster", value.getSafeUrlString()); + } + + /** Sets the {@code preload} attribute for this element. */ + public SafeHtmlBuilder setPreload(String value) { + return setAttribute("preload", value); + } + + /** + * Sets the {@code rel} attribute for this element. + * + *

If this is a {@code link}} element, and {@code href} has been set from a {@link SafeUrl}, + * then {@code value} has to be an allowed value. See {@link #setHref(SafeHtml)}. + * + * @throws IllegalArgumentException if this is a {@code link} element and this value of {@code + * rel} is not allowed + */ + public SafeHtmlBuilder setRel(String value) { + checkLinkDependentAttributes(value, hrefValueContract); + return setAttribute("rel", value); + } + + /** Sets the {@code required} attribute for this element. */ + public SafeHtmlBuilder setRequired(String value) { + return setAttribute("required", value); + } + + /** Sets the {@code reversed} attribute for this element. */ + public SafeHtmlBuilder setReversed(String value) { + return setAttribute("reversed", value); + } + + /** Sets the {@code role} attribute for this element. */ + public SafeHtmlBuilder setRole(String value) { + return setAttribute("role", value); + } + + /** Sets the {@code rows} attribute for this element. */ + public SafeHtmlBuilder setRows(String value) { + return setAttribute("rows", value); + } + + /** Sets the {@code rowspan} attribute for this element. */ + public SafeHtmlBuilder setRowspan(String value) { + return setAttribute("rowspan", value); + } + + /** Sets the {@code selected} attribute for this element. */ + public SafeHtmlBuilder setSelected(String value) { + return setAttribute("selected", value); + } + + /** Sets the {@code shape} attribute for this element. */ + public SafeHtmlBuilder setShape(String value) { + return setAttribute("shape", value); + } + + /** Sets the {@code size} attribute for this element. */ + public SafeHtmlBuilder setSize(String value) { + return setAttribute("size", value); + } + + /** Sets the {@code sizes} attribute for this element. */ + public SafeHtmlBuilder setSizes(String value) { + return setAttribute("sizes", value); + } + + /** Sets the {@code span} attribute for this element. */ + public SafeHtmlBuilder setSpan(String value) { + return setAttribute("span", value); + } + + /** Sets the {@code spellcheck} attribute for this element. */ + public SafeHtmlBuilder setSpellcheck(String value) { + return setAttribute("spellcheck", value); + } + + /** These elements are whitelisted to use src with a SafeUrl value. */ + private static final Set SRC_SAFE_URL_ELEMENT_WHITELIST = + createUnmodifiableSet("audio", "img", "input", "source", "video"); + + /** + * Sets the {@code src} attribute for this element. + * + *

The attribute {@code src} with a {@code SafeUrl} value is allowed on these elements: + * + *

    + *
  • {@code audio} + *
  • {@code img} + *
  • {@code input} + *
  • {@code source} + *
  • {@code video} + *
+ * + * @throws IllegalArgumentException if the {@code src} attribute with a {@code SafeUrl} value is + * not allowed on this element + */ + public SafeHtmlBuilder setSrc(SafeUrl value) { + if (!SRC_SAFE_URL_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"src\" with a SafeUrl value can only be used " + + "by one of the following elements: " + + SRC_SAFE_URL_ELEMENT_WHITELIST); + } + return setAttribute("src", value.getSafeUrlString()); + } + + /** Sets the {@code src} attribute for this element. */ + public SafeHtmlBuilder setSrc(TrustedResourceUrl value) { + return setAttribute("src", value.getTrustedResourceUrlString()); + } + + /** These elements are whitelisted to use srcdoc with a SafeHtml value. */ + private static final Set SRCDOC_SAFE_HTML_ELEMENT_WHITELIST = + createUnmodifiableSet("iframe"); + + /** + * Sets the {@code srcdoc} attribute for this element. + * + *

The attribute {@code srcdoc} with a {@code SafeHtml} value is allowed on these elements: + * + *

    + *
  • {@code iframe} + *
+ * + * @throws IllegalArgumentException if the {@code srcdoc} attribute with a {@code SafeHtml} value + * is not allowed on this element + */ + public SafeHtmlBuilder setSrcdoc(SafeHtml value) { + if (!SRCDOC_SAFE_HTML_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"srcdoc\" with a SafeHtml value can only be used " + + "by one of the following elements: " + + SRCDOC_SAFE_HTML_ELEMENT_WHITELIST); + } + return setAttribute("srcdoc", value.getSafeHtmlString()); + } + + /** Sets the {@code start} attribute for this element. */ + public SafeHtmlBuilder setStart(String value) { + return setAttribute("start", value); + } + + /** Sets the {@code step} attribute for this element. */ + public SafeHtmlBuilder setStep(String value) { + return setAttribute("step", value); + } + + /** Sets the {@code style} attribute for this element. */ + public SafeHtmlBuilder setStyle(SafeStyle value) { + return setAttribute("style", value.getSafeStyleString()); + } + + /** Sets the {@code summary} attribute for this element. */ + public SafeHtmlBuilder setSummary(String value) { + return setAttribute("summary", value); + } + + /** Sets the {@code tabindex} attribute for this element. */ + public SafeHtmlBuilder setTabindex(String value) { + return setAttribute("tabindex", value); + } + + /** Values that can be passed to {@link #setTarget(TargetValue)}. */ + public enum TargetValue { + + /** Value of {@code _blank}. */ + BLANK("_blank"), + /** Value of {@code _self}. */ + SELF("_self"); + + private final String value; + + private TargetValue(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + /** Sets the {@code target} attribute for this element. */ + public SafeHtmlBuilder setTarget(TargetValue value) { + return setAttribute("target", value.toString()); + } + + /** Sets the {@code title} attribute for this element. */ + public SafeHtmlBuilder setTitle(String value) { + return setAttribute("title", value); + } + + /** Sets the {@code translate} attribute for this element. */ + public SafeHtmlBuilder setTranslate(String value) { + return setAttribute("translate", value); + } + + /** These elements are whitelisted to use type with a String value. */ + private static final Set TYPE_STRING_ELEMENT_WHITELIST = + createUnmodifiableSet("button", "command", "input", "li", "link", "ol"); + + /** + * Sets the {@code type} attribute for this element. + * + *

The attribute {@code type} with a {@code String} value is allowed on these elements: + * + *

    + *
  • {@code button} + *
  • {@code command} + *
  • {@code input} + *
  • {@code li} + *
  • {@code link} + *
  • {@code ol} + *
+ * + * @throws IllegalArgumentException if the {@code type} attribute with a {@code String} value is + * not allowed on this element + */ + public SafeHtmlBuilder setType(String value) { + if (!TYPE_STRING_ELEMENT_WHITELIST.contains(elementName)) { + throw new IllegalArgumentException( + "Attribute \"type\" with a String value can only be used " + + "by one of the following elements: " + + TYPE_STRING_ELEMENT_WHITELIST); + } + return setAttribute("type", value); + } + + /** Sets the {@code valign} attribute for this element. */ + public SafeHtmlBuilder setValign(String value) { + return setAttribute("valign", value); + } + + /** Sets the {@code value} attribute for this element. */ + public SafeHtmlBuilder setValue(String value) { + return setAttribute("value", value); + } + + /** Sets the {@code width} attribute for this element. */ + public SafeHtmlBuilder setWidth(String value) { + return setAttribute("width", value); + } + + /** Sets the {@code wrap} attribute for this element. */ + public SafeHtmlBuilder setWrap(String value) { + return setAttribute("wrap", value); + } + + /** + * Sets a custom data attribute, {@code name}, to {@code value} for this element. {@code value} + * must consist only of letters and {@code -}. + * + * @param name including the "data-" prefix, e.g. "data-tooltip" + * @throws IllegalArgumentException if the attribute name isn't valid + * @see + * http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes + */ + public SafeHtmlBuilder setDataAttribute(@CompileTimeConstant final String name, String value) { + if (!name.matches(VALID_DATA_ATTRIBUTES_REGEXP)) { + throw new IllegalArgumentException( + "Invalid data attribute name \"" + + name + + "\"." + + "Name must start with \"data-\" and be followed by letters and '-'."); + } + return setAttribute(name, value); + } + + /** + * Appends the given {@code htmls} as this element's content, in sequence. + * + * @throws IllegalStateException if this builder represents a void element + */ + public SafeHtmlBuilder appendContent(SafeHtml... htmls) { + checkNotVoidElement(); + Collections.addAll(contents, htmls); + return this; + } + + /** + * Appends the given {@code htmls} as this element's content, in the sequence the Iterable returns + * them. + * + * @throws IllegalStateException if this builder represents a void element + */ + public SafeHtmlBuilder appendContent(Iterable htmls) { + checkNotVoidElement(); + for (SafeHtml html : htmls) { + contents.add(html); + } + return this; + } + + /** + * Appends the given {@code htmls} as this element's content, in the sequence the Iterator returns + * them. + * + * @throws IllegalStateException if this builder represents a void element + */ + public SafeHtmlBuilder appendContent(Iterator htmls) { + checkNotVoidElement(); + while (htmls.hasNext()) { + contents.add(htmls.next()); + } + return this; + } + + /** + * Checks that this combination of rel value and href contract is safe. + * + * @param relValue is the value of rel or null if rel isn't present. + * @throws IllegalArgumentException if this value and contract combination is not allowed. + */ + private static void checkLinkDependentAttributes( + @Nullable String relValue, AttributeContract hrefValueContract) { + + if (hrefValueContract.equals(AttributeContract.SAFE_URL) + && relValue != null + && !LINK_HREF_SAFE_URL_REL_WHITELIST.contains(relValue.toLowerCase(Locale.ENGLISH))) { + throw new IllegalArgumentException( + "SafeUrl values for the href attribute are not allowed on . Did you intend to use a TrustedResourceUrl?"); + } + } + + private void checkNotVoidElement() { + if (VOID_ELEMENTS.contains(elementName)) { + throw new IllegalStateException( + "Element \"" + elementName + "\" is a void element and so cannot have content."); + } + } + + /** + * HTML-escapes and appends {@code text} to this element's content. + * + * @throws IllegalStateException if this builder represents a void element + */ + public SafeHtmlBuilder escapeAndAppendContent(String text) { + // htmlEscape() unicode coerces in non-portable version. + return appendContent(SafeHtmls.htmlEscape(text)); + } + + @CheckReturnValue + public SafeHtml build() { + StringBuilder sb = new StringBuilder("<" + elementName); + for (Map.Entry entry : attributes.entrySet()) { + sb.append(" " + entry.getKey() + "=\"" + escapeHtmlInternal(entry.getValue()) + "\""); + } + + boolean isVoid = VOID_ELEMENTS.contains(elementName); + if (isVoid && useSlashOnVoid) { + sb.append("/"); + } + sb.append(">"); + if (!isVoid) { + for (SafeHtml content : contents) { + sb.append(content.getSafeHtmlString()); + } + sb.append(""); + } + return SafeHtmls.create(sb.toString()); + } + + private static final Set createUnmodifiableSet(String... strings) { + HashSet set = new HashSet<>(); + Collections.addAll(set, strings); + return Collections.unmodifiableSet(set); + } + + private SafeHtmlBuilder setAttribute(@CompileTimeConstant final String name, String value) { + if (value == null) { + throw new NullPointerException("setAttribute requires a non-null value."); + } + attributes.put(name, coerceToInterchangeValid(value)); + return this; + } +} diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeHtmlProto.java b/third_party/safe_html_types/com/google/common/html/types/SafeHtmlProto.java new file mode 100644 index 00000000000..e02f9674010 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeHtmlProto.java @@ -0,0 +1,614 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: webutil/html/types/html.proto + +package com.google.common.html.types; + +/** + *
+ * IMPORTANT: It is unsafe to accept this message from an untrusted source,
+ * since it's trivial for an attacker to forge serialized messages that
+ * don't fulfill the type's safety contract -- for example, it could contain
+ * attacker controlled script. A system which receives a SafeHtmlProto
+ * implicitly trusts the producer of the SafeHtmlProto. So, it's generally safe
+ * to return this message in RPC responses, but generally unsafe to accept it
+ * in RPC requests.
+ * 
+ * + * Protobuf type {@code webutil.html.types.SafeHtmlProto} + */ +public final class SafeHtmlProto extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:webutil.html.types.SafeHtmlProto) + SafeHtmlProtoOrBuilder { + // Use SafeHtmlProto.newBuilder() to construct. + private SafeHtmlProto(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private SafeHtmlProto() { + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = ""; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private SafeHtmlProto( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 18: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = bs; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeHtmlProto_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeHtmlProto_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.common.html.types.SafeHtmlProto.class, com.google.common.html.types.SafeHtmlProto.Builder.class); + } + + private int bitField0_; + public static final int PRIVATE_DO_NOT_ACCESS_OR_ELSE_SAFE_HTML_WRAPPED_VALUE_FIELD_NUMBER = 2; + private volatile java.lang.Object privateDoNotAccessOrElseSafeHtmlWrappedValue_; + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + public boolean hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + public java.lang.String getPrivateDoNotAccessOrElseSafeHtmlWrappedValue() { + java.lang.Object ref = privateDoNotAccessOrElseSafeHtmlWrappedValue_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = s; + } + return s; + } + } + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + public com.google.protobuf.ByteString + getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes() { + java.lang.Object ref = privateDoNotAccessOrElseSafeHtmlWrappedValue_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, privateDoNotAccessOrElseSafeHtmlWrappedValue_); + } + unknownFields.writeTo(output); + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, privateDoNotAccessOrElseSafeHtmlWrappedValue_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.common.html.types.SafeHtmlProto)) { + return super.equals(obj); + } + com.google.common.html.types.SafeHtmlProto other = (com.google.common.html.types.SafeHtmlProto) obj; + + boolean result = true; + result = result && (hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue() == other.hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()); + if (hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()) { + result = result && getPrivateDoNotAccessOrElseSafeHtmlWrappedValue() + .equals(other.getPrivateDoNotAccessOrElseSafeHtmlWrappedValue()); + } + result = result && unknownFields.equals(other.unknownFields); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()) { + hash = (37 * hash) + PRIVATE_DO_NOT_ACCESS_OR_ELSE_SAFE_HTML_WRAPPED_VALUE_FIELD_NUMBER; + hash = (53 * hash) + getPrivateDoNotAccessOrElseSafeHtmlWrappedValue().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.common.html.types.SafeHtmlProto parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.google.common.html.types.SafeHtmlProto parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.google.common.html.types.SafeHtmlProto parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.google.common.html.types.SafeHtmlProto parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.google.common.html.types.SafeHtmlProto parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.google.common.html.types.SafeHtmlProto parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.google.common.html.types.SafeHtmlProto parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.google.common.html.types.SafeHtmlProto parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static com.google.common.html.types.SafeHtmlProto parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static com.google.common.html.types.SafeHtmlProto parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static com.google.common.html.types.SafeHtmlProto parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.google.common.html.types.SafeHtmlProto parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(com.google.common.html.types.SafeHtmlProto prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * IMPORTANT: It is unsafe to accept this message from an untrusted source,
+   * since it's trivial for an attacker to forge serialized messages that
+   * don't fulfill the type's safety contract -- for example, it could contain
+   * attacker controlled script. A system which receives a SafeHtmlProto
+   * implicitly trusts the producer of the SafeHtmlProto. So, it's generally safe
+   * to return this message in RPC responses, but generally unsafe to accept it
+   * in RPC requests.
+   * 
+ * + * Protobuf type {@code webutil.html.types.SafeHtmlProto} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:webutil.html.types.SafeHtmlProto) + com.google.common.html.types.SafeHtmlProtoOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeHtmlProto_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeHtmlProto_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.common.html.types.SafeHtmlProto.class, com.google.common.html.types.SafeHtmlProto.Builder.class); + } + + // Construct using com.google.common.html.types.SafeHtmlProto.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeHtmlProto_descriptor; + } + + public com.google.common.html.types.SafeHtmlProto getDefaultInstanceForType() { + return com.google.common.html.types.SafeHtmlProto.getDefaultInstance(); + } + + public com.google.common.html.types.SafeHtmlProto build() { + com.google.common.html.types.SafeHtmlProto result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.google.common.html.types.SafeHtmlProto buildPartial() { + com.google.common.html.types.SafeHtmlProto result = new com.google.common.html.types.SafeHtmlProto(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = privateDoNotAccessOrElseSafeHtmlWrappedValue_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.common.html.types.SafeHtmlProto) { + return mergeFrom((com.google.common.html.types.SafeHtmlProto)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.common.html.types.SafeHtmlProto other) { + if (other == com.google.common.html.types.SafeHtmlProto.getDefaultInstance()) return this; + if (other.hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()) { + bitField0_ |= 0x00000001; + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = other.privateDoNotAccessOrElseSafeHtmlWrappedValue_; + onChanged(); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.common.html.types.SafeHtmlProto parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.google.common.html.types.SafeHtmlProto) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.lang.Object privateDoNotAccessOrElseSafeHtmlWrappedValue_ = ""; + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + public boolean hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + public java.lang.String getPrivateDoNotAccessOrElseSafeHtmlWrappedValue() { + java.lang.Object ref = privateDoNotAccessOrElseSafeHtmlWrappedValue_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + public com.google.protobuf.ByteString + getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes() { + java.lang.Object ref = privateDoNotAccessOrElseSafeHtmlWrappedValue_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + public Builder setPrivateDoNotAccessOrElseSafeHtmlWrappedValue( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = value; + onChanged(); + return this; + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + public Builder clearPrivateDoNotAccessOrElseSafeHtmlWrappedValue() { + bitField0_ = (bitField0_ & ~0x00000001); + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = getDefaultInstance().getPrivateDoNotAccessOrElseSafeHtmlWrappedValue(); + onChanged(); + return this; + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + public Builder setPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + privateDoNotAccessOrElseSafeHtmlWrappedValue_ = value; + onChanged(); + return this; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:webutil.html.types.SafeHtmlProto) + } + + // @@protoc_insertion_point(class_scope:webutil.html.types.SafeHtmlProto) + private static final com.google.common.html.types.SafeHtmlProto DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new com.google.common.html.types.SafeHtmlProto(); + } + + public static com.google.common.html.types.SafeHtmlProto getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + @java.lang.Deprecated public static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public SafeHtmlProto parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new SafeHtmlProto(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public com.google.common.html.types.SafeHtmlProto getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeHtmlProtoOrBuilder.java b/third_party/safe_html_types/com/google/common/html/types/SafeHtmlProtoOrBuilder.java new file mode 100644 index 00000000000..a8907533107 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeHtmlProtoOrBuilder.java @@ -0,0 +1,41 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: webutil/html/types/html.proto + +package com.google.common.html.types; + +public interface SafeHtmlProtoOrBuilder extends + // @@protoc_insertion_point(interface_extends:webutil.html.types.SafeHtmlProto) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + boolean hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue(); + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + java.lang.String getPrivateDoNotAccessOrElseSafeHtmlWrappedValue(); + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_html_wrapped_value = 2 [ctype = CORD]; + */ + com.google.protobuf.ByteString + getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes(); +} diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeHtmls.java b/third_party/safe_html_types/com/google/common/html/types/SafeHtmls.java new file mode 100644 index 00000000000..a746a4e72f4 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeHtmls.java @@ -0,0 +1,198 @@ +// **** GENERATED CODE, DO NOT MODIFY **** +// This file was generated via preprocessing from input: +// java/com/google/common/html/types/SafeHtmls.java.tpl +// *************************************** +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * 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.common.html.types; + +import static com.google.common.html.types.BuilderUtils.coerceToInterchangeValid; +import static com.google.common.html.types.BuilderUtils.escapeHtmlInternal; + +import com.google.common.annotations.GwtCompatible; +import com.google.common.base.Preconditions; +import java.util.Arrays; +import javax.annotation.CheckReturnValue; + +/** + * Protocol conversions, builders and factory methods for {@link SafeHtml}. + */ +@CheckReturnValue +@GwtCompatible +public final class SafeHtmls { + + /** + * Deserializes a SafeHtmlProto into a SafeHtml instance. + * + *

Protocol-message forms are intended to be opaque. The fields of the protocol message should + * be considered encapsulated and are not intended for direct inspection or manipulation. Protocol + * message forms of this type should be produced by {@link #toProto(SafeHtml)} or its + * equivalent in other implementation languages. + * + *

Important: It is unsafe to invoke this method on a protocol message that has been + * received from an entity outside the application's trust domain. Data coming from the browser + * is outside the application's trust domain. + */ + public static SafeHtml fromProto(SafeHtmlProto proto) { + return create(proto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValue()); + } + + /** + * Wraps a SafeScript inside a <script type="text/javascript"> tag. + */ + public static SafeHtml fromScript(SafeScript script) { + return create(""); + } + + /** + * Wraps a SafeScript inside a <script type="text/javascript"> tag. + * The tag has a nonce attribute populated from the provided CSP nonce value. + */ + public static SafeHtml fromScriptWithCspNonce(SafeScript script, String cspNonce) { + return create(""); + } + + /** + * Creates a <script type="text/javascript" src="url"><script> where the + * {@code src} attribute points to the given {@code trustedResourceUrl}. + */ + public static SafeHtml fromScriptUrl(TrustedResourceUrl trustedResourceUrl) { + String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString()); + return create(""); + } + + /** + * Creates a <script defer type="text/javascript" src="url"><script> where the + * {@code src} attribute points to the given {@code trustedResourceUrl}. + */ + public static SafeHtml fromScriptUrlDeferred(TrustedResourceUrl trustedResourceUrl) { + String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString()); + return create(""); + } + + /** + * Creates a <script type="text/javascript" src="url"><script> where the + * {@code src} attribute points to the given {@code trustedResourceUrl}. + * The tag has a nonce attribute populated from the provided CSP nonce value. + */ + public static SafeHtml fromScriptUrlWithCspNonce(TrustedResourceUrl trustedResourceUrl, + String cspNonce) { + String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString()); + return create(""); + } + + /** + * Creates a <script defer type="text/javascript" src="url"><script> where the + * {@code src} attribute points to the given {@code trustedResourceUrl}. + * The tag has a nonce attribute populated from the provided CSP nonce value. + */ + public static SafeHtml fromScriptUrlWithCspNonceDeferred(TrustedResourceUrl trustedResourceUrl, + String cspNonce) { + String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString()); + return create(""); + } + + /** + * Wraps a SafeStyleSheet inside a <style type="text/css"> tag. + */ + public static SafeHtml fromStyleSheet(SafeStyleSheet safeStyleSheet) { + Preconditions.checkArgument(!safeStyleSheet.getSafeStyleSheetString().contains("<")); + return create(""); + } + + /** + * Creates a <style type="text/css" src="url"><style> where the + * {@code src} attribute points to the given {@code trustedResourceUrl}. + */ + public static SafeHtml fromStyleUrl(TrustedResourceUrl trustedResourceUrl) { + String escapedUrl = htmlEscapeInternal(trustedResourceUrl.getTrustedResourceUrlString()); + return create(""); + } + + /** + * Serializes a SafeHtml into its opaque protocol message representation. + * + *

Protocol message forms of this type are intended to be opaque. The fields of the returned + * protocol message should be considered encapsulated and are not intended for direct inspection + * or manipulation. Protocol messages can be converted back into a SafeHtml using + * {@link #fromProto(SafeHtmlProto)}. + */ + public static SafeHtmlProto toProto(SafeHtml safeHtml) { + return SafeHtmlProto.newBuilder().setPrivateDoNotAccessOrElseSafeHtmlWrappedValue( + safeHtml.getSafeHtmlString()).build(); + } + + /** + * Converts, by HTML-escaping, an arbitrary string into a contract-compliant {@link SafeHtml}. + */ + public static SafeHtml htmlEscape(String text) { + return create(htmlEscapeInternal(text)); + } + + /** + * Converts an arbitrary string into an HTML comment by HTML-escaping the contents and embedding + * the result between HTML comment markers. + * + *

Escaping is needed because Internet Explorer supports conditional comments and so may render + * HTML markup within comments. + */ + public static SafeHtml comment(String text) { + return create(""); + } + + + /** + * Creates a new SafeHtml which contains, in order, the string representations of the given + * {@code htmls}. + */ + public static SafeHtml concat(SafeHtml... htmls) { + return concat(Arrays.asList(htmls)); + } + + /** + * Creates a new SafeHtml which contains, in order, the string representations of the given + * {@code htmls}. + */ + public static SafeHtml concat(Iterable htmls) { + int concatLength = 0; + for (SafeHtml html : htmls) { + concatLength += html.getSafeHtmlString().length(); + } + + StringBuilder result = new StringBuilder(concatLength); + for (SafeHtml html : htmls) { + result.append(html.getSafeHtmlString()); + } + return create(result.toString()); + } + + // Default visibility for use by SafeHtmlBuilder. + static SafeHtml create(String html) { + return new SafeHtml(html); + } + + private static String htmlEscapeInternal(String text) { + return escapeHtmlInternal(coerceToInterchangeValid(text)); + } + + private SafeHtmls() { } +} + diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeScript.java b/third_party/safe_html_types/com/google/common/html/types/SafeScript.java new file mode 100644 index 00000000000..1abf042c432 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeScript.java @@ -0,0 +1,101 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * 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.common.html.types; + +import javax.annotation.CheckReturnValue; +import javax.annotation.concurrent.Immutable; +import jsinterop.annotations.JsType; + +/** + * A string-like object which represents JavaScript code and that carries the security type + * contract that its value, as a string, will not cause execution of unconstrained attacker + * controlled code (XSS) when evaluated as JavaScript in a browser. + * + * A SafeScript's string representation ({@link #getSafeScriptString()}) can safely be interpolated + * as the content of a script element within HTML. The SafeScript string should not be escaped + * before interpolation. + * + * Note that the SafeScript might contain text that is attacker-controlled but that text should + * have been interpolated with appropriate escaping, sanitization and/or validation into the right + * location in the script, such that it is highly constrained in its effect (for example, it had to + * match a set of whitelisted words). + * + * A SafeScript can be constructed via security-reviewed unchecked conversions. In this case + * producers of SafeScript must ensure themselves that the SafeScript does not contain unsafe + * script. Note in particular that {@code <} is dangerous, even when inside JavaScript strings, + * and so should always be forbidden or JavaScript escaped in user controlled input. For example, + * if {@code </script><script>evil</script>"} were interpolated inside a + * JavaScript string, it would break out of the context of the original script element and + * {@code evil} would execute. Also note that within an HTML script (raw text) element, HTML + * character references, such as {@code &lt;}, are not allowed. See + * http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements. + */ +@CheckReturnValue +@Immutable +@JsType +public final class SafeScript { + + /** The SafeScript wrapping an empty string. */ + public static final SafeScript EMPTY = new SafeScript(""); + + private final String privateDoNotAccessOrElseSafeScriptWrappedValue; + + SafeScript(String script) { + if (script == null) { + throw new NullPointerException(); + } + this.privateDoNotAccessOrElseSafeScriptWrappedValue = script; + } + + @Override + public int hashCode() { + return privateDoNotAccessOrElseSafeScriptWrappedValue.hashCode() ^ 0x6914dfaa; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof SafeScript)) { + return false; + } + SafeScript that = (SafeScript) other; + return this.privateDoNotAccessOrElseSafeScriptWrappedValue.equals( + that.privateDoNotAccessOrElseSafeScriptWrappedValue); + } + + /** + * Returns a debug representation of this value's underlying string, NOT the string representation + * of the SafeScript. + * + *

Having {@code toString()} return a debug representation is intentional. This type has + * a GWT-compiled JavaScript version; JavaScript has no static typing and a distinct method + * method name provides a modicum of type-safety. + * + * @see #getSafeScriptString + */ + @Override + public String toString() { + return "SafeScript{" + privateDoNotAccessOrElseSafeScriptWrappedValue + "}"; + } + + /** + * Returns this value's underlying string. See class documentation for what guarantees exist on + * the returned string. + */ + public String getSafeScriptString() { + return privateDoNotAccessOrElseSafeScriptWrappedValue; + } +} diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeScriptProto.java b/third_party/safe_html_types/com/google/common/html/types/SafeScriptProto.java new file mode 100644 index 00000000000..b51c657fc52 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeScriptProto.java @@ -0,0 +1,604 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: webutil/html/types/html.proto + +package com.google.common.html.types; + +/** + *

+ * Message containing JavaScript code that is safe to use as the content of an
+ * HTML script element.
+ * 
+ * + * Protobuf type {@code webutil.html.types.SafeScriptProto} + */ +public final class SafeScriptProto extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:webutil.html.types.SafeScriptProto) + SafeScriptProtoOrBuilder { + // Use SafeScriptProto.newBuilder() to construct. + private SafeScriptProto(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private SafeScriptProto() { + privateDoNotAccessOrElseSafeScriptWrappedValue_ = ""; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private SafeScriptProto( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 50: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + privateDoNotAccessOrElseSafeScriptWrappedValue_ = bs; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeScriptProto_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeScriptProto_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.common.html.types.SafeScriptProto.class, com.google.common.html.types.SafeScriptProto.Builder.class); + } + + private int bitField0_; + public static final int PRIVATE_DO_NOT_ACCESS_OR_ELSE_SAFE_SCRIPT_WRAPPED_VALUE_FIELD_NUMBER = 6; + private volatile java.lang.Object privateDoNotAccessOrElseSafeScriptWrappedValue_; + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + public boolean hasPrivateDoNotAccessOrElseSafeScriptWrappedValue() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + public java.lang.String getPrivateDoNotAccessOrElseSafeScriptWrappedValue() { + java.lang.Object ref = privateDoNotAccessOrElseSafeScriptWrappedValue_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + privateDoNotAccessOrElseSafeScriptWrappedValue_ = s; + } + return s; + } + } + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + public com.google.protobuf.ByteString + getPrivateDoNotAccessOrElseSafeScriptWrappedValueBytes() { + java.lang.Object ref = privateDoNotAccessOrElseSafeScriptWrappedValue_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + privateDoNotAccessOrElseSafeScriptWrappedValue_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) == 0x00000001)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 6, privateDoNotAccessOrElseSafeScriptWrappedValue_); + } + unknownFields.writeTo(output); + } + + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, privateDoNotAccessOrElseSafeScriptWrappedValue_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.common.html.types.SafeScriptProto)) { + return super.equals(obj); + } + com.google.common.html.types.SafeScriptProto other = (com.google.common.html.types.SafeScriptProto) obj; + + boolean result = true; + result = result && (hasPrivateDoNotAccessOrElseSafeScriptWrappedValue() == other.hasPrivateDoNotAccessOrElseSafeScriptWrappedValue()); + if (hasPrivateDoNotAccessOrElseSafeScriptWrappedValue()) { + result = result && getPrivateDoNotAccessOrElseSafeScriptWrappedValue() + .equals(other.getPrivateDoNotAccessOrElseSafeScriptWrappedValue()); + } + result = result && unknownFields.equals(other.unknownFields); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasPrivateDoNotAccessOrElseSafeScriptWrappedValue()) { + hash = (37 * hash) + PRIVATE_DO_NOT_ACCESS_OR_ELSE_SAFE_SCRIPT_WRAPPED_VALUE_FIELD_NUMBER; + hash = (53 * hash) + getPrivateDoNotAccessOrElseSafeScriptWrappedValue().hashCode(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.common.html.types.SafeScriptProto parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.google.common.html.types.SafeScriptProto parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.google.common.html.types.SafeScriptProto parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.google.common.html.types.SafeScriptProto parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.google.common.html.types.SafeScriptProto parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static com.google.common.html.types.SafeScriptProto parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static com.google.common.html.types.SafeScriptProto parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.google.common.html.types.SafeScriptProto parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static com.google.common.html.types.SafeScriptProto parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static com.google.common.html.types.SafeScriptProto parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static com.google.common.html.types.SafeScriptProto parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static com.google.common.html.types.SafeScriptProto parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(com.google.common.html.types.SafeScriptProto prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + *
+   * Message containing JavaScript code that is safe to use as the content of an
+   * HTML script element.
+   * 
+ * + * Protobuf type {@code webutil.html.types.SafeScriptProto} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:webutil.html.types.SafeScriptProto) + com.google.common.html.types.SafeScriptProtoOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeScriptProto_descriptor; + } + + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeScriptProto_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.common.html.types.SafeScriptProto.class, com.google.common.html.types.SafeScriptProto.Builder.class); + } + + // Construct using com.google.common.html.types.SafeScriptProto.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + public Builder clear() { + super.clear(); + privateDoNotAccessOrElseSafeScriptWrappedValue_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return com.google.common.html.types.Html.internal_static_webutil_html_types_SafeScriptProto_descriptor; + } + + public com.google.common.html.types.SafeScriptProto getDefaultInstanceForType() { + return com.google.common.html.types.SafeScriptProto.getDefaultInstance(); + } + + public com.google.common.html.types.SafeScriptProto build() { + com.google.common.html.types.SafeScriptProto result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public com.google.common.html.types.SafeScriptProto buildPartial() { + com.google.common.html.types.SafeScriptProto result = new com.google.common.html.types.SafeScriptProto(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.privateDoNotAccessOrElseSafeScriptWrappedValue_ = privateDoNotAccessOrElseSafeScriptWrappedValue_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder clone() { + return (Builder) super.clone(); + } + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.setField(field, value); + } + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + Object value) { + return (Builder) super.addRepeatedField(field, value); + } + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.common.html.types.SafeScriptProto) { + return mergeFrom((com.google.common.html.types.SafeScriptProto)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.common.html.types.SafeScriptProto other) { + if (other == com.google.common.html.types.SafeScriptProto.getDefaultInstance()) return this; + if (other.hasPrivateDoNotAccessOrElseSafeScriptWrappedValue()) { + bitField0_ |= 0x00000001; + privateDoNotAccessOrElseSafeScriptWrappedValue_ = other.privateDoNotAccessOrElseSafeScriptWrappedValue_; + onChanged(); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.common.html.types.SafeScriptProto parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (com.google.common.html.types.SafeScriptProto) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.lang.Object privateDoNotAccessOrElseSafeScriptWrappedValue_ = ""; + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + public boolean hasPrivateDoNotAccessOrElseSafeScriptWrappedValue() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + public java.lang.String getPrivateDoNotAccessOrElseSafeScriptWrappedValue() { + java.lang.Object ref = privateDoNotAccessOrElseSafeScriptWrappedValue_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + privateDoNotAccessOrElseSafeScriptWrappedValue_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + public com.google.protobuf.ByteString + getPrivateDoNotAccessOrElseSafeScriptWrappedValueBytes() { + java.lang.Object ref = privateDoNotAccessOrElseSafeScriptWrappedValue_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + privateDoNotAccessOrElseSafeScriptWrappedValue_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + public Builder setPrivateDoNotAccessOrElseSafeScriptWrappedValue( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + privateDoNotAccessOrElseSafeScriptWrappedValue_ = value; + onChanged(); + return this; + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + public Builder clearPrivateDoNotAccessOrElseSafeScriptWrappedValue() { + bitField0_ = (bitField0_ & ~0x00000001); + privateDoNotAccessOrElseSafeScriptWrappedValue_ = getDefaultInstance().getPrivateDoNotAccessOrElseSafeScriptWrappedValue(); + onChanged(); + return this; + } + /** + *
+     * IMPORTANT: Never set or read this field, even from tests, it is private.
+     * See documentation at the top of .proto file for programming language
+     * packages with which to create or read this message.
+     * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + public Builder setPrivateDoNotAccessOrElseSafeScriptWrappedValueBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + privateDoNotAccessOrElseSafeScriptWrappedValue_ = value; + onChanged(); + return this; + } + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:webutil.html.types.SafeScriptProto) + } + + // @@protoc_insertion_point(class_scope:webutil.html.types.SafeScriptProto) + private static final com.google.common.html.types.SafeScriptProto DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new com.google.common.html.types.SafeScriptProto(); + } + + public static com.google.common.html.types.SafeScriptProto getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + @java.lang.Deprecated public static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + public SafeScriptProto parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new SafeScriptProto(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + public com.google.common.html.types.SafeScriptProto getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeScriptProtoOrBuilder.java b/third_party/safe_html_types/com/google/common/html/types/SafeScriptProtoOrBuilder.java new file mode 100644 index 00000000000..0434edce5aa --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeScriptProtoOrBuilder.java @@ -0,0 +1,41 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: webutil/html/types/html.proto + +package com.google.common.html.types; + +public interface SafeScriptProtoOrBuilder extends + // @@protoc_insertion_point(interface_extends:webutil.html.types.SafeScriptProto) + com.google.protobuf.MessageOrBuilder { + + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + boolean hasPrivateDoNotAccessOrElseSafeScriptWrappedValue(); + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + java.lang.String getPrivateDoNotAccessOrElseSafeScriptWrappedValue(); + /** + *
+   * IMPORTANT: Never set or read this field, even from tests, it is private.
+   * See documentation at the top of .proto file for programming language
+   * packages with which to create or read this message.
+   * 
+ * + * optional string private_do_not_access_or_else_safe_script_wrapped_value = 6 [ctype = CORD]; + */ + com.google.protobuf.ByteString + getPrivateDoNotAccessOrElseSafeScriptWrappedValueBytes(); +} diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeScripts.java b/third_party/safe_html_types/com/google/common/html/types/SafeScripts.java new file mode 100644 index 00000000000..a1a22d6dac2 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeScripts.java @@ -0,0 +1,99 @@ +// **** GENERATED CODE, DO NOT MODIFY **** +// This file was generated via preprocessing from input: +// java/com/google/common/html/types/SafeScripts.java.tpl +// *************************************** +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * 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.common.html.types; + +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.GwtIncompatible; +import com.google.common.io.Resources; +import com.google.errorprone.annotations.CompileTimeConstant; +import java.io.IOException; +import java.nio.charset.Charset; +import javax.annotation.CheckReturnValue; + + +/** + * Protocol conversions and factory methods for {@link SafeScript}. + */ +@CheckReturnValue +@GwtCompatible(emulated = true) +public final class SafeScripts { + + private SafeScripts() {} + + /** + * Creates a SafeScript from the given compile-time constant string {@code script}. + */ + public static SafeScript fromConstant(@CompileTimeConstant final String script) { + if (script.length() == 0) { + return SafeScript.EMPTY; + } + return create(script); + } + + /** + * Creates a SafeScript from the given compile-time constant {@code resourceName} using the given + * {@code charset}. + * + *

This performs ZERO VALIDATION of the data. We assume that resources should be safe because + * they are part of the binary, and therefore not attacker controlled. + * + * @param contextClass Class relative to which to load the resource. + */ + @GwtIncompatible("Resources") + public static SafeScript fromResource( + Class contextClass, @CompileTimeConstant final String resourceName, Charset charset) + throws IOException { + return create(Resources.toString(Resources.getResource(contextClass, resourceName), charset)); + } + + /** + * Deserializes a SafeScriptProto into a SafeScript instance. + * + *

Protocol-message forms are intended to be opaque. The fields of the protocol message should + * be considered encapsulated and are not intended for direct inspection or manipulation. Protocol + * message forms of this type should be produced by {@link #toProto(SafeScript)} or its equivalent + * in other implementation languages. + * + *

Important: It is unsafe to invoke this method on a protocol message that has been + * received from an entity outside the application's trust domain. Data coming from the browser + * is outside the application's trust domain. + */ + public static SafeScript fromProto(SafeScriptProto proto) { + return create(proto.getPrivateDoNotAccessOrElseSafeScriptWrappedValue()); + } + + /** + * Serializes a SafeScript into its opaque protocol message representation. + * + *

Protocol message forms of this type are intended to be opaque. The fields of the returned + * protocol message should be considered encapsulated and are not intended for direct inspection + * or manipulation. Protocol messages can be converted back into a SafeScript using + * {@link #fromProto(SafeScriptProto)}. + */ + public static SafeScriptProto toProto(SafeScript script) { + return SafeScriptProto.newBuilder() + .setPrivateDoNotAccessOrElseSafeScriptWrappedValue(script.getSafeScriptString()).build(); + } + + static SafeScript create(String script) { + return new SafeScript(script); + } +} diff --git a/third_party/safe_html_types/com/google/common/html/types/SafeStyle.java b/third_party/safe_html_types/com/google/common/html/types/SafeStyle.java new file mode 100644 index 00000000000..3a3571677e2 --- /dev/null +++ b/third_party/safe_html_types/com/google/common/html/types/SafeStyle.java @@ -0,0 +1,146 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * 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.common.html.types; + +import javax.annotation.CheckReturnValue; +import javax.annotation.concurrent.Immutable; +import jsinterop.annotations.JsType; + +/** + * A string-like object which represents a sequence of CSS declarations + * ({@code propertyName1: propertyvalue1; propertyName2: propertyValue2; ...}) and that carries the + * security type contract that its value, as a string, will not cause untrusted script execution + * (XSS) when evaluated as CSS in a browser. + * + *

A SafeStyle's string representation ({@link #getSafeStyleString()}) can safely be: + *

    + *
  • Interpolated as the content of a quoted HTML style attribute. However, the SafeStyle + * string must be HTML-attribute-escaped before interpolation. + *
  • Interpolated as the content of a {}-wrapped block within a stylesheet. '<' characters in the + * SafeStyle string must be CSS-escaped before interpolation. The SafeStyle string is also + * guaranteed not to be able to introduce new properties or elide existing ones. + *
  • Interpolated as the content of a {}-wrapped block within an HTML