1
0
mirror of https://github.com/google/nomulus synced 2026-06-09 16:33:02 +00:00

Compare commits

...

22 Commits

Author SHA1 Message Date
Lai Jiang d55230933b Upgrade to Gradle 6.0 (#364) 2019-11-13 13:17:29 -05:00
Shicong Huang 09aef04117 Add PersistenceXmlUtility and refactor related code (#357)
* Refactor GenerateSqlSchemaCommand

* Add and throw UncheckedClassNotFoundException
2019-11-12 15:08:54 -05:00
gbrodman a392100852 Add by-repo-id method to RegistryLockDao (#344)
* Add by-repo-id method to RegistryLockDao

When we create new registry lock objects on user request, we will want
to make sure that there are no pending lock/unlock actions on this
domain. In order to do that, we will need to know what lock actions
there have been for this domain.

* Inline the query into a single statement

* whoops

* comments
2019-11-12 11:47:59 -05:00
Weimin Yu b005e3aeb0 Fix a few lint errors (#361)
Replace deprecated bouncycastle class in SslInitializerTestUils.

Generic array as vargs: worked around it in ProbingAction and
removed unused method in CircularList.
2019-11-12 11:14:51 -05:00
Weimin Yu bce09a3aa3 Deploy SQL schema from Cloud Build (#350)
Defined Docker image for schema deployment.

Included schema deploymer docker in the Cloud Build release process.

Defined Cloud Build config for schema deployment.

TESTED=Used cloud-build-local to test deployment flow
TESTED=Used docker to test schema deployer image in more ways
2019-11-12 11:06:16 -05:00
Weimin Yu cb87658827 Remove unnecessary usage of CircularList (#358)
Implementation of CircularList is an overkill for its stated
purpose. Remove an unnecessary usage so that the remaining
use case may be refactored in isolation.
2019-11-11 18:04:46 -05:00
Michael Muller 455daae25c Add converter for DateTime (#346)
* Add converter for DateTime

* Added to sql integration test suite

* Removed obsolete "auto update schema" property
2019-11-11 17:24:20 -05:00
gbrodman dea7dfcf28 Refactor UI actions to be more reliable (#348)
* Refactor UI actions to be more reliable

- Created HtmlAction to handle the nitty-gritty of login and setting up
HTML pages
- Created a test to verify that all UI actions implement JSON GET, JSON
POST, or HTML classes
- Move CSS renaming into a utility class

* Move logging of request into HtmlAction

* Comment and wording in exception

* mention JsonGetAction in the comment

* JsonGetAction extends Runnable
2019-11-11 16:18:48 -05:00
Shicong Huang 3a47fa2fe9 Fix beam pipeline deployment issue (#360) 2019-11-11 15:57:33 -05:00
gbrodman 0b7a0ba99d Update puppeteer (#359)
* Update puppeteer

They released 2.0.0 which fixes the security vuln in https-proxy-agent
2019-11-11 15:38:44 -05:00
gbrodman ae89a8b76f Run both the AppEngineRule and JpaTransactionManagerRule in tests (#356)
* Run both the AppEngineRule and JpaTransactionManagerRule in tests

As previously written, the AppEngineRule wraps the infinite loop of the
server handling requests. This changes the code so that we'll have a
chain that does both the AppEngine management and the JPA transaction
manager management so we can actually use SQL in tests and in the test
server.

* remove log line
2019-11-11 11:26:20 -05:00
Shicong Huang f0345ddf89 Resolve test flakiness caused by connection leak (#355) 2019-11-08 15:40:27 -05:00
Weimin Yu e9f20b3401 Delete obsolet gradle config in root project (#354)
* Delete obsolet gradle config in root project
2019-11-08 14:32:08 -05:00
Lai Jiang 64e7a593ef Make Joda Money embeddable in entities (#340) 2019-11-07 17:03:00 -05:00
gbrodman 135ab66e55 Throw an EPP exception when using discount on premium domains (#351)
We should communicate to the users why this command failed, that they
are not allowed to use discounted allocation tokens on premium domains.
Currently it still fails, but we don't yet tell them why.
2019-11-07 15:30:23 -05:00
sarahcaseybot 69acb9f6de Add cursors for tracking ICANN report uploads to Cursor.java (#349) 2019-11-07 10:49:21 -05:00
gbrodman 5359f4640a Clean up Karma config file (#345)
Because we moved it into the source dirs, we don't need to reference
soyutils_usegoog.js separately
2019-11-06 10:33:58 -05:00
gbrodman 5c2856e3e2 Add RegistryLockGetActionTest to SQL testclasses (#347) 2019-11-05 15:10:13 -05:00
gbrodman 86e1fb85b6 Add a GET action and tests for registry lock retrieval (#326)
* Add a GET action and tests for registry lock retrieval

* Create isVerified method

* Allow lock access for admins even if they're not enabled on the registrar

* Simple CR responses

* Move locks retrieval to the GET action

* add newline at eof

* Switch to using ID
2019-11-05 13:19:32 -05:00
Michael Muller 301ab54fb4 Improve FilteringTest so it works in all cases (#339)
* Improve FilteringTest so it works in all cases

- Disable failOnMatchingTests so we don't fail if we filter out all of the
  tests for any given task.
- Add excludeTestCases flag so that we can turn this behavior off for test
  tasks that need to run TestCas/TestSuite classes.
- Add includeAllTests() function for test tasks where we don't explicitly
  include our required tests.

This makes all test tasks in core FilteringTest, with the exception of the
default test task which now does nothing (it just depends on the other test
tasks).

* Improve wording of excludeTestCases comment
2019-11-05 12:04:56 -05:00
Shicong Huang 2c6d71f04c Prevent test from changing golden schema (#337)
When we add the extra test entity to the current JpaTransactionManagerRule by calling jpaRule.withEntityClass(TestEntity.class) and jpaRule.withProperty(Environment.HBM2DDL_AUTO, "update"), the rule would override the golden database scheme with the schema derived from the current entity class(This is an expected behavior by enabling HBM2DDL_AUTO). This behavior prevents us from detecting breaking changes in ORM classes.

This PR fixed the issue by adding HibernateSchemaExporter to export the DDL script for given extra entity class, and make JpaTransactionManagerRule execute the DDL script to create the corresponding table for the extra entity when initializing the database. This PR also simplified the code when adding extra entity class for testing. For now, you don't need to(and shouldn't) call jpaRule.withProperty(Environment.HBM2DDL_AUTO, "update").
2019-11-05 11:36:03 -05:00
Shicong Huang ee4e6ace2a Remove jdbcUrl config for nomulus tool (#330) 2019-11-05 10:33:53 -05:00
166 changed files with 2453 additions and 876 deletions
+2 -16
View File
@@ -34,7 +34,7 @@ buildscript {
plugins {
// Java static analysis plugins. Keep versions consistent with
// ./buildSrc/build.gradle
id 'nebula.lint' version '10.4.2'
id 'nebula.lint' version '16.0.2'
// TODO(weiminyu): consider remove net.ltgt.apt. Gradle 5.2+
// has similar functionalities.
id 'net.ltgt.apt' version '0.19' apply false
@@ -46,7 +46,7 @@ plugins {
id "com.moowork.node" version "1.2.0"
id 'idea'
id 'com.diffplug.gradle.spotless' version '3.18.0'
id 'com.diffplug.gradle.spotless' version '3.25.0'
id 'jacoco'
}
@@ -288,20 +288,6 @@ subprojects {
}
}
}
if (['util', 'proxy', 'core', 'prober', 'db'].contains(project.name)) return
// TODO(weiminyu): investigate if the block below is still needed
ext.relativePath = "google/registry/${project.name}"
sourceSets.each {
it.java {
include "${project.relativePath}/"
}
it.resources {
include "${project.relativePath}/"
}
}
}
// If "-P verboseTestOutput=true" is passed in, configure all subprojects to dump all of their
+2 -2
View File
@@ -23,13 +23,13 @@ buildscript {
plugins {
// Java static analysis plugins. Keep versions consistent with ../build.gradle
id 'nebula.lint' version '10.4.2'
id 'nebula.lint' version '16.0.2'
// Config helper for annotation processors such as AutoValue and Dagger.
// Ensures that source code is generated at an appropriate location.
id 'net.ltgt.apt' version '0.19' apply false
id 'net.ltgt.errorprone' version '0.6.1'
id 'checkstyle'
id 'com.diffplug.gradle.spotless' version '3.18.0'
id 'com.diffplug.gradle.spotless' version '3.25.0'
}
if (rootProject.enableDependencyLocking.toBoolean()) {
@@ -1,60 +1,44 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
cglib:cglib-nodep:3.2.2
com.diffplug.durian:durian-collect:1.2.0
com.diffplug.durian:durian-core:1.2.0
com.diffplug.durian:durian-io:1.2.0
com.diffplug.gradle.spotless:com.diffplug.gradle.spotless.gradle.plugin:3.18.0
com.diffplug.spotless:spotless-lib-extra:1.18.0
com.diffplug.spotless:spotless-lib:1.18.0
com.diffplug.spotless:spotless-plugin-gradle:3.18.0
com.diffplug.gradle.spotless:com.diffplug.gradle.spotless.gradle.plugin:3.25.0
com.diffplug.spotless:spotless-lib-extra:1.25.0
com.diffplug.spotless:spotless-lib:1.25.0
com.diffplug.spotless:spotless-plugin-gradle:3.25.0
com.google.guava:guava:19.0
com.googlecode.concurrent-trees:concurrent-trees:2.6.1
com.googlecode.javaewah:JavaEWAH:1.1.6
com.jcraft:jsch:0.1.54
com.jcraft:jsch:0.1.55
com.jcraft:jzlib:1.1.1
com.netflix.nebula:gradle-lint-plugin:10.4.2
com.netflix.nebula:gradle-lint-plugin:16.0.2
com.netflix.nebula:nebula-gradle-interop:1.0.11
com.netflix.nebula:nebula-test:7.4.0
commons-codec:commons-codec:1.9
commons-io:commons-io:2.5
commons-lang:commons-lang:2.6
commons-logging:commons-logging:1.2
javax.inject:javax.inject:1
junit:junit:4.12
log4j:log4j:1.2.14
nebula.lint:nebula.lint.gradle.plugin:10.4.2
nebula.lint:nebula.lint.gradle.plugin:16.0.2
net.ltgt.apt:net.ltgt.apt.gradle.plugin:0.19
net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:0.6.1
net.ltgt.gradle:gradle-apt-plugin:0.19
net.ltgt.gradle:gradle-errorprone-plugin:0.6.1
org.apache.ant:ant-antlr:1.8.4
org.apache.ant:ant-junit:1.8.4
org.apache.ant:ant-launcher:1.8.4
org.apache.ant:ant:1.8.4
org.apache.commons:commons-lang3:3.8.1
org.apache.httpcomponents:httpclient:4.5.2
org.apache.httpcomponents:httpcore:4.4.4
org.apache.maven:maven-artifact:3.6.2
org.apache.maven:maven-builder-support:3.6.2
org.apache.maven:maven-model-builder:3.6.2
org.apache.maven:maven-model:3.6.2
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.codehaus.gpars:gpars:1.2.1
org.codehaus.groovy:groovy-all:2.4.15
org.codehaus.groovy:groovy-ant:2.1.8
org.codehaus.groovy:groovy-groovydoc:2.1.8
org.codehaus.groovy:groovy-templates:2.1.8
org.codehaus.groovy:groovy-xml:2.4.7
org.codehaus.groovy:groovy:2.4.7
org.codehaus.jsr166-mirror:jsr166y:1.7.0
org.codehaus.plexus:plexus-interpolation:1.25
org.codehaus.plexus:plexus-utils:3.2.1
org.codenarc:CodeNarc:0.25.2
org.eclipse.jdt:core:3.1.1
org.eclipse.jgit:org.eclipse.jgit:5.0.1.201806211838-r
org.eclipse.jgit:org.eclipse.jgit:5.5.0.201909110433-r
org.eclipse.sisu:org.eclipse.sisu.inject:0.3.3
org.gmetrics:GMetrics:0.7
org.hamcrest:hamcrest-core:1.3
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50
@@ -62,7 +46,8 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50
org.jetbrains.kotlin:kotlin-stdlib:1.3.50
org.jetbrains:annotations:13.0
org.multiverse:multiverse-core:0.7.0
org.objenesis:objenesis:2.4
org.ow2.asm:asm:7.0
org.ow2.asm:asm-analysis:7.1
org.ow2.asm:asm-commons:7.1
org.ow2.asm:asm-tree:7.1
org.ow2.asm:asm:7.1
org.slf4j:slf4j-api:1.7.2
org.spockframework:spock-core:1.3-groovy-2.4
@@ -3,16 +3,16 @@
# This file is expected to be part of source control.
antlr:antlr:2.7.7
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.2.0
com.google.errorprone:error_prone_annotations:2.3.2
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-jre
com.google.guava:guava:28.0-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.puppycrawl.tools:checkstyle:8.17
commons-beanutils:commons-beanutils:1.9.3
com.google.j2objc:j2objc-annotations:1.3
com.puppycrawl.tools:checkstyle:8.24
commons-beanutils:commons-beanutils:1.9.4
commons-collections:commons-collections:3.2.2
info.picocli:picocli:3.9.0
net.sf.saxon:Saxon-HE:9.9.0-2
info.picocli:picocli:4.0.3
net.sf.saxon:Saxon-HE:9.9.1-4
org.antlr:antlr4-runtime:4.7.2
org.checkerframework:checker-qual:2.5.2
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.17
@@ -1,4 +1,4 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.agent:0.8.5
@@ -1,11 +1,11 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.ant:0.8.4
org.jacoco:org.jacoco.core:0.8.4
org.jacoco:org.jacoco.report:0.8.4
org.ow2.asm:asm-analysis:7.1
org.ow2.asm:asm-commons:7.1
org.ow2.asm:asm-tree:7.1
org.ow2.asm:asm:7.1
org.jacoco:org.jacoco.agent:0.8.5
org.jacoco:org.jacoco.ant:0.8.5
org.jacoco:org.jacoco.core:0.8.5
org.jacoco:org.jacoco.report:0.8.5
org.ow2.asm:asm-analysis:7.2
org.ow2.asm:asm-commons:7.2
org.ow2.asm:asm-tree:7.2
org.ow2.asm:asm:7.2
@@ -0,0 +1,61 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
com.fasterxml.jackson.core:jackson-core:2.9.9
com.google.api-client:google-api-client:1.27.0
com.google.api.grpc:proto-google-common-protos:1.12.0
com.google.api.grpc:proto-google-iam-v1:0.12.0
com.google.api:api-common:1.7.0
com.google.api:gax-httpjson:0.52.1
com.google.api:gax:1.35.1
com.google.apis:google-api-services-storage:v1-rev20181013-1.27.0
com.google.auth:google-auth-library-credentials:0.16.1
com.google.auth:google-auth-library-oauth2-http:0.16.1
com.google.auto.value:auto-value-annotations:1.6.3
com.google.cloud:google-cloud-core-http:1.59.0
com.google.cloud:google-cloud-core:1.59.0
com.google.cloud:google-cloud-storage:1.59.0
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.7
com.google.common.html.types:types:1.0.4
com.google.errorprone:error_prone_annotations:2.3.2
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.0-beta1
com.google.http-client:google-http-client-appengine:1.27.0
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client:1.30.1
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.oauth-client:google-oauth-client:1.27.0
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
com.google.template:soy:2018-03-14
com.ibm.icu:icu4j:57.1
commons-codec:commons-codec:1.11
commons-logging:commons-logging:1.2
io.grpc:grpc-context:1.19.0
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-contrib-http-util:0.21.0
javax.annotation:javax.annotation-api:1.2
javax.annotation:jsr250-api:1.0
javax.inject:javax.inject:1
javax.validation:validation-api:1.0.0.GA
joda-time:joda-time:2.9.2
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.json:json:20160212
org.ow2.asm:asm-analysis:6.0
org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0
org.threeten:threetenbp:1.3.3
@@ -0,0 +1,71 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
com.fasterxml.jackson.core:jackson-core:2.9.9
com.google.api-client:google-api-client:1.27.0
com.google.api.grpc:proto-google-common-protos:1.12.0
com.google.api.grpc:proto-google-iam-v1:0.12.0
com.google.api:api-common:1.7.0
com.google.api:gax-httpjson:0.52.1
com.google.api:gax:1.35.1
com.google.apis:google-api-services-storage:v1-rev20181013-1.27.0
com.google.auth:google-auth-library-credentials:0.16.1
com.google.auth:google-auth-library-oauth2-http:0.16.1
com.google.auto.value:auto-value-annotations:1.6.3
com.google.cloud:google-cloud-core-http:1.59.0
com.google.cloud:google-cloud-core:1.59.0
com.google.cloud:google-cloud-storage:1.59.0
com.google.code.findbugs:jsr305:3.0.2
com.google.code.gson:gson:2.7
com.google.common.html.types:types:1.0.4
com.google.errorprone:error_prone_annotations:2.3.2
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.0-beta1
com.google.http-client:google-http-client-appengine:1.27.0
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client:1.30.1
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.oauth-client:google-oauth-client:1.27.0
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
com.google.template:soy:2018-03-14
com.google.truth.extensions:truth-java8-extension:1.0
com.google.truth:truth:1.0
com.googlecode.java-diff-utils:diffutils:1.3.0
com.ibm.icu:icu4j:57.1
commons-codec:commons-codec:1.11
commons-logging:commons-logging:1.2
io.grpc:grpc-context:1.19.0
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-contrib-http-util:0.21.0
javax.annotation:javax.annotation-api:1.2
javax.annotation:jsr250-api:1.0
javax.inject:javax.inject:1
javax.validation:validation-api:1.0.0.GA
joda-time:joda-time:2.9.2
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.9.7
net.bytebuddy:byte-buddy:1.9.7
org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.checkerframework:checker-compat-qual:2.5.5
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.hamcrest:hamcrest-core:1.3
org.json:json:20160212
org.mockito:mockito-core:2.25.0
org.objenesis:objenesis:2.6
org.ow2.asm:asm-analysis:6.0
org.ow2.asm:asm-commons:6.0
org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0
org.threeten:threetenbp:1.3.3
+13 -13
View File
@@ -73,6 +73,19 @@ by Joshua Bloch in his book Effective Java -->
<property name="message" value="MockitoJUnitRunner is deprecated. Use @RunWith(JUnit4.class) and MockitoRule instead."/>
</module>
<module name="LineLength">
<!-- Checks if a line is too long. -->
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="100"/>
<property name="severity" value="error"/>
<!-- Ignore lines that have any series of 80 or more non-whitespace characters.
These lines likely cannot be broken.
-->
<property name="ignorePattern"
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
default=".*[^ ]{80,}.*"/>
</module>
<!-- All Java AST specific tests live under TreeWalker module. -->
<module name="TreeWalker">
@@ -184,19 +197,6 @@ by Joshua Bloch in his book Effective Java -->
LENGTH and CODING CHECKS
-->
<module name="LineLength">
<!-- Checks if a line is too long. -->
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="100"/>
<property name="severity" value="error"/>
<!-- Ignore lines that have any series of 80 or more non-whitespace characters.
These lines likely cannot be broken.
-->
<property name="ignorePattern"
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
default=".*[^ ]{80,}.*"/>
</module>
<module name="OperatorWrap">
<property name="option" value="nl"/>
<property name="tokens" value="QUESTION, EQUAL, NOT_EQUAL, DIV, PLUS, MINUS, STAR, MOD, SR, BSR, GE, GT, SL, LE, LT, BXOR, BOR, LOR, BAND, LAND, TYPE_EXTENSION_AND, LITERAL_INSTANCEOF"/>
@@ -141,6 +141,9 @@
{
"moduleLicense": "Eclipse Public License - v 2.0"
},
{
"moduleLicense": "Eclipse Public License 2.0"
},
{
"moduleLicense": "https://www.eclipse.org/legal/epl-2.0/, http://www.gnu.org/copyleft/gpl.html, http://www.gnu.org/licenses/lgpl.html"
},
+56 -17
View File
@@ -160,7 +160,6 @@ dependencies {
compile deps['com.google.apis:google-api-services-groupssettings']
compile deps['com.google.apis:google-api-services-monitoring']
compile deps['com.google.apis:google-api-services-sheets']
testCompileOnly deps['com.google.appengine:appengine-api-1.0-sdk']
testCompile deps['com.google.appengine:appengine-api-stubs']
compile deps['com.google.appengine.tools:appengine-gcs-client']
compile deps['com.google.appengine.tools:appengine-mapreduce']
@@ -193,9 +192,11 @@ dependencies {
testCompile deps['com.thoughtworks.qdox:qdox']
compile deps['dnsjava:dnsjava']
testCompile deps['io.github.classgraph:classgraph']
testCompile deps['javax.annotation:javax.annotation-api']
testCompile deps['javax.annotation:jsr250-api']
compile deps['javax.inject:javax.inject']
compile deps['javax.mail:mail']
compile deps['javax.persistence:javax.persistence-api']
compile deps['javax.servlet:servlet-api']
compile deps['javax.xml.bind:jaxb-api']
compile deps['jline:jline']
@@ -206,6 +207,7 @@ dependencies {
compile deps['org.apache.beam:beam-sdks-java-core']
compile deps['org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core']
compile deps['org.apache.beam:beam-sdks-java-io-google-cloud-platform']
testCompile deps['org.apache.commons:commons-lang3']
testCompile deps['org.apache.commons:commons-text']
testCompile deps['org.apache.ftpserver:ftplet-api']
testCompile deps['org.apache.ftpserver:ftpserver-core']
@@ -219,6 +221,7 @@ dependencies {
testCompile deps['org.bouncycastle:bcpkix-jdk15on']
compile deps['org.bouncycastle:bcprov-jdk15on']
runtime deps['org.glassfish.jaxb:jaxb-runtime']
compile deps['org.hibernate:hibernate-core']
compile deps['org.joda:joda-money']
compile deps['org.json:json']
testCompile deps['org.mortbay.jetty:jetty']
@@ -227,10 +230,15 @@ dependencies {
testCompile deps['org.seleniumhq.selenium:selenium-chrome-driver']
testCompile deps['org.seleniumhq.selenium:selenium-java']
testCompile deps['org.seleniumhq.selenium:selenium-remote-driver']
testCompile deps['org.testcontainers:jdbc']
compile deps['org.testcontainers:postgresql']
testCompile deps['org.testcontainers:selenium']
testCompile deps['org.testcontainers:testcontainers']
compile deps['xerces:xmlParserAPIs']
compile deps['xpp3:xpp3']
// This dependency must come after javax.mail:mail as it would otherwise
// shadow classes in package javax.mail with its own implementation.
compile deps['com.google.appengine:appengine-api-1.0-sdk']
// Known issue: nebula-lint misses inherited dependency.
compile project(':third_party')
@@ -534,8 +542,8 @@ task compileProdJS(type: JavaExec) {
compileJava.dependsOn jaxbToJava
compileJava.dependsOn soyToJava
// The Closure JS compiler does not support Windows. It is fine to disable it if all we want to do
// is to complile the Java code on Windows.
// The Closure JS compiler does not support Windows. It is fine to disable it if
// all we want to do is to complile the Java code on Windows.
if (!System.properties['os.name'].toLowerCase().contains('windows')) {
compileJava.dependsOn compileProdJS
assemble.dependsOn compileProdJS
@@ -590,14 +598,43 @@ artifacts {
*/
class FilteringTest extends Test {
void setTests(List<String> tests) {
// Common exclude pattern. See README in parent directory for explanation.
exclude "**/*TestCase.*", "**/*TestSuite.*"
include tests
private void applyTestFilter() {
if (project.testFilter) {
testNameIncludePatterns = project.testFilter.split(',')
// By default, gradle test tasks will produce a failure if no tests
// match the include/exclude/filter rules. Since test filtering allows us
// to select a set of tests from a particular task, we don't want this
// behavior.
filter.failOnNoMatchingTests = false
}
}
/**
* Set to false if you also want to include TestCase and TestSuite classes.
*
* <p>Must be defined before "test", if at all.
*/
boolean excludeTestCases = true
void setTests(List<String> tests) {
// Common exclude pattern. See README in parent directory for explanation.
if (excludeTestCases) {
exclude "**/*TestCase.*", "**/*TestSuite.*"
}
include tests
applyTestFilter()
}
/**
* Include all of the tests (except Test{Case,TestSuite}). This actually
* doesn't explicitly "include" anything, in which cast the Test class tries
* to include everything that is not explicitly excluded.
*/
void includeAllTests() {
exclude "**/*TestCase.*", "**/*TestSuite.*"
applyTestFilter()
}
}
task fragileTest(type: FilteringTest) {
@@ -620,12 +657,9 @@ task outcastTest(type: FilteringTest) {
}
// Dedicated test suite for schema-dependent tests.
task sqlIntegrationTest(type: Test) {
include 'google/registry/schema/integration/SqlIntegrationTestSuite.*'
// Copied from FilteringTest. Not inheriting b/c it excludes TestSuites.
if (project.testFilter) {
testNameIncludePatterns = project.testFilter.split(',')
}
task sqlIntegrationTest(type: FilteringTest) {
excludeTestCases = false
tests = ['google/registry/schema/integration/SqlIntegrationTestSuite.*']
}
task findGoldenImages(type: JavaExec) {
@@ -710,9 +744,8 @@ task flowDocsTool(type: JavaExec) {
args arguments
}
test {
// Common exclude pattern. See README in parent directory for explanation.
exclude "**/*TestCase.*", "**/*TestSuite.*"
task standardTest(type: FilteringTest) {
includeAllTests()
exclude fragileTestPatterns
exclude outcastTestPatterns
@@ -734,7 +767,13 @@ test {
doFirst {
new File(screenshotsDir).deleteDir()
}
}.dependsOn(fragileTest, outcastTest)
}
test {
// Don't run any tests from this task, all testing gets done in the
// FilteringTest tasks.
exclude "**"
}.dependsOn(fragileTest, outcastTest, standardTest)
createUberJar('nomulus', 'nomulus', 'google.registry.tools.RegistryTool')
project.nomulus.dependsOn project(':third_party').jar
@@ -3,16 +3,16 @@
# This file is expected to be part of source control.
antlr:antlr:2.7.7
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.2.0
com.google.errorprone:error_prone_annotations:2.3.2
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-jre
com.google.guava:guava:28.0-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.puppycrawl.tools:checkstyle:8.17
commons-beanutils:commons-beanutils:1.9.3
com.google.j2objc:j2objc-annotations:1.3
com.puppycrawl.tools:checkstyle:8.24
commons-beanutils:commons-beanutils:1.9.4
commons-collections:commons-collections:3.2.2
info.picocli:picocli:3.9.0
net.sf.saxon:Saxon-HE:9.9.0-2
info.picocli:picocli:4.0.3
net.sf.saxon:Saxon-HE:9.9.1-4
org.antlr:antlr4-runtime:4.7.2
org.checkerframework:checker-qual:2.5.2
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.17
@@ -204,7 +204,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5
@@ -202,7 +202,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5
@@ -215,7 +215,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5
@@ -1,4 +1,4 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.agent:0.8.5
@@ -1,11 +1,11 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.ant:0.8.4
org.jacoco:org.jacoco.core:0.8.4
org.jacoco:org.jacoco.report:0.8.4
org.ow2.asm:asm-analysis:7.1
org.ow2.asm:asm-commons:7.1
org.ow2.asm:asm-tree:7.1
org.ow2.asm:asm:7.1
org.jacoco:org.jacoco.agent:0.8.5
org.jacoco:org.jacoco.ant:0.8.5
org.jacoco:org.jacoco.core:0.8.5
org.jacoco:org.jacoco.report:0.8.5
org.ow2.asm:asm-analysis:7.2
org.ow2.asm:asm-commons:7.2
org.ow2.asm:asm-tree:7.2
org.ow2.asm:asm:7.2
@@ -204,7 +204,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5
@@ -215,7 +215,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5
@@ -228,7 +228,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0
@@ -226,7 +226,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0
@@ -1,4 +1,3 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.appengine:appengine-api-1.0-sdk:1.9.48
@@ -240,7 +240,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0
@@ -240,7 +240,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0
-5
View File
@@ -42,10 +42,6 @@ module.exports = function(config) {
pattern: 'core/build/generated/source/custom/main/**/*.soy.js',
included: false
},
{
pattern: 'node_modules/soyutils_usegoog.js',
included: false
},
{
pattern: 'node_modules/google-closure-library/closure/goog/deps.js',
included: false,
@@ -70,7 +66,6 @@ module.exports = function(config) {
'node_modules/google-closure-library/closure/**/*.js': ['closure'],
'core/src/*/javascript/**/*.js': ['closure'],
'core/build/generated/source/custom/main/**/*.soy.js': ['closure'],
'node_modules/soyutils_usegoog.js': ['closure']
},
proxies: {
"/assets/": "/base/core/build/resources/main/google/registry/ui/assets/"
@@ -85,7 +85,7 @@ public class InvoicingPipeline implements Serializable {
}
/** Custom options for running the invoicing pipeline. */
interface InvoicingPipelineOptions extends DataflowPipelineOptions {
public interface InvoicingPipelineOptions extends DataflowPipelineOptions {
/** Returns the yearMonth we're generating invoices for, in yyyy-MM format. */
@Description("The yearMonth we generate invoices for, in yyyy-MM format.")
ValueProvider<String> getYearMonth();
@@ -105,7 +105,7 @@ public class Spec11Pipeline implements Serializable {
}
/** Custom options for running the spec11 pipeline. */
interface Spec11PipelineOptions extends DataflowPipelineOptions {
public interface Spec11PipelineOptions extends DataflowPipelineOptions {
/** Returns the local date we're generating the report for, in yyyy-MM-dd format. */
@Description("The local date we generate the report for, in yyyy-MM-dd format.")
ValueProvider<String> getDate();
@@ -1296,12 +1296,6 @@ public final class RegistryConfig {
return config.registryTool.clientSecret;
}
@Provides
@Config("toolsCloudSqlJdbcUrl")
public static String providesToolsCloudSqlJdbcUrl(RegistryConfigSettings config) {
return config.registryTool.jdbcUrl;
}
@Provides
@Config("toolsCloudSqlUsername")
public static String providesToolsCloudSqlUsername(RegistryConfigSettings config) {
@@ -213,7 +213,6 @@ public class RegistryConfigSettings {
public static class RegistryTool {
public String clientId;
public String clientSecret;
public String jdbcUrl;
public String username;
}
}
@@ -422,6 +422,4 @@ registryTool:
clientId: YOUR_CLIENT_ID
# OAuth client secret used by the tool.
clientSecret: YOUR_CLIENT_SECRET
# Nomulus tool uses a different jdbc url and user to connect to Cloud SQL
jdbcUrl: jdbc:postgresql://localhost/tool
username: toolusername
@@ -55,6 +55,12 @@
<url-pattern>/registrar-settings</url-pattern>
</servlet-mapping>
<!-- Registry lock get/post/verify. -->
<servlet-mapping>
<servlet-name>frontend-servlet</servlet-name>
<url-pattern>/registry-lock-get</url-pattern>
</servlet-mapping>
<!-- Security config -->
<security-constraint>
<web-resource-collection>
@@ -187,6 +187,7 @@ import org.joda.time.Duration;
* @error {@link DomainFlowUtils.UnexpectedClaimsNoticeException}
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
* @error {@link DomainFlowUtils.UnsupportedMarkTypeException}
* @error {@link DomainPricingLogic.AllocationTokenInvalidForPremiumNameException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_CREATE)
public class DomainCreateFlow implements TransactionalFlow {
@@ -14,12 +14,12 @@
package google.registry.flows.domain;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.pricing.PricingEngineProxy.getDomainFeeClass;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
import com.google.common.net.InternetDomainName;
import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.FlowScope;
import google.registry.flows.custom.DomainPricingCustomLogic;
import google.registry.flows.custom.DomainPricingCustomLogic.CreatePriceParameters;
@@ -182,13 +182,14 @@ public final class DomainPricingLogic {
}
private Money getDomainCreateCostWithDiscount(
String domainName, DateTime date, int years, Optional<AllocationToken> allocationToken) {
String domainName, DateTime date, int years, Optional<AllocationToken> allocationToken)
throws EppException {
DomainPrices domainPrices = PricingEngineProxy.getPricesForDomainName(domainName, date);
checkArgument(
!allocationToken.isPresent()
|| allocationToken.get().getDiscountFraction() == 0.0
|| !domainPrices.isPremium(),
"A nonzero discount code cannot be applied to premium domains");
if (allocationToken.isPresent()
&& allocationToken.get().getDiscountFraction() != 0.0
&& domainPrices.isPremium()) {
throw new AllocationTokenInvalidForPremiumNameException();
}
Money oneYearCreateCost = domainPrices.getCreateCost();
Money totalDomainCreateCost = oneYearCreateCost.multipliedBy(years);
// If a discount is applicable, apply it only to the first year
@@ -200,4 +201,12 @@ public final class DomainPricingLogic {
}
return totalDomainCreateCost;
}
/** An allocation token was provided that is invalid for premium domains. */
public static class AllocationTokenInvalidForPremiumNameException
extends CommandUseErrorException {
public AllocationTokenInvalidForPremiumNameException() {
super("A nonzero discount code cannot be applied to premium domains");
}
}
}
@@ -79,7 +79,16 @@ public class Cursor extends ImmutableObject {
* stored is the last time that registrar changes were successfully synced to the sheet. If
* there were no changes since the last time the action run, the cursor is not updated.
*/
SYNC_REGISTRAR_SHEET(EntityGroupRoot.class);
SYNC_REGISTRAR_SHEET(EntityGroupRoot.class),
/** Cursor for tracking monthly uploads of ICANN transaction reports. */
ICANN_UPLOAD_TX(Registry.class),
/** Cursor for tracking monthly uploads of ICANN activity reports. */
ICANN_UPLOAD_ACTIVITY(Registry.class),
/** Cursor for tracking monthly upload of MANIFEST.txt to ICANN. */
ICANN_UPLOAD_MANIFEST(EntityGroupRoot.class);
/** See the definition of scope on {@link #getScopeClass}. */
private final Class<? extends ImmutableObject> scope;
@@ -19,6 +19,7 @@ import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
import com.google.common.collect.ImmutableList;
import google.registry.schema.domain.RegistryLock;
import java.util.Optional;
import javax.persistence.EntityManager;
/** Data access object for {@link google.registry.schema.domain.RegistryLock}. */
@@ -47,6 +48,7 @@ public final class RegistryLockDao {
});
}
/** Returns all lock objects that this registrar has created. */
public static ImmutableList<RegistryLock> getByRegistrarId(String registrarId) {
return jpaTm()
.transact(
@@ -62,6 +64,26 @@ public final class RegistryLockDao {
.getResultList()));
}
/**
* Returns the most recent lock object for a given repo ID (i.e. a domain) or empty if this domain
* hasn't been locked before.
*/
public static Optional<RegistryLock> getMostRecentByRepoId(String repoId) {
return jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createQuery(
"SELECT lock FROM RegistryLock lock WHERE lock.repoId = :repoId"
+ " ORDER BY lock.revisionId DESC",
RegistryLock.class)
.setParameter("repoId", repoId)
.setMaxResults(1)
.getResultStream()
.findFirst());
}
public static RegistryLock save(RegistryLock registryLock) {
checkNotNull(registryLock, "Null registry lock cannot be saved");
return jpaTm().transact(() -> jpaTm().getEntityManager().merge(registryLock));
@@ -30,6 +30,7 @@ import google.registry.ui.server.registrar.ConsoleUiAction;
import google.registry.ui.server.registrar.OteStatusAction;
import google.registry.ui.server.registrar.RegistrarConsoleModule;
import google.registry.ui.server.registrar.RegistrarSettingsAction;
import google.registry.ui.server.registrar.RegistryLockGetAction;
/** Dagger component with per-request lifetime for "default" App Engine module. */
@RequestScope
@@ -50,6 +51,8 @@ interface FrontendRequestComponent {
OteStatusAction oteStatusAction();
RegistrarSettingsAction registrarSettingsAction();
RegistryLockGetAction registryLockGetAction();
@Subcomponent.Builder
abstract class Builder implements RequestComponentBuilder<FrontendRequestComponent> {
@Override public abstract Builder requestModule(RequestModule requestModule);
@@ -0,0 +1,41 @@
// 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.
package google.registry.persistence;
import static org.joda.time.DateTimeZone.UTC;
import java.sql.Timestamp;
import javax.annotation.Nullable;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import org.joda.time.DateTime;
/** JPA converter to for storing/retrieving {@link org.joda.time.DateTime} objects. */
@Converter(autoApply = true)
public class DateTimeConverter implements AttributeConverter<DateTime, Timestamp> {
@Override
@Nullable
public Timestamp convertToDatabaseColumn(@Nullable DateTime attribute) {
return attribute == null ? null : new Timestamp(attribute.getMillis());
}
@Override
@Nullable
public DateTime convertToEntityAttribute(@Nullable Timestamp dbData) {
DateTime result = dbData == null ? null : new DateTime(dbData.getTime(), UTC);
return result;
}
}
@@ -0,0 +1,86 @@
// 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.
package google.registry.persistence;
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import java.io.File;
import java.util.EnumSet;
import java.util.Map;
import java.util.stream.Stream;
import javax.persistence.AttributeConverter;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
/** Utility class to export DDL script for given {@link javax.persistence.Entity} classes. */
public class HibernateSchemaExporter {
private final String jdbcUrl;
private final String username;
private final String password;
private HibernateSchemaExporter(String jdbcUrl, String username, String password) {
this.jdbcUrl = jdbcUrl;
this.username = username;
this.password = password;
}
/** Constructs a {@link HibernateSchemaExporter} instance. */
public static HibernateSchemaExporter create(String jdbcUrl, String username, String password) {
return new HibernateSchemaExporter(jdbcUrl, username, password);
}
/** Exports DDL script to the {@code outputFile} for the given {@code entityClasses}. */
public void export(ImmutableList<Class> entityClasses, File outputFile) {
// Configure Hibernate settings.
Map<String, String> settings = Maps.newHashMap();
settings.put(Environment.DIALECT, NomulusPostgreSQLDialect.class.getName());
settings.put(Environment.URL, jdbcUrl);
settings.put(Environment.USER, username);
settings.put(Environment.PASS, password);
settings.put(Environment.HBM2DDL_AUTO, "none");
settings.put(Environment.SHOW_SQL, "true");
settings.put(
Environment.PHYSICAL_NAMING_STRATEGY, NomulusNamingStrategy.class.getCanonicalName());
try (StandardServiceRegistry registry =
new StandardServiceRegistryBuilder().applySettings(settings).build()) {
MetadataSources metadata = new MetadataSources(registry);
// Note that we need to also add all converters to the Hibernate context because
// the entity class may use the customized type.
Stream.concat(entityClasses.stream(), findAllConverters().stream())
.forEach(metadata::addAnnotatedClass);
SchemaExport export = new SchemaExport();
export.setHaltOnError(true);
export.setFormat(true);
export.setDelimiter(";");
export.setOutputFile(outputFile.getAbsolutePath());
export.createOnly(EnumSet.of(TargetType.SCRIPT), metadata.buildMetadata());
}
}
private ImmutableList<Class> findAllConverters() {
return PersistenceXmlUtility.getManagedClasses().stream()
.filter(AttributeConverter.class::isAssignableFrom)
.collect(toImmutableList());
}
}
@@ -0,0 +1,59 @@
// 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.
package google.registry.persistence;
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.collect.ImmutableList;
import java.util.Properties;
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
/** Utility class that provides methods to manipulate persistence.xml file. */
public class PersistenceXmlUtility {
private PersistenceXmlUtility() {}
/**
* Returns the {@link ParsedPersistenceXmlDescriptor} instance constructed from persistence.xml.
*/
public static ParsedPersistenceXmlDescriptor getParsedPersistenceXmlDescriptor() {
return PersistenceXmlParser.locatePersistenceUnits(new Properties()).stream()
.filter(unit -> PersistenceModule.PERSISTENCE_UNIT_NAME.equals(unit.getName()))
.findFirst()
.orElseThrow(
() ->
new IllegalArgumentException(
String.format(
"Could not find persistence unit with name %s",
PersistenceModule.PERSISTENCE_UNIT_NAME)));
}
/** Returns all managed classes defined in persistence.xml. */
public static ImmutableList<Class> getManagedClasses() {
return getParsedPersistenceXmlDescriptor().getManagedClassNames().stream()
.map(
className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(
String.format(
"Could not load class with name %s present in persistence.xml", className),
e);
}
})
.collect(toImmutableList());
}
}
@@ -347,7 +347,7 @@ public class AuthenticatedRegistrarAccessor {
/** Exception thrown when the current user doesn't have access to the requested Registrar. */
public static class RegistrarAccessDeniedException extends Exception {
RegistrarAccessDeniedException(String message) {
public RegistrarAccessDeniedException(String message) {
super(message);
}
}
@@ -176,6 +176,10 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
this.completionTimestamp = toZonedDateTime(dateTime);
}
public boolean isVerified() {
return completionTimestamp != null;
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
@@ -72,7 +72,7 @@ final class CreateDomainCommand extends CreateOrUpdateDomainCommand
!force || forcePremiums,
"Forced creates on premium domain(s) require --force_premiums");
Money createCost = prices.getCreateCost();
currency = createCost.getCurrencyUnit().getCurrencyCode();
currency = createCost.getCurrencyUnit().getCode();
cost = createCost.multipliedBy(period).getAmount().toString();
System.out.printf(
"NOTE: %s is premium at %s per year; sending total cost for %d year(s) of %s %s.\n",
@@ -19,23 +19,11 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.annotations.VisibleForTesting;
import google.registry.persistence.NomulusNamingStrategy;
import google.registry.persistence.NomulusPostgreSQLDialect;
import google.registry.persistence.PersistenceModule;
import google.registry.persistence.HibernateSchemaExporter;
import google.registry.persistence.PersistenceXmlUtility;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
import org.testcontainers.containers.PostgreSQLContainer;
/**
@@ -47,6 +35,9 @@ import org.testcontainers.containers.PostgreSQLContainer;
*/
@Parameters(separators = " =", commandDescription = "Generate PostgreSQL schema.")
public class GenerateSqlSchemaCommand implements Command {
private static final String DB_NAME = "postgres";
private static final String DB_USERNAME = "postgres";
private static final String DB_PASSWORD = "domain-registry";
@VisibleForTesting
public static final String DB_OPTIONS_CLASH =
@@ -91,10 +82,11 @@ public class GenerateSqlSchemaCommand implements Command {
}
// Start the container and store the address information.
postgresContainer = new PostgreSQLContainer()
.withDatabaseName("postgres")
.withUsername("postgres")
.withPassword("domain-registry");
postgresContainer =
new PostgreSQLContainer()
.withDatabaseName(DB_NAME)
.withUsername(DB_USERNAME)
.withPassword(DB_PASSWORD);
postgresContainer.start();
databaseHost = postgresContainer.getContainerIpAddress();
databasePort = postgresContainer.getMappedPort(POSTGRESQL_PORT);
@@ -119,29 +111,7 @@ public class GenerateSqlSchemaCommand implements Command {
}
try {
// Configure Hibernate settings.
Map<String, String> settings = new HashMap<>();
settings.put("hibernate.dialect", NomulusPostgreSQLDialect.class.getName());
settings.put(
"hibernate.connection.url",
"jdbc:postgresql://" + databaseHost + ":" + databasePort + "/postgres?useSSL=false");
settings.put("hibernate.connection.username", "postgres");
settings.put("hibernate.connection.password", "domain-registry");
settings.put("hibernate.hbm2ddl.auto", "none");
settings.put("show_sql", "true");
settings.put(
Environment.PHYSICAL_NAMING_STRATEGY, NomulusNamingStrategy.class.getCanonicalName());
MetadataSources metadata =
new MetadataSources(new StandardServiceRegistryBuilder().applySettings(settings).build());
addAnnotatedClasses(metadata, settings);
SchemaExport schemaExport = new SchemaExport();
schemaExport.setHaltOnError(true);
schemaExport.setFormat(true);
schemaExport.setDelimiter(";");
schemaExport.setOutputFile(outFile);
File outputFile = new File(outFile);
// Generate the copyright header (this file gets checked for copyright). The schema exporter
// appends to the existing file, so this has the additional desired effect of clearing any
@@ -161,44 +131,30 @@ public class GenerateSqlSchemaCommand implements Command {
+ "-- See the License for the specific language governing permissions and\n"
+ "-- limitations under the License.\n";
try {
Files.write(Paths.get(outFile), copyright.getBytes(UTF_8));
Files.write(outputFile.toPath(), copyright.getBytes(UTF_8));
} catch (IOException e) {
System.err.println("Error writing sql file: " + e);
e.printStackTrace();
System.exit(1);
}
schemaExport.createOnly(EnumSet.of(TargetType.SCRIPT), metadata.buildMetadata());
HibernateSchemaExporter exporter =
HibernateSchemaExporter.create(
"jdbc:postgresql://"
+ databaseHost
+ ":"
+ databasePort
+ "/"
+ DB_NAME
+ "?useSSL=false",
DB_USERNAME,
DB_PASSWORD);
exporter.export(PersistenceXmlUtility.getManagedClasses(), outputFile);
} finally {
if (postgresContainer != null) {
postgresContainer.stop();
}
}
}
private void addAnnotatedClasses(MetadataSources metadata, Map<String, String> settings) {
ParsedPersistenceXmlDescriptor descriptor =
PersistenceXmlParser.locatePersistenceUnits(settings).stream()
.filter(unit -> PersistenceModule.PERSISTENCE_UNIT_NAME.equals(unit.getName()))
.findFirst()
.orElseThrow(
() ->
new IllegalArgumentException(
String.format(
"Could not find persistence unit with name %s",
PersistenceModule.PERSISTENCE_UNIT_NAME)));
List<String> classNames = descriptor.getManagedClassNames();
for (String className : classNames) {
try {
Class<?> clazz = Class.forName(className);
metadata.addAnnotatedClass(clazz);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(
String.format(
"Could not load class with name %s present in persistence.xml", className),
e);
}
}
}
}
@@ -19,6 +19,7 @@ import static com.google.common.io.Resources.asCharSource;
import static com.google.common.io.Resources.getResource;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
@@ -42,6 +43,12 @@ import java.util.Map;
/** Helper methods for rendering Soy templates from Java code. */
public final class SoyTemplateUtils {
@VisibleForTesting
public static final Supplier<SoyCssRenamingMap> CSS_RENAMING_MAP_SUPPLIER =
SoyTemplateUtils.createCssRenamingMapSupplier(
Resources.getResource("google/registry/ui/css/registrar_bin.css.js"),
Resources.getResource("google/registry/ui/css/registrar_dbg.css.js"));
/** Returns a memoized supplier containing compiled tofu. */
public static Supplier<SoyTofu> createTofuSupplier(final SoyFileInfo... soyInfos) {
return memoize(
@@ -15,45 +15,30 @@
package google.registry.ui.server.registrar;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
import static google.registry.config.RegistryEnvironment.PRODUCTION;
import static google.registry.ui.server.SoyTemplateUtils.CSS_RENAMING_MAP_SUPPLIER;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Ascii;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.Resources;
import com.google.common.net.MediaType;
import com.google.template.soy.shared.SoyCssRenamingMap;
import com.google.template.soy.tofu.SoyTofu;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.model.OteAccountBuilder;
import google.registry.request.Action;
import google.registry.request.Action.Method;
import google.registry.request.Parameter;
import google.registry.request.RequestMethod;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.security.XsrfTokenManager;
import google.registry.ui.server.SendEmailUtils;
import google.registry.ui.server.SoyTemplateUtils;
import google.registry.ui.soy.registrar.OteSetupConsoleSoyInfo;
import google.registry.util.StringGenerator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
/**
* Action that serves OT&amp;E setup web page.
@@ -69,14 +54,9 @@ import javax.servlet.http.HttpServletRequest;
path = ConsoleOteSetupAction.PATH,
method = {Method.POST, Method.GET},
auth = Auth.AUTH_PUBLIC)
public final class ConsoleOteSetupAction implements Runnable {
public final class ConsoleOteSetupAction extends HtmlAction {
public static final String PATH = "/registrar-ote-setup";
@VisibleForTesting // webdriver and screenshot tests need this
public static final Supplier<SoyCssRenamingMap> CSS_RENAMING_MAP_SUPPLIER =
SoyTemplateUtils.createCssRenamingMapSupplier(
Resources.getResource("google/registry/ui/css/registrar_bin.css.js"),
Resources.getResource("google/registry/ui/css/registrar_dbg.css.js"));
private static final int PASSWORD_LENGTH = 16;
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Supplier<SoyTofu> TOFU_SUPPLIER =
@@ -85,27 +65,10 @@ public final class ConsoleOteSetupAction implements Runnable {
google.registry.ui.soy.FormsSoyInfo.getInstance(),
google.registry.ui.soy.AnalyticsSoyInfo.getInstance(),
google.registry.ui.soy.registrar.OteSetupConsoleSoyInfo.getInstance());
@Inject HttpServletRequest req;
@Inject @RequestMethod Method method;
@Inject Response response;
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
@Inject UserService userService;
@Inject XsrfTokenManager xsrfTokenManager;
@Inject AuthResult authResult;
@Inject SendEmailUtils sendEmailUtils;
@Inject
@Config("logoFilename")
String logoFilename;
@Inject
@Config("productName")
String productName;
@Inject
@Config("analyticsConfig")
Map<String, Object> analyticsConfig;
@Inject
@Named("base58StringGenerator")
StringGenerator passwordGenerator;
@@ -126,43 +89,9 @@ public final class ConsoleOteSetupAction implements Runnable {
ConsoleOteSetupAction() {}
@Override
public void run() {
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
logger.atInfo().log(
"User %s is accessing the OT&E setup page. Method= %s",
registrarAccessor.userIdForLogging(), method);
public void runAfterLogin(HashMap<String, Object> data) {
checkState(
!RegistryEnvironment.get().equals(PRODUCTION), "Can't create OT&E in prod");
if (!authResult.userAuthInfo().isPresent()) {
response.setStatus(SC_MOVED_TEMPORARILY);
String location;
try {
location = userService.createLoginURL(req.getRequestURI());
} catch (IllegalArgumentException e) {
// UserServiceImpl.createLoginURL() throws IllegalArgumentException if underlying API call
// returns an error code of NOT_ALLOWED. createLoginURL() assumes that the error is caused
// by an invalid URL. But in fact, the error can also occur if UserService doesn't have any
// user information, which happens when the request has been authenticated as internal. In
// this case, we want to avoid dying before we can send the redirect, so just redirect to
// the root path.
location = "/";
}
response.setHeader(LOCATION, location);
return;
}
User user = authResult.userAuthInfo().get().user();
// Using HashMap to allow null values
HashMap<String, Object> data = new HashMap<>();
data.put("logoFilename", logoFilename);
data.put("productName", productName);
data.put("username", user.getNickname());
data.put("logoutUrl", userService.createLogoutURL(PATH));
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
data.put("analyticsConfig", analyticsConfig);
response.setContentType(MediaType.HTML_UTF_8);
if (!registrarAccessor.isAdmin()) {
response.setStatus(SC_FORBIDDEN);
@@ -187,6 +116,11 @@ public final class ConsoleOteSetupAction implements Runnable {
}
}
@Override
public String getPath() {
return PATH;
}
private void runPost(HashMap<String, Object> data) {
try {
checkState(clientId.isPresent() && email.isPresent(), "Must supply clientId and email");
@@ -18,27 +18,18 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
import static google.registry.model.common.GaeUserIdConverter.convertEmailAddressToGaeUserId;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.transaction.TransactionManagerFactory.tm;
import static google.registry.ui.server.SoyTemplateUtils.CSS_RENAMING_MAP_SUPPLIER;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Ascii;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.Resources;
import com.google.common.net.MediaType;
import com.google.template.soy.shared.SoyCssRenamingMap;
import com.google.template.soy.tofu.SoyTofu;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
@@ -46,23 +37,17 @@ import google.registry.model.registrar.RegistrarContact;
import google.registry.request.Action;
import google.registry.request.Action.Method;
import google.registry.request.Parameter;
import google.registry.request.RequestMethod;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.security.XsrfTokenManager;
import google.registry.ui.server.SendEmailUtils;
import google.registry.ui.server.SoyTemplateUtils;
import google.registry.ui.soy.registrar.RegistrarCreateConsoleSoyInfo;
import google.registry.util.StringGenerator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import org.joda.money.CurrencyUnit;
/**
@@ -79,7 +64,7 @@ import org.joda.money.CurrencyUnit;
path = ConsoleRegistrarCreatorAction.PATH,
method = {Method.POST, Method.GET},
auth = Auth.AUTH_PUBLIC)
public final class ConsoleRegistrarCreatorAction implements Runnable {
public final class ConsoleRegistrarCreatorAction extends HtmlAction {
private static final int PASSWORD_LENGTH = 16;
private static final int PASSCODE_LENGTH = 5;
@@ -95,23 +80,8 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
google.registry.ui.soy.AnalyticsSoyInfo.getInstance(),
google.registry.ui.soy.registrar.RegistrarCreateConsoleSoyInfo.getInstance());
@VisibleForTesting // webdriver and screenshot tests need this
public static final Supplier<SoyCssRenamingMap> CSS_RENAMING_MAP_SUPPLIER =
SoyTemplateUtils.createCssRenamingMapSupplier(
Resources.getResource("google/registry/ui/css/registrar_bin.css.js"),
Resources.getResource("google/registry/ui/css/registrar_dbg.css.js"));
@Inject HttpServletRequest req;
@Inject @RequestMethod Method method;
@Inject Response response;
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
@Inject UserService userService;
@Inject XsrfTokenManager xsrfTokenManager;
@Inject AuthResult authResult;
@Inject SendEmailUtils sendEmailUtils;
@Inject @Config("logoFilename") String logoFilename;
@Inject @Config("productName") String productName;
@Inject @Config("analyticsConfig") Map<String, Object> analyticsConfig;
@Inject @Named("base58StringGenerator") StringGenerator passwordGenerator;
@Inject @Named("digitOnlyStringGenerator") StringGenerator passcodeGenerator;
@Inject @Parameter("clientId") Optional<String> clientId;
@@ -137,42 +107,7 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
@Inject ConsoleRegistrarCreatorAction() {}
@Override
public void run() {
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
logger.atInfo().log(
"User %s is accessing the Registrar creation page. Method= %s",
registrarAccessor.userIdForLogging(), method);
if (!authResult.userAuthInfo().isPresent()) {
response.setStatus(SC_MOVED_TEMPORARILY);
String location;
try {
location = userService.createLoginURL(req.getRequestURI());
} catch (IllegalArgumentException e) {
// UserServiceImpl.createLoginURL() throws IllegalArgumentException if underlying API call
// returns an error code of NOT_ALLOWED. createLoginURL() assumes that the error is caused
// by an invalid URL. But in fact, the error can also occur if UserService doesn't have any
// user information, which happens when the request has been authenticated as internal. In
// this case, we want to avoid dying before we can send the redirect, so just redirect to
// the root path.
location = "/";
}
response.setHeader(LOCATION, location);
return;
}
User user = authResult.userAuthInfo().get().user();
// Using HashMap to allow null values
HashMap<String, Object> data = new HashMap<>();
data.put("logoFilename", logoFilename);
data.put("productName", productName);
data.put("username", user.getNickname());
data.put("logoutUrl", userService.createLogoutURL(PATH));
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
data.put("analyticsConfig", analyticsConfig);
response.setContentType(MediaType.HTML_UTF_8);
public void runAfterLogin(HashMap<String, Object> data) {
if (!registrarAccessor.isAdmin()) {
response.setStatus(SC_FORBIDDEN);
response.setPayload(
@@ -196,6 +131,11 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
}
}
@Override
public String getPath() {
return PATH;
}
private void checkPresent(Optional<?> value, String name) {
checkState(value.isPresent(), "Missing value for %s", name);
}
@@ -226,7 +166,6 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
private void runPost(HashMap<String, Object> data) {
try {
checkPresent(clientId, "clientId");
checkPresent(name, "name");
checkPresent(billingAccount, "billingAccount");
@@ -321,11 +260,11 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
data.put("errorMessage", e.getMessage());
response.setPayload(
TOFU_SUPPLIER
.get()
.newRenderer(RegistrarCreateConsoleSoyInfo.FORM_PAGE)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.render());
.get()
.newRenderer(RegistrarCreateConsoleSoyInfo.FORM_PAGE)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.render());
}
}
@@ -357,8 +296,8 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
String environment = Ascii.toLowerCase(String.valueOf(RegistryEnvironment.get()));
String body =
String.format(
"The following registrar was created in %s by %s:\n",
environment, registrarAccessor.userIdForLogging())
"The following registrar was created in %s by %s:\n",
environment, registrarAccessor.userIdForLogging())
+ toEmailLine(clientId, "clientId")
+ toEmailLine(name, "name")
+ toEmailLine(billingAccount, "billingAccount")
@@ -14,47 +14,35 @@
package google.registry.ui.server.registrar;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.ADMIN;
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.OWNER;
import static google.registry.ui.server.SoyTemplateUtils.CSS_RENAMING_MAP_SUPPLIER;
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.Resources;
import com.google.common.net.MediaType;
import com.google.template.soy.data.SoyMapData;
import com.google.template.soy.shared.SoyCssRenamingMap;
import com.google.template.soy.tofu.SoyTofu;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.request.Action;
import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.Role;
import google.registry.security.XsrfTokenManager;
import google.registry.ui.server.SoyTemplateUtils;
import google.registry.ui.soy.registrar.ConsoleSoyInfo;
import java.util.Map;
import java.util.HashMap;
import java.util.Optional;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
/** Action that serves Registrar Console single HTML page (SPA). */
@Action(service = Action.Service.DEFAULT, path = ConsoleUiAction.PATH, auth = Auth.AUTH_PUBLIC)
public final class ConsoleUiAction implements Runnable {
public final class ConsoleUiAction extends HtmlAction {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -66,27 +54,8 @@ public final class ConsoleUiAction implements Runnable {
google.registry.ui.soy.registrar.ConsoleSoyInfo.getInstance(),
google.registry.ui.soy.AnalyticsSoyInfo.getInstance());
@VisibleForTesting // webdriver and screenshot tests need this
public static final Supplier<SoyCssRenamingMap> CSS_RENAMING_MAP_SUPPLIER =
SoyTemplateUtils.createCssRenamingMapSupplier(
Resources.getResource("google/registry/ui/css/registrar_bin.css.js"),
Resources.getResource("google/registry/ui/css/registrar_dbg.css.js"));
@Inject HttpServletRequest req;
@Inject Response response;
@Inject RegistrarConsoleMetrics registrarConsoleMetrics;
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
@Inject UserService userService;
@Inject XsrfTokenManager xsrfTokenManager;
@Inject AuthResult authResult;
@Inject
@Config("logoFilename")
String logoFilename;
@Inject
@Config("productName")
String productName;
@Inject
@Config("integrationEmail")
@@ -112,10 +81,6 @@ public final class ConsoleUiAction implements Runnable {
@Config("registrarConsoleEnabled")
boolean enabled;
@Inject
@Config("analyticsConfig")
Map<String, Object> analyticsConfig;
@Inject
@Parameter(PARAM_CLIENT_ID)
Optional<String> paramClientId;
@@ -124,37 +89,15 @@ public final class ConsoleUiAction implements Runnable {
ConsoleUiAction() {}
@Override
public void run() {
if (!authResult.userAuthInfo().isPresent()) {
response.setStatus(SC_MOVED_TEMPORARILY);
String location;
try {
location = userService.createLoginURL(req.getRequestURI());
} catch (IllegalArgumentException e) {
// UserServiceImpl.createLoginURL() throws IllegalArgumentException if underlying API call
// returns an error code of NOT_ALLOWED. createLoginURL() assumes that the error is caused
// by an invalid URL. But in fact, the error can also occur if UserService doesn't have any
// user information, which happens when the request has been authenticated as internal. In
// this case, we want to avoid dying before we can send the redirect, so just redirect to
// the root path.
location = "/";
}
response.setHeader(LOCATION, location);
return;
}
User user = authResult.userAuthInfo().get().user();
response.setContentType(MediaType.HTML_UTF_8);
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
SoyMapData data = new SoyMapData();
data.put("logoFilename", logoFilename);
data.put("productName", productName);
data.put("integrationEmail", integrationEmail);
data.put("supportEmail", supportEmail);
data.put("announcementsEmail", announcementsEmail);
data.put("supportPhoneNumber", supportPhoneNumber);
data.put("technicalDocsUrl", technicalDocsUrl);
data.put("analyticsConfig", analyticsConfig);
public void runAfterLogin(HashMap<String, Object> data) {
SoyMapData soyMapData = new SoyMapData();
data.forEach((key, value) -> soyMapData.put(key, value));
soyMapData.put("integrationEmail", integrationEmail);
soyMapData.put("supportEmail", supportEmail);
soyMapData.put("announcementsEmail", announcementsEmail);
soyMapData.put("supportPhoneNumber", supportPhoneNumber);
soyMapData.put("technicalDocsUrl", technicalDocsUrl);
if (!enabled) {
response.setStatus(SC_SERVICE_UNAVAILABLE);
response.setPayload(
@@ -162,23 +105,20 @@ public final class ConsoleUiAction implements Runnable {
.get()
.newRenderer(ConsoleSoyInfo.DISABLED)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.setData(soyMapData)
.render());
return;
}
data.put("username", user.getNickname());
data.put("logoutUrl", userService.createLogoutURL(PATH));
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
ImmutableSetMultimap<String, Role> roleMap = registrarAccessor.getAllClientIdWithRoles();
data.put("allClientIds", roleMap.keySet());
data.put("environment", RegistryEnvironment.get().toString());
soyMapData.put("allClientIds", roleMap.keySet());
soyMapData.put("environment", RegistryEnvironment.get().toString());
// We set the initial value to the value that will show if guessClientId throws.
String clientId = "<null>";
try {
clientId = paramClientId.orElse(registrarAccessor.guessClientId());
data.put("clientId", clientId);
data.put("isOwner", roleMap.containsEntry(clientId, OWNER));
data.put("isAdmin", roleMap.containsEntry(clientId, ADMIN));
soyMapData.put("clientId", clientId);
soyMapData.put("isOwner", roleMap.containsEntry(clientId, OWNER));
soyMapData.put("isAdmin", roleMap.containsEntry(clientId, ADMIN));
// We want to load the registrar even if we won't use it later (even if we remove the
// requireFeeExtension) - to make sure the user indeed has access to the guessed registrar.
@@ -197,7 +137,7 @@ public final class ConsoleUiAction implements Runnable {
.get()
.newRenderer(ConsoleSoyInfo.WHOAREYOU)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.setData(soyMapData)
.render());
registrarConsoleMetrics.registerConsoleRequest(
clientId, paramClientId.isPresent(), roleMap.get(clientId), "FORBIDDEN");
@@ -213,10 +153,15 @@ public final class ConsoleUiAction implements Runnable {
.get()
.newRenderer(ConsoleSoyInfo.MAIN)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.setData(soyMapData)
.render();
response.setPayload(payload);
registrarConsoleMetrics.registerConsoleRequest(
clientId, paramClientId.isPresent(), roleMap.get(clientId), "SUCCESS");
}
@Override
public String getPath() {
return PATH;
}
}
@@ -0,0 +1,109 @@
// 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.
package google.registry.ui.server.registrar;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.Config;
import google.registry.request.Action;
import google.registry.request.RequestMethod;
import google.registry.request.Response;
import google.registry.request.auth.AuthResult;
import google.registry.security.XsrfTokenManager;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
/**
* Handles some of the nitty-gritty of responding to requests that should return HTML, including
* login, redirects, analytics, and some headers.
*
* If the user is not logged in, this will redirect to the login URL.
*/
public abstract class HtmlAction implements Runnable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Inject HttpServletRequest req;
@Inject Response response;
@Inject UserService userService;
@Inject XsrfTokenManager xsrfTokenManager;
@Inject AuthResult authResult;
@Inject @RequestMethod Action.Method method;
@Inject
@Config("logoFilename")
String logoFilename;
@Inject
@Config("productName")
String productName;
@Inject
@Config("analyticsConfig")
Map<String, Object> analyticsConfig;
@Override
public void run() {
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
if (!authResult.userAuthInfo().isPresent()) {
response.setStatus(SC_MOVED_TEMPORARILY);
String location;
try {
location = userService.createLoginURL(req.getRequestURI());
} catch (IllegalArgumentException e) {
// UserServiceImpl.createLoginURL() throws IllegalArgumentException if underlying API call
// returns an error code of NOT_ALLOWED. createLoginURL() assumes that the error is caused
// by an invalid URL. But in fact, the error can also occur if UserService doesn't have any
// user information, which happens when the request has been authenticated as internal. In
// this case, we want to avoid dying before we can send the redirect, so just redirect to
// the root path.
location = "/";
}
response.setHeader(LOCATION, location);
return;
}
response.setContentType(MediaType.HTML_UTF_8);
User user = authResult.userAuthInfo().get().user();
// Using HashMap to allow null values
HashMap<String, Object> data = new HashMap<>();
data.put("logoFilename", logoFilename);
data.put("productName", productName);
data.put("username", user.getNickname());
data.put("logoutUrl", userService.createLogoutURL(getPath()));
data.put("analyticsConfig", analyticsConfig);
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
logger.atInfo().log(
"User %s is accessing %s. Method= %s",
authResult.userIdForLogging(), getClass().getName(), method);
runAfterLogin(data);
}
public abstract void runAfterLogin(HashMap<String, Object> data);
public abstract String getPath();
}
@@ -0,0 +1,21 @@
// 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.
package google.registry.ui.server.registrar;
/**
* Marker interface for {@link google.registry.request.Action}s that serve GET requests and return
* JSON, rather than HTML.
*/
public interface JsonGetAction extends Runnable {}
@@ -0,0 +1,168 @@
// 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.
package google.registry.ui.server.registrar;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import com.google.appengine.api.users.User;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import com.google.gson.Gson;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarContact;
import google.registry.model.registry.RegistryLockDao;
import google.registry.request.Action;
import google.registry.request.Action.Method;
import google.registry.request.Parameter;
import google.registry.request.RequestMethod;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
import google.registry.request.auth.UserAuthInfo;
import google.registry.schema.domain.RegistryLock;
import google.registry.security.JsonResponseHelper;
import java.util.Optional;
import javax.inject.Inject;
import org.joda.time.DateTime;
/**
* Servlet that allows for getting locks for a particular registrar.
*
* <p>Note: at the moment we have no mechanism for JSON GET/POSTs in the same class or at the same
* URL, which is why this is distinct from the {@link RegistryLockPostAction}.
*/
@Action(
service = Action.Service.DEFAULT,
path = RegistryLockGetAction.PATH,
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public final class RegistryLockGetAction implements JsonGetAction {
public static final String PATH = "/registry-lock-get";
private static final String LOCK_ENABLED_FOR_CONTACT_PARAM = "lockEnabledForContact";
private static final String EMAIL_PARAM = "email";
private static final String LOCKS_PARAM = "locks";
private static final String FULLY_QUALIFIED_DOMAIN_NAME_PARAM = "fullyQualifiedDomainName";
private static final String LOCKED_TIME_PARAM = "lockedTime";
private static final String LOCKED_BY_PARAM = "lockedBy";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Gson GSON = new Gson();
@VisibleForTesting Method method;
private final Response response;
private final AuthenticatedRegistrarAccessor registrarAccessor;
@VisibleForTesting AuthResult authResult;
@VisibleForTesting Optional<String> paramClientId;
@Inject
RegistryLockGetAction(
@RequestMethod Method method,
Response response,
AuthenticatedRegistrarAccessor registrarAccessor,
AuthResult authResult,
@Parameter(PARAM_CLIENT_ID) Optional<String> paramClientId) {
this.method = method;
this.response = response;
this.registrarAccessor = registrarAccessor;
this.authResult = authResult;
this.paramClientId = paramClientId;
}
@Override
public void run() {
checkArgument(Method.GET.equals(method), "Only GET requests allowed");
checkArgument(authResult.userAuthInfo().isPresent(), "User auth info must be present");
checkArgument(paramClientId.isPresent(), "clientId must be present");
response.setContentType(MediaType.JSON_UTF_8);
try {
ImmutableMap<String, ?> resultMap = getLockedDomainsMap(paramClientId.get());
ImmutableMap<String, ?> payload =
JsonResponseHelper.create(SUCCESS, "Successful locks retrieval", resultMap);
response.setPayload(GSON.toJson(payload));
} catch (RegistrarAccessDeniedException e) {
logger.atWarning().withCause(e).log(
"User %s doesn't have access to this registrar", authResult.userIdForLogging());
response.setStatus(SC_FORBIDDEN);
} catch (Exception e) {
logger.atWarning().withCause(e).log("Unexpected error when retrieving locks for a registrar");
response.setStatus(SC_INTERNAL_SERVER_ERROR);
}
}
private ImmutableMap<String, ?> getLockedDomainsMap(String clientId)
throws RegistrarAccessDeniedException {
// Note: admins always have access to the locks page
checkArgument(authResult.userAuthInfo().isPresent(), "User auth info must be present");
UserAuthInfo userAuthInfo = authResult.userAuthInfo().get();
boolean isAdmin = userAuthInfo.isUserAdmin();
Registrar registrar = getRegistrarAndVerifyLockAccess(clientId, isAdmin);
User user = userAuthInfo.user();
boolean isRegistryLockAllowed =
isAdmin
|| registrar.getContacts().stream()
.filter(contact -> contact.getEmailAddress().equals(user.getEmail()))
.findFirst()
.map(RegistrarContact::isRegistryLockAllowed)
.orElse(false);
return ImmutableMap.of(
LOCK_ENABLED_FOR_CONTACT_PARAM,
isRegistryLockAllowed,
EMAIL_PARAM,
user.getEmail(),
PARAM_CLIENT_ID,
registrar.getClientId(),
LOCKS_PARAM,
getLockedDomains(clientId));
}
private Registrar getRegistrarAndVerifyLockAccess(String clientId, boolean isAdmin)
throws RegistrarAccessDeniedException {
Registrar registrar = registrarAccessor.getRegistrar(clientId);
checkArgument(
isAdmin || registrar.isRegistryLockAllowed(),
"Registry lock not allowed for this registrar");
return registrar;
}
private ImmutableList<ImmutableMap<String, ?>> getLockedDomains(String clientId) {
ImmutableList<RegistryLock> locks =
RegistryLockDao.getByRegistrarId(clientId).stream()
.filter(RegistryLock::isVerified)
.collect(toImmutableList());
return locks.stream().map(this::lockToMap).collect(toImmutableList());
}
private ImmutableMap<String, ?> lockToMap(RegistryLock lock) {
return ImmutableMap.of(
FULLY_QUALIFIED_DOMAIN_NAME_PARAM,
lock.getDomainName(),
LOCKED_TIME_PARAM,
lock.getCompletionTimestamp().map(DateTime::toString).orElse(""),
LOCKED_BY_PARAM,
lock.isSuperuser() ? "admin" : lock.getRegistrarPocId());
}
}
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
version="2.2">
<embeddable class="org.joda.money.Money" access="FIELD">
<attributes>
<embedded name="money" access="FIELD"/>
</attributes>
</embeddable>
<embeddable class="org.joda.money.BigMoney" access="FIELD">
<attributes>
<basic name="amount" access="FIELD"/>
<basic name="currency" access="FIELD"/>
</attributes>
</embeddable>
</entity-mappings>
@@ -36,6 +36,7 @@
<class>google.registry.persistence.BloomFilterConverter</class>
<class>google.registry.persistence.CreateAutoTimestampConverter</class>
<class>google.registry.persistence.CurrencyUnitConverter</class>
<class>google.registry.persistence.DateTimeConverter</class>
<class>google.registry.persistence.UpdateAutoTimestampConverter</class>
<class>google.registry.persistence.ZonedDateTimeConverter</class>
@@ -129,6 +129,7 @@ import google.registry.flows.domain.DomainFlowUtils.TrailingDashException;
import google.registry.flows.domain.DomainFlowUtils.UnexpectedClaimsNoticeException;
import google.registry.flows.domain.DomainFlowUtils.UnsupportedFeeAttributeException;
import google.registry.flows.domain.DomainFlowUtils.UnsupportedMarkTypeException;
import google.registry.flows.domain.DomainPricingLogic.AllocationTokenInvalidForPremiumNameException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotInPromotionException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForRegistrarException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException;
@@ -1227,9 +1228,9 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow,
.build());
clock.advanceOneMilli();
setEppInput("domain_create_premium_allocationtoken.xml");
assertThat(assertThrows(IllegalArgumentException.class, this::runFlow))
.hasMessageThat()
.isEqualTo("A nonzero discount code cannot be applied to premium domains");
assertAboutEppExceptions()
.that(assertThrows(AllocationTokenInvalidForPremiumNameException.class, this::runFlow))
.marshalsToXml();
}
@Test
@@ -120,6 +120,26 @@ public final class RegistryLockDaoTest {
assertThat(RegistryLockDao.getByRegistrarId("nonexistent")).isEmpty();
}
@Test
public void testLoad_byRepoId() {
RegistryLock completedLock =
createLock().asBuilder().setCompletionTimestamp(jpaTmRule.getTxnClock().nowUtc()).build();
RegistryLockDao.save(completedLock);
jpaTmRule.getTxnClock().advanceOneMilli();
RegistryLock inProgressLock = createLock();
RegistryLockDao.save(inProgressLock);
Optional<RegistryLock> mostRecent = RegistryLockDao.getMostRecentByRepoId("repoId");
assertThat(mostRecent.isPresent()).isTrue();
assertThat(mostRecent.get().isVerified()).isFalse();
}
@Test
public void testLoad_byRepoId_empty() {
assertThat(RegistryLockDao.getMostRecentByRepoId("nonexistent").isPresent()).isFalse();
}
private RegistryLock createLock() {
return new RegistryLock.Builder()
.setRepoId("repoId")
@@ -14,6 +14,7 @@
package google.registry.model.transaction;
import static com.google.common.truth.Truth.assertThat;
import static org.joda.time.DateTimeZone.UTC;
import static org.testcontainers.containers.PostgreSQLContainer.POSTGRESQL_PORT;
@@ -23,11 +24,20 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.io.Resources;
import google.registry.persistence.HibernateSchemaExporter;
import google.registry.persistence.PersistenceModule;
import google.registry.persistence.PersistenceXmlUtility;
import google.registry.testing.FakeClock;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -36,7 +46,6 @@ import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import org.hibernate.cfg.Environment;
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.joda.time.DateTime;
import org.junit.rules.ExternalResource;
@@ -52,8 +61,8 @@ import org.testcontainers.containers.PostgreSQLContainer;
* PostgreSQLContainer} to achieve test purpose.
*/
public class JpaTransactionManagerRule extends ExternalResource {
private static final String SCHEMA_GOLDEN_SQL = "sql/schema/nomulus.golden.sql";
private static final String DB_CLEANUP_SQL =
private static final String GOLDEN_SCHEMA_SQL_PATH = "sql/schema/nomulus.golden.sql";
private static final String DB_CLEANUP_SQL_PATH =
"google/registry/model/transaction/cleanup_database.sql";
private static final String MANAGEMENT_DB_NAME = "management";
private static final String POSTGRES_DB_NAME = "postgres";
@@ -65,6 +74,9 @@ public class JpaTransactionManagerRule extends ExternalResource {
private final ImmutableMap userProperties;
private static final JdbcDatabaseContainer database = create();
private static final HibernateSchemaExporter exporter =
HibernateSchemaExporter.create(
database.getJdbcUrl(), database.getUsername(), database.getPassword());
private EntityManagerFactory emf;
private JpaTransactionManager cachedTm;
@@ -86,8 +98,16 @@ public class JpaTransactionManagerRule extends ExternalResource {
@Override
public void before() throws Exception {
executeSql(MANAGEMENT_DB_NAME, DB_CLEANUP_SQL);
executeSql(POSTGRES_DB_NAME, initScriptPath);
executeSql(MANAGEMENT_DB_NAME, readSqlInClassPath(DB_CLEANUP_SQL_PATH));
executeSql(POSTGRES_DB_NAME, readSqlInClassPath(initScriptPath));
if (!extraEntityClasses.isEmpty()) {
File tempSqlFile = File.createTempFile("tempSqlFile", ".sql");
tempSqlFile.deleteOnExit();
exporter.export(extraEntityClasses, tempSqlFile);
executeSql(
POSTGRES_DB_NAME,
new String(Files.readAllBytes(tempSqlFile.toPath()), StandardCharsets.UTF_8));
}
ImmutableMap properties = PersistenceModule.providesDefaultDatabaseConfigs();
if (!userProperties.isEmpty()) {
@@ -96,7 +116,7 @@ public class JpaTransactionManagerRule extends ExternalResource {
builder.putAll(userProperties);
properties = builder.build();
}
assertNormalActiveConnection();
emf =
createEntityManagerFactory(
getJdbcUrlFor(POSTGRES_DB_NAME),
@@ -114,14 +134,45 @@ public class JpaTransactionManagerRule extends ExternalResource {
TransactionManagerFactory.jpaTm = cachedTm;
if (emf != null) {
emf.close();
emf = null;
}
cachedTm = null;
assertNormalActiveConnection();
}
private void executeSql(String dbName, String sqlScriptPath) {
try (Connection conn = createConnection(dbName)) {
String sqlScript = Resources.toString(Resources.getResource(sqlScriptPath), Charsets.UTF_8);
conn.createStatement().execute(sqlScript);
/**
* This function throws exception if it detects connection leak by checking the metadata table
* pg_stat_activity.
*/
private void assertNormalActiveConnection() {
try (Connection conn = createConnection(POSTGRES_DB_NAME);
Statement statement = conn.createStatement()) {
ResultSet rs =
statement.executeQuery(
"SELECT COUNT(1) FROM pg_stat_activity WHERE usename = '"
+ database.getUsername()
+ "'");
rs.next();
long activeConns = rs.getLong(1);
// There should be only 1 active connection which is executing this query
assertThat(activeConns).isEqualTo(1L);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static String readSqlInClassPath(String sqlScriptPath) {
try {
return Resources.toString(Resources.getResource(sqlScriptPath), Charsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void executeSql(String dbName, String sqlScript) {
try (Connection conn = createConnection(dbName);
Statement statement = conn.createStatement()) {
statement.execute(sqlScript);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -163,15 +214,7 @@ public class JpaTransactionManagerRule extends ExternalResource {
properties.put(Environment.PASS, password);
ParsedPersistenceXmlDescriptor descriptor =
PersistenceXmlParser.locatePersistenceUnits(properties).stream()
.filter(unit -> PersistenceModule.PERSISTENCE_UNIT_NAME.equals(unit.getName()))
.findFirst()
.orElseThrow(
() ->
new IllegalArgumentException(
String.format(
"Could not find persistence unit with name %s",
PersistenceModule.PERSISTENCE_UNIT_NAME)));
PersistenceXmlUtility.getParsedPersistenceXmlDescriptor();
extraEntityClasses.stream().map(Class::getName).forEach(descriptor::addClasses);
return Bootstrap.getEntityManagerFactoryBuilder(descriptor, properties).build();
@@ -212,7 +255,7 @@ public class JpaTransactionManagerRule extends ExternalResource {
/** Builds a {@link JpaTransactionManagerRule} instance. */
public JpaTransactionManagerRule build() {
if (initScript == null) {
initScript = SCHEMA_GOLDEN_SQL;
initScript = GOLDEN_SCHEMA_SQL_PATH;
}
return new JpaTransactionManagerRule(
initScript,
@@ -23,7 +23,6 @@ import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PersistenceException;
import org.hibernate.cfg.Environment;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,7 +36,6 @@ public class JpaTransactionManagerRuleTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
@@ -24,7 +24,6 @@ import google.registry.model.ImmutableObject;
import google.registry.model.transaction.JpaTransactionManagerRule;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.cfg.Environment;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,7 +37,6 @@ public class BloomFilterConverterTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
@@ -21,7 +21,6 @@ import google.registry.model.ImmutableObject;
import google.registry.model.transaction.JpaTransactionManagerRule;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.cfg.Environment;
import org.joda.time.DateTime;
import org.junit.Rule;
import org.junit.Test;
@@ -36,7 +35,6 @@ public class CreateAutoTimestampConverterTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
@@ -22,7 +22,6 @@ import google.registry.model.transaction.JpaTransactionManagerRule;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PersistenceException;
import org.hibernate.cfg.Environment;
import org.joda.money.CurrencyUnit;
import org.junit.Rule;
import org.junit.Test;
@@ -37,7 +36,6 @@ public class CurrencyUnitConverterTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
@@ -50,7 +48,8 @@ public class CurrencyUnitConverterTest {
() ->
jpaTm()
.getEntityManager()
.createNativeQuery("SELECT currency FROM TestEntity WHERE name = 'id'")
.createNativeQuery(
"SELECT currency FROM \"TestEntity\" WHERE name = 'id'")
.getResultList()))
.containsExactly("EUR");
TestEntity persisted =
@@ -66,7 +65,7 @@ public class CurrencyUnitConverterTest {
jpaTm()
.getEntityManager()
.createNativeQuery(
"INSERT INTO TestEntity (name, currency) VALUES('id', 'XXXX')")
"INSERT INTO \"TestEntity\" (name, currency) VALUES('id', 'XXXX')")
.executeUpdate());
PersistenceException thrown =
assertThrows(
@@ -0,0 +1,107 @@
// 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.
package google.registry.persistence;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
import google.registry.model.ImmutableObject;
import google.registry.model.transaction.JpaTransactionManagerRule;
import java.sql.Timestamp;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link DateTimeConverter}. */
@RunWith(JUnit4.class)
public class DateTimeConverterTest {
@Rule
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder().withEntityClass(TestEntity.class).build();
private final DateTimeConverter converter = new DateTimeConverter();
@Test
public void convertToDatabaseColumn_returnsNullIfInputIsNull() {
assertThat(converter.convertToDatabaseColumn(null)).isNull();
}
@Test
public void convertToDatabaseColumn_convertsCorrectly() {
DateTime dateTime = DateTime.parse("2019-09-01T01:01:01");
assertThat(converter.convertToDatabaseColumn(dateTime).getTime())
.isEqualTo(dateTime.getMillis());
}
@Test
public void convertToEntityAttribute_returnsNullIfInputIsNull() {
assertThat(converter.convertToEntityAttribute(null)).isNull();
}
@Test
public void convertToEntityAttribute_convertsCorrectly() {
DateTime dateTime = DateTime.parse("2019-09-01T01:01:01Z");
long millis = dateTime.getMillis();
assertThat(converter.convertToEntityAttribute(new Timestamp(millis))).isEqualTo(dateTime);
}
static DateTime parseDateTime(String value) {
return ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed().parseDateTime(value);
}
@Test
public void converter_generatesTimestampWithNormalizedZone() {
DateTime dt = parseDateTime("2019-09-01T01:01:01Z");
TestEntity entity = new TestEntity("normalized_utc_time", dt);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
TestEntity retrievedEntity =
jpaTm()
.transact(
() -> jpaTm().getEntityManager().find(TestEntity.class, "normalized_utc_time"));
assertThat(retrievedEntity.dt.toString()).isEqualTo("2019-09-01T01:01:01.000Z");
}
@Test
public void converter_convertsNonUtcZoneCorrectly() {
DateTime dt = parseDateTime("2019-09-01T01:01:01-05:00");
TestEntity entity = new TestEntity("new_york_time", dt);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
TestEntity retrievedEntity =
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "new_york_time"));
assertThat(retrievedEntity.dt.toString()).isEqualTo("2019-09-01T06:01:01.000Z");
}
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
private static class TestEntity extends ImmutableObject {
@Id String name;
DateTime dt;
public TestEntity() {}
TestEntity(String name, DateTime dt) {
this.name = name;
this.dt = dt;
}
}
}
@@ -0,0 +1,72 @@
// 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.
package google.registry.persistence;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.joda.money.CurrencyUnit;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.testcontainers.containers.PostgreSQLContainer;
/** Unit tests for {@link HibernateSchemaExporter}. */
@RunWith(JUnit4.class)
public class HibernateSchemaExporterTest {
@ClassRule public static final PostgreSQLContainer database = new PostgreSQLContainer();
private static HibernateSchemaExporter exporter;
@Rule public final TemporaryFolder tempFolder = new TemporaryFolder();
@BeforeClass
public static void init() {
exporter =
HibernateSchemaExporter.create(
database.getJdbcUrl(), database.getUsername(), database.getPassword());
}
@Test
public void export_succeeds() throws IOException {
File sqlFile = tempFolder.newFile();
exporter.export(ImmutableList.of(TestEntity.class), sqlFile);
assertThat(Files.readAllBytes(sqlFile.toPath()))
.isEqualTo(
("\n"
+ " create table \"TestEntity\" (\n"
+ " name text not null,\n"
+ " cu text,\n"
+ " primary key (name)\n"
+ " );\n")
.getBytes(StandardCharsets.UTF_8));
}
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
private static class TestEntity {
@Id String name;
CurrencyUnit cu;
}
}
@@ -0,0 +1,217 @@
// 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.
package google.registry.persistence;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
import com.google.common.collect.ImmutableMap;
import google.registry.model.ImmutableObject;
import google.registry.model.transaction.JpaTransactionManagerRule;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKeyColumn;
import javax.persistence.PostLoad;
import org.hibernate.cfg.Environment;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Unit tests for embeddable {@link Money}.
*
* <p>{@link Money} is a wrapper around {@link org.joda.money.BigMoney} which itself contains two
* fields: a {@link BigDecimal} {@code amount} and a {@link CurrencyUnit} {@code currency}. When we
* store an entity with a {@link Money} field, we would like to store it in two columns, for the
* amount and the currency separately, so that it is easily queryable. This requires that we make
* {@link Money} a nested embeddable object.
*
* <p>However becaues {@link Money} is not a class that we control, we cannot use annotation-based
* mapping. Therefore there is no {@code JodaMoneyConverter} class. Instead, we define the mapping
* in {@code META-INF/orm.xml}.
*
* <p>Also note that any entity that contains a {@link Money} should should implement a
* {@link @PostLoad} callback that converts the amount in the {@link Money} to a scale that is
* appropriate for the currency. This is espcially necessary for currencies like JPY where the scale
* is 0, which is different from the default scale that {@link BigDecimal} is persisted in database.
*/
@RunWith(JUnit4.class)
public class JodaMoneyConverterTest {
@Rule
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class, ComplexTestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
public void roundTripConversion() {
Money money = Money.of(CurrencyUnit.USD, 100);
TestEntity entity = new TestEntity(money);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
List<?> result =
jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT amount, currency FROM TestEntity WHERE name = 'id'")
.getResultList());
assertThat(result.size()).isEqualTo(1);
assertThat(Arrays.asList((Object[]) result.get(0)))
.containsExactly(
BigDecimal.valueOf(100).setScale(CurrencyUnit.USD.getDecimalPlaces()), "USD")
.inOrder();
TestEntity persisted =
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
assertThat(persisted.money).isEqualTo(money);
}
@Test
public void roundTripConversionWithComplexEntity() {
Money myMoney = Money.of(CurrencyUnit.USD, 100);
Money yourMoney = Money.of(CurrencyUnit.GBP, 80);
ImmutableMap<String, Money> moneyMap =
ImmutableMap.of(
"uno", Money.of(CurrencyUnit.EUR, 500),
"dos", Money.ofMajor(CurrencyUnit.JPY, 2000),
"tres", Money.of(CurrencyUnit.GBP, 20));
ComplexTestEntity entity = new ComplexTestEntity(moneyMap, myMoney, yourMoney);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
List<?> result =
jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT my_amount, my_currency, your_amount, your_currency FROM"
+ " ComplexTestEntity WHERE name = 'id'")
.getResultList());
assertThat(result.size()).isEqualTo(1);
assertThat(Arrays.asList((Object[]) result.get(0)))
.containsExactly(
BigDecimal.valueOf(100).setScale(2), "USD", BigDecimal.valueOf(80).setScale(2), "GBP")
.inOrder();
result =
jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT map_amount, map_currency FROM MoneyMap"
+ " WHERE entity_name = 'id' AND map_key = 'dos'")
.getResultList());
ComplexTestEntity persisted =
jpaTm().transact(() -> jpaTm().getEntityManager().find(ComplexTestEntity.class, "id"));
assertThat(result.size()).isEqualTo(1);
// Note that the amount has two decimal places even though JPY is supposed to have scale 0.
// This is due to the unfournate fact that we need to accommodate differet currencies stored
// in the same table so that the scale has to be set to the largest (2). When a Money field is
// persisted in an entity, the entity should always have a @PostLoad callback to convert the
// Money to the correct scale.
assertThat(Arrays.asList((Object[]) result.get(0)))
.containsExactly(BigDecimal.valueOf(2000).setScale(2), "JPY")
.inOrder();
// Make sure that the loaded entity contains the fields exactly as they are persisted.
assertThat(persisted.myMoney).isEqualTo(myMoney);
assertThat(persisted.yourMoney).isEqualTo(yourMoney);
assertThat(persisted.moneyMap).containsExactlyEntriesIn(moneyMap);
}
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
public static class TestEntity extends ImmutableObject {
@Id String name = "id";
Money money;
public TestEntity() {}
TestEntity(Money money) {
this.money = money;
}
}
@Entity(name = "ComplexTestEntity") // Override entity name to avoid the nested class reference.
// This entity is used to test column override for embedded fields and collections.
public static class ComplexTestEntity extends ImmutableObject {
// After the entity is loaded from the database, go through the money map and make sure that
// the scale is consistent with the currency. This is necessary for currency like JPY where
// the scale is 0 but the amount is persisteted as BigDecimal with scale 2.
@PostLoad
void setCurrencyScale() {
moneyMap
.entrySet()
.forEach(
entry -> {
Money money = entry.getValue();
if (!money.toBigMoney().isCurrencyScale()) {
CurrencyUnit currency = money.getCurrencyUnit();
BigDecimal amount = money.getAmount().setScale(currency.getDecimalPlaces());
entry.setValue(Money.of(currency, amount));
}
});
}
@Id String name = "id";
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "MoneyMap", joinColumns = @JoinColumn(name = "entity_name"))
@MapKeyColumn(name = "map_key")
@AttributeOverrides({
@AttributeOverride(name = "value.money.amount", column = @Column(name = "map_amount")),
@AttributeOverride(name = "value.money.currency", column = @Column(name = "map_currency"))
})
Map<String, Money> moneyMap;
@AttributeOverrides({
@AttributeOverride(name = "money.amount", column = @Column(name = "my_amount")),
@AttributeOverride(name = "money.currency", column = @Column(name = "my_currency"))
})
Money myMoney;
@AttributeOverrides({
@AttributeOverride(name = "money.amount", column = @Column(name = "your_amount")),
@AttributeOverride(name = "money.currency", column = @Column(name = "your_currency"))
})
Money yourMoney;
public ComplexTestEntity() {}
ComplexTestEntity(ImmutableMap<String, Money> moneyMap, Money myMoney, Money yourMoney) {
this.moneyMap = moneyMap;
this.myMoney = myMoney;
this.yourMoney = yourMoney;
}
}
}
@@ -21,7 +21,6 @@ import google.registry.model.UpdateAutoTimestamp;
import google.registry.model.transaction.JpaTransactionManagerRule;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.cfg.Environment;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,7 +34,6 @@ public class UpdateAutoTimestampConverterTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
@@ -24,7 +24,6 @@ import java.time.Instant;
import java.time.ZonedDateTime;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.cfg.Environment;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,7 +37,6 @@ public class ZonedDateTimeConverterTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
private final ZonedDateTimeConverter converter = new ZonedDateTimeConverter();
@@ -21,9 +21,12 @@ import google.registry.model.transaction.JpaTransactionManagerRuleTest;
import google.registry.persistence.BloomFilterConverterTest;
import google.registry.persistence.CreateAutoTimestampConverterTest;
import google.registry.persistence.CurrencyUnitConverterTest;
import google.registry.persistence.DateTimeConverterTest;
import google.registry.persistence.JodaMoneyConverterTest;
import google.registry.persistence.UpdateAutoTimestampConverterTest;
import google.registry.persistence.ZonedDateTimeConverterTest;
import google.registry.schema.tld.PremiumListDaoTest;
import google.registry.ui.server.registrar.RegistryLockGetActionTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@@ -44,10 +47,13 @@ import org.junit.runners.Suite.SuiteClasses;
ClaimsListDaoTest.class,
CreateAutoTimestampConverterTest.class,
CurrencyUnitConverterTest.class,
DateTimeConverterTest.class,
JodaMoneyConverterTest.class,
JpaTransactionManagerImplTest.class,
JpaTransactionManagerRuleTest.class,
PremiumListDaoTest.class,
RegistryLockDaoTest.class,
RegistryLockGetActionTest.class,
UpdateAutoTimestampConverterTest.class,
ZonedDateTimeConverterTest.class
})
@@ -82,7 +82,8 @@ public final class RegistryTestServer {
route("/registrar-create", FrontendServlet.class),
route("/registrar-ote-setup", FrontendServlet.class),
route("/registrar-ote-status", FrontendServlet.class),
route("/registrar-settings", FrontendServlet.class));
route("/registrar-settings", FrontendServlet.class),
route("/registry-lock-get", FrontendServlet.class));
private static final ImmutableList<Class<? extends Filter>> FILTERS = ImmutableList.of(
ObjectifyFilter.class,
@@ -19,6 +19,7 @@ import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.collect.ImmutableList;
import com.google.common.net.HostAndPort;
import google.registry.model.transaction.JpaTransactionManagerRule;
import google.registry.testing.AppEngineRule;
import google.registry.testing.UserInfo;
import google.registry.tools.params.HostAndPortParameter;
@@ -134,36 +135,44 @@ public final class RegistryTestServerMain {
LIGHT_PURPLE, ORANGE, PINK, RESET);
final RegistryTestServer server = new RegistryTestServer(address);
Statement runner = new Statement() {
@Override
public void evaluate() throws InterruptedException {
System.out.printf("%sLoading Datastore fixtures...%s\n", BLUE, RESET);
for (Fixture fixture : fixtures) {
fixture.load();
}
System.out.printf("%sStarting Jetty6 HTTP Server...%s\n", BLUE, RESET);
server.start();
System.out.printf("%sListening on: %s%s\n", PURPLE, server.getUrl("/"), RESET);
try {
while (true) {
server.process();
Statement runner =
new Statement() {
@Override
public void evaluate() throws InterruptedException {
System.out.printf("%sLoading Datastore fixtures...%s\n", BLUE, RESET);
for (Fixture fixture : fixtures) {
fixture.load();
}
System.out.printf("%sStarting Jetty6 HTTP Server...%s\n", BLUE, RESET);
server.start();
System.out.printf("%sListening on: %s%s\n", PURPLE, server.getUrl("/"), RESET);
try {
while (true) {
server.process();
}
} finally {
server.stop();
}
}
} finally {
server.stop();
}
}};
};
System.out.printf("%sLoading AppEngineRule...%s\n", BLUE, RESET);
AppEngineRule.builder()
.withDatastore()
.withUrlFetch()
.withTaskQueue()
.withLocalModules()
.withUserService(loginIsAdmin
? UserInfo.createAdmin(loginEmail, loginUserId)
: UserInfo.create(loginEmail, loginUserId))
Statement withAppEngine =
AppEngineRule.builder()
.withDatastore()
.withUrlFetch()
.withTaskQueue()
.withLocalModules()
.withUserService(
loginIsAdmin
? UserInfo.createAdmin(loginEmail, loginUserId)
: UserInfo.create(loginEmail, loginUserId))
.build()
.apply(runner, Description.EMPTY);
System.out.printf("%sLoading SQL fixtures and AppEngineRule...%s\n", BLUE, RESET);
new JpaTransactionManagerRule.Builder()
.build()
.apply(runner, Description.EMPTY)
.apply(withAppEngine, Description.EMPTY)
.evaluate();
}
@@ -0,0 +1,59 @@
// 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.
package google.registry.ui.server;
import static com.google.common.truth.Truth.assertWithMessage;
import com.google.common.collect.ImmutableSet;
import google.registry.request.Action;
import google.registry.request.JsonActionRunner;
import google.registry.ui.server.registrar.HtmlAction;
import google.registry.ui.server.registrar.JsonGetAction;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ScanResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class ActionMembershipTest {
@Test
public void testAllActionsEitherHtmlOrJson() {
// All UI actions should serve valid HTML or JSON. There are three valid options:
// 1. Extending HtmlAction to signal that we are serving an HTML page
// 2. Extending JsonAction to show that we are serving JSON POST requests
// 3. Extending JsonGetAction to serve JSON GET requests
ImmutableSet.Builder<String> failingClasses = new ImmutableSet.Builder<>();
try (ScanResult scanResult =
new ClassGraph().enableAnnotationInfo().whitelistPackages("google.registry.ui").scan()) {
scanResult
.getClassesWithAnnotation(Action.class.getName())
.forEach(
classInfo -> {
if (!classInfo.extendsSuperclass(HtmlAction.class.getName())
&& !classInfo.implementsInterface(JsonActionRunner.JsonAction.class.getName())
&& !classInfo.implementsInterface(JsonGetAction.class.getName())) {
failingClasses.add(classInfo.getName());
}
});
}
assertWithMessage(
"All UI actions must implement / extend HtmlAction, JsonGetAction, "
+ "or JsonActionRunner.JsonAction. Failing classes:")
.that(failingClasses.build())
.isEmpty();
}
}
@@ -28,6 +28,7 @@ import com.google.appengine.api.users.UserServiceFactory;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.net.MediaType;
import google.registry.request.Action.Method;
import google.registry.request.auth.AuthLevel;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
@@ -77,6 +78,7 @@ public class ConsoleUiActionTest {
action.registrarConsoleMetrics = new RegistrarConsoleMetrics();
action.userService = UserServiceFactory.getUserService();
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
action.method = Method.GET;
action.paramClientId = Optional.empty();
action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
action.analyticsConfig = ImmutableMap.of("googleAnalyticsId", "sampleId");
@@ -0,0 +1,256 @@
// 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.
package google.registry.ui.server.registrar;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.OWNER;
import static google.registry.testing.AppEngineRule.makeRegistrar2;
import static google.registry.testing.AppEngineRule.makeRegistrarContact3;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.JUnitBackports.assertThrows;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import com.google.api.client.http.HttpStatusCodes;
import com.google.appengine.api.users.User;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.gson.Gson;
import google.registry.model.registry.RegistryLockDao;
import google.registry.model.transaction.JpaTransactionManagerRule;
import google.registry.request.Action.Method;
import google.registry.request.auth.AuthLevel;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.UserAuthInfo;
import google.registry.schema.domain.RegistryLock;
import google.registry.schema.domain.RegistryLock.Action;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeResponse;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.joda.time.DateTime;
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.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
/** Unit tests for {@link RegistryLockGetAction}. */
@RunWith(JUnit4.class)
public final class RegistryLockGetActionTest {
private static final Gson GSON = new Gson();
@Rule public final AppEngineRule appEngineRule = AppEngineRule.builder().withDatastore().build();
@Rule
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder().build();
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
private final FakeResponse response = new FakeResponse();
private final User user = new User("Marla.Singer@crr.com", "gmail.com", "12345");
private AuthResult authResult;
private AuthenticatedRegistrarAccessor accessor;
private RegistryLockGetAction action;
@Before
public void setup() {
jpaTmRule.getTxnClock().setTo(DateTime.parse("2000-06-08T22:00:00.0Z"));
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
accessor =
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of(
"TheRegistrar", OWNER,
"NewRegistrar", OWNER));
action =
new RegistryLockGetAction(
Method.GET, response, accessor, authResult, Optional.of("TheRegistrar"));
}
@Test
public void testSuccess_retrievesLocks() {
RegistryLock regularLock =
new RegistryLock.Builder()
.setRepoId("repoId")
.setDomainName("example.test")
.setRegistrarId("TheRegistrar")
.setAction(Action.LOCK)
.setVerificationCode(UUID.randomUUID().toString())
.setRegistrarPocId("johndoe@theregistrar.com")
.setCompletionTimestamp(jpaTmRule.getTxnClock().nowUtc())
.build();
jpaTmRule.getTxnClock().advanceOneMilli();
RegistryLock adminLock =
new RegistryLock.Builder()
.setRepoId("repoId")
.setDomainName("adminexample.test")
.setRegistrarId("TheRegistrar")
.setAction(Action.LOCK)
.setVerificationCode(UUID.randomUUID().toString())
.isSuperuser(true)
.setCompletionTimestamp(jpaTmRule.getTxnClock().nowUtc())
.build();
RegistryLock incompleteLock =
new RegistryLock.Builder()
.setRepoId("repoId")
.setDomainName("incomplete.test")
.setRegistrarId("TheRegistrar")
.setAction(Action.LOCK)
.setVerificationCode(UUID.randomUUID().toString())
.setRegistrarPocId("johndoe@theregistrar.com")
.build();
RegistryLockDao.save(regularLock);
RegistryLockDao.save(adminLock);
RegistryLockDao.save(incompleteLock);
action.run();
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
assertThat(GSON.fromJson(response.getPayload(), Map.class))
.containsExactly(
"status", "SUCCESS",
"message", "Successful locks retrieval",
"results",
ImmutableList.of(
ImmutableMap.of(
"lockEnabledForContact", true,
"email", "Marla.Singer@crr.com",
"clientId", "TheRegistrar",
"locks",
ImmutableList.of(
ImmutableMap.of(
"fullyQualifiedDomainName", "example.test",
"lockedTime", "2000-06-08T22:00:00.000Z",
"lockedBy", "johndoe@theregistrar.com"),
ImmutableMap.of(
"fullyQualifiedDomainName", "adminexample.test",
"lockedTime", "2000-06-08T22:00:00.001Z",
"lockedBy", "admin")))));
}
@Test
public void testFailure_invalidMethod() {
action.method = Method.POST;
assertThat(assertThrows(IllegalArgumentException.class, action::run))
.hasMessageThat()
.isEqualTo("Only GET requests allowed");
}
@Test
public void testFailure_noAuthInfo() {
action.authResult = AuthResult.NOT_AUTHENTICATED;
assertThat(assertThrows(IllegalArgumentException.class, action::run))
.hasMessageThat()
.isEqualTo("User auth info must be present");
}
@Test
public void testFailure_noClientId() {
action.paramClientId = Optional.empty();
assertThat(assertThrows(IllegalArgumentException.class, action::run))
.hasMessageThat()
.isEqualTo("clientId must be present");
}
@Test
public void testFailure_noRegistrarAccess() {
accessor = AuthenticatedRegistrarAccessor.createForTesting(ImmutableSetMultimap.of());
action =
new RegistryLockGetAction(
Method.GET, response, accessor, authResult, Optional.of("TheRegistrar"));
action.run();
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
}
@Test
public void testSuccess_readOnlyAccessForOtherUsers() {
// If lock is not enabled for a user, this should be read-only
persistResource(
makeRegistrarContact3().asBuilder().setAllowedToSetRegistryLockPassword(true).build());
action.run();
assertThat(GSON.fromJson(response.getPayload(), Map.class).get("results"))
.isEqualTo(
ImmutableList.of(
ImmutableMap.of(
"lockEnabledForContact",
false,
"email",
"Marla.Singer@crr.com",
"clientId",
"TheRegistrar",
"locks",
ImmutableList.of())));
}
@Test
public void testSuccess_lockAllowedForAdmin() throws Exception {
// Locks are allowed for admins even when they're not enabled for the registrar
persistResource(makeRegistrar2().asBuilder().setRegistryLockAllowed(false).build());
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, true));
action =
new RegistryLockGetAction(
Method.GET, response, accessor, authResult, Optional.of("TheRegistrar"));
action.run();
assertThat(GSON.fromJson(response.getPayload(), Map.class).get("results"))
.isEqualTo(
ImmutableList.of(
ImmutableMap.of(
"lockEnabledForContact",
true,
"email",
"Marla.Singer@crr.com",
"clientId",
"TheRegistrar",
"locks",
ImmutableList.of())));
}
@Test
public void testFailure_lockNotAllowedForRegistrar() {
// The UI shouldn't be making requests where lock isn't enabled for this registrar
action =
new RegistryLockGetAction(
Method.GET, response, accessor, authResult, Optional.of("NewRegistrar"));
action.run();
assertThat(response.getStatus()).isEqualTo(SC_INTERNAL_SERVER_ERROR);
}
@Test
public void testFailure_accessDenied() {
accessor = AuthenticatedRegistrarAccessor.createForTesting(ImmutableSetMultimap.of());
action =
new RegistryLockGetAction(
Method.GET, response, accessor, authResult, Optional.of("TheRegistrar"));
action.run();
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
}
@Test
public void testFailure_badRegistrar() {
action =
new RegistryLockGetAction(
Method.GET, response, accessor, authResult, Optional.of("SomeBadRegistrar"));
action.run();
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
}
}
@@ -23,6 +23,7 @@ import static google.registry.util.NetworkUtils.pickUnusedPort;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.net.HostAndPort;
import google.registry.model.transaction.JpaTransactionManagerRule;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.server.Fixture;
import google.registry.server.Route;
@@ -53,6 +54,7 @@ public final class TestServerRule extends ExternalResource {
private final ImmutableList<Fixture> fixtures;
private final AppEngineRule appEngineRule;
private final JpaTransactionManagerRule jpaTransactionManagerRule;
private final BlockingQueue<FutureTask<?>> jobs = new LinkedBlockingDeque<>();
private final ImmutableMap<String, Path> runfiles;
private final ImmutableList<Route> routes;
@@ -80,6 +82,7 @@ public final class TestServerRule extends ExternalResource {
.withTaskQueue()
.withUserService(UserInfo.createAdmin(email, THE_REGISTRAR_GAE_USER_ID))
.build();
this.jpaTransactionManagerRule = new JpaTransactionManagerRule.Builder().build();
}
@Override
@@ -164,9 +167,8 @@ public final class TestServerRule extends ExternalResource {
@Override
public void run() {
try {
appEngineRule
.apply(this, Description.EMPTY)
.evaluate();
Statement appEngineStatement = appEngineRule.apply(this, Description.EMPTY);
jpaTransactionManagerRule.apply(appEngineStatement, Description.EMPTY).evaluate();
} catch (InterruptedException e) {
// This is what we expect to happen.
} catch (Throwable e) {
@@ -5,3 +5,4 @@ PATH CLASS METHODS OK AUTH_METHODS
/registrar-ote-setup ConsoleOteSetupAction POST,GET n INTERNAL,API,LEGACY NONE PUBLIC
/registrar-ote-status OteStatusAction POST n API,LEGACY USER PUBLIC
/registrar-settings RegistrarSettingsAction POST n API,LEGACY USER PUBLIC
/registry-lock-get RegistryLockGetAction GET n API,LEGACY USER PUBLIC
+3 -1
View File
@@ -161,10 +161,12 @@ dependencies {
testCompile deps['com.google.flogger:flogger']
testRuntime deps['com.google.flogger:flogger-system-backend']
testCompile deps['com.google.guava:guava']
testCompile deps['com.google.truth:truth']
testCompile deps['io.github.java-diff-utils:java-diff-utils']
testCompile deps['org.testcontainers:postgresql']
testCompile deps['junit:junit']
testCompile deps['org.testcontainers:postgresql']
testCompile deps['org.testcontainers:testcontainers']
testCompile project(':third_party')
}
@@ -3,16 +3,16 @@
# This file is expected to be part of source control.
antlr:antlr:2.7.7
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.2.0
com.google.errorprone:error_prone_annotations:2.3.2
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-jre
com.google.guava:guava:28.0-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.puppycrawl.tools:checkstyle:8.17
commons-beanutils:commons-beanutils:1.9.3
com.google.j2objc:j2objc-annotations:1.3
com.puppycrawl.tools:checkstyle:8.24
commons-beanutils:commons-beanutils:1.9.4
commons-collections:commons-collections:3.2.2
info.picocli:picocli:3.9.0
net.sf.saxon:Saxon-HE:9.9.0-2
info.picocli:picocli:4.0.3
net.sf.saxon:Saxon-HE:9.9.1-4
org.antlr:antlr4-runtime:4.7.2
org.checkerframework:checker-qual:2.5.2
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.17
@@ -1,4 +1,4 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.agent:0.8.5
@@ -1,11 +1,11 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.ant:0.8.4
org.jacoco:org.jacoco.core:0.8.4
org.jacoco:org.jacoco.report:0.8.4
org.ow2.asm:asm-analysis:7.1
org.ow2.asm:asm-commons:7.1
org.ow2.asm:asm-tree:7.1
org.ow2.asm:asm:7.1
org.jacoco:org.jacoco.agent:0.8.5
org.jacoco:org.jacoco.ant:0.8.5
org.jacoco:org.jacoco.core:0.8.5
org.jacoco:org.jacoco.report:0.8.5
org.ow2.asm:asm-analysis:7.2
org.ow2.asm:asm-commons:7.2
org.ow2.asm:asm-tree:7.2
org.ow2.asm:asm:7.2
@@ -3,12 +3,12 @@
# This file is expected to be part of source control.
com.google.auto.value:auto-value-annotations:1.6.3
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.1
com.google.errorprone:error_prone_annotations:2.3.2
com.google.flogger:flogger:0.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-android
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.0
com.googlecode.java-diff-utils:diffutils:1.3.0
com.kohlschutter.junixsocket:junixsocket-common:2.0.4
@@ -22,7 +22,8 @@ net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.commons:commons-compress:1.19
org.checkerframework:checker-compat-qual:2.5.5
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
org.flywaydb:flyway-core:5.2.4
org.hamcrest:hamcrest-core:1.3
@@ -3,12 +3,12 @@
# This file is expected to be part of source control.
com.google.auto.value:auto-value-annotations:1.6.3
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.1
com.google.errorprone:error_prone_annotations:2.3.2
com.google.flogger:flogger:0.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-android
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.0
com.googlecode.java-diff-utils:diffutils:1.3.0
com.kohlschutter.junixsocket:junixsocket-common:2.0.4
@@ -22,7 +22,8 @@ net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.commons:commons-compress:1.19
org.checkerframework:checker-compat-qual:2.5.5
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
org.flywaydb:flyway-core:5.2.4
org.hamcrest:hamcrest-core:1.3
@@ -3,13 +3,13 @@
# This file is expected to be part of source control.
com.google.auto.value:auto-value-annotations:1.6.3
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.1
com.google.errorprone:error_prone_annotations:2.3.2
com.google.flogger:flogger-system-backend:0.1
com.google.flogger:flogger:0.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-android
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.google.j2objc:j2objc-annotations:1.3
com.google.truth:truth:1.0
com.googlecode.java-diff-utils:diffutils:1.3.0
com.kohlschutter.junixsocket:junixsocket-common:2.0.4
@@ -23,7 +23,8 @@ net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.commons:commons-compress:1.19
org.checkerframework:checker-compat-qual:2.5.5
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
org.flywaydb:flyway-core:5.2.4
org.hamcrest:hamcrest-core:1.3
@@ -16,15 +16,15 @@ com.google.auto.value:auto-value-annotations:1.6.3
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
com.google.cloud.sql:postgres-socket-factory:1.0.12
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.1
com.google.errorprone:error_prone_annotations:2.3.2
com.google.flogger:flogger-system-backend:0.1
com.google.flogger:flogger:0.1
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-android
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.http-client:google-http-client-jackson2:1.23.0
com.google.http-client:google-http-client:1.23.0
com.google.j2objc:j2objc-annotations:1.1
com.google.j2objc:j2objc-annotations:1.3
com.google.oauth-client:google-oauth-client:1.23.0
com.google.truth:truth:1.0
com.googlecode.java-diff-utils:diffutils:1.3.0
@@ -43,7 +43,8 @@ org.apache.commons:commons-compress:1.19
org.apache.httpcomponents:httpclient:4.0.1
org.apache.httpcomponents:httpcore:4.0.1
org.checkerframework:checker-compat-qual:2.5.5
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
org.flywaydb:flyway-core:5.2.4
org.hamcrest:hamcrest-core:1.3
+20 -14
View File
@@ -18,8 +18,8 @@ ext {
dependencyList = [
'args4j:args4j:2.0.26',
'com.beust:jcommander:1.60',
'com.google.api-client:google-api-client:1.29.2',
'com.google.api-client:google-api-client-java6:1.27.0',
'com.google.api-client:google-api-client:1.29.2',
'com.google.apis:google-api-services-admin-directory:directory_v1-rev72-1.22.0',
'com.google.apis:google-api-services-appengine:v1-rev101-1.25.0',
'com.google.apis:google-api-services-bigquery:v2-rev325-1.22.0',
@@ -31,46 +31,46 @@ ext {
'com.google.apis:google-api-services-monitoring:v3-rev11-1.22.0',
'com.google.apis:google-api-services-sheets:v4-rev483-1.22.0',
'com.google.apis:google-api-services-storage:v1-rev150-1.22.0',
'com.google.appengine.tools:appengine-gcs-client:0.6',
'com.google.appengine.tools:appengine-mapreduce:0.9',
'com.google.appengine.tools:appengine-pipeline:0.2.13',
'com.google.appengine:appengine-api-1.0-sdk:1.9.48',
'com.google.appengine:appengine-api-stubs:1.9.48',
'com.google.appengine:appengine-remote-api:1.9.48',
'com.google.appengine:appengine-testing:1.9.58',
'com.google.appengine.tools:appengine-gcs-client:0.6',
'com.google.appengine.tools:appengine-mapreduce:0.9',
'com.google.appengine.tools:appengine-pipeline:0.2.13',
'com.google.auth:google-auth-library-credentials:0.16.1',
'com.google.auth:google-auth-library-oauth2-http:0.16.1',
'com.google.auto.value:auto-value:1.6.3',
'com.google.auto.value:auto-value-annotations:1.6.3',
'com.google.auto.value:auto-value:1.6.3',
'com.google.closure-stylesheets:closure-stylesheets:1.5.0',
'com.google.cloud.sql:postgres-socket-factory:1.0.12',
'com.google.cloud:google-cloud-core:1.59.0',
'com.google.cloud:google-cloud-storage:1.59.0',
'com.google.cloud.sql:postgres-socket-factory:1.0.12',
'com.google.code.findbugs:jsr305:3.0.2',
'com.google.code.gson:gson:2.8.5',
'com.googlecode.json-simple:json-simple:1.1.1',
'com.google.dagger:dagger:2.21',
'com.google.dagger:dagger-compiler:2.21',
'com.google.dagger:dagger:2.21',
'com.google.errorprone:error_prone_annotations:2.3.3',
'com.google.flogger:flogger:0.1',
'com.google.flogger:flogger-system-backend:0.1',
'com.google.guava:guava:28.1-jre',
'com.google.flogger:flogger:0.1',
'com.google.guava:guava-testlib:28.1-jre',
'com.google.guava:guava:28.1-jre',
'com.google.gwt:gwt-user:2.8.2',
'com.google.http-client:google-http-client:1.29.2',
'com.google.http-client:google-http-client-appengine:1.29.2',
'com.google.http-client:google-http-client-jackson2:1.29.2',
'com.google.http-client:google-http-client:1.29.2',
'com.google.javascript:closure-compiler:v20190301',
'com.google.monitoring-client:contrib:1.0.6',
'com.google.monitoring-client:metrics:1.0.6',
'com.google.monitoring-client:stackdriver:1.0.6',
'com.google.oauth-client:google-oauth-client:1.29.2',
'com.google.oauth-client:google-oauth-client-java6:1.27.0',
'com.google.oauth-client:google-oauth-client-jetty:1.28.0',
'com.google.oauth-client:google-oauth-client:1.29.2',
'com.google.re2j:re2j:1.1',
'com.google.template:soy:2018-03-14',
'com.google.truth.extensions:truth-java8-extension:1.0',
'com.google.truth:truth:1.0',
'com.googlecode.json-simple:json-simple:1.1.1',
'com.ibm.icu:icu4j:57.1',
'com.jcraft:jsch:0.1.55',
'com.sun.activation:javax.activation:1.2.0',
@@ -82,15 +82,17 @@ ext {
'io.github.classgraph:classgraph:4.8.52',
'io.github.java-diff-utils:java-diff-utils:4.0',
'io.netty:netty-buffer:4.1.31.Final',
'io.netty:netty-codec:4.1.31.Final',
'io.netty:netty-codec-http:4.1.31.Final',
'io.netty:netty-codec:4.1.31.Final',
'io.netty:netty-common:4.1.31.Final',
'io.netty:netty-handler:4.1.31.Final',
'io.netty:netty-tcnative-boringssl-static:2.0.22.Final',
'io.netty:netty-transport:4.1.31.Final',
'javax.annotation:javax.annotation-api:1.3.2',
'javax.annotation:jsr250-api:1.0',
'javax.inject:javax.inject:1',
'javax.mail:mail:1.4',
'javax.persistence:javax.persistence-api:2.2',
'javax.servlet:servlet-api:2.5',
'javax.xml.bind:jaxb-api:2.3.0',
'jline:jline:1.0',
@@ -102,6 +104,7 @@ ext {
'org.apache.beam:beam-sdks-java-core:2.16.0',
'org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0',
'org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0',
'org.apache.commons:commons-lang3:3.8.1',
'org.apache.commons:commons-text:1.6',
'org.apache.ftpserver:ftplet-api:1.0.6',
'org.apache.ftpserver:ftpserver-core:1.0.6',
@@ -119,8 +122,9 @@ ext {
'org.hamcrest:hamcrest-all:1.3',
'org.hamcrest:hamcrest-core:1.3',
'org.hamcrest:hamcrest-library:1.3',
'org.hibernate:hibernate-core:5.4.4.Final',
'org.hibernate:hibernate-hikaricp:5.4.4.Final',
'org.joda:joda-money:0.10.0',
'org.joda:joda-money:1.0.1',
'org.json:json:20160810',
'org.mockito:mockito-core:2.25.0',
'org.mortbay.jetty:jetty:6.1.26',
@@ -129,8 +133,10 @@ ext {
'org.seleniumhq.selenium:selenium-chrome-driver:3.141.59',
'org.seleniumhq.selenium:selenium-java:3.141.59',
'org.seleniumhq.selenium:selenium-remote-driver:3.141.59',
'org.testcontainers:jdbc:1.12.1',
'org.testcontainers:postgresql:1.12.1',
'org.testcontainers:selenium:1.12.1',
'org.testcontainers:testcontainers:1.12.1',
'org.yaml:snakeyaml:1.17',
'xerces:xmlParserAPIs:2.6.2',
'xpp3:xpp3:1.1.4c'
+1
View File
@@ -302,6 +302,7 @@ An EPP flow that creates a new domain resource.
* The current registry phase allows registrations only with signed marks.
* The current registry phase does not allow for general registrations.
* Signed marks are only allowed during sunrise.
* An allocation token was provided that is invalid for premium domains.
* 2003
* The provided mark does not match the desired domain label.
* Fees must be explicitly acknowledged when creating domains during the
@@ -1,14 +1,13 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
cglib:cglib-nodep:3.2.2
com.diffplug.durian:durian-collect:1.2.0
com.diffplug.durian:durian-core:1.2.0
com.diffplug.durian:durian-io:1.2.0
com.diffplug.gradle.spotless:com.diffplug.gradle.spotless.gradle.plugin:3.18.0
com.diffplug.spotless:spotless-lib-extra:1.18.0
com.diffplug.spotless:spotless-lib:1.18.0
com.diffplug.spotless:spotless-plugin-gradle:3.18.0
com.diffplug.gradle.spotless:com.diffplug.gradle.spotless.gradle.plugin:3.25.0
com.diffplug.spotless:spotless-lib-extra:1.25.0
com.diffplug.spotless:spotless-lib:1.25.0
com.diffplug.spotless:spotless-plugin-gradle:3.25.0
com.github.jengelman.gradle.plugins:shadow:5.1.0
com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:5.1.0
com.google.cloud.tools:appengine-gradle-plugin:2.0.1
@@ -22,73 +21,61 @@ com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.googlecode.concurrent-trees:concurrent-trees:2.6.1
com.googlecode.javaewah:JavaEWAH:1.1.6
com.jcraft:jsch:0.1.54
com.jcraft:jsch:0.1.55
com.jcraft:jzlib:1.1.1
com.moowork.gradle:gradle-node-plugin:1.2.0
com.moowork.node:com.moowork.node.gradle.plugin:1.2.0
com.netflix.nebula:gradle-lint-plugin:10.4.2
com.netflix.nebula:nebula-gradle-interop:1.0.7
com.netflix.nebula:nebula-test:7.2.5
commons-codec:commons-codec:1.9
com.netflix.nebula:gradle-lint-plugin:16.0.2
com.netflix.nebula:nebula-gradle-interop:1.0.11
commons-io:commons-io:2.6
commons-lang:commons-lang:2.6
commons-logging:commons-logging:1.2
javax.inject:javax.inject:1
junit:junit:4.12
log4j:log4j:1.2.14
nebula.lint:nebula.lint.gradle.plugin:10.4.2
nebula.lint:nebula.lint.gradle.plugin:16.0.2
net.ltgt.apt:net.ltgt.apt.gradle.plugin:0.19
net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:0.6.1
net.ltgt.gradle:gradle-apt-plugin:0.19
net.ltgt.gradle:gradle-errorprone-plugin:0.6.1
org.apache.ant:ant-antlr:1.8.4
org.apache.ant:ant-junit:1.8.4
org.apache.ant:ant-launcher:1.9.7
org.apache.ant:ant:1.9.7
org.apache.commons:commons-compress:1.18
org.apache.commons:commons-lang3:3.8.1
org.apache.httpcomponents:httpclient:4.5.2
org.apache.httpcomponents:httpcore:4.4.4
org.apache.logging.log4j:log4j-api:2.11.0
org.apache.logging.log4j:log4j-core:2.11.0
org.apache.maven:maven-artifact:3.6.1
org.apache.maven:maven-builder-support:3.6.1
org.apache.maven:maven-model-builder:3.6.1
org.apache.maven:maven-model:3.6.1
org.apache.maven:maven-artifact:3.6.2
org.apache.maven:maven-builder-support:3.6.2
org.apache.maven:maven-model-builder:3.6.2
org.apache.maven:maven-model:3.6.2
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.5.2
org.codehaus.gpars:gpars:1.2.1
org.codehaus.groovy:groovy-all:2.4.9
org.codehaus.groovy:groovy-ant:2.1.8
org.codehaus.groovy:groovy-groovydoc:2.1.8
org.codehaus.groovy:groovy-templates:2.1.8
org.codehaus.groovy:groovy-xml:2.4.7
org.codehaus.groovy:groovy:2.4.7
org.codehaus.jsr166-mirror:jsr166y:1.7.0
org.codehaus.mojo:animal-sniffer-annotations:1.17
org.codehaus.plexus:plexus-component-annotations:1.7.1
org.codehaus.plexus:plexus-interpolation:1.25
org.codehaus.plexus:plexus-utils:3.2.0
org.codenarc:CodeNarc:0.25.2
org.eclipse.jdt:core:3.1.1
org.eclipse.jgit:org.eclipse.jgit:5.0.1.201806211838-r
org.codehaus.plexus:plexus-utils:3.2.1
org.eclipse.jgit:org.eclipse.jgit:5.5.0.201909110433-r
org.eclipse.sisu:org.eclipse.sisu.inject:0.3.3
org.glassfish:javax.json:1.0.4
org.gmetrics:GMetrics:0.7
org.hamcrest:hamcrest-core:1.3
org.jdom:jdom2:2.0.6
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.11
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.11
org.jetbrains.kotlin:kotlin-stdlib:1.3.11
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50
org.jetbrains.kotlin:kotlin-stdlib:1.3.50
org.jetbrains:annotations:13.0
org.multiverse:multiverse-core:0.7.0
org.objenesis:objenesis:2.4
org.ow2.asm:asm-analysis:7.0-beta
org.ow2.asm:asm-commons:7.0-beta
org.ow2.asm:asm-tree:7.0-beta
org.ow2.asm:asm:7.0
org.ow2.asm:asm-analysis:7.1
org.ow2.asm:asm-commons:7.1
org.ow2.asm:asm-tree:7.1
org.ow2.asm:asm:7.1
org.slf4j:slf4j-api:1.7.2
org.sonatype.aether:aether-api:1.13.1
org.sonatype.aether:aether-impl:1.13.1
org.sonatype.aether:aether-spi:1.13.1
org.sonatype.aether:aether-util:1.13.1
org.spockframework:spock-core:1.1-groovy-2.4-rc-4
org.vafer:jdependency:2.1.1
org.yaml:snakeyaml:1.21
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+12 -17
View File
@@ -154,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -175,14 +175,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
+99 -69
View File
@@ -55,9 +55,9 @@
}
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
"dev": true
},
"backo2": {
@@ -189,9 +189,9 @@
"dev": true
},
"chokidar": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.2.2.tgz",
"integrity": "sha512-bw3pm7kZ2Wa6+jQWYP/c7bAZy3i4GwiIiMO2EeRjrE48l8vBqC/WvFhSF0xyM8fQiPEGvwMY/5bqDG7sSEOuhg==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz",
"integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==",
"dev": true,
"requires": {
"anymatch": "~3.1.1",
@@ -544,16 +544,16 @@
"dev": true
},
"fsevents": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz",
"integrity": "sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
"integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
"dev": true,
"optional": true
},
"glob": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -579,9 +579,9 @@
"integrity": "sha512-B+Cdh2c3BbvSIONufK3yU/yKwhm7vxaqrAvxIBo3JmUAhA3WQPRSculbJPKC4ca7b/pjlsIR76KDpVqVrJd4dg=="
},
"graceful-fs": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
"integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
"dev": true
},
"has-binary2": {
@@ -591,14 +591,6 @@
"dev": true,
"requires": {
"isarray": "2.0.1"
},
"dependencies": {
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
"dev": true
}
}
},
"has-cors": {
@@ -631,6 +623,33 @@
"requires-port": "^1.0.0"
}
},
"https-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz",
"integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
"dev": true,
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
}
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -693,9 +712,9 @@
"dev": true
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
"dev": true
},
"isbinaryfile": {
@@ -870,9 +889,9 @@
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
"dev": true
},
"mkdirp": {
@@ -882,6 +901,14 @@
"dev": true,
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
}
}
},
"ms": {
@@ -985,9 +1012,9 @@
"dev": true
},
"picomatch": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz",
"integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz",
"integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==",
"dev": true
},
"process-nextick-args": {
@@ -1015,14 +1042,14 @@
"dev": true
},
"puppeteer": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz",
"integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.0.0.tgz",
"integrity": "sha512-t3MmTWzQxPRP71teU6l0jX47PHXlc4Z52sQv4LJQSZLq1ttkKS2yGM3gaI57uQwZkNaoGd0+HPPMELZkcyhlqA==",
"dev": true,
"requires": {
"debug": "^4.1.0",
"extract-zip": "^1.6.6",
"https-proxy-agent": "^2.2.1",
"https-proxy-agent": "^3.0.0",
"mime": "^2.0.3",
"progress": "^2.0.1",
"proxy-from-env": "^1.0.0",
@@ -1039,27 +1066,6 @@
"ms": "^2.1.1"
}
},
"https-proxy-agent": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz",
"integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==",
"dev": true,
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
}
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -1120,6 +1126,20 @@
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
}
}
},
"readdirp": {
@@ -1144,18 +1164,18 @@
"dev": true
},
"rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
"dev": true
},
"safer-buffer": {
@@ -1253,12 +1273,6 @@
"requires": {
"ms": "2.0.0"
}
},
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
"dev": true
}
}
},
@@ -1311,6 +1325,14 @@
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
}
}
},
"tmp": {
@@ -1435,6 +1457,14 @@
"async-limiter": "~1.0.0",
"safe-buffer": "~5.1.0",
"ultron": "~1.1.0"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
}
}
},
"xmlhttprequest-ssl": {
+1 -1
View File
@@ -25,6 +25,6 @@
"karma-chrome-launcher": "2.2.0",
"karma-closure": "0.1.3",
"karma-jasmine": "2.0.1",
"puppeteer": "1.20.0"
"puppeteer": "2.0.0"
}
}
+3 -1
View File
@@ -27,8 +27,8 @@ dependencies {
compile deps['com.google.guava:guava']
compile deps['com.google.monitoring-client:metrics']
compile deps['io.netty:netty-buffer']
compile deps['io.netty:netty-codec-http']
compile deps['io.netty:netty-codec']
compile deps['io.netty:netty-codec-http']
compile deps['io.netty:netty-common']
compile deps['io.netty:netty-handler']
compile deps['io.netty:netty-transport']
@@ -36,6 +36,8 @@ dependencies {
compile deps['joda-time:joda-time']
compile deps['org.bouncycastle:bcpkix-jdk15on']
compile deps['org.bouncycastle:bcprov-jdk15on']
compile deps['xerces:xmlParserAPIs']
compile deps['xpp3:xpp3']
compile project(':util')
runtime deps['com.google.flogger:flogger-system-backend']
@@ -3,16 +3,16 @@
# This file is expected to be part of source control.
antlr:antlr:2.7.7
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.2.0
com.google.errorprone:error_prone_annotations:2.3.2
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:27.0.1-jre
com.google.guava:guava:28.0-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.puppycrawl.tools:checkstyle:8.17
commons-beanutils:commons-beanutils:1.9.3
com.google.j2objc:j2objc-annotations:1.3
com.puppycrawl.tools:checkstyle:8.24
commons-beanutils:commons-beanutils:1.9.4
commons-collections:commons-collections:3.2.2
info.picocli:picocli:3.9.0
net.sf.saxon:Saxon-HE:9.9.0-2
info.picocli:picocli:4.0.3
net.sf.saxon:Saxon-HE:9.9.1-4
org.antlr:antlr4-runtime:4.7.2
org.checkerframework:checker-qual:2.5.2
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.17
@@ -48,3 +48,5 @@ org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.yaml:snakeyaml:1.17
xerces:xmlParserAPIs:2.6.2
xpp3:xpp3:1.1.4c
@@ -48,3 +48,5 @@ org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.yaml:snakeyaml:1.17
xerces:xmlParserAPIs:2.6.2
xpp3:xpp3:1.1.4c
@@ -50,3 +50,5 @@ org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.yaml:snakeyaml:1.17
xerces:xmlParserAPIs:2.6.2
xpp3:xpp3:1.1.4c
@@ -1,4 +1,4 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.agent:0.8.5
@@ -1,11 +1,11 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.ant:0.8.4
org.jacoco:org.jacoco.core:0.8.4
org.jacoco:org.jacoco.report:0.8.4
org.ow2.asm:asm-analysis:7.1
org.ow2.asm:asm-commons:7.1
org.ow2.asm:asm-tree:7.1
org.ow2.asm:asm:7.1
org.jacoco:org.jacoco.agent:0.8.5
org.jacoco:org.jacoco.ant:0.8.5
org.jacoco:org.jacoco.core:0.8.5
org.jacoco:org.jacoco.report:0.8.5
org.ow2.asm:asm-analysis:7.2
org.ow2.asm:asm-commons:7.2
org.ow2.asm:asm-tree:7.2
org.ow2.asm:asm:7.2
@@ -50,3 +50,5 @@ org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.yaml:snakeyaml:1.17
xerces:xmlParserAPIs:2.6.2
xpp3:xpp3:1.1.4c
@@ -50,3 +50,5 @@ org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.yaml:snakeyaml:1.17
xerces:xmlParserAPIs:2.6.2
xpp3:xpp3:1.1.4c
@@ -240,7 +240,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0
@@ -228,7 +228,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0
@@ -240,7 +240,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0

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