Compare commits

..
Author SHA1 Message Date
Lai JiangandGitHub 25ee92b5d8 Re-add hello.xml file (#147)
* Re-add hello.xml file

Apparently it was lost during the great refactoring.

* Remove hello.xml from test resources
2019-07-02 17:21:40 -04:00
gbrodmanandGitHub cf507dad6d Move test resource files into src/test/resources (#143)
* Move test resource files into src/test/resources

* fix a test

* Remove references to javatests/ in Java files

* fix import order

* fix semantic merge conflict
2019-07-02 16:54:49 -04:00
gbrodmanandGitHub 32d5940be3 Remove old Bazel files (#151) 2019-07-02 16:24:01 -04:00
Shicong HuangandGitHub 82fa3d7349 Change button color to blue style (#150) 2019-07-02 15:29:17 -04:00
Ben McIlwainandGitHub 07239710ef Throw a more useful error message on attempted domain restore reports (#145)
* Throw a more useful error message on attempted domain restore reports

Per DomainRestoreRequestFlow's Javadoc, we automatically approve and instantly
enact all domain restore requests, thus we don't use or support restore
reports. This improves the registrar-visible error message to help make this
more clear.
2019-07-02 14:11:37 -04:00
gbrodmanandGitHub 0e8724a48f Require the license in Gradle files (#149) 2019-07-02 11:47:35 -04:00
gbrodmanandGitHub 8332664af9 Move golden test files to src/test/resources (#146) 2019-07-02 11:34:41 -04:00
gbrodmanandGitHub 39abee6279 Update checkstyle.xml with many presubmit checks (#130)
* Update checkstyle.xml with many presubmit checks

* Remove a comment
2019-07-02 10:35:32 -04:00
Shicong HuangandGitHub 6daf72a54e Replace deprecated GoogleCredential with new auth lib (#129)
Replace deprecated GoogleCredential with new lib

This PR also introduced a CredentialsBundle class to carry
HttpTransport and JsonFactory object which are needed by
most of the GCP library to instantiate client.
2019-07-02 10:29:51 -04:00
1106 changed files with 1197 additions and 1556 deletions
+14
View File
@@ -1,3 +1,17 @@
// Copyright 2019 The Nomulus 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.
def environments = ['production', 'sandbox', 'alpha', 'crash']
def projects = ['production': 'domain-registry',
+14
View File
@@ -1,3 +1,17 @@
// Copyright 2019 The Nomulus 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.
buildscript {
if (project.disableDependencyLocking.toBoolean() == false) {
// Lock buildscript dependencies.
+14
View File
@@ -1,3 +1,17 @@
// Copyright 2019 The Nomulus 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.
buildscript {
if (rootProject.disableDependencyLocking.toBoolean() == false) {
// Lock buildscript dependencies.
+47
View File
@@ -25,6 +25,53 @@ by Joshua Bloch in his book Effective Java -->
<property name="message" value='TODO is preferred to FIXME. e.g. "TODO(johndoe): Refactor when v2 is released."' />
</module>
<!-- Checks that String.toUpper/LowerCase() is never used without locale. -->
<module name="RegexpSingleline">
<property name="format" value="\.to(Upper|Lower)Case\(\)"/>
<property name="message" value="String.toUpper/LowerCase() can have unexpected results depending on locale. Either set the locale explicitly - e.g., toUpperCase(Locale.ENGLISH) - or use Ascii.toUpper/LowerCase(...) instead." />
</module>
<!-- Checks that DateTime.now(...) is always passed a DateTimeZone parameter. -->
<module name="RegexpSingleline">
<property name="format" value="DateTime\.now\(\)"/>
<property name="message" value="DateTime.now() must be called with a DateTimeZone parameter, e.g. DateTime.now(UTC)" />
</module>
<!-- Checks that Javadoc does not include a malformed @see tag. -->
<module name="RegexpSingleline">
<property name="format" value='@see\s\"http(|s)://'/>
<property name="message" value='Your Javadocs appear to use invalid &lt;a&gt; tag syntax in @see tags. Please use the correct syntax: @see &lt;a href="http(s)://your_url"&gt;url_description&lt;/a&gt;'/>
</module>
<!-- Checks that our Ofy wrapper is used instead of the "real" ofy(). -->
<module name="RegexpSingleline">
<property name="format" value="com\.googlecode\.objectify\.ObjectifyService\.ofy"/>
<property name="message" value="Use google.registry.model.ofy.ObjectifyService.ofy(). Do not use com.googlecode.objectify.v4.ObjectifyService.ofy()."/>
</module>
<!-- Checks that java.util.Optional is used instead of Guava's Optional. -->
<module name="RegexpSingleline">
<property name="format" value="com\.google\.common\.base\.Optional"/>
<property name="message" value="Use java.util.Optional instead of Guava's Optional."/>
</module>
<!-- Checks that our backport JUnit exception assertion methods are used instead of the ones slated for release in JUnit 4.13. -->
<module name="RegexpSingleline">
<property name="format" value="org\.junit\.Assert\.(assert|expect)Throws"/>
<property name="message" value="Use the exception assertion methods in google.registry.testing.JUnitBackports instead of those in JUnit."/>
</module>
<!-- Checks that the deprecated ExpectedException is not used. -->
<module name="RegexpSingleline">
<property name="format" value="org\.junit\.rules\.ExpectedException"/>
<property name="message" value="Use assertThrows and expectThrows from JUnitBackports instead of the deprecated methods on ExpectedException."/>
</module>
<!-- Checks that the deprecated MockitoJUnitRunner is not used. -->
<module name="RegexpSingleline">
<property name="format" value="MockitoJUnitRunner"/>
<property name="message" value="MockitoJUnitRunner is deprecated. Use @RunWith(JUnit4.class) and MockitoRule instead."/>
</module>
<!-- All Java AST specific tests live under TreeWalker module. -->
<module name="TreeWalker">
+2
View File
@@ -9,4 +9,6 @@
<suppress files="[/\\].*[/\\]generated.*[/\\]" checks="."/>
<!-- Ignore Javadoc checks in test files -->
<suppress files="[/\\].*[/\\]src/test/java/.*[/\\]" checks="JavadocType"/>
<!-- ofy() regex check doesn't apply to these files -->
<suppress files="AugmentedDeleter.java|AugmentedSaver.java|Ofy.java" checks="RegexpSingleline"/>
</suppressions>
+1 -1
View File
@@ -76,7 +76,7 @@ PRESUBMITS = {
# License check
PresubmitCheck(
r".*Copyright 20\d{2} The Nomulus Authors\. All Rights Reserved\.",
("java", "js", "soy", "sql", "py", "sh"), {
("java", "js", "soy", "sql", "py", "sh", "gradle"), {
".git", "/build/", "/generated/", "node_modules/",
"JUnitBackports.java"
}, REQUIRED):
+14
View File
@@ -1,3 +1,17 @@
// Copyright 2019 The Nomulus 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.
plugins {
id 'java-library'
}
@@ -14,13 +14,13 @@
package google.registry.beam.invoicing;
import com.google.auth.oauth2.GoogleCredentials;
import google.registry.beam.invoicing.BillingEvent.InvoiceGroupingKey;
import google.registry.beam.invoicing.BillingEvent.InvoiceGroupingKey.InvoiceGroupingKeyCoder;
import google.registry.config.CredentialModule.LocalCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.reporting.billing.BillingModule;
import google.registry.reporting.billing.GenerateInvoicesAction;
import google.registry.tools.AuthModule.LocalOAuth2Credentials;
import google.registry.util.GoogleCredentialsBundle;
import java.io.Serializable;
import javax.inject.Inject;
import org.apache.beam.runners.dataflow.DataflowRunner;
@@ -81,8 +81,8 @@ public class InvoicingPipeline implements Serializable {
@Config("invoiceFilePrefix")
String invoiceFilePrefix;
@Inject @LocalOAuth2Credentials
GoogleCredentials credentials;
@Inject @LocalCredential
GoogleCredentialsBundle credentialsBundle;
@Inject
InvoicingPipeline() {}
@@ -105,7 +105,7 @@ public class InvoicingPipeline implements Serializable {
public void deploy() {
// We can't store options as a member variable due to serialization concerns.
InvoicingPipelineOptions options = PipelineOptionsFactory.as(InvoicingPipelineOptions.class);
options.setGcpCredential(credentials);
options.setGcpCredential(credentialsBundle.getGoogleCredentials());
options.setProject(projectId);
options.setRunner(DataflowRunner.class);
// This causes p.run() to stage the pipeline as a template on GCS, as opposed to running it.
@@ -14,7 +14,6 @@
package google.registry.bigquery;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.bigquery.Bigquery;
import com.google.api.services.bigquery.model.TableFieldSchema;
import com.google.common.collect.ImmutableList;
@@ -23,24 +22,29 @@ import dagger.Provides;
import dagger.multibindings.Multibinds;
import google.registry.config.CredentialModule.DefaultCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.GoogleCredentialsBundle;
import java.util.Map;
/** Dagger module for Google {@link Bigquery} connection objects. */
@Module
public abstract class BigqueryModule {
/** Provides a map of BigQuery table names to field names. */
@Multibinds
abstract Map<String, ImmutableList<TableFieldSchema>> bigquerySchemas();
// No subclasses.
private BigqueryModule() {}
@Provides
static Bigquery provideBigquery(
@DefaultCredential GoogleCredential credential, @Config("projectId") String projectId) {
return new Bigquery.Builder(credential.getTransport(), credential.getJsonFactory(), credential)
@DefaultCredential GoogleCredentialsBundle credentialsBundle,
@Config("projectId") String projectId) {
return new Bigquery.Builder(
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId)
.build();
}
// No subclasses.
private BigqueryModule() {}
/** Provides a map of BigQuery table names to field names. */
@Multibinds
abstract Map<String, ImmutableList<TableFieldSchema>> bigquerySchemas();
}
@@ -1,60 +0,0 @@
# Copyright 2017 The Nomulus 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.
"""Common routines for Nomulus build rules."""
ZIPPER = "@bazel_tools//tools/zip:zipper"
def long_path(ctx, file_):
"""Constructs canonical runfile path relative to TEST_SRCDIR.
Args:
ctx: A Skylark rule context.
file_: A File object that should appear in the runfiles for the test.
Returns:
A string path relative to TEST_SRCDIR suitable for use in tests and
testing infrastructure.
"""
if file_.short_path.startswith("../"):
return file_.short_path[3:]
if file_.owner and file_.owner.workspace_root:
return file_.owner.workspace_root + "/" + file_.short_path
return ctx.workspace_name + "/" + file_.short_path
def collect_runfiles(targets):
"""Aggregates runfiles from targets.
Args:
targets: A list of Bazel targets.
Returns:
A list of Bazel files.
"""
data = depset()
for target in targets:
if hasattr(target, "runfiles"):
data += target.runfiles.files
continue
if hasattr(target, "data_runfiles"):
data += target.data_runfiles.files
if hasattr(target, "default_runfiles"):
data += target.default_runfiles.files
return data
def _get_runfiles(target, attribute):
runfiles = getattr(target, attribute, None)
if runfiles:
return runfiles.files
return []
@@ -1,53 +0,0 @@
# Copyright 2017 The Nomulus 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.
"""Build macro for creating App Engine EAR archives for Nomulus."""
load("//java/google/registry/builddefs:defs.bzl", "ZIPPER")
def registry_ear_file(name, out, configs, wars, **kwargs):
"""Creates an EAR archive by combining WAR archives."""
cmd = [
"set -e",
"repo=$$(pwd)",
"zipper=$$repo/$(location %s)" % ZIPPER,
"tmp=$$(mktemp -d $${TMPDIR:-/tmp}/registry_ear_file.XXXXXXXXXX)",
"cd $${tmp}",
]
for target, dest in configs.items():
cmd += [
"mkdir -p $${tmp}/$$(dirname %s)" % dest,
"ln -s $${repo}/$(location %s) $${tmp}/%s" % (target, dest),
]
for target, dest in wars.items():
cmd += [
"mkdir " + dest,
"cd " + dest,
"$${zipper} x $${repo}/$(location %s)" % target,
"cd ..",
]
cmd += [
"$${zipper} cC $${repo}/$@ $$(find . | sed 1d | cut -c 3- | LC_ALL=C sort)",
"cd $${repo}",
"rm -rf $${tmp}",
]
native.genrule(
name = name,
srcs = configs.keys() + wars.keys(),
outs = [out],
cmd = "\n".join(cmd),
tools = [ZIPPER],
message = "Generating EAR archive",
**kwargs
)
@@ -1,256 +0,0 @@
# Copyright 2017 The Nomulus 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.
"""Zip file creator that allows arbitrary path renaming.
This rule takes two main inputs: a bunch of filesets and a dictionary of
hard-coded source to dest mappings. It then applies those mappings to the input
file paths, to create a zip file with the same name as the rule.
The following preconditions must be met:
- Sources and destinations can't begin or end with slash.
- Every file must be matched by a mapping.
- Every mapping must match something.
The source can either be an exact match or a prefix.
- If a match is exact, the destination replaces the entire path. If the
destination path is empty, then the path remains the same.
- If the match is a prefix, then the destination replaces the source prefix in
the path. If the destination is empty, then the source prefix is removed.
- If source is an empty string, it matches everything. In this case,
destination becomes the path prefix.
Prefixes are matched with component granularity, not characters. Mappings with
more components take precedence. Mappings with equal components are sorted
asciibetically.
Mappings apply to the "long path" of a file, i.e. relative to TEST_SRCDIR,
e.g. workspace_name/pkg/file. Long paths do not take into consideration
bazel-foo/ output directories.
The deps attribute allows zip_file() rules to depend on other zip_file() rules.
In such cases, the contents of directly dependent zip files are unzipped and
then re-zipped. Mappings specified by the current rule do not apply to the
files extracted from dependent zips. However those files can be overridden.
The simplest example of this rule, which simply zips up short paths, is as
follows:
# //my/package/BUILD
zip_file(
name = "doodle",
srcs = ["hello.txt"],
mappings = {"": ""},
)
The rule above would create a zip file name //my/package/doodle.zip which would
contain a single file named "my/package/hello.txt".
If we wanted to strip the package path, we could do the following:
# //my/package/BUILD
zip_file(
name = "doodle",
srcs = ["hello.txt"],
mappings = {"my/package": ""},
)
In this case, doodle.zip would contain a single file: "hello.txt".
If we wanted to rename hello.txt, we could do the following:
# //my/package/BUILD
zip_file(
name = "doodle",
srcs = ["hello.txt"],
mappings = {"my/package/hello.txt": "my/package/world.txt"},
)
A zip file can be assembled across many rules. For example:
# //webapp/html/BUILD
zip_file(
name = "assets",
srcs = glob(["*.html"]),
mappings = {"webapp/html": ""},
)
# //webapp/js/BUILD
zip_file(
name = "assets",
srcs = glob(["*.js"]),
mappings = {"webapp/js": "assets/js"},
)
# //webapp/BUILD
zip_file(
name = "war",
deps = [
"//webapp/html:assets",
"//webapp/js:assets",
],
mappings = {"webapp/html": ""},
)
You can exclude files with the "exclude" attribute:
# //webapp/BUILD
zip_file(
name = "war_without_tears",
deps = ["war"],
exclude = ["assets/js/tears.js"],
)
Note that "exclude" excludes based on the mapped path relative to the root of
the zipfile. If the file doesn't exist, you'll get an error.
"""
load(
"//java/google/registry/builddefs:defs.bzl",
"ZIPPER",
"collect_runfiles",
"long_path",
)
def _zip_file(ctx):
"""Implementation of zip_file() rule."""
for s, d in ctx.attr.mappings.items():
if (s.startswith("/") or s.endswith("/") or
d.startswith("/") or d.endswith("/")):
fail("mappings should not begin or end with slash")
srcs = depset()
srcs += ctx.files.srcs
srcs += ctx.files.data
srcs += collect_runfiles(ctx.attr.data)
mapped = _map_sources(ctx, srcs, ctx.attr.mappings)
cmd = [
"#!/bin/sh",
"set -e",
'repo="$(pwd)"',
'zipper="${repo}/%s"' % ctx.file._zipper.path,
'archive="${repo}/%s"' % ctx.outputs.out.path,
'tmp="$(mktemp -d "${TMPDIR:-/tmp}/zip_file.XXXXXXXXXX")"',
'cd "${tmp}"',
]
cmd += [
'"${zipper}" x "${repo}/%s"' % dep.zip_file.path
for dep in ctx.attr.deps
]
cmd += ["rm %s" % filename for filename in ctx.attr.exclude]
cmd += [
'mkdir -p "${tmp}/%s"' % zip_path
for zip_path in depset(
[
zip_path[:zip_path.rindex("/")]
for _, zip_path in mapped
if "/" in zip_path
],
).to_list()
]
cmd += [
'ln -sf "${repo}/%s" "${tmp}/%s"' % (path, zip_path)
for path, zip_path in mapped
]
cmd += [
("find . | sed 1d | cut -c 3- | LC_ALL=C sort" +
' | xargs "${zipper}" cC "${archive}"'),
'cd "${repo}"',
'rm -rf "${tmp}"',
]
if hasattr(ctx, "bin_dir"):
script = ctx.new_file(ctx.bin_dir, "%s.sh" % ctx.label.name)
else:
# TODO(kchodorow): remove this once Bazel 4.0+ is required.
script = ctx.new_file(ctx.configuration.bin_dir, "%s.sh" % ctx.label.name)
ctx.actions.write(output = script, content = "\n".join(cmd), is_executable = True)
inputs = [ctx.file._zipper]
inputs += [dep.zip_file for dep in ctx.attr.deps]
inputs += srcs.to_list()
ctx.actions.run(
inputs = inputs,
outputs = [ctx.outputs.out],
executable = script,
mnemonic = "zip",
progress_message = "Creating zip with %d inputs %s" % (
len(inputs),
ctx.label,
),
)
return struct(files = depset([ctx.outputs.out]), zip_file = ctx.outputs.out)
def _map_sources(ctx, srcs, mappings):
"""Calculates paths in zip file for srcs."""
# order mappings with more path components first
mappings = sorted([
(-len(source.split("/")), source, dest)
for source, dest in mappings.items()
])
# get rid of the integer part of tuple used for sorting
mappings = [(source, dest) for _, source, dest in mappings]
mappings_indexes = range(len(mappings))
used = {i: False for i in mappings_indexes}
mapped = []
for file_ in srcs:
run_path = long_path(ctx, file_)
zip_path = None
for i in mappings_indexes:
source = mappings[i][0]
dest = mappings[i][1]
if not source:
if dest:
zip_path = dest + "/" + run_path
else:
zip_path = run_path
elif source == run_path:
if dest:
zip_path = dest
else:
zip_path = run_path
elif run_path.startswith(source + "/"):
if dest:
zip_path = dest + run_path[len(source):]
else:
zip_path = run_path[len(source) + 1:]
else:
continue
used[i] = True
break
if not zip_path:
fail("no mapping matched: " + run_path)
mapped += [(file_.path, zip_path)]
for i in mappings_indexes:
if not used[i]:
fail('superfluous mapping: "%s" -> "%s"' % mappings[i])
return mapped
zip_file = rule(
implementation = _zip_file,
output_to_genfiles = True,
attrs = {
"out": attr.output(mandatory = True),
"srcs": attr.label_list(allow_files = True),
"data": attr.label_list(allow_files = True),
"deps": attr.label_list(providers = ["zip_file"]),
"exclude": attr.string_list(),
"mappings": attr.string_dict(),
"_zipper": attr.label(default = Label(ZIPPER), allow_single_file = True),
},
)
@@ -16,32 +16,28 @@ package google.registry.config;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.util.Utils;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.common.collect.ImmutableList;
import dagger.Module;
import dagger.Provides;
import google.registry.config.RegistryConfig.Config;
import google.registry.keyring.api.KeyModule.Key;
import google.registry.util.GoogleCredentialsBundle;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.GeneralSecurityException;
import javax.inject.Qualifier;
import javax.inject.Singleton;
/**
* Dagger module that provides all {@link GoogleCredential GoogleCredentials} used in the
* application.
*/
/** Dagger module that provides all {@link GoogleCredentials} used in the application. */
@Module
public abstract class CredentialModule {
/**
* Provides the default {@link GoogleCredential} from the Google Cloud runtime.
* Provides the default {@link GoogleCredentialsBundle} from the Google Cloud runtime.
*
* <p>The credential returned depends on the runtime environment:
*
@@ -58,22 +54,22 @@ public abstract class CredentialModule {
@DefaultCredential
@Provides
@Singleton
public static GoogleCredential provideDefaultCredential(
public static GoogleCredentialsBundle provideDefaultCredential(
@Config("defaultCredentialOauthScopes") ImmutableList<String> requiredScopes) {
GoogleCredential credential;
GoogleCredentials credential;
try {
credential = GoogleCredential.getApplicationDefault();
credential = GoogleCredentials.getApplicationDefault();
} catch (IOException e) {
throw new RuntimeException(e);
}
if (credential.createScopedRequired()) {
return credential.createScoped(requiredScopes);
credential = credential.createScoped(requiredScopes);
}
return credential;
return GoogleCredentialsBundle.create(credential);
}
/**
* Provides a {@link GoogleCredential} from the service account's JSON key file.
* Provides a {@link GoogleCredentialsBundle} from the service account's JSON key file.
*
* <p>On App Engine, a thread created using Java's built-in API needs this credential when it
* calls App Engine API. The Google Sheets API also needs this credential.
@@ -81,28 +77,24 @@ public abstract class CredentialModule {
@JsonCredential
@Provides
@Singleton
public static GoogleCredential provideJsonCredential(
public static GoogleCredentialsBundle provideJsonCredential(
@Config("defaultCredentialOauthScopes") ImmutableList<String> requiredScopes,
@Key("jsonCredential") String jsonCredential) {
GoogleCredential credential;
GoogleCredentials credential;
try {
credential =
GoogleCredential.fromStream(
new ByteArrayInputStream(jsonCredential.getBytes(UTF_8)),
// We cannot use UrlFetchTransport as that uses App Engine API.
GoogleNetHttpTransport.newTrustedTransport(),
Utils.getDefaultJsonFactory());
} catch (IOException | GeneralSecurityException e) {
throw new RuntimeException(e);
GoogleCredentials.fromStream(new ByteArrayInputStream(jsonCredential.getBytes(UTF_8)));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
if (credential.createScopedRequired()) {
credential = credential.createScoped(requiredScopes);
}
return credential;
return GoogleCredentialsBundle.create(credential);
}
/**
* Provides a {@link GoogleCredential} with delegated admin access for a G Suite domain.
* Provides a {@link GoogleCredentialsBundle} with delegated admin access for a G Suite domain.
*
* <p>The G Suite domain must grant delegated admin access to the registry service account with
* all scopes in {@code requiredScopes}, including ones not related to G Suite.
@@ -110,18 +102,14 @@ public abstract class CredentialModule {
@DelegatedCredential
@Provides
@Singleton
public static GoogleCredential provideDelegatedCredential(
public static GoogleCredentialsBundle provideDelegatedCredential(
@Config("delegatedCredentialOauthScopes") ImmutableList<String> requiredScopes,
@JsonCredential GoogleCredential googleCredential,
@JsonCredential GoogleCredentialsBundle credentialsBundle,
@Config("gSuiteAdminAccountEmailAddress") String gSuiteAdminAccountEmailAddress) {
return new GoogleCredential.Builder()
.setTransport(Utils.getDefaultTransport())
.setJsonFactory(Utils.getDefaultJsonFactory())
.setServiceAccountId(googleCredential.getServiceAccountId())
.setServiceAccountPrivateKey(googleCredential.getServiceAccountPrivateKey())
.setServiceAccountScopes(requiredScopes)
.setServiceAccountUser(gSuiteAdminAccountEmailAddress)
.build();
return GoogleCredentialsBundle.create(credentialsBundle
.getGoogleCredentials()
.createDelegated(gSuiteAdminAccountEmailAddress)
.createScoped(requiredScopes));
}
/** Dagger qualifier for the Application Default Credential. */
@@ -14,7 +14,6 @@
package google.registry.dns.writer.clouddns;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.dns.Dns;
import com.google.common.util.concurrent.RateLimiter;
import dagger.Binds;
@@ -26,6 +25,7 @@ import dagger.multibindings.StringKey;
import google.registry.config.CredentialModule.DefaultCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.dns.writer.DnsWriter;
import google.registry.util.GoogleCredentialsBundle;
import java.util.Optional;
import javax.inject.Named;
@@ -35,12 +35,15 @@ public abstract class CloudDnsWriterModule {
@Provides
static Dns provideDns(
@DefaultCredential GoogleCredential credential,
@DefaultCredential GoogleCredentialsBundle credentialsBundle,
@Config("projectId") String projectId,
@Config("cloudDnsRootUrl") Optional<String> rootUrl,
@Config("cloudDnsServicePath") Optional<String> servicePath) {
Dns.Builder builder =
new Dns.Builder(credential.getTransport(), credential.getJsonFactory(), credential)
new Dns.Builder(
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId);
rootUrl.ifPresent(builder::setRootUrl);
@@ -14,7 +14,6 @@
package google.registry.export;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.drive.Drive;
import dagger.Component;
import dagger.Module;
@@ -24,6 +23,7 @@ import google.registry.config.CredentialModule.DefaultCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.storage.drive.DriveConnection;
import google.registry.util.GoogleCredentialsBundle;
import javax.inject.Singleton;
/** Dagger module for Google {@link Drive} service connection objects. */
@@ -32,8 +32,13 @@ public final class DriveModule {
@Provides
static Drive provideDrive(
@DefaultCredential GoogleCredential credential, @Config("projectId") String projectId) {
return new Drive.Builder(credential.getTransport(), credential.getJsonFactory(), credential)
@DefaultCredential GoogleCredentialsBundle credentialsBundle,
@Config("projectId") String projectId) {
return new Drive.Builder(
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId)
.build();
}
@@ -14,11 +14,11 @@
package google.registry.export.datastore;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import dagger.Module;
import dagger.Provides;
import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig;
import google.registry.util.GoogleCredentialsBundle;
import javax.inject.Singleton;
/** Dagger module that configures provision of {@link DatastoreAdmin}. */
@@ -28,10 +28,12 @@ public abstract class DatastoreAdminModule {
@Singleton
@Provides
static DatastoreAdmin provideDatastoreAdmin(
@CredentialModule.DefaultCredential GoogleCredential credential,
@CredentialModule.DefaultCredential GoogleCredentialsBundle credentialsBundle,
@RegistryConfig.Config("projectId") String projectId) {
return new DatastoreAdmin.Builder(
credential.getTransport(), credential.getJsonFactory(), credential)
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId)
.setProjectId(projectId)
.build();
@@ -14,12 +14,12 @@
package google.registry.export.sheet;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.sheets.v4.Sheets;
import dagger.Module;
import dagger.Provides;
import google.registry.config.CredentialModule.JsonCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.GoogleCredentialsBundle;
/** Dagger module for {@link Sheets}. */
@Module
@@ -27,8 +27,12 @@ public final class SheetsServiceModule {
@Provides
static Sheets provideSheets(
@JsonCredential GoogleCredential credential, @Config("projectId") String projectId) {
return new Sheets.Builder(credential.getTransport(), credential.getJsonFactory(), credential)
@JsonCredential GoogleCredentialsBundle credentialsBundle,
@Config("projectId") String projectId) {
return new Sheets.Builder(
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId)
.build();
}
@@ -209,6 +209,7 @@ public abstract class EppException extends Exception {
/** Specified command is not implemented. */
@EppResultCode(Code.UNIMPLEMENTED_COMMAND)
public static class UnimplementedCommandException extends EppException {
public UnimplementedCommandException(InnerCommand command) {
super(String.format(
"No flow found for %s with extension %s",
@@ -217,6 +218,10 @@ public abstract class EppException extends Exception {
? ((ResourceCommandWrapper) command).getResourceCommand().getClass().getSimpleName()
: null));
}
public UnimplementedCommandException(String message) {
super(message);
}
}
/** Abstract exception class. Do not throw this directly or catch in tests. */
@@ -82,6 +82,9 @@ public class FlowPicker {
/** Marker class for unimplemented flows. */
private abstract static class UnimplementedFlow implements Flow {}
/** Marker class for unimplemented restore flows. */
private abstract static class UnimplementedRestoreFlow implements Flow {}
/** A function type that takes an {@link EppInput} and returns a {@link Flow} class. */
private abstract static class FlowProvider {
/** Get the flow associated with this {@link EppInput} or return null to signal no match. */
@@ -160,7 +163,7 @@ public class FlowPicker {
// Restore command with an op of "report" is not currently supported.
return (rgpUpdateExtension.get().getRestoreCommand().getRestoreOp() == RestoreOp.REQUEST)
? DomainRestoreRequestFlow.class
: UnimplementedFlow.class;
: UnimplementedRestoreFlow.class;
}};
/**
@@ -265,8 +268,11 @@ public class FlowPicker {
Class<? extends Flow> flowClass = flowProvider.get(eppInput);
if (flowClass == UnimplementedFlow.class) {
break; // We found it, but it's marked as not implemented.
}
if (flowClass != null) {
} else if (flowClass == UnimplementedRestoreFlow.class) {
throw new UnimplementedCommandException(
"Domain restores are approved and enacted instantly, "
+ "therefore domain restore reports are not supported");
} else if (flowClass != null) {
return flowClass; // We found it!
}
}
@@ -14,12 +14,12 @@
package google.registry.groups;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.admin.directory.Directory;
import dagger.Module;
import dagger.Provides;
import google.registry.config.CredentialModule.DelegatedCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.GoogleCredentialsBundle;
/** Dagger module for the Google {@link Directory} service. */
@Module
@@ -27,8 +27,12 @@ public final class DirectoryModule {
@Provides
static Directory provideDirectory(
@DelegatedCredential GoogleCredential credential, @Config("projectId") String projectId) {
return new Directory.Builder(credential.getTransport(), credential.getJsonFactory(), credential)
@DelegatedCredential GoogleCredentialsBundle credentialsBundle,
@Config("projectId") String projectId) {
return new Directory.Builder(
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId)
.build();
}
@@ -14,12 +14,12 @@
package google.registry.groups;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.groupssettings.Groupssettings;
import dagger.Module;
import dagger.Provides;
import google.registry.config.CredentialModule.DelegatedCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.GoogleCredentialsBundle;
/** Dagger module for the Google {@link Groupssettings} service. */
@Module
@@ -27,9 +27,12 @@ public final class GroupssettingsModule {
@Provides
static Groupssettings provideDirectory(
@DelegatedCredential GoogleCredential credential, @Config("projectId") String projectId) {
@DelegatedCredential GoogleCredentialsBundle credentialsBundle,
@Config("projectId") String projectId) {
return new Groupssettings.Builder(
credential.getTransport(), credential.getJsonFactory(), credential)
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId)
.build();
}
@@ -14,7 +14,6 @@
package google.registry.keyring.kms;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.cloudkms.v1.CloudKMS;
import dagger.Binds;
import dagger.Module;
@@ -24,6 +23,7 @@ import dagger.multibindings.StringKey;
import google.registry.config.CredentialModule.DefaultCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.keyring.api.Keyring;
import google.registry.util.GoogleCredentialsBundle;
/** Dagger module for Cloud KMS. */
@Module
@@ -31,20 +31,23 @@ public abstract class KmsModule {
public static final String NAME = "KMS";
@Binds
@IntoMap
@StringKey(NAME)
abstract Keyring provideKeyring(KmsKeyring keyring);
@Provides
static CloudKMS provideKms(
@DefaultCredential GoogleCredential credential,
@DefaultCredential GoogleCredentialsBundle credentialsBundle,
@Config("cloudKmsProjectId") String projectId) {
return new CloudKMS.Builder(credential.getTransport(), credential.getJsonFactory(), credential)
return new CloudKMS.Builder(
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId)
.build();
}
@Binds
@IntoMap
@StringKey(NAME)
abstract Keyring provideKeyring(KmsKeyring keyring);
@Binds
abstract KmsConnection provideKmsConnection(KmsConnectionImpl kmsConnectionImpl);
}
@@ -104,7 +104,7 @@ public class DomainBase extends EppResource
* from (creationTime, deletionTime) there can only be one domain in Datastore with this name.
* However, there can be many domains with the same name and non-overlapping lifetimes.
*
* @invariant fullyQualifiedDomainName == fullyQualifiedDomainName.toLowerCase()
* @invariant fullyQualifiedDomainName == fullyQualifiedDomainName.toLowerCase(Locale.ENGLISH)
*/
@Index
String fullyQualifiedDomainName;
@@ -14,7 +14,6 @@
package google.registry.monitoring.whitebox;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.monitoring.v3.Monitoring;
import com.google.api.services.monitoring.v3.model.MonitoredResource;
import com.google.appengine.api.modules.ModulesService;
@@ -27,6 +26,7 @@ import dagger.Module;
import dagger.Provides;
import google.registry.config.CredentialModule.JsonCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.GoogleCredentialsBundle;
import org.joda.time.Duration;
/** Dagger module for Google Stackdriver service connection objects. */
@@ -39,9 +39,12 @@ public final class StackdriverModule {
@Provides
static Monitoring provideMonitoring(
@JsonCredential GoogleCredential credential, @Config("projectId") String projectId) {
@JsonCredential GoogleCredentialsBundle credentialsBundle,
@Config("projectId") String projectId) {
return new Monitoring.Builder(
credential.getTransport(), credential.getJsonFactory(), credential)
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId)
.build();
}
@@ -17,7 +17,6 @@ package google.registry.reporting;
import static google.registry.request.RequestParameters.extractOptionalParameter;
import static google.registry.request.RequestParameters.extractRequiredParameter;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.dataflow.Dataflow;
import dagger.Module;
import dagger.Provides;
@@ -26,6 +25,7 @@ import google.registry.config.RegistryConfig.Config;
import google.registry.request.HttpException.BadRequestException;
import google.registry.request.Parameter;
import google.registry.util.Clock;
import google.registry.util.GoogleCredentialsBundle;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import org.joda.time.DateTimeZone;
@@ -118,8 +118,12 @@ public class ReportingModule {
/** Constructs a {@link Dataflow} API client with default settings. */
@Provides
static Dataflow provideDataflow(
@DefaultCredential GoogleCredential credential, @Config("projectId") String projectId) {
return new Dataflow.Builder(credential.getTransport(), credential.getJsonFactory(), credential)
@DefaultCredential GoogleCredentialsBundle credentialsBundle,
@Config("projectId") String projectId) {
return new Dataflow.Builder(
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(String.format("%s billing", projectId))
.build();
}
@@ -14,13 +14,12 @@
package google.registry.tools;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.util.Utils;
import com.google.api.services.appengine.v1.Appengine;
import dagger.Module;
import dagger.Provides;
import google.registry.config.CredentialModule.LocalCredential;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.GoogleCredentialsBundle;
import javax.inject.Singleton;
/** Module providing the instance of {@link Appengine} to access App Engine Admin Api. */
@@ -30,9 +29,12 @@ public abstract class AppEngineAdminApiModule {
@Provides
@Singleton
public static Appengine provideAppengine(
@LocalCredential GoogleCredential credential, @Config("projectId") String projectId) {
@LocalCredential GoogleCredentialsBundle credentialsBundle,
@Config("projectId") String projectId) {
return new Appengine.Builder(
Utils.getDefaultTransport(), Utils.getDefaultJsonFactory(), credential)
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName(projectId)
.build();
}
@@ -20,7 +20,6 @@ import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.Details;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.util.store.AbstractDataStoreFactory;
@@ -39,10 +38,10 @@ import google.registry.config.CredentialModule.DefaultCredential;
import google.registry.config.CredentialModule.LocalCredential;
import google.registry.config.CredentialModule.LocalCredentialJson;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.GoogleCredentialsBundle;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -60,14 +59,6 @@ public class AuthModule {
private static final File DATA_STORE_DIR =
new File(System.getProperty("user.home"), ".config/nomulus/credentials");
@Module
abstract static class LocalCredentialModule {
@Binds
@DefaultCredential
abstract GoogleCredential provideLocalCredentialAsDefaultCredential(
@LocalCredential GoogleCredential credential);
}
@Provides
@StoredCredential
static Credential provideCredential(
@@ -86,38 +77,21 @@ public class AuthModule {
@Provides
@LocalCredential
public static GoogleCredential provideLocalCredential(
public static GoogleCredentialsBundle provideLocalCredential(
@LocalCredentialJson String credentialJson,
@Config("localCredentialOauthScopes") ImmutableList<String> scopes) {
try {
GoogleCredential credential =
GoogleCredential.fromStream(new ByteArrayInputStream(credentialJson.getBytes(UTF_8)));
GoogleCredentials credential =
GoogleCredentials.fromStream(new ByteArrayInputStream(credentialJson.getBytes(UTF_8)));
if (credential.createScopedRequired()) {
credential = credential.createScoped(scopes);
}
return credential;
return GoogleCredentialsBundle.create(credential);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Provides
@LocalOAuth2Credentials
public static GoogleCredentials provideLocalOAuth2Credentials(
@LocalCredentialJson String credentialJson,
@Config("localCredentialOauthScopes") ImmutableList<String> scopes) {
try {
GoogleCredentials credentials =
GoogleCredentials.fromStream(new ByteArrayInputStream(credentialJson.getBytes(UTF_8)));
if (credentials.createScopedRequired()) {
credentials = credentials.createScoped(scopes);
}
return credentials;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Provides
public static GoogleAuthorizationCodeFlow provideAuthorizationCodeFlow(
JsonFactory jsonFactory,
@@ -198,16 +172,11 @@ public class AuthModule {
}
}
/** Raised when we need a user login. */
static class LoginRequiredException extends RuntimeException {
LoginRequiredException() {}
}
/**
* Dagger qualifier for the {@link Credential} constructed from the data stored on disk.
*
* <p>This {@link Credential} should not be used in another module, hence the private qualifier.
* It's only use is to build a {@link GoogleCredential}, which is used in injection sites
* It's only use is to build a {@link GoogleCredentials}, which is used in injection sites
* elsewhere.
*/
@Qualifier
@@ -227,9 +196,16 @@ public class AuthModule {
@Retention(RetentionPolicy.RUNTIME)
@interface OAuthClientId {}
/** Dagger qualifier for the local OAuth2 Credentials. */
@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface LocalOAuth2Credentials {}
@Module
abstract static class LocalCredentialModule {
@Binds
@DefaultCredential
abstract GoogleCredentialsBundle provideLocalCredentialAsDefaultCredential(
@LocalCredential GoogleCredentialsBundle credential);
}
/** Raised when we need a user login. */
static class LoginRequiredException extends RuntimeException {
LoginRequiredException() {}
}
}
@@ -14,13 +14,13 @@
package google.registry.tools;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.javanet.NetHttpTransport;
import dagger.Module;
import dagger.Provides;
import google.registry.config.CredentialModule.DefaultCredential;
import google.registry.config.RegistryConfig;
import google.registry.util.GoogleCredentialsBundle;
/**
* Module for providing the HttpRequestFactory.
@@ -30,12 +30,12 @@ import google.registry.config.RegistryConfig;
*/
@Module
class RequestFactoryModule {
static final int REQUEST_TIMEOUT_MS = 10 * 60 * 1000;
@Provides
static HttpRequestFactory provideHttpRequestFactory(
@DefaultCredential GoogleCredential credential) {
@DefaultCredential GoogleCredentialsBundle credentialsBundle) {
if (RegistryConfig.areServersLocal()) {
return new NetHttpTransport()
.createRequestFactory(
@@ -47,11 +47,12 @@ class RequestFactoryModule {
return new NetHttpTransport()
.createRequestFactory(
request -> {
credential.initialize(request);
credentialsBundle.getHttpRequestInitializer().initialize(request);
// GAE request times out after 10 min, so here we set the timeout to 10 min. This is
// needed to support some nomulus commands like updating premium lists that take
// a lot of time to complete.
// See https://developers.google.com/api-client-library/java/google-api-java-client/errors
// See
// https://developers.google.com/api-client-library/java/google-api-java-client/errors
request.setConnectTimeout(REQUEST_TIMEOUT_MS);
request.setReadTimeout(REQUEST_TIMEOUT_MS);
});
@@ -4402,3 +4402,92 @@ Component: Footers
border:1px solid #a7a7a7;
border-bottom:0;
}
/*------------------------------------------------------------------
Blue style override
------------------------------------------------------------------*/
.componentName, #stickersheet h2.componentName a { color: #dd4b3a; }
.kd-content-sidebar .kd-sidebarlistitem.selected > a { border-left-color:#dd4b3a; }
.kd-appbar .kd-appname, .kd-appbar .kd-appname a { color:#dd4b3a; }
.kd-button-submit.disabled, .kd-button-submit.disabled:hover, .kd-button-submit.disabled:active {
border-color:#3079ee;
background-color: #4d90ff;
}
.kd-button-action.disabled, .kd-button-action.disabled:hover, .kd-button-action.disabled:active {
border-color: #b0281b;
background-color: #d14837;
}
.kd-button-submit:focus, .kd-button-submit.focus{
border-color:#4d90ff
}
.kd-button-action:focus, .kd-button-action.focus{
border-color:#d14837;
}
.kd-button-submit {
border-color: #3079ee;
background-color: #4d90ff;
background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90ff),to(#4787ed));
/* @alternate */ background-image: -webkit-linear-gradient(top,#4d90ff,#4787ed);
/* @alternate */ background-image: -moz-linear-gradient(top,#4d90ff,#4787ed);
/* @alternate */ background-image: -ms-linear-gradient(top,#4d90ff,#4787ed);
/* @alternate */ background-image: -o-linear-gradient(top,#4d90ff,#4787ed);
/* @alternate */ background-image: linear-gradient(top,#4d90ff,#4787ed);
/* filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#4d90ff',EndColorStr='#4787ed'); */
}
.kd-button-submit:hover {
border-color: #2f5bb8;
background-color: #357ae9;
background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90ff),to(#357ae9));
/* @alternate */ background-image: -webkit-linear-gradient(top,#4d90ff,#357ae9);
/* @alternate */ background-image: -moz-linear-gradient(top,#4d90ff,#357ae9);
/* @alternate */ background-image: -ms-linear-gradient(top,#4d90ff,#357ae9);
/* @alternate */ background-image: -o-linear-gradient(top,#4d90ff,#357ae9);
/* @alternate */ background-image: linear-gradient(top,#4d90ff,#357ae9);
/* filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#4d90ff',EndColorStr='#357ae9'); */
}
.kd-button-action {
margin-bottom: 16px;
border: 1px solid transparent;
color: #fff;
text-transform: uppercase;
letter-spacing: 1;
background-color: #d14837;
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b3a),to(#d14837));
/* @alternate */ background-image: -webkit-linear-gradient(top,#dd4b3a,#d14837);
/* @alternate */ background-image: -moz-linear-gradient(top,#dd4b3a,#d14837);
/* @alternate */ background-image: -ms-linear-gradient(top,#dd4b3a,#d14837);
/* @alternate */ background-image: -o-linear-gradient(top,#dd4b3a,#d14837);
/* @alternate */ background-image: linear-gradient(top,#dd4b3a,#d14837);
/* filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#dd4b3a',EndColorStr='#d14837'); */
}
.kd-button-action:hover {
border-color: #b0281b;
border-bottom-color: #af3020;
background-color: #c53728;
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b3a),to(#c53728));
/* @alternate */ background-image: -webkit-linear-gradient(top,#dd4b3a,#c53728);
/* @alternate */ background-image: -moz-linear-gradient(top,#dd4b3a,#c53728);
/* @alternate */ background-image: -ms-linear-gradient(top,#dd4b3a,#c53728);
/* @alternate */ background-image: -o-linear-gradient(top,#dd4b3a,#c53728);
/* @alternate */ background-image: linear-gradient(top,#dd4b3a,#c53728);
/* filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#dd4b3a',EndColorStr='#c53728'); */
}
.kd-button-action:active,
.kd-button-action:focus:active,
.kd-button-action.focus:active {
border-color: #992a1c;
background-color: #b0281b;
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b3a),to(#b0281b));
/* @alternate */ background-image: -webkit-linear-gradient(top,#dd4b3a,#b0281b);
/* @alternate */ background-image: -moz-linear-gradient(top,#dd4b3a,#b0281b);
/* @alternate */ background-image: -ms-linear-gradient(top,#dd4b3a,#b0281b);
/* @alternate */ background-image: -o-linear-gradient(top,#dd4b3a,#b0281b);
/* @alternate */ background-image: linear-gradient(top,#dd4b3a,#b0281b);
}
.kd-accordion .expanded .row > a { color:#d14837; }
@@ -1,410 +0,0 @@
# Copyright 2017 The Nomulus 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.
#
# .'``'. ...
# :o o `....'` ;
# `. O :'
# `': `.
# `:. `.
# : `. `.
# `..'`... `.
# `... `.
# DO NOT EDIT ``... `.
# THIS FILE `````.
#
# When you make changes to the XML schemas (*.xsd) or the JAXB bindings file
# (bindings.xjb), you must regenerate this file with the following commands:
#
# bazel run java/google/registry/xjc:list_generated_files | tee /tmp/lol
# mv /tmp/lol java/google/registry/xjc/generated_files.bzl
#
pkginfo_generated_files = [
"contact/package-info.java",
"domain/package-info.java",
"dsig/package-info.java",
"epp/package-info.java",
"eppcom/package-info.java",
"fee06/package-info.java",
"fee11/package-info.java",
"fee12/package-info.java",
"host/package-info.java",
"iirdea/package-info.java",
"launch/package-info.java",
"mark/package-info.java",
"rde/package-info.java",
"rdecontact/package-info.java",
"rdedomain/package-info.java",
"rdeeppparams/package-info.java",
"rdeheader/package-info.java",
"rdehost/package-info.java",
"rdeidn/package-info.java",
"rdenndn/package-info.java",
"rdenotification/package-info.java",
"rdepolicy/package-info.java",
"rderegistrar/package-info.java",
"rdereport/package-info.java",
"rgp/package-info.java",
"secdns/package-info.java",
"smd/package-info.java",
]
xjc_generated_files = [
"contact/ObjectFactory.java",
"contact/XjcContactAddRemType.java",
"contact/XjcContactAddrType.java",
"contact/XjcContactAuthIDType.java",
"contact/XjcContactAuthInfoType.java",
"contact/XjcContactCheck.java",
"contact/XjcContactCheckIDType.java",
"contact/XjcContactCheckType.java",
"contact/XjcContactChgPostalInfoType.java",
"contact/XjcContactChgType.java",
"contact/XjcContactChkData.java",
"contact/XjcContactCreData.java",
"contact/XjcContactCreate.java",
"contact/XjcContactDelete.java",
"contact/XjcContactDiscloseType.java",
"contact/XjcContactE164Type.java",
"contact/XjcContactInfData.java",
"contact/XjcContactInfo.java",
"contact/XjcContactIntLocType.java",
"contact/XjcContactPaCLIDType.java",
"contact/XjcContactPanData.java",
"contact/XjcContactPostalInfoEnumType.java",
"contact/XjcContactPostalInfoType.java",
"contact/XjcContactStatusType.java",
"contact/XjcContactStatusValueType.java",
"contact/XjcContactTransfer.java",
"contact/XjcContactTrnData.java",
"contact/XjcContactUpdate.java",
"domain/ObjectFactory.java",
"domain/XjcDomainAddRemType.java",
"domain/XjcDomainAuthInfoChgType.java",
"domain/XjcDomainAuthInfoType.java",
"domain/XjcDomainCheck.java",
"domain/XjcDomainCheckNameType.java",
"domain/XjcDomainCheckType.java",
"domain/XjcDomainChgType.java",
"domain/XjcDomainChkData.java",
"domain/XjcDomainContactAttrType.java",
"domain/XjcDomainContactType.java",
"domain/XjcDomainCreData.java",
"domain/XjcDomainCreate.java",
"domain/XjcDomainDelete.java",
"domain/XjcDomainHostAttrType.java",
"domain/XjcDomainHostsType.java",
"domain/XjcDomainInfData.java",
"domain/XjcDomainInfo.java",
"domain/XjcDomainInfoNameType.java",
"domain/XjcDomainNsType.java",
"domain/XjcDomainPUnitType.java",
"domain/XjcDomainPaNameType.java",
"domain/XjcDomainPanData.java",
"domain/XjcDomainPeriodType.java",
"domain/XjcDomainRenData.java",
"domain/XjcDomainRenew.java",
"domain/XjcDomainStatusType.java",
"domain/XjcDomainStatusValueType.java",
"domain/XjcDomainTransfer.java",
"domain/XjcDomainTrnData.java",
"domain/XjcDomainUpdate.java",
"dsig/ObjectFactory.java",
"dsig/XjcDsigCanonicalizationMethod.java",
"dsig/XjcDsigDSAKeyValue.java",
"dsig/XjcDsigDigestMethod.java",
"dsig/XjcDsigDigestValue.java",
"dsig/XjcDsigKeyInfo.java",
"dsig/XjcDsigKeyName.java",
"dsig/XjcDsigKeyValue.java",
"dsig/XjcDsigManifest.java",
"dsig/XjcDsigMgmtData.java",
"dsig/XjcDsigObject.java",
"dsig/XjcDsigPGPData.java",
"dsig/XjcDsigRSAKeyValue.java",
"dsig/XjcDsigReference.java",
"dsig/XjcDsigRetrievalMethod.java",
"dsig/XjcDsigSPKIData.java",
"dsig/XjcDsigSignature.java",
"dsig/XjcDsigSignatureMethod.java",
"dsig/XjcDsigSignatureProperties.java",
"dsig/XjcDsigSignatureProperty.java",
"dsig/XjcDsigSignatureValue.java",
"dsig/XjcDsigSignedInfo.java",
"dsig/XjcDsigTransform.java",
"dsig/XjcDsigTransforms.java",
"dsig/XjcDsigX509Data.java",
"dsig/XjcDsigX509IssuerSerialType.java",
"epp/ObjectFactory.java",
"epp/XjcEpp.java",
"epp/XjcEppCommandType.java",
"epp/XjcEppCredsOptionsType.java",
"epp/XjcEppDcpAccessType.java",
"epp/XjcEppDcpExpiryType.java",
"epp/XjcEppDcpOursType.java",
"epp/XjcEppDcpPurposeType.java",
"epp/XjcEppDcpRecipientType.java",
"epp/XjcEppDcpRetentionType.java",
"epp/XjcEppDcpStatementType.java",
"epp/XjcEppDcpType.java",
"epp/XjcEppElement.java",
"epp/XjcEppErrValueType.java",
"epp/XjcEppExtAnyType.java",
"epp/XjcEppExtErrValueType.java",
"epp/XjcEppExtURIType.java",
"epp/XjcEppGreetingType.java",
"epp/XjcEppLoginSvcType.java",
"epp/XjcEppLoginType.java",
"epp/XjcEppMixedMsgType.java",
"epp/XjcEppMsgQType.java",
"epp/XjcEppMsgType.java",
"epp/XjcEppPollOpType.java",
"epp/XjcEppPollType.java",
"epp/XjcEppReadWriteType.java",
"epp/XjcEppResponse.java",
"epp/XjcEppResultType.java",
"epp/XjcEppSvcMenuType.java",
"epp/XjcEppTrIDType.java",
"epp/XjcEppTransferOpType.java",
"epp/XjcEppTransferType.java",
"eppcom/ObjectFactory.java",
"eppcom/XjcEppcomExtAuthInfoType.java",
"eppcom/XjcEppcomPwAuthInfoType.java",
"eppcom/XjcEppcomReasonType.java",
"eppcom/XjcEppcomTrStatusType.java",
"fee06/ObjectFactory.java",
"fee06/XjcFee06Check.java",
"fee06/XjcFee06ChkData.java",
"fee06/XjcFee06CommandType.java",
"fee06/XjcFee06CreData.java",
"fee06/XjcFee06Create.java",
"fee06/XjcFee06CreditType.java",
"fee06/XjcFee06DelData.java",
"fee06/XjcFee06DomainCDType.java",
"fee06/XjcFee06DomainCheckType.java",
"fee06/XjcFee06FeeType.java",
"fee06/XjcFee06InfData.java",
"fee06/XjcFee06Info.java",
"fee06/XjcFee06RenData.java",
"fee06/XjcFee06Renew.java",
"fee06/XjcFee06Transfer.java",
"fee06/XjcFee06TransformCommandType.java",
"fee06/XjcFee06TransformResultType.java",
"fee06/XjcFee06TrnData.java",
"fee06/XjcFee06UpdData.java",
"fee06/XjcFee06Update.java",
"fee11/ObjectFactory.java",
"fee11/XjcFee11Check.java",
"fee11/XjcFee11ChkData.java",
"fee11/XjcFee11CommandType.java",
"fee11/XjcFee11CreData.java",
"fee11/XjcFee11Create.java",
"fee11/XjcFee11CreditType.java",
"fee11/XjcFee11DelData.java",
"fee11/XjcFee11FeeType.java",
"fee11/XjcFee11ObjectCDType.java",
"fee11/XjcFee11RenData.java",
"fee11/XjcFee11Renew.java",
"fee11/XjcFee11Transfer.java",
"fee11/XjcFee11TransformCommandType.java",
"fee11/XjcFee11TransformResultType.java",
"fee11/XjcFee11TrnData.java",
"fee11/XjcFee11UpdData.java",
"fee11/XjcFee11Update.java",
"fee12/ObjectFactory.java",
"fee12/XjcFee12Check.java",
"fee12/XjcFee12ChkData.java",
"fee12/XjcFee12CommandCDType.java",
"fee12/XjcFee12CommandCheckType.java",
"fee12/XjcFee12CreData.java",
"fee12/XjcFee12Create.java",
"fee12/XjcFee12CreditType.java",
"fee12/XjcFee12DelData.java",
"fee12/XjcFee12FeeType.java",
"fee12/XjcFee12ObjectCDType.java",
"fee12/XjcFee12RenData.java",
"fee12/XjcFee12Renew.java",
"fee12/XjcFee12Transfer.java",
"fee12/XjcFee12TransformCommandType.java",
"fee12/XjcFee12TransformResultType.java",
"fee12/XjcFee12TrnData.java",
"fee12/XjcFee12UpdData.java",
"fee12/XjcFee12Update.java",
"host/ObjectFactory.java",
"host/XjcHostAddRemType.java",
"host/XjcHostAddrType.java",
"host/XjcHostCheck.java",
"host/XjcHostCheckNameType.java",
"host/XjcHostCheckType.java",
"host/XjcHostChgType.java",
"host/XjcHostChkData.java",
"host/XjcHostCreData.java",
"host/XjcHostCreate.java",
"host/XjcHostDelete.java",
"host/XjcHostInfData.java",
"host/XjcHostInfo.java",
"host/XjcHostIpType.java",
"host/XjcHostPaNameType.java",
"host/XjcHostPanData.java",
"host/XjcHostSNameType.java",
"host/XjcHostStatusType.java",
"host/XjcHostStatusValueType.java",
"host/XjcHostUpdate.java",
"iirdea/ObjectFactory.java",
"iirdea/XjcIirdeaCode.java",
"iirdea/XjcIirdeaResponse.java",
"iirdea/XjcIirdeaResponseElement.java",
"iirdea/XjcIirdeaResult.java",
"launch/ObjectFactory.java",
"launch/XjcLaunchCdNameType.java",
"launch/XjcLaunchCdType.java",
"launch/XjcLaunchCheck.java",
"launch/XjcLaunchCheckFormType.java",
"launch/XjcLaunchChkData.java",
"launch/XjcLaunchClaimKeyType.java",
"launch/XjcLaunchCodeMarkType.java",
"launch/XjcLaunchCodeType.java",
"launch/XjcLaunchCreData.java",
"launch/XjcLaunchCreate.java",
"launch/XjcLaunchCreateNoticeType.java",
"launch/XjcLaunchDelete.java",
"launch/XjcLaunchIdContainerType.java",
"launch/XjcLaunchInfData.java",
"launch/XjcLaunchInfo.java",
"launch/XjcLaunchNoticeIDType.java",
"launch/XjcLaunchObjectType.java",
"launch/XjcLaunchPhaseType.java",
"launch/XjcLaunchPhaseTypeValue.java",
"launch/XjcLaunchStatusType.java",
"launch/XjcLaunchStatusValueType.java",
"launch/XjcLaunchUpdate.java",
"mark/ObjectFactory.java",
"mark/XjcMarkAbstractMark.java",
"mark/XjcMarkAbstractMarkType.java",
"mark/XjcMarkAddrType.java",
"mark/XjcMarkContactType.java",
"mark/XjcMarkContactTypeType.java",
"mark/XjcMarkCourtType.java",
"mark/XjcMarkE164Type.java",
"mark/XjcMarkEntitlementType.java",
"mark/XjcMarkHolderType.java",
"mark/XjcMarkMark.java",
"mark/XjcMarkMarkType.java",
"mark/XjcMarkProtectionType.java",
"mark/XjcMarkTrademarkType.java",
"mark/XjcMarkTreatyOrStatuteType.java",
"rde/ObjectFactory.java",
"rde/XjcRdeContent.java",
"rde/XjcRdeContentType.java",
"rde/XjcRdeContentsType.java",
"rde/XjcRdeDelete.java",
"rde/XjcRdeDeleteType.java",
"rde/XjcRdeDeletesType.java",
"rde/XjcRdeDeposit.java",
"rde/XjcRdeDepositTypeType.java",
"rde/XjcRdeMenuType.java",
"rde/XjcRdeRrType.java",
"rdecontact/ObjectFactory.java",
"rdecontact/XjcRdeContact.java",
"rdecontact/XjcRdeContactAbstract.java",
"rdecontact/XjcRdeContactDelete.java",
"rdecontact/XjcRdeContactDeleteType.java",
"rdecontact/XjcRdeContactElement.java",
"rdecontact/XjcRdeContactTransferDataType.java",
"rdedomain/ObjectFactory.java",
"rdedomain/XjcRdeDomain.java",
"rdedomain/XjcRdeDomainAbstract.java",
"rdedomain/XjcRdeDomainDelete.java",
"rdedomain/XjcRdeDomainDeleteType.java",
"rdedomain/XjcRdeDomainElement.java",
"rdedomain/XjcRdeDomainTransferDataType.java",
"rdeeppparams/ObjectFactory.java",
"rdeeppparams/XjcRdeEppParams.java",
"rdeeppparams/XjcRdeEppParamsAbstract.java",
"rdeeppparams/XjcRdeEppParamsElement.java",
"rdeheader/ObjectFactory.java",
"rdeheader/XjcRdeHeader.java",
"rdeheader/XjcRdeHeaderCount.java",
"rdeheader/XjcRdeHeaderElement.java",
"rdehost/ObjectFactory.java",
"rdehost/XjcRdeHost.java",
"rdehost/XjcRdeHostAbstractHost.java",
"rdehost/XjcRdeHostDelete.java",
"rdehost/XjcRdeHostDeleteType.java",
"rdehost/XjcRdeHostElement.java",
"rdeidn/ObjectFactory.java",
"rdeidn/XjcRdeIdn.java",
"rdeidn/XjcRdeIdnDelete.java",
"rdeidn/XjcRdeIdnDeleteType.java",
"rdeidn/XjcRdeIdnElement.java",
"rdenndn/ObjectFactory.java",
"rdenndn/XjcRdeNndn.java",
"rdenndn/XjcRdeNndnAbstract.java",
"rdenndn/XjcRdeNndnDelete.java",
"rdenndn/XjcRdeNndnDeleteType.java",
"rdenndn/XjcRdeNndnElement.java",
"rdenndn/XjcRdeNndnNameState.java",
"rdenndn/XjcRdeNndnNameStateValue.java",
"rdenotification/ObjectFactory.java",
"rdenotification/XjcRdeNotification.java",
"rdenotification/XjcRdeNotificationElement.java",
"rdenotification/XjcRdeNotificationName.java",
"rdenotification/XjcRdeNotificationStatusType.java",
"rdepolicy/ObjectFactory.java",
"rdepolicy/XjcRdePolicy.java",
"rdepolicy/XjcRdePolicyElement.java",
"rderegistrar/ObjectFactory.java",
"rderegistrar/XjcRdeRegistrar.java",
"rderegistrar/XjcRdeRegistrarAbstract.java",
"rderegistrar/XjcRdeRegistrarAddrType.java",
"rderegistrar/XjcRdeRegistrarDelete.java",
"rderegistrar/XjcRdeRegistrarDeleteType.java",
"rderegistrar/XjcRdeRegistrarElement.java",
"rderegistrar/XjcRdeRegistrarPostalInfoEnumType.java",
"rderegistrar/XjcRdeRegistrarPostalInfoType.java",
"rderegistrar/XjcRdeRegistrarStatusType.java",
"rderegistrar/XjcRdeRegistrarWhoisInfoType.java",
"rdereport/ObjectFactory.java",
"rdereport/XjcRdeReport.java",
"rdereport/XjcRdeReportReport.java",
"rgp/ObjectFactory.java",
"rgp/XjcRgpInfData.java",
"rgp/XjcRgpMixedType.java",
"rgp/XjcRgpOpType.java",
"rgp/XjcRgpReportTextType.java",
"rgp/XjcRgpReportType.java",
"rgp/XjcRgpRespDataType.java",
"rgp/XjcRgpRestoreType.java",
"rgp/XjcRgpStatusType.java",
"rgp/XjcRgpStatusValueType.java",
"rgp/XjcRgpUpData.java",
"rgp/XjcRgpUpdate.java",
"secdns/ObjectFactory.java",
"secdns/XjcSecdnsChgType.java",
"secdns/XjcSecdnsCreate.java",
"secdns/XjcSecdnsDsDataType.java",
"secdns/XjcSecdnsDsOrKeyType.java",
"secdns/XjcSecdnsInfData.java",
"secdns/XjcSecdnsKeyDataType.java",
"secdns/XjcSecdnsRemType.java",
"secdns/XjcSecdnsUpdate.java",
"smd/ObjectFactory.java",
"smd/XjcSmdAbstractSignedMark.java",
"smd/XjcSmdAbstractSignedMarkElement.java",
"smd/XjcSmdEncodedSignedMark.java",
"smd/XjcSmdIssuerInfo.java",
"smd/XjcSmdSignedMark.java",
"smd/XjcSmdSignedMarkElement.java",
]
@@ -1,66 +0,0 @@
# Copyright 2017 The Nomulus 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.
"""Build rule for unit testing the zip_file() rule."""
load("//java/google/registry/builddefs:defs.bzl", "ZIPPER")
def _impl(ctx):
"""Implementation of zip_contents_test() rule."""
cmd = [
"set -e",
'repo="$(pwd)"',
'zipper="${repo}/%s"' % ctx.file._zipper.short_path,
'archive="${repo}/%s"' % ctx.file.src.short_path,
('listing="$("${zipper}" v "${archive}"' +
' | grep -v ^d | awk \'{print $3}\' | LC_ALL=C sort)"'),
'if [[ "${listing}" != "%s" ]]; then' % (
"\n".join(ctx.attr.contents.keys())
),
' echo "archive had different file listing:"',
' "${zipper}" v "${archive}" | grep -v ^d',
" exit 1",
"fi",
'tmp="$(mktemp -d "${TMPDIR:-/tmp}/zip_contents_test.XXXXXXXXXX")"',
'cd "${tmp}"',
'"${zipper}" x "${archive}"',
]
for path, data in ctx.attr.contents.items():
cmd += [
'if [[ "$(cat "%s")" != "%s" ]]; then' % (path, data),
' echo "%s had different contents:"' % path,
' cat "%s"' % path,
" exit 1",
"fi",
]
cmd += [
'cd "${repo}"',
'rm -rf "${tmp}"',
]
ctx.actions.write(
output = ctx.outputs.executable,
content = "\n".join(cmd),
is_executable = True,
)
return struct(runfiles = ctx.runfiles([ctx.file.src, ctx.file._zipper]))
zip_contents_test = rule(
implementation = _impl,
test = True,
attrs = {
"src": attr.label(allow_single_file = True),
"contents": attr.string_dict(),
"_zipper": attr.label(default = Label(ZIPPER), allow_single_file = True),
},
)
@@ -96,7 +96,7 @@ public class FlowContext {
}
/**
* Helper to locate test files for this flow by looking in javatests/ for all files with the
* Helper to locate test files for this flow by looking in src/test/java/ for all files with the
* exact same relative filename as the flow file, but with a "*Test{,Case}.java" suffix.
*/
private static Set<String> getTestFilenames(String flowName) throws IOException {
@@ -35,10 +35,10 @@ import org.junit.runners.JUnit4;
* condition. For example, there should always be a matching pair of lines such as the following:
*
* <pre>
* java/.../flows/session/LoginFlow.java:
* src/main/java/.../flows/session/LoginFlow.java:
* @error {&#64;link AlreadyLoggedInException}
*
* javatests/.../flows/session/LoginFlowTest.java:
* src/test/java/.../flows/session/LoginFlowTest.java:
* import .....flows.session.LoginFlow.AlreadyLoggedInException;
* </pre>
*
@@ -17,17 +17,17 @@ package google.registry.export.datastore;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.common.collect.ImmutableList;
import google.registry.testing.TestDataHelper;
import google.registry.util.GoogleCredentialsBundle;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Optional;
import org.junit.Before;
import org.junit.Rule;
@@ -48,27 +48,44 @@ public class DatastoreAdminTest {
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
private HttpTransport httpTransport;
private GoogleCredential googleCredential;
private DatastoreAdmin datastoreAdmin;
private static HttpRequest simulateSendRequest(HttpRequest httpRequest) {
try {
httpRequest.setUrl(new GenericUrl("https://localhost:65537")).execute();
} catch (Exception expected) {
}
return httpRequest;
}
private static Optional<String> getAccessToken(HttpRequest httpRequest) {
return httpRequest.getHeaders().getAuthorizationAsList().stream()
.filter(header -> header.startsWith(AUTH_HEADER_PREFIX))
.map(header -> header.substring(AUTH_HEADER_PREFIX.length()))
.findAny();
}
private static Optional<String> getRequestContent(HttpRequest httpRequest) throws IOException {
if (httpRequest.getContent() == null) {
return Optional.empty();
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
httpRequest.getContent().writeTo(outputStream);
outputStream.close();
return Optional.of(outputStream.toString(StandardCharsets.UTF_8.name()));
}
@Before
public void setup() {
httpTransport = new NetHttpTransport();
googleCredential =
new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JacksonFactory.getDefaultInstance())
.setClock(() -> 0)
.build();
googleCredential.setAccessToken(ACCESS_TOKEN);
googleCredential.setExpiresInSeconds(1_000L);
Date oneHourLater = new Date(System.currentTimeMillis() + 3_600_000);
GoogleCredentials googleCredentials = GoogleCredentials
.create(new AccessToken(ACCESS_TOKEN, oneHourLater));
GoogleCredentialsBundle credentialsBundle = GoogleCredentialsBundle.create(googleCredentials);
datastoreAdmin =
new DatastoreAdmin.Builder(
googleCredential.getTransport(),
googleCredential.getJsonFactory(),
googleCredential)
credentialsBundle.getHttpTransport(),
credentialsBundle.getJsonFactory(),
credentialsBundle.getHttpRequestInitializer())
.setApplicationName("MyApplication")
.setProjectId("MyCloudProject")
.build();
@@ -151,29 +168,4 @@ public class DatastoreAdminTest {
simulateSendRequest(httpRequest);
assertThat(getAccessToken(httpRequest)).hasValue(ACCESS_TOKEN);
}
private static HttpRequest simulateSendRequest(HttpRequest httpRequest) {
try {
httpRequest.setUrl(new GenericUrl("https://localhost:65537")).execute();
} catch (Exception expected) {
}
return httpRequest;
}
private static Optional<String> getAccessToken(HttpRequest httpRequest) {
return httpRequest.getHeaders().getAuthorizationAsList().stream()
.filter(header -> header.startsWith(AUTH_HEADER_PREFIX))
.map(header -> header.substring(AUTH_HEADER_PREFIX.length()))
.findAny();
}
private static Optional<String> getRequestContent(HttpRequest httpRequest) throws IOException {
if (httpRequest.getContent() == null) {
return Optional.empty();
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
httpRequest.getContent().writeTo(outputStream);
outputStream.close();
return Optional.of(outputStream.toString(StandardCharsets.UTF_8.name()));
}
}
@@ -632,4 +632,16 @@ public class DomainRestoreRequestFlowTest
TransactionReportField.RESTORED_DOMAINS,
1));
}
@Test
public void testFailure_restoreReportsAreNotSupported() {
setEppInput("domain_update_restore_report.xml");
// This exception is referred to by its fully qualified path (rather than being imported) so
// that it is not included in the list of exceptions thrown by DomainRestoreRequestFlow, as this
// test EPP won't trigger the request flow at all.
EppException thrown = assertThrows(
google.registry.flows.EppException.UnimplementedCommandException.class, this::runFlow);
assertThat(thrown).hasMessageThat().contains("domain restore reports are not supported");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
}
@@ -38,7 +38,7 @@ import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.bc.BcPGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.bc.BcPGPSecretKeyRingCollection;
/** Keyring factory that loads keys from {@code javatests/.../testing/testdata} */
/** Keyring factory that loads keys from {@code src/test/java/.../testing} */
@Module
@Immutable
public final class FakeKeyringModule {
@@ -79,7 +79,7 @@ public final class TestDataHelper {
public static String loadFile(Class<?> context, String filename) {
return fileCache.computeIfAbsent(
FileKey.create(context, filename),
k -> readResourceUtf8(context, "testdata/" + filename));
k -> readResourceUtf8(context, filename));
}
/**
@@ -102,15 +102,16 @@ public final class TestDataHelper {
public static ByteSource loadBytes(Class<?> context, String filename) {
return byteCache.computeIfAbsent(
FileKey.create(context, filename),
k -> readResourceBytes(context, "testdata/" + filename));
k -> readResourceBytes(context, filename));
}
/**
* Returns the "real" location of the file loaded by the other commands, starting from javatests/.
* Returns the "real" location of the file loaded by the other commands, starting from
* src/test/resources/.
*/
public static String filePath(Class<?> context, String filename) {
String packagePath = context.getPackage().getName().replace('.', '/');
return String.format("javatests/%s/testdata/%s", packagePath, filename);
return String.format("src/test/resources/%s/%s", packagePath, filename);
}
/** Returns a recursive iterable of all files in the given directory. */
@@ -47,7 +47,7 @@ public class TmchTestDataExpirationTest {
new TmchXmlSignature(
new TmchCertificateAuthority(TmchCaMode.PILOT, new SystemClock())));
for (Path path : listFiles(TmchTestDataExpirationTest.class, "testdata/active/")) {
for (Path path : listFiles(TmchTestDataExpirationTest.class, "active/")) {
if (path.toString().endsWith(".smd")) {
logger.atInfo().log("Verifying: %s", path);
String tmchData = ResourceUtils.readResourceUtf8(path.toUri().toURL());
@@ -16,34 +16,40 @@ package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.tools.RequestFactoryModule.REQUEST_TIMEOUT_MS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpRequestInitializer;
import google.registry.config.RegistryConfig;
import google.registry.testing.SystemPropertyRule;
import google.registry.util.GoogleCredentialsBundle;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@RunWith(JUnit4.class)
public class RequestFactoryModuleTest {
private final GoogleCredential googleCredential = mock(GoogleCredential.class);
@Rule public final MockitoRule mockitoRule = MockitoJUnit.rule();
@Rule public final SystemPropertyRule systemPropertyRule = new SystemPropertyRule();
@Mock public GoogleCredentialsBundle credentialsBundle;
@Mock public HttpRequestInitializer httpRequestInitializer;
@Before
public void setUp() {
RegistryToolEnvironment.UNITTEST.setup(systemPropertyRule);
when(credentialsBundle.getHttpRequestInitializer()).thenReturn(httpRequestInitializer);
}
@Test
@@ -52,12 +58,13 @@ public class RequestFactoryModuleTest {
boolean origIsLocal = RegistryConfig.CONFIG_SETTINGS.get().appEngine.isLocal;
RegistryConfig.CONFIG_SETTINGS.get().appEngine.isLocal = true;
try {
HttpRequestFactory factory = RequestFactoryModule.provideHttpRequestFactory(googleCredential);
HttpRequestFactory factory =
RequestFactoryModule.provideHttpRequestFactory(credentialsBundle);
HttpRequestInitializer initializer = factory.getInitializer();
assertThat(initializer).isNotNull();
HttpRequest request = factory.buildGetRequest(new GenericUrl("http://localhost"));
initializer.initialize(request);
verifyZeroInteractions(googleCredential);
verifyZeroInteractions(httpRequestInitializer);
} finally {
RegistryConfig.CONFIG_SETTINGS.get().appEngine.isLocal = origIsLocal;
}
@@ -69,15 +76,16 @@ public class RequestFactoryModuleTest {
boolean origIsLocal = RegistryConfig.CONFIG_SETTINGS.get().appEngine.isLocal;
RegistryConfig.CONFIG_SETTINGS.get().appEngine.isLocal = false;
try {
HttpRequestFactory factory = RequestFactoryModule.provideHttpRequestFactory(googleCredential);
HttpRequestFactory factory =
RequestFactoryModule.provideHttpRequestFactory(credentialsBundle);
HttpRequestInitializer initializer = factory.getInitializer();
assertThat(initializer).isNotNull();
// HttpRequestFactory#buildGetRequest() calls initialize() once.
HttpRequest request = factory.buildGetRequest(new GenericUrl("http://localhost"));
verify(googleCredential).initialize(request);
verify(httpRequestInitializer).initialize(request);
assertThat(request.getConnectTimeout()).isEqualTo(REQUEST_TIMEOUT_MS);
assertThat(request.getReadTimeout()).isEqualTo(REQUEST_TIMEOUT_MS);
verifyNoMoreInteractions(googleCredential);
verifyNoMoreInteractions(httpRequestInitializer);
} finally {
RegistryConfig.CONFIG_SETTINGS.get().appEngine.isLocal = origIsLocal;
}

Some files were not shown because too many files have changed in this diff Show More