diff --git a/tensorboard/backend/http_util.py b/tensorboard/backend/http_util.py
index cb16f882b8..2ac9bafb3b 100644
--- a/tensorboard/backend/http_util.py
+++ b/tensorboard/backend/http_util.py
@@ -183,13 +183,9 @@ def Respond(request,
_validate_global_whitelist(_CSP_FONT_DOMAINS_WHITELIST)
_validate_global_whitelist(_CSP_SCRIPT_DOMAINS_WHITELIST)
- enable_unsafe_eval = (
- (_CSP_SCRIPT_DOMAINS_WHITELIST or csp_scripts_sha256s)
- and _CSP_SCRIPT_UNSAFE_EVAL
- )
frags = _CSP_SCRIPT_DOMAINS_WHITELIST + [
"'self'" if _CSP_SCRIPT_SELF else '',
- "'unsafe-eval'" if enable_unsafe_eval else '',
+ "'unsafe-eval'" if _CSP_SCRIPT_UNSAFE_EVAL else '',
] + [
"'sha256-{}'".format(sha256) for sha256 in (csp_scripts_sha256s or [])
]
diff --git a/tensorboard/backend/http_util_test.py b/tensorboard/backend/http_util_test.py
index 6e38b18371..83c2df4bdf 100644
--- a/tensorboard/backend/http_util_test.py
+++ b/tensorboard/backend/http_util_test.py
@@ -201,6 +201,19 @@ def testCsp(self):
@mock.patch.object(http_util, '_CSP_SCRIPT_SELF', False)
def testCsp_noHash(self):
+ q = wrappers.Request(wtest.EnvironBuilder().get_environ())
+ r = http_util.Respond(q, 'hello', 'text/html', csp_scripts_sha256s=None)
+ expected_csp = (
+ "default-src 'self';font-src 'self';frame-ancestors *;"
+ "frame-src 'self';img-src 'self' data: blob:;object-src 'none';"
+ "style-src 'self' https://www.gstatic.com data: 'unsafe-inline';"
+ "script-src 'unsafe-eval'"
+ )
+ self.assertEqual(r.headers.get('Content-Security-Policy'), expected_csp)
+
+ @mock.patch.object(http_util, '_CSP_SCRIPT_SELF', False)
+ @mock.patch.object(http_util, '_CSP_SCRIPT_UNSAFE_EVAL', False)
+ def testCsp_noHash_noUnsafeEval(self):
q = wrappers.Request(wtest.EnvironBuilder().get_environ())
r = http_util.Respond(q, 'hello', 'text/html', csp_scripts_sha256s=None)
expected_csp = (
@@ -212,6 +225,7 @@ def testCsp_noHash(self):
self.assertEqual(r.headers.get('Content-Security-Policy'), expected_csp)
@mock.patch.object(http_util, '_CSP_SCRIPT_SELF', True)
+ @mock.patch.object(http_util, '_CSP_SCRIPT_UNSAFE_EVAL', False)
def testCsp_onlySelf(self):
q = wrappers.Request(wtest.EnvironBuilder().get_environ())
r = http_util.Respond(q, 'hello', 'text/html', csp_scripts_sha256s=None)
diff --git a/tensorboard/defs/vulcanize.bzl b/tensorboard/defs/vulcanize.bzl
index 4cd327a82b..6c3566ded8 100644
--- a/tensorboard/defs/vulcanize.bzl
+++ b/tensorboard/defs/vulcanize.bzl
@@ -22,10 +22,9 @@ def _tensorboard_html_binary(ctx):
The rule outputs a HTML that resolves all HTML import statements into one
document. When compile option is on, it compiles all script sources with
- JSCompiler and combines script elements. The rule also outputs
- [name].html.scripts_sha256 file that contains sha256 hash, in base64, of all
- script elements (sources inside element and content of JavaScript src they
- point at). The hashes are delimited by newline.
+ JSCompiler (unless DOM is annotated to opt-out of compilation). When js_path
+ is specified, the rule combines content of all script elements to a JavaScript
+ file.
"""
deps = unfurl(ctx.attr.deps, provider="webfiles")
@@ -55,7 +54,7 @@ def _tensorboard_html_binary(ctx):
ignore_regexs_file_set,
]).to_list(),
tools=jslibs,
- outputs=[ctx.outputs.html, ctx.outputs.js, ctx.outputs.shasum],
+ outputs=[ctx.outputs.html, ctx.outputs.js],
executable=ctx.executable._Vulcanize,
arguments=([ctx.attr.compilation_level,
"true" if ctx.attr.compile else "false",
@@ -65,7 +64,6 @@ def _tensorboard_html_binary(ctx):
ctx.attr.js_path,
ctx.outputs.html.path,
ctx.outputs.js.path,
- ctx.outputs.shasum.path,
ignore_regexs_file_path] +
[f.path for f in jslibs.to_list()] +
[f.path for f in manifests.to_list()]),
@@ -155,5 +153,4 @@ tensorboard_html_binary = rule(
outputs={
"html": "%{name}.html",
"js": "%{name}.js",
- "shasum": "%{name}.html.scripts_sha256",
})
diff --git a/tensorboard/java/org/tensorflow/tensorboard/vulcanize/Vulcanize.java b/tensorboard/java/org/tensorflow/tensorboard/vulcanize/Vulcanize.java
index aeba9bfb45..c495e174ce 100644
--- a/tensorboard/java/org/tensorflow/tensorboard/vulcanize/Vulcanize.java
+++ b/tensorboard/java/org/tensorflow/tensorboard/vulcanize/Vulcanize.java
@@ -30,8 +30,6 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
-import com.google.common.hash.Hashing;
-import com.google.common.io.BaseEncoding;
import com.google.javascript.jscomp.BasicErrorManager;
import com.google.javascript.jscomp.CheckLevel;
import com.google.javascript.jscomp.CompilationLevel;
@@ -138,7 +136,6 @@ public static void main(String[] args)
Webpath jsPath = Webpath.get(args[argIdx++]);
Path output = Paths.get(args[argIdx++]);
Path jsOutput = Paths.get(args[argIdx++]);
- Path shasumOutput = Paths.get(args[argIdx++]);
if (!args[argIdx++].equals(NO_NOINLINE_FILE_PROVIDED)) {
String ignoreFile = new String(Files.readAllBytes(Paths.get(args[argIdx])), UTF_8);
Arrays.asList(ignoreFile.split("\n"))
@@ -169,7 +166,6 @@ public static void main(String[] args)
transform(document);
if (wantsCompile) {
compile();
- combineScriptElements(document);
} else if (firstScript != null) {
firstScript.before(
new Element(Tag.valueOf("script"), firstScript.baseUri())
@@ -189,7 +185,6 @@ public static void main(String[] args)
createFile(
jsOutput, shouldExtractJs ? extractAndTransformJavaScript(document, jsPath) : "");
// Write an empty file for shasum when all scripts are extracted out.
- createFile(shasumOutput, shouldExtractJs ? "" : getScriptsShasums(document));
createFile(output, Html5Printer.stringify(document));
}
@@ -732,108 +727,6 @@ private static ImmutableMultimap initDiagnosticGroups()
return ImmutableMultimap.copyOf(builder);
}
- /**
- * Combine content of script tags into a group. To guarantee the correctness, it only groups
- * content of `src`-less scripts between `src`-full scripts. The last combination gets inserted at
- * the end of the document.
- * e.g., {@code
- *
- *
- *
- *
- *
- *
- *
- *
- * }
- * gets compiled as {@code
- *
- *
- *
- *
- *
- *
- * }
- *
- * @deprecated Script combination is deprecated in favor of script extraction.
- */
- @Deprecated
- private static void combineScriptElements(Document document) {
- Elements scripts = document.getElementsByTag("script");
- StringBuilder sourcesBuilder = new StringBuilder();
-
- for (Element script : scripts) {
- if (!script.attr("src").isEmpty()) {
- if (sourcesBuilder.length() == 0) {
- continue;
- }
-
- Element scriptElement = new Element(Tag.valueOf("script"), "")
- .appendChild(new DataNode(sourcesBuilder.toString(), ""));
- script.before(scriptElement);
- sourcesBuilder = new StringBuilder();
- } else {
- sourcesBuilder.append(script.html()).append("\n");
- script.remove();
- }
- }
-
- // jsoup parser creates body elements for each HTML files. Since document.body() returns the
- // first instance and we want to insert the script element at the end of the document, we
- // manually grab the last one.
- Element lastBody = Iterables.getLast(document.getElementsByTag("body"));
-
- Element scriptElement = new Element(Tag.valueOf("script"), "")
- .appendChild(new DataNode(sourcesBuilder.toString(), ""));
- lastBody.appendChild(scriptElement);
- }
-
- /** @deprecated Shasum is deprecated in favor of script extraction. */
- @Deprecated
- private static ArrayList computeScriptShasum(Document document)
- throws FileNotFoundException, IOException {
- ArrayList hashes = new ArrayList<>();
- for (Element script : document.getElementsByTag("script")) {
- String src = script.attr("src");
- String sourceContent;
- if (src.isEmpty()) {
- sourceContent = script.html();
- } else {
- // script element that remains are the ones with src that is absolute or annotated with
- // `jscomp-ignore`. They must resolve from the root because those srcs are rootified.
- Webpath webpathSrc = Webpath.get(src);
- Webpath webpath = Webpath.get("/").resolve(Webpath.get(src)).normalize();
- if (isAbsolutePath(webpathSrc)) {
- System.err.println(
- "WARNING: "
- + webpathSrc
- + " refers to a remote resource. Please add it to CSP manually. Detail: "
- + script.outerHtml());
- continue;
- } else if (!webfiles.containsKey(webpath)) {
- throw new FileNotFoundException(
- "Expected webfiles for " + webpath + " to exist. Related: " + script.outerHtml());
- }
- sourceContent = new String(Files.readAllBytes(webfiles.get(webpath)), UTF_8);
- }
- String hash = BaseEncoding.base64().encode(
- Hashing.sha256().hashString(sourceContent, UTF_8).asBytes());
- hashes.add(hash);
- }
- return hashes;
- }
-
- /**
- * Writes sha256 of script tags in base64 in the document.
- *
- * @deprecated Shasum is deprecated in favor of script extraction.
- */
- @Deprecated
- private static String getScriptsShasums(Document document)
- throws FileNotFoundException, IOException {
- return Joiner.on("\n").join(computeScriptShasum(document));
- }
-
private static String extractScriptContent(Document document)
throws FileNotFoundException, IOException, IllegalArgumentException {
Elements scripts = document.getElementsByTag("script");
diff --git a/tensorboard/pip_package/setup.py b/tensorboard/pip_package/setup.py
index f295bb5864..52c4c911f7 100644
--- a/tensorboard/pip_package/setup.py
+++ b/tensorboard/pip_package/setup.py
@@ -76,7 +76,7 @@ def get_readme():
'tensorboard.plugins.projector': [
'tf_projector_plugin/index.js',
'tf_projector_plugin/projector_binary.html',
- 'tf_projector_plugin/projector_binary.html.scripts_sha256',
+ 'tf_projector_plugin/projector_binary.js',
],
},
# Disallow python 3.0 and 3.1 which lack a 'futures' module (see above).
diff --git a/tensorboard/plugins/core/core_plugin.py b/tensorboard/plugins/core/core_plugin.py
index 6e290f1b53..d09c2e5e23 100644
--- a/tensorboard/plugins/core/core_plugin.py
+++ b/tensorboard/plugins/core/core_plugin.py
@@ -42,8 +42,6 @@
# for more details.
DEFAULT_PORT = 6006
-SHASUM_DIR = '_shasums'
-SHASUM_FILE_SUFFIX = '.scripts_sha256'
class CorePlugin(base_plugin.TBPlugin):
"""Core plugin for TensorBoard.
@@ -102,27 +100,9 @@ def get_resource_apps(self):
with self._assets_zip_provider() as fp:
with zipfile.ZipFile(fp) as zip_:
for path in zip_.namelist():
- # Do not serve the shasum data as static files.
- if path.startswith(SHASUM_DIR):
- continue
-
gzipped_asset_bytes = _gzip(zip_.read(path))
-
- if os.path.splitext(path)[1] == '.html':
- checksum_path = os.path.join(SHASUM_DIR, path + SHASUM_FILE_SUFFIX)
- # TODO(stephanwlee): devise a way to omit font-roboto/roboto.html from
- # the assets zip file.
- if checksum_path in zip_.namelist():
- lines = zip_.read(checksum_path).splitlines(False);
- shasums = [hash.decode('utf8') for hash in lines]
- else:
- shasums = None
-
- wsgi_app = functools.partial(
- self._serve_html, shasums, gzipped_asset_bytes)
- else:
- wsgi_app = functools.partial(
- self._serve_asset, path, gzipped_asset_bytes)
+ wsgi_app = functools.partial(
+ self._serve_asset, path, gzipped_asset_bytes)
apps['/' + path] = wsgi_app
apps['/'] = apps['/index.html']
return apps
@@ -142,17 +122,6 @@ def _serve_asset(self, path, gzipped_asset_bytes, request):
return http_util.Respond(
request, gzipped_asset_bytes, mimetype, content_encoding='gzip')
- @wrappers.Request.application
- def _serve_html(self, shasums, gzipped_asset_bytes, request):
- """Serves a pre-gzipped static HTML with script shasums."""
- return http_util.Respond(
- request,
- gzipped_asset_bytes,
- 'text/html',
- content_encoding='gzip',
- csp_scripts_sha256s=shasums,
- )
-
@wrappers.Request.application
def _serve_environment(self, request):
"""Serve a JSON object containing some base properties used by the frontend.
diff --git a/tensorboard/plugins/projector/projector_plugin.py b/tensorboard/plugins/projector/projector_plugin.py
index 68fab242ee..11c36a4b64 100644
--- a/tensorboard/plugins/projector/projector_plugin.py
+++ b/tensorboard/plugins/projector/projector_plugin.py
@@ -269,8 +269,12 @@ def get_plugin_apps(self):
os.path.join('tf_projector_plugin', 'index.js')),
'/projector_binary.html':
functools.partial(
- self._serve_html,
+ self._serve_file,
os.path.join('tf_projector_plugin', 'projector_binary.html')),
+ '/projector_binary.js':
+ functools.partial(
+ self._serve_file,
+ os.path.join('tf_projector_plugin', 'projector_binary.js')),
}
return self._handlers
@@ -489,24 +493,6 @@ def _serve_file(self, file_path, request):
mimetype = mimetypes.guess_type(file_path)[0]
return Respond(request, read_file.read(), content_type=mimetype)
- @wrappers.Request.application
- def _serve_html(self, file_path, request):
- """Returns a resource file."""
- res_path = os.path.join(os.path.dirname(__file__), file_path)
- sha_path = '%s.scripts_sha256' % res_path
- with open(sha_path, 'rb') as sha_file:
- lines = sha_file.read().splitlines(False);
- shasums = [hash.decode('utf8') for hash in lines]
-
- with open(res_path, 'rb') as read_file:
- mimetype = mimetypes.guess_type(file_path)[0]
- return Respond(
- request,
- read_file.read(),
- content_type='text/html',
- csp_scripts_sha256s=shasums,
- )
-
@wrappers.Request.application
def _serve_runs(self, request):
"""Returns a list of runs that have embeddings."""
diff --git a/tensorboard/plugins/projector/tf_projector_plugin/BUILD b/tensorboard/plugins/projector/tf_projector_plugin/BUILD
index a523416f98..73b31afb9f 100644
--- a/tensorboard/plugins/projector/tf_projector_plugin/BUILD
+++ b/tensorboard/plugins/projector/tf_projector_plugin/BUILD
@@ -10,7 +10,7 @@ tf_web_library(
srcs = [
# Keep this in sync with pip_package/setup.py
":projector_binary.html",
- ":projector_binary.html.scripts_sha256",
+ ":projector_binary.js",
"index.js",
],
path = "/tf-projector",
@@ -21,6 +21,7 @@ tensorboard_html_binary(
compile = True,
input_path = "/tf-projector/tf-projector-plugin.html",
output_path = "/tf-projector/projector_binary.html",
+ js_path = "/projector_binary.js",
deps = [
":tf_projector_plugin",
],